Commit ca9e3f18 authored by Jim Fulton's avatar Jim Fulton

Added __basicnew__ class protocol.

Added support for user-defined method attributes.  User-defined method
attributes can only be set or accessed for bound methods.
User-defined method attributes are stored in instances under a name
formed by concatinating the method and attribute names.  Default
values for user-defined method attributes may be set in the class
statement. For example, to define the default '__roles__' attribute of
a method, 'f'::

   class C:
      def f(self): print 'f called'
      f__roles__=('manage',)

User-defined attributes may not be set in restricted execution mode.
User-defined attribute names may only be accessed in
restricted-execution mode if their names begin with double
underscores.

Added default __cmp__ support for extension subclasses.  I only
recently noticed that extension subclasses overcome Python's
willingness to only compare objects of the same type, because they
smell to Python like numeric types.
parent 7224d742
/* /*
$Id: ExtensionClass.c,v 1.17 1997/11/13 21:05:35 jim Exp $ $Id: ExtensionClass.c,v 1.18 1997/12/11 16:00:22 jim Exp $
Extension Class Extension Class
...@@ -65,7 +65,7 @@ static char ExtensionClass_module_documentation[] = ...@@ -65,7 +65,7 @@ static char ExtensionClass_module_documentation[] =
" - They provide access to unbound methods,\n" " - They provide access to unbound methods,\n"
" - They can be called to create instances.\n" " - They can be called to create instances.\n"
"\n" "\n"
"$Id: ExtensionClass.c,v 1.17 1997/11/13 21:05:35 jim Exp $\n" "$Id: ExtensionClass.c,v 1.18 1997/12/11 16:00:22 jim Exp $\n"
; ;
#include <stdio.h> #include <stdio.h>
...@@ -110,10 +110,11 @@ static PyObject *py__add__, *py__sub__, *py__mul__, *py__div__, ...@@ -110,10 +110,11 @@ static PyObject *py__add__, *py__sub__, *py__mul__, *py__div__,
*py__getitem__, *py__setitem__, *py__delitem__, *py__getitem__, *py__setitem__, *py__delitem__,
*py__getslice__, *py__setslice__, *py__delslice__, *py__len__, *py__getslice__, *py__setslice__, *py__delslice__, *py__len__,
*py__getattr__, *py__setattr__, *py__delattr__, *py__getattr__, *py__setattr__, *py__delattr__,
*py__del__, *py__repr__, *py__str__, *py__class__, *py__del__, *py__repr__, *py__str__, *py__class__, *py__name__,
*py__hash__, *py__cmp__, *py__var_size__, *py__init__, *py__getinitargs__, *py__hash__, *py__cmp__, *py__var_size__, *py__init__, *py__getinitargs__,
*py__getstate__, *py__setstate__, *py__dict__, *pyclass_; *py__getstate__, *py__setstate__, *py__dict__, *pyclass_;
static PyObject *concat_fmt=0;
static PyObject *subclass_watcher=0; /* Object that subclass events */ static PyObject *subclass_watcher=0; /* Object that subclass events */
static void static void
...@@ -160,6 +161,7 @@ init_py_names() ...@@ -160,6 +161,7 @@ init_py_names()
INIT_PY_NAME(__repr__); INIT_PY_NAME(__repr__);
INIT_PY_NAME(__str__); INIT_PY_NAME(__str__);
INIT_PY_NAME(__class__); INIT_PY_NAME(__class__);
INIT_PY_NAME(__name__);
INIT_PY_NAME(__hash__); INIT_PY_NAME(__hash__);
INIT_PY_NAME(__cmp__); INIT_PY_NAME(__cmp__);
INIT_PY_NAME(__var_size__); INIT_PY_NAME(__var_size__);
...@@ -196,7 +198,6 @@ typedef struct { ...@@ -196,7 +198,6 @@ typedef struct {
PyCFunction meth; PyCFunction meth;
int flags; int flags;
char *doc; char *doc;
PyObject *dict;
} CMethod; } CMethod;
staticforward PyTypeObject CMethodType; staticforward PyTypeObject CMethodType;
...@@ -361,7 +362,6 @@ newCMethod(PyExtensionClass *type, PyObject *inst, ...@@ -361,7 +362,6 @@ newCMethod(PyExtensionClass *type, PyObject *inst,
self->meth=meth; self->meth=meth;
self->flags=flags; self->flags=flags;
self->doc=doc; self->doc=doc;
self->dict=NULL;
return (PyObject*)self; return (PyObject*)self;
} }
...@@ -389,8 +389,6 @@ bindCMethod(CMethod *m, PyObject *inst) ...@@ -389,8 +389,6 @@ bindCMethod(CMethod *m, PyObject *inst)
self->meth=m->meth; self->meth=m->meth;
self->flags=m->flags; self->flags=m->flags;
self->doc=m->doc; self->doc=m->doc;
self->dict=m->dict;
Py_XINCREF(self->dict);
return self; return self;
} }
...@@ -402,7 +400,6 @@ CMethod_dealloc(CMethod *self) ...@@ -402,7 +400,6 @@ CMethod_dealloc(CMethod *self)
#endif #endif
Py_XDECREF(self->type); Py_XDECREF(self->type);
Py_XDECREF(self->self); Py_XDECREF(self->self);
Py_XDECREF(self->dict);
PyMem_DEL(self); PyMem_DEL(self);
} }
...@@ -517,6 +514,15 @@ CMethod_getattro(CMethod *self, PyObject *oname) ...@@ -517,6 +514,15 @@ CMethod_getattro(CMethod *self, PyObject *oname)
char *name; char *name;
UNLESS(name=PyString_AsString(oname)) return NULL; UNLESS(name=PyString_AsString(oname)) return NULL;
if (name[0] != '_' && name[0] && name[1] != '_' &&
PyEval_GetRestricted())
{
PyErr_SetString(PyExc_RuntimeError,
"function attributes not accessible in restricted mode");
return NULL;
}
if(strcmp(name,"__name__")==0 || strcmp(name,"func_name")==0 ) if(strcmp(name,"__name__")==0 || strcmp(name,"func_name")==0 )
return PyString_FromString(self->name); return PyString_FromString(self->name);
if(strcmp(name,"func_code")==0 || if(strcmp(name,"func_code")==0 ||
...@@ -547,7 +553,14 @@ CMethod_getattro(CMethod *self, PyObject *oname) ...@@ -547,7 +553,14 @@ CMethod_getattro(CMethod *self, PyObject *oname)
} }
} }
if(self->dict && (r=PyObject_GetItem(self->dict, oname))) return r; if(self->self) /* Psuedo attributes */
{
UNLESS(oname=Py_BuildValue("sO", self->name, oname)) return NULL;
UNLESS_ASSIGN(oname,PyString_Format(concat_fmt, oname)) return NULL;
r=PyObject_GetAttr(self->self, oname);
Py_DECREF(oname);
return r;
}
PyErr_SetObject(PyExc_AttributeError, oname); PyErr_SetObject(PyExc_AttributeError, oname);
return NULL; return NULL;
...@@ -556,9 +569,19 @@ CMethod_getattro(CMethod *self, PyObject *oname) ...@@ -556,9 +569,19 @@ CMethod_getattro(CMethod *self, PyObject *oname)
static int static int
CMethod_setattro(CMethod *self, PyObject *oname, PyObject *v) CMethod_setattro(CMethod *self, PyObject *oname, PyObject *v)
{ {
if(! self->dict && ! (self->dict=PyDict_New())) return -1; int r;
if(self->self && ! PyEval_GetRestricted()) /* Psuedo attributes */
{
UNLESS(oname=Py_BuildValue("sO", self->name, oname)) return NULL;
UNLESS_ASSIGN(oname,PyString_Format(concat_fmt, oname)) return NULL;
r=PyObject_SetAttr(self->self, oname, v);
Py_DECREF(oname);
return r;
}
return PyDict_SetItem(self->dict, oname, v); PyErr_SetObject(PyExc_AttributeError, oname);
return -1;
} }
static PyTypeObject CMethodType = { static PyTypeObject CMethodType = {
...@@ -769,6 +792,14 @@ PMethod_getattro(PMethod *self, PyObject *oname) ...@@ -769,6 +792,14 @@ PMethod_getattro(PMethod *self, PyObject *oname)
UNLESS(name=PyString_AsString(oname)) return NULL; UNLESS(name=PyString_AsString(oname)) return NULL;
if (name[0] != '_' && name[0] && name[1] != '_' &&
PyEval_GetRestricted())
{
PyErr_SetString(PyExc_RuntimeError,
"function attributes not accessible in restricted mode");
return NULL;
}
if(*name++=='i' && *name++=='m' && *name++=='_') if(*name++=='i' && *name++=='m' && *name++=='_')
{ {
if(strcmp(name,"func")==0) if(strcmp(name,"func")==0)
...@@ -791,9 +822,50 @@ PMethod_getattro(PMethod *self, PyObject *oname) ...@@ -791,9 +822,50 @@ PMethod_getattro(PMethod *self, PyObject *oname)
} }
} }
if(self->self && self->meth) /* Psuedo attrs */
{
PyObject *myname;
UNLESS(myname=PyObject_GetAttr(self->meth, py__name__)) return NULL;
oname=Py_BuildValue("OO", myname, oname);
Py_DECREF(myname);
UNLESS(oname) return NULL;
UNLESS_ASSIGN(oname,PyString_Format(concat_fmt, oname)) return NULL;
r=PyObject_GetAttr(self->self, oname);
Py_DECREF(oname);
return r;
}
PyErr_SetObject(PyExc_AttributeError, oname);
return NULL;
return PyObject_GetAttr(self->meth, oname); return PyObject_GetAttr(self->meth, oname);
} }
static int
PMethod_setattro(PMethod *self, PyObject *oname, PyObject *v)
{
int r;
if(self->self && self->meth && ! PyEval_GetRestricted()) /* Psuedo attrs */
{
PyObject *myname;
UNLESS(myname=PyObject_GetAttr(self->meth, py__name__)) return NULL;
oname=Py_BuildValue("OO", myname, oname);
Py_DECREF(myname);
UNLESS(oname) return NULL;
UNLESS_ASSIGN(oname,PyString_Format(concat_fmt, oname)) return NULL;
r=PyObject_SetAttr(self->self, oname, v);
Py_DECREF(oname);
return r;
}
PyErr_SetObject(PyExc_AttributeError, oname);
return -1;
}
static PyTypeObject PMethodType = { static PyTypeObject PMethodType = {
PyObject_HEAD_INIT(NULL) PyObject_HEAD_INIT(NULL)
0, /*ob_size*/ 0, /*ob_size*/
...@@ -814,9 +886,10 @@ static PyTypeObject PMethodType = { ...@@ -814,9 +886,10 @@ static PyTypeObject PMethodType = {
(ternaryfunc)PMethod_call, /*tp_call*/ (ternaryfunc)PMethod_call, /*tp_call*/
(reprfunc)0, /*tp_str*/ (reprfunc)0, /*tp_str*/
(getattrofunc)PMethod_getattro, /*tp_getattro*/ (getattrofunc)PMethod_getattro, /*tp_getattro*/
(setattrofunc)PMethod_setattro, /* tp_setattro */
/* Space for future expansion */ /* Space for future expansion */
0L,0L,0L, 0L,0L,
"Storage manager for unbound C function PyObject data" "Storage manager for unbound C function PyObject data"
/* Documentation string */ /* Documentation string */
}; };
...@@ -1181,7 +1254,12 @@ EC_reduce(PyObject *self, PyObject *args) ...@@ -1181,7 +1254,12 @@ EC_reduce(PyObject *self, PyObject *args)
else else
{ {
PyErr_Clear(); PyErr_Clear();
args=PyTuple_New(0); if(ExtensionClassOf(self)->class_flags & EXTENSIONCLASS_BASICNEW_FLAG)
{
args=Py_None;
Py_INCREF(args);
}
else args=PyTuple_New(0);
} }
if((state=PyObject_GetAttr(self,py__getstate__))) if((state=PyObject_GetAttr(self,py__getstate__)))
...@@ -1244,6 +1322,58 @@ inheritedAttribute(PyObject *self, PyObject *args) ...@@ -1244,6 +1322,58 @@ inheritedAttribute(PyObject *self, PyObject *args)
return name; return name;
} }
static PyObject *
basicnew(PyExtensionClass *self, PyObject *args)
{
PyObject *inst=0;
typedef struct { PyObject_VAR_HEAD } PyVarObject__;
if(! self->tp_dealloc)
{
PyErr_SetString(PyExc_TypeError,
"Attempt to create instance of an abstract type");
return NULL;
}
if(self->tp_itemsize)
{
/* We have a variable-sized object, we need to get it's size */
PyObject *var_size;
int size;
UNLESS(var_size=CCL_getattr(self,py__var_size__, 0)) return NULL;
UNLESS_ASSIGN(var_size,PyObject_CallObject(var_size,NULL)) return NULL;
size=PyInt_AsLong(var_size);
if(PyErr_Occurred()) return NULL;
UNLESS(inst=PyObject_NEW_VAR(PyObject,(PyTypeObject *)self, size))
return NULL;
memset(inst,0,self->tp_basicsize+self->tp_itemsize*size);
((PyVarObject__*)inst)->ob_size=size;
}
else
{
UNLESS(inst=PyObject_NEW(PyObject,(PyTypeObject *)self)) return NULL;
memset(inst,0,self->tp_basicsize);
}
inst->ob_refcnt=1;
inst->ob_type=(PyTypeObject *)self;
Py_INCREF(self);
if(ClassHasInstDict(self))
UNLESS(INSTANCE_DICT(inst)=PyDict_New()) goto err;
if(self->bases && subclass_watcher &&
! PyObject_CallMethod(subclass_watcher,"created","O",inst))
PyErr_Clear();
return inst;
err:
Py_DECREF(inst);
return NULL;
}
struct PyMethodDef ECI_methods[] = { struct PyMethodDef ECI_methods[] = {
{"__reduce__",(PyCFunction)EC_reduce,0, {"__reduce__",(PyCFunction)EC_reduce,0,
"__reduce__() -- Reduce an instance into it's class and creation data" "__reduce__() -- Reduce an instance into it's class and creation data"
...@@ -1520,6 +1650,26 @@ CCL_getattro(PyExtensionClass *self, PyObject *name) ...@@ -1520,6 +1650,26 @@ CCL_getattro(PyExtensionClass *self, PyObject *name)
if(strcmp(n,"name__")==0) if(strcmp(n,"name__")==0)
return PyString_FromString(self->tp_name); return PyString_FromString(self->tp_name);
break; break;
case 'b':
if(self->class_flags & EXTENSIONCLASS_BASICNEW_FLAG &&
strcmp(n,"basicnew__")==0
)
return newCMethod(self,(PyObject*)self,
"__basicnew__",(PyCFunction)basicnew,0,
"__basicnew__() -- "
"Create a new instance without executing it's constructor"
);
else if(strcmp(n,"bases__")==0)
{
if(self->bases)
{
Py_INCREF(self->bases);
return self->bases;
}
else
return PyTuple_New(0);
}
break;
case 'r': case 'r':
if(strcmp(n,"reduce__")==0) if(strcmp(n,"reduce__")==0)
return newCMethod(self,(PyObject*)self, return newCMethod(self,(PyObject*)self,
...@@ -1533,18 +1683,6 @@ CCL_getattro(PyExtensionClass *self, PyObject *name) ...@@ -1533,18 +1683,6 @@ CCL_getattro(PyExtensionClass *self, PyObject *name)
return self->class_dictionary; return self->class_dictionary;
} }
break; break;
case 'b':
if(strcmp(n,"bases__")==0)
{
if(self->bases)
{
Py_INCREF(self->bases);
return self->bases;
}
else
return PyTuple_New(0);
}
break;
} }
} }
} }
...@@ -1709,6 +1847,8 @@ CCL_call(PyExtensionClass *self, PyObject *arg, PyObject *kw) ...@@ -1709,6 +1847,8 @@ CCL_call(PyExtensionClass *self, PyObject *arg, PyObject *kw)
{ {
UNLESS_ASSIGN(var_size,PyObject_CallObject(var_size,arg)) UNLESS_ASSIGN(var_size,PyObject_CallObject(var_size,arg))
return NULL; return NULL;
size=PyInt_AsLong(var_size);
if(PyErr_Occurred()) return NULL;
} }
else else
{ {
...@@ -1733,18 +1873,16 @@ CCL_call(PyExtensionClass *self, PyObject *arg, PyObject *kw) ...@@ -1733,18 +1873,16 @@ CCL_call(PyExtensionClass *self, PyObject *arg, PyObject *kw)
UNLESS(inst=PyObject_NEW_VAR(PyObject,(PyTypeObject *)self, size)) UNLESS(inst=PyObject_NEW_VAR(PyObject,(PyTypeObject *)self, size))
return NULL; return NULL;
memset(inst,0,self->tp_basicsize+self->tp_itemsize*size); memset(inst,0,self->tp_basicsize+self->tp_itemsize*size);
inst->ob_refcnt=1;
inst->ob_type=(PyTypeObject *)self;
((PyVarObject__*)inst)->ob_size=size; ((PyVarObject__*)inst)->ob_size=size;
} }
else else
{ {
UNLESS(inst=PyObject_NEW(PyObject,(PyTypeObject *)self)) return NULL; UNLESS(inst=PyObject_NEW(PyObject,(PyTypeObject *)self)) return NULL;
memset(inst,0,self->tp_basicsize); memset(inst,0,self->tp_basicsize);
inst->ob_refcnt=1;
inst->ob_type=(PyTypeObject *)self;
} }
inst->ob_refcnt=1;
inst->ob_type=(PyTypeObject *)self;
Py_INCREF(self); Py_INCREF(self);
if(ClassHasInstDict(self)) if(ClassHasInstDict(self))
...@@ -1966,7 +2104,12 @@ subclass_compare(PyObject *self, PyObject *v) ...@@ -1966,7 +2104,12 @@ subclass_compare(PyObject *self, PyObject *v)
PyObject *m; PyObject *m;
long r; long r;
UNLESS(m=subclass_getspecial(self,py__cmp__)) return -1; UNLESS(m=subclass_getspecial(self,py__cmp__))
{
PyErr_Clear();
return self-v;
}
if(UnboundCMethod_Check(m) && AsCMethod(m)->meth==compare_by_name if(UnboundCMethod_Check(m) && AsCMethod(m)->meth==compare_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type) && SubclassInstance_Check(self,AsCMethod(m)->type)
&& ! HasMethodHook(self)) && ! HasMethodHook(self))
...@@ -3071,7 +3214,7 @@ void ...@@ -3071,7 +3214,7 @@ void
initExtensionClass() initExtensionClass()
{ {
PyObject *m, *d; PyObject *m, *d;
char *rev="$Revision: 1.17 $"; char *rev="$Revision: 1.18 $";
PURE_MIXIN_CLASS(Base, "Minimalbase class for Extension Classes", NULL); PURE_MIXIN_CLASS(Base, "Minimalbase class for Extension Classes", NULL);
PMethodType.ob_type=&PyType_Type; PMethodType.ob_type=&PyType_Type;
...@@ -3079,6 +3222,8 @@ initExtensionClass() ...@@ -3079,6 +3222,8 @@ initExtensionClass()
ECTypeType.ob_type=&PyType_Type; ECTypeType.ob_type=&PyType_Type;
ECType.ob_type=&ECTypeType; ECType.ob_type=&ECTypeType;
UNLESS(concat_fmt=PyString_FromString("%s%s"));
m = Py_InitModule4("ExtensionClass", CC_methods, m = Py_InitModule4("ExtensionClass", CC_methods,
ExtensionClass_module_documentation, ExtensionClass_module_documentation,
(PyObject*)NULL,PYTHON_API_VERSION); (PyObject*)NULL,PYTHON_API_VERSION);
...@@ -3110,6 +3255,31 @@ initExtensionClass() ...@@ -3110,6 +3255,31 @@ initExtensionClass()
/**************************************************************************** /****************************************************************************
$Log: ExtensionClass.c,v $ $Log: ExtensionClass.c,v $
Revision 1.18 1997/12/11 16:00:22 jim
Added __basicnew__ class protocol.
Added support for user-defined method attributes. User-defined method
attributes can only be set or accessed for bound methods.
User-defined method attributes are stored in instances under a name
formed by concatinating the method and attribute names. Default
values for user-defined method attributes may be set in the class
statement. For example, to define the default '__roles__' attribute of
a method, 'f'::
class C:
def f(self): print 'f called'
f__roles__=('manage',)
User-defined attributes may not be set in restricted execution mode.
User-defined attribute names may only be accessed in
restricted-execution mode if their names begin with double
underscores.
Added default __cmp__ support for extension subclasses. I only
recently noticed that extension subclasses overcome Python's
willingness to only compare objects of the same type, because they
smell to Python like numeric types.
Revision 1.17 1997/11/13 21:05:35 jim Revision 1.17 1997/11/13 21:05:35 jim
Fixed some bad return values. Fixed some bad return values.
......
/* /*
$Id: ExtensionClass.c,v 1.17 1997/11/13 21:05:35 jim Exp $ $Id: ExtensionClass.c,v 1.18 1997/12/11 16:00:22 jim Exp $
Extension Class Extension Class
...@@ -65,7 +65,7 @@ static char ExtensionClass_module_documentation[] = ...@@ -65,7 +65,7 @@ static char ExtensionClass_module_documentation[] =
" - They provide access to unbound methods,\n" " - They provide access to unbound methods,\n"
" - They can be called to create instances.\n" " - They can be called to create instances.\n"
"\n" "\n"
"$Id: ExtensionClass.c,v 1.17 1997/11/13 21:05:35 jim Exp $\n" "$Id: ExtensionClass.c,v 1.18 1997/12/11 16:00:22 jim Exp $\n"
; ;
#include <stdio.h> #include <stdio.h>
...@@ -110,10 +110,11 @@ static PyObject *py__add__, *py__sub__, *py__mul__, *py__div__, ...@@ -110,10 +110,11 @@ static PyObject *py__add__, *py__sub__, *py__mul__, *py__div__,
*py__getitem__, *py__setitem__, *py__delitem__, *py__getitem__, *py__setitem__, *py__delitem__,
*py__getslice__, *py__setslice__, *py__delslice__, *py__len__, *py__getslice__, *py__setslice__, *py__delslice__, *py__len__,
*py__getattr__, *py__setattr__, *py__delattr__, *py__getattr__, *py__setattr__, *py__delattr__,
*py__del__, *py__repr__, *py__str__, *py__class__, *py__del__, *py__repr__, *py__str__, *py__class__, *py__name__,
*py__hash__, *py__cmp__, *py__var_size__, *py__init__, *py__getinitargs__, *py__hash__, *py__cmp__, *py__var_size__, *py__init__, *py__getinitargs__,
*py__getstate__, *py__setstate__, *py__dict__, *pyclass_; *py__getstate__, *py__setstate__, *py__dict__, *pyclass_;
static PyObject *concat_fmt=0;
static PyObject *subclass_watcher=0; /* Object that subclass events */ static PyObject *subclass_watcher=0; /* Object that subclass events */
static void static void
...@@ -160,6 +161,7 @@ init_py_names() ...@@ -160,6 +161,7 @@ init_py_names()
INIT_PY_NAME(__repr__); INIT_PY_NAME(__repr__);
INIT_PY_NAME(__str__); INIT_PY_NAME(__str__);
INIT_PY_NAME(__class__); INIT_PY_NAME(__class__);
INIT_PY_NAME(__name__);
INIT_PY_NAME(__hash__); INIT_PY_NAME(__hash__);
INIT_PY_NAME(__cmp__); INIT_PY_NAME(__cmp__);
INIT_PY_NAME(__var_size__); INIT_PY_NAME(__var_size__);
...@@ -196,7 +198,6 @@ typedef struct { ...@@ -196,7 +198,6 @@ typedef struct {
PyCFunction meth; PyCFunction meth;
int flags; int flags;
char *doc; char *doc;
PyObject *dict;
} CMethod; } CMethod;
staticforward PyTypeObject CMethodType; staticforward PyTypeObject CMethodType;
...@@ -361,7 +362,6 @@ newCMethod(PyExtensionClass *type, PyObject *inst, ...@@ -361,7 +362,6 @@ newCMethod(PyExtensionClass *type, PyObject *inst,
self->meth=meth; self->meth=meth;
self->flags=flags; self->flags=flags;
self->doc=doc; self->doc=doc;
self->dict=NULL;
return (PyObject*)self; return (PyObject*)self;
} }
...@@ -389,8 +389,6 @@ bindCMethod(CMethod *m, PyObject *inst) ...@@ -389,8 +389,6 @@ bindCMethod(CMethod *m, PyObject *inst)
self->meth=m->meth; self->meth=m->meth;
self->flags=m->flags; self->flags=m->flags;
self->doc=m->doc; self->doc=m->doc;
self->dict=m->dict;
Py_XINCREF(self->dict);
return self; return self;
} }
...@@ -402,7 +400,6 @@ CMethod_dealloc(CMethod *self) ...@@ -402,7 +400,6 @@ CMethod_dealloc(CMethod *self)
#endif #endif
Py_XDECREF(self->type); Py_XDECREF(self->type);
Py_XDECREF(self->self); Py_XDECREF(self->self);
Py_XDECREF(self->dict);
PyMem_DEL(self); PyMem_DEL(self);
} }
...@@ -517,6 +514,15 @@ CMethod_getattro(CMethod *self, PyObject *oname) ...@@ -517,6 +514,15 @@ CMethod_getattro(CMethod *self, PyObject *oname)
char *name; char *name;
UNLESS(name=PyString_AsString(oname)) return NULL; UNLESS(name=PyString_AsString(oname)) return NULL;
if (name[0] != '_' && name[0] && name[1] != '_' &&
PyEval_GetRestricted())
{
PyErr_SetString(PyExc_RuntimeError,
"function attributes not accessible in restricted mode");
return NULL;
}
if(strcmp(name,"__name__")==0 || strcmp(name,"func_name")==0 ) if(strcmp(name,"__name__")==0 || strcmp(name,"func_name")==0 )
return PyString_FromString(self->name); return PyString_FromString(self->name);
if(strcmp(name,"func_code")==0 || if(strcmp(name,"func_code")==0 ||
...@@ -547,7 +553,14 @@ CMethod_getattro(CMethod *self, PyObject *oname) ...@@ -547,7 +553,14 @@ CMethod_getattro(CMethod *self, PyObject *oname)
} }
} }
if(self->dict && (r=PyObject_GetItem(self->dict, oname))) return r; if(self->self) /* Psuedo attributes */
{
UNLESS(oname=Py_BuildValue("sO", self->name, oname)) return NULL;
UNLESS_ASSIGN(oname,PyString_Format(concat_fmt, oname)) return NULL;
r=PyObject_GetAttr(self->self, oname);
Py_DECREF(oname);
return r;
}
PyErr_SetObject(PyExc_AttributeError, oname); PyErr_SetObject(PyExc_AttributeError, oname);
return NULL; return NULL;
...@@ -556,9 +569,19 @@ CMethod_getattro(CMethod *self, PyObject *oname) ...@@ -556,9 +569,19 @@ CMethod_getattro(CMethod *self, PyObject *oname)
static int static int
CMethod_setattro(CMethod *self, PyObject *oname, PyObject *v) CMethod_setattro(CMethod *self, PyObject *oname, PyObject *v)
{ {
if(! self->dict && ! (self->dict=PyDict_New())) return -1; int r;
if(self->self && ! PyEval_GetRestricted()) /* Psuedo attributes */
{
UNLESS(oname=Py_BuildValue("sO", self->name, oname)) return NULL;
UNLESS_ASSIGN(oname,PyString_Format(concat_fmt, oname)) return NULL;
r=PyObject_SetAttr(self->self, oname, v);
Py_DECREF(oname);
return r;
}
return PyDict_SetItem(self->dict, oname, v); PyErr_SetObject(PyExc_AttributeError, oname);
return -1;
} }
static PyTypeObject CMethodType = { static PyTypeObject CMethodType = {
...@@ -769,6 +792,14 @@ PMethod_getattro(PMethod *self, PyObject *oname) ...@@ -769,6 +792,14 @@ PMethod_getattro(PMethod *self, PyObject *oname)
UNLESS(name=PyString_AsString(oname)) return NULL; UNLESS(name=PyString_AsString(oname)) return NULL;
if (name[0] != '_' && name[0] && name[1] != '_' &&
PyEval_GetRestricted())
{
PyErr_SetString(PyExc_RuntimeError,
"function attributes not accessible in restricted mode");
return NULL;
}
if(*name++=='i' && *name++=='m' && *name++=='_') if(*name++=='i' && *name++=='m' && *name++=='_')
{ {
if(strcmp(name,"func")==0) if(strcmp(name,"func")==0)
...@@ -791,9 +822,50 @@ PMethod_getattro(PMethod *self, PyObject *oname) ...@@ -791,9 +822,50 @@ PMethod_getattro(PMethod *self, PyObject *oname)
} }
} }
if(self->self && self->meth) /* Psuedo attrs */
{
PyObject *myname;
UNLESS(myname=PyObject_GetAttr(self->meth, py__name__)) return NULL;
oname=Py_BuildValue("OO", myname, oname);
Py_DECREF(myname);
UNLESS(oname) return NULL;
UNLESS_ASSIGN(oname,PyString_Format(concat_fmt, oname)) return NULL;
r=PyObject_GetAttr(self->self, oname);
Py_DECREF(oname);
return r;
}
PyErr_SetObject(PyExc_AttributeError, oname);
return NULL;
return PyObject_GetAttr(self->meth, oname); return PyObject_GetAttr(self->meth, oname);
} }
static int
PMethod_setattro(PMethod *self, PyObject *oname, PyObject *v)
{
int r;
if(self->self && self->meth && ! PyEval_GetRestricted()) /* Psuedo attrs */
{
PyObject *myname;
UNLESS(myname=PyObject_GetAttr(self->meth, py__name__)) return NULL;
oname=Py_BuildValue("OO", myname, oname);
Py_DECREF(myname);
UNLESS(oname) return NULL;
UNLESS_ASSIGN(oname,PyString_Format(concat_fmt, oname)) return NULL;
r=PyObject_SetAttr(self->self, oname, v);
Py_DECREF(oname);
return r;
}
PyErr_SetObject(PyExc_AttributeError, oname);
return -1;
}
static PyTypeObject PMethodType = { static PyTypeObject PMethodType = {
PyObject_HEAD_INIT(NULL) PyObject_HEAD_INIT(NULL)
0, /*ob_size*/ 0, /*ob_size*/
...@@ -814,9 +886,10 @@ static PyTypeObject PMethodType = { ...@@ -814,9 +886,10 @@ static PyTypeObject PMethodType = {
(ternaryfunc)PMethod_call, /*tp_call*/ (ternaryfunc)PMethod_call, /*tp_call*/
(reprfunc)0, /*tp_str*/ (reprfunc)0, /*tp_str*/
(getattrofunc)PMethod_getattro, /*tp_getattro*/ (getattrofunc)PMethod_getattro, /*tp_getattro*/
(setattrofunc)PMethod_setattro, /* tp_setattro */
/* Space for future expansion */ /* Space for future expansion */
0L,0L,0L, 0L,0L,
"Storage manager for unbound C function PyObject data" "Storage manager for unbound C function PyObject data"
/* Documentation string */ /* Documentation string */
}; };
...@@ -1181,7 +1254,12 @@ EC_reduce(PyObject *self, PyObject *args) ...@@ -1181,7 +1254,12 @@ EC_reduce(PyObject *self, PyObject *args)
else else
{ {
PyErr_Clear(); PyErr_Clear();
args=PyTuple_New(0); if(ExtensionClassOf(self)->class_flags & EXTENSIONCLASS_BASICNEW_FLAG)
{
args=Py_None;
Py_INCREF(args);
}
else args=PyTuple_New(0);
} }
if((state=PyObject_GetAttr(self,py__getstate__))) if((state=PyObject_GetAttr(self,py__getstate__)))
...@@ -1244,6 +1322,58 @@ inheritedAttribute(PyObject *self, PyObject *args) ...@@ -1244,6 +1322,58 @@ inheritedAttribute(PyObject *self, PyObject *args)
return name; return name;
} }
static PyObject *
basicnew(PyExtensionClass *self, PyObject *args)
{
PyObject *inst=0;
typedef struct { PyObject_VAR_HEAD } PyVarObject__;
if(! self->tp_dealloc)
{
PyErr_SetString(PyExc_TypeError,
"Attempt to create instance of an abstract type");
return NULL;
}
if(self->tp_itemsize)
{
/* We have a variable-sized object, we need to get it's size */
PyObject *var_size;
int size;
UNLESS(var_size=CCL_getattr(self,py__var_size__, 0)) return NULL;
UNLESS_ASSIGN(var_size,PyObject_CallObject(var_size,NULL)) return NULL;
size=PyInt_AsLong(var_size);
if(PyErr_Occurred()) return NULL;
UNLESS(inst=PyObject_NEW_VAR(PyObject,(PyTypeObject *)self, size))
return NULL;
memset(inst,0,self->tp_basicsize+self->tp_itemsize*size);
((PyVarObject__*)inst)->ob_size=size;
}
else
{
UNLESS(inst=PyObject_NEW(PyObject,(PyTypeObject *)self)) return NULL;
memset(inst,0,self->tp_basicsize);
}
inst->ob_refcnt=1;
inst->ob_type=(PyTypeObject *)self;
Py_INCREF(self);
if(ClassHasInstDict(self))
UNLESS(INSTANCE_DICT(inst)=PyDict_New()) goto err;
if(self->bases && subclass_watcher &&
! PyObject_CallMethod(subclass_watcher,"created","O",inst))
PyErr_Clear();
return inst;
err:
Py_DECREF(inst);
return NULL;
}
struct PyMethodDef ECI_methods[] = { struct PyMethodDef ECI_methods[] = {
{"__reduce__",(PyCFunction)EC_reduce,0, {"__reduce__",(PyCFunction)EC_reduce,0,
"__reduce__() -- Reduce an instance into it's class and creation data" "__reduce__() -- Reduce an instance into it's class and creation data"
...@@ -1520,6 +1650,26 @@ CCL_getattro(PyExtensionClass *self, PyObject *name) ...@@ -1520,6 +1650,26 @@ CCL_getattro(PyExtensionClass *self, PyObject *name)
if(strcmp(n,"name__")==0) if(strcmp(n,"name__")==0)
return PyString_FromString(self->tp_name); return PyString_FromString(self->tp_name);
break; break;
case 'b':
if(self->class_flags & EXTENSIONCLASS_BASICNEW_FLAG &&
strcmp(n,"basicnew__")==0
)
return newCMethod(self,(PyObject*)self,
"__basicnew__",(PyCFunction)basicnew,0,
"__basicnew__() -- "
"Create a new instance without executing it's constructor"
);
else if(strcmp(n,"bases__")==0)
{
if(self->bases)
{
Py_INCREF(self->bases);
return self->bases;
}
else
return PyTuple_New(0);
}
break;
case 'r': case 'r':
if(strcmp(n,"reduce__")==0) if(strcmp(n,"reduce__")==0)
return newCMethod(self,(PyObject*)self, return newCMethod(self,(PyObject*)self,
...@@ -1533,18 +1683,6 @@ CCL_getattro(PyExtensionClass *self, PyObject *name) ...@@ -1533,18 +1683,6 @@ CCL_getattro(PyExtensionClass *self, PyObject *name)
return self->class_dictionary; return self->class_dictionary;
} }
break; break;
case 'b':
if(strcmp(n,"bases__")==0)
{
if(self->bases)
{
Py_INCREF(self->bases);
return self->bases;
}
else
return PyTuple_New(0);
}
break;
} }
} }
} }
...@@ -1709,6 +1847,8 @@ CCL_call(PyExtensionClass *self, PyObject *arg, PyObject *kw) ...@@ -1709,6 +1847,8 @@ CCL_call(PyExtensionClass *self, PyObject *arg, PyObject *kw)
{ {
UNLESS_ASSIGN(var_size,PyObject_CallObject(var_size,arg)) UNLESS_ASSIGN(var_size,PyObject_CallObject(var_size,arg))
return NULL; return NULL;
size=PyInt_AsLong(var_size);
if(PyErr_Occurred()) return NULL;
} }
else else
{ {
...@@ -1733,18 +1873,16 @@ CCL_call(PyExtensionClass *self, PyObject *arg, PyObject *kw) ...@@ -1733,18 +1873,16 @@ CCL_call(PyExtensionClass *self, PyObject *arg, PyObject *kw)
UNLESS(inst=PyObject_NEW_VAR(PyObject,(PyTypeObject *)self, size)) UNLESS(inst=PyObject_NEW_VAR(PyObject,(PyTypeObject *)self, size))
return NULL; return NULL;
memset(inst,0,self->tp_basicsize+self->tp_itemsize*size); memset(inst,0,self->tp_basicsize+self->tp_itemsize*size);
inst->ob_refcnt=1;
inst->ob_type=(PyTypeObject *)self;
((PyVarObject__*)inst)->ob_size=size; ((PyVarObject__*)inst)->ob_size=size;
} }
else else
{ {
UNLESS(inst=PyObject_NEW(PyObject,(PyTypeObject *)self)) return NULL; UNLESS(inst=PyObject_NEW(PyObject,(PyTypeObject *)self)) return NULL;
memset(inst,0,self->tp_basicsize); memset(inst,0,self->tp_basicsize);
inst->ob_refcnt=1;
inst->ob_type=(PyTypeObject *)self;
} }
inst->ob_refcnt=1;
inst->ob_type=(PyTypeObject *)self;
Py_INCREF(self); Py_INCREF(self);
if(ClassHasInstDict(self)) if(ClassHasInstDict(self))
...@@ -1966,7 +2104,12 @@ subclass_compare(PyObject *self, PyObject *v) ...@@ -1966,7 +2104,12 @@ subclass_compare(PyObject *self, PyObject *v)
PyObject *m; PyObject *m;
long r; long r;
UNLESS(m=subclass_getspecial(self,py__cmp__)) return -1; UNLESS(m=subclass_getspecial(self,py__cmp__))
{
PyErr_Clear();
return self-v;
}
if(UnboundCMethod_Check(m) && AsCMethod(m)->meth==compare_by_name if(UnboundCMethod_Check(m) && AsCMethod(m)->meth==compare_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type) && SubclassInstance_Check(self,AsCMethod(m)->type)
&& ! HasMethodHook(self)) && ! HasMethodHook(self))
...@@ -3071,7 +3214,7 @@ void ...@@ -3071,7 +3214,7 @@ void
initExtensionClass() initExtensionClass()
{ {
PyObject *m, *d; PyObject *m, *d;
char *rev="$Revision: 1.17 $"; char *rev="$Revision: 1.18 $";
PURE_MIXIN_CLASS(Base, "Minimalbase class for Extension Classes", NULL); PURE_MIXIN_CLASS(Base, "Minimalbase class for Extension Classes", NULL);
PMethodType.ob_type=&PyType_Type; PMethodType.ob_type=&PyType_Type;
...@@ -3079,6 +3222,8 @@ initExtensionClass() ...@@ -3079,6 +3222,8 @@ initExtensionClass()
ECTypeType.ob_type=&PyType_Type; ECTypeType.ob_type=&PyType_Type;
ECType.ob_type=&ECTypeType; ECType.ob_type=&ECTypeType;
UNLESS(concat_fmt=PyString_FromString("%s%s"));
m = Py_InitModule4("ExtensionClass", CC_methods, m = Py_InitModule4("ExtensionClass", CC_methods,
ExtensionClass_module_documentation, ExtensionClass_module_documentation,
(PyObject*)NULL,PYTHON_API_VERSION); (PyObject*)NULL,PYTHON_API_VERSION);
...@@ -3110,6 +3255,31 @@ initExtensionClass() ...@@ -3110,6 +3255,31 @@ initExtensionClass()
/**************************************************************************** /****************************************************************************
$Log: ExtensionClass.c,v $ $Log: ExtensionClass.c,v $
Revision 1.18 1997/12/11 16:00:22 jim
Added __basicnew__ class protocol.
Added support for user-defined method attributes. User-defined method
attributes can only be set or accessed for bound methods.
User-defined method attributes are stored in instances under a name
formed by concatinating the method and attribute names. Default
values for user-defined method attributes may be set in the class
statement. For example, to define the default '__roles__' attribute of
a method, 'f'::
class C:
def f(self): print 'f called'
f__roles__=('manage',)
User-defined attributes may not be set in restricted execution mode.
User-defined attribute names may only be accessed in
restricted-execution mode if their names begin with double
underscores.
Added default __cmp__ support for extension subclasses. I only
recently noticed that extension subclasses overcome Python's
willingness to only compare objects of the same type, because they
smell to Python like numeric types.
Revision 1.17 1997/11/13 21:05:35 jim Revision 1.17 1997/11/13 21:05:35 jim
Fixed some bad return values. Fixed some bad return values.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment