Commit 6cc20dbd authored by Jim Fulton's avatar Jim Fulton

Major speed enhancements for attribute lookup and calling special

methods.
parent 4bf47247
/* /*
$Id: ExtensionClass.c,v 1.3 1996/10/24 21:07:49 jim Exp $ $Id: ExtensionClass.c,v 1.4 1996/12/06 17:12:29 jim Exp $
Extension Class Extension Class
...@@ -56,6 +56,10 @@ ...@@ -56,6 +56,10 @@
(540) 371-6909 (540) 371-6909
$Log: ExtensionClass.c,v $ $Log: ExtensionClass.c,v $
Revision 1.4 1996/12/06 17:12:29 jim
Major speed enhancements for attribute lookup and calling special
methods.
Revision 1.3 1996/10/24 21:07:49 jim Revision 1.3 1996/10/24 21:07:49 jim
Fixed bug in returning __bases__ for base classes. Fixed bug in returning __bases__ for base classes.
Added missing PyErr_Clear() call. Added missing PyErr_Clear() call.
...@@ -84,7 +88,7 @@ static char ExtensionClass_module_documentation[] = ...@@ -84,7 +88,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.3 1996/10/24 21:07:49 jim Exp $\n" "$Id: ExtensionClass.c,v 1.4 1996/12/06 17:12:29 jim Exp $\n"
; ;
#include "Python.h" #include "Python.h"
...@@ -102,6 +106,72 @@ typedef struct { PyObject_HEAD } Dataless; ...@@ -102,6 +106,72 @@ typedef struct { PyObject_HEAD } Dataless;
#include "ExtensionClass.h" #include "ExtensionClass.h"
staticforward PyExtensionClass CCLtype; staticforward PyExtensionClass CCLtype;
#define PyExtensionClass_Check(O) ((O)->ob_type == (PyTypeObject*)&CCLtype)
#define PyExtensionInstance_Check(O) \
((O)->ob_type->ob_type == (PyTypeObject*)&CCLtype)
#define AsPyExtensionClass(O) ((PyExtensionClass*)(O))
#define PyExtensionClassOf(O) ((PyExtensionClass*)((O)->ob_type))
#define AsPyObject(O) ((PyObject*)(O))
static PyObject *py__add__, *py__sub__, *py__mul__, *py__div__,
*py__mod__, *py__pow__, *py__divmod__, *py__lshift__, *py__rshift__,
*py__and__, *py__or__, *py__xor__, *py__coerce__, *py__neg__,
*py__pos__, *py__abs__, *py__nonzero__, *py__inv__, *py__int__,
*py__long__, *py__float__, *py__oct__, *py__hex__, *py__getitem__,
*py__setitem__, *py__getslice__, *py__setslice__, *py__concat__,
*py__repeat__, *py__len__, *py__bind_to_object__, *py__call__,
*py__getattr__, *py__setattr__, *py__del__, *py__repr__, *py__str__,
*py__hash__, *py__cmp__, *py__var_size__, *py__init__;
static void
init_py_names()
{
#define INIT_PY_NAME(N) py ## N = PyString_FromString(#N)
INIT_PY_NAME(__add__);
INIT_PY_NAME(__sub__);
INIT_PY_NAME(__mul__);
INIT_PY_NAME(__div__);
INIT_PY_NAME(__mod__);
INIT_PY_NAME(__pow__);
INIT_PY_NAME(__divmod__);
INIT_PY_NAME(__lshift__);
INIT_PY_NAME(__rshift__);
INIT_PY_NAME(__and__);
INIT_PY_NAME(__or__);
INIT_PY_NAME(__xor__);
INIT_PY_NAME(__coerce__);
INIT_PY_NAME(__neg__);
INIT_PY_NAME(__pos__);
INIT_PY_NAME(__abs__);
INIT_PY_NAME(__nonzero__);
INIT_PY_NAME(__inv__);
INIT_PY_NAME(__int__);
INIT_PY_NAME(__long__);
INIT_PY_NAME(__float__);
INIT_PY_NAME(__oct__);
INIT_PY_NAME(__hex__);
INIT_PY_NAME(__getitem__);
INIT_PY_NAME(__setitem__);
INIT_PY_NAME(__getslice__);
INIT_PY_NAME(__setslice__);
INIT_PY_NAME(__concat__);
INIT_PY_NAME(__repeat__);
INIT_PY_NAME(__len__);
INIT_PY_NAME(__bind_to_object__);
INIT_PY_NAME(__call__);
INIT_PY_NAME(__getattr__);
INIT_PY_NAME(__setattr__);
INIT_PY_NAME(__del__);
INIT_PY_NAME(__repr__);
INIT_PY_NAME(__str__);
INIT_PY_NAME(__hash__);
INIT_PY_NAME(__cmp__);
INIT_PY_NAME(__var_size__);
INIT_PY_NAME(__init__);
#undef INIT_PY_NAME
}
/* CMethod objects: */ /* CMethod objects: */
typedef struct { typedef struct {
...@@ -116,6 +186,40 @@ typedef struct { ...@@ -116,6 +186,40 @@ typedef struct {
staticforward PyTypeObject CMethodType; staticforward PyTypeObject CMethodType;
#define CMethod_Check(O) ((O)->ob_type==&CMethodType)
#define UnboundCMethod_Check(O) \
((O)->ob_type==&CMethodType && ! ((CMethod*)(O))->self)
#define AsCMethod(O) ((CMethod*)(O))
static int
CMethod_issubclass(PyExtensionClass *sub, PyExtensionClass *type)
{
int i,l;
PyObject *t;
if(sub==type) return 1;
if(! sub->bases) return 0;
l=PyTuple_Size(sub->bases);
for(i=0; i < l; i++)
{
t=PyTuple_GET_ITEM(sub->bases, i);
if(t==(PyObject*)type) return 1;
if(PyExtensionClass_Check(t)
&& AsPyExtensionClass(t)->bases
&& CMethod_issubclass(AsPyExtensionClass(t),type)
) return 1;
}
return 0;
}
#define Subclass_Check(C1,C2) \
CMethod_issubclass((PyExtensionClass *)(C1), (PyExtensionClass *)(C2))
#define SubclassInstance_Check(C1,C2) \
CMethod_issubclass((PyExtensionClass *)((C1)->ob_type), \
(PyExtensionClass *)(C2))
static CMethod * static CMethod *
newCMethod(PyTypeObject *type, newCMethod(PyTypeObject *type,
char *name, PyCFunction meth, int flags, char *doc) char *name, PyCFunction meth, int flags, char *doc)
...@@ -139,6 +243,15 @@ bindCMethod(CMethod *m, PyObject *inst) ...@@ -139,6 +243,15 @@ bindCMethod(CMethod *m, PyObject *inst)
{ {
CMethod *self; CMethod *self;
UNLESS(inst->ob_type==m->type ||
(PyExtensionInstance_Check(inst)
&& SubclassInstance_Check(inst,m->type))
)
{
Py_INCREF(m);
return m;
}
UNLESS(self = PyObject_NEW(CMethod, &CMethodType)) return NULL; UNLESS(self = PyObject_NEW(CMethod, &CMethodType)) return NULL;
Py_INCREF(inst); Py_INCREF(inst);
...@@ -153,8 +266,7 @@ bindCMethod(CMethod *m, PyObject *inst) ...@@ -153,8 +266,7 @@ bindCMethod(CMethod *m, PyObject *inst)
} }
static void static void
CMethod_dealloc(self) CMethod_dealloc(CMethod *self)
CMethod *self;
{ {
Py_DECREF(self->type); Py_DECREF(self->type);
Py_XDECREF(self->self); Py_XDECREF(self->self);
...@@ -162,11 +274,7 @@ CMethod_dealloc(self) ...@@ -162,11 +274,7 @@ CMethod_dealloc(self)
} }
static PyObject * static PyObject *
call_cmethod(self, inst, args, kw) call_cmethod(CMethod *self, PyObject *inst, PyObject *args, PyObject *kw)
CMethod *self;
PyObject *inst;
PyObject *args;
PyObject *kw;
{ {
if (!(self->flags & METH_VARARGS)) { if (!(self->flags & METH_VARARGS)) {
int size = PyTuple_Size(args); int size = PyTuple_Size(args);
...@@ -189,31 +297,9 @@ call_cmethod(self, inst, args, kw) ...@@ -189,31 +297,9 @@ call_cmethod(self, inst, args, kw)
} }
} }
static int
CMethod_issubclass(PyExtensionClass *sub, PyExtensionClass *type)
{
int i,l;
PyObject *t;
if(! sub->bases) return 0;
l=PyTuple_Size(sub->bases);
for(i=0; i < l; i++)
{
t=PyTuple_GET_ITEM(sub->bases, i);
if(t==(PyObject*)type) return 1;
if(t->ob_type==(PyTypeObject*)&CCLtype
&& ((PyExtensionClass*)t)->bases
&& CMethod_issubclass((PyExtensionClass*)t,type)
) return 1;
}
return 0;
}
static PyObject * static PyObject *
CMethod_call(self,args,kw) CMethod_call(CMethod *self, PyObject *args, PyObject *kw)
CMethod *self;
PyObject *args;
PyObject *kw;
{ {
int size; int size;
char *buf; char *buf;
...@@ -227,10 +313,10 @@ CMethod_call(self,args,kw) ...@@ -227,10 +313,10 @@ CMethod_call(self,args,kw)
UNLESS(first=PyTuple_GET_ITEM(args, 0)) return NULL; UNLESS(first=PyTuple_GET_ITEM(args, 0)) return NULL;
if(first->ob_type==self->type if(first->ob_type==self->type
|| ||
(first->ob_type->ob_type==(PyTypeObject*)&CCLtype (PyExtensionInstance_Check(first)
&& &&
CMethod_issubclass((PyExtensionClass *)(first->ob_type), CMethod_issubclass(PyExtensionClassOf(first),
(PyExtensionClass *)(self->type)) AsPyExtensionClass(self->type))
) )
); );
{ {
...@@ -253,9 +339,7 @@ CMethod_call(self,args,kw) ...@@ -253,9 +339,7 @@ CMethod_call(self,args,kw)
} }
static PyObject * static PyObject *
CMethod_getattr(self,name) CMethod_getattr(CMethod *self, char *name)
CMethod *self;
char *name;
{ {
PyObject *r; PyObject *r;
...@@ -299,7 +383,7 @@ static PyTypeObject CMethodType = { ...@@ -299,7 +383,7 @@ static PyTypeObject CMethodType = {
/* methods */ /* methods */
(destructor)CMethod_dealloc, /*tp_dealloc*/ (destructor)CMethod_dealloc, /*tp_dealloc*/
(printfunc)0, /*tp_print*/ (printfunc)0, /*tp_print*/
(getattrfunc)0, /*tp_getattr*/ (getattrfunc)CMethod_getattr, /*tp_getattr*/
(setattrfunc)0, /*tp_setattr*/ (setattrfunc)0, /*tp_setattr*/
(cmpfunc)0, /*tp_compare*/ (cmpfunc)0, /*tp_compare*/
(reprfunc)0, /*tp_repr*/ (reprfunc)0, /*tp_repr*/
...@@ -316,23 +400,32 @@ static PyTypeObject CMethodType = { ...@@ -316,23 +400,32 @@ static PyTypeObject CMethodType = {
/* Documentation string */ /* Documentation string */
}; };
/* Pmethod objects: */ /* PMethod objects: */
typedef struct { typedef struct {
PyObject_HEAD PyObject_HEAD
PyTypeObject *type; PyTypeObject *type;
PyObject *self; PyObject *self;
PyObject *meth; PyObject *meth;
} Pmethod; } PMethod;
staticforward PyTypeObject PMethodType;
#define PMethod_Check(O) ((O)->ob_type==&PMethodType)
#define UnboundPMethod_Check(O) \
((O)->ob_type==&PMethodType && ! ((PMethod*)(O))->self)
staticforward PyTypeObject PmethodType; #define UnboundEMethod_Check(O) \
(((O)->ob_type==&PMethodType ||(O)->ob_type==&CMethodType) \
&& ! ((PMethod*)(O))->self)
static Pmethod *
newPmethod(PyTypeObject *type, PyObject *meth) static PMethod *
newPMethod(PyTypeObject *type, PyObject *meth)
{ {
Pmethod *self; PMethod *self;
UNLESS(self = PyObject_NEW(Pmethod, &PmethodType)) return NULL; UNLESS(self = PyObject_NEW(PMethod, &PMethodType)) return NULL;
Py_INCREF(type); Py_INCREF(type);
Py_INCREF(meth); Py_INCREF(meth);
self->type=type; self->type=type;
...@@ -341,12 +434,20 @@ newPmethod(PyTypeObject *type, PyObject *meth) ...@@ -341,12 +434,20 @@ newPmethod(PyTypeObject *type, PyObject *meth)
return self; return self;
} }
static Pmethod * static PMethod *
bindPmethod(Pmethod *m, PyObject *inst) bindPMethod(PMethod *m, PyObject *inst)
{ {
Pmethod *self; PMethod *self;
UNLESS(PyExtensionInstance_Check(inst))
{
PyErr_SetString(PyExc_TypeError,
"attempt to wrap extension method using an object that\n"
"is not an extension class instance.");
return NULL;
}
UNLESS(self = PyObject_NEW(Pmethod, &PmethodType)) return NULL; UNLESS(self = PyObject_NEW(PMethod, &PMethodType)) return NULL;
Py_INCREF(inst); Py_INCREF(inst);
Py_INCREF(m->type); Py_INCREF(m->type);
...@@ -357,8 +458,7 @@ bindPmethod(Pmethod *m, PyObject *inst) ...@@ -357,8 +458,7 @@ bindPmethod(Pmethod *m, PyObject *inst)
} }
static void static void
Pmethod_dealloc(self) PMethod_dealloc(PMethod *self)
Pmethod *self;
{ {
Py_DECREF(self->type); Py_DECREF(self->type);
Py_XDECREF(self->self); Py_XDECREF(self->self);
...@@ -366,11 +466,7 @@ Pmethod_dealloc(self) ...@@ -366,11 +466,7 @@ Pmethod_dealloc(self)
} }
static PyObject * static PyObject *
call_pmethod(self, inst, args, kw) call_PMethod(PMethod *self, PyObject *inst, PyObject *args, PyObject *kw)
Pmethod *self;
PyObject *inst;
PyObject *args;
PyObject *kw;
{ {
PyObject *a; PyObject *a;
...@@ -381,16 +477,13 @@ call_pmethod(self, inst, args, kw) ...@@ -381,16 +477,13 @@ call_pmethod(self, inst, args, kw)
} }
static PyObject * static PyObject *
Pmethod_call(self,args,kw) PMethod_call(PMethod *self, PyObject *args, PyObject *kw)
Pmethod *self;
PyObject *args;
PyObject *kw;
{ {
int size; int size;
char *buf; char *buf;
PyObject *s; PyObject *s;
if(self->self) return call_pmethod(self,self->self,args,kw); if(self->self) return call_PMethod(self,self->self,args,kw);
if((size=PyTuple_Size(args)) > 0) if((size=PyTuple_Size(args)) > 0)
{ {
...@@ -398,16 +491,16 @@ Pmethod_call(self,args,kw) ...@@ -398,16 +491,16 @@ Pmethod_call(self,args,kw)
UNLESS(first=PyTuple_GET_ITEM(args, 0)) return NULL; UNLESS(first=PyTuple_GET_ITEM(args, 0)) return NULL;
if(first->ob_type==self->type if(first->ob_type==self->type
|| ||
(first->ob_type->ob_type==(PyTypeObject*)&CCLtype (PyExtensionInstance_Check(first)
&& &&
CMethod_issubclass((PyExtensionClass *)(first->ob_type), CMethod_issubclass(PyExtensionClassOf(first),
(PyExtensionClass *)(self->type)) AsPyExtensionClass(self->type))
) )
); );
{ {
PyObject *rest=0; PyObject *rest=0;
UNLESS(rest=PySequence_GetSlice(args,1,size)) return NULL; UNLESS(rest=PySequence_GetSlice(args,1,size)) return NULL;
return call_pmethod(self,first,rest,kw); return call_PMethod(self,first,rest,kw);
} }
} }
...@@ -424,9 +517,7 @@ Pmethod_call(self,args,kw) ...@@ -424,9 +517,7 @@ Pmethod_call(self,args,kw)
} }
static PyObject * static PyObject *
Pmethod_getattr(self,name) PMethod_getattr(PMethod *self, char *name)
Pmethod *self;
char *name;
{ {
PyObject *r; PyObject *r;
...@@ -455,16 +546,16 @@ Pmethod_getattr(self,name) ...@@ -455,16 +546,16 @@ Pmethod_getattr(self,name)
} }
} }
static PyTypeObject PmethodType = { static PyTypeObject PMethodType = {
PyObject_HEAD_INIT(&PyType_Type) PyObject_HEAD_INIT(&PyType_Type)
0, /*ob_size*/ 0, /*ob_size*/
"Python Method", /*tp_name*/ "Python Method", /*tp_name*/
sizeof(Pmethod), /*tp_basicsize*/ sizeof(PMethod), /*tp_basicsize*/
0, /*tp_itemsize*/ 0, /*tp_itemsize*/
/* methods */ /* methods */
(destructor)Pmethod_dealloc, /*tp_dealloc*/ (destructor)PMethod_dealloc, /*tp_dealloc*/
(printfunc)0, /*tp_print*/ (printfunc)0, /*tp_print*/
(getattrfunc)0, /*tp_getattr*/ (getattrfunc)PMethod_getattr, /*tp_getattr*/
(setattrfunc)0, /*tp_setattr*/ (setattrfunc)0, /*tp_setattr*/
(cmpfunc)0, /*tp_compare*/ (cmpfunc)0, /*tp_compare*/
(reprfunc)0, /*tp_repr*/ (reprfunc)0, /*tp_repr*/
...@@ -472,7 +563,7 @@ static PyTypeObject PmethodType = { ...@@ -472,7 +563,7 @@ static PyTypeObject PmethodType = {
0, /*tp_as_sequence*/ 0, /*tp_as_sequence*/
0, /*tp_as_mapping*/ 0, /*tp_as_mapping*/
(hashfunc)0, /*tp_hash*/ (hashfunc)0, /*tp_hash*/
(ternaryfunc)Pmethod_call, /*tp_call*/ (ternaryfunc)PMethod_call, /*tp_call*/
(reprfunc)0, /*tp_str*/ (reprfunc)0, /*tp_str*/
/* Space for future expansion */ /* Space for future expansion */
...@@ -537,6 +628,28 @@ setattr_by_name(PyObject *self, PyObject *args) ...@@ -537,6 +628,28 @@ setattr_by_name(PyObject *self, PyObject *args)
return Py_None; return Py_None;
} }
#if PYTHON_API_VERSION >= 1005
static PyObject *
getattro_by_name(PyObject *self, PyObject *args)
{
PyObject *name;
UNLESS(PyArg_Parse(args,"O",&name)) return NULL;
return self->ob_type->tp_getattro(self,name);
}
static PyObject *
setattro_by_name(PyObject *self, PyObject *args)
{
PyObject *name;
PyObject *v;
UNLESS(PyArg_Parse(args,"OO",&name,&v)) return NULL;
UNLESS(-1 != self->ob_type->tp_setattro(self,name,v)) return NULL;
Py_INCREF(Py_None);
return Py_None;
}
#endif
static PyObject * static PyObject *
length_by_name(PyObject *self, PyObject *args) length_by_name(PyObject *self, PyObject *args)
...@@ -725,6 +838,12 @@ getBaseDictionary(PyExtensionClass *type) ...@@ -725,6 +838,12 @@ getBaseDictionary(PyExtensionClass *type)
FILLENTRY(type->tp, compare, comp, 0, "compare with another object"); FILLENTRY(type->tp, compare, comp, 0, "compare with another object");
FILLENTRY(type->tp, getattr, getattr, 0, "Get an attribute"); FILLENTRY(type->tp, getattr, getattr, 0, "Get an attribute");
FILLENTRY(type->tp, setattr, setattr, 0, "Set an attribute"); FILLENTRY(type->tp, setattr, setattr, 0, "Set an attribute");
#if PYTHON_API_VERSION >= 1005
FILLENTRY(type->tp, getattro, getattr, 0, "Get an attribute");
FILLENTRY(type->tp, setattro, setattr, 0, "Set an attribute");
#endif
if(sm=type->tp_as_sequence) if(sm=type->tp_as_sequence)
{ {
FILLENTRY(sm->sq, length, len, 0, "Get the object length"); FILLENTRY(sm->sq, length, len, 0, "Get the object length");
...@@ -837,8 +956,7 @@ initializeBaseExtensionClass(PyExtensionClass *self) ...@@ -837,8 +956,7 @@ initializeBaseExtensionClass(PyExtensionClass *self)
} }
static void static void
CCL_dealloc(self) CCL_dealloc(PyExtensionClass *self)
PyExtensionClass *self;
{ {
Py_XDECREF(self->class_dictionary); Py_XDECREF(self->class_dictionary);
Py_XDECREF(self->bases); Py_XDECREF(self->bases);
...@@ -849,9 +967,8 @@ CCL_dealloc(self) ...@@ -849,9 +967,8 @@ CCL_dealloc(self)
static PyObject *CCL_getattr(); static PyObject *CCL_getattr();
static PyObject * static PyObject *
ExtensionClass_FindInstanceAttribute(inst,name) ExtensionClass_FindInstanceAttribute(PyObject *inst, PyObject *oname,
PyObject *inst; char *name)
char *name;
{ {
/* Look up an attribute for an instance from: /* Look up an attribute for an instance from:
...@@ -862,6 +979,8 @@ ExtensionClass_FindInstanceAttribute(inst,name) ...@@ -862,6 +979,8 @@ ExtensionClass_FindInstanceAttribute(inst,name)
PyObject *r=0; PyObject *r=0;
PyExtensionClass *self; PyExtensionClass *self;
if(! name) return NULL;
self=(PyExtensionClass*)(inst->ob_type); self=(PyExtensionClass*)(inst->ob_type);
if(*name=='_' && name[1]=='_') if(*name=='_' && name[1]=='_')
...@@ -882,25 +1001,25 @@ ExtensionClass_FindInstanceAttribute(inst,name) ...@@ -882,25 +1001,25 @@ ExtensionClass_FindInstanceAttribute(inst,name)
if(self->bases) if(self->bases)
{ {
r= INSTANCE_DICT(inst); r= INSTANCE_DICT(inst);
r = PyMapping_GetItemString(r,name); r = PyObject_GetItem(r,oname);
} }
UNLESS(r) UNLESS(r)
{ {
PyErr_Clear(); PyErr_Clear();
UNLESS(r=CCL_getattr(self,name)) return NULL; UNLESS(r=CCL_getattr(self,oname,name)) return NULL;
/* We got something from our class, maybe its an unbound method. */ /* We got something from our class, maybe its an unbound method. */
if(r->ob_type==&CMethodType) if(UnboundCMethod_Check(r))
{ {
UNLESS_ASSIGN(r,(PyObject*)bindCMethod((CMethod*)r,inst)) UNLESS_ASSIGN(r,(PyObject*)bindCMethod((CMethod*)r,inst))
return NULL; return NULL;
} }
if(r->ob_type==&PmethodType) else if(UnboundPMethod_Check(r))
{ {
PyObject *m; PyObject *m;
m=((Pmethod *)r)->meth; m=((PMethod *)r)->meth;
if(m->ob_type->ob_type==(PyTypeObject*)&CCLtype && if(PyExtensionInstance_Check(m) &&
(((PyExtensionClass*)m->ob_type)->class_flags & (PyExtensionClassOf(m)->class_flags &
EXTENSIONCLASS_BINDABLE_FLAG EXTENSIONCLASS_BINDABLE_FLAG
) )
) )
...@@ -911,7 +1030,7 @@ ExtensionClass_FindInstanceAttribute(inst,name) ...@@ -911,7 +1030,7 @@ ExtensionClass_FindInstanceAttribute(inst,name)
} }
else else
{ {
UNLESS_ASSIGN(r,(PyObject*)bindPmethod((Pmethod*)r,inst)) UNLESS_ASSIGN(r,(PyObject*)bindPMethod((PMethod*)r,inst))
return NULL; return NULL;
} }
} }
...@@ -921,19 +1040,47 @@ ExtensionClass_FindInstanceAttribute(inst,name) ...@@ -921,19 +1040,47 @@ ExtensionClass_FindInstanceAttribute(inst,name)
} }
static PyObject * static PyObject *
CCL_getattr(self, name) EC_findiattrs(PyObject *self, char *name)
PyExtensionClass *self; {
char *name; PyObject *s, *r;
UNLESS(s=PyString_FromString(name)) return NULL;
r=ExtensionClass_FindInstanceAttribute(self,s,name);
Py_DECREF(s);
return r;
}
static PyObject *
EC_findiattro(PyObject *self, PyObject *name)
{
return ExtensionClass_FindInstanceAttribute(self,name,
PyString_AsString(name));
}
static int
subclass_simple_setattr(PyObject *self, char *name, PyObject *v);
static PyObject *
CCL_getattr(PyExtensionClass *self, PyObject *oname, char *name)
{ {
PyObject *r; PyObject *r;
int local=1; int local=1;
char *n;
if(*name=='.' && name[1]==0) if(! name) return NULL;
return (PyObject*)ExtensionClass_FindInstanceAttribute;
if(*name=='.')
{
n=name+1;
if(*n==0)
return (PyObject*)EC_findiattrs;
if(*n=='o' && n[1]==0)
return (PyObject*)EC_findiattro;
if(*n=='s' && n[1]==0)
return (PyObject*)subclass_simple_setattr;
}
if(*name=='_' && name[1]=='_') if(*name=='_' && name[1]=='_')
{ {
char *n;
n=name+2; n=name+2;
if(strcmp(n,"doc__")==0 && self->tp_doc) if(strcmp(n,"doc__")==0 && self->tp_doc)
return PyString_FromString(self->tp_doc); return PyString_FromString(self->tp_doc);
...@@ -956,7 +1103,7 @@ CCL_getattr(self, name) ...@@ -956,7 +1103,7 @@ CCL_getattr(self, name)
} }
} }
r=PyMapping_GetItemString(self->class_dictionary,name); r=PyObject_GetItem(self->class_dictionary,oname);
UNLESS(r) UNLESS(r)
{ {
local=0; local=0;
...@@ -970,7 +1117,7 @@ CCL_getattr(self, name) ...@@ -970,7 +1117,7 @@ CCL_getattr(self, name)
{ {
PyErr_Clear(); PyErr_Clear();
c=PyTuple_GET_ITEM(self->bases, i); c=PyTuple_GET_ITEM(self->bases, i);
if(r=PyObject_GetAttrString(c,name)) break; if(r=PyObject_GetAttr(c,oname)) break;
} }
} }
UNLESS(r) UNLESS(r)
...@@ -979,9 +1126,7 @@ CCL_getattr(self, name) ...@@ -979,9 +1126,7 @@ CCL_getattr(self, name)
char *s; char *s;
PyErr_Fetch(&t,&v,&tb); PyErr_Fetch(&t,&v,&tb);
if(t==PyExc_KeyError && if(t==PyExc_KeyError && PyObject_Compare(v,oname) == 0)
PyString_Check(v) && (s=PyString_AsString(v))
&& strcmp(s,name)==0)
{ {
Py_DECREF(t); Py_DECREF(t);
t=PyExc_AttributeError; t=PyExc_AttributeError;
...@@ -993,25 +1138,46 @@ CCL_getattr(self, name) ...@@ -993,25 +1138,46 @@ CCL_getattr(self, name)
} }
if(PyFunction_Check(r) || if(PyFunction_Check(r) ||
(r->ob_type->ob_type==(PyTypeObject*)&CCLtype && (PyExtensionInstance_Check(r) &&
(((PyExtensionClass*)r->ob_type)->class_flags & (PyExtensionClassOf(r)->class_flags &
EXTENSIONCLASS_BINDABLE_FLAG EXTENSIONCLASS_BINDABLE_FLAG
) )
) )
) )
UNLESS_ASSIGN(r,(PyObject*)newPmethod((PyTypeObject *)self,r)) {
UNLESS_ASSIGN(r,(PyObject*)newPMethod((PyTypeObject *)self,r))
return NULL; return NULL;
}
if(PyMethod_Check(r) && ! PyMethod_Self(r)) else if(PyMethod_Check(r) && ! PyMethod_Self(r))
UNLESS_ASSIGN(r,(PyObject*)newPmethod((PyTypeObject *)self, {
UNLESS_ASSIGN(r,(PyObject*)newPMethod((PyTypeObject *)self,
PyMethod_Function(r))) PyMethod_Function(r)))
return NULL; return NULL;
}
else local=0;
if(local) /* We have a PMethod that we built from our dict, cache it */
{
UNLESS(-1 != PyObject_SetItem(self->class_dictionary, oname, r))
PyErr_Clear(); /* Oh well */
}
return r;
}
PyObject *
CCL_getattrs(PyExtensionClass *self, char *name)
{
PyObject *s, *r;
UNLESS(s=PyString_FromString(name)) return NULL;
r=CCL_getattr(self,s,name);
Py_DECREF(s);
return r; return r;
} }
static int static int
CCL_setattr(self, name, v) CCL_setattrs(self, name, v)
PyExtensionClass *self; PyExtensionClass *self;
char *name; char *name;
PyObject *v; PyObject *v;
...@@ -1019,10 +1185,138 @@ CCL_setattr(self, name, v) ...@@ -1019,10 +1185,138 @@ CCL_setattr(self, name, v)
return PyMapping_SetItemString(self->class_dictionary, name, v); return PyMapping_SetItemString(self->class_dictionary, name, v);
} }
PyObject *
CCL_getattro(PyExtensionClass *self, PyObject *name)
{
return CCL_getattr(self,name,PyString_AsString(name));
}
static int
CCL_setattro(PyExtensionClass *self, PyObject *name, PyObject *v)
{
if(UnboundCMethod_Check(v))
{
char *n;
PyNumberMethods *nm;
PySequenceMethods *s, *ms;
PyMappingMethods *m, *mm;
UNLESS(n=PyString_AsString(name)) return -1;
if(*n=='_' && n[1]=='_')
{
n+=2;
#define SET_SPECIAL(C,P) \
if(strcmp(n,#P "__")==0 \
&& AsCMethod(v)->meth==(PyCFunction)C ## _by_name \
&& Subclass_Check(self,AsCMethod(v)->type)) { \
self->tp_ ## C=AsCMethod(v)->type->tp_ ## C; \
return PyObject_SetItem(self->class_dictionary, name, v); }
/*
SET_SPECIAL(setattr,setattr);
SET_SPECIAL(setattro,setattr);
*/
SET_SPECIAL(compare,cmp);
SET_SPECIAL(hash,hash);
SET_SPECIAL(repr,repr);
SET_SPECIAL(call,call);
SET_SPECIAL(str,str);
#undef SET_SPECIAL
#define SET_SPECIAL(C,P) \
if(strcmp(n,#P "__")==0 && AsCMethod(v)->meth==C ## _by_name \
&& Subclass_Check(self,AsCMethod(v)->type) \
&& (nm=self->tp_as_number)) { \
nm->nb_ ## C=AsCMethod(v)->type->tp_as_number->nb_ ## C; \
return PyObject_SetItem(self->class_dictionary, name, v); }
SET_SPECIAL(add,add);
SET_SPECIAL(subtract,sub);
SET_SPECIAL(multiply,mult);
SET_SPECIAL(divide,div);
SET_SPECIAL(remainder,mod);
SET_SPECIAL(power,pow);
SET_SPECIAL(divmod,divmod);
SET_SPECIAL(lshift,lshift);
SET_SPECIAL(rshift,rshift);
SET_SPECIAL(and,and);
SET_SPECIAL(or,or);
SET_SPECIAL(xor,xor);
SET_SPECIAL(coerce,coerce);
SET_SPECIAL(negative,neg);
SET_SPECIAL(positive,pos);
SET_SPECIAL(absolute,abs);
SET_SPECIAL(nonzero,nonzero);
SET_SPECIAL(invert,inv);
SET_SPECIAL(int,int);
SET_SPECIAL(long,long);
SET_SPECIAL(float,float);
SET_SPECIAL(oct,oct);
SET_SPECIAL(hex,hex);
#undef SET_SPECIAL
if(strcmp(n,"len__")==0 && AsCMethod(v)->meth==length_by_name
&& Subclass_Check(self,AsCMethod(v)->type))
{
if((s=self->tp_as_sequence) &&
(ms=AsCMethod(v)->type->tp_as_sequence) &&
ms->sq_length)
s->sq_length=ms->sq_length;
if((m=self->tp_as_mapping) &&
(mm=AsCMethod(v)->type->tp_as_mapping) &&
mm->mp_length)
m->mp_length=mm->mp_length;
return PyObject_SetItem(self->class_dictionary, name, v);
}
if(strcmp(n,"getitem__")==0 && AsCMethod(v)->meth==getitem_by_name
&& Subclass_Check(self,AsCMethod(v)->type))
{
if((s=self->tp_as_sequence) &&
(ms=AsCMethod(v)->type->tp_as_sequence) &&
ms->sq_item)
s->sq_item=ms->sq_item;
if((m=self->tp_as_mapping) &&
(mm=AsCMethod(v)->type->tp_as_mapping) &&
mm->mp_subscript)
m->mp_subscript=mm->mp_subscript;
return PyObject_SetItem(self->class_dictionary, name, v);
}
if(strcmp(n,"setitem__")==0 &&
AsCMethod(v)->meth==(PyCFunction)setitem_by_name
&& Subclass_Check(self,AsCMethod(v)->type))
{
if((s=self->tp_as_sequence) &&
(ms=AsCMethod(v)->type->tp_as_sequence) &&
ms->sq_ass_item)
s->sq_ass_item=ms->sq_ass_item;
if((m=self->tp_as_mapping) &&
(mm=AsCMethod(v)->type->tp_as_mapping) &&
mm->mp_ass_subscript)
m->mp_ass_subscript=mm->mp_ass_subscript;
return PyObject_SetItem(self->class_dictionary, name, v);
}
#define SET_SPECIAL(C,P) \
if(strcmp(n,#P "__")==0 \
&& AsCMethod(v)->meth==(PyCFunction)C ## _by_name \
&& Subclass_Check(self,AsCMethod(v)->type) \
&& (s=self->tp_as_sequence)) { \
s->sq_ ## C=AsCMethod(v)->type->tp_as_sequence->sq_ ## C; \
return PyObject_SetItem(self->class_dictionary, name, v); }
SET_SPECIAL(slice,getslice);
SET_SPECIAL(ass_slice,setslice);
SET_SPECIAL(concat,concat);
SET_SPECIAL(repeat,repeat);
#undef SET_SPECIAL
}
}
return PyObject_SetItem(self->class_dictionary, name, v);
}
static PyObject * static PyObject *
CCL_call(self, arg, kw) CCL_call(PyExtensionClass *self, PyObject *arg, PyObject *kw)
PyExtensionClass *self;
PyObject *arg, *kw;
{ {
PyObject *inst=0, *init=0, *args=0; PyObject *inst=0, *init=0, *args=0;
int check; int check;
...@@ -1045,7 +1339,7 @@ CCL_call(self, arg, kw) ...@@ -1045,7 +1339,7 @@ CCL_call(self, arg, kw)
PyObject *var_size; PyObject *var_size;
int size; int size;
if(var_size=CCL_getattr(self,"__var_size__")) if(var_size=CCL_getattro(self,py__var_size__))
{ {
UNLESS_ASSIGN(var_size,PyObject_CallObject(var_size,args)) UNLESS_ASSIGN(var_size,PyObject_CallObject(var_size,args))
return NULL; return NULL;
...@@ -1093,7 +1387,7 @@ CCL_call(self, arg, kw) ...@@ -1093,7 +1387,7 @@ CCL_call(self, arg, kw)
if(init=CCL_getattr(self,"__init__")) if(init=CCL_getattro(self,py__init__))
{ {
UNLESS(args=Py_BuildValue("(O)",inst)) goto err; UNLESS(args=Py_BuildValue("(O)",inst)) goto err;
if(arg) UNLESS_ASSIGN(args,PySequence_Concat(args,arg)) goto err; if(arg) UNLESS_ASSIGN(args,PySequence_Concat(args,arg)) goto err;
...@@ -1113,8 +1407,7 @@ err: ...@@ -1113,8 +1407,7 @@ err:
} }
static PyObject * static PyObject *
CCL_repr(self) CCL_repr(PyExtensionClass *self)
PyExtensionClass *self;
{ {
PyObject *s; PyObject *s;
int l; int l;
...@@ -1124,7 +1417,7 @@ CCL_repr(self) ...@@ -1124,7 +1417,7 @@ CCL_repr(self)
l=strlen(self->ob_type->tp_name)+strlen(p); l=strlen(self->ob_type->tp_name)+strlen(p);
UNLESS(s=PyString_FromStringAndSize(NULL,l+22)) return NULL; UNLESS(s=PyString_FromStringAndSize(NULL,l+22)) return NULL;
buf=PyString_AsString(s); buf=PyString_AsString(s);
sprintf(buf,"<extension class %s at %p>",self->tp_name); sprintf(buf,"<extension class %s at %p>", self->tp_name, self);
return s; return s;
} }
...@@ -1137,8 +1430,8 @@ static PyTypeObject CCLtype_class = { ...@@ -1137,8 +1430,8 @@ static PyTypeObject CCLtype_class = {
/* methods */ /* methods */
(destructor)CCL_dealloc, /*tp_dealloc*/ (destructor)CCL_dealloc, /*tp_dealloc*/
(printfunc)0, /*tp_print*/ (printfunc)0, /*tp_print*/
(getattrfunc)CCL_getattr, /*tp_getattr*/ (getattrfunc)CCL_getattrs, /*tp_getattr*/
(setattrfunc)CCL_setattr, /*tp_setattr*/ (setattrfunc)CCL_setattrs, /*tp_setattr*/
(cmpfunc)0, /*tp_compare*/ (cmpfunc)0, /*tp_compare*/
(reprfunc)CCL_repr, /*tp_repr*/ (reprfunc)CCL_repr, /*tp_repr*/
0, /*tp_as_number*/ 0, /*tp_as_number*/
...@@ -1147,9 +1440,14 @@ static PyTypeObject CCLtype_class = { ...@@ -1147,9 +1440,14 @@ static PyTypeObject CCLtype_class = {
(hashfunc)0, /*tp_hash*/ (hashfunc)0, /*tp_hash*/
(ternaryfunc)CCL_call, /*tp_call*/ (ternaryfunc)CCL_call, /*tp_call*/
(reprfunc)0, /*tp_str*/ (reprfunc)0, /*tp_str*/
#if PYTHON_API_VERSION >= 1005
(getattrofunc)CCL_getattro, /*tp_getattr with object key*/
(setattrofunc)CCL_setattro, /*tp_setattr with object key*/
#else
/* Space for future expansion */ /* Space for future expansion */
0L,0L,0L,0L, 0L,0L,
#endif
0L,0L,
"Class of C classes" /* Documentation string */ "Class of C classes" /* Documentation string */
}; };
...@@ -1158,20 +1456,90 @@ static PyTypeObject CCLtype_class = { ...@@ -1158,20 +1456,90 @@ static PyTypeObject CCLtype_class = {
/* subclassing code: */ /* subclassing code: */
static PyObject *
subclass_getspecial(PyObject *inst, PyObject *oname)
{
PyObject *r=0;
PyExtensionClass *self;
self=(PyExtensionClass*)(inst->ob_type);
r= INSTANCE_DICT(inst);
r = PyObject_GetItem(r,oname);
UNLESS(r)
{
PyErr_Clear();
r=CCL_getattr(self,oname,"");
}
return r;
}
static PyObject *
subclass_getattro(PyObject *self, PyObject *name)
{
PyObject *r=0;
if(! name) return NULL;
UNLESS(r=EC_findiattro(self,name))
{
PyErr_Clear();
UNLESS(r=EC_findiattro(self,py__getattr__)) return NULL;
UNLESS_ASSIGN(r,PyObject_CallFunction(r,"O",name)) return NULL;
}
return r;
}
static PyObject *
subclass_getattrs(PyObject *self, char *name)
{
return subclass_getattro(self,PyString_FromString(name));
}
static int static int
subclass_setattr(PyObject *self, char *name, PyObject *v) subclass_simple_setattro(PyObject *self, PyObject *name, PyObject *v)
{
Py_INCREF(v);
return PyDict_SetItem(INSTANCE_DICT(self),name,v);
}
static int
subclass_simple_setattr(PyObject *self, char *name, PyObject *v)
{
Py_INCREF(v);
return PyDict_SetItemString(INSTANCE_DICT(self),name,v);
}
static int
subclass_setattr(PyObject *self, PyObject *oname, char *name, PyObject *v)
{ {
PyObject *m=0, *et, *ev, *etb; PyObject *m=0, *et, *ev, *etb;
UNLESS(m=PyObject_GetAttrString(self,"__setattr__")) if(! name) return -1;
UNLESS(m=subclass_getspecial(self,py__setattr__))
goto default_setattr; goto default_setattr;
if(m->ob_type==&CMethodType && ((CMethod*)m)->meth==setattr_by_name) if(UnboundCMethod_Check(m) && AsCMethod(m)->meth==setattr_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type))
{ {
UNLESS(-1 != ((CMethod*)m)->type->tp_setattr(self,name,v)) UNLESS(-1 != AsCMethod(m)->type->tp_setattr(self,name,v))
goto dictionary_setattr; goto dictionary_setattr;
return 0; return 0;
} }
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"sO",name,v)) return -1; #if PYTHON_API_VERSION >= 1005
else
if(UnboundCMethod_Check(m) && AsCMethod(m)->meth==setattro_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type))
{
UNLESS(-1 != AsCMethod(m)->type->tp_setattro(self,oname,v))
goto dictionary_setattr;
return 0;
}
#endif
if(UnboundEMethod_Check(m))
{
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"OOO",self,oname,v)) return -1;
}
else UNLESS_ASSIGN(m,PyObject_CallFunction(m,"OO",oname,v)) return -1;
Py_DECREF(m); Py_DECREF(m);
return 0; return 0;
...@@ -1203,24 +1571,46 @@ default_setattr: ...@@ -1203,24 +1571,46 @@ default_setattr:
PyErr_Clear(); PyErr_Clear();
UNLESS(-1 != PyMapping_SetItemString(INSTANCE_DICT(self),name,v)) return subclass_simple_setattro(self, oname, v);
return -1; }
return 0; static int
subclass_setattrs(PyObject *self, char *name, PyObject *v)
{
PyObject *s;
int r;
UNLESS(s=PyString_FromString(name)) return -1;
r=subclass_setattr(self,s,name,v);
Py_DECREF(s);
return r;
}
static int
subclass_setattro(PyObject *self, PyObject *name, PyObject *v)
{
return subclass_setattr(self,name,PyString_AsString(name),v);
} }
static int static int
subclass_compare(PyObject *self, PyObject *v) subclass_compare(PyObject *self, PyObject *v)
{ {
PyObject *m; PyObject *m;
long r; long r;
UNLESS(m=PyObject_GetAttrString(self,"__cmp__")) return -1; UNLESS(m=subclass_getspecial(self,py__cmp__)) return -1;
if(m->ob_type==&CMethodType && ((CMethod*)m)->meth==compare_by_name) if(UnboundCMethod_Check(m) && AsCMethod(m)->meth==compare_by_name
r=((CMethod*)m)->type->tp_compare(self,v); && SubclassInstance_Check(self,AsCMethod(m)->type))
r=AsCMethod(m)->type->tp_compare(self,v);
else else
{ {
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"O",v)) return -1; if(UnboundEMethod_Check(m))
{
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"OO",self,v))
return -1;
}
else UNLESS_ASSIGN(m,PyObject_CallFunction(m,"O",v)) return -1;
r=PyInt_AsLong(m); r=PyInt_AsLong(m);
} }
Py_DECREF(m); Py_DECREF(m);
...@@ -1233,12 +1623,18 @@ subclass_hash(PyObject *self) ...@@ -1233,12 +1623,18 @@ subclass_hash(PyObject *self)
PyObject *m; PyObject *m;
long r; long r;
UNLESS(m=PyObject_GetAttrString(self,"__hash__")) return -1; UNLESS(m=subclass_getspecial(self,py__hash__)) return -1;
if(m->ob_type==&CMethodType && ((CMethod*)m)->meth==hash_by_name) if(UnboundCMethod_Check(m) && AsCMethod(m)->meth==hash_by_name
r=((CMethod*)m)->type->tp_hash(self); && SubclassInstance_Check(self,AsCMethod(m)->type))
r=AsCMethod(m)->type->tp_hash(self);
else else
{ {
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"")) return -1; if(UnboundEMethod_Check(m))
{
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"O",self))
return -1;
}
else UNLESS_ASSIGN(m,PyObject_CallFunction(m,"")) return -1;
r=PyInt_AsLong(m); r=PyInt_AsLong(m);
} }
Py_DECREF(m); Py_DECREF(m);
...@@ -1250,7 +1646,7 @@ subclass_repr(PyObject *self) ...@@ -1250,7 +1646,7 @@ subclass_repr(PyObject *self)
{ {
PyObject *m; PyObject *m;
UNLESS(m=PyObject_GetAttrString(self,"__repr__")) UNLESS(m=subclass_getspecial(self,py__repr__))
{ {
int l; int l;
char *buf, p[64]; char *buf, p[64];
...@@ -1263,13 +1659,19 @@ subclass_repr(PyObject *self) ...@@ -1263,13 +1659,19 @@ subclass_repr(PyObject *self)
sprintf(buf,"<%s instance at %s>",self->ob_type->tp_name,p); sprintf(buf,"<%s instance at %s>",self->ob_type->tp_name,p);
return m; return m;
} }
if(m->ob_type==&CMethodType && ((CMethod*)m)->meth==repr_by_name) if(UnboundCMethod_Check(m) && AsCMethod(m)->meth==repr_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type))
{ {
UNLESS_ASSIGN(m,((CMethod*)m)->type->tp_repr(self)) return NULL; UNLESS_ASSIGN(m,AsCMethod(m)->type->tp_repr(self)) return NULL;
} }
else else
{ {
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"")) return NULL; if(UnboundEMethod_Check(m))
{
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"O",self))
return NULL;
}
else UNLESS_ASSIGN(m,PyObject_CallFunction(m,"")) return NULL;
} }
return m; return m;
} }
...@@ -1277,18 +1679,29 @@ subclass_repr(PyObject *self) ...@@ -1277,18 +1679,29 @@ subclass_repr(PyObject *self)
static PyObject * static PyObject *
subclass_call(PyObject *self, PyObject *args, PyObject *kw) subclass_call(PyObject *self, PyObject *args, PyObject *kw)
{ {
PyObject *m; PyObject *m, *a=0;
UNLESS(m=PyObject_GetAttrString(self,"__call__")) return NULL; UNLESS(m=subclass_getspecial(self,py__call__)) return NULL;
if(m->ob_type==&CMethodType && ((CMethod*)m)->meth==(PyCFunction)call_by_name) if(UnboundCMethod_Check(m) && AsCMethod(m)->meth==(PyCFunction)call_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type))
{ {
UNLESS_ASSIGN(m,((CMethod*)m)->type->tp_call(self,args,kw)) return NULL; UNLESS_ASSIGN(m,AsCMethod(m)->type->tp_call(self,args,kw)) return NULL;
} }
else else
{ {
UNLESS_ASSIGN(m,PyEval_CallObjectWithKeywords(m,args,kw)) return NULL; if(UnboundEMethod_Check(m))
{
UNLESS(a=Py_BuildValue("(O)",self)) goto err;
UNLESS_ASSIGN(a,PySequence_Concat(a,args)) goto err;
args=a;
}
UNLESS_ASSIGN(m,PyEval_CallObjectWithKeywords(m,args,kw)) goto err;
} }
Py_XDECREF(a);
return m; return m;
err:
Py_XDECREF(m);
Py_XDECREF(a);
} }
static PyObject * static PyObject *
...@@ -1296,18 +1709,24 @@ subclass_str(PyObject *self) ...@@ -1296,18 +1709,24 @@ subclass_str(PyObject *self)
{ {
PyObject *m; PyObject *m;
UNLESS(m=PyObject_GetAttrString(self,"__str__")) UNLESS(m=subclass_getspecial(self,py__str__))
{ {
PyErr_Clear(); PyErr_Clear();
return subclass_repr(self); return subclass_repr(self);
} }
if(m->ob_type==&CMethodType && ((CMethod*)m)->meth==str_by_name) if(UnboundCMethod_Check(m) && AsCMethod(m)->meth==str_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type))
{ {
UNLESS_ASSIGN(m,((CMethod*)m)->type->tp_str(self)) return NULL; UNLESS_ASSIGN(m,AsCMethod(m)->type->tp_str(self)) return NULL;
} }
else else
{ {
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"")) return NULL; if(UnboundEMethod_Check(m))
{
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"O",self))
return NULL;
}
else UNLESS_ASSIGN(m,PyObject_CallFunction(m,"")) return NULL;
} }
return m; return m;
} }
...@@ -1317,15 +1736,21 @@ static PyObject * \ ...@@ -1317,15 +1736,21 @@ static PyObject * \
subclass_ ## M(PyObject *self, PyObject *v) \ subclass_ ## M(PyObject *self, PyObject *v) \
{ \ { \
PyObject *m; \ PyObject *m; \
UNLESS(m=PyObject_GetAttrString(self,"__" # M "__")) return NULL; \ UNLESS(m=subclass_getspecial(self,py__ ## N ## __)) return NULL; \
if(m->ob_type==&CMethodType && ((CMethod*)m)->meth==M ## _by_name) \ if(UnboundCMethod_Check(m) && AsCMethod(m)->meth==M ## _by_name \
&& SubclassInstance_Check(self,AsCMethod(m)->type)) \
{ \ { \
UNLESS_ASSIGN(m,PyNumber_ ## A(self,v)) \ UNLESS_ASSIGN(m,PyNumber_ ## A(self,v)) \
return NULL; \ return NULL; \
} \ } \
else \ else \
{ \ { \
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"O",v)) return NULL; \ if(UnboundEMethod_Check(m)) \
{ \
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"OO",self,v)) \
return NULL; \
} \
else UNLESS_ASSIGN(m,PyObject_CallFunction(m,"O",v)) return NULL; \
} \ } \
return m; \ return m; \
} }
...@@ -1340,15 +1765,21 @@ static PyObject * ...@@ -1340,15 +1765,21 @@ static PyObject *
subclass_power(PyObject *self, PyObject *v, PyObject *w) subclass_power(PyObject *self, PyObject *v, PyObject *w)
{ {
PyObject *m; PyObject *m;
UNLESS(m=PyObject_GetAttrString(self,"__pow__")) return NULL; UNLESS(m=subclass_getspecial(self,py__pow__)) return NULL;
if(m->ob_type==&CMethodType && ((CMethod*)m)->meth==power_by_name) if(UnboundCMethod_Check(m) && AsCMethod(m)->meth==power_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type))
{ {
UNLESS_ASSIGN(m,((CMethod*)m)->type->tp_as_number->nb_power(self,v,w)) UNLESS_ASSIGN(m,AsCMethod(m)->type->tp_as_number->nb_power(self,v,w))
return NULL; return NULL;
} }
else else
{ {
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"OO",v,w)) return NULL; if(UnboundEMethod_Check(m))
{
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"OOO",self,v,w))
return NULL;
}
else UNLESS_ASSIGN(m,PyObject_CallFunction(m,"OO",v,w)) return NULL;
} }
return m; return m;
} }
...@@ -1368,12 +1799,18 @@ subclass_coerce(PyObject **self, PyObject **v) ...@@ -1368,12 +1799,18 @@ subclass_coerce(PyObject **self, PyObject **v)
PyObject *m; PyObject *m;
int r; int r;
UNLESS(m=PyObject_GetAttrString(*self,"__coerce__")) return -1; UNLESS(m=subclass_getspecial(*self,py__coerce__)) return -1;
if(m->ob_type==&CMethodType && ((CMethod*)m)->meth==coerce_by_name) if(UnboundCMethod_Check(m) && AsCMethod(m)->meth==coerce_by_name
r=((CMethod*)m)->type->tp_as_number->nb_coerce(self,v); && SubclassInstance_Check(*self,AsCMethod(m)->type))
r=AsCMethod(m)->type->tp_as_number->nb_coerce(self,v);
else else
{ {
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"OO",*self,*v)) return -1; if(UnboundEMethod_Check(m))
{
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"OO",*self,v))
return NULL;
}
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"O",*v)) return -1;
if(m==Py_None) r=-1; if(m==Py_None) r=-1;
else else
{ {
...@@ -1392,15 +1829,21 @@ static PyObject * \ ...@@ -1392,15 +1829,21 @@ static PyObject * \
subclass_ ## M(PyObject *self) \ subclass_ ## M(PyObject *self) \
{ \ { \
PyObject *m; \ PyObject *m; \
UNLESS(m=PyObject_GetAttrString(self,"__" # M "__")) return NULL; \ UNLESS(m=subclass_getspecial(self,py__ ## N ## __)) return NULL; \
if(m->ob_type==&CMethodType && ((CMethod*)m)->meth==M ## _by_name) \ if(UnboundCMethod_Check(m) && AsCMethod(m)->meth==M ## _by_name \
&& SubclassInstance_Check(self,AsCMethod(m)->type)) \
{ \ { \
UNLESS_ASSIGN(m,((CMethod*)m)->type->tp_as_number->nb_ ## M(self)) \ UNLESS_ASSIGN(m,AsCMethod(m)->type->tp_as_number->nb_ ## M(self)) \
return NULL; \ return NULL; \
} \ } \
else \ else \
{ \ { \
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"O")) return NULL; \ if(UnboundEMethod_Check(m)) \
{ \
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"O",self)) \
return NULL; \
} \
else UNLESS_ASSIGN(m,PyObject_CallFunction(m,"")) return NULL; \
} \ } \
return m; \ return m; \
} }
...@@ -1415,12 +1858,18 @@ subclass_nonzero(PyObject *self) ...@@ -1415,12 +1858,18 @@ subclass_nonzero(PyObject *self)
PyObject *m; PyObject *m;
long r; long r;
UNLESS(m=PyObject_GetAttrString(self,"__nonzero__")) return -1; UNLESS(m=subclass_getspecial(self,py__nonzero__)) return -1;
if(m->ob_type==&CMethodType && ((CMethod*)m)->meth==nonzero_by_name) if(UnboundCMethod_Check(m) && AsCMethod(m)->meth==nonzero_by_name
r=((CMethod*)m)->type->tp_as_number->nb_nonzero(self); && SubclassInstance_Check(self,AsCMethod(m)->type))
r=AsCMethod(m)->type->tp_as_number->nb_nonzero(self);
else else
{ {
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"")) return -1; if(UnboundEMethod_Check(m))
{
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"O",self))
return -1;
}
else UNLESS_ASSIGN(m,PyObject_CallFunction(m,"")) return -1;
r=PyInt_AsLong(m); r=PyInt_AsLong(m);
} }
Py_DECREF(m); Py_DECREF(m);
...@@ -1471,10 +1920,11 @@ subclass_length(PyObject *self) ...@@ -1471,10 +1920,11 @@ subclass_length(PyObject *self)
long r; long r;
PyExtensionClass *t; PyExtensionClass *t;
UNLESS(m=PyObject_GetAttrString(self,"__len__")) return -1; UNLESS(m=subclass_getspecial(self,py__len__)) return -1;
if(m->ob_type==&CMethodType && ((CMethod*)m)->meth==length_by_name) if(UnboundCMethod_Check(m) && AsCMethod(m)->meth==length_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type))
{ {
t=(PyExtensionClass*)((CMethod*)m)->type; t=(PyExtensionClass*)AsCMethod(m)->type;
Py_DECREF(m); Py_DECREF(m);
if(t->tp_as_sequence) if(t->tp_as_sequence)
return t->tp_as_sequence->sq_length(self); return t->tp_as_sequence->sq_length(self);
...@@ -1496,10 +1946,11 @@ subclass_item(PyObject *self, int index) ...@@ -1496,10 +1946,11 @@ subclass_item(PyObject *self, int index)
PyObject *m; PyObject *m;
PyExtensionClass *t; PyExtensionClass *t;
UNLESS(m=PyObject_GetAttrString(self,"__getitem__")) return NULL; UNLESS(m=subclass_getspecial(self,py__getitem__)) return NULL;
if(m->ob_type==&CMethodType && ((CMethod*)m)->meth==getitem_by_name) if(UnboundCMethod_Check(m) && AsCMethod(m)->meth==getitem_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type))
{ {
t=(PyExtensionClass*)((CMethod*)m)->type; t=(PyExtensionClass*)AsCMethod(m)->type;
if(t->tp_as_sequence && t->tp_as_sequence->sq_item) if(t->tp_as_sequence && t->tp_as_sequence->sq_item)
{ {
Py_DECREF(m); Py_DECREF(m);
...@@ -1520,11 +1971,12 @@ subclass_ass_item(PyObject *self, int index, PyObject *v) ...@@ -1520,11 +1971,12 @@ subclass_ass_item(PyObject *self, int index, PyObject *v)
PyObject *m; PyObject *m;
PyExtensionClass *t; PyExtensionClass *t;
UNLESS(m=PyObject_GetAttrString(self,"__setitem__")) return -1; UNLESS(m=subclass_getspecial(self,py__setitem__)) return -1;
if(m->ob_type==&CMethodType && if(UnboundCMethod_Check(m) &&
((CMethod*)m)->meth==(PyCFunction)setitem_by_name) AsCMethod(m)->meth==(PyCFunction)setitem_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type))
{ {
t=(PyExtensionClass*)((CMethod*)m)->type; t=(PyExtensionClass*)AsCMethod(m)->type;
if(t->tp_as_sequence && t->tp_as_sequence->sq_ass_item) if(t->tp_as_sequence && t->tp_as_sequence->sq_ass_item)
{ {
Py_DECREF(m); Py_DECREF(m);
...@@ -1545,10 +1997,11 @@ subclass_slice(PyObject *self, int i1, int i2) ...@@ -1545,10 +1997,11 @@ subclass_slice(PyObject *self, int i1, int i2)
{ {
PyObject *m; PyObject *m;
UNLESS(m=PyObject_GetAttrString(self,"__getslice__")) return NULL; UNLESS(m=subclass_getspecial(self,py__getslice__)) return NULL;
if(m->ob_type==&CMethodType && ((CMethod*)m)->meth==slice_by_name) if(UnboundCMethod_Check(m) && AsCMethod(m)->meth==slice_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type))
{ {
UNLESS_ASSIGN(m,((CMethod*)m)->type->tp_as_sequence->sq_slice(self,i1,i2)) UNLESS_ASSIGN(m,AsCMethod(m)->type->tp_as_sequence->sq_slice(self,i1,i2))
return NULL; return NULL;
} }
else else
...@@ -1564,10 +2017,11 @@ subclass_ass_slice(PyObject *self, int i1, int i2, PyObject *v) ...@@ -1564,10 +2017,11 @@ subclass_ass_slice(PyObject *self, int i1, int i2, PyObject *v)
PyObject *m; PyObject *m;
long r; long r;
UNLESS(m=PyObject_GetAttrString(self,"__setslice__")) return -1; UNLESS(m=subclass_getspecial(self,py__setslice__)) return -1;
if(m->ob_type==&CMethodType && if(UnboundCMethod_Check(m) &&
((CMethod*)m)->meth==(PyCFunction)ass_slice_by_name) AsCMethod(m)->meth==(PyCFunction)ass_slice_by_name
r=((CMethod*)m)->type->tp_as_sequence->sq_ass_slice(self,i1,i2,v); && SubclassInstance_Check(self,AsCMethod(m)->type))
r=AsCMethod(m)->type->tp_as_sequence->sq_ass_slice(self,i1,i2,v);
else else
{ {
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"iiO",i1,i2,v)) return -1; UNLESS_ASSIGN(m,PyObject_CallFunction(m,"iiO",i1,i2,v)) return -1;
...@@ -1582,21 +2036,22 @@ subclass_concat(PyObject *self, PyObject *v) ...@@ -1582,21 +2036,22 @@ subclass_concat(PyObject *self, PyObject *v)
{ {
PyObject *m; PyObject *m;
UNLESS(m=PyObject_GetAttrString(self,"__concat__")) UNLESS(m=subclass_getspecial(self,py__concat__))
{ /* Maybe we should check for __add__ */ { /* Maybe we should check for __add__ */
PyObject *am; PyObject *am;
PyErr_Clear(); PyErr_Clear();
UNLESS(am=PyObject_GetAttrString(self,"__add__")) return NULL; UNLESS(am=subclass_getspecial(self,py__add__)) return NULL;
if(m=PyObject_GetAttrString(self,"__coerce__")) if(m=subclass_getspecial(self,py__coerce__))
{ {
if(m->ob_type==&CMethodType && ((CMethod*)m)->meth==coerce_by_name) if(UnboundCMethod_Check(m) && AsCMethod(m)->meth==coerce_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type))
{ {
PyObject *x,*y; PyObject *x,*y;
x=self; x=self;
y=v; y=v;
if(0==((CMethod*)m)->type->tp_as_number->nb_coerce(&x,&y)) if(0==AsCMethod(m)->type->tp_as_number->nb_coerce(&x,&y))
{ {
Py_DECREF(am); Py_DECREF(am);
if(x->ob_type->tp_as_number) if(x->ob_type->tp_as_number)
...@@ -1616,9 +2071,10 @@ subclass_concat(PyObject *self, PyObject *v) ...@@ -1616,9 +2071,10 @@ subclass_concat(PyObject *self, PyObject *v)
"No __add__ or __concat__ methods, or maybe I'm just being stupid."); "No __add__ or __concat__ methods, or maybe I'm just being stupid.");
return NULL; return NULL;
} }
if(m->ob_type==&CMethodType && ((CMethod*)m)->meth==concat_by_name) if(UnboundCMethod_Check(m) && AsCMethod(m)->meth==concat_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type))
{ {
UNLESS_ASSIGN(m,((CMethod*)m)->type->tp_as_sequence->sq_concat(self,v)) UNLESS_ASSIGN(m,AsCMethod(m)->type->tp_as_sequence->sq_concat(self,v))
return NULL; return NULL;
} }
else else
...@@ -1633,10 +2089,11 @@ subclass_repeat(PyObject *self, int v) ...@@ -1633,10 +2089,11 @@ subclass_repeat(PyObject *self, int v)
{ {
PyObject *m; PyObject *m;
UNLESS(m=PyObject_GetAttrString(self,"__repeat__")) return NULL; UNLESS(m=subclass_getspecial(self,py__repeat__)) return NULL;
if(m->ob_type==&CMethodType && ((CMethod*)m)->meth==repeat_by_name) if(UnboundCMethod_Check(m) && AsCMethod(m)->meth==repeat_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type))
{ {
UNLESS_ASSIGN(m,((CMethod*)m)->type->tp_as_sequence->sq_repeat(self,v)) UNLESS_ASSIGN(m,AsCMethod(m)->type->tp_as_sequence->sq_repeat(self,v))
return NULL; return NULL;
} }
else else
...@@ -1662,11 +2119,12 @@ subclass_subscript(PyObject *self, PyObject *key) ...@@ -1662,11 +2119,12 @@ subclass_subscript(PyObject *self, PyObject *key)
PyObject *m; PyObject *m;
PyExtensionClass *t; PyExtensionClass *t;
UNLESS(m=PyObject_GetAttrString(self,"__getitem__")) return NULL; UNLESS(m=subclass_getspecial(self,py__getitem__)) return NULL;
if(m->ob_type==&CMethodType && if(UnboundCMethod_Check(m) &&
((CMethod*)m)->meth==(PyCFunction)getitem_by_name) AsCMethod(m)->meth==(PyCFunction)getitem_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type))
{ {
t=(PyExtensionClass*)((CMethod*)m)->type; t=(PyExtensionClass*)AsCMethod(m)->type;
if(t->tp_as_mapping && t->tp_as_mapping->mp_subscript) if(t->tp_as_mapping && t->tp_as_mapping->mp_subscript)
{ {
Py_DECREF(m); Py_DECREF(m);
...@@ -1687,11 +2145,12 @@ subclass_ass_subscript(PyObject *self, PyObject *index, PyObject *v) ...@@ -1687,11 +2145,12 @@ subclass_ass_subscript(PyObject *self, PyObject *index, PyObject *v)
PyObject *m; PyObject *m;
PyExtensionClass *t; PyExtensionClass *t;
UNLESS(m=PyObject_GetAttrString(self,"__setitem__")) return -1; UNLESS(m=subclass_getspecial(self,py__setitem__)) return -1;
if(m->ob_type==&CMethodType && if(UnboundCMethod_Check(m) &&
((CMethod*)m)->meth==(PyCFunction)setitem_by_name) AsCMethod(m)->meth==(PyCFunction)setitem_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type))
{ {
t=(PyExtensionClass*)((CMethod*)m)->type; t=(PyExtensionClass*)AsCMethod(m)->type;
if(t->tp_as_sequence && t->tp_as_mapping->mp_ass_subscript) if(t->tp_as_sequence && t->tp_as_mapping->mp_ass_subscript)
{ {
Py_DECREF(m); Py_DECREF(m);
...@@ -1723,11 +2182,11 @@ dealloc_base(PyObject *inst, PyExtensionClass* self) ...@@ -1723,11 +2182,11 @@ dealloc_base(PyObject *inst, PyExtensionClass* self)
for(i=0; i < l; i++) for(i=0; i < l; i++)
{ {
t=PyTuple_GET_ITEM(self->bases, i); t=PyTuple_GET_ITEM(self->bases, i);
if(t->ob_type==(PyTypeObject*)&CCLtype) if(PyExtensionClass_Check(t))
{ {
if(((PyExtensionClass*)t)->bases) if(AsPyExtensionClass(t)->bases)
{ {
if(dealloc_base(inst,(PyExtensionClass*)t)) return 1; if(dealloc_base(inst,AsPyExtensionClass(t))) return 1;
} }
else else
{ {
...@@ -1749,7 +2208,7 @@ subclass_dealloc(PyObject *self) ...@@ -1749,7 +2208,7 @@ subclass_dealloc(PyObject *self)
PyErr_Fetch(&t,&v,&tb); PyErr_Fetch(&t,&v,&tb);
if(m=PyObject_GetAttrString(self,"__del__")) if(m=subclass_getspecial(self,py__del__))
PyObject_CallFunction(m,""); PyObject_CallFunction(m,"");
PyErr_Clear(); PyErr_Clear();
...@@ -1775,14 +2234,14 @@ datafull_baseclasses(PyExtensionClass *type) ...@@ -1775,14 +2234,14 @@ datafull_baseclasses(PyExtensionClass *type)
for(i=0; i < l; i++) for(i=0; i < l; i++)
{ {
base=PyTuple_GET_ITEM(type->bases, i); base=PyTuple_GET_ITEM(type->bases, i);
if(base->ob_type==(PyTypeObject*)&CCLtype) if(PyExtensionClass_Check(base))
{ {
if(((PyExtensionClass*)base->ob_type)->bases) if(AsPyExtensionClass(base)->bases)
n+=datafull_baseclasses((PyExtensionClass*)base); n+=datafull_baseclasses(AsPyExtensionClass(base));
else else
{ {
if(((PyExtensionClass*)base)->tp_basicsize > sizeof(Dataless) || if(AsPyExtensionClass(base)->tp_basicsize > sizeof(Dataless) ||
((PyExtensionClass*)base)->tp_itemsize > 0) AsPyExtensionClass(base)->tp_itemsize > 0)
n++; n++;
} }
} }
...@@ -1803,17 +2262,17 @@ datafull_baseclass(PyExtensionClass *type) ...@@ -1803,17 +2262,17 @@ datafull_baseclass(PyExtensionClass *type)
for(i=0; i < l; i++) for(i=0; i < l; i++)
{ {
base=PyTuple_GET_ITEM(type->bases, i); base=PyTuple_GET_ITEM(type->bases, i);
if(base->ob_type==(PyTypeObject*)&CCLtype) if(PyExtensionClass_Check(base))
{ {
if(((PyExtensionClass*)base->ob_type)->bases) if(AsPyExtensionClass(base)->bases)
{ {
if(dbase=datafull_baseclass((PyExtensionClass*)base)) if(dbase=datafull_baseclass(AsPyExtensionClass(base)))
return dbase; return dbase;
} }
else else
{ {
if(((PyExtensionClass*)base)->tp_basicsize > sizeof(Dataless) || if(AsPyExtensionClass(base)->tp_basicsize > sizeof(Dataless) ||
((PyExtensionClass*)base)->tp_itemsize > 0) AsPyExtensionClass(base)->tp_itemsize > 0)
return base; return base;
} }
} }
...@@ -1822,11 +2281,11 @@ datafull_baseclass(PyExtensionClass *type) ...@@ -1822,11 +2281,11 @@ datafull_baseclass(PyExtensionClass *type)
} }
static int static int
subclass_hasattr(PyExtensionClass *type, char *name) subclass_hasattr(PyExtensionClass *type, PyObject *name)
{ {
PyObject *o; PyObject *o;
if(o=CCL_getattr(type,name)) if(o=CCL_getattro(type,name))
{ {
Py_DECREF(o); Py_DECREF(o);
return 1; return 1;
...@@ -1838,56 +2297,135 @@ subclass_hasattr(PyExtensionClass *type, char *name) ...@@ -1838,56 +2297,135 @@ subclass_hasattr(PyExtensionClass *type, char *name)
static int static int
has_number_methods(PyExtensionClass *type) has_number_methods(PyExtensionClass *type)
{ {
return (subclass_hasattr(type,"__add__") || return (subclass_hasattr(type,py__add__) ||
subclass_hasattr(type,"__sub__") || subclass_hasattr(type,py__sub__) ||
subclass_hasattr(type,"__mul__") || subclass_hasattr(type,py__mul__) ||
subclass_hasattr(type,"__div__") || subclass_hasattr(type,py__div__) ||
subclass_hasattr(type,"__mod__") || subclass_hasattr(type,py__mod__) ||
subclass_hasattr(type,"__pow__") || subclass_hasattr(type,py__pow__) ||
subclass_hasattr(type,"__divmod__") || subclass_hasattr(type,py__divmod__) ||
subclass_hasattr(type,"__lshift__") || subclass_hasattr(type,py__lshift__) ||
subclass_hasattr(type,"__rshift__") || subclass_hasattr(type,py__rshift__) ||
subclass_hasattr(type,"__and__") || subclass_hasattr(type,py__and__) ||
subclass_hasattr(type,"__or__") || subclass_hasattr(type,py__or__) ||
subclass_hasattr(type,"__xor__") || subclass_hasattr(type,py__xor__) ||
subclass_hasattr(type,"__coerce__") || subclass_hasattr(type,py__coerce__) ||
subclass_hasattr(type,"__neg__") || subclass_hasattr(type,py__neg__) ||
subclass_hasattr(type,"__pos__") || subclass_hasattr(type,py__pos__) ||
subclass_hasattr(type,"__abs__") || subclass_hasattr(type,py__abs__) ||
subclass_hasattr(type,"__nonzero__") || subclass_hasattr(type,py__nonzero__) ||
subclass_hasattr(type,"__inv__") || subclass_hasattr(type,py__inv__) ||
subclass_hasattr(type,"__int__") || subclass_hasattr(type,py__int__) ||
subclass_hasattr(type,"__long__") || subclass_hasattr(type,py__long__) ||
subclass_hasattr(type,"__float__") || subclass_hasattr(type,py__float__) ||
subclass_hasattr(type,"__oct__") || subclass_hasattr(type,py__oct__) ||
subclass_hasattr(type,"__hex__") subclass_hasattr(type,py__hex__)
); );
} }
static int static int
has_collection_methods(PyExtensionClass *type) has_collection_methods(PyExtensionClass *type)
{ {
return (subclass_hasattr(type,"__getitem__") || return (subclass_hasattr(type,py__getitem__) ||
subclass_hasattr(type,"__setitem__") || subclass_hasattr(type,py__setitem__) ||
subclass_hasattr(type,"__getslice__") || subclass_hasattr(type,py__getslice__) ||
subclass_hasattr(type,"__setslice__") || subclass_hasattr(type,py__setslice__) ||
subclass_hasattr(type,"__concat__") || subclass_hasattr(type,py__concat__) ||
subclass_hasattr(type,"__repeat__") || subclass_hasattr(type,py__repeat__) ||
subclass_hasattr(type,"__len__") subclass_hasattr(type,py__len__)
); );
} }
static void
subclass_init_getattr(PyExtensionClass *self, PyObject *methods)
{
PyObject *m;
if((m=CCL_getattr(self,py__getattr__,"__getattr__")))
{
if(UnboundCMethod_Check(m) && AsCMethod(m)->meth==getattr_by_name
&& Subclass_Check(self,AsCMethod(m)->type))
{
self->tp_getattr=AsCMethod(m)->type->tp_getattr;
}
#if PYTHON_API_VERSION >= 1005
else if(UnboundCMethod_Check(m) && AsCMethod(m)->meth==getattro_by_name
&& Subclass_Check(self,AsCMethod(m)->type))
{
self->tp_getattro=AsCMethod(m)->type->tp_getattro;
}
#endif
else
{
PyDict_SetItem(methods,py__getattr__,m);
#if PYTHON_API_VERSION >= 1005
self->tp_getattro=subclass_getattro;
#else
self->tp_getattr=subclass_getattr;
#endif
}
}
else
{
PyErr_Clear();
#if PYTHON_API_VERSION >= 1005
self->tp_getattro=EC_findiattro;
#else
self->tp_getattr=EC_findiattrs;
#endif
}
}
static void
subclass_init_setattr(PyExtensionClass *self, PyObject *methods)
{
PyObject *m;
if((m=CCL_getattr(self,py__setattr__,"__setattr__")))
{
if(UnboundCMethod_Check(m) && AsCMethod(m)->meth==setattr_by_name
&& Subclass_Check(self,AsCMethod(m)->type))
{
self->tp_setattr=AsCMethod(m)->type->tp_setattr;
}
#if PYTHON_API_VERSION >= 1005
else if(UnboundCMethod_Check(m) && AsCMethod(m)->meth==setattro_by_name
&& Subclass_Check(self,AsCMethod(m)->type))
{
self->tp_setattro=AsCMethod(m)->type->tp_setattro;
}
#endif
else
{
PyDict_SetItem(methods,py__setattr__,m);
#if PYTHON_API_VERSION >= 1005
self->tp_setattro=subclass_setattro;
#else
self->tp_setattr=subclass_setattr;
#endif
}
}
else
{
PyErr_Clear();
#if PYTHON_API_VERSION >= 1005
self->tp_setattro=subclass_simple_setattro;
#else
self->tp_setattro=subclass_simple_setattr;
#endif
}
}
/* Constructor for building subclasses of C classes. /* Constructor for building subclasses of C classes.
That is, we want to build a C class object that described a That is, we want to build a C class object that described a
subclass of a built-in type. subclass of a built-in type.
*/ */
static PyObject * static PyObject *
subclass__init__(self,args) subclass__init__(PyExtensionClass *self, PyObject *args)
PyExtensionClass *self;
PyObject *args;
{ {
PyObject *bases, *methods; PyObject *bases, *methods, *class_init;
PyExtensionClass *type; PyExtensionClass *type;
char *name; char *name;
int dynamic=1; int dynamic=1;
...@@ -1932,9 +2470,10 @@ subclass__init__(self,args) ...@@ -1932,9 +2470,10 @@ subclass__init__(self,args)
copy_member(tp_itemsize); copy_member(tp_itemsize);
copy_member(tp_print); copy_member(tp_print);
copy_member(tp_getattr);
self->tp_dealloc=subclass_dealloc; self->tp_dealloc=subclass_dealloc;
self->tp_setattr=subclass_setattr;
subclass_init_getattr(self,methods);
subclass_init_setattr(self,methods);
#define subclass_set(OP,N) \ #define subclass_set(OP,N) \
self->tp_ ##OP = subclass_ ##OP self->tp_ ##OP = subclass_ ##OP
...@@ -1942,8 +2481,8 @@ subclass__init__(self,args) ...@@ -1942,8 +2481,8 @@ subclass__init__(self,args)
subclass_set(compare,cmp); subclass_set(compare,cmp);
subclass_set(repr,repr); subclass_set(repr,repr);
if(subclass_hasattr(self,"__bind_to_object__") && if(subclass_hasattr(self,py__bind_to_object__) &&
subclass_hasattr(self,"__call__")) subclass_hasattr(self,py__call__))
self->class_flags |= EXTENSIONCLASS_BINDABLE_FLAG; self->class_flags |= EXTENSIONCLASS_BINDABLE_FLAG;
if(dynamic || has_number_methods(self)) if(dynamic || has_number_methods(self))
...@@ -1965,6 +2504,19 @@ subclass__init__(self,args) ...@@ -1965,6 +2504,19 @@ subclass__init__(self,args)
subclass_set(call,call); subclass_set(call,call);
subclass_set(str,str); subclass_set(str,str);
self->tp_doc=0; self->tp_doc=0;
/* Check for and use __class_init__ */
if(class_init=PyObject_GetAttrString(AsPyObject(self),"__class_init__"))
{
UNLESS_ASSIGN(class_init,PyObject_GetAttrString(class_init,"im_func"))
return NULL;
UNLESS_ASSIGN(class_init,PyObject_CallFunction(class_init,"O",self))
return NULL;
Py_DECREF(class_init);
}
else
PyErr_Clear();
Py_INCREF(Py_None); Py_INCREF(Py_None);
return Py_None; return Py_None;
} }
...@@ -1985,8 +2537,8 @@ static PyExtensionClass CCLtype = { ...@@ -1985,8 +2537,8 @@ static PyExtensionClass CCLtype = {
/* methods */ /* methods */
(destructor)CCL_dealloc, /*tp_dealloc*/ (destructor)CCL_dealloc, /*tp_dealloc*/
(printfunc)0, /*tp_print*/ (printfunc)0, /*tp_print*/
(getattrfunc)CCL_getattr, /*tp_getattr*/ (getattrfunc)CCL_getattrs, /*tp_getattr*/
(setattrfunc)CCL_setattr, /*tp_setattr*/ (setattrfunc)CCL_setattrs, /*tp_setattr*/
(cmpfunc)0, /*tp_compare*/ (cmpfunc)0, /*tp_compare*/
(reprfunc)CCL_repr, /*tp_repr*/ (reprfunc)CCL_repr, /*tp_repr*/
0, /*tp_as_number*/ 0, /*tp_as_number*/
...@@ -1995,9 +2547,14 @@ static PyExtensionClass CCLtype = { ...@@ -1995,9 +2547,14 @@ static PyExtensionClass CCLtype = {
(hashfunc)0, /*tp_hash*/ (hashfunc)0, /*tp_hash*/
(ternaryfunc)CCL_call, /*tp_call*/ (ternaryfunc)CCL_call, /*tp_call*/
(reprfunc)0, /*tp_str*/ (reprfunc)0, /*tp_str*/
#if PYTHON_API_VERSION >= 1005
(getattrofunc)CCL_getattro, /*tp_getattr with object key*/
(setattrofunc)CCL_setattro, /*tp_setattr with object key*/
#else
/* Space for future expansion */ /* Space for future expansion */
0L,0L,0L,0L, 0L,0L,
#endif
0L,0L,
"C classes", /* Documentation string */ "C classes", /* Documentation string */
METHOD_CHAIN(ExtensionClass_methods) METHOD_CHAIN(ExtensionClass_methods)
}; };
...@@ -2011,7 +2568,7 @@ static PyExtensionClass Basetype = { ...@@ -2011,7 +2568,7 @@ static PyExtensionClass Basetype = {
/* methods */ /* methods */
(destructor)0, /*tp_dealloc*/ (destructor)0, /*tp_dealloc*/
(printfunc)0, /*tp_print*/ (printfunc)0, /*tp_print*/
(getattrfunc)ExtensionClass_FindInstanceAttribute, /*tp_getattr*/ (getattrfunc)EC_findiattrs, /*tp_getattr*/
(setattrfunc)0, /*tp_setattr*/ (setattrfunc)0, /*tp_setattr*/
(cmpfunc)0, /*tp_compare*/ (cmpfunc)0, /*tp_compare*/
(reprfunc)0, /*tp_repr*/ (reprfunc)0, /*tp_repr*/
...@@ -2021,9 +2578,14 @@ static PyExtensionClass Basetype = { ...@@ -2021,9 +2578,14 @@ static PyExtensionClass Basetype = {
(hashfunc)0, /*tp_hash*/ (hashfunc)0, /*tp_hash*/
(ternaryfunc)0, /*tp_call*/ (ternaryfunc)0, /*tp_call*/
(reprfunc)0, /*tp_str*/ (reprfunc)0, /*tp_str*/
#if PYTHON_API_VERSION >= 1005
(getattrofunc)EC_findiattro, /*tp_getattr with object key*/
(setattrofunc)0, /*tp_setattr with object key*/
#else
/* Space for future expansion */ /* Space for future expansion */
0L,0L,0L,0L, 0L,0L,
#endif
0L,0L,
"Base -- a do nothing base class\n" "Base -- a do nothing base class\n"
"\n" "\n"
"A trivial base class that doesn't have any inheritable\n" "A trivial base class that doesn't have any inheritable\n"
...@@ -2032,6 +2594,79 @@ static PyExtensionClass Basetype = { ...@@ -2032,6 +2594,79 @@ static PyExtensionClass Basetype = {
{NULL,NULL} {NULL,NULL}
}; };
static PyObject *
bind_to_object(PyObject *self, PyObject *args)
{
PyObject *inst;
PMethod *r;
UNLESS(PyArg_Parse(args,"O",&inst)) return NULL;
UNLESS(PyExtensionInstance_Check(inst))
{
PyErr_SetString(PyExc_TypeError,
"attempt to wrap extension method using an object that\n"
"is not an extension class instance.");
return NULL;
}
UNLESS(r = PyObject_NEW(PMethod, &PMethodType)) return NULL;
Py_INCREF(inst);
Py_INCREF(inst->ob_type);
r->type=inst->ob_type;
r->self=inst;
r->meth=self;
return AsPyObject(r);
}
struct PyMethodDef Method_methods[] = {
{"__bind_to_object__",(PyCFunction)bind_to_object,0,""},
{NULL, NULL} /* sentinel */
};
static PyExtensionClass Methodtype = {
PyObject_HEAD_INIT(&PyType_Type)
0, /*ob_size*/
"Method", /*tp_name*/
sizeof(Dataless), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
(destructor)0, /*tp_dealloc*/
(printfunc)0, /*tp_print*/
(getattrfunc)EC_findiattrs, /*tp_getattr*/
(setattrfunc)0, /*tp_setattr*/
(cmpfunc)0, /*tp_compare*/
(reprfunc)0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
(hashfunc)0, /*tp_hash*/
(ternaryfunc)0, /*tp_call*/
(reprfunc)0, /*tp_str*/
#if PYTHON_API_VERSION >= 1005
(getattrofunc)EC_findiattro, /*tp_getattr with object key*/
(setattrofunc)0, /*tp_setattr with object key*/
#else
/* Space for future expansion */
0L,0L,
#endif
0L,0L,
"Base class for objects that want to be treated as methods\n"
"\n"
"The method class provides a method, __bind_to_object__, that\n"
"binds an object to an instance. If a method is a subobject\n"
"of an extension-class instance, the the method will be bound\n"
"to the instance and when the resulting object is called, it\n"
"will call the method and pass the instance in addition to\n"
"other arguments. It is the responsibility of Method objects\n"
"to implement (or inherit) a __call__ method.\n",
METHOD_CHAIN(Method_methods)
};
PyObject * PyObject *
MetaTypeUndefinedMethod() MetaTypeUndefinedMethod()
...@@ -2063,14 +2698,30 @@ initExtensionClass() ...@@ -2063,14 +2698,30 @@ initExtensionClass()
/* Add some symbolic constants to the module */ /* Add some symbolic constants to the module */
d = PyModule_GetDict(m); d = PyModule_GetDict(m);
init_py_names();
initializeBaseExtensionClass(&CCLtype); initializeBaseExtensionClass(&CCLtype);
PyDict_SetItemString(d, "ExtensionClassType", (PyObject*)&CCLtype); PyDict_SetItemString(d, "ExtensionClassType", (PyObject*)&CCLtype);
initializeBaseExtensionClass(&Basetype); initializeBaseExtensionClass(&Basetype);
PyDict_SetItemString(d, "Base", (PyObject*)&Basetype); PyDict_SetItemString(d, "Base", (PyObject*)&Basetype);
initializeBaseExtensionClass(&Methodtype);
PyDict_SetItemString(d, "Method", (PyObject*)&Methodtype);
#ifdef Py_COBJECT_H
/* Export C attribute lookup API */
PyDict_SetItemString(d, "_PyEC_getattrs",
PyCObject_FromVoidPtr(EC_findiattrs,NULL));
PyDict_SetItemString(d, "_PyEC_getattro",
PyCObject_FromVoidPtr(EC_findiattro,NULL));
PyDict_SetItemString(d, "_PyEC_setattrs",
PyCObject_FromVoidPtr(subclass_simple_setattr,NULL));
PyDict_SetItemString(d, "_PyEC_setattro",
PyCObject_FromVoidPtr(subclass_simple_setattro,NULL));
#endif
/* Check for errors */ /* Check for errors */
if (PyErr_Occurred()) if (PyErr_Occurred())
Py_FatalError("can't initialize module ExtensionClass"); Py_FatalError("can't initialize module ExtensionClass");
} }
/* /*
$Id: ExtensionClass.c,v 1.3 1996/10/24 21:07:49 jim Exp $ $Id: ExtensionClass.c,v 1.4 1996/12/06 17:12:29 jim Exp $
Extension Class Extension Class
...@@ -56,6 +56,10 @@ ...@@ -56,6 +56,10 @@
(540) 371-6909 (540) 371-6909
$Log: ExtensionClass.c,v $ $Log: ExtensionClass.c,v $
Revision 1.4 1996/12/06 17:12:29 jim
Major speed enhancements for attribute lookup and calling special
methods.
Revision 1.3 1996/10/24 21:07:49 jim Revision 1.3 1996/10/24 21:07:49 jim
Fixed bug in returning __bases__ for base classes. Fixed bug in returning __bases__ for base classes.
Added missing PyErr_Clear() call. Added missing PyErr_Clear() call.
...@@ -84,7 +88,7 @@ static char ExtensionClass_module_documentation[] = ...@@ -84,7 +88,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.3 1996/10/24 21:07:49 jim Exp $\n" "$Id: ExtensionClass.c,v 1.4 1996/12/06 17:12:29 jim Exp $\n"
; ;
#include "Python.h" #include "Python.h"
...@@ -102,6 +106,72 @@ typedef struct { PyObject_HEAD } Dataless; ...@@ -102,6 +106,72 @@ typedef struct { PyObject_HEAD } Dataless;
#include "ExtensionClass.h" #include "ExtensionClass.h"
staticforward PyExtensionClass CCLtype; staticforward PyExtensionClass CCLtype;
#define PyExtensionClass_Check(O) ((O)->ob_type == (PyTypeObject*)&CCLtype)
#define PyExtensionInstance_Check(O) \
((O)->ob_type->ob_type == (PyTypeObject*)&CCLtype)
#define AsPyExtensionClass(O) ((PyExtensionClass*)(O))
#define PyExtensionClassOf(O) ((PyExtensionClass*)((O)->ob_type))
#define AsPyObject(O) ((PyObject*)(O))
static PyObject *py__add__, *py__sub__, *py__mul__, *py__div__,
*py__mod__, *py__pow__, *py__divmod__, *py__lshift__, *py__rshift__,
*py__and__, *py__or__, *py__xor__, *py__coerce__, *py__neg__,
*py__pos__, *py__abs__, *py__nonzero__, *py__inv__, *py__int__,
*py__long__, *py__float__, *py__oct__, *py__hex__, *py__getitem__,
*py__setitem__, *py__getslice__, *py__setslice__, *py__concat__,
*py__repeat__, *py__len__, *py__bind_to_object__, *py__call__,
*py__getattr__, *py__setattr__, *py__del__, *py__repr__, *py__str__,
*py__hash__, *py__cmp__, *py__var_size__, *py__init__;
static void
init_py_names()
{
#define INIT_PY_NAME(N) py ## N = PyString_FromString(#N)
INIT_PY_NAME(__add__);
INIT_PY_NAME(__sub__);
INIT_PY_NAME(__mul__);
INIT_PY_NAME(__div__);
INIT_PY_NAME(__mod__);
INIT_PY_NAME(__pow__);
INIT_PY_NAME(__divmod__);
INIT_PY_NAME(__lshift__);
INIT_PY_NAME(__rshift__);
INIT_PY_NAME(__and__);
INIT_PY_NAME(__or__);
INIT_PY_NAME(__xor__);
INIT_PY_NAME(__coerce__);
INIT_PY_NAME(__neg__);
INIT_PY_NAME(__pos__);
INIT_PY_NAME(__abs__);
INIT_PY_NAME(__nonzero__);
INIT_PY_NAME(__inv__);
INIT_PY_NAME(__int__);
INIT_PY_NAME(__long__);
INIT_PY_NAME(__float__);
INIT_PY_NAME(__oct__);
INIT_PY_NAME(__hex__);
INIT_PY_NAME(__getitem__);
INIT_PY_NAME(__setitem__);
INIT_PY_NAME(__getslice__);
INIT_PY_NAME(__setslice__);
INIT_PY_NAME(__concat__);
INIT_PY_NAME(__repeat__);
INIT_PY_NAME(__len__);
INIT_PY_NAME(__bind_to_object__);
INIT_PY_NAME(__call__);
INIT_PY_NAME(__getattr__);
INIT_PY_NAME(__setattr__);
INIT_PY_NAME(__del__);
INIT_PY_NAME(__repr__);
INIT_PY_NAME(__str__);
INIT_PY_NAME(__hash__);
INIT_PY_NAME(__cmp__);
INIT_PY_NAME(__var_size__);
INIT_PY_NAME(__init__);
#undef INIT_PY_NAME
}
/* CMethod objects: */ /* CMethod objects: */
typedef struct { typedef struct {
...@@ -116,6 +186,40 @@ typedef struct { ...@@ -116,6 +186,40 @@ typedef struct {
staticforward PyTypeObject CMethodType; staticforward PyTypeObject CMethodType;
#define CMethod_Check(O) ((O)->ob_type==&CMethodType)
#define UnboundCMethod_Check(O) \
((O)->ob_type==&CMethodType && ! ((CMethod*)(O))->self)
#define AsCMethod(O) ((CMethod*)(O))
static int
CMethod_issubclass(PyExtensionClass *sub, PyExtensionClass *type)
{
int i,l;
PyObject *t;
if(sub==type) return 1;
if(! sub->bases) return 0;
l=PyTuple_Size(sub->bases);
for(i=0; i < l; i++)
{
t=PyTuple_GET_ITEM(sub->bases, i);
if(t==(PyObject*)type) return 1;
if(PyExtensionClass_Check(t)
&& AsPyExtensionClass(t)->bases
&& CMethod_issubclass(AsPyExtensionClass(t),type)
) return 1;
}
return 0;
}
#define Subclass_Check(C1,C2) \
CMethod_issubclass((PyExtensionClass *)(C1), (PyExtensionClass *)(C2))
#define SubclassInstance_Check(C1,C2) \
CMethod_issubclass((PyExtensionClass *)((C1)->ob_type), \
(PyExtensionClass *)(C2))
static CMethod * static CMethod *
newCMethod(PyTypeObject *type, newCMethod(PyTypeObject *type,
char *name, PyCFunction meth, int flags, char *doc) char *name, PyCFunction meth, int flags, char *doc)
...@@ -139,6 +243,15 @@ bindCMethod(CMethod *m, PyObject *inst) ...@@ -139,6 +243,15 @@ bindCMethod(CMethod *m, PyObject *inst)
{ {
CMethod *self; CMethod *self;
UNLESS(inst->ob_type==m->type ||
(PyExtensionInstance_Check(inst)
&& SubclassInstance_Check(inst,m->type))
)
{
Py_INCREF(m);
return m;
}
UNLESS(self = PyObject_NEW(CMethod, &CMethodType)) return NULL; UNLESS(self = PyObject_NEW(CMethod, &CMethodType)) return NULL;
Py_INCREF(inst); Py_INCREF(inst);
...@@ -153,8 +266,7 @@ bindCMethod(CMethod *m, PyObject *inst) ...@@ -153,8 +266,7 @@ bindCMethod(CMethod *m, PyObject *inst)
} }
static void static void
CMethod_dealloc(self) CMethod_dealloc(CMethod *self)
CMethod *self;
{ {
Py_DECREF(self->type); Py_DECREF(self->type);
Py_XDECREF(self->self); Py_XDECREF(self->self);
...@@ -162,11 +274,7 @@ CMethod_dealloc(self) ...@@ -162,11 +274,7 @@ CMethod_dealloc(self)
} }
static PyObject * static PyObject *
call_cmethod(self, inst, args, kw) call_cmethod(CMethod *self, PyObject *inst, PyObject *args, PyObject *kw)
CMethod *self;
PyObject *inst;
PyObject *args;
PyObject *kw;
{ {
if (!(self->flags & METH_VARARGS)) { if (!(self->flags & METH_VARARGS)) {
int size = PyTuple_Size(args); int size = PyTuple_Size(args);
...@@ -189,31 +297,9 @@ call_cmethod(self, inst, args, kw) ...@@ -189,31 +297,9 @@ call_cmethod(self, inst, args, kw)
} }
} }
static int
CMethod_issubclass(PyExtensionClass *sub, PyExtensionClass *type)
{
int i,l;
PyObject *t;
if(! sub->bases) return 0;
l=PyTuple_Size(sub->bases);
for(i=0; i < l; i++)
{
t=PyTuple_GET_ITEM(sub->bases, i);
if(t==(PyObject*)type) return 1;
if(t->ob_type==(PyTypeObject*)&CCLtype
&& ((PyExtensionClass*)t)->bases
&& CMethod_issubclass((PyExtensionClass*)t,type)
) return 1;
}
return 0;
}
static PyObject * static PyObject *
CMethod_call(self,args,kw) CMethod_call(CMethod *self, PyObject *args, PyObject *kw)
CMethod *self;
PyObject *args;
PyObject *kw;
{ {
int size; int size;
char *buf; char *buf;
...@@ -227,10 +313,10 @@ CMethod_call(self,args,kw) ...@@ -227,10 +313,10 @@ CMethod_call(self,args,kw)
UNLESS(first=PyTuple_GET_ITEM(args, 0)) return NULL; UNLESS(first=PyTuple_GET_ITEM(args, 0)) return NULL;
if(first->ob_type==self->type if(first->ob_type==self->type
|| ||
(first->ob_type->ob_type==(PyTypeObject*)&CCLtype (PyExtensionInstance_Check(first)
&& &&
CMethod_issubclass((PyExtensionClass *)(first->ob_type), CMethod_issubclass(PyExtensionClassOf(first),
(PyExtensionClass *)(self->type)) AsPyExtensionClass(self->type))
) )
); );
{ {
...@@ -253,9 +339,7 @@ CMethod_call(self,args,kw) ...@@ -253,9 +339,7 @@ CMethod_call(self,args,kw)
} }
static PyObject * static PyObject *
CMethod_getattr(self,name) CMethod_getattr(CMethod *self, char *name)
CMethod *self;
char *name;
{ {
PyObject *r; PyObject *r;
...@@ -299,7 +383,7 @@ static PyTypeObject CMethodType = { ...@@ -299,7 +383,7 @@ static PyTypeObject CMethodType = {
/* methods */ /* methods */
(destructor)CMethod_dealloc, /*tp_dealloc*/ (destructor)CMethod_dealloc, /*tp_dealloc*/
(printfunc)0, /*tp_print*/ (printfunc)0, /*tp_print*/
(getattrfunc)0, /*tp_getattr*/ (getattrfunc)CMethod_getattr, /*tp_getattr*/
(setattrfunc)0, /*tp_setattr*/ (setattrfunc)0, /*tp_setattr*/
(cmpfunc)0, /*tp_compare*/ (cmpfunc)0, /*tp_compare*/
(reprfunc)0, /*tp_repr*/ (reprfunc)0, /*tp_repr*/
...@@ -316,23 +400,32 @@ static PyTypeObject CMethodType = { ...@@ -316,23 +400,32 @@ static PyTypeObject CMethodType = {
/* Documentation string */ /* Documentation string */
}; };
/* Pmethod objects: */ /* PMethod objects: */
typedef struct { typedef struct {
PyObject_HEAD PyObject_HEAD
PyTypeObject *type; PyTypeObject *type;
PyObject *self; PyObject *self;
PyObject *meth; PyObject *meth;
} Pmethod; } PMethod;
staticforward PyTypeObject PMethodType;
#define PMethod_Check(O) ((O)->ob_type==&PMethodType)
#define UnboundPMethod_Check(O) \
((O)->ob_type==&PMethodType && ! ((PMethod*)(O))->self)
staticforward PyTypeObject PmethodType; #define UnboundEMethod_Check(O) \
(((O)->ob_type==&PMethodType ||(O)->ob_type==&CMethodType) \
&& ! ((PMethod*)(O))->self)
static Pmethod *
newPmethod(PyTypeObject *type, PyObject *meth) static PMethod *
newPMethod(PyTypeObject *type, PyObject *meth)
{ {
Pmethod *self; PMethod *self;
UNLESS(self = PyObject_NEW(Pmethod, &PmethodType)) return NULL; UNLESS(self = PyObject_NEW(PMethod, &PMethodType)) return NULL;
Py_INCREF(type); Py_INCREF(type);
Py_INCREF(meth); Py_INCREF(meth);
self->type=type; self->type=type;
...@@ -341,12 +434,20 @@ newPmethod(PyTypeObject *type, PyObject *meth) ...@@ -341,12 +434,20 @@ newPmethod(PyTypeObject *type, PyObject *meth)
return self; return self;
} }
static Pmethod * static PMethod *
bindPmethod(Pmethod *m, PyObject *inst) bindPMethod(PMethod *m, PyObject *inst)
{ {
Pmethod *self; PMethod *self;
UNLESS(PyExtensionInstance_Check(inst))
{
PyErr_SetString(PyExc_TypeError,
"attempt to wrap extension method using an object that\n"
"is not an extension class instance.");
return NULL;
}
UNLESS(self = PyObject_NEW(Pmethod, &PmethodType)) return NULL; UNLESS(self = PyObject_NEW(PMethod, &PMethodType)) return NULL;
Py_INCREF(inst); Py_INCREF(inst);
Py_INCREF(m->type); Py_INCREF(m->type);
...@@ -357,8 +458,7 @@ bindPmethod(Pmethod *m, PyObject *inst) ...@@ -357,8 +458,7 @@ bindPmethod(Pmethod *m, PyObject *inst)
} }
static void static void
Pmethod_dealloc(self) PMethod_dealloc(PMethod *self)
Pmethod *self;
{ {
Py_DECREF(self->type); Py_DECREF(self->type);
Py_XDECREF(self->self); Py_XDECREF(self->self);
...@@ -366,11 +466,7 @@ Pmethod_dealloc(self) ...@@ -366,11 +466,7 @@ Pmethod_dealloc(self)
} }
static PyObject * static PyObject *
call_pmethod(self, inst, args, kw) call_PMethod(PMethod *self, PyObject *inst, PyObject *args, PyObject *kw)
Pmethod *self;
PyObject *inst;
PyObject *args;
PyObject *kw;
{ {
PyObject *a; PyObject *a;
...@@ -381,16 +477,13 @@ call_pmethod(self, inst, args, kw) ...@@ -381,16 +477,13 @@ call_pmethod(self, inst, args, kw)
} }
static PyObject * static PyObject *
Pmethod_call(self,args,kw) PMethod_call(PMethod *self, PyObject *args, PyObject *kw)
Pmethod *self;
PyObject *args;
PyObject *kw;
{ {
int size; int size;
char *buf; char *buf;
PyObject *s; PyObject *s;
if(self->self) return call_pmethod(self,self->self,args,kw); if(self->self) return call_PMethod(self,self->self,args,kw);
if((size=PyTuple_Size(args)) > 0) if((size=PyTuple_Size(args)) > 0)
{ {
...@@ -398,16 +491,16 @@ Pmethod_call(self,args,kw) ...@@ -398,16 +491,16 @@ Pmethod_call(self,args,kw)
UNLESS(first=PyTuple_GET_ITEM(args, 0)) return NULL; UNLESS(first=PyTuple_GET_ITEM(args, 0)) return NULL;
if(first->ob_type==self->type if(first->ob_type==self->type
|| ||
(first->ob_type->ob_type==(PyTypeObject*)&CCLtype (PyExtensionInstance_Check(first)
&& &&
CMethod_issubclass((PyExtensionClass *)(first->ob_type), CMethod_issubclass(PyExtensionClassOf(first),
(PyExtensionClass *)(self->type)) AsPyExtensionClass(self->type))
) )
); );
{ {
PyObject *rest=0; PyObject *rest=0;
UNLESS(rest=PySequence_GetSlice(args,1,size)) return NULL; UNLESS(rest=PySequence_GetSlice(args,1,size)) return NULL;
return call_pmethod(self,first,rest,kw); return call_PMethod(self,first,rest,kw);
} }
} }
...@@ -424,9 +517,7 @@ Pmethod_call(self,args,kw) ...@@ -424,9 +517,7 @@ Pmethod_call(self,args,kw)
} }
static PyObject * static PyObject *
Pmethod_getattr(self,name) PMethod_getattr(PMethod *self, char *name)
Pmethod *self;
char *name;
{ {
PyObject *r; PyObject *r;
...@@ -455,16 +546,16 @@ Pmethod_getattr(self,name) ...@@ -455,16 +546,16 @@ Pmethod_getattr(self,name)
} }
} }
static PyTypeObject PmethodType = { static PyTypeObject PMethodType = {
PyObject_HEAD_INIT(&PyType_Type) PyObject_HEAD_INIT(&PyType_Type)
0, /*ob_size*/ 0, /*ob_size*/
"Python Method", /*tp_name*/ "Python Method", /*tp_name*/
sizeof(Pmethod), /*tp_basicsize*/ sizeof(PMethod), /*tp_basicsize*/
0, /*tp_itemsize*/ 0, /*tp_itemsize*/
/* methods */ /* methods */
(destructor)Pmethod_dealloc, /*tp_dealloc*/ (destructor)PMethod_dealloc, /*tp_dealloc*/
(printfunc)0, /*tp_print*/ (printfunc)0, /*tp_print*/
(getattrfunc)0, /*tp_getattr*/ (getattrfunc)PMethod_getattr, /*tp_getattr*/
(setattrfunc)0, /*tp_setattr*/ (setattrfunc)0, /*tp_setattr*/
(cmpfunc)0, /*tp_compare*/ (cmpfunc)0, /*tp_compare*/
(reprfunc)0, /*tp_repr*/ (reprfunc)0, /*tp_repr*/
...@@ -472,7 +563,7 @@ static PyTypeObject PmethodType = { ...@@ -472,7 +563,7 @@ static PyTypeObject PmethodType = {
0, /*tp_as_sequence*/ 0, /*tp_as_sequence*/
0, /*tp_as_mapping*/ 0, /*tp_as_mapping*/
(hashfunc)0, /*tp_hash*/ (hashfunc)0, /*tp_hash*/
(ternaryfunc)Pmethod_call, /*tp_call*/ (ternaryfunc)PMethod_call, /*tp_call*/
(reprfunc)0, /*tp_str*/ (reprfunc)0, /*tp_str*/
/* Space for future expansion */ /* Space for future expansion */
...@@ -537,6 +628,28 @@ setattr_by_name(PyObject *self, PyObject *args) ...@@ -537,6 +628,28 @@ setattr_by_name(PyObject *self, PyObject *args)
return Py_None; return Py_None;
} }
#if PYTHON_API_VERSION >= 1005
static PyObject *
getattro_by_name(PyObject *self, PyObject *args)
{
PyObject *name;
UNLESS(PyArg_Parse(args,"O",&name)) return NULL;
return self->ob_type->tp_getattro(self,name);
}
static PyObject *
setattro_by_name(PyObject *self, PyObject *args)
{
PyObject *name;
PyObject *v;
UNLESS(PyArg_Parse(args,"OO",&name,&v)) return NULL;
UNLESS(-1 != self->ob_type->tp_setattro(self,name,v)) return NULL;
Py_INCREF(Py_None);
return Py_None;
}
#endif
static PyObject * static PyObject *
length_by_name(PyObject *self, PyObject *args) length_by_name(PyObject *self, PyObject *args)
...@@ -725,6 +838,12 @@ getBaseDictionary(PyExtensionClass *type) ...@@ -725,6 +838,12 @@ getBaseDictionary(PyExtensionClass *type)
FILLENTRY(type->tp, compare, comp, 0, "compare with another object"); FILLENTRY(type->tp, compare, comp, 0, "compare with another object");
FILLENTRY(type->tp, getattr, getattr, 0, "Get an attribute"); FILLENTRY(type->tp, getattr, getattr, 0, "Get an attribute");
FILLENTRY(type->tp, setattr, setattr, 0, "Set an attribute"); FILLENTRY(type->tp, setattr, setattr, 0, "Set an attribute");
#if PYTHON_API_VERSION >= 1005
FILLENTRY(type->tp, getattro, getattr, 0, "Get an attribute");
FILLENTRY(type->tp, setattro, setattr, 0, "Set an attribute");
#endif
if(sm=type->tp_as_sequence) if(sm=type->tp_as_sequence)
{ {
FILLENTRY(sm->sq, length, len, 0, "Get the object length"); FILLENTRY(sm->sq, length, len, 0, "Get the object length");
...@@ -837,8 +956,7 @@ initializeBaseExtensionClass(PyExtensionClass *self) ...@@ -837,8 +956,7 @@ initializeBaseExtensionClass(PyExtensionClass *self)
} }
static void static void
CCL_dealloc(self) CCL_dealloc(PyExtensionClass *self)
PyExtensionClass *self;
{ {
Py_XDECREF(self->class_dictionary); Py_XDECREF(self->class_dictionary);
Py_XDECREF(self->bases); Py_XDECREF(self->bases);
...@@ -849,9 +967,8 @@ CCL_dealloc(self) ...@@ -849,9 +967,8 @@ CCL_dealloc(self)
static PyObject *CCL_getattr(); static PyObject *CCL_getattr();
static PyObject * static PyObject *
ExtensionClass_FindInstanceAttribute(inst,name) ExtensionClass_FindInstanceAttribute(PyObject *inst, PyObject *oname,
PyObject *inst; char *name)
char *name;
{ {
/* Look up an attribute for an instance from: /* Look up an attribute for an instance from:
...@@ -862,6 +979,8 @@ ExtensionClass_FindInstanceAttribute(inst,name) ...@@ -862,6 +979,8 @@ ExtensionClass_FindInstanceAttribute(inst,name)
PyObject *r=0; PyObject *r=0;
PyExtensionClass *self; PyExtensionClass *self;
if(! name) return NULL;
self=(PyExtensionClass*)(inst->ob_type); self=(PyExtensionClass*)(inst->ob_type);
if(*name=='_' && name[1]=='_') if(*name=='_' && name[1]=='_')
...@@ -882,25 +1001,25 @@ ExtensionClass_FindInstanceAttribute(inst,name) ...@@ -882,25 +1001,25 @@ ExtensionClass_FindInstanceAttribute(inst,name)
if(self->bases) if(self->bases)
{ {
r= INSTANCE_DICT(inst); r= INSTANCE_DICT(inst);
r = PyMapping_GetItemString(r,name); r = PyObject_GetItem(r,oname);
} }
UNLESS(r) UNLESS(r)
{ {
PyErr_Clear(); PyErr_Clear();
UNLESS(r=CCL_getattr(self,name)) return NULL; UNLESS(r=CCL_getattr(self,oname,name)) return NULL;
/* We got something from our class, maybe its an unbound method. */ /* We got something from our class, maybe its an unbound method. */
if(r->ob_type==&CMethodType) if(UnboundCMethod_Check(r))
{ {
UNLESS_ASSIGN(r,(PyObject*)bindCMethod((CMethod*)r,inst)) UNLESS_ASSIGN(r,(PyObject*)bindCMethod((CMethod*)r,inst))
return NULL; return NULL;
} }
if(r->ob_type==&PmethodType) else if(UnboundPMethod_Check(r))
{ {
PyObject *m; PyObject *m;
m=((Pmethod *)r)->meth; m=((PMethod *)r)->meth;
if(m->ob_type->ob_type==(PyTypeObject*)&CCLtype && if(PyExtensionInstance_Check(m) &&
(((PyExtensionClass*)m->ob_type)->class_flags & (PyExtensionClassOf(m)->class_flags &
EXTENSIONCLASS_BINDABLE_FLAG EXTENSIONCLASS_BINDABLE_FLAG
) )
) )
...@@ -911,7 +1030,7 @@ ExtensionClass_FindInstanceAttribute(inst,name) ...@@ -911,7 +1030,7 @@ ExtensionClass_FindInstanceAttribute(inst,name)
} }
else else
{ {
UNLESS_ASSIGN(r,(PyObject*)bindPmethod((Pmethod*)r,inst)) UNLESS_ASSIGN(r,(PyObject*)bindPMethod((PMethod*)r,inst))
return NULL; return NULL;
} }
} }
...@@ -921,19 +1040,47 @@ ExtensionClass_FindInstanceAttribute(inst,name) ...@@ -921,19 +1040,47 @@ ExtensionClass_FindInstanceAttribute(inst,name)
} }
static PyObject * static PyObject *
CCL_getattr(self, name) EC_findiattrs(PyObject *self, char *name)
PyExtensionClass *self; {
char *name; PyObject *s, *r;
UNLESS(s=PyString_FromString(name)) return NULL;
r=ExtensionClass_FindInstanceAttribute(self,s,name);
Py_DECREF(s);
return r;
}
static PyObject *
EC_findiattro(PyObject *self, PyObject *name)
{
return ExtensionClass_FindInstanceAttribute(self,name,
PyString_AsString(name));
}
static int
subclass_simple_setattr(PyObject *self, char *name, PyObject *v);
static PyObject *
CCL_getattr(PyExtensionClass *self, PyObject *oname, char *name)
{ {
PyObject *r; PyObject *r;
int local=1; int local=1;
char *n;
if(*name=='.' && name[1]==0) if(! name) return NULL;
return (PyObject*)ExtensionClass_FindInstanceAttribute;
if(*name=='.')
{
n=name+1;
if(*n==0)
return (PyObject*)EC_findiattrs;
if(*n=='o' && n[1]==0)
return (PyObject*)EC_findiattro;
if(*n=='s' && n[1]==0)
return (PyObject*)subclass_simple_setattr;
}
if(*name=='_' && name[1]=='_') if(*name=='_' && name[1]=='_')
{ {
char *n;
n=name+2; n=name+2;
if(strcmp(n,"doc__")==0 && self->tp_doc) if(strcmp(n,"doc__")==0 && self->tp_doc)
return PyString_FromString(self->tp_doc); return PyString_FromString(self->tp_doc);
...@@ -956,7 +1103,7 @@ CCL_getattr(self, name) ...@@ -956,7 +1103,7 @@ CCL_getattr(self, name)
} }
} }
r=PyMapping_GetItemString(self->class_dictionary,name); r=PyObject_GetItem(self->class_dictionary,oname);
UNLESS(r) UNLESS(r)
{ {
local=0; local=0;
...@@ -970,7 +1117,7 @@ CCL_getattr(self, name) ...@@ -970,7 +1117,7 @@ CCL_getattr(self, name)
{ {
PyErr_Clear(); PyErr_Clear();
c=PyTuple_GET_ITEM(self->bases, i); c=PyTuple_GET_ITEM(self->bases, i);
if(r=PyObject_GetAttrString(c,name)) break; if(r=PyObject_GetAttr(c,oname)) break;
} }
} }
UNLESS(r) UNLESS(r)
...@@ -979,9 +1126,7 @@ CCL_getattr(self, name) ...@@ -979,9 +1126,7 @@ CCL_getattr(self, name)
char *s; char *s;
PyErr_Fetch(&t,&v,&tb); PyErr_Fetch(&t,&v,&tb);
if(t==PyExc_KeyError && if(t==PyExc_KeyError && PyObject_Compare(v,oname) == 0)
PyString_Check(v) && (s=PyString_AsString(v))
&& strcmp(s,name)==0)
{ {
Py_DECREF(t); Py_DECREF(t);
t=PyExc_AttributeError; t=PyExc_AttributeError;
...@@ -993,25 +1138,46 @@ CCL_getattr(self, name) ...@@ -993,25 +1138,46 @@ CCL_getattr(self, name)
} }
if(PyFunction_Check(r) || if(PyFunction_Check(r) ||
(r->ob_type->ob_type==(PyTypeObject*)&CCLtype && (PyExtensionInstance_Check(r) &&
(((PyExtensionClass*)r->ob_type)->class_flags & (PyExtensionClassOf(r)->class_flags &
EXTENSIONCLASS_BINDABLE_FLAG EXTENSIONCLASS_BINDABLE_FLAG
) )
) )
) )
UNLESS_ASSIGN(r,(PyObject*)newPmethod((PyTypeObject *)self,r)) {
UNLESS_ASSIGN(r,(PyObject*)newPMethod((PyTypeObject *)self,r))
return NULL; return NULL;
}
if(PyMethod_Check(r) && ! PyMethod_Self(r)) else if(PyMethod_Check(r) && ! PyMethod_Self(r))
UNLESS_ASSIGN(r,(PyObject*)newPmethod((PyTypeObject *)self, {
UNLESS_ASSIGN(r,(PyObject*)newPMethod((PyTypeObject *)self,
PyMethod_Function(r))) PyMethod_Function(r)))
return NULL; return NULL;
}
else local=0;
if(local) /* We have a PMethod that we built from our dict, cache it */
{
UNLESS(-1 != PyObject_SetItem(self->class_dictionary, oname, r))
PyErr_Clear(); /* Oh well */
}
return r;
}
PyObject *
CCL_getattrs(PyExtensionClass *self, char *name)
{
PyObject *s, *r;
UNLESS(s=PyString_FromString(name)) return NULL;
r=CCL_getattr(self,s,name);
Py_DECREF(s);
return r; return r;
} }
static int static int
CCL_setattr(self, name, v) CCL_setattrs(self, name, v)
PyExtensionClass *self; PyExtensionClass *self;
char *name; char *name;
PyObject *v; PyObject *v;
...@@ -1019,10 +1185,138 @@ CCL_setattr(self, name, v) ...@@ -1019,10 +1185,138 @@ CCL_setattr(self, name, v)
return PyMapping_SetItemString(self->class_dictionary, name, v); return PyMapping_SetItemString(self->class_dictionary, name, v);
} }
PyObject *
CCL_getattro(PyExtensionClass *self, PyObject *name)
{
return CCL_getattr(self,name,PyString_AsString(name));
}
static int
CCL_setattro(PyExtensionClass *self, PyObject *name, PyObject *v)
{
if(UnboundCMethod_Check(v))
{
char *n;
PyNumberMethods *nm;
PySequenceMethods *s, *ms;
PyMappingMethods *m, *mm;
UNLESS(n=PyString_AsString(name)) return -1;
if(*n=='_' && n[1]=='_')
{
n+=2;
#define SET_SPECIAL(C,P) \
if(strcmp(n,#P "__")==0 \
&& AsCMethod(v)->meth==(PyCFunction)C ## _by_name \
&& Subclass_Check(self,AsCMethod(v)->type)) { \
self->tp_ ## C=AsCMethod(v)->type->tp_ ## C; \
return PyObject_SetItem(self->class_dictionary, name, v); }
/*
SET_SPECIAL(setattr,setattr);
SET_SPECIAL(setattro,setattr);
*/
SET_SPECIAL(compare,cmp);
SET_SPECIAL(hash,hash);
SET_SPECIAL(repr,repr);
SET_SPECIAL(call,call);
SET_SPECIAL(str,str);
#undef SET_SPECIAL
#define SET_SPECIAL(C,P) \
if(strcmp(n,#P "__")==0 && AsCMethod(v)->meth==C ## _by_name \
&& Subclass_Check(self,AsCMethod(v)->type) \
&& (nm=self->tp_as_number)) { \
nm->nb_ ## C=AsCMethod(v)->type->tp_as_number->nb_ ## C; \
return PyObject_SetItem(self->class_dictionary, name, v); }
SET_SPECIAL(add,add);
SET_SPECIAL(subtract,sub);
SET_SPECIAL(multiply,mult);
SET_SPECIAL(divide,div);
SET_SPECIAL(remainder,mod);
SET_SPECIAL(power,pow);
SET_SPECIAL(divmod,divmod);
SET_SPECIAL(lshift,lshift);
SET_SPECIAL(rshift,rshift);
SET_SPECIAL(and,and);
SET_SPECIAL(or,or);
SET_SPECIAL(xor,xor);
SET_SPECIAL(coerce,coerce);
SET_SPECIAL(negative,neg);
SET_SPECIAL(positive,pos);
SET_SPECIAL(absolute,abs);
SET_SPECIAL(nonzero,nonzero);
SET_SPECIAL(invert,inv);
SET_SPECIAL(int,int);
SET_SPECIAL(long,long);
SET_SPECIAL(float,float);
SET_SPECIAL(oct,oct);
SET_SPECIAL(hex,hex);
#undef SET_SPECIAL
if(strcmp(n,"len__")==0 && AsCMethod(v)->meth==length_by_name
&& Subclass_Check(self,AsCMethod(v)->type))
{
if((s=self->tp_as_sequence) &&
(ms=AsCMethod(v)->type->tp_as_sequence) &&
ms->sq_length)
s->sq_length=ms->sq_length;
if((m=self->tp_as_mapping) &&
(mm=AsCMethod(v)->type->tp_as_mapping) &&
mm->mp_length)
m->mp_length=mm->mp_length;
return PyObject_SetItem(self->class_dictionary, name, v);
}
if(strcmp(n,"getitem__")==0 && AsCMethod(v)->meth==getitem_by_name
&& Subclass_Check(self,AsCMethod(v)->type))
{
if((s=self->tp_as_sequence) &&
(ms=AsCMethod(v)->type->tp_as_sequence) &&
ms->sq_item)
s->sq_item=ms->sq_item;
if((m=self->tp_as_mapping) &&
(mm=AsCMethod(v)->type->tp_as_mapping) &&
mm->mp_subscript)
m->mp_subscript=mm->mp_subscript;
return PyObject_SetItem(self->class_dictionary, name, v);
}
if(strcmp(n,"setitem__")==0 &&
AsCMethod(v)->meth==(PyCFunction)setitem_by_name
&& Subclass_Check(self,AsCMethod(v)->type))
{
if((s=self->tp_as_sequence) &&
(ms=AsCMethod(v)->type->tp_as_sequence) &&
ms->sq_ass_item)
s->sq_ass_item=ms->sq_ass_item;
if((m=self->tp_as_mapping) &&
(mm=AsCMethod(v)->type->tp_as_mapping) &&
mm->mp_ass_subscript)
m->mp_ass_subscript=mm->mp_ass_subscript;
return PyObject_SetItem(self->class_dictionary, name, v);
}
#define SET_SPECIAL(C,P) \
if(strcmp(n,#P "__")==0 \
&& AsCMethod(v)->meth==(PyCFunction)C ## _by_name \
&& Subclass_Check(self,AsCMethod(v)->type) \
&& (s=self->tp_as_sequence)) { \
s->sq_ ## C=AsCMethod(v)->type->tp_as_sequence->sq_ ## C; \
return PyObject_SetItem(self->class_dictionary, name, v); }
SET_SPECIAL(slice,getslice);
SET_SPECIAL(ass_slice,setslice);
SET_SPECIAL(concat,concat);
SET_SPECIAL(repeat,repeat);
#undef SET_SPECIAL
}
}
return PyObject_SetItem(self->class_dictionary, name, v);
}
static PyObject * static PyObject *
CCL_call(self, arg, kw) CCL_call(PyExtensionClass *self, PyObject *arg, PyObject *kw)
PyExtensionClass *self;
PyObject *arg, *kw;
{ {
PyObject *inst=0, *init=0, *args=0; PyObject *inst=0, *init=0, *args=0;
int check; int check;
...@@ -1045,7 +1339,7 @@ CCL_call(self, arg, kw) ...@@ -1045,7 +1339,7 @@ CCL_call(self, arg, kw)
PyObject *var_size; PyObject *var_size;
int size; int size;
if(var_size=CCL_getattr(self,"__var_size__")) if(var_size=CCL_getattro(self,py__var_size__))
{ {
UNLESS_ASSIGN(var_size,PyObject_CallObject(var_size,args)) UNLESS_ASSIGN(var_size,PyObject_CallObject(var_size,args))
return NULL; return NULL;
...@@ -1093,7 +1387,7 @@ CCL_call(self, arg, kw) ...@@ -1093,7 +1387,7 @@ CCL_call(self, arg, kw)
if(init=CCL_getattr(self,"__init__")) if(init=CCL_getattro(self,py__init__))
{ {
UNLESS(args=Py_BuildValue("(O)",inst)) goto err; UNLESS(args=Py_BuildValue("(O)",inst)) goto err;
if(arg) UNLESS_ASSIGN(args,PySequence_Concat(args,arg)) goto err; if(arg) UNLESS_ASSIGN(args,PySequence_Concat(args,arg)) goto err;
...@@ -1113,8 +1407,7 @@ err: ...@@ -1113,8 +1407,7 @@ err:
} }
static PyObject * static PyObject *
CCL_repr(self) CCL_repr(PyExtensionClass *self)
PyExtensionClass *self;
{ {
PyObject *s; PyObject *s;
int l; int l;
...@@ -1124,7 +1417,7 @@ CCL_repr(self) ...@@ -1124,7 +1417,7 @@ CCL_repr(self)
l=strlen(self->ob_type->tp_name)+strlen(p); l=strlen(self->ob_type->tp_name)+strlen(p);
UNLESS(s=PyString_FromStringAndSize(NULL,l+22)) return NULL; UNLESS(s=PyString_FromStringAndSize(NULL,l+22)) return NULL;
buf=PyString_AsString(s); buf=PyString_AsString(s);
sprintf(buf,"<extension class %s at %p>",self->tp_name); sprintf(buf,"<extension class %s at %p>", self->tp_name, self);
return s; return s;
} }
...@@ -1137,8 +1430,8 @@ static PyTypeObject CCLtype_class = { ...@@ -1137,8 +1430,8 @@ static PyTypeObject CCLtype_class = {
/* methods */ /* methods */
(destructor)CCL_dealloc, /*tp_dealloc*/ (destructor)CCL_dealloc, /*tp_dealloc*/
(printfunc)0, /*tp_print*/ (printfunc)0, /*tp_print*/
(getattrfunc)CCL_getattr, /*tp_getattr*/ (getattrfunc)CCL_getattrs, /*tp_getattr*/
(setattrfunc)CCL_setattr, /*tp_setattr*/ (setattrfunc)CCL_setattrs, /*tp_setattr*/
(cmpfunc)0, /*tp_compare*/ (cmpfunc)0, /*tp_compare*/
(reprfunc)CCL_repr, /*tp_repr*/ (reprfunc)CCL_repr, /*tp_repr*/
0, /*tp_as_number*/ 0, /*tp_as_number*/
...@@ -1147,9 +1440,14 @@ static PyTypeObject CCLtype_class = { ...@@ -1147,9 +1440,14 @@ static PyTypeObject CCLtype_class = {
(hashfunc)0, /*tp_hash*/ (hashfunc)0, /*tp_hash*/
(ternaryfunc)CCL_call, /*tp_call*/ (ternaryfunc)CCL_call, /*tp_call*/
(reprfunc)0, /*tp_str*/ (reprfunc)0, /*tp_str*/
#if PYTHON_API_VERSION >= 1005
(getattrofunc)CCL_getattro, /*tp_getattr with object key*/
(setattrofunc)CCL_setattro, /*tp_setattr with object key*/
#else
/* Space for future expansion */ /* Space for future expansion */
0L,0L,0L,0L, 0L,0L,
#endif
0L,0L,
"Class of C classes" /* Documentation string */ "Class of C classes" /* Documentation string */
}; };
...@@ -1158,20 +1456,90 @@ static PyTypeObject CCLtype_class = { ...@@ -1158,20 +1456,90 @@ static PyTypeObject CCLtype_class = {
/* subclassing code: */ /* subclassing code: */
static PyObject *
subclass_getspecial(PyObject *inst, PyObject *oname)
{
PyObject *r=0;
PyExtensionClass *self;
self=(PyExtensionClass*)(inst->ob_type);
r= INSTANCE_DICT(inst);
r = PyObject_GetItem(r,oname);
UNLESS(r)
{
PyErr_Clear();
r=CCL_getattr(self,oname,"");
}
return r;
}
static PyObject *
subclass_getattro(PyObject *self, PyObject *name)
{
PyObject *r=0;
if(! name) return NULL;
UNLESS(r=EC_findiattro(self,name))
{
PyErr_Clear();
UNLESS(r=EC_findiattro(self,py__getattr__)) return NULL;
UNLESS_ASSIGN(r,PyObject_CallFunction(r,"O",name)) return NULL;
}
return r;
}
static PyObject *
subclass_getattrs(PyObject *self, char *name)
{
return subclass_getattro(self,PyString_FromString(name));
}
static int static int
subclass_setattr(PyObject *self, char *name, PyObject *v) subclass_simple_setattro(PyObject *self, PyObject *name, PyObject *v)
{
Py_INCREF(v);
return PyDict_SetItem(INSTANCE_DICT(self),name,v);
}
static int
subclass_simple_setattr(PyObject *self, char *name, PyObject *v)
{
Py_INCREF(v);
return PyDict_SetItemString(INSTANCE_DICT(self),name,v);
}
static int
subclass_setattr(PyObject *self, PyObject *oname, char *name, PyObject *v)
{ {
PyObject *m=0, *et, *ev, *etb; PyObject *m=0, *et, *ev, *etb;
UNLESS(m=PyObject_GetAttrString(self,"__setattr__")) if(! name) return -1;
UNLESS(m=subclass_getspecial(self,py__setattr__))
goto default_setattr; goto default_setattr;
if(m->ob_type==&CMethodType && ((CMethod*)m)->meth==setattr_by_name) if(UnboundCMethod_Check(m) && AsCMethod(m)->meth==setattr_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type))
{ {
UNLESS(-1 != ((CMethod*)m)->type->tp_setattr(self,name,v)) UNLESS(-1 != AsCMethod(m)->type->tp_setattr(self,name,v))
goto dictionary_setattr; goto dictionary_setattr;
return 0; return 0;
} }
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"sO",name,v)) return -1; #if PYTHON_API_VERSION >= 1005
else
if(UnboundCMethod_Check(m) && AsCMethod(m)->meth==setattro_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type))
{
UNLESS(-1 != AsCMethod(m)->type->tp_setattro(self,oname,v))
goto dictionary_setattr;
return 0;
}
#endif
if(UnboundEMethod_Check(m))
{
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"OOO",self,oname,v)) return -1;
}
else UNLESS_ASSIGN(m,PyObject_CallFunction(m,"OO",oname,v)) return -1;
Py_DECREF(m); Py_DECREF(m);
return 0; return 0;
...@@ -1203,24 +1571,46 @@ default_setattr: ...@@ -1203,24 +1571,46 @@ default_setattr:
PyErr_Clear(); PyErr_Clear();
UNLESS(-1 != PyMapping_SetItemString(INSTANCE_DICT(self),name,v)) return subclass_simple_setattro(self, oname, v);
return -1; }
return 0; static int
subclass_setattrs(PyObject *self, char *name, PyObject *v)
{
PyObject *s;
int r;
UNLESS(s=PyString_FromString(name)) return -1;
r=subclass_setattr(self,s,name,v);
Py_DECREF(s);
return r;
}
static int
subclass_setattro(PyObject *self, PyObject *name, PyObject *v)
{
return subclass_setattr(self,name,PyString_AsString(name),v);
} }
static int static int
subclass_compare(PyObject *self, PyObject *v) subclass_compare(PyObject *self, PyObject *v)
{ {
PyObject *m; PyObject *m;
long r; long r;
UNLESS(m=PyObject_GetAttrString(self,"__cmp__")) return -1; UNLESS(m=subclass_getspecial(self,py__cmp__)) return -1;
if(m->ob_type==&CMethodType && ((CMethod*)m)->meth==compare_by_name) if(UnboundCMethod_Check(m) && AsCMethod(m)->meth==compare_by_name
r=((CMethod*)m)->type->tp_compare(self,v); && SubclassInstance_Check(self,AsCMethod(m)->type))
r=AsCMethod(m)->type->tp_compare(self,v);
else else
{ {
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"O",v)) return -1; if(UnboundEMethod_Check(m))
{
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"OO",self,v))
return -1;
}
else UNLESS_ASSIGN(m,PyObject_CallFunction(m,"O",v)) return -1;
r=PyInt_AsLong(m); r=PyInt_AsLong(m);
} }
Py_DECREF(m); Py_DECREF(m);
...@@ -1233,12 +1623,18 @@ subclass_hash(PyObject *self) ...@@ -1233,12 +1623,18 @@ subclass_hash(PyObject *self)
PyObject *m; PyObject *m;
long r; long r;
UNLESS(m=PyObject_GetAttrString(self,"__hash__")) return -1; UNLESS(m=subclass_getspecial(self,py__hash__)) return -1;
if(m->ob_type==&CMethodType && ((CMethod*)m)->meth==hash_by_name) if(UnboundCMethod_Check(m) && AsCMethod(m)->meth==hash_by_name
r=((CMethod*)m)->type->tp_hash(self); && SubclassInstance_Check(self,AsCMethod(m)->type))
r=AsCMethod(m)->type->tp_hash(self);
else else
{ {
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"")) return -1; if(UnboundEMethod_Check(m))
{
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"O",self))
return -1;
}
else UNLESS_ASSIGN(m,PyObject_CallFunction(m,"")) return -1;
r=PyInt_AsLong(m); r=PyInt_AsLong(m);
} }
Py_DECREF(m); Py_DECREF(m);
...@@ -1250,7 +1646,7 @@ subclass_repr(PyObject *self) ...@@ -1250,7 +1646,7 @@ subclass_repr(PyObject *self)
{ {
PyObject *m; PyObject *m;
UNLESS(m=PyObject_GetAttrString(self,"__repr__")) UNLESS(m=subclass_getspecial(self,py__repr__))
{ {
int l; int l;
char *buf, p[64]; char *buf, p[64];
...@@ -1263,13 +1659,19 @@ subclass_repr(PyObject *self) ...@@ -1263,13 +1659,19 @@ subclass_repr(PyObject *self)
sprintf(buf,"<%s instance at %s>",self->ob_type->tp_name,p); sprintf(buf,"<%s instance at %s>",self->ob_type->tp_name,p);
return m; return m;
} }
if(m->ob_type==&CMethodType && ((CMethod*)m)->meth==repr_by_name) if(UnboundCMethod_Check(m) && AsCMethod(m)->meth==repr_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type))
{ {
UNLESS_ASSIGN(m,((CMethod*)m)->type->tp_repr(self)) return NULL; UNLESS_ASSIGN(m,AsCMethod(m)->type->tp_repr(self)) return NULL;
} }
else else
{ {
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"")) return NULL; if(UnboundEMethod_Check(m))
{
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"O",self))
return NULL;
}
else UNLESS_ASSIGN(m,PyObject_CallFunction(m,"")) return NULL;
} }
return m; return m;
} }
...@@ -1277,18 +1679,29 @@ subclass_repr(PyObject *self) ...@@ -1277,18 +1679,29 @@ subclass_repr(PyObject *self)
static PyObject * static PyObject *
subclass_call(PyObject *self, PyObject *args, PyObject *kw) subclass_call(PyObject *self, PyObject *args, PyObject *kw)
{ {
PyObject *m; PyObject *m, *a=0;
UNLESS(m=PyObject_GetAttrString(self,"__call__")) return NULL; UNLESS(m=subclass_getspecial(self,py__call__)) return NULL;
if(m->ob_type==&CMethodType && ((CMethod*)m)->meth==(PyCFunction)call_by_name) if(UnboundCMethod_Check(m) && AsCMethod(m)->meth==(PyCFunction)call_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type))
{ {
UNLESS_ASSIGN(m,((CMethod*)m)->type->tp_call(self,args,kw)) return NULL; UNLESS_ASSIGN(m,AsCMethod(m)->type->tp_call(self,args,kw)) return NULL;
} }
else else
{ {
UNLESS_ASSIGN(m,PyEval_CallObjectWithKeywords(m,args,kw)) return NULL; if(UnboundEMethod_Check(m))
{
UNLESS(a=Py_BuildValue("(O)",self)) goto err;
UNLESS_ASSIGN(a,PySequence_Concat(a,args)) goto err;
args=a;
}
UNLESS_ASSIGN(m,PyEval_CallObjectWithKeywords(m,args,kw)) goto err;
} }
Py_XDECREF(a);
return m; return m;
err:
Py_XDECREF(m);
Py_XDECREF(a);
} }
static PyObject * static PyObject *
...@@ -1296,18 +1709,24 @@ subclass_str(PyObject *self) ...@@ -1296,18 +1709,24 @@ subclass_str(PyObject *self)
{ {
PyObject *m; PyObject *m;
UNLESS(m=PyObject_GetAttrString(self,"__str__")) UNLESS(m=subclass_getspecial(self,py__str__))
{ {
PyErr_Clear(); PyErr_Clear();
return subclass_repr(self); return subclass_repr(self);
} }
if(m->ob_type==&CMethodType && ((CMethod*)m)->meth==str_by_name) if(UnboundCMethod_Check(m) && AsCMethod(m)->meth==str_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type))
{ {
UNLESS_ASSIGN(m,((CMethod*)m)->type->tp_str(self)) return NULL; UNLESS_ASSIGN(m,AsCMethod(m)->type->tp_str(self)) return NULL;
} }
else else
{ {
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"")) return NULL; if(UnboundEMethod_Check(m))
{
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"O",self))
return NULL;
}
else UNLESS_ASSIGN(m,PyObject_CallFunction(m,"")) return NULL;
} }
return m; return m;
} }
...@@ -1317,15 +1736,21 @@ static PyObject * \ ...@@ -1317,15 +1736,21 @@ static PyObject * \
subclass_ ## M(PyObject *self, PyObject *v) \ subclass_ ## M(PyObject *self, PyObject *v) \
{ \ { \
PyObject *m; \ PyObject *m; \
UNLESS(m=PyObject_GetAttrString(self,"__" # M "__")) return NULL; \ UNLESS(m=subclass_getspecial(self,py__ ## N ## __)) return NULL; \
if(m->ob_type==&CMethodType && ((CMethod*)m)->meth==M ## _by_name) \ if(UnboundCMethod_Check(m) && AsCMethod(m)->meth==M ## _by_name \
&& SubclassInstance_Check(self,AsCMethod(m)->type)) \
{ \ { \
UNLESS_ASSIGN(m,PyNumber_ ## A(self,v)) \ UNLESS_ASSIGN(m,PyNumber_ ## A(self,v)) \
return NULL; \ return NULL; \
} \ } \
else \ else \
{ \ { \
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"O",v)) return NULL; \ if(UnboundEMethod_Check(m)) \
{ \
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"OO",self,v)) \
return NULL; \
} \
else UNLESS_ASSIGN(m,PyObject_CallFunction(m,"O",v)) return NULL; \
} \ } \
return m; \ return m; \
} }
...@@ -1340,15 +1765,21 @@ static PyObject * ...@@ -1340,15 +1765,21 @@ static PyObject *
subclass_power(PyObject *self, PyObject *v, PyObject *w) subclass_power(PyObject *self, PyObject *v, PyObject *w)
{ {
PyObject *m; PyObject *m;
UNLESS(m=PyObject_GetAttrString(self,"__pow__")) return NULL; UNLESS(m=subclass_getspecial(self,py__pow__)) return NULL;
if(m->ob_type==&CMethodType && ((CMethod*)m)->meth==power_by_name) if(UnboundCMethod_Check(m) && AsCMethod(m)->meth==power_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type))
{ {
UNLESS_ASSIGN(m,((CMethod*)m)->type->tp_as_number->nb_power(self,v,w)) UNLESS_ASSIGN(m,AsCMethod(m)->type->tp_as_number->nb_power(self,v,w))
return NULL; return NULL;
} }
else else
{ {
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"OO",v,w)) return NULL; if(UnboundEMethod_Check(m))
{
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"OOO",self,v,w))
return NULL;
}
else UNLESS_ASSIGN(m,PyObject_CallFunction(m,"OO",v,w)) return NULL;
} }
return m; return m;
} }
...@@ -1368,12 +1799,18 @@ subclass_coerce(PyObject **self, PyObject **v) ...@@ -1368,12 +1799,18 @@ subclass_coerce(PyObject **self, PyObject **v)
PyObject *m; PyObject *m;
int r; int r;
UNLESS(m=PyObject_GetAttrString(*self,"__coerce__")) return -1; UNLESS(m=subclass_getspecial(*self,py__coerce__)) return -1;
if(m->ob_type==&CMethodType && ((CMethod*)m)->meth==coerce_by_name) if(UnboundCMethod_Check(m) && AsCMethod(m)->meth==coerce_by_name
r=((CMethod*)m)->type->tp_as_number->nb_coerce(self,v); && SubclassInstance_Check(*self,AsCMethod(m)->type))
r=AsCMethod(m)->type->tp_as_number->nb_coerce(self,v);
else else
{ {
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"OO",*self,*v)) return -1; if(UnboundEMethod_Check(m))
{
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"OO",*self,v))
return NULL;
}
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"O",*v)) return -1;
if(m==Py_None) r=-1; if(m==Py_None) r=-1;
else else
{ {
...@@ -1392,15 +1829,21 @@ static PyObject * \ ...@@ -1392,15 +1829,21 @@ static PyObject * \
subclass_ ## M(PyObject *self) \ subclass_ ## M(PyObject *self) \
{ \ { \
PyObject *m; \ PyObject *m; \
UNLESS(m=PyObject_GetAttrString(self,"__" # M "__")) return NULL; \ UNLESS(m=subclass_getspecial(self,py__ ## N ## __)) return NULL; \
if(m->ob_type==&CMethodType && ((CMethod*)m)->meth==M ## _by_name) \ if(UnboundCMethod_Check(m) && AsCMethod(m)->meth==M ## _by_name \
&& SubclassInstance_Check(self,AsCMethod(m)->type)) \
{ \ { \
UNLESS_ASSIGN(m,((CMethod*)m)->type->tp_as_number->nb_ ## M(self)) \ UNLESS_ASSIGN(m,AsCMethod(m)->type->tp_as_number->nb_ ## M(self)) \
return NULL; \ return NULL; \
} \ } \
else \ else \
{ \ { \
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"O")) return NULL; \ if(UnboundEMethod_Check(m)) \
{ \
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"O",self)) \
return NULL; \
} \
else UNLESS_ASSIGN(m,PyObject_CallFunction(m,"")) return NULL; \
} \ } \
return m; \ return m; \
} }
...@@ -1415,12 +1858,18 @@ subclass_nonzero(PyObject *self) ...@@ -1415,12 +1858,18 @@ subclass_nonzero(PyObject *self)
PyObject *m; PyObject *m;
long r; long r;
UNLESS(m=PyObject_GetAttrString(self,"__nonzero__")) return -1; UNLESS(m=subclass_getspecial(self,py__nonzero__)) return -1;
if(m->ob_type==&CMethodType && ((CMethod*)m)->meth==nonzero_by_name) if(UnboundCMethod_Check(m) && AsCMethod(m)->meth==nonzero_by_name
r=((CMethod*)m)->type->tp_as_number->nb_nonzero(self); && SubclassInstance_Check(self,AsCMethod(m)->type))
r=AsCMethod(m)->type->tp_as_number->nb_nonzero(self);
else else
{ {
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"")) return -1; if(UnboundEMethod_Check(m))
{
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"O",self))
return -1;
}
else UNLESS_ASSIGN(m,PyObject_CallFunction(m,"")) return -1;
r=PyInt_AsLong(m); r=PyInt_AsLong(m);
} }
Py_DECREF(m); Py_DECREF(m);
...@@ -1471,10 +1920,11 @@ subclass_length(PyObject *self) ...@@ -1471,10 +1920,11 @@ subclass_length(PyObject *self)
long r; long r;
PyExtensionClass *t; PyExtensionClass *t;
UNLESS(m=PyObject_GetAttrString(self,"__len__")) return -1; UNLESS(m=subclass_getspecial(self,py__len__)) return -1;
if(m->ob_type==&CMethodType && ((CMethod*)m)->meth==length_by_name) if(UnboundCMethod_Check(m) && AsCMethod(m)->meth==length_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type))
{ {
t=(PyExtensionClass*)((CMethod*)m)->type; t=(PyExtensionClass*)AsCMethod(m)->type;
Py_DECREF(m); Py_DECREF(m);
if(t->tp_as_sequence) if(t->tp_as_sequence)
return t->tp_as_sequence->sq_length(self); return t->tp_as_sequence->sq_length(self);
...@@ -1496,10 +1946,11 @@ subclass_item(PyObject *self, int index) ...@@ -1496,10 +1946,11 @@ subclass_item(PyObject *self, int index)
PyObject *m; PyObject *m;
PyExtensionClass *t; PyExtensionClass *t;
UNLESS(m=PyObject_GetAttrString(self,"__getitem__")) return NULL; UNLESS(m=subclass_getspecial(self,py__getitem__)) return NULL;
if(m->ob_type==&CMethodType && ((CMethod*)m)->meth==getitem_by_name) if(UnboundCMethod_Check(m) && AsCMethod(m)->meth==getitem_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type))
{ {
t=(PyExtensionClass*)((CMethod*)m)->type; t=(PyExtensionClass*)AsCMethod(m)->type;
if(t->tp_as_sequence && t->tp_as_sequence->sq_item) if(t->tp_as_sequence && t->tp_as_sequence->sq_item)
{ {
Py_DECREF(m); Py_DECREF(m);
...@@ -1520,11 +1971,12 @@ subclass_ass_item(PyObject *self, int index, PyObject *v) ...@@ -1520,11 +1971,12 @@ subclass_ass_item(PyObject *self, int index, PyObject *v)
PyObject *m; PyObject *m;
PyExtensionClass *t; PyExtensionClass *t;
UNLESS(m=PyObject_GetAttrString(self,"__setitem__")) return -1; UNLESS(m=subclass_getspecial(self,py__setitem__)) return -1;
if(m->ob_type==&CMethodType && if(UnboundCMethod_Check(m) &&
((CMethod*)m)->meth==(PyCFunction)setitem_by_name) AsCMethod(m)->meth==(PyCFunction)setitem_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type))
{ {
t=(PyExtensionClass*)((CMethod*)m)->type; t=(PyExtensionClass*)AsCMethod(m)->type;
if(t->tp_as_sequence && t->tp_as_sequence->sq_ass_item) if(t->tp_as_sequence && t->tp_as_sequence->sq_ass_item)
{ {
Py_DECREF(m); Py_DECREF(m);
...@@ -1545,10 +1997,11 @@ subclass_slice(PyObject *self, int i1, int i2) ...@@ -1545,10 +1997,11 @@ subclass_slice(PyObject *self, int i1, int i2)
{ {
PyObject *m; PyObject *m;
UNLESS(m=PyObject_GetAttrString(self,"__getslice__")) return NULL; UNLESS(m=subclass_getspecial(self,py__getslice__)) return NULL;
if(m->ob_type==&CMethodType && ((CMethod*)m)->meth==slice_by_name) if(UnboundCMethod_Check(m) && AsCMethod(m)->meth==slice_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type))
{ {
UNLESS_ASSIGN(m,((CMethod*)m)->type->tp_as_sequence->sq_slice(self,i1,i2)) UNLESS_ASSIGN(m,AsCMethod(m)->type->tp_as_sequence->sq_slice(self,i1,i2))
return NULL; return NULL;
} }
else else
...@@ -1564,10 +2017,11 @@ subclass_ass_slice(PyObject *self, int i1, int i2, PyObject *v) ...@@ -1564,10 +2017,11 @@ subclass_ass_slice(PyObject *self, int i1, int i2, PyObject *v)
PyObject *m; PyObject *m;
long r; long r;
UNLESS(m=PyObject_GetAttrString(self,"__setslice__")) return -1; UNLESS(m=subclass_getspecial(self,py__setslice__)) return -1;
if(m->ob_type==&CMethodType && if(UnboundCMethod_Check(m) &&
((CMethod*)m)->meth==(PyCFunction)ass_slice_by_name) AsCMethod(m)->meth==(PyCFunction)ass_slice_by_name
r=((CMethod*)m)->type->tp_as_sequence->sq_ass_slice(self,i1,i2,v); && SubclassInstance_Check(self,AsCMethod(m)->type))
r=AsCMethod(m)->type->tp_as_sequence->sq_ass_slice(self,i1,i2,v);
else else
{ {
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"iiO",i1,i2,v)) return -1; UNLESS_ASSIGN(m,PyObject_CallFunction(m,"iiO",i1,i2,v)) return -1;
...@@ -1582,21 +2036,22 @@ subclass_concat(PyObject *self, PyObject *v) ...@@ -1582,21 +2036,22 @@ subclass_concat(PyObject *self, PyObject *v)
{ {
PyObject *m; PyObject *m;
UNLESS(m=PyObject_GetAttrString(self,"__concat__")) UNLESS(m=subclass_getspecial(self,py__concat__))
{ /* Maybe we should check for __add__ */ { /* Maybe we should check for __add__ */
PyObject *am; PyObject *am;
PyErr_Clear(); PyErr_Clear();
UNLESS(am=PyObject_GetAttrString(self,"__add__")) return NULL; UNLESS(am=subclass_getspecial(self,py__add__)) return NULL;
if(m=PyObject_GetAttrString(self,"__coerce__")) if(m=subclass_getspecial(self,py__coerce__))
{ {
if(m->ob_type==&CMethodType && ((CMethod*)m)->meth==coerce_by_name) if(UnboundCMethod_Check(m) && AsCMethod(m)->meth==coerce_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type))
{ {
PyObject *x,*y; PyObject *x,*y;
x=self; x=self;
y=v; y=v;
if(0==((CMethod*)m)->type->tp_as_number->nb_coerce(&x,&y)) if(0==AsCMethod(m)->type->tp_as_number->nb_coerce(&x,&y))
{ {
Py_DECREF(am); Py_DECREF(am);
if(x->ob_type->tp_as_number) if(x->ob_type->tp_as_number)
...@@ -1616,9 +2071,10 @@ subclass_concat(PyObject *self, PyObject *v) ...@@ -1616,9 +2071,10 @@ subclass_concat(PyObject *self, PyObject *v)
"No __add__ or __concat__ methods, or maybe I'm just being stupid."); "No __add__ or __concat__ methods, or maybe I'm just being stupid.");
return NULL; return NULL;
} }
if(m->ob_type==&CMethodType && ((CMethod*)m)->meth==concat_by_name) if(UnboundCMethod_Check(m) && AsCMethod(m)->meth==concat_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type))
{ {
UNLESS_ASSIGN(m,((CMethod*)m)->type->tp_as_sequence->sq_concat(self,v)) UNLESS_ASSIGN(m,AsCMethod(m)->type->tp_as_sequence->sq_concat(self,v))
return NULL; return NULL;
} }
else else
...@@ -1633,10 +2089,11 @@ subclass_repeat(PyObject *self, int v) ...@@ -1633,10 +2089,11 @@ subclass_repeat(PyObject *self, int v)
{ {
PyObject *m; PyObject *m;
UNLESS(m=PyObject_GetAttrString(self,"__repeat__")) return NULL; UNLESS(m=subclass_getspecial(self,py__repeat__)) return NULL;
if(m->ob_type==&CMethodType && ((CMethod*)m)->meth==repeat_by_name) if(UnboundCMethod_Check(m) && AsCMethod(m)->meth==repeat_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type))
{ {
UNLESS_ASSIGN(m,((CMethod*)m)->type->tp_as_sequence->sq_repeat(self,v)) UNLESS_ASSIGN(m,AsCMethod(m)->type->tp_as_sequence->sq_repeat(self,v))
return NULL; return NULL;
} }
else else
...@@ -1662,11 +2119,12 @@ subclass_subscript(PyObject *self, PyObject *key) ...@@ -1662,11 +2119,12 @@ subclass_subscript(PyObject *self, PyObject *key)
PyObject *m; PyObject *m;
PyExtensionClass *t; PyExtensionClass *t;
UNLESS(m=PyObject_GetAttrString(self,"__getitem__")) return NULL; UNLESS(m=subclass_getspecial(self,py__getitem__)) return NULL;
if(m->ob_type==&CMethodType && if(UnboundCMethod_Check(m) &&
((CMethod*)m)->meth==(PyCFunction)getitem_by_name) AsCMethod(m)->meth==(PyCFunction)getitem_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type))
{ {
t=(PyExtensionClass*)((CMethod*)m)->type; t=(PyExtensionClass*)AsCMethod(m)->type;
if(t->tp_as_mapping && t->tp_as_mapping->mp_subscript) if(t->tp_as_mapping && t->tp_as_mapping->mp_subscript)
{ {
Py_DECREF(m); Py_DECREF(m);
...@@ -1687,11 +2145,12 @@ subclass_ass_subscript(PyObject *self, PyObject *index, PyObject *v) ...@@ -1687,11 +2145,12 @@ subclass_ass_subscript(PyObject *self, PyObject *index, PyObject *v)
PyObject *m; PyObject *m;
PyExtensionClass *t; PyExtensionClass *t;
UNLESS(m=PyObject_GetAttrString(self,"__setitem__")) return -1; UNLESS(m=subclass_getspecial(self,py__setitem__)) return -1;
if(m->ob_type==&CMethodType && if(UnboundCMethod_Check(m) &&
((CMethod*)m)->meth==(PyCFunction)setitem_by_name) AsCMethod(m)->meth==(PyCFunction)setitem_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type))
{ {
t=(PyExtensionClass*)((CMethod*)m)->type; t=(PyExtensionClass*)AsCMethod(m)->type;
if(t->tp_as_sequence && t->tp_as_mapping->mp_ass_subscript) if(t->tp_as_sequence && t->tp_as_mapping->mp_ass_subscript)
{ {
Py_DECREF(m); Py_DECREF(m);
...@@ -1723,11 +2182,11 @@ dealloc_base(PyObject *inst, PyExtensionClass* self) ...@@ -1723,11 +2182,11 @@ dealloc_base(PyObject *inst, PyExtensionClass* self)
for(i=0; i < l; i++) for(i=0; i < l; i++)
{ {
t=PyTuple_GET_ITEM(self->bases, i); t=PyTuple_GET_ITEM(self->bases, i);
if(t->ob_type==(PyTypeObject*)&CCLtype) if(PyExtensionClass_Check(t))
{ {
if(((PyExtensionClass*)t)->bases) if(AsPyExtensionClass(t)->bases)
{ {
if(dealloc_base(inst,(PyExtensionClass*)t)) return 1; if(dealloc_base(inst,AsPyExtensionClass(t))) return 1;
} }
else else
{ {
...@@ -1749,7 +2208,7 @@ subclass_dealloc(PyObject *self) ...@@ -1749,7 +2208,7 @@ subclass_dealloc(PyObject *self)
PyErr_Fetch(&t,&v,&tb); PyErr_Fetch(&t,&v,&tb);
if(m=PyObject_GetAttrString(self,"__del__")) if(m=subclass_getspecial(self,py__del__))
PyObject_CallFunction(m,""); PyObject_CallFunction(m,"");
PyErr_Clear(); PyErr_Clear();
...@@ -1775,14 +2234,14 @@ datafull_baseclasses(PyExtensionClass *type) ...@@ -1775,14 +2234,14 @@ datafull_baseclasses(PyExtensionClass *type)
for(i=0; i < l; i++) for(i=0; i < l; i++)
{ {
base=PyTuple_GET_ITEM(type->bases, i); base=PyTuple_GET_ITEM(type->bases, i);
if(base->ob_type==(PyTypeObject*)&CCLtype) if(PyExtensionClass_Check(base))
{ {
if(((PyExtensionClass*)base->ob_type)->bases) if(AsPyExtensionClass(base)->bases)
n+=datafull_baseclasses((PyExtensionClass*)base); n+=datafull_baseclasses(AsPyExtensionClass(base));
else else
{ {
if(((PyExtensionClass*)base)->tp_basicsize > sizeof(Dataless) || if(AsPyExtensionClass(base)->tp_basicsize > sizeof(Dataless) ||
((PyExtensionClass*)base)->tp_itemsize > 0) AsPyExtensionClass(base)->tp_itemsize > 0)
n++; n++;
} }
} }
...@@ -1803,17 +2262,17 @@ datafull_baseclass(PyExtensionClass *type) ...@@ -1803,17 +2262,17 @@ datafull_baseclass(PyExtensionClass *type)
for(i=0; i < l; i++) for(i=0; i < l; i++)
{ {
base=PyTuple_GET_ITEM(type->bases, i); base=PyTuple_GET_ITEM(type->bases, i);
if(base->ob_type==(PyTypeObject*)&CCLtype) if(PyExtensionClass_Check(base))
{ {
if(((PyExtensionClass*)base->ob_type)->bases) if(AsPyExtensionClass(base)->bases)
{ {
if(dbase=datafull_baseclass((PyExtensionClass*)base)) if(dbase=datafull_baseclass(AsPyExtensionClass(base)))
return dbase; return dbase;
} }
else else
{ {
if(((PyExtensionClass*)base)->tp_basicsize > sizeof(Dataless) || if(AsPyExtensionClass(base)->tp_basicsize > sizeof(Dataless) ||
((PyExtensionClass*)base)->tp_itemsize > 0) AsPyExtensionClass(base)->tp_itemsize > 0)
return base; return base;
} }
} }
...@@ -1822,11 +2281,11 @@ datafull_baseclass(PyExtensionClass *type) ...@@ -1822,11 +2281,11 @@ datafull_baseclass(PyExtensionClass *type)
} }
static int static int
subclass_hasattr(PyExtensionClass *type, char *name) subclass_hasattr(PyExtensionClass *type, PyObject *name)
{ {
PyObject *o; PyObject *o;
if(o=CCL_getattr(type,name)) if(o=CCL_getattro(type,name))
{ {
Py_DECREF(o); Py_DECREF(o);
return 1; return 1;
...@@ -1838,56 +2297,135 @@ subclass_hasattr(PyExtensionClass *type, char *name) ...@@ -1838,56 +2297,135 @@ subclass_hasattr(PyExtensionClass *type, char *name)
static int static int
has_number_methods(PyExtensionClass *type) has_number_methods(PyExtensionClass *type)
{ {
return (subclass_hasattr(type,"__add__") || return (subclass_hasattr(type,py__add__) ||
subclass_hasattr(type,"__sub__") || subclass_hasattr(type,py__sub__) ||
subclass_hasattr(type,"__mul__") || subclass_hasattr(type,py__mul__) ||
subclass_hasattr(type,"__div__") || subclass_hasattr(type,py__div__) ||
subclass_hasattr(type,"__mod__") || subclass_hasattr(type,py__mod__) ||
subclass_hasattr(type,"__pow__") || subclass_hasattr(type,py__pow__) ||
subclass_hasattr(type,"__divmod__") || subclass_hasattr(type,py__divmod__) ||
subclass_hasattr(type,"__lshift__") || subclass_hasattr(type,py__lshift__) ||
subclass_hasattr(type,"__rshift__") || subclass_hasattr(type,py__rshift__) ||
subclass_hasattr(type,"__and__") || subclass_hasattr(type,py__and__) ||
subclass_hasattr(type,"__or__") || subclass_hasattr(type,py__or__) ||
subclass_hasattr(type,"__xor__") || subclass_hasattr(type,py__xor__) ||
subclass_hasattr(type,"__coerce__") || subclass_hasattr(type,py__coerce__) ||
subclass_hasattr(type,"__neg__") || subclass_hasattr(type,py__neg__) ||
subclass_hasattr(type,"__pos__") || subclass_hasattr(type,py__pos__) ||
subclass_hasattr(type,"__abs__") || subclass_hasattr(type,py__abs__) ||
subclass_hasattr(type,"__nonzero__") || subclass_hasattr(type,py__nonzero__) ||
subclass_hasattr(type,"__inv__") || subclass_hasattr(type,py__inv__) ||
subclass_hasattr(type,"__int__") || subclass_hasattr(type,py__int__) ||
subclass_hasattr(type,"__long__") || subclass_hasattr(type,py__long__) ||
subclass_hasattr(type,"__float__") || subclass_hasattr(type,py__float__) ||
subclass_hasattr(type,"__oct__") || subclass_hasattr(type,py__oct__) ||
subclass_hasattr(type,"__hex__") subclass_hasattr(type,py__hex__)
); );
} }
static int static int
has_collection_methods(PyExtensionClass *type) has_collection_methods(PyExtensionClass *type)
{ {
return (subclass_hasattr(type,"__getitem__") || return (subclass_hasattr(type,py__getitem__) ||
subclass_hasattr(type,"__setitem__") || subclass_hasattr(type,py__setitem__) ||
subclass_hasattr(type,"__getslice__") || subclass_hasattr(type,py__getslice__) ||
subclass_hasattr(type,"__setslice__") || subclass_hasattr(type,py__setslice__) ||
subclass_hasattr(type,"__concat__") || subclass_hasattr(type,py__concat__) ||
subclass_hasattr(type,"__repeat__") || subclass_hasattr(type,py__repeat__) ||
subclass_hasattr(type,"__len__") subclass_hasattr(type,py__len__)
); );
} }
static void
subclass_init_getattr(PyExtensionClass *self, PyObject *methods)
{
PyObject *m;
if((m=CCL_getattr(self,py__getattr__,"__getattr__")))
{
if(UnboundCMethod_Check(m) && AsCMethod(m)->meth==getattr_by_name
&& Subclass_Check(self,AsCMethod(m)->type))
{
self->tp_getattr=AsCMethod(m)->type->tp_getattr;
}
#if PYTHON_API_VERSION >= 1005
else if(UnboundCMethod_Check(m) && AsCMethod(m)->meth==getattro_by_name
&& Subclass_Check(self,AsCMethod(m)->type))
{
self->tp_getattro=AsCMethod(m)->type->tp_getattro;
}
#endif
else
{
PyDict_SetItem(methods,py__getattr__,m);
#if PYTHON_API_VERSION >= 1005
self->tp_getattro=subclass_getattro;
#else
self->tp_getattr=subclass_getattr;
#endif
}
}
else
{
PyErr_Clear();
#if PYTHON_API_VERSION >= 1005
self->tp_getattro=EC_findiattro;
#else
self->tp_getattr=EC_findiattrs;
#endif
}
}
static void
subclass_init_setattr(PyExtensionClass *self, PyObject *methods)
{
PyObject *m;
if((m=CCL_getattr(self,py__setattr__,"__setattr__")))
{
if(UnboundCMethod_Check(m) && AsCMethod(m)->meth==setattr_by_name
&& Subclass_Check(self,AsCMethod(m)->type))
{
self->tp_setattr=AsCMethod(m)->type->tp_setattr;
}
#if PYTHON_API_VERSION >= 1005
else if(UnboundCMethod_Check(m) && AsCMethod(m)->meth==setattro_by_name
&& Subclass_Check(self,AsCMethod(m)->type))
{
self->tp_setattro=AsCMethod(m)->type->tp_setattro;
}
#endif
else
{
PyDict_SetItem(methods,py__setattr__,m);
#if PYTHON_API_VERSION >= 1005
self->tp_setattro=subclass_setattro;
#else
self->tp_setattr=subclass_setattr;
#endif
}
}
else
{
PyErr_Clear();
#if PYTHON_API_VERSION >= 1005
self->tp_setattro=subclass_simple_setattro;
#else
self->tp_setattro=subclass_simple_setattr;
#endif
}
}
/* Constructor for building subclasses of C classes. /* Constructor for building subclasses of C classes.
That is, we want to build a C class object that described a That is, we want to build a C class object that described a
subclass of a built-in type. subclass of a built-in type.
*/ */
static PyObject * static PyObject *
subclass__init__(self,args) subclass__init__(PyExtensionClass *self, PyObject *args)
PyExtensionClass *self;
PyObject *args;
{ {
PyObject *bases, *methods; PyObject *bases, *methods, *class_init;
PyExtensionClass *type; PyExtensionClass *type;
char *name; char *name;
int dynamic=1; int dynamic=1;
...@@ -1932,9 +2470,10 @@ subclass__init__(self,args) ...@@ -1932,9 +2470,10 @@ subclass__init__(self,args)
copy_member(tp_itemsize); copy_member(tp_itemsize);
copy_member(tp_print); copy_member(tp_print);
copy_member(tp_getattr);
self->tp_dealloc=subclass_dealloc; self->tp_dealloc=subclass_dealloc;
self->tp_setattr=subclass_setattr;
subclass_init_getattr(self,methods);
subclass_init_setattr(self,methods);
#define subclass_set(OP,N) \ #define subclass_set(OP,N) \
self->tp_ ##OP = subclass_ ##OP self->tp_ ##OP = subclass_ ##OP
...@@ -1942,8 +2481,8 @@ subclass__init__(self,args) ...@@ -1942,8 +2481,8 @@ subclass__init__(self,args)
subclass_set(compare,cmp); subclass_set(compare,cmp);
subclass_set(repr,repr); subclass_set(repr,repr);
if(subclass_hasattr(self,"__bind_to_object__") && if(subclass_hasattr(self,py__bind_to_object__) &&
subclass_hasattr(self,"__call__")) subclass_hasattr(self,py__call__))
self->class_flags |= EXTENSIONCLASS_BINDABLE_FLAG; self->class_flags |= EXTENSIONCLASS_BINDABLE_FLAG;
if(dynamic || has_number_methods(self)) if(dynamic || has_number_methods(self))
...@@ -1965,6 +2504,19 @@ subclass__init__(self,args) ...@@ -1965,6 +2504,19 @@ subclass__init__(self,args)
subclass_set(call,call); subclass_set(call,call);
subclass_set(str,str); subclass_set(str,str);
self->tp_doc=0; self->tp_doc=0;
/* Check for and use __class_init__ */
if(class_init=PyObject_GetAttrString(AsPyObject(self),"__class_init__"))
{
UNLESS_ASSIGN(class_init,PyObject_GetAttrString(class_init,"im_func"))
return NULL;
UNLESS_ASSIGN(class_init,PyObject_CallFunction(class_init,"O",self))
return NULL;
Py_DECREF(class_init);
}
else
PyErr_Clear();
Py_INCREF(Py_None); Py_INCREF(Py_None);
return Py_None; return Py_None;
} }
...@@ -1985,8 +2537,8 @@ static PyExtensionClass CCLtype = { ...@@ -1985,8 +2537,8 @@ static PyExtensionClass CCLtype = {
/* methods */ /* methods */
(destructor)CCL_dealloc, /*tp_dealloc*/ (destructor)CCL_dealloc, /*tp_dealloc*/
(printfunc)0, /*tp_print*/ (printfunc)0, /*tp_print*/
(getattrfunc)CCL_getattr, /*tp_getattr*/ (getattrfunc)CCL_getattrs, /*tp_getattr*/
(setattrfunc)CCL_setattr, /*tp_setattr*/ (setattrfunc)CCL_setattrs, /*tp_setattr*/
(cmpfunc)0, /*tp_compare*/ (cmpfunc)0, /*tp_compare*/
(reprfunc)CCL_repr, /*tp_repr*/ (reprfunc)CCL_repr, /*tp_repr*/
0, /*tp_as_number*/ 0, /*tp_as_number*/
...@@ -1995,9 +2547,14 @@ static PyExtensionClass CCLtype = { ...@@ -1995,9 +2547,14 @@ static PyExtensionClass CCLtype = {
(hashfunc)0, /*tp_hash*/ (hashfunc)0, /*tp_hash*/
(ternaryfunc)CCL_call, /*tp_call*/ (ternaryfunc)CCL_call, /*tp_call*/
(reprfunc)0, /*tp_str*/ (reprfunc)0, /*tp_str*/
#if PYTHON_API_VERSION >= 1005
(getattrofunc)CCL_getattro, /*tp_getattr with object key*/
(setattrofunc)CCL_setattro, /*tp_setattr with object key*/
#else
/* Space for future expansion */ /* Space for future expansion */
0L,0L,0L,0L, 0L,0L,
#endif
0L,0L,
"C classes", /* Documentation string */ "C classes", /* Documentation string */
METHOD_CHAIN(ExtensionClass_methods) METHOD_CHAIN(ExtensionClass_methods)
}; };
...@@ -2011,7 +2568,7 @@ static PyExtensionClass Basetype = { ...@@ -2011,7 +2568,7 @@ static PyExtensionClass Basetype = {
/* methods */ /* methods */
(destructor)0, /*tp_dealloc*/ (destructor)0, /*tp_dealloc*/
(printfunc)0, /*tp_print*/ (printfunc)0, /*tp_print*/
(getattrfunc)ExtensionClass_FindInstanceAttribute, /*tp_getattr*/ (getattrfunc)EC_findiattrs, /*tp_getattr*/
(setattrfunc)0, /*tp_setattr*/ (setattrfunc)0, /*tp_setattr*/
(cmpfunc)0, /*tp_compare*/ (cmpfunc)0, /*tp_compare*/
(reprfunc)0, /*tp_repr*/ (reprfunc)0, /*tp_repr*/
...@@ -2021,9 +2578,14 @@ static PyExtensionClass Basetype = { ...@@ -2021,9 +2578,14 @@ static PyExtensionClass Basetype = {
(hashfunc)0, /*tp_hash*/ (hashfunc)0, /*tp_hash*/
(ternaryfunc)0, /*tp_call*/ (ternaryfunc)0, /*tp_call*/
(reprfunc)0, /*tp_str*/ (reprfunc)0, /*tp_str*/
#if PYTHON_API_VERSION >= 1005
(getattrofunc)EC_findiattro, /*tp_getattr with object key*/
(setattrofunc)0, /*tp_setattr with object key*/
#else
/* Space for future expansion */ /* Space for future expansion */
0L,0L,0L,0L, 0L,0L,
#endif
0L,0L,
"Base -- a do nothing base class\n" "Base -- a do nothing base class\n"
"\n" "\n"
"A trivial base class that doesn't have any inheritable\n" "A trivial base class that doesn't have any inheritable\n"
...@@ -2032,6 +2594,79 @@ static PyExtensionClass Basetype = { ...@@ -2032,6 +2594,79 @@ static PyExtensionClass Basetype = {
{NULL,NULL} {NULL,NULL}
}; };
static PyObject *
bind_to_object(PyObject *self, PyObject *args)
{
PyObject *inst;
PMethod *r;
UNLESS(PyArg_Parse(args,"O",&inst)) return NULL;
UNLESS(PyExtensionInstance_Check(inst))
{
PyErr_SetString(PyExc_TypeError,
"attempt to wrap extension method using an object that\n"
"is not an extension class instance.");
return NULL;
}
UNLESS(r = PyObject_NEW(PMethod, &PMethodType)) return NULL;
Py_INCREF(inst);
Py_INCREF(inst->ob_type);
r->type=inst->ob_type;
r->self=inst;
r->meth=self;
return AsPyObject(r);
}
struct PyMethodDef Method_methods[] = {
{"__bind_to_object__",(PyCFunction)bind_to_object,0,""},
{NULL, NULL} /* sentinel */
};
static PyExtensionClass Methodtype = {
PyObject_HEAD_INIT(&PyType_Type)
0, /*ob_size*/
"Method", /*tp_name*/
sizeof(Dataless), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
(destructor)0, /*tp_dealloc*/
(printfunc)0, /*tp_print*/
(getattrfunc)EC_findiattrs, /*tp_getattr*/
(setattrfunc)0, /*tp_setattr*/
(cmpfunc)0, /*tp_compare*/
(reprfunc)0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
(hashfunc)0, /*tp_hash*/
(ternaryfunc)0, /*tp_call*/
(reprfunc)0, /*tp_str*/
#if PYTHON_API_VERSION >= 1005
(getattrofunc)EC_findiattro, /*tp_getattr with object key*/
(setattrofunc)0, /*tp_setattr with object key*/
#else
/* Space for future expansion */
0L,0L,
#endif
0L,0L,
"Base class for objects that want to be treated as methods\n"
"\n"
"The method class provides a method, __bind_to_object__, that\n"
"binds an object to an instance. If a method is a subobject\n"
"of an extension-class instance, the the method will be bound\n"
"to the instance and when the resulting object is called, it\n"
"will call the method and pass the instance in addition to\n"
"other arguments. It is the responsibility of Method objects\n"
"to implement (or inherit) a __call__ method.\n",
METHOD_CHAIN(Method_methods)
};
PyObject * PyObject *
MetaTypeUndefinedMethod() MetaTypeUndefinedMethod()
...@@ -2063,14 +2698,30 @@ initExtensionClass() ...@@ -2063,14 +2698,30 @@ initExtensionClass()
/* Add some symbolic constants to the module */ /* Add some symbolic constants to the module */
d = PyModule_GetDict(m); d = PyModule_GetDict(m);
init_py_names();
initializeBaseExtensionClass(&CCLtype); initializeBaseExtensionClass(&CCLtype);
PyDict_SetItemString(d, "ExtensionClassType", (PyObject*)&CCLtype); PyDict_SetItemString(d, "ExtensionClassType", (PyObject*)&CCLtype);
initializeBaseExtensionClass(&Basetype); initializeBaseExtensionClass(&Basetype);
PyDict_SetItemString(d, "Base", (PyObject*)&Basetype); PyDict_SetItemString(d, "Base", (PyObject*)&Basetype);
initializeBaseExtensionClass(&Methodtype);
PyDict_SetItemString(d, "Method", (PyObject*)&Methodtype);
#ifdef Py_COBJECT_H
/* Export C attribute lookup API */
PyDict_SetItemString(d, "_PyEC_getattrs",
PyCObject_FromVoidPtr(EC_findiattrs,NULL));
PyDict_SetItemString(d, "_PyEC_getattro",
PyCObject_FromVoidPtr(EC_findiattro,NULL));
PyDict_SetItemString(d, "_PyEC_setattrs",
PyCObject_FromVoidPtr(subclass_simple_setattr,NULL));
PyDict_SetItemString(d, "_PyEC_setattro",
PyCObject_FromVoidPtr(subclass_simple_setattro,NULL));
#endif
/* Check for errors */ /* Check for errors */
if (PyErr_Occurred()) if (PyErr_Occurred())
Py_FatalError("can't initialize module ExtensionClass"); Py_FatalError("can't initialize module ExtensionClass");
} }
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