diff options
author | Alexey Borzenkov <snaury@gmail.com> | 2013-12-13 02:46:06 +0400 |
---|---|---|
committer | Alexey Borzenkov <snaury@gmail.com> | 2014-06-25 00:51:50 +0400 |
commit | d3993dacf6d90b84781e5060b2a345059f10e6c6 (patch) | |
tree | 5cf890e00b9dd63ad92c5733f67836327aab7213 | |
parent | f88a2be609a5cd7c0f986263d6d04e16f02db47f (diff) | |
download | greenlet-d3993dacf6d90b84781e5060b2a345059f10e6c6.tar.gz |
Call PyBaseObject_Type.tp_new instead of tp_alloc
This allows object.__new__ to check greenlet subclasses for
being abstract and raise an exception in that case.
-rw-r--r-- | greenlet.c | 16 | ||||
-rw-r--r-- | tests/test_greenlet.py | 23 |
2 files changed, 38 insertions, 1 deletions
@@ -130,6 +130,8 @@ static PyObject* ts_event_throw; #endif static PyObject* PyExc_GreenletError; static PyObject* PyExc_GreenletExit; +static PyObject* ts_empty_tuple; +static PyObject* ts_empty_dict; #if GREENLET_USE_GC #define GREENLET_GC_FLAGS Py_TPFLAGS_HAVE_GC @@ -825,7 +827,7 @@ static PyObject* green_new(PyTypeObject *type, PyObject *args, PyObject *kwds) if (!STATE_OK) return NULL; - o = type->tp_alloc(type, 0); + o = PyBaseObject_Type.tp_new(type, ts_empty_tuple, ts_empty_dict); if (o != NULL) { Py_INCREF(ts_current); ((PyGreenlet*) o)->parent = ts_current; @@ -1634,6 +1636,18 @@ initgreenlet(void) INITERROR; } + ts_empty_tuple = PyTuple_New(0); + if (ts_empty_tuple == NULL) + { + INITERROR; + } + + ts_empty_dict = PyDict_New(); + if (ts_empty_dict == NULL) + { + INITERROR; + } + ts_current = green_create_main(); if (ts_current == NULL) { diff --git a/tests/test_greenlet.py b/tests/test_greenlet.py index 99f3e74..6b17eca 100644 --- a/tests/test_greenlet.py +++ b/tests/test_greenlet.py @@ -6,6 +6,12 @@ import unittest from greenlet import greenlet +try: + from abc import ABCMeta, abstractmethod +except ImportError: + ABCMeta = None + abstractmethod = None + class SomeError(Exception): pass @@ -462,3 +468,20 @@ class GreenletTests(unittest.TestCase): apply(greenlet.getcurrent().parent.switch, args, kwargs) g = greenlet(switchapply) self.assertEqual(g.switch(), kwargs) + + if ABCMeta is not None and abstractmethod is not None: + def test_abstract_subclasses(self): + AbstractSubclass = ABCMeta( + 'AbstractSubclass', + (greenlet,), + {'run': abstractmethod(lambda self: None)}) + + class BadSubclass(AbstractSubclass): + pass + + class GoodSubclass(AbstractSubclass): + def run(self): + pass + + GoodSubclass() # should not raise + self.assertRaises(TypeError, BadSubclass) |