Skip to content

Commit

Permalink
Add support for instance dictionaries
Browse files Browse the repository at this point in the history
  • Loading branch information
snaury committed May 12, 2012
1 parent 9418125 commit a4cc1c9
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 1 deletion.
36 changes: 35 additions & 1 deletion greenlet.c
Original file line number Diff line number Diff line change
Expand Up @@ -728,6 +728,7 @@ green_traverse(PyGreenlet *self, visitproc visit, void *arg)
Py_VISIT(self->exc_type);
Py_VISIT(self->exc_value);
Py_VISIT(self->exc_traceback);
Py_VISIT(self->dict);
return 0;
}

Expand Down Expand Up @@ -802,6 +803,7 @@ static void green_dealloc(PyGreenlet* self)
Py_CLEAR(self->exc_type);
Py_CLEAR(self->exc_value);
Py_CLEAR(self->exc_traceback);
Py_CLEAR(self->dict);
if (self->weakreflist != NULL)
PyObject_ClearWeakRefs((PyObject *) self);
Py_CLEAR(self->run_info);
Expand Down Expand Up @@ -978,6 +980,36 @@ static int green_bool(PyGreenlet* self)
return PyGreenlet_ACTIVE(self);
}

static PyObject* green_getdict(PyGreenlet* self, void* c)
{
if (self->dict == NULL) {
self->dict = PyDict_New();
if (self->dict == NULL)
return NULL;
}
Py_INCREF(self->dict);
return self->dict;
}

static int green_setdict(PyGreenlet* self, PyObject* val, void* c)
{
PyObject* tmp;

if (val == NULL) {
PyErr_SetString(PyExc_TypeError, "__dict__ may not be deleted");
return -1;
}
if (!PyDict_Check(val)) {
PyErr_SetString(PyExc_TypeError, "__dict__ must be a dictionary");
return -1;
}
tmp = self->dict;
Py_INCREF(val);
self->dict = val;
Py_XDECREF(tmp);
return 0;
}

static PyObject* green_getdead(PyGreenlet* self, void* c)
{
PyObject* res;
Expand Down Expand Up @@ -1156,6 +1188,8 @@ static PyMethodDef green_methods[] = {
};

static PyGetSetDef green_getsets[] = {
{"__dict__", (getter)green_getdict,
(setter)green_setdict, /*XXX*/ NULL},
{"run", (getter)green_getrun,
(setter)green_setrun, /*XXX*/ NULL},
{"parent", (getter)green_getparent,
Expand Down Expand Up @@ -1229,7 +1263,7 @@ PyTypeObject PyGreenlet_Type = {
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
offsetof(PyGreenlet, dict), /* tp_dictoffset */
(initproc)green_init, /* tp_init */
GREENLET_tp_alloc, /* tp_alloc */
green_new, /* tp_new */
Expand Down
1 change: 1 addition & 0 deletions greenlet.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ typedef struct _greenlet {
PyObject* exc_type;
PyObject* exc_value;
PyObject* exc_traceback;
PyObject* dict;
} PyGreenlet;

#define PyGreenlet_Check(op) PyObject_TypeCheck(op, &PyGreenlet_Type)
Expand Down
17 changes: 17 additions & 0 deletions tests/test_greenlet.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,3 +245,20 @@ def h():
self.assertEqual(sys.exc_info(), (None, None, None))

greenlet(f).switch()

def test_instance_dict(self):
def f():
greenlet.getcurrent().test = 42
def deldict(g):
del g.__dict__
def setdict(g, value):
g.__dict__ = value
g = greenlet(f)
self.assertEqual(g.__dict__, {})
g.switch()
self.assertEqual(g.test, 42)
self.assertEqual(g.__dict__, {'test': 42})
g.__dict__ = g.__dict__
self.assertEqual(g.__dict__, {'test': 42})
self.assertRaises(TypeError, deldict, g)
self.assertRaises(TypeError, setdict, g, 42)

0 comments on commit a4cc1c9

Please sign in to comment.