Commit c1b89700 authored by Godefroid Chapelle's avatar Godefroid Chapelle

J1m: /lib/Component/ExtensionClass should be removed afaik

parent 09545b1d
#!/usr/bin/env python
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
"""Support for Python classes implemented in C
A lightweight mechanism has been developed for making Python
extension types more class-like. Classes can be developed in an
extension language, such as C or C++, and these classes can be
treated like other python classes:
- They can be sub-classed in python,
- They provide access to method documentation strings, and
- They can be used to directly create new instances.
An example class shows how extension classes are implemented and how
they differ from extension types.
Extension classes provide additional extensions to class and
instance semantics, including:
- A protocol for accessing subobjects "in the context of" their
containers. This is used to implement custom method types
and "environmental acquisition":Acquisition.html.
- A protocol for overriding method call semantics. This is used
to implement "synchonized" classes and could be used to
implement argument type checking.
- A protocol for class initialization that supports execution of a
special '__class_init__' method after a class has been
initialized.
Extension classes illustrate how the Python class mechanism can be
extended and may provide a basis for improved or specialized class
models.
"""
# Setup file for ExtensionClass
# setup.py contributed by A.M. Kuchling <amk1@bigfoot.com>
from distutils.core import setup
from distutils.extension import Extension
ExtensionClass = Extension(name = 'ExtensionClass',
sources = ['src/ExtensionClass.c'])
Acquisition = Extension(name = 'Acquisition',
sources = ['src/Acquisition.c'])
ComputedAttribute = Extension(name = 'ComputedAttribute',
sources = ['src/ComputedAttribute.c'])
MethodObject = Extension(name = 'MethodObject',
sources = ['src/MethodObject.c'])
Missing = Extension(name = 'Missing',
sources = ['src/Missing.c'])
MultiMapping = Extension(name = 'MultiMapping',
sources = ['src/MultiMapping.c'])
Record = Extension(name = 'Record', sources = ['src/Record.c'])
ThreadLock = Extension(name = 'ThreadLock',
sources = ['src/ThreadLock.c'])
setup(name = "ExtensionClass",
version = "1.3",
description = "Support for Python classes implemented in C",
maintainer = "Zope Corporation",
maintainer_email = "zodb-dev@zope.org",
url = "http://www.zope.com",
ext_modules = [ExtensionClass, Acquisition, ComputedAttribute,
MethodObject, Missing, MultiMapping,
ThreadLock, Record],
headers = ["src/ExtensionClass.h"],
long_description=__doc__
)
/*****************************************************************************
Copyright (c) 1996-2002 Zope Corporation and Contributors.
All Rights Reserved.
This software is subject to the provisions of the Zope Public License,
Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
FOR A PARTICULAR PURPOSE
****************************************************************************/
#include "ExtensionClass.h"
#define _IN_ACQUISITION_C
#include "Acquisition.h"
static ACQUISITIONCAPI AcquisitionCAPI;
static void
PyVar_Assign(PyObject **v, PyObject *e)
{
Py_XDECREF(*v);
*v=e;
}
#define ASSIGN(V,E) PyVar_Assign(&(V),(E))
#define UNLESS(E) if (!(E))
#define UNLESS_ASSIGN(V,E) ASSIGN(V,E); UNLESS(V)
#define OBJECT(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__invert__, *py__int__,
*py__long__, *py__float__, *py__oct__, *py__hex__,
*py__getitem__, *py__setitem__, *py__delitem__,
*py__getslice__, *py__setslice__, *py__delslice__,
*py__len__, *py__of__, *py__call__, *py__repr__, *py__str__, *py__cmp__;
static PyObject *Acquired=0;
static void
init_py_names(void)
{
#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(__invert__);
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(__delitem__);
INIT_PY_NAME(__getslice__);
INIT_PY_NAME(__setslice__);
INIT_PY_NAME(__delslice__);
INIT_PY_NAME(__len__);
INIT_PY_NAME(__of__);
INIT_PY_NAME(__call__);
INIT_PY_NAME(__repr__);
INIT_PY_NAME(__str__);
INIT_PY_NAME(__cmp__);
#undef INIT_PY_NAME
}
static PyObject *
CallMethodO(PyObject *self, PyObject *name,
PyObject *args, PyObject *kw)
{
if (! args && PyErr_Occurred()) return NULL;
UNLESS(name=PyObject_GetAttr(self,name)) {
if (args) { Py_DECREF(args); }
return NULL;
}
ASSIGN(name,PyEval_CallObjectWithKeywords(name,args,kw));
if (args) { Py_DECREF(args); }
return name;
}
#define Build Py_BuildValue
/* Declarations for objects of type Wrapper */
typedef struct {
PyObject_HEAD
PyObject *obj;
PyObject *container;
} Wrapper;
staticforward PyExtensionClass Wrappertype, XaqWrappertype;
#define isWrapper(O) ((O)->ob_type==(PyTypeObject*)&Wrappertype || \
(O)->ob_type==(PyTypeObject*)&XaqWrappertype)
#define WRAPPER(O) ((Wrapper*)(O))
static PyObject *
Wrapper__init__(Wrapper *self, PyObject *args)
{
PyObject *obj, *container;
UNLESS(PyArg_Parse(args,"(OO)",&obj,&container)) return NULL;
if (self == WRAPPER(obj)) {
PyErr_SetString(PyExc_ValueError,
"Cannot wrap acquisition wrapper in itself (Wrapper__init__)");
return NULL;
}
Py_INCREF(obj);
Py_INCREF(container);
self->obj=obj;
self->container=container;
Py_INCREF(Py_None);
return Py_None;
}
/* ---------------------------------------------------------------- */
static PyObject *
__of__(PyObject *inst, PyObject *parent)
{
PyObject *r, *t;
UNLESS(r=PyObject_GetAttr(inst, py__of__)) return NULL;
UNLESS(t=PyTuple_New(1)) goto err;
PyTuple_SET_ITEM(t,0,parent);
ASSIGN(r,PyObject_CallObject(r,t));
PyTuple_SET_ITEM(t,0,NULL);
Py_DECREF(t);
if (r
&& r->ob_refcnt==1
&& isWrapper(r)
&& WRAPPER(r)->container && isWrapper(WRAPPER(r)->container)
)
while (WRAPPER(r)->obj && isWrapper(WRAPPER(r)->obj)
&& (WRAPPER(WRAPPER(r)->obj)->container ==
WRAPPER(WRAPPER(r)->container)->obj)
)
{
/* Simplify wrapper */
Py_XINCREF(WRAPPER(WRAPPER(r)->obj)->obj);
ASSIGN(WRAPPER(r)->obj, WRAPPER(WRAPPER(r)->obj)->obj);
}
return r;
err:
Py_DECREF(r);
return NULL;
}
static Wrapper *freeWrappers=0;
static int nWrappers=0;
#define MAX_CACHED_WRAPPERS 200
static PyObject *
newWrapper(PyObject *obj, PyObject *container, PyTypeObject *Wrappertype)
{
Wrapper *self;
if (freeWrappers)
{
self=freeWrappers;
freeWrappers=(Wrapper*)self->obj;
_Py_NewReference((PyObject *)self);
assert(self->ob_refcnt == 1);
self->ob_type=Wrappertype;
nWrappers--;
}
else
{
UNLESS(self = PyObject_NEW(Wrapper, Wrappertype)) return NULL;
}
if (self == WRAPPER(obj)) {
PyErr_SetString(PyExc_ValueError,
"Cannot wrap acquisition wrapper in itself (newWrapper)");
Py_DECREF(self);
return NULL;
}
Py_INCREF(Wrappertype);
Py_XINCREF(obj);
Py_XINCREF(container);
self->obj=obj;
self->container=container;
return OBJECT(self);
}
static void
Wrapper_dealloc(Wrapper *self)
{
Py_XDECREF(self->obj);
Py_XDECREF(self->container);
Py_DECREF(self->ob_type);
if (nWrappers < MAX_CACHED_WRAPPERS)
{
self->obj=OBJECT(freeWrappers);
freeWrappers=self;
nWrappers++;
}
else
{
PyObject_DEL(self);
}
}
static PyObject *
Wrapper_special(Wrapper *self, char *name, PyObject *oname)
{
PyObject *r=0;
switch(*name)
{
case 'b':
if (strcmp(name,"base")==0)
{
if (self->obj)
{
r=self->obj;
while (isWrapper(r) && WRAPPER(r)->obj) r=WRAPPER(r)->obj;
}
else r=Py_None;
Py_INCREF(r);
return r;
}
break;
case 'p':
if (strcmp(name,"parent")==0)
{
if (self->container) r=self->container;
else r=Py_None;
Py_INCREF(r);
return r;
}
break;
case 's':
if (strcmp(name,"self")==0)
{
if (self->obj) r=self->obj;
else r=Py_None;
Py_INCREF(r);
return r;
}
break;
case 'e':
if (strcmp(name,"explicit")==0)
{
if (self->ob_type != (PyTypeObject *)&XaqWrappertype)
return newWrapper(self->obj, self->container,
(PyTypeObject *)&XaqWrappertype);
Py_INCREF(self);
return OBJECT(self);
}
break;
case 'a':
if (strcmp(name,"acquire")==0)
{
return Py_FindAttr(OBJECT(self),oname);
}
break;
case 'c':
if (strcmp(name,"chain")==0)
{
if ((r = PyList_New(0)))
while (1)
{
if (PyList_Append(r,OBJECT(self)) >= 0)
{
if (isWrapper(self) && self->container)
{
self=WRAPPER(self->container);
continue;
}
}
else
{
Py_DECREF(r);
}
break;
}
return r;
}
break;
case 'i':
if (strcmp(name,"inContextOf")==0)
{
return Py_FindAttr(OBJECT(self),oname);
}
if (strcmp(name,"inner")==0)
{
if (self->obj)
{
r=self->obj;
while (isWrapper(r) && WRAPPER(r)->obj)
{
self=WRAPPER(r);
r=WRAPPER(r)->obj;
}
r=OBJECT(self);
}
else r=Py_None;
Py_INCREF(r);
return r;
}
break;
case 'u':
if (strcmp(name,"uncle")==0)
{
return PyString_FromString("Bob");
}
break;
}
return NULL;
}
static int
apply_filter(PyObject *filter, PyObject *inst, PyObject *oname, PyObject *r,
PyObject *extra, PyObject *orig)
{
/* Calls the filter, passing arguments.
Returns 1 if the filter accepts the value, 0 if not, -1 if an
exception occurred.
Note the special reference counting rule: This function decrements
the refcount of 'r' when it returns 0 or -1. When it returns 1, it
leaves the refcount unchanged.
*/
PyObject *fr;
int ir;
UNLESS(fr=PyTuple_New(5)) goto err;
PyTuple_SET_ITEM(fr,0,orig);
Py_INCREF(orig);
PyTuple_SET_ITEM(fr,1,inst);
Py_INCREF(inst);
PyTuple_SET_ITEM(fr,2,oname);
Py_INCREF(oname);
PyTuple_SET_ITEM(fr,3,r);
Py_INCREF(r);
PyTuple_SET_ITEM(fr,4,extra);
Py_INCREF(extra);
UNLESS_ASSIGN(fr,PyObject_CallObject(filter, fr)) goto err;
ir=PyObject_IsTrue(fr);
Py_DECREF(fr);
if (ir) return 1;
Py_DECREF(r);
return 0;
err:
Py_DECREF(r);
return -1;
}
static PyObject *
Wrapper_acquire(Wrapper *self, PyObject *oname,
PyObject *filter, PyObject *extra, PyObject *orig,
int explicit, int containment);
static PyObject *
Wrapper_findattr(Wrapper *self, PyObject *oname,
PyObject *filter, PyObject *extra, PyObject *orig,
int sob, int sco, int explicit, int containment)
{
PyObject *r, *v, *tb;
char *name="";
if (PyString_Check(oname)) name=PyString_AS_STRING(oname);
if (*name=='a' && name[1]=='q' && name[2]=='_')
if ((r=Wrapper_special(self, name+3, oname)))
{
if (filter)
switch(apply_filter(filter,OBJECT(self),oname,r,extra,orig))
{
case -1: return NULL;
case 1: return r;
}
else return r;
}
else PyErr_Clear();
else if (*name=='_' && name[1]=='_' && strcmp(name+2,"reduce__")==0)
{
PyErr_SetString(PyExc_TypeError,
"Can't pickle objects in acquisition wrappers.");
return NULL;
}
/* If we are doing a containment search, then replace self with aq_inner */
if (containment)
while (self->obj && isWrapper(self->obj))
self=WRAPPER(self->obj);
if (sob && self->obj)
{
if (isWrapper(self->obj))
{
if (self == WRAPPER(self->obj)) {
PyErr_SetString(PyExc_RuntimeError,
"Recursion detected in acquisition wrapper");
return NULL;
}
if ((r=Wrapper_findattr(WRAPPER(self->obj),
oname, filter, extra, orig, 1,
/* Search object container if explicit,
or object is implicit acquirer */
explicit ||
self->obj->ob_type ==
(PyTypeObject*)&Wrappertype,
explicit, containment)))
{
if (PyECMethod_Check(r) && PyECMethod_Self(r)==self->obj)
ASSIGN(r,PyECMethod_New(r,OBJECT(self)));
else if (has__of__(r)) ASSIGN(r,__of__(r,OBJECT(self)));
return r;
}
PyErr_Fetch(&r,&v,&tb);
if (r && (r != PyExc_AttributeError))
{
PyErr_Restore(r,v,tb);
return NULL;
}
Py_XDECREF(r); Py_XDECREF(v); Py_XDECREF(tb);
r=NULL;
}
else if ((r=PyObject_GetAttr(self->obj,oname)))
{
if (r==Acquired)
{
Py_DECREF(r);
return Wrapper_acquire(self, oname, filter, extra, orig, 1,
containment);
}
if (PyECMethod_Check(r) && PyECMethod_Self(r)==self->obj)
ASSIGN(r,PyECMethod_New(r,OBJECT(self)));
else if (has__of__(r)) ASSIGN(r,__of__(r,OBJECT(self)));
if (filter)
switch(apply_filter(filter,OBJECT(self),oname,r,extra,orig))
{
case -1: return NULL;
case 1: return r;
}
else return r;
}
else {
PyErr_Fetch(&r,&v,&tb);
if (r != PyExc_AttributeError)
{
PyErr_Restore(r,v,tb);
return NULL;
}
Py_XDECREF(r); Py_XDECREF(v); Py_XDECREF(tb);
r=NULL;
}
PyErr_Clear();
}
if (sco && (*name != '_' || explicit))
return Wrapper_acquire(self, oname, filter, extra, orig, explicit,
containment);
PyErr_SetObject(PyExc_AttributeError,oname);
return NULL;
}
static PyObject *
Wrapper_acquire(Wrapper *self, PyObject *oname,
PyObject *filter, PyObject *extra, PyObject *orig,
int explicit, int containment)
{
PyObject *r;
int sob=1, sco=1;
if (self->container)
{
if (isWrapper(self->container))
{
if (self->obj && isWrapper(self->obj))
{
/* Try to optimize search by recognizing repeated obs in path */
if (WRAPPER(self->obj)->container==
WRAPPER(self->container)->container)
sco=0;
else if (WRAPPER(self->obj)->container==
WRAPPER(self->container)->obj)
sob=0;
}
r=Wrapper_findattr((Wrapper*)self->container,
oname, filter, extra, orig, sob, sco, explicit,
containment);
if (r && has__of__(r)) ASSIGN(r,__of__(r,OBJECT(self)));
return r;
}
else
{
if ((r=PyObject_GetAttr(self->container,oname))) {
if (r == Acquired) {
Py_DECREF(r);
}
else {
if (filter) {
switch(apply_filter(filter,self->container,oname,r,
extra,orig))
{
case -1:
return NULL;
case 1:
if (has__of__(r)) ASSIGN(r,__of__(r,OBJECT(self)));
return r;
}
}
else {
if (has__of__(r)) ASSIGN(r,__of__(r,OBJECT(self)));
return r;
}
}
}
else {
/* May be AttributeError or some other kind of error */
return NULL;
}
}
}
PyErr_SetObject(PyExc_AttributeError, oname);
return NULL;
}
static PyObject *
Wrapper_getattro(Wrapper *self, PyObject *oname)
{
if (self->obj || self->container)
return Wrapper_findattr(self, oname, NULL, NULL, NULL, 1, 1, 0, 0);
/* Maybe we are getting initialized? */
return Py_FindAttr(OBJECT(self),oname);
}
static PyObject *
Xaq_getattro(Wrapper *self, PyObject *oname)
{
char *name="";
/* Special case backward-compatible acquire method. */
if (PyString_Check(oname)) name=PyString_AS_STRING(oname);
if (*name=='a' && name[1]=='c' && strcmp(name+2,"quire")==0)
return Py_FindAttr(OBJECT(self),oname);
if (self->obj || self->container)
return Wrapper_findattr(self, oname, NULL, NULL, NULL, 1, 0, 0, 0);
/* Maybe we are getting initialized? */
return Py_FindAttr(OBJECT(self),oname);
}
static int
Wrapper_setattro(Wrapper *self, PyObject *oname, PyObject *v)
{
char *name="";
/* Allow assignment to parent, to change context. */
if (PyString_Check(oname)) name=PyString_AS_STRING(oname);
if (*name=='a' && name[1]=='q' && name[2]=='_'
&& strcmp(name+3,"parent")==0)
{
Py_XINCREF(v);
ASSIGN(self->container, v);
return 0;
}
if (self->obj)
{
/* Unwrap passed in wrappers! */
while (v && isWrapper(v))
v=WRAPPER(v)->obj;
if (v) return PyObject_SetAttr(self->obj, oname, v);
else return PyObject_DelAttr(self->obj, oname);
}
PyErr_SetString(PyExc_AttributeError,
"Attempt to set attribute on empty acquisition wrapper");
return -1;
}
static int
Wrapper_compare(Wrapper *self, PyObject *w)
{
PyObject *obj, *wobj;
PyObject *m;
int r;
if (OBJECT(self) == w) return 0;
UNLESS (m=PyObject_GetAttr(OBJECT(self), py__cmp__))
{
/* Unwrap self completely -> obj. */
while (self->obj && isWrapper(self->obj))
self=WRAPPER(self->obj);
obj = self->obj;
/* Unwrap w completely -> wobj. */
if (isWrapper(w))
{
while (WRAPPER(w)->obj && isWrapper(WRAPPER(w)->obj))
w=WRAPPER(w)->obj;
wobj = WRAPPER(w)->obj;
}
else wobj = w;
PyErr_Clear();
if (obj == wobj) return 0;
return (obj < w) ? -1 : 1;
}
ASSIGN(m, PyObject_CallFunction(m, "O", w));
UNLESS (m) return -1;
r=PyInt_AsLong(m);
Py_DECREF(m);
return r;
}
static PyObject *
Wrapper_repr(Wrapper *self)
{
PyObject *r;
if ((r=PyObject_GetAttr(OBJECT(self),py__repr__)))
{
ASSIGN(r,PyObject_CallFunction(r,NULL,NULL));
return r;
}
else
{
PyErr_Clear();
return PyObject_Repr(self->obj);
}
}
static PyObject *
Wrapper_str(Wrapper *self)
{
PyObject *r;
if ((r=PyObject_GetAttr(OBJECT(self),py__str__)))
{
ASSIGN(r,PyObject_CallFunction(r,NULL,NULL));
return r;
}
else
{
PyErr_Clear();
return PyObject_Str(self->obj);
}
}
static long
Wrapper_hash(Wrapper *self)
{
return PyObject_Hash(self->obj);
}
static PyObject *
Wrapper_call(Wrapper *self, PyObject *args, PyObject *kw)
{
Py_INCREF(args);
return CallMethodO(OBJECT(self),py__call__,args,kw);
}
/* Code to handle accessing Wrapper objects as sequence objects */
static int
Wrapper_length(Wrapper *self)
{
long l;
PyObject *r;
UNLESS(r=PyObject_GetAttr(OBJECT(self), py__len__)) return -1;
UNLESS_ASSIGN(r,PyObject_CallObject(r,NULL)) return -1;
l=PyInt_AsLong(r);
Py_DECREF(r);
return l;
}
static PyObject *
Wrapper_add(Wrapper *self, PyObject *bb)
{
return CallMethodO(OBJECT(self),py__add__,Build("(O)", bb) ,NULL);
}
static PyObject *
Wrapper_mul(Wrapper *self, int n)
{
return CallMethodO(OBJECT(self),py__mul__,Build("(i)", n),NULL);
}
static PyObject *
Wrapper_item(Wrapper *self, int i)
{
return CallMethodO(OBJECT(self),py__getitem__, Build("(i)", i),NULL);
}
static PyObject *
Wrapper_slice(Wrapper *self, int ilow, int ihigh)
{
return CallMethodO(OBJECT(self),py__getslice__,
Build("(ii)", ilow, ihigh),NULL);
}
static int
Wrapper_ass_item(Wrapper *self, int i, PyObject *v)
{
if (v)
{
UNLESS(v=CallMethodO(OBJECT(self),py__setitem__,
Build("(iO)", i, v),NULL))
return -1;
}
else
{
UNLESS(v=CallMethodO(OBJECT(self),py__delitem__,
Build("(i)", i),NULL))
return -1;
}
Py_DECREF(v);
return 0;
}
static int
Wrapper_ass_slice(Wrapper *self, int ilow, int ihigh, PyObject *v)
{
if (v)
{
UNLESS(v=CallMethodO(OBJECT(self),py__setslice__,
Build("(iiO)", ilow, ihigh, v),NULL))
return -1;
}
else
{
UNLESS(v=CallMethodO(OBJECT(self),py__delslice__,
Build("(ii)", ilow, ihigh),NULL))
return -1;
}
Py_DECREF(v);
return 0;
}
static PySequenceMethods Wrapper_as_sequence = {
(inquiry)Wrapper_length, /*sq_length*/
(binaryfunc)Wrapper_add, /*sq_concat*/
(intargfunc)Wrapper_mul, /*sq_repeat*/
(intargfunc)Wrapper_item, /*sq_item*/
(intintargfunc)Wrapper_slice, /*sq_slice*/
(intobjargproc)Wrapper_ass_item, /*sq_ass_item*/
(intintobjargproc)Wrapper_ass_slice, /*sq_ass_slice*/
};
/* -------------------------------------------------------------- */
/* Code to access Wrapper objects as mappings */
static PyObject *
Wrapper_subscript(Wrapper *self, PyObject *key)
{
return CallMethodO(OBJECT(self),py__getitem__,Build("(O)", key),NULL);
}
static int
Wrapper_ass_sub(Wrapper *self, PyObject *key, PyObject *v)
{
if (v)
{
UNLESS(v=CallMethodO(OBJECT(self),py__setitem__,
Build("(OO)", key, v),NULL))
return -1;
}
else
{
UNLESS(v=CallMethodO(OBJECT(self),py__delitem__,
Build("(O)", key),NULL))
return -1;
}
Py_XDECREF(v);
return 0;
}
static PyMappingMethods Wrapper_as_mapping = {
(inquiry)Wrapper_length, /*mp_length*/
(binaryfunc)Wrapper_subscript, /*mp_subscript*/
(objobjargproc)Wrapper_ass_sub, /*mp_ass_subscript*/
};
/* -------------------------------------------------------------- */
/* Code to access Wrapper objects as numbers */
static PyObject *
Wrapper_sub(Wrapper *self, PyObject *o)
{
return CallMethodO(OBJECT(self),py__sub__,Build("(O)", o),NULL);
}
static PyObject *
Wrapper_div(Wrapper *self, PyObject *o)
{
return CallMethodO(OBJECT(self),py__div__,Build("(O)", o),NULL);
}
static PyObject *
Wrapper_mod(Wrapper *self, PyObject *o)
{
return CallMethodO(OBJECT(self),py__mod__,Build("(O)", o),NULL);
}
static PyObject *
Wrapper_divmod(Wrapper *self, PyObject *o)
{
return CallMethodO(OBJECT(self),py__divmod__,Build("(O)", o),NULL);
}
static PyObject *
Wrapper_pow(Wrapper *self, PyObject *o, PyObject *m)
{
return CallMethodO(OBJECT(self),py__pow__,Build("(OO)", o, m),NULL);
}
static PyObject *
Wrapper_neg(Wrapper *self)
{
return CallMethodO(OBJECT(self), py__neg__, NULL, NULL);
}
static PyObject *
Wrapper_pos(Wrapper *self)
{
return CallMethodO(OBJECT(self), py__pos__, NULL, NULL);
}
static PyObject *
Wrapper_abs(Wrapper *self)
{
return CallMethodO(OBJECT(self), py__abs__, NULL, NULL);
}
static PyObject *
Wrapper_invert(Wrapper *self)
{
return CallMethodO(OBJECT(self), py__invert__, NULL, NULL);
}
static PyObject *
Wrapper_lshift(Wrapper *self, PyObject *o)
{
return CallMethodO(OBJECT(self),py__lshift__,Build("(O)", o),NULL);
}
static PyObject *
Wrapper_rshift(Wrapper *self, PyObject *o)
{
return CallMethodO(OBJECT(self),py__rshift__,Build("(O)", o),NULL);
}
static PyObject *
Wrapper_and(Wrapper *self, PyObject *o)
{
return CallMethodO(OBJECT(self),py__and__,Build("(O)", o),NULL);
}
static PyObject *
Wrapper_xor(Wrapper *self, PyObject *o)
{
return CallMethodO(OBJECT(self),py__xor__,Build("(O)", o),NULL);
}
static PyObject *
Wrapper_or(Wrapper *self, PyObject *o)
{
return CallMethodO(OBJECT(self),py__or__,Build("(O)", o),NULL);
}
static int
Wrapper_coerce(Wrapper **self, PyObject **o)
{
PyObject *m;
UNLESS (m=PyObject_GetAttr(OBJECT(*self), py__coerce__))
{
PyErr_Clear();
Py_INCREF(*self);
Py_INCREF(*o);
return 0;
}
ASSIGN(m, PyObject_CallFunction(m, "O", *o));
UNLESS (m) return -1;
UNLESS (PyArg_ParseTuple(m,"OO", self, o)) goto err;
Py_INCREF(*self);
Py_INCREF(*o);
Py_DECREF(m);
return 0;
err:
Py_DECREF(m);
return -1;
}
static PyObject *
Wrapper_int(Wrapper *self)
{
return CallMethodO(OBJECT(self), py__int__, NULL, NULL);
}
static PyObject *
Wrapper_long(Wrapper *self)
{
return CallMethodO(OBJECT(self), py__long__, NULL, NULL);
}
static PyObject *
Wrapper_float(Wrapper *self)
{
return CallMethodO(OBJECT(self), py__float__, NULL, NULL);
}
static PyObject *
Wrapper_oct(Wrapper *self)
{
return CallMethodO(OBJECT(self), py__oct__, NULL, NULL);
}
static PyObject *
Wrapper_hex(Wrapper *self)
{
return CallMethodO(OBJECT(self), py__hex__, NULL, NULL);
}
static int
Wrapper_nonzero(Wrapper *self)
{
long l;
PyObject *r;
UNLESS(r=PyObject_GetAttr(OBJECT(self), py__nonzero__))
{
PyErr_Clear();
/* Try len */
UNLESS(r=PyObject_GetAttr(OBJECT(self), py__len__))
{
/* No len, it's true :-) */
PyErr_Clear();
return 1;
}
}
UNLESS_ASSIGN(r,PyObject_CallObject(r,NULL)) return -1;
l=PyInt_AsLong(r);
Py_DECREF(r);
return l;
}
static PyNumberMethods Wrapper_as_number = {
(binaryfunc)Wrapper_add, /*nb_add*/
(binaryfunc)Wrapper_sub, /*nb_subtract*/
(binaryfunc)Wrapper_mul, /*nb_multiply*/
(binaryfunc)Wrapper_div, /*nb_divide*/
(binaryfunc)Wrapper_mod, /*nb_remainder*/
(binaryfunc)Wrapper_divmod, /*nb_divmod*/
(ternaryfunc)Wrapper_pow, /*nb_power*/
(unaryfunc)Wrapper_neg, /*nb_negative*/
(unaryfunc)Wrapper_pos, /*nb_positive*/
(unaryfunc)Wrapper_abs, /*nb_absolute*/
(inquiry)Wrapper_nonzero, /*nb_nonzero*/
(unaryfunc)Wrapper_invert, /*nb_invert*/
(binaryfunc)Wrapper_lshift, /*nb_lshift*/
(binaryfunc)Wrapper_rshift, /*nb_rshift*/
(binaryfunc)Wrapper_and, /*nb_and*/
(binaryfunc)Wrapper_xor, /*nb_xor*/
(binaryfunc)Wrapper_or, /*nb_or*/
(coercion)Wrapper_coerce, /*nb_coerce*/
(unaryfunc)Wrapper_int, /*nb_int*/
(unaryfunc)Wrapper_long, /*nb_long*/
(unaryfunc)Wrapper_float, /*nb_float*/
(unaryfunc)Wrapper_oct, /*nb_oct*/
(unaryfunc)Wrapper_hex, /*nb_hex*/
};
/* -------------------------------------------------------- */
static char *acquire_args[] = {"object", "name", "filter", "extra", "explicit",
"default", "containment", NULL};
static PyObject *
Wrapper_acquire_method(Wrapper *self, PyObject *args, PyObject *kw)
{
PyObject *name, *filter=0, *extra=Py_None;
PyObject *expl=0, *defalt=0;
PyObject *result;
int explicit=1;
int containment=0;
UNLESS (PyArg_ParseTupleAndKeywords(
args, kw, "O|OOOOi", acquire_args+1,
&name, &filter, &extra, &explicit, &defalt, &containment
))
return NULL;
if (expl) explicit=PyObject_IsTrue(expl);
if (filter==Py_None) filter=0;
result=Wrapper_findattr(self,name,filter,extra,OBJECT(self),1,
explicit ||
self->ob_type==(PyTypeObject*)&Wrappertype,
explicit, containment);
if (result == NULL && defalt != NULL) {
/* contrary to "Python/bltinmodule.c:builtin_getattr" turn
only 'AttributeError' into a default value, such
that e.g. "ConflictError" and errors raised by the filter
are not mapped to the default value.
*/
if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
PyErr_Clear();
Py_INCREF(defalt);
result = defalt;
}
}
return result;
}
static PyObject *
Wrapper_inContextOf(Wrapper *self, PyObject *args)
{
PyObject *subob, *o, *c;
int inner=1;
UNLESS(PyArg_ParseTuple(args,"O|i",&o,&inner)) return NULL;
if (inner) {
/* subob = self */
subob = OBJECT(self);
/* o = aq_base(o) */
while (isWrapper(o) && WRAPPER(o)->obj) o=WRAPPER(o)->obj;
/* while 1: */
while (1) {
/* if aq_base(subob) is o: return 1 */
c = subob;
while (isWrapper(c) && WRAPPER(c)->obj) c = WRAPPER(c)->obj;
if (c == o) return PyInt_FromLong(1);
/* self = aq_inner(subob) */
/* if self is None: break */
if (isWrapper(subob)) {
self = WRAPPER(subob);
while (self->obj && isWrapper(self->obj))
self = WRAPPER(self->obj);
}
else break;
/* subob = aq_parent(self) */
/* if subob is None: break */
if (self->container)
subob = self->container;
else break;
}
}
else {
/* Follow wrappers instead. */
c = OBJECT(self);
while (1) {
if (c==o) return PyInt_FromLong(1);
if (c && isWrapper(c)) c=WRAPPER(c)->container;
else break;
}
}
return PyInt_FromLong(0);
}
static struct PyMethodDef Wrapper_methods[] = {
{"__init__", (PyCFunction)Wrapper__init__, 0,
"Initialize an Acquirer Wrapper"},
{"acquire", (PyCFunction)Wrapper_acquire_method,
METH_VARARGS|METH_KEYWORDS,
"Get an attribute, acquiring it if necessary"},
{"aq_acquire", (PyCFunction)Wrapper_acquire_method,
METH_VARARGS|METH_KEYWORDS,
"Get an attribute, acquiring it if necessary"},
{"aq_inContextOf", (PyCFunction)Wrapper_inContextOf, METH_VARARGS,
"Test whether the object is currently in the context of the argument"},
{NULL, NULL} /* sentinel */
};
static PyExtensionClass Wrappertype = {
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
"ImplicitAcquirerWrapper", /*tp_name*/
sizeof(Wrapper), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
(destructor)Wrapper_dealloc, /*tp_dealloc*/
(printfunc)0, /*tp_print*/
(getattrfunc)0, /*tp_getattr*/
(setattrfunc)0, /*tp_setattr*/
(cmpfunc)Wrapper_compare, /*tp_compare*/
(reprfunc)Wrapper_repr, /*tp_repr*/
&Wrapper_as_number, /*tp_as_number*/
&Wrapper_as_sequence, /*tp_as_sequence*/
&Wrapper_as_mapping, /*tp_as_mapping*/
(hashfunc)Wrapper_hash, /*tp_hash*/
(ternaryfunc)Wrapper_call, /*tp_call*/
(reprfunc)Wrapper_str, /*tp_str*/
(getattrofunc)Wrapper_getattro, /*tp_getattr with object key*/
(setattrofunc)Wrapper_setattro, /*tp_setattr with object key*/
/* Space for future expansion */
0L,0L,
"Wrapper object for implicit acquisition", /* Documentation string */
METHOD_CHAIN(Wrapper_methods),
EXTENSIONCLASS_BINDABLE_FLAG,
};
static PyExtensionClass XaqWrappertype = {
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
"ExplicitAcquirerWrapper", /*tp_name*/
sizeof(Wrapper), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
(destructor)Wrapper_dealloc, /*tp_dealloc*/
(printfunc)0, /*tp_print*/
(getattrfunc)0, /*tp_getattr*/
(setattrfunc)0, /*tp_setattr*/
(cmpfunc)Wrapper_compare, /*tp_compare*/
(reprfunc)Wrapper_repr, /*tp_repr*/
&Wrapper_as_number, /*tp_as_number*/
&Wrapper_as_sequence, /*tp_as_sequence*/
&Wrapper_as_mapping, /*tp_as_mapping*/
(hashfunc)Wrapper_hash, /*tp_hash*/
(ternaryfunc)Wrapper_call, /*tp_call*/
(reprfunc)Wrapper_str, /*tp_str*/
(getattrofunc)Xaq_getattro, /*tp_getattr with object key*/
(setattrofunc)Wrapper_setattro, /*tp_setattr with object key*/
/* Space for future expansion */
0L,0L,
"Wrapper object for explicit acquisition", /* Documentation string */
METHOD_CHAIN(Wrapper_methods),
EXTENSIONCLASS_BINDABLE_FLAG,
};
static PyObject *
acquire_of(PyObject *self, PyObject *args)
{
PyObject *inst;
UNLESS(PyArg_ParseTuple(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;
}
return newWrapper(self, inst, (PyTypeObject *)&Wrappertype);
}
static PyObject *
xaq_of(PyObject *self, PyObject *args)
{
PyObject *inst;
UNLESS(PyArg_ParseTuple(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;
}
return newWrapper(self, inst, (PyTypeObject *)&XaqWrappertype);
}
static struct PyMethodDef Acquirer_methods[] = {
{"__of__",(PyCFunction)acquire_of, METH_VARARGS,
"__of__(context) -- return the object in a context"},
{NULL, NULL} /* sentinel */
};
static struct PyMethodDef Xaq_methods[] = {
{"__of__",(PyCFunction)xaq_of, METH_VARARGS,""},
{NULL, NULL} /* sentinel */
};
static PyObject *
capi_aq_acquire(PyObject *self, PyObject *name, PyObject *filter,
PyObject *extra, int explicit, PyObject *defalt, int containment)
{
PyObject *result;
if (filter==Py_None) filter=0;
/* We got a wrapped object, so business as usual */
if (isWrapper(self))
return Wrapper_findattr(
WRAPPER(self), name, filter, extra, OBJECT(self),1,
explicit ||
WRAPPER(self)->ob_type==(PyTypeObject*)&Wrappertype,
explicit, containment);
/* Not wrapped and no filter, so just getattr */
if (! filter) return PyObject_GetAttr(self, name);
/* Crap, we've got to construct a wrapper so we can use Wrapper_findattr */
UNLESS (self=newWrapper(self, NULL, (PyTypeObject*)&Wrappertype))
return NULL;
result=Wrapper_findattr(WRAPPER(self), name, filter, extra, OBJECT(self),
1, 1, explicit, containment);
/* get rid of temp wrapper */
Py_DECREF(self);
return result;
}
static PyObject *
module_aq_acquire(PyObject *ignored, PyObject *args, PyObject *kw)
{
PyObject *self;
PyObject *name, *filter=0, *extra=Py_None;
PyObject *expl=0, *defalt=0;
int explicit=1, containment=0;
UNLESS (PyArg_ParseTupleAndKeywords(
args, kw, "OO|OOOOi", acquire_args,
&self, &name, &filter, &extra, &expl, &defalt, &containment
))
return NULL;
if (expl) explicit=PyObject_IsTrue(expl);
return capi_aq_acquire(self, name, filter, extra, explicit, defalt,
containment);
}
static PyObject *
capi_aq_get(PyObject *self, PyObject *name, PyObject *defalt, int containment)
{
PyObject *result = NULL;
/* We got a wrapped object, so business as usual */
if (isWrapper(self))
result=Wrapper_findattr(WRAPPER(self), name, 0, 0, OBJECT(self), 1, 1, 1,
containment);
else
result=PyObject_GetAttr(self, name);
if (! result && defalt)
{
PyErr_Clear();
result=defalt;
Py_INCREF(result);
}
return result;
}
static PyObject *
module_aq_get(PyObject *r, PyObject *args)
{
PyObject *self, *name, *defalt=0;
int containment=0;
UNLESS (PyArg_ParseTuple(args, "OO|Oi",
&self, &name, &defalt, &containment
)) return NULL;
return capi_aq_get(self, name, defalt, containment);
}
static int
capi_aq_iswrapper(PyObject *self) {
return isWrapper(self);
}
static PyObject *
capi_aq_base(PyObject *self)
{
PyObject *result;
if (! isWrapper(self))
{
Py_INCREF(self);
return self;
}
if (WRAPPER(self)->obj)
{
result=WRAPPER(self)->obj;
while (isWrapper(result) && WRAPPER(result)->obj)
result=WRAPPER(result)->obj;
}
else result=Py_None;
Py_INCREF(result);
return result;
}
static PyObject *
module_aq_base(PyObject *ignored, PyObject *args)
{
PyObject *self;
UNLESS (PyArg_ParseTuple(args, "O", &self)) return NULL;
return capi_aq_base(self);
}
static PyObject *
capi_aq_parent(PyObject *self)
{
PyObject *result=Py_None;
if (isWrapper(self) && WRAPPER(self)->container)
result=WRAPPER(self)->container;
Py_INCREF(result);
return result;
}
static PyObject *
module_aq_parent(PyObject *ignored, PyObject *args)
{
PyObject *self;
UNLESS (PyArg_ParseTuple(args, "O", &self)) return NULL;
return capi_aq_parent(self);
}
static PyObject *
capi_aq_self(PyObject *self)
{
PyObject *result;
if (! isWrapper(self))
{
Py_INCREF(self);
return self;
}
if (WRAPPER(self)->obj) result=WRAPPER(self)->obj;
else result=Py_None;
Py_INCREF(result);
return result;
}
static PyObject *
module_aq_self(PyObject *ignored, PyObject *args)
{
PyObject *self;
UNLESS (PyArg_ParseTuple(args, "O", &self)) return NULL;
return capi_aq_self(self);
}
static PyObject *
capi_aq_inner(PyObject *self)
{
PyObject *result;
if (! isWrapper(self))
{
Py_INCREF(self);
return self;
}
if (WRAPPER(self)->obj)
{
result=WRAPPER(self)->obj;
while (isWrapper(result) && WRAPPER(result)->obj)
{
self=result;
result=WRAPPER(result)->obj;
}
result=self;
}
else result=Py_None;
Py_INCREF(result);
return result;
}
static PyObject *
module_aq_inner(PyObject *ignored, PyObject *args)
{
PyObject *self;
UNLESS (PyArg_ParseTuple(args, "O", &self)) return NULL;
return capi_aq_inner(self);
}
static PyObject *
capi_aq_chain(PyObject *self, int containment)
{
PyObject *result;
UNLESS (result=PyList_New(0)) return NULL;
while (1)
{
if (isWrapper(self))
{
if (WRAPPER(self)->obj)
{
if (containment)
while (WRAPPER(self)->obj && isWrapper(WRAPPER(self)->obj))
self=WRAPPER(self)->obj;
if (PyList_Append(result,OBJECT(self)) < 0)
goto err;
}
if (WRAPPER(self)->container)
{
self=WRAPPER(self)->container;
continue;
}
}
else
if (PyList_Append(result, self) < 0)
goto err;
break;
}
return result;
err:
Py_DECREF(result);
return result;
}
static PyObject *
module_aq_chain(PyObject *ignored, PyObject *args)
{
PyObject *self;
int containment=0;
UNLESS (PyArg_ParseTuple(args, "O|i", &self, &containment))
return NULL;
return capi_aq_chain(self, containment);
}
static struct PyMethodDef methods[] = {
{"aq_acquire", (PyCFunction)module_aq_acquire, METH_VARARGS|METH_KEYWORDS,
"aq_acquire(ob, name [, filter, extra, explicit]) -- "
"Get an attribute, acquiring it if necessary"
},
{"aq_get", (PyCFunction)module_aq_get, METH_VARARGS,
"aq_get(ob, name [, default]) -- "
"Get an attribute, acquiring it if necessary."
},
{"aq_base", (PyCFunction)module_aq_base, METH_VARARGS,
"aq_base(ob) -- Get the object unwrapped"},
{"aq_parent", (PyCFunction)module_aq_parent, METH_VARARGS,
"aq_parent(ob) -- Get the parent of an object"},
{"aq_self", (PyCFunction)module_aq_self, METH_VARARGS,
"aq_self(ob) -- Get the object with the outermost wrapper removed"},
{"aq_inner", (PyCFunction)module_aq_inner, METH_VARARGS,
"aq_inner(ob) -- "
"Get the object with alll but the innermost wrapper removed"},
{"aq_chain", (PyCFunction)module_aq_chain, METH_VARARGS,
"aq_chain(ob [, containment]) -- "
"Get a list of objects in the acquisition environment"},
{NULL, NULL}
};
void
initAcquisition(void)
{
PyObject *m, *d;
PyObject *api;
PURE_MIXIN_CLASS(Acquirer,
"Base class for objects that implicitly"
" acquire attributes from containers\n"
, Acquirer_methods);
PURE_MIXIN_CLASS(ExplicitAcquirer,
"Base class for objects that explicitly"
" acquire attributes from containers\n"
, Xaq_methods);
UNLESS(ExtensionClassImported) return;
UNLESS(Acquired=PyString_FromStringAndSize(NULL,42)) return;
strcpy(PyString_AsString(Acquired),
"<Special Object Used to Force Acquisition>");
/* Create the module and add the functions */
m = Py_InitModule4("Acquisition", methods,
"Provide base classes for acquiring objects\n\n"
"$Id$\n",
OBJECT(NULL),PYTHON_API_VERSION);
d = PyModule_GetDict(m);
init_py_names();
PyExtensionClass_Export(d,"Acquirer",AcquirerType);
PyExtensionClass_Export(d,"ImplicitAcquisitionWrapper",Wrappertype);
PyExtensionClass_Export(d,"ExplicitAcquirer",ExplicitAcquirerType);
PyExtensionClass_Export(d,"ExplicitAcquisitionWrapper",XaqWrappertype);
/* Create aliases */
PyDict_SetItemString(d,"Implicit",OBJECT(&AcquirerType));
PyDict_SetItemString(d,"Explicit",OBJECT(&ExplicitAcquirerType));
PyDict_SetItemString(d,"Acquired",Acquired);
AcquisitionCAPI.AQ_Acquire = capi_aq_acquire;
AcquisitionCAPI.AQ_Get = capi_aq_get;
AcquisitionCAPI.AQ_IsWrapper = capi_aq_iswrapper;
AcquisitionCAPI.AQ_Base = capi_aq_base;
AcquisitionCAPI.AQ_Parent = capi_aq_parent;
AcquisitionCAPI.AQ_Self = capi_aq_self;
AcquisitionCAPI.AQ_Inner = capi_aq_inner;
AcquisitionCAPI.AQ_Chain = capi_aq_chain;
api = PyCObject_FromVoidPtr(&AcquisitionCAPI, NULL);
PyDict_SetItemString(d, "AcquisitionCAPI", api);
Py_DECREF(api);
}
/*****************************************************************************
Copyright (c) 1996-2002 Zope Corporation and Contributors.
All Rights Reserved.
This software is subject to the provisions of the Zope Public License,
Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
FOR A PARTICULAR PURPOSE
****************************************************************************/
static char ExtensionClass_module_documentation[] =
"ExtensionClass - Classes implemented in c\n"
"\n"
"Built-in C classes are like Built-in types except that\n"
"they provide some of the behavior of Python classes:\n"
"\n"
" - They provide access to unbound methods,\n"
" - They can be called to create instances.\n"
"\n"
"$Id$\n"
;
#include "ExtensionClass.h"
static void
PyVar_Assign(PyObject **v, PyObject *e)
{
Py_XDECREF(*v);
*v=e;
}
#define ASSIGN(V,E) PyVar_Assign(&(V),(E))
#define UNLESS(E) if (!(E))
#define UNLESS_ASSIGN(V,E) ASSIGN(V,E); UNLESS(V)
#define OBJECT(O) ((PyObject*)O)
/* Declarations for objects of type ExtensionClass */
staticforward PyExtensionClass ECType;
#define ExtensionClass_Check(O) ((O)->ob_type == (PyTypeObject*)&ECType)
#define ExtensionInstance_Check(O) \
((O)->ob_type->ob_type == (PyTypeObject*)&ECType)
#define AsExtensionClass(O) ((PyExtensionClass*)(O))
#define ExtensionClassOf(O) ((PyExtensionClass*)((O)->ob_type))
#define AsPyObject(O) ((PyObject*)(O))
#define NeedsToBeBound(O) \
((O)->ob_type->ob_type == (PyTypeObject*)&ECType && \
(((PyExtensionClass*)((O)->ob_type))->class_flags & \
EXTENSIONCLASS_BINDABLE_FLAG))
#define HasMethodHook(O) \
((O)->ob_type->ob_type == (PyTypeObject*)&ECType && \
(((PyExtensionClass*)((O)->ob_type))->class_flags & \
EXTENSIONCLASS_METHODHOOK_FLAG))
#define ALLOC_FREE(T) \
if (free ## T) { \
self=free ## T; \
free ## T=(T*)self->self; \
_Py_NewReference((PyObject *)self); \
assert(self->ob_refcnt == 1); \
} \
else UNLESS(self = PyObject_NEW(T, & T ## Type)) return NULL;
#define METH_BY_NAME (2 << 16)
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__of__, *py__call__, *py__call_method__,
*py__getitem__, *py__setitem__, *py__delitem__,
*py__getslice__, *py__setslice__, *py__delslice__, *py__len__,
*py__getattr__, *py__setattr__, *py__delattr__,
*py__del__, *py__repr__, *py__str__, *py__class__, *py__name__,
*py__hash__, *py__cmp__, *py__var_size__, *py__init__, *py__getinitargs__,
*py__getstate__, *py__setstate__, *py__dict__, *pyclass_,
*py__module__;
static PyObject *concat_fmt=0;
static PyObject *subclass_watcher=0; /* Object that subclass events */
static void
init_py_names(void)
{
#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(__delitem__);
INIT_PY_NAME(__getslice__);
INIT_PY_NAME(__setslice__);
INIT_PY_NAME(__delslice__);
INIT_PY_NAME(__len__);
INIT_PY_NAME(__of__);
INIT_PY_NAME(__call__);
INIT_PY_NAME(__call_method__);
INIT_PY_NAME(__getattr__);
INIT_PY_NAME(__setattr__);
INIT_PY_NAME(__delattr__);
INIT_PY_NAME(__del__);
INIT_PY_NAME(__repr__);
INIT_PY_NAME(__str__);
INIT_PY_NAME(__class__);
INIT_PY_NAME(__name__);
INIT_PY_NAME(__hash__);
INIT_PY_NAME(__cmp__);
INIT_PY_NAME(__var_size__);
INIT_PY_NAME(__init__);
INIT_PY_NAME(__getinitargs__);
INIT_PY_NAME(__getstate__);
INIT_PY_NAME(__setstate__);
INIT_PY_NAME(__dict__);
INIT_PY_NAME(class_);
INIT_PY_NAME(__module__);
#undef INIT_PY_NAME
}
static PyObject *
CallMethodO(PyObject *self, PyObject *name,
PyObject *args, PyObject *kw)
{
if (! args && PyErr_Occurred()) return NULL;
UNLESS(name=PyObject_GetAttr(self,name)) return NULL;
ASSIGN(name,PyEval_CallObjectWithKeywords(name,args,kw));
if (args) { Py_DECREF(args); }
return name;
}
#define Build Py_BuildValue
/* CMethod objects: */
typedef struct {
PyObject_HEAD
PyTypeObject *type;
PyObject *self;
char *name;
PyCFunction meth;
int flags;
char *doc;
} CMethod;
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))
#define CMETHOD(O) ((CMethod*)(O))
#define PMethod PyECMethodObject
#define PMethodType PyECMethodObjectType
staticforward PyTypeObject PMethodType;
#define PMethod_Check(O) ((O)->ob_type==&PMethodType)
#define UnboundPMethod_Check(O) \
((O)->ob_type==&PMethodType && ! ((PMethod*)(O))->self)
#define UnboundEMethod_Check(O) \
(((O)->ob_type==&PMethodType ||(O)->ob_type==&CMethodType) \
&& ! ((PMethod*)(O))->self)
#define PMETHOD(O) ((PMethod*)(O))
static PyObject *
bindPMethod(PMethod *m, PyObject *inst);
static PyObject *
#ifdef HAVE_STDARG_PROTOTYPES
/* VARARGS 2 */
JimErr_Format(PyObject *ErrType, char *stringformat, char *format, ...)
#else
/* VARARGS */
JimErr_Format(va_alist) va_dcl
#endif
{
va_list va;
PyObject *args=0, *retval=0;
#ifdef HAVE_STDARG_PROTOTYPES
va_start(va, format);
#else
PyObject *ErrType;
char *stringformat, *format;
va_start(va);
ErrType = va_arg(va, PyObject *);
stringformat = va_arg(va, char *);
format = va_arg(va, char *);
#endif
if (format) args = Py_VaBuildValue(format, va);
va_end(va);
if (format && ! args) return NULL;
if (stringformat && !(retval=PyString_FromString(stringformat))) return NULL;
if (retval)
{
if (args)
{
PyObject *v;
v=PyString_Format(retval, args);
Py_DECREF(retval);
Py_DECREF(args);
if (! v) return NULL;
retval=v;
}
}
else
if (args) retval=args;
else
{
PyErr_SetObject(ErrType,Py_None);
return NULL;
}
PyErr_SetObject(ErrType,retval);
Py_DECREF(retval);
return NULL;
}
static PyObject *
#ifdef HAVE_STDARG_PROTOTYPES
/* VARARGS 2 */
JimString_Build(char *out_format, char *build_format, ...)
#else
/* VARARGS */
JimString_Build(va_alist) va_dcl
#endif
{
va_list va;
PyObject *args, *retval, *fmt;
#ifdef HAVE_STDARG_PROTOTYPES
va_start(va, build_format);
#else
char *build_format;
char *out_format;
va_start(va);
out_format = va_arg(va, char *);
build_format = va_arg(va, char *);
#endif
if (build_format)
args = Py_VaBuildValue(build_format, va);
else
args = PyTuple_New(0);
va_end(va);
if (! args)
return NULL;
if (! PyTuple_Check(args))
{
PyObject *a;
a=PyTuple_New(1);
if (! a)
return NULL;
if (PyTuple_SetItem(a,0,args) == -1)
return NULL;
args=a;
}
fmt = PyString_FromString(out_format);
retval = PyString_Format(fmt, args);
Py_DECREF(args);
Py_DECREF(fmt);
return retval;
}
static PyObject *
EC_NewObject(PyTypeObject *type, int size)
{
PyObject *inst;
int len;
if (type->tp_itemsize) {
inst = PyObject_NEW_VAR(PyObject, type, size);
if (inst == NULL)
return NULL;
((PyVarObject *)inst)->ob_size = size;
}
else {
assert(size == 0);
inst = PyObject_NEW(PyObject, type);
if (inst == NULL)
return NULL;
}
Py_INCREF(type);
len = (type->tp_basicsize + type->tp_itemsize * size) - sizeof(PyObject);
memset(((char *)inst) + sizeof(PyObject), 0, len);
return inst;
}
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 (ExtensionClass_Check(t)
&& AsExtensionClass(t)->bases
&& CMethod_issubclass(AsExtensionClass(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 *freeCMethod=0;
static PyObject *
newCMethod(PyExtensionClass *type, PyObject *inst,
char *name, PyCFunction meth, int flags, char *doc)
{
CMethod *self;
ALLOC_FREE(CMethod);
Py_INCREF(type);
Py_XINCREF(inst);
self->type=(PyTypeObject*)type;
self->self=inst;
self->name=name;
self->meth=meth;
self->flags=flags;
self->doc=doc;
return (PyObject*)self;
}
static CMethod *
bindCMethod(CMethod *m, PyObject *inst)
{
CMethod *self;
UNLESS(inst->ob_type==m->type
|| (ExtensionInstance_Check(inst)
&& SubclassInstance_Check(inst,m->type))
|| ((m->flags & METH_CLASS_METHOD) && ExtensionClass_Check(inst))
)
{
Py_INCREF(m);
return m;
}
ALLOC_FREE(CMethod);
Py_INCREF(inst);
Py_INCREF(m->type);
self->type=m->type;
self->self=inst;
self->name=m->name;
self->meth=m->meth;
self->flags=m->flags;
self->doc=m->doc;
return self;
}
static void
CMethod_dealloc(CMethod *self)
{
#ifdef TRACE_DEALLOC
fprintf(stderr,"Deallocating C method %s\n", self->name);
#endif
Py_XDECREF(self->type);
Py_XDECREF(self->self);
self->self=(PyObject*)freeCMethod;
freeCMethod=self;
}
typedef PyObject *(*call_by_name_type)(PyObject*,PyObject*,PyObject*,
PyTypeObject*);
typedef PyObject *(*by_name_type)(PyObject*,PyObject*,
PyTypeObject*);
static PyObject *
call_cmethod(CMethod *self, PyObject *inst, PyObject *args, PyObject *kw)
{
if (!(self->flags & METH_VARARGS))
{
int size = PyTuple_Size(args);
if (size == 1) args = PyTuple_GET_ITEM(args, 0);
else if (size == 0) args = NULL;
}
if (self->flags & METH_KEYWORDS)
{
if (self->flags & METH_BY_NAME)
return (*(call_by_name_type)self->meth)(inst, args, kw,
self->type);
else
return (*(PyCFunctionWithKeywords)self->meth)(inst, args, kw);
}
else if (self->flags & METH_BY_NAME)
return (*(by_name_type)self->meth)(inst, args, self->type);
else
{
if (kw != NULL && PyDict_Size(kw) != 0)
{
PyErr_SetString(PyExc_TypeError,
"this function takes no keyword arguments");
return NULL;
}
return (*self->meth)(inst, args);
}
}
static char *hook_mark="C method being called through a hook.";
static PyObject *
callCMethodWithHook(CMethod *self, PyObject *inst,
PyObject *args, PyObject *kw)
{
PyObject *hook, *m;
UNLESS(m=newCMethod(AsExtensionClass(self->type),
inst, self->name, self->meth,
self->flags, hook_mark)) return NULL;
if ((hook=PyObject_GetAttr(inst,py__call_method__)))
{
if ((CMethod_Check(hook) && CMETHOD(hook)->meth==self->meth)
||
(PMethod_Check(hook)
&& CMethod_Check(PMETHOD(hook)->meth)
&& CMETHOD(PMETHOD(hook)->meth)->meth==self->meth)
)
{
/* Oops, we are already calling the hook! */
Py_DECREF(hook);
return PyEval_CallObjectWithKeywords(m,args,kw);
}
if (kw)
ASSIGN(hook,PyObject_CallFunction(hook,"OOO",m,args,kw));
else
ASSIGN(hook,PyObject_CallFunction(hook,"OO",m,args));
}
else
{
PyErr_Clear();
hook=PyEval_CallObjectWithKeywords(m,args,kw);
}
Py_DECREF(m);
return hook;
}
static PyObject *
CMethod_call(CMethod *self, PyObject *args, PyObject *kw)
{
int size;
if (self->self)
{
if (HasMethodHook(self->self) &&
self->doc != hook_mark /* This check prevents infinite recursion */
)
return callCMethodWithHook(self,self->self,args,kw);
return call_cmethod(self,self->self,args,kw);
}
if ((size=PyTuple_Size(args)) > 0)
{
PyObject *first=0;
UNLESS(first=PyTuple_GET_ITEM(args, 0)) return NULL;
if (
first->ob_type==self->type
||
(ExtensionInstance_Check(first)
&&
CMethod_issubclass(ExtensionClassOf(first),
AsExtensionClass(self->type))
)
)
{
PyObject *rest=0;
UNLESS (rest=PySequence_GetSlice(args,1,size)) return NULL;
if (HasMethodHook(first) &&
self->doc != hook_mark /* This check prevents infinite recursion */
)
ASSIGN(rest, callCMethodWithHook(self, first, rest, kw) );
else
ASSIGN(rest, call_cmethod(self, first, rest, kw) );
return rest;
}
}
return JimErr_Format(PyExc_TypeError,
"unbound C method must be called with %s 1st argument",
"s", self->type->tp_name);
}
static PyObject *
CMethod_getattro(CMethod *self, PyObject *oname)
{
PyObject *r;
if (PyString_Check(oname))
{
char *name;
UNLESS(name=PyString_AsString(oname)) return NULL;
if (name[0] != '_' && name[0] && name[1] != '_' &&
PyEval_GetRestricted())
{
PyErr_SetString(PyExc_RuntimeError,
"function attributes not accessible in restricted mode");
return NULL;
}
if (strcmp(name,"__name__")==0 || strcmp(name,"func_name")==0 )
return PyString_FromString(self->name);
if (strcmp(name,"func_code")==0 ||
strcmp(name,"im_func")==0)
{
Py_INCREF(self);
return (PyObject *)self;
}
if (strcmp(name,"__doc__")==0 ||
strcmp(name,"func_doc")==0)
{
if (self->doc)
return PyString_FromString(self->doc);
else
return PyString_FromString("");
}
if (strcmp(name,"im_class")==0)
{
Py_INCREF(self->type);
return (PyObject *)self->type;
}
if (strcmp(name,"im_self")==0)
{
if (self->self) r=self->self;
else r=Py_None;
Py_INCREF(r);
return r;
}
}
if (self->self) /* Psuedo attributes */
{
UNLESS(oname=Py_BuildValue("sO", self->name, oname)) return NULL;
UNLESS_ASSIGN(oname,PyString_Format(concat_fmt, oname)) return NULL;
r=PyObject_GetAttr(OBJECT(self->self), py__class__);
if (r)
{
ASSIGN(r, PyObject_GetAttr(r, oname));
if (r) {
if (UnboundCMethod_Check(r))
ASSIGN(r, (PyObject*)bindCMethod((CMethod*)r, self->self));
else if (UnboundPMethod_Check(r))
ASSIGN(r, bindPMethod((PMethod*)r, self->self));
}
}
Py_DECREF(oname);
return r;
}
PyErr_SetObject(PyExc_AttributeError, oname);
return NULL;
}
static PyTypeObject CMethodType = {
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
"CMethod", /*tp_name*/
sizeof(CMethod), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
(destructor)CMethod_dealloc, /*tp_dealloc*/
(printfunc)0, /*tp_print*/
0, /*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)CMethod_call, /*tp_call*/
(reprfunc)0, /*tp_str*/
(getattrofunc)CMethod_getattro, /* tp_getattro */
(setattrofunc)0, /* tp_setattro */
/* Space for future expansion */
0L,0L,
"Storage manager for unbound C function PyObject data"
/* Documentation string */
};
/* PMethod objects: */
static PMethod *freePMethod=0;
static PyObject *
newPMethod(PyExtensionClass *type, PyObject *meth)
{
PMethod *self;
ALLOC_FREE(PMethod);
Py_INCREF(type);
Py_INCREF(meth);
self->type=(PyTypeObject*)type;
self->self=NULL;
self->meth=meth;
return (PyObject*)self;
}
static PyObject *
bindPMethod(PMethod *m, PyObject *inst)
{
PMethod *self;
if (NeedsToBeBound(m->meth))
return CallMethodO(m->meth, py__of__, Build("(O)", inst), NULL);
if (m->ob_refcnt==1)
{
Py_INCREF(inst);
ASSIGN(m->self, inst);
Py_INCREF(m);
return (PyObject*)m;
}
ALLOC_FREE(PMethod);
Py_INCREF(inst);
Py_INCREF(m->type);
Py_INCREF(m->meth);
self->type=m->type;
self->self=inst;
self->meth=m->meth;
return (PyObject*)self;
}
static PyObject *
PMethod_New(PyObject *meth, PyObject *inst)
{
if (PMethod_Check(meth)) return bindPMethod((PMethod*)meth,inst);
UNLESS(ExtensionInstance_Check(inst))
return JimErr_Format(PyExc_TypeError,
"Attempt to use %s as method for %s, which is "
"not an extension class instance.",
"OO",meth,inst);
if ((meth=newPMethod(ExtensionClassOf(inst), meth)))
UNLESS_ASSIGN(((PMethod*)meth)->self,inst) return NULL;
Py_INCREF(inst);
return meth;
}
static void
PMethod_dealloc(PMethod *self)
{
#ifdef TRACE_DEALLOC
fprintf(stderr,"Deallocating PM ... ");
#endif
Py_XDECREF(self->type);
Py_XDECREF(self->self);
Py_XDECREF(self->meth);
self->self=(PyObject*)freePMethod;
freePMethod=self;
#ifdef TRACE_DEALLOC
fprintf(stderr," Done Deallocating PM\n");
#endif
}
static PyObject *
callMethodWithPossibleHook(PyObject *inst,
PyObject *meth, PyObject *args, PyObject *kw)
{
if (HasMethodHook(inst))
{
PyObject *hook;
if ((hook=PyObject_GetAttr(inst,py__call_method__)))
{
if (PMethod_Check(hook) && ((PMethod*)hook)->meth==meth)
{
/* Oops, we are already calling the hook! */
Py_DECREF(hook);
return PyEval_CallObjectWithKeywords(meth,args,kw);
}
if (kw)
ASSIGN(hook,PyObject_CallFunction(hook,"OOO",meth,args,kw));
else
ASSIGN(hook,PyObject_CallFunction(hook,"OO",meth,args));
return hook;
}
PyErr_Clear();
}
return PyEval_CallObjectWithKeywords(meth,args,kw);
}
static PyObject *
call_PMethod(PMethod *self, PyObject *inst, PyObject *args, PyObject *kw)
{
PyObject *a;
if (CMethod_Check(self->meth)
&& CMETHOD(self->meth)->type->tp_basicsize == sizeof(PyPureMixinObject)
&& ! (CMETHOD(self->meth)->self)
)
{
/* Special HACK^H^H^Hcase:
we are wrapping an abstract unbound CMethod */
if (HasMethodHook(inst) &&
/* This check prevents infinite recursion: */
CMETHOD(self->meth)->doc != hook_mark
)
return callCMethodWithHook(CMETHOD(self->meth),inst,args,kw);
return call_cmethod(CMETHOD(self->meth),inst,args,kw);
}
else
{
a=Py_BuildValue("(O)",inst);
if (a) ASSIGN(a,PySequence_Concat(a,args));
if (a) ASSIGN(a,callMethodWithPossibleHook(inst,self->meth,a,kw));
return a;
}
}
static PyObject *
PMethod_call(PMethod *self, PyObject *args, PyObject *kw)
{
int size;
if (self->self) return call_PMethod(self,self->self,args,kw);
if ((size=PyTuple_Size(args)) > 0)
{
PyObject *first=0, *ftype=0;
UNLESS(first=PyTuple_GET_ITEM(args, 0)) return NULL;
if (! self->type ||
((ftype=PyObject_GetAttr(first,py__class__)) &&
(ftype==(PyObject*)self->type ||
(ExtensionClass_Check(ftype) &&
CMethod_issubclass(AsExtensionClass(ftype),
AsExtensionClass(self->type))
)
)
)
)
{
if (NeedsToBeBound(self->meth))
{
PyObject *r, *rest;
UNLESS(r=CallMethodO(self->meth,py__of__,Build("(O)", first),
NULL))
return NULL;
UNLESS(rest=PySequence_GetSlice(args,1,size))
{
Py_DECREF(r);
return NULL;
}
ASSIGN(r,callMethodWithPossibleHook(first,r,rest,kw));
Py_DECREF(rest);
return r;
}
Py_DECREF(ftype);
return callMethodWithPossibleHook(first,self->meth,args,kw);
}
Py_XDECREF(ftype);
}
return JimErr_Format(PyExc_TypeError,
"unbound Python method must be called with %s"
" 1st argument",
"s", self->type->tp_name);
}
static PyObject *
PMethod_repr(PMethod *self)
{
char *func_name, buf[8192];
int n;
if (PyFunction_Check(self->meth)) {
func_name = PyString_AS_STRING(
((PyFunctionObject*)self->meth)->func_name);
}
else {
/* self->meth is some other kind of object */
func_name = "(?)";
}
if (self->self) {
PyObject *repr = PyObject_Repr(self->self);
if (!repr)
return NULL;
n = sprintf(buf,
"<bound method %.1000s.%.1000s of %.1000s>",
self->type->tp_name, func_name,
PyString_AS_STRING(repr));
Py_DECREF(repr);
}
else {
n = sprintf(buf,
"<unbound method %.1000s.%.1000s>",
self->type->tp_name, func_name);
}
return PyString_FromStringAndSize(buf, n);
}
static PyObject *
PMethod_getattro(PMethod *self, PyObject *oname)
{
PyObject *r;
if (PyString_Check(oname))
{
char *name;
UNLESS(name=PyString_AsString(oname)) return NULL;
if (name[0]=='_' && name[1]=='_')
{
if (strcmp(name+2,"name__")==0)
return PyObject_GetAttrString(self->meth,"__name__");
if (strcmp(name+2,"doc__")==0)
return PyObject_GetAttrString(self->meth,"__doc__");
}
else if (PyEval_GetRestricted())
{
PyErr_SetString(PyExc_RuntimeError,
"function attributes not accessible in restricted mode");
return NULL;
}
else if (name[0]=='f' && name[1]=='u' && name[2]=='n' && name[3]=='c'
&& name[4]=='_')
{
if (strcmp(name+5,"name")==0 )
return PyObject_GetAttrString(self->meth,"__name__");
if (strcmp(name+5,"doc")==0)
return PyObject_GetAttrString(self->meth,"__doc__");
}
if (*name++=='i' && *name++=='m' && *name++=='_')
{
if (strcmp(name,"func")==0)
{
Py_INCREF(self->meth);
return self->meth;
}
if (strcmp(name,"class")==0)
{
Py_INCREF(self->type);
return (PyObject *)self->type;
}
if (strcmp(name,"self")==0)
{
if (self->self) r=self->self;
else r=Py_None;
Py_INCREF(r);
return r;
}
}
}
if (self->meth)
{
if ((r=PyObject_GetAttr(self->meth, oname))) return r;
PyErr_Clear();
if (self->self) /* Psuedo attrs */
{
PyObject *myname;
UNLESS(myname=PyObject_GetAttr(self->meth, py__name__)) return NULL;
oname=Py_BuildValue("OO", myname, oname);
Py_DECREF(myname);
UNLESS(oname) return NULL;
UNLESS_ASSIGN(oname,PyString_Format(concat_fmt, oname)) return NULL;
r=PyObject_GetAttr(OBJECT(self->self), py__class__);
if (r)
{
ASSIGN(r, PyObject_GetAttr(r, oname));
if (r) {
if (UnboundCMethod_Check(r))
ASSIGN(r, (PyObject*)bindCMethod((CMethod*)r, self->self));
else if (UnboundPMethod_Check(r))
ASSIGN(r, bindPMethod((PMethod*)r, self->self));
}
}
Py_DECREF(oname);
return r;
}
}
PyErr_SetObject(PyExc_AttributeError, oname);
return NULL;
return PyObject_GetAttr(self->meth, oname);
}
static PyTypeObject PMethodType = {
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
"Python Method", /*tp_name*/
sizeof(PMethod), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
(destructor)PMethod_dealloc, /*tp_dealloc*/
(printfunc)0, /*tp_print*/
0, /*tp_getattr*/
(setattrfunc)0, /*tp_setattr*/
(cmpfunc)0, /*tp_compare*/
(reprfunc)PMethod_repr, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
(hashfunc)0, /*tp_hash*/
(ternaryfunc)PMethod_call, /*tp_call*/
(reprfunc)0, /*tp_str*/
(getattrofunc)PMethod_getattro, /*tp_getattro*/
(setattrofunc)0, /* tp_setattro */
/* Space for future expansion */
0L,0L,
"Storage manager for unbound C function PyObject data"
/* Documentation string */
};
static PyObject *CCL_getattr(PyExtensionClass*,PyObject*,int);
static int
CCL_hasattr(PyExtensionClass *self,PyObject *name)
{
PyObject *r;
r=CCL_getattr(self, name, 0);
if (r)
{
Py_DECREF(r);
return 1;
}
else
PyErr_Clear();
return 0;
}
/* Special Methods */
#define UNARY_OP(OP) \
static PyObject * \
OP ## _by_name(PyObject *self, PyObject *args, PyTypeObject *ob_type) { \
UNLESS(PyArg_ParseTuple(args,"")) return NULL; \
return ob_type->tp_ ## OP(self); \
}
UNARY_OP(repr)
UNARY_OP(str)
static PyObject *
hash_by_name(PyObject *self, PyObject *args, PyTypeObject *ob_type) {
long r;
UNLESS(PyArg_ParseTuple(args,"")) return NULL;
UNLESS(-1 != (r=ob_type->tp_hash(self))) return NULL;
return PyInt_FromLong(r);
}
static PyObject *
call_by_name(PyObject *self, PyObject *args, PyObject *kw,
PyTypeObject *ob_type)
{
return ob_type->tp_call(self,args,kw);
}
static PyObject *
compare_by_name(PyObject *self, PyObject *args, PyTypeObject *ob_type)
{
PyObject *other;
UNLESS(PyArg_ParseTuple(args,"O", &other)) return NULL;
return PyInt_FromLong(ob_type->tp_compare(self,other));
}
static PyObject *
getattr_by_name(PyObject *self, PyObject *args, PyTypeObject *ob_type)
{
char *name;
UNLESS(PyArg_ParseTuple(args,"s",&name)) return NULL;
return ob_type->tp_getattr(self,name);
}
static PyObject *
setattr_by_name(PyObject *self, PyObject *args, PyTypeObject *ob_type)
{
char *name;
PyObject *v;
UNLESS(PyArg_ParseTuple(args,"sO",&name,&v)) return NULL;
UNLESS(-1 != ob_type->tp_setattr(self,name,v)) return NULL;
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *
delsetattr_by_name(PyObject *self, PyObject *args, PyTypeObject *ob_type)
{
char *name;
UNLESS(PyArg_ParseTuple(args,"s",&name)) return NULL;
UNLESS(-1 != ob_type->tp_setattr(self,name,NULL)) return NULL;
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *
getattro_by_name(PyObject *self, PyObject *args, PyTypeObject *ob_type)
{
PyObject *name;
UNLESS(PyArg_ParseTuple(args,"O",&name)) return NULL;
return ob_type->tp_getattro(self,name);
}
static PyObject *
setattro_by_name(PyObject *self, PyObject *args, PyTypeObject *ob_type)
{
PyObject *name;
PyObject *v;
UNLESS(PyArg_ParseTuple(args,"OO",&name,&v)) return NULL;
UNLESS(-1 != ob_type->tp_setattro(self,name,v)) return NULL;
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *
delsetattro_by_name(PyObject *self, PyObject *args, PyTypeObject *ob_type)
{
PyObject *name;
UNLESS(PyArg_ParseTuple(args,"O",&name)) return NULL;
UNLESS(-1 != ob_type->tp_setattro(self,name,NULL)) return NULL;
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *
length_by_name(PyObject *self, PyObject *args, PyTypeObject *ob_type)
{
long r;
UNLESS(PyArg_ParseTuple(args,"")) return NULL;
if (ob_type->tp_as_sequence)
{
UNLESS(-1 != (r=ob_type->tp_as_sequence->sq_length(self)))
return NULL;
}
else
{
UNLESS(-1 != (r=ob_type->tp_as_mapping->mp_length(self)))
return NULL;
}
return PyInt_FromLong(r);
}
static PyObject *
getitem_by_name(PyObject *self, PyObject *args, PyTypeObject *ob_type)
{
PyObject *key;
UNLESS(PyArg_ParseTuple(args,"O",&key)) return NULL;
if (ob_type->tp_as_mapping)
return ob_type->tp_as_mapping->mp_subscript(self,key);
else
{
int index;
UNLESS(-1 != (index=PyInt_AsLong(key))) return NULL;
return ob_type->tp_as_sequence->sq_item(self,index);
}
}
static PyCFunction item_by_name=(PyCFunction)getitem_by_name;
static PyCFunction subscript_by_name=(PyCFunction)getitem_by_name;
static PyObject *
setitem_by_name(PyObject *self, PyObject *args, PyTypeObject *ob_type)
{
PyObject *key, *v;
long r;
UNLESS(PyArg_ParseTuple(args,"OO",&key,&v)) return NULL;
if (ob_type->tp_as_mapping)
r=ob_type->tp_as_mapping->mp_ass_subscript(self,key,v);
else
{
int index;
UNLESS(-1 != (index=PyInt_AsLong(key))) return NULL;
r=ob_type->tp_as_sequence->sq_ass_item(self,index,v);
}
if (r < 0) return NULL;
Py_INCREF(Py_None);
return Py_None;
}
static PyCFunction ass_item_by_name=(PyCFunction)setitem_by_name;
static PyCFunction ass_subscript_by_name=(PyCFunction)setitem_by_name;
static PyObject *
slice_by_name(PyObject *self, PyObject *args, PyTypeObject *ob_type)
{
int i1,i2;
UNLESS(PyArg_ParseTuple(args,"ii",&i1,&i2)) return NULL;
return ob_type->tp_as_sequence->sq_slice(self,i1,i2);
}
static PyObject *
ass_slice_by_name(PyObject *self, PyObject *args, PyTypeObject *ob_type)
{
int i1,i2;
PyObject *v;
long r;
UNLESS(PyArg_ParseTuple(args,"iiO",&i1,&i2,&v)) return NULL;
r=ob_type->tp_as_sequence->sq_ass_slice(self,i1,i2,v);
if (r<0) return NULL;
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *
concat_by_name(PyObject *self, PyObject *args, PyTypeObject *ob_type)
{
PyObject *other;
UNLESS(PyArg_ParseTuple(args,"O",&other)) return NULL;
return ob_type->tp_as_sequence->sq_concat(self,other);
}
static PyObject *
repeat_by_name(PyObject *self, PyObject *args, PyTypeObject *ob_type)
{
int r;
UNLESS(PyArg_ParseTuple(args,"i",&r)) return NULL;
return ob_type->tp_as_sequence->sq_repeat(self,r);
}
#define BINOP(OP,AOP) \
static PyObject * \
OP ## _by_name(PyObject *self, PyObject *args, PyTypeObject *ob_type) { \
PyObject *v; \
UNLESS(PyArg_ParseTuple(args,"O",&v)) return NULL; \
return ob_type->tp_as_number->nb_ ## OP(self, v); \
}
BINOP(add,Add)
BINOP(subtract,Subtract)
BINOP(multiply,Multiply)
BINOP(divide,Divide)
BINOP(remainder,Remainder)
BINOP(divmod,Divmod)
static PyObject *
power_by_name(PyObject *self, PyObject *args, PyTypeObject *ob_type)
{
PyObject *v, *z=NULL;
UNLESS(PyArg_ParseTuple(args,"O|O",&v,&z)) return NULL;
return ob_type->tp_as_number->nb_power(self,v,z);
}
#define UNOP(OP) \
static PyObject * \
OP ## _by_name(PyObject *self, PyObject *args, PyTypeObject *ob_type) { \
UNLESS(PyArg_ParseTuple(args,"")) return NULL; \
return ob_type->tp_as_number->nb_ ## OP(self); \
}
UNOP(negative)
UNOP(positive)
UNOP(absolute)
static PyObject *
nonzero_by_name(PyObject *self, PyObject *args, PyTypeObject *ob_type) {
long r;
UNLESS(PyArg_ParseTuple(args,"")) return NULL;
UNLESS(-1 != (r=ob_type->tp_as_number->nb_nonzero(self))) return NULL;
return PyInt_FromLong(r);
}
UNOP(invert)
BINOP(lshift,Lshift)
BINOP(rshift,Rshift)
BINOP(and,And)
BINOP(or,Or)
BINOP(xor,Xor)
static PyObject *
coerce_by_name(PyObject *self, PyObject *args, PyTypeObject *ob_type)
{
PyObject *v;
int r;
UNLESS(PyArg_ParseTuple(args,"O", &v)) return NULL;
UNLESS(-1 != (r=ob_type->tp_as_number->nb_coerce(&self,&v)))
{
Py_INCREF(Py_None);
return Py_None;
}
args=Py_BuildValue("OO",self,v);
Py_DECREF(self);
Py_DECREF(v);
return args;
}
UNOP(long)
UNOP(int)
UNOP(float)
UNOP(oct)
UNOP(hex)
#define FILLENTRY(T,MN,N,F,D) if (T ## _ ## MN) { \
UNLESS(-1 != PyMapping_SetItemString(dict,"__" # N "__", \
newCMethod(type, NULL, "__" # N "__", \
(PyCFunction)MN ## _by_name, F | METH_BY_NAME, # D))) \
goto err; }
#define delFILLENTRY(T,MN,N,F,D) if (T ## _ ## MN) { \
UNLESS(-1 != PyMapping_SetItemString(dict,"__" # N "__", \
newCMethod(type, NULL, "__" # N "__", \
(PyCFunction)del ## MN ## _by_name, F | METH_BY_NAME, # D))) \
goto err; }
static PyObject *
getBaseDictionary(PyExtensionClass *type)
{
PyNumberMethods *nm;
PySequenceMethods *sm;
PyMappingMethods *mm;
PyObject *dict;
UNLESS(dict=type->class_dictionary)
UNLESS(dict=PyDict_New()) return NULL;
FILLENTRY(type->tp, repr, repr, METH_VARARGS,
"convert to an expression string");
FILLENTRY(type->tp, hash, hash, METH_VARARGS, "compute a hash value");
FILLENTRY(type->tp, call, call, METH_VARARGS | METH_KEYWORDS,
"call as a function");
FILLENTRY(type->tp, compare, comp, METH_VARARGS,
"compare with another object");
UNLESS (type->class_flags & EXTENSIONCLASS_PYTHONICATTR_FLAG)
{
FILLENTRY(type->tp, getattr, getattr, METH_VARARGS, "Get an attribute");
FILLENTRY(type->tp, setattr, setattr, METH_VARARGS, "Set an attribute");
delFILLENTRY(type->tp, setattr, delattr, METH_VARARGS,
"Delete an attribute");
FILLENTRY(type->tp, getattro, getattr, METH_VARARGS, "Get an attribute");
FILLENTRY(type->tp, setattro, setattr, METH_VARARGS, "Set an attribute");
delFILLENTRY(type->tp, setattro, delattr, METH_VARARGS,
"Delete an attribute");
}
if ((sm=type->tp_as_sequence))
{
FILLENTRY(sm->sq, length, len, METH_VARARGS, "Get the object length");
FILLENTRY(sm->sq, repeat, mul, METH_VARARGS,
"Get a new object that is the object repeated.");
FILLENTRY(sm->sq, item, getitem, METH_VARARGS, "Get an item");
FILLENTRY(sm->sq, slice, getslice, METH_VARARGS, "Get a slice");
FILLENTRY(sm->sq, ass_item, setitem, METH_VARARGS, "Assign an item");
FILLENTRY(sm->sq, ass_slice, setslice, METH_VARARGS, "Assign a slice");
}
if ((mm=type->tp_as_mapping))
{
FILLENTRY(mm->mp, length, len, METH_VARARGS, "Get the object length");
FILLENTRY(mm->mp, subscript, getitem, METH_VARARGS, "Get an item");
FILLENTRY(mm->mp, ass_subscript, setitem, METH_VARARGS,
"Assign an item");
}
if ((nm=type->tp_as_number) != NULL)
{
FILLENTRY(nm->nb, add, add, METH_VARARGS, "Add to another");
FILLENTRY(nm->nb, subtract, sub, METH_VARARGS, "Subtract another");
FILLENTRY(nm->nb, multiply, mul, METH_VARARGS, "Multiple by another");
FILLENTRY(nm->nb, divide, div, METH_VARARGS, "Divide by another");
FILLENTRY(nm->nb, remainder, mod, METH_VARARGS, "Compute a remainder");
FILLENTRY(nm->nb, power, pow, METH_VARARGS, "Raise to a power");
FILLENTRY(nm->nb, divmod, divmod, METH_VARARGS,
"Compute the whole result and remainder of dividing\n"
"by another");
FILLENTRY(nm->nb, negative, neg, METH_VARARGS,
"Get the negative value.");
FILLENTRY(nm->nb, positive, pos, METH_VARARGS, "Compute positive value");
FILLENTRY(nm->nb, absolute, abs, METH_VARARGS, "Compute absolute value");
FILLENTRY(nm->nb, nonzero, nonzero, METH_VARARGS,
"Determine whether nonzero");
FILLENTRY(nm->nb, invert, inv, METH_VARARGS, "Compute inverse");
FILLENTRY(nm->nb, lshift, lshift, METH_VARARGS, "Shist left");
FILLENTRY(nm->nb, rshift, rshift, METH_VARARGS, "Shist right");
FILLENTRY(nm->nb, and, and, METH_VARARGS, "bitwize logical and");
FILLENTRY(nm->nb, or, or, METH_VARARGS, "bitwize logical or");
FILLENTRY(nm->nb, xor, xor, METH_VARARGS, "bitwize logical excusive or");
FILLENTRY(nm->nb, coerce, coerce, METH_VARARGS,
"Coerce with another to a common type");
FILLENTRY(nm->nb, int, int, METH_VARARGS, "Convert to an integer");
FILLENTRY(nm->nb, long, long, METH_VARARGS,
"Convert to an infinite-precision integer");
FILLENTRY(nm->nb, float, float, METH_VARARGS,
"Convert to floating point number");
FILLENTRY(nm->nb, oct, oct, METH_VARARGS, "Convert to an octal string");
FILLENTRY(nm->nb, hex, hex, METH_VARARGS,
"Convert to a hexadecimal string");
}
if ((sm=type->tp_as_sequence))
{
FILLENTRY(sm->sq, concat, add, METH_VARARGS,
"Concatinate the object with another");
}
return dict;
err:
Py_DECREF(dict);
return NULL;
}
#undef UNARY_OP
#undef BINOP
#undef UNOP
#undef FILLENTRY
PyObject *
EC_reduce(PyObject *self, PyObject *args)
{
PyObject *state=0;
if ((args=PyObject_GetAttr(self,py__getinitargs__)))
{
UNLESS_ASSIGN(args,PyEval_CallObject(args,NULL)) return NULL;
UNLESS_ASSIGN(args,PySequence_Tuple(args)) return NULL;
}
else
{
PyErr_Clear();
if (ExtensionClassOf(self)->class_flags & EXTENSIONCLASS_BASICNEW_FLAG)
{
args=Py_None;
Py_INCREF(args);
}
else args=PyTuple_New(0);
}
if ((state=PyObject_GetAttr(self,py__getstate__)))
{
UNLESS_ASSIGN(state,PyEval_CallObject(state,NULL)) goto err;
ASSIGN(args,Py_BuildValue("OOO", self->ob_type, args, state));
Py_DECREF(state);
}
else
{
PyErr_Clear();
if ((state=PyObject_GetAttr(self, py__dict__)))
{
ASSIGN(args,Py_BuildValue("OOO", self->ob_type, args, state));
Py_DECREF(state);
}
else
{
PyErr_Clear();
ASSIGN(args, Py_BuildValue("OO", self->ob_type, args));
}
}
return args;
err:
Py_DECREF(args);
return NULL;
}
static PyObject *
inheritedAttribute(PyExtensionClass *self, PyObject *args)
{
PyObject *name;
UNLESS(PyArg_ParseTuple(args,"O!",&PyString_Type, &name)) return NULL;
return CCL_getattr(AsExtensionClass(self),name,1);
}
static PyObject *
basicnew(PyExtensionClass *self, PyObject *args)
{
PyObject *inst=0;
int size = 0;
if (! self->tp_dealloc)
{
PyErr_SetString(PyExc_TypeError,
"Attempt to create instance of an abstract type");
return NULL;
}
UNLESS(self->class_flags & EXTENSIONCLASS_BASICNEW_FLAG)
return PyObject_CallObject(OBJECT(self), NULL);
if (self->tp_itemsize)
{
/* We have a variable-sized object, we need to get it's size */
PyObject *var_size;
UNLESS(var_size=CCL_getattr(self, py__var_size__, 0)) return NULL;
UNLESS_ASSIGN(var_size,PyObject_CallObject(var_size,NULL)) return NULL;
size=PyInt_AsLong(var_size);
if (PyErr_Occurred()) return NULL;
}
UNLESS(inst=EC_NewObject((PyTypeObject *)self, size))
return NULL;
if (ClassHasInstDict(self))
UNLESS(INSTANCE_DICT(inst)=PyDict_New()) goto err;
if (self->bases && subclass_watcher &&
! PyObject_CallMethod(subclass_watcher,"created","O",inst))
PyErr_Clear();
return inst;
err:
Py_DECREF(inst);
return NULL;
}
struct PyMethodDef ECI_methods[] = {
{"__reduce__",(PyCFunction)EC_reduce, METH_VARARGS,
"__reduce__() -- Reduce an instance into it's class and creation data"
},
{"inheritedAttribute",(PyCFunction)inheritedAttribute,
METH_VARARGS | METH_CLASS_METHOD,
"inheritedAttribute(class,name) -- Get an inherited attribute\n\n"
"Get an attribute that would be inherited if the given (extension)\n"
"class did not define it. This method is used when overriding\n"
"inherited methods. It provides 2 advantages over accessing\n"
"\n"
"attributes directly through a superclass:\n"
"\n"
"1. The superclass need not be known,\n"
"\n"
"2. The superclass may be a Python class. Without this method, it would\n"
" be possible to override methods inherited from python classes because\n"
" unbound methods gotten from Python classes cannot be called with \n"
" extension class instances. \n"
},
{"__basicnew__",(PyCFunction)basicnew,
METH_VARARGS | METH_CLASS_METHOD,
"__basicnew__() -- return a new uninitialized instance"
},
{NULL, NULL} /* sentinel */
};
static PyObject *
initializeBaseExtensionClass(PyExtensionClass *self)
{
static PyMethodChain top = { ECI_methods, NULL };
PyMethodChain *chain;
PyObject *dict;
int abstract;
/* Is this an abstract, or at least a dataless, class? */
abstract=self->tp_basicsize == sizeof(PyPureMixinObject);
self->ob_type=(PyTypeObject*)&ECType;
Py_INCREF(self->ob_type);
UNLESS(dict=self->class_dictionary=getBaseDictionary(self)) return NULL;
if (self->tp_name)
{
PyObject *name;
UNLESS(name=PyString_FromString(self->tp_name)) goto err;
if (0 > PyMapping_SetItemString(dict,"__doc__",name)) goto err;
Py_DECREF(name);
}
else if (0 > PyMapping_SetItemString(dict,"__doc__",Py_None)) goto err;
if (&self->methods) chain=&(self->methods);
else chain=&top;
while (1)
{
PyMethodDef *ml = chain->methods;
for (; ml && ml->ml_name != NULL; ml++)
{
if (ml->ml_meth)
{
if (! PyMapping_HasKeyString(dict,ml->ml_name))
{
PyObject *m;
/* Note that we create a circular reference here.
I suppose that this isn't so bad, since this is
probably a static thing anyway. Still, it is a
bit troubling. Oh well.
*/
if (ml->ml_flags & METH_CLASS_METHOD)
{
UNLESS(m=newCMethod(
AsExtensionClass(self->ob_type), NULL,
ml->ml_name, ml->ml_meth,
ml->ml_flags, ml->ml_doc))
return NULL;
}
else
{
UNLESS(m=newCMethod(self, NULL, ml->ml_name, ml->ml_meth,
ml->ml_flags, ml->ml_doc))
return NULL;
if (abstract)
UNLESS_ASSIGN(m, newPMethod(self, m))
return NULL;
}
if (PyMapping_SetItemString(dict,ml->ml_name,m) < 0)
return NULL;
}
}
else if (ml->ml_doc && *(ml->ml_doc))
{
/* No actual meth, this is probably to hook a doc string
onto a special method. */
PyObject *m;
if ((m=PyMapping_GetItemString(dict,ml->ml_name)))
{
if (m->ob_type==&CMethodType)
((CMethod *)(m))->doc=ml->ml_doc;
}
else
PyErr_Clear();
}
}
if (chain == &top) break;
UNLESS(chain=chain->link) chain=&top;
}
return (PyObject*)self;
err:
Py_DECREF(dict);
return NULL;
}
static void
CCL_dealloc(PyExtensionClass *self)
{
#ifdef TRACE_DEALLOC
fprintf(stderr,"Deallocating %s\n", self->tp_name);
#endif
Py_XDECREF(self->class_dictionary);
if (self->bases)
{
/* If we are a subclass, then we strduped our name */
free(self->tp_name);
/* And we allocated our own protocol structures */
if (self->tp_as_number) free(self->tp_as_number);
if (self->tp_as_sequence) free(self->tp_as_sequence);
if (self->tp_as_mapping) free(self->tp_as_mapping);
Py_DECREF(self->bases);
}
if (((PyExtensionClass*)self->ob_type) != self) {
Py_XDECREF(self->ob_type);
}
PyObject_DEL(self);
}
static PyObject *
ExtensionClass_FindInstanceAttribute(PyObject *inst, PyObject *oname,
char *name)
{
/* Look up an attribute for an instance from:
The instance dictionary,
The class dictionary, or
The base objects.
*/
PyObject *r=0;
PyExtensionClass *self;
if (! name) return NULL;
self=(PyExtensionClass*)(inst->ob_type);
if (*name=='_' && name[1]=='_')
{
char *n=name+2;
if (*n == 'c' && strcmp(n,"class__")==0)
{
Py_INCREF(self);
return (PyObject*)self;
}
if (ClassHasInstDict(self) && *n=='d' && strcmp(n,"dict__")==0)
{
r = INSTANCE_DICT(inst);
Py_INCREF(r);
return r;
}
}
if (ClassHasInstDict(self))
{
r= INSTANCE_DICT(inst);
if (PyDict_Check(r))
{
r = PyDict_GetItem(r,oname);
Py_XINCREF(r);
}
else
{
UNLESS (r = PyObject_GetItem(r,oname))
PyErr_Clear();
}
if (r)
{
if (NeedsToBeBound(r))
{
ASSIGN(r, CallMethodO(r, py__of__, Build("(O)", inst), NULL));
}
return r;
}
}
if (*name=='_' && name[1]=='_'
&&
( (name[2]=='b' && strcmp(name+2,"bases__")==0)
|| (name[2]=='d' && strcmp(name+2,"dict__")==0)
)
)
{
PyErr_SetObject(PyExc_AttributeError, oname);
return NULL;
}
UNLESS(r=CCL_getattr(self,oname,0)) return NULL;
/* We got something from our class, maybe its an unbound method. */
if (UnboundCMethod_Check(r))
ASSIGN(r,(PyObject*)bindCMethod((CMethod*)r,inst));
else if (UnboundPMethod_Check(r))
ASSIGN(r,bindPMethod((PMethod*)r,inst));
return r;
}
static PyObject *
EC_findiattrs(PyObject *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_getattr2(PyObject *self, PyObject *oname, int look_super)
{
PyObject *r=0, *b, *d;
if (ExtensionClass_Check(self))
{
b=((PyExtensionClass*)self)->bases;
d=((PyExtensionClass*)self)->class_dictionary;
}
else if (PyClass_Check(self))
{
b=((PyClassObject*)self)->cl_bases;
d=((PyClassObject*)self)->cl_dict;
}
else
{
UNLESS (r=PyObject_GetAttr(self, oname)) PyErr_Clear();
return r;
}
if (! look_super && d)
{
if (PyDict_Check(d))
{
if((r=PyDict_GetItem(d, oname)))
{
Py_INCREF(r);
return r;
}
}
else
{
if((r=PyObject_GetItem(d, oname))) return r;
PyErr_Clear();
}
}
if (b)
{
int n, i;
n = PyTuple_Check(b) ? PyTuple_GET_SIZE(b) : 0; /* I don't care ;) */
for (i=0; i < n; i++)
{
r=CCL_getattr2(PyTuple_GET_ITEM(b, i), oname, 0);
if (r) return r;
}
}
return NULL;
}
static PyObject *
CCL_getattr(PyExtensionClass *self, PyObject *oname, int look_super)
{
PyObject *r=0;
UNLESS (r=CCL_getattr2(OBJECT(self), oname, look_super))
{
PyErr_SetObject(PyExc_AttributeError, oname);
return NULL;
}
if (PyFunction_Check(r) || NeedsToBeBound(r))
ASSIGN(r,newPMethod(self,r));
else if (PyMethod_Check(r) && ! PyMethod_Self(r))
ASSIGN(r,newPMethod(self, PyMethod_Function(r)));
return r;
}
static PyObject *
CCL_reduce(PyExtensionClass *self, PyObject *args)
{
return PyString_FromString(self->tp_name);
}
PyObject *
CCL_getattro(PyExtensionClass *self, PyObject *name)
{
char *n, *nm=0;
PyObject *r;
if (PyString_Check(name) && (n=nm=PyString_AS_STRING((PyStringObject*)name)))
{
if (*n=='_' && *++n=='_')
{
switch (*++n)
{
case 's':
if (strcmp(n,"safe_for_unpickling__")==0)
return PyInt_FromLong(1);
break;
case 'n':
if (strcmp(n,"name__")==0)
return PyString_FromString(self->tp_name);
break;
case 'b':
if (strcmp(n,"bases__")==0)
{
if (self->bases)
{
Py_INCREF(self->bases);
return self->bases;
}
else
return PyTuple_New(0);
}
break;
case 'r':
if (strcmp(n,"reduce__")==0)
return newCMethod(self,(PyObject*)self,
"__reduce__",(PyCFunction)CCL_reduce,0,
"__reduce__() -- Reduce the class to a class name");
break;
case 'd':
if (strcmp(n,"dict__")==0)
{
Py_INCREF(self->class_dictionary);
return self->class_dictionary;
}
break;
case 'c':
if (strcmp(n,"class__")==0)
{
Py_INCREF(self->ob_type);
return OBJECT(self->ob_type);
}
break;
}
}
}
if ((r=CCL_getattr(self,name,0)))
{
if (UnboundCMethod_Check(r) && (AsCMethod(r)->flags & METH_CLASS_METHOD))
ASSIGN(r,(PyObject*)bindCMethod((CMethod*)r,OBJECT(self)));
}
return r;
}
static int
CCL_setattro(PyExtensionClass *self, PyObject *name, PyObject *v)
{
if (! v) return PyObject_DelItem(self->class_dictionary, name);
if (v && UnboundCMethod_Check(v) &&
! (self->class_flags & EXTENSIONCLASS_METHODHOOK_FLAG)
)
{
char *n;
PyNumberMethods *nm;
PySequenceMethods *s, *ms;
PyMappingMethods *m, *mm;
UNLESS(n=PyString_AsString(name)) return -1;
if (*n++=='_' && *n++=='_')
{
#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==(PyCFunction)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==(PyCFunction)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==(PyCFunction)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 *
CCL_call(PyExtensionClass *self, PyObject *arg, PyObject *kw)
{
PyObject *inst=0, *init=0, *args=0;
int size = 0;
if (! self->tp_dealloc)
{
PyErr_SetString(PyExc_TypeError,
"Attempt to create instance of an abstract type");
return NULL;
}
if (self->tp_itemsize)
{
/* We have a variable-sized object, we need to get it's size */
PyObject *var_size;
if ((var_size=CCL_getattr(self,py__var_size__, 0)))
{
UNLESS_ASSIGN(var_size,PyObject_CallObject(var_size,arg))
return NULL;
size=PyInt_AsLong(var_size);
if (PyErr_Occurred()) return NULL;
}
else
{
UNLESS(-1 != (size=PyTuple_Size(arg))) return NULL;
if (size > 0)
{
var_size=PyTuple_GET_ITEM(arg, 0);
if (PyInt_Check(var_size))
size=PyInt_AsLong(var_size);
else
size=-1;
}
else
size=-1;
if (size < 0)
{
PyErr_SetString(PyExc_TypeError,
"object size expected as first argument");
return NULL;
}
}
}
UNLESS(inst=EC_NewObject((PyTypeObject *)self, size)) return NULL;
if (ClassHasInstDict(self))
UNLESS(INSTANCE_DICT(inst)=PyDict_New()) goto err;
if ((init=CCL_getattr(self,py__init__,0)))
{
UNLESS(args=Py_BuildValue("(O)",inst)) goto err;
if (arg) UNLESS_ASSIGN(args,PySequence_Concat(args,arg)) goto err;
UNLESS_ASSIGN(args,PyEval_CallObjectWithKeywords(init,args,kw)) goto err;
Py_DECREF(args);
Py_DECREF(init);
}
else PyErr_Clear();
if (self->bases && subclass_watcher &&
! PyObject_CallMethod(subclass_watcher,"created","O",inst))
PyErr_Clear();
return inst;
err:
Py_DECREF(inst);
Py_XDECREF(init);
Py_XDECREF(args);
return NULL;
}
static PyObject *
CCL_repr(PyExtensionClass *self)
{
char p[128], *pp;
PyObject *m;
if ((m=PyObject_GetAttr(OBJECT(self), py__module__)))
{
if (! PyObject_IsTrue(m))
{
Py_DECREF(m);
m=0;
}
}
else PyErr_Clear();
sprintf(p,"%p",self);
if (*p=='0' && p[1]=='x') pp=p+2;
else pp=p;
if (m) ASSIGN(m, JimString_Build("<extension class %s.%s at %s>","Oss",
m, self->tp_name, pp));
else m= JimString_Build("<extension class %s at %s>","ss",
self->tp_name, pp);
return m;
}
static PyTypeObject ECTypeType = {
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
"ExtensionClass Class", /*tp_name*/
sizeof(PyExtensionClass), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
(destructor)CCL_dealloc, /*tp_dealloc*/
(printfunc)0, /*tp_print*/
(getattrfunc)0, /*tp_getattr*/
(setattrfunc)0, /*tp_setattr*/
(cmpfunc)0, /*tp_compare*/
(reprfunc)CCL_repr, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
(hashfunc)0, /*tp_hash*/
(ternaryfunc)CCL_call, /*tp_call*/
(reprfunc)0, /*tp_str*/
(getattrofunc)CCL_getattro, /*tp_getattr with object key*/
(setattrofunc)CCL_setattro, /*tp_setattr with object key*/
/* Space for future expansion */
0L,0L,
"Class of C classes" /* Documentation string */
};
/* End of code for ExtensionClass objects */
/* -------------------------------------------------------- */
/* subclassing code: */
static PyObject *
subclass_getspecial(PyObject *inst, PyObject *oname)
{
PyObject *r=0;
PyExtensionClass *self;
self=(PyExtensionClass*)(inst->ob_type);
if (HasInstDict(inst))
{
r= INSTANCE_DICT(inst);
if (PyDict_Check(r))
{
if ((r = PyDict_GetItem(r,oname)))
Py_INCREF(r);
else
r=CCL_getattr(self,oname,0);
}
else
{
UNLESS (r = PyObject_GetItem(r,oname))
{
PyErr_Clear();
r=CCL_getattr(self,oname,0);
}
}
}
else
r=CCL_getattr(self,oname,0);
return r;
}
static PyObject *
subclass_getattro(PyObject *self, PyObject *name)
{
PyObject *r;
if (! name) return NULL;
UNLESS(r=EC_findiattro(self,name))
{
PyErr_Clear();
r=EC_findiattro(self,py__getattr__);
if (r) ASSIGN(r,PyObject_CallFunction(r,"O",name));
if (r && NeedsToBeBound(r))
ASSIGN(r, CallMethodO(r, py__of__, Build("(O)", self), NULL));
}
return r;
}
static int
subclass_simple_setattro(PyObject *self, PyObject *name, PyObject *v)
{
if (! HasInstDict(self))
{
PyErr_SetObject(PyExc_AttributeError, name);
return -1;
}
if (v)
return PyDict_SetItem(INSTANCE_DICT(self),name,v);
else
return PyDict_DelItem(INSTANCE_DICT(self),name);
}
static int
subclass_simple_setattr(PyObject *self, char *name, PyObject *v)
{
if (! HasInstDict(self))
{
PyErr_SetString(PyExc_AttributeError, name);
return -1;
}
if (v)
return PyDict_SetItemString(INSTANCE_DICT(self),name,v);
else
return PyDict_DelItemString(INSTANCE_DICT(self),name);
}
static int
subclass_setattr(PyObject *self, PyObject *oname, char *name, PyObject *v)
{
PyObject *m=0, *et, *ev, *etb;
if (! name) return -1;
if (!v && (m=subclass_getspecial(self,py__delattr__)))
{
if (UnboundEMethod_Check(m))
{
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"OO",self,oname)) return -1;
}
else UNLESS_ASSIGN(m,PyObject_CallFunction(m,"O",oname)) return -1;
Py_DECREF(m);
return 0;
}
UNLESS(m=subclass_getspecial(self,py__setattr__))
goto default_setattr;
if (UnboundCMethod_Check(m)
&& AsCMethod(m)->meth==(PyCFunction)setattr_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type))
{
UNLESS(-1 != AsCMethod(m)->type->tp_setattr(self,name,v))
goto dictionary_setattr;
return 0;
}
else
if (UnboundCMethod_Check(m)
&& AsCMethod(m)->meth==(PyCFunction)setattro_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type))
{
UNLESS(-1 != AsCMethod(m)->type->tp_setattro(self,oname,v))
goto dictionary_setattr;
return 0;
}
if (! v) goto default_setattr;
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);
return 0;
dictionary_setattr:
Py_XDECREF(m);
PyErr_Fetch(&et, &ev, &etb);
if (et==PyExc_AttributeError)
{
char *s;
if (ev && PyString_Check(ev) && (s=PyString_AsString(ev)) &&
strcmp(s,name)==0)
{
Py_XDECREF(et);
Py_XDECREF(ev);
Py_XDECREF(etb);
et=0;
}
}
if (et)
{
PyErr_Restore(et,ev,etb);
return -1;
}
default_setattr:
PyErr_Clear();
return subclass_simple_setattro(self, oname, v);
}
static int
subclass_setattro(PyObject *self, PyObject *name, PyObject *v)
{
return subclass_setattr(self,name,PyString_AsString(name),v);
}
static int
subclass_compare(PyObject *self, PyObject *v)
{
PyObject *m;
long r;
UNLESS(m=subclass_getspecial(self,py__cmp__))
{
PyErr_Clear();
return self < v ? -1 : (self != v);
}
if (UnboundCMethod_Check(m)
&& AsCMethod(m)->meth==(PyCFunction)compare_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type)
&& ! HasMethodHook(self))
r=AsCMethod(m)->type->tp_compare(self,v);
else
{
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);
}
Py_DECREF(m);
return r;
}
static long
subclass_hash(PyObject *self)
{
PyObject *m;
long r;
UNLESS(m=subclass_getspecial(self,py__hash__)) return -1;
if (UnboundCMethod_Check(m)
&& AsCMethod(m)->meth==(PyCFunction)hash_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type)
&& ! HasMethodHook(self))
r=AsCMethod(m)->type->tp_hash(self);
else
{
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);
}
Py_DECREF(m);
return r;
}
static PyObject *
default_subclass_repr(PyObject *self)
{
char p[128], *pp;
PyErr_Clear();
sprintf(p,"%p",self);
if (*p=='0' && p[1]=='x') pp=p+2;
else pp=p;
return JimString_Build("<%s instance at %s>","ss",
self->ob_type->tp_name, pp);
}
static PyObject *
subclass_repr(PyObject *self)
{
PyObject *m;
UNLESS(m=subclass_getspecial(self,py__repr__))
return default_subclass_repr(self);
if (UnboundCMethod_Check(m)
&& AsCMethod(m)->meth==(PyCFunction)repr_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type)
&& ! HasMethodHook(self))
ASSIGN(m,AsCMethod(m)->type->tp_repr(self));
else if (UnboundEMethod_Check(m))
ASSIGN(m,PyObject_CallFunction(m,"O",self));
else
ASSIGN(m,PyObject_CallFunction(m,""));
return m;
}
static PyObject *
subclass_call(PyObject *self, PyObject *args, PyObject *kw)
{
PyObject *m;
UNLESS(m=subclass_getspecial(self,py__call__)) return NULL;
if (UnboundCMethod_Check(m) && AsCMethod(m)->meth==(PyCFunction)call_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type)
&& ! HasMethodHook(self))
ASSIGN(m,AsCMethod(m)->type->tp_call(self,args,kw));
else
{
if (UnboundEMethod_Check(m))
{
PyObject *a;
a=Py_BuildValue("(O)",self);
if (a) ASSIGN(a,PySequence_Concat(a,args));
if (a) ASSIGN(m,PyEval_CallObjectWithKeywords(m,a,kw));
else ASSIGN(m,NULL);
Py_XDECREF(a);
}
else
ASSIGN(m,PyEval_CallObjectWithKeywords(m,args,kw));
}
return m;
}
static PyObject *
subclass_str(PyObject *self)
{
PyObject *m;
UNLESS(m=subclass_getspecial(self,py__str__))
{
PyErr_Clear();
return subclass_repr(self);
}
if (UnboundCMethod_Check(m)
&& AsCMethod(m)->meth==(PyCFunction)str_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type)
&& ! HasMethodHook(self))
ASSIGN(m,AsCMethod(m)->type->tp_str(self));
else if (UnboundEMethod_Check(m))
ASSIGN(m,PyObject_CallFunction(m,"O",self));
else
ASSIGN(m,PyObject_CallFunction(m,""));
return m;
}
#define BINSUB(M,N,A) \
static PyObject * \
subclass_ ## M(PyObject *self, PyObject *v) \
{ \
PyObject *m; \
UNLESS(m=subclass_getspecial(self,py__ ## N ## __)) return NULL; \
if (UnboundCMethod_Check(m) \
&& AsCMethod(m)->meth==(PyCFunction)M ## _by_name \
&& SubclassInstance_Check(self,AsCMethod(m)->type) \
&& ! HasMethodHook(self)) \
ASSIGN(m,AsCMethod(m)->type->tp_as_number->nb_ ## M(self,v)); \
else if (UnboundEMethod_Check(m)) \
ASSIGN(m,PyObject_CallFunction(m,"OO",self,v)); \
else \
ASSIGN(m,PyObject_CallFunction(m,"O",v)); \
return m; \
}
static PyObject *
subclass_add(PyObject *self, PyObject *v)
{
PyObject *m;
UNLESS(m=subclass_getspecial(self,py__add__)) return NULL;
if (UnboundCMethod_Check(m)
&& AsCMethod(m)->meth==(PyCFunction)concat_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type)
&& ! HasMethodHook(self))
ASSIGN(m,AsCMethod(m)->type->tp_as_sequence->sq_concat(self,v));
else if (UnboundCMethod_Check(m)
&& AsCMethod(m)->meth==(PyCFunction)add_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type)
&& ! HasMethodHook(self))
ASSIGN(m,AsCMethod(m)->type->tp_as_number->nb_add(self,v));
else if (UnboundEMethod_Check(m))
ASSIGN(m,PyObject_CallFunction(m,"OO",self,v));
else
ASSIGN(m,PyObject_CallFunction(m,"O",v));
return m;
}
BINSUB(subtract,sub,Subtract)
static PyObject *
subclass_multiply(PyObject *self, PyObject *v)
{
PyObject *m;
UNLESS(m=subclass_getspecial(self,py__mul__)) return NULL;
if (UnboundCMethod_Check(m)
&& AsCMethod(m)->meth==(PyCFunction)repeat_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type)
&& ! HasMethodHook(self))
{
int i;
i=PyInt_AsLong(v);
if (i==-1 && PyErr_Occurred()) return NULL;
ASSIGN(m,AsCMethod(m)->type->tp_as_sequence->sq_repeat(self,i));
}
else if (UnboundCMethod_Check(m)
&& AsCMethod(m)->meth==(PyCFunction)multiply_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type)
&& ! HasMethodHook(self))
ASSIGN(m,AsCMethod(m)->type->tp_as_number->nb_multiply(self,v));
else if (UnboundEMethod_Check(m))
ASSIGN(m,PyObject_CallFunction(m,"OO",self,v));
else
ASSIGN(m,PyObject_CallFunction(m,"O",v));
return m;
}
BINSUB(divide,div,Divide)
BINSUB(remainder,mod,Remainder)
static PyObject *
subclass_power(PyObject *self, PyObject *v, PyObject *w)
{
PyObject *m;
UNLESS(m=subclass_getspecial(self,py__pow__)) return NULL;
if (UnboundCMethod_Check(m)
&& AsCMethod(m)->meth==(PyCFunction)power_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type)
&& ! HasMethodHook(self))
ASSIGN(m,AsCMethod(m)->type->tp_as_number->nb_power(self,v,w));
else if (UnboundEMethod_Check(m))
ASSIGN(m,PyObject_CallFunction(m,"OOO",self,v,w));
else
ASSIGN(m,PyObject_CallFunction(m,"OO",v,w));
return m;
}
BINSUB(divmod,divmod,Divmod)
BINSUB(lshift,lshift,Lshift)
BINSUB(rshift,rshift,Rshift)
BINSUB(and,and,And)
BINSUB(or,or,Or)
BINSUB(xor,xor,Xor)
static int
subclass_coerce(PyObject **self, PyObject **v)
{
PyObject *m;
int r;
UNLESS(m=subclass_getspecial(*self,py__coerce__))
{
PyErr_Clear();
Py_INCREF(*self);
Py_INCREF(*v);
return 0;
}
if (UnboundCMethod_Check(m)
&& AsCMethod(m)->meth==(PyCFunction)coerce_by_name
&& SubclassInstance_Check(*self,AsCMethod(m)->type)
&& ! HasMethodHook(*self))
r=AsCMethod(m)->type->tp_as_number->nb_coerce(self,v);
else
{
if (UnboundEMethod_Check(m))
ASSIGN(m,PyObject_CallFunction(m,"OO",*self,*v));
else
ASSIGN(m,PyObject_CallFunction(m,"O",*v));
UNLESS (m) return -1;
if (m==Py_None) r=-1;
else
{
if (PyArg_ParseTuple(m,"OO", self, v))
{
Py_INCREF(*self);
Py_INCREF(*v);
r=0;
}
else r=-1;
}
}
Py_DECREF(m);
return r;
}
#define UNSUB(M,N) \
static PyObject * \
subclass_ ## M(PyObject *self) \
{ \
PyObject *m; \
UNLESS(m=subclass_getspecial(self,py__ ## N ## __)) return NULL; \
if (UnboundCMethod_Check(m) \
&& AsCMethod(m)->meth==(PyCFunction)M ## _by_name \
&& SubclassInstance_Check(self,AsCMethod(m)->type) \
&& ! HasMethodHook(self)) \
ASSIGN(m,AsCMethod(m)->type->tp_as_number->nb_ ## M(self)); \
else if (UnboundEMethod_Check(m)) \
ASSIGN(m,PyObject_CallFunction(m,"O",self)); \
else \
ASSIGN(m,PyObject_CallFunction(m,"")); \
return m; \
}
UNSUB(negative, neg)
UNSUB(positive, pos)
UNSUB(absolute, abs)
static int
subclass_nonzero(PyObject *self)
{
PyObject *m;
long r;
UNLESS(m=subclass_getspecial(self,py__nonzero__))
{ /* We are being asked is we are true
Check out len, and if that fails, say we are true.
*/
PyErr_Clear();
UNLESS(m=subclass_getspecial(self,py__len__))
{
PyErr_Clear();
return 1;
}
}
if (UnboundCMethod_Check(m)
&& AsCMethod(m)->meth==(PyCFunction)nonzero_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type)
&& ! HasMethodHook(self))
r=AsCMethod(m)->type->tp_as_number->nb_nonzero(self);
else
{
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);
}
Py_DECREF(m);
return r;
}
UNSUB(invert, inv)
UNSUB(int, int)
UNSUB(long, long)
UNSUB(float, float)
UNSUB(oct, oct)
UNSUB(hex, hex)
#undef UNSUB
#undef BINSUB
static PyNumberMethods subclass_as_number = {
(binaryfunc)subclass_add, /*nb_add*/
(binaryfunc)subclass_subtract, /*nb_subtract*/
(binaryfunc)subclass_multiply, /*nb_multiply*/
(binaryfunc)subclass_divide, /*nb_divide*/
(binaryfunc)subclass_remainder, /*nb_remainder*/
(binaryfunc)subclass_divmod, /*nb_divmod*/
(ternaryfunc)subclass_power, /*nb_power*/
(unaryfunc)subclass_negative, /*nb_negative*/
(unaryfunc)subclass_positive, /*nb_positive*/
(unaryfunc)subclass_absolute, /*nb_absolute*/
(inquiry)subclass_nonzero, /*nb_nonzero*/
(unaryfunc)subclass_invert, /*nb_invert*/
(binaryfunc)subclass_lshift, /*nb_lshift*/
(binaryfunc)subclass_rshift, /*nb_rshift*/
(binaryfunc)subclass_and, /*nb_and*/
(binaryfunc)subclass_xor, /*nb_xor*/
(binaryfunc)subclass_or, /*nb_or*/
(coercion)subclass_coerce, /*nb_coerce*/
(unaryfunc)subclass_int, /*nb_int*/
(unaryfunc)subclass_long, /*nb_long*/
(unaryfunc)subclass_float, /*nb_float*/
(unaryfunc)subclass_oct, /*nb_oct*/
(unaryfunc)subclass_hex, /*nb_hex*/
};
static long
subclass_length(PyObject *self)
{
PyObject *m;
long r;
PyExtensionClass *t;
UNLESS(m=subclass_getspecial(self,py__len__))
{
/* Hm. Maybe we are being checked to see if we are true.
Check to see if we have a __getitem__. If we don't, then
answer that we are true.
*/
PyErr_Clear();
if ((m=subclass_getspecial(self,py__getitem__)))
{
/* Hm, we have getitem, must be error */
Py_DECREF(m);
PyErr_SetObject(PyExc_AttributeError, py__len__);
return -1;
}
PyErr_Clear();
return subclass_nonzero(self);
}
if (UnboundCMethod_Check(m)
&& AsCMethod(m)->meth==(PyCFunction)length_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type)
&& ! HasMethodHook(self))
{
t=(PyExtensionClass*)AsCMethod(m)->type;
Py_DECREF(m);
if (t->tp_as_sequence)
return t->tp_as_sequence->sq_length(self);
else
return t->tp_as_mapping->mp_length(self);
}
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);
Py_DECREF(m);
return r;
}
static PyObject *
subclass_item(PyObject *self, int index)
{
PyObject *m;
PyExtensionClass *t;
UNLESS(m=subclass_getspecial(self,py__getitem__)) return NULL;
if (UnboundCMethod_Check(m)
&& AsCMethod(m)->meth==(PyCFunction)getitem_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type)
&& ! HasMethodHook(self))
{
t=(PyExtensionClass*)AsCMethod(m)->type;
if (t->tp_as_sequence && t->tp_as_sequence->sq_item)
{
Py_DECREF(m);
return t->tp_as_sequence->sq_item(self,index);
}
}
if (UnboundEMethod_Check(m))
ASSIGN(m,PyObject_CallFunction(m,"Oi",self,index));
else
ASSIGN(m,PyObject_CallFunction(m,"i",index));
return m;
}
static PyObject *
subclass_slice(PyObject *self, int i1, int i2)
{
PyObject *m;
UNLESS(m=subclass_getspecial(self,py__getslice__)) return NULL;
if (UnboundCMethod_Check(m)
&& AsCMethod(m)->meth==(PyCFunction)slice_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type)
&& ! HasMethodHook(self))
ASSIGN(m,AsCMethod(m)->type->tp_as_sequence->sq_slice(self,i1,i2));
else if (UnboundEMethod_Check(m))
ASSIGN(m,PyObject_CallFunction(m,"Oii",self,i1,i2));
else
ASSIGN(m,PyObject_CallFunction(m,"ii",i1,i2));
return m;
}
static long
subclass_ass_item(PyObject *self, int index, PyObject *v)
{
PyObject *m;
PyExtensionClass *t;
if (! v && (m=subclass_getspecial(self,py__delitem__)))
{
if (UnboundEMethod_Check(m))
{
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"Oi",self,index)) return -1;
}
else UNLESS_ASSIGN(m,PyObject_CallFunction(m,"i",index)) return -1;
Py_DECREF(m);
return 0;
}
UNLESS(m=subclass_getspecial(self,py__setitem__)) return -1;
if (UnboundCMethod_Check(m) &&
AsCMethod(m)->meth==(PyCFunction)setitem_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type)
&& ! HasMethodHook(self))
{
t=(PyExtensionClass*)AsCMethod(m)->type;
if (t->tp_as_sequence && t->tp_as_sequence->sq_ass_item)
{
Py_DECREF(m);
return t->tp_as_sequence->sq_ass_item(self,index,v);
}
}
if (! v)
{
PyErr_SetObject(PyExc_AttributeError, py__delitem__);
return -1;
}
if (UnboundEMethod_Check(m))
{
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"OiO",self,index,v)) return -1;
}
else UNLESS_ASSIGN(m,PyObject_CallFunction(m,"iO",index,v)) return -1;
Py_DECREF(m);
return 0;
}
static int
subclass_ass_slice(PyObject *self, int i1, int i2, PyObject *v)
{
PyObject *m;
long r;
if (! v && (m=subclass_getspecial(self,py__delslice__)))
{
if (UnboundEMethod_Check(m))
{
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"Oii",self,i1,i2)) return -1;
}
else UNLESS_ASSIGN(m,PyObject_CallFunction(m,"ii",i1,i2)) return -1;
Py_DECREF(m);
return 0;
}
UNLESS(m=subclass_getspecial(self,py__setslice__)) return -1;
if (UnboundCMethod_Check(m) &&
AsCMethod(m)->meth==(PyCFunction)ass_slice_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type)
&& ! HasMethodHook(self))
{
r=AsCMethod(m)->type->tp_as_sequence->sq_ass_slice(self,i1,i2,v);
Py_DECREF(m);
return r;
}
if (! v)
{
PyErr_SetObject(PyExc_AttributeError, py__delslice__);
return -1;
}
if (UnboundEMethod_Check(m))
{
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"OiiO",self,i1,i2,v))
return -1;
}
else UNLESS_ASSIGN(m,PyObject_CallFunction(m,"iiO",i1,i2,v)) return -1;
Py_DECREF(m);
return 0;
}
static PyObject *
subclass_repeat(PyObject *self, int v)
{
PyObject *m;
UNLESS(m=subclass_getspecial(self,py__mul__)) return NULL;
if (UnboundCMethod_Check(m)
&& AsCMethod(m)->meth==(PyCFunction)repeat_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type)
&& ! HasMethodHook(self))
ASSIGN(m,AsCMethod(m)->type->tp_as_sequence->sq_repeat(self,v));
else if (UnboundEMethod_Check(m))
ASSIGN(m,PyObject_CallFunction(m,"Oi",self,v));
else
ASSIGN(m,PyObject_CallFunction(m,"i",v));
return m;
}
PySequenceMethods subclass_as_sequence = {
(inquiry)subclass_length, /*sq_length*/
(binaryfunc)subclass_add, /*sq_concat*/
(intargfunc)subclass_repeat, /*sq_repeat*/
(intargfunc)subclass_item, /*sq_item*/
(intintargfunc)subclass_slice, /*sq_slice*/
(intobjargproc)subclass_ass_item, /*sq_ass_item*/
(intintobjargproc)subclass_ass_slice, /*sq_ass_slice*/
};
static PyObject *
subclass_subscript(PyObject *self, PyObject *key)
{
PyObject *m;
PyExtensionClass *t;
UNLESS(m=subclass_getspecial(self,py__getitem__)) return NULL;
if (UnboundCMethod_Check(m) &&
AsCMethod(m)->meth==(PyCFunction)getitem_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type)
&& ! HasMethodHook(self))
{
t=(PyExtensionClass*)AsCMethod(m)->type;
if (t->tp_as_mapping && t->tp_as_mapping->mp_subscript)
{
Py_DECREF(m);
return t->tp_as_mapping->mp_subscript(self,key);
}
else if (t->tp_as_sequence && t->tp_as_sequence->sq_item)
{
int i, l;
Py_DECREF(m);
UNLESS(PyInt_Check(key))
{
PyErr_SetString(PyExc_TypeError, "sequence subscript not int");
return NULL;
}
i=PyInt_AsLong(key);
if (i < 0)
{
if ((l=PyObject_Length(self)) < 0) return NULL;
i+=l;
}
return t->tp_as_sequence->sq_item(self,i);
}
}
if (UnboundEMethod_Check(m))
ASSIGN(m,PyObject_CallFunction(m,"OO",self,key));
else
ASSIGN(m,PyObject_CallFunction(m,"O",key));
return m;
}
static long
subclass_ass_subscript(PyObject *self, PyObject *index, PyObject *v)
{
PyObject *m;
PyExtensionClass *t;
if (! v && (m=subclass_getspecial(self,py__delitem__)))
{
if (UnboundEMethod_Check(m))
{
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"OO",self,index)) return -1;
}
else UNLESS_ASSIGN(m,PyObject_CallFunction(m,"O",index)) return -1;
Py_DECREF(m);
return 0;
}
UNLESS(m=subclass_getspecial(self,py__setitem__)) return -1;
if (UnboundCMethod_Check(m) &&
AsCMethod(m)->meth==(PyCFunction)setitem_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type)
&& ! HasMethodHook(self))
{
t=(PyExtensionClass*)AsCMethod(m)->type;
if (t->tp_as_mapping && t->tp_as_mapping->mp_ass_subscript)
{
Py_DECREF(m);
return t->tp_as_mapping->mp_ass_subscript(self,index,v);
}
else if (t->tp_as_sequence && t->tp_as_sequence->sq_ass_item)
{
int i, l;
Py_DECREF(m);
UNLESS(PyInt_Check(index))
{
PyErr_SetString(PyExc_TypeError, "sequence subscript not int");
return -1;
}
i=PyInt_AsLong(index);
if (i < 0)
{
if ((l=PyObject_Length(self)) < 0) return -1;
i+=l;
}
return t->tp_as_sequence->sq_ass_item(self,i,v);
}
}
if (! v)
{
PyErr_SetObject(PyExc_AttributeError, py__delitem__);
return -1;
}
if (UnboundEMethod_Check(m))
{
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"OOO",self,index,v)) return -1;
}
else UNLESS_ASSIGN(m,PyObject_CallFunction(m,"OO",index,v)) return -1;
Py_DECREF(m);
return 0;
}
PyMappingMethods subclass_as_mapping = {
(inquiry)subclass_length, /*mp_length*/
(binaryfunc)subclass_subscript, /*mp_subscript*/
(objobjargproc)subclass_ass_subscript, /*mp_ass_subscript*/
};
static int
dealloc_base(PyObject *inst, PyExtensionClass* self)
{
int i,l;
PyObject *t;
l=PyTuple_Size(self->bases);
for (i=0; i < l; i++)
{
t=PyTuple_GET_ITEM(self->bases, i);
if (ExtensionClass_Check(t))
{
if (AsExtensionClass(t)->bases)
{
if (dealloc_base(inst,AsExtensionClass(t))) return 1;
}
else
{
if (((PyExtensionClass*)t)->tp_dealloc)
{
((PyExtensionClass*)t)->tp_dealloc(inst);
return 1;
}
}
}
}
return 0;
}
static void
subclass_dealloc(PyObject *self)
{
PyObject *m, *t, *v, *tb;
int base_dealloced;
#ifdef TRACE_DEALLOC
fprintf(stderr,"Deallocating a %s\n", self->ob_type->tp_name);
#endif
PyErr_Fetch(&t,&v,&tb);
Py_INCREF(self); /* Give us a new lease on life */
if (subclass_watcher &&
! PyObject_CallMethod(subclass_watcher,"destroying","O",self))
PyErr_Clear();
if ((m=subclass_getspecial(self,py__del__)))
{
if (UnboundEMethod_Check(m))
ASSIGN(m,PyObject_CallFunction(m,"O",self));
else
ASSIGN(m,PyObject_CallFunction(m,""));
Py_XDECREF(m);
}
PyErr_Clear();
if (--self->ob_refcnt > 0)
{
PyErr_Restore(t,v,tb);
return; /* we added a reference; don't delete now */
}
if (HasInstDict(self)) {
Py_XDECREF(INSTANCE_DICT(self));
}
/* See if there was a dealloc handler in a (C) base class.
If there was, then it deallocates the object and we
get a true value back.
Note that if there *is* a base class dealloc, then
*it* should decref the class.
*/
base_dealloced=dealloc_base(self,(PyExtensionClass*)self->ob_type);
/* We only deallocate ourselves if a base class didn't */
UNLESS(base_dealloced)
{
Py_DECREF(self->ob_type);
PyObject_DEL(self);
}
PyErr_Restore(t,v,tb);
}
static void
datafull_baseclassesf(PyExtensionClass *type, PyObject **c1, PyObject **c2)
{
/* Find the number of classes that have data and return them.
There should be no more than one.
*/
int l, i;
PyObject *base;
l=PyTuple_Size(type->bases);
for (i=0; i < l && ! (*c1 && *c2); i++)
{
base=PyTuple_GET_ITEM(type->bases, i);
if (ExtensionClass_Check(base))
{
if (AsExtensionClass(base)->bases)
datafull_baseclassesf(AsExtensionClass(base),c1,c2);
else
{
if (AsExtensionClass(base)->tp_basicsize >
sizeof(PyPureMixinObject) ||
AsExtensionClass(base)->tp_itemsize > 0)
{
if (! *c1)
*c1=base;
else if (*c1 != base)
*c2=base;
}
}
}
}
}
static int
datafull_baseclasses(PyExtensionClass *type)
{
PyObject *c1=0, *c2=0;
datafull_baseclassesf(type, &c1, &c2);
if (c2) return 2;
if (c1) return 1;
return 0;
}
static PyObject *
datafull_baseclass(PyExtensionClass *type)
{
/* Find the baseclass that has data and. There should be only one. */
int l, i;
PyObject *base, *dbase;
l=PyTuple_Size(type->bases);
for (i=0; i < l; i++)
{
base=PyTuple_GET_ITEM(type->bases, i);
if (ExtensionClass_Check(base))
{
if (AsExtensionClass(base)->bases)
{
if ((dbase=datafull_baseclass(AsExtensionClass(base))))
return dbase;
}
else
{
if (AsExtensionClass(base)->tp_basicsize >
sizeof(PyPureMixinObject) ||
AsExtensionClass(base)->tp_itemsize > 0)
return base;
}
}
}
return NULL;
}
static PyObject *
extension_baseclass(PyExtensionClass *type)
{
/* Find the first immediate base class that is an extension class */
int l, i;
PyObject *base;
l=PyTuple_Size(type->bases);
for (i=0; i < l; i++)
{
base=PyTuple_GET_ITEM(type->bases, i);
if (ExtensionClass_Check(base)) return base;
}
return JimErr_Format(PyExc_TypeError,
"No extension class found in subclass", NULL);
}
static int
subclass_hasattr(PyExtensionClass *type, PyObject *name)
{
PyObject *o;
if ((o=CCL_getattro(type,name)))
{
Py_DECREF(o);
return 1;
}
PyErr_Clear();
return 0;
}
static void
subclass_init_getattr(PyExtensionClass *self, PyObject *methods)
{
PyObject *m;
if ((m=CCL_getattr(self,py__getattr__,0)))
{
if (UnboundCMethod_Check(m)
&& AsCMethod(m)->meth==(PyCFunction)getattr_by_name
&& Subclass_Check(self,AsCMethod(m)->type))
{
self->tp_getattr=AsCMethod(m)->type->tp_getattr;
}
else if (UnboundCMethod_Check(m)
&& AsCMethod(m)->meth==(PyCFunction)getattro_by_name
&& Subclass_Check(self,AsCMethod(m)->type))
{
self->tp_getattro=AsCMethod(m)->type->tp_getattro;
}
else
{
PyObject_SetItem(methods,py__getattr__,m);
self->tp_getattro=subclass_getattro;
}
Py_DECREF(m);
}
else
{
PyErr_Clear();
self->tp_getattro=EC_findiattro;
}
}
static void
subclass_init_setattr(PyExtensionClass *self, PyObject *methods)
{
PyObject *m;
if ((m=CCL_getattr(self,py__setattr__,0)))
{
if (UnboundCMethod_Check(m)
&& AsCMethod(m)->meth==(PyCFunction)setattr_by_name
&& Subclass_Check(self,AsCMethod(m)->type))
{
self->tp_setattr=AsCMethod(m)->type->tp_setattr;
}
else if (UnboundCMethod_Check(m)
&& AsCMethod(m)->meth==(PyCFunction)setattro_by_name
&& Subclass_Check(self,AsCMethod(m)->type))
{
self->tp_setattro=AsCMethod(m)->type->tp_setattro;
}
else
{
PyObject_SetItem(methods,py__setattr__,m);
self->tp_setattro=subclass_setattro;
}
Py_DECREF(m);
}
else
{
PyErr_Clear();
self->tp_setattro=subclass_simple_setattro;
}
}
static PyObject *
CopyMethods(PyExtensionClass *type, PyObject *base_methods)
{
PyObject *methods, *key, *v;
int pos;
UNLESS(type->class_dictionary && PyDict_Check(base_methods) &&
ExtensionInstance_Check(type->class_dictionary))
{
Py_INCREF(base_methods);
return base_methods;
}
UNLESS(methods=
PyObject_CallObject((PyObject*)type->class_dictionary->ob_type, NULL))
return NULL;
for (pos=0; PyDict_Next(base_methods, &pos, &key, &v); )
UNLESS(0 <= PyObject_SetItem(methods,key,v)) goto err;
return methods;
err:
Py_DECREF(methods);
return NULL;
}
/* Constructor for building subclasses of C classes.
That is, we want to build a C class object that described a
subclass of a built-in type.
*/
static PyObject *
subclass__init__(PyExtensionClass *self, PyObject *args)
{
PyObject *bases, *methods, *class_init;
PyExtensionClass *type;
char *name, *p;
int l;
UNLESS(PyArg_ParseTuple(args,"sOO", &name, &bases, &methods)) return NULL;
l=strlen(name)+1;
UNLESS(p=(char*)malloc(l*sizeof(char))) return PyErr_NoMemory();
memcpy(p,name,l);
name=p;
UNLESS(PyTuple_Check(bases) && PyTuple_Size(bases))
{
PyErr_SetString
(PyExc_TypeError,
"second argument must be a tuple of 1 or more base classes");
}
self->bases=bases;
Py_INCREF(bases);
if (datafull_baseclasses(self) > 1)
{
PyErr_SetString(PyExc_TypeError, "too many datafull base classes");
return NULL;
}
UNLESS(type=(PyExtensionClass *)datafull_baseclass(self))
UNLESS(type=(PyExtensionClass *)extension_baseclass(self)) return NULL;
self->tp_name=name;
UNLESS(self->class_dictionary=CopyMethods(type,methods)) return NULL;
#define copy_member(M) self->M=type->M
copy_member(ob_size);
copy_member(class_flags);
copy_member(tp_itemsize);
copy_member(tp_print);
self->tp_dealloc=subclass_dealloc;
if (type->class_flags & EXTENSIONCLASS_PYTHONICATTR_FLAG)
{
/* The base class wants subclass __get/setattr__ to have
Python class semantics and *it* will be providing them.
That means that we simply copy the base class
get/setattr.
*/
copy_member(tp_getattr);
copy_member(tp_getattro);
copy_member(tp_setattr);
copy_member(tp_setattro);
self->class_flags |= EXTENSIONCLASS_PYTHONICATTR_FLAG;
if (CCL_hasattr(self, py__getattr__))
self->class_flags |= EXTENSIONCLASS_USERGETATTR_FLAG;
if (CCL_hasattr(self, py__setattr__))
self->class_flags |= EXTENSIONCLASS_USERSETATTR_FLAG;
if (CCL_hasattr(self, py__delattr__))
self->class_flags |= EXTENSIONCLASS_USERDELATTR_FLAG;
}
else
{
subclass_init_getattr(self, methods);
subclass_init_setattr(self, methods);
}
#define subclass_set(OP,N) \
self->tp_ ##OP = subclass_ ##OP
subclass_set(compare,cmp);
subclass_set(repr,repr);
if (subclass_hasattr(self,py__of__))
self->class_flags |= EXTENSIONCLASS_BINDABLE_FLAG;
if (subclass_hasattr(self,py__call_method__))
self->class_flags |= EXTENSIONCLASS_METHODHOOK_FLAG;
UNLESS(self->class_flags & EXTENSIONCLASS_NOINSTDICT_FLAG)
self->class_flags |= EXTENSIONCLASS_INSTDICT_FLAG;
if (type->bases || ! ClassHasInstDict(self))
copy_member(tp_basicsize);
else
{
self->tp_basicsize=type->tp_basicsize/sizeof(PyObject*)*sizeof(PyObject*);
if (self->tp_basicsize < type->tp_basicsize)
self->tp_basicsize += sizeof(PyObject*); /* To align on PyObject */
self->tp_basicsize += sizeof(PyObject*); /* For instance dictionary */
}
self->tp_as_number=(PyNumberMethods*)malloc(sizeof(PyNumberMethods));
UNLESS(self->tp_as_number) return PyErr_NoMemory();
*(self->tp_as_number)=subclass_as_number;
self->tp_as_sequence=
(PySequenceMethods*)malloc(sizeof(PySequenceMethods));
UNLESS(self->tp_as_sequence) return PyErr_NoMemory();
*(self->tp_as_sequence)=subclass_as_sequence;
self->tp_as_mapping=(PyMappingMethods*)malloc(sizeof(PyMappingMethods));
UNLESS(self->tp_as_mapping) return PyErr_NoMemory();
*(self->tp_as_mapping)=subclass_as_mapping;
subclass_set(hash,hash);
subclass_set(call,call);
subclass_set(str,str);
self->tp_doc=0;
/* Implement __module__=__name__ */
if (PyDict_GetItem(methods, py__module__) == NULL)
{
PyObject *globals = PyEval_GetGlobals();
if (globals != NULL)
{
PyObject *modname = PyDict_GetItem(globals, py__name__);
if (modname != NULL) {
if (PyDict_SetItem(methods, py__module__, modname) < 0)
return NULL;
}
}
}
/* 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);
return Py_None;
}
struct PyMethodDef ExtensionClass_methods[] = {
{"__init__",(PyCFunction)subclass__init__,1,""},
{NULL, NULL} /* sentinel */
};
static PyExtensionClass ECType = {
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
"ExtensionClass", /*tp_name*/
sizeof(PyExtensionClass), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
(destructor)CCL_dealloc, /*tp_dealloc*/
(printfunc)0, /*tp_print*/
(getattrfunc)0, /*tp_getattr*/
(setattrfunc)0, /*tp_setattr*/
(cmpfunc)0, /*tp_compare*/
(reprfunc)CCL_repr, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
(hashfunc)0, /*tp_hash*/
(ternaryfunc)CCL_call, /*tp_call*/
(reprfunc)0, /*tp_str*/
(getattrofunc)CCL_getattro, /*tp_getattr with object key*/
(setattrofunc)CCL_setattro, /*tp_setattr with object key*/
/* Space for future expansion */
0L,0L,
"C classes", /* Documentation string */
METHOD_CHAIN(ExtensionClass_methods)
};
/* List of methods defined in the module */
static PyObject *
set_subclass_watcher(PyObject *ignored, PyObject *args)
{
PyObject *old, *sw=0;
UNLESS(PyArg_ParseTuple(args,"|O",&sw)) return NULL;
old=subclass_watcher;
subclass_watcher=sw;
if (sw) Py_INCREF(sw);
if (old) return old;
Py_INCREF(Py_None);
return Py_None;
}
static struct PyMethodDef CC_methods[] = {
{"subclass_watcher", (PyCFunction)set_subclass_watcher, 1,
"subclass_watcher(ob) -- "
"Register an object to watch subclass instance events"
},
{NULL, NULL} /* sentinel */
};
static int
export_type(PyObject *dict, char *name, PyExtensionClass *typ)
{
initializeBaseExtensionClass(typ);
if (PyErr_Occurred()) return -1;
if (PyDict_GetItem(typ->class_dictionary, py__module__) == NULL)
{
PyObject *modname = PyDict_GetItem(dict, py__name__);
if (modname != NULL) {
if (PyDict_SetItem(typ->class_dictionary, py__module__, modname) < 0)
return -1;
}
}
PyErr_Clear();
return PyMapping_SetItemString(dict,name,(PyObject*)typ);
}
static struct ExtensionClassCAPIstruct
TrueExtensionClassCAPI = {
export_type, /* Export */
EC_findiattrs, /* getattrs */
EC_findiattro, /* getattro */
subclass_simple_setattr, /* setattrs */
subclass_simple_setattro, /* setattro */
(PyObject*)&ECType, /* ExtensionClassType */
(PyObject*)&PMethodType, /* MethodType */
PMethod_New, /* Method_New */
CMethod_issubclass, /* issubclass */
};
void
initExtensionClass(void)
{
PyObject *m, *d, *s;
PURE_MIXIN_CLASS(Base, "Minimalbase class for Extension Classes", NULL);
PMethodType.ob_type=&PyType_Type;
CMethodType.ob_type=&PyType_Type;
ECTypeType.ob_type=&PyType_Type;
ECType.ob_type=&ECTypeType;
UNLESS(concat_fmt=PyString_FromString("%s%s"));
m = Py_InitModule4("ExtensionClass", CC_methods,
ExtensionClass_module_documentation,
(PyObject*)NULL,PYTHON_API_VERSION);
d = PyModule_GetDict(m);
init_py_names();
if (0) PyCObject_Import14("this will go away", "in 1.5 :-)");
initializeBaseExtensionClass(&ECType);
PyDict_SetItemString(d, "ExtensionClass", (PyObject*)&ECType);
initializeBaseExtensionClass(&BaseType);
PyDict_SetItemString(d, "Base", (PyObject*)&BaseType);
PyDict_SetItemString(d, "PythonMethodType", (PyObject*)&PMethodType);
PyDict_SetItemString(d, "ExtensionMethodType", (PyObject*)&CMethodType);
/* Export C attribute lookup API */
PyExtensionClassCAPI=&TrueExtensionClassCAPI;
s = PyCObject_FromVoidPtr(PyExtensionClassCAPI, NULL);
PyDict_SetItemString(d, "CAPI", s);
Py_XDECREF(s);
CHECK_FOR_ERRORS("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