Skip to content

Commit

Permalink
Call PyBaseObject_Type.tp_new instead of tp_alloc
Browse files Browse the repository at this point in the history
This allows object.__new__ to check greenlet subclasses for
being abstract and raise an exception in that case.
  • Loading branch information
snaury committed Jun 24, 2014
1 parent f88a2be commit d3993da
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 1 deletion.
16 changes: 15 additions & 1 deletion greenlet.c
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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)
{
Expand Down
23 changes: 23 additions & 0 deletions tests/test_greenlet.py
Expand Up @@ -6,6 +6,12 @@

from greenlet import greenlet

try:
from abc import ABCMeta, abstractmethod
except ImportError:
ABCMeta = None
abstractmethod = None


class SomeError(Exception):
pass
Expand Down Expand Up @@ -462,3 +468,20 @@ def switchapply():
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)

0 comments on commit d3993da

Please sign in to comment.