summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexey Borzenkov <snaury@gmail.com>2013-12-13 02:46:06 +0400
committerAlexey Borzenkov <snaury@gmail.com>2014-06-25 00:51:50 +0400
commitd3993dacf6d90b84781e5060b2a345059f10e6c6 (patch)
tree5cf890e00b9dd63ad92c5733f67836327aab7213
parentf88a2be609a5cd7c0f986263d6d04e16f02db47f (diff)
downloadgreenlet-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.c16
-rw-r--r--tests/test_greenlet.py23
2 files changed, 38 insertions, 1 deletions
diff --git a/greenlet.c b/greenlet.c
index ea32bd2..733ceab 100644
--- a/greenlet.c
+++ b/greenlet.c
@@ -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)