Skip to content

Commit

Permalink
Improve type error messages. Refs #330
Browse files Browse the repository at this point in the history
  • Loading branch information
jamadden committed Jan 28, 2023
1 parent 1784361 commit b55ea9e
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 6 deletions.
12 changes: 12 additions & 0 deletions src/greenlet/greenlet_exceptions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <stdexcept>
#include <string>

#ifdef __clang__
# pragma clang diagnostic push
Expand All @@ -25,6 +26,13 @@ namespace greenlet {
{
PyErr_SetString(exc_kind, msg);
}
PyErrOccurred(PyObject* exc_kind, const std::string msg)
: std::runtime_error(msg)
{
// This copies the c_str, so we don't have any lifetime
// issues to worry about.
PyErr_SetString(exc_kind, msg.c_str());
}
};

class TypeError : public PyErrOccurred
Expand All @@ -34,6 +42,10 @@ namespace greenlet {
: PyErrOccurred(PyExc_TypeError, what)
{
}
TypeError(const std::string what)
: PyErrOccurred(PyExc_TypeError, what)
{
}
};

class ValueError : public PyErrOccurred
Expand Down
9 changes: 7 additions & 2 deletions src/greenlet/greenlet_internal.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "greenlet_allocator.hpp"

#include <vector>
#include <string>

#define GREENLET_MODULE
struct _greenlet;
Expand All @@ -45,7 +46,9 @@ greenlet::refs::MainGreenletExactChecker(void *p)
}
// We control the class of the main greenlet exactly.
if (Py_TYPE(p) != &PyGreenlet_Type) {
throw greenlet::TypeError("Expected a greenlet");
std::string err("MainGreenlet: Expected exactly a greenlet, not a ");
err += Py_TYPE(p)->tp_name;
throw greenlet::TypeError(err);
}

// Greenlets from dead threads no longer respond to main() with a
Expand All @@ -56,7 +59,9 @@ greenlet::refs::MainGreenletExactChecker(void *p)
return;
}
if (!dynamic_cast<MainGreenlet*>(g)) {
throw greenlet::TypeError("Expected a main greenlet");
std::string err("MainGreenlet: Expected exactly a main greenlet, not a ");
err += Py_TYPE(p)->tp_name;
throw greenlet::TypeError(err);
}
}

Expand Down
4 changes: 3 additions & 1 deletion src/greenlet/greenlet_refs.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,9 @@ namespace greenlet
}

if (!PyObject_TypeCheck(p, &PyGreenlet_Type)) {
throw TypeError("Expected a greenlet");
std::string err("GreenletChecker: Expected any type of greenlet, not ");
err += Py_TYPE(p)->tp_name;
throw TypeError(err);
}
}

Expand Down
13 changes: 11 additions & 2 deletions src/greenlet/tests/test_cpp.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,17 @@ def _do_test_unhandled_exception(self, target):
# https://devblogs.microsoft.com/oldnewthing/20110519-00/?p=10623
# and
# https://docs.microsoft.com/en-us/previous-versions/k089yyh0(v=vs.140)?redirectedfrom=MSDN
expected_exit = -signal.SIGABRT if not WIN else 3
self.assertEqual(p.exitcode, expected_exit)
expected_exit = (
-signal.SIGABRT,
# But beginning on Python 3.11, the faulthandler
# that prints the C backtraces sometimes segfaults after
# reporting the exception but before printing the stack.
# This has only been seen on linux/gcc.
-signal.SIGSEGV
) if not WIN else (
3,
)
self.assertIn(p.exitcode, expected_exit)

def test_unhandled_exception_aborts(self):
# verify that plain unhandled throw aborts
Expand Down
5 changes: 4 additions & 1 deletion src/greenlet/tests/test_greenlet.py
Original file line number Diff line number Diff line change
Expand Up @@ -972,7 +972,10 @@ def check(glet):
for p in None, 1, self, "42":
with self.assertRaises(TypeError) as exc:
glet.parent = p
self.assertEqual(str(exc.exception), "Expected a greenlet")

self.assertEqual(
str(exc.exception),
"GreenletChecker: Expected any type of greenlet, not " + type(p).__name__)

# First, not running
g = greenlet(bg)
Expand Down

0 comments on commit b55ea9e

Please sign in to comment.