[Zope-Checkins] CVS: Zope/lib/python/ExtensionClass - ExtensionClass.h:1.1.2.1 _ExtensionClass.c:1.1.2.1 __init__.py:1.1.2.1 setup.py:1.1.2.1

Jim Fulton jim at zope.com
Sun Oct 19 17:25:42 EDT 2003


Update of /cvs-repository/Zope/lib/python/ExtensionClass
In directory cvs.zope.org:/tmp/cvs-serv1926/lib/python/ExtensionClass

Added Files:
      Tag: zodb33-devel-branch
	ExtensionClass.h _ExtensionClass.c __init__.py setup.py 
Log Message:
New-style ExtensionClass, in C.

This is an initial cut. The next step is to start converting some of
the old EC extensions, like Acquisition and Persistent.


=== Added File Zope/lib/python/ExtensionClass/ExtensionClass.h ===
/*****************************************************************************

  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

 ****************************************************************************/

/*

  $Id: ExtensionClass.h,v 1.1.2.1 2003/10/19 21:25:41 jim Exp $

  Extension Class Definitions

  Implementing base extension classes
  
    A base extension class is implemented in much the same way that an
    extension type is implemented, except:
  
    - The include file, 'ExtensionClass.h', must be included.
 
    - The type structure is declared to be of type
	  'PyExtensionClass', rather than of type 'PyTypeObject'.
 
    - The type structure has an additional member that must be defined
	  after the documentation string.  This extra member is a method chain
	  ('PyMethodChain') containing a linked list of method definition
	  ('PyMethodDef') lists.  Method chains can be used to implement
	  method inheritance in C.  Most extensions don't use method chains,
	  but simply define method lists, which are null-terminated arrays
	  of method definitions.  A macro, 'METHOD_CHAIN' is defined in
	  'ExtensionClass.h' that converts a method list to a method chain.
	  (See the example below.)
  
    - Module functions that create new instances must be replaced by an
	  '__init__' method that initializes, but does not create storage for 
	  instances.
  
    - The extension class must be initialized and exported to the module
	  with::
  
	      PyExtensionClass_Export(d,"name",type);
  
	  where 'name' is the module name and 'type' is the extension class
	  type object.
  
    Attribute lookup
  
	  Attribute lookup is performed by calling the base extension class
	  'getattr' operation for the base extension class that includes C
	  data, or for the first base extension class, if none of the base
	  extension classes include C data.  'ExtensionClass.h' defines a
	  macro 'Py_FindAttrString' that can be used to find an object's
	  attributes that are stored in the object's instance dictionary or
	  in the object's class or base classes::
  
	     v = Py_FindAttrString(self,name);
  
	  In addition, a macro is provided that replaces 'Py_FindMethod'
	  calls with logic to perform the same sort of lookup that is
	  provided by 'Py_FindAttrString'.
  
    Linking
  
	  The extension class mechanism was designed to be useful with
	  dynamically linked extension modules.  Modules that implement
	  extension classes do not have to be linked against an extension
	  class library.  The macro 'PyExtensionClass_Export' imports the
	  'ExtensionClass' module and uses objects imported from this module
	  to initialize an extension class with necessary behavior.
 
  If you have questions regarding this software,
  contact:
 
  
  If you have questions regarding this software,
  contact:
 
    Digital Creations L.C.  
    info at digicool.com
 
    (540) 371-6909

*/

#ifndef EXTENSIONCLASS_H
#define EXTENSIONCLASS_H

#include "Python.h"
#include "import.h"

/* Declarations for objects of type ExtensionClass */

typedef struct {
  PyHeapTypeObject tp;
  long class_flags;  
} PyExtensionClass;

#define EC PyExtensionClass

  /* The following flags are used by ExtensionClass */
#define EXTENSIONCLASS_DYNAMIC_FLAG       1 << 0
#define EXTENSIONCLASS_BINDABLE_FLAG      1 << 2
#define EXTENSIONCLASS_METHODHOOK_FLAG    1 << 3
#define EXTENSIONCLASS_INSTDICT_FLAG      1 << 4
#define EXTENSIONCLASS_NOINSTDICT_FLAG    1 << 5
#define EXTENSIONCLASS_BASICNEW_FLAG      1 << 6
#define EXTENSIONCLASS_PYTHONICATTR_FLAG  1 << 7
#define EXTENSIONCLASS_USERGETATTR_FLAG   1 << 8
#define EXTENSIONCLASS_USERSETATTR_FLAG   1 << 9
#define EXTENSIONCLASS_USERDELATTR_FLAG   1 << 10

  /* The following flags are for use by extension class developers. */
#define EXTENSIONCLASS_USER_FLAG1  	  1 << 16
#define EXTENSIONCLASS_USER_FLAG2  	  1 << 17
#define EXTENSIONCLASS_USER_FLAG3  	  1 << 18
#define EXTENSIONCLASS_USER_FLAG4  	  1 << 19
#define EXTENSIONCLASS_USER_FLAG5  	  1 << 20
#define EXTENSIONCLASS_USER_FLAG6  	  1 << 21
#define EXTENSIONCLASS_USER_FLAG7  	  1 << 22
#define EXTENSIONCLASS_USER_FLAG8  	  1 << 23
#define EXTENSIONCLASS_USER_FLAG9  	  1 << 24
#define EXTENSIONCLASS_USER_FLAG10 	  1 << 25
#define EXTENSIONCLASS_USER_FLAG11 	  1 << 26
#define EXTENSIONCLASS_USER_FLAG12 	  1 << 27
#define EXTENSIONCLASS_USER_FLAG13 	  1 << 28
#define EXTENSIONCLASS_USER_FLAG14 	  1 << 29
#define EXTENSIONCLASS_USER_FLAG15 	  1 << 30
#define EXTENSIONCLASS_USER_FLAG16 	  1 << 31

#endif /* EXTENSIONCLASS_H */


=== Added File Zope/lib/python/ExtensionClass/_ExtensionClass.c ===
/*

 Copyright (c) 2003 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\n"
"\n"
"$Id: _ExtensionClass.c,v 1.1.2.1 2003/10/19 21:25:41 jim Exp $\n"
;

#include "ExtensionClass.h"

static PyObject *str__of__, *str__get__, *str__class_init__;

#define OBJECT(O) ((PyObject *)(O))
#define TYPE(O) ((PyTypeObject *)(O))

extern PyTypeObject ExtensionClassType;

static PyObject *
of_get(PyObject *self, PyObject *inst, PyObject *cls)
{
  /* Descriptor slot function that calls __of__ */
  if (inst)
    return PyObject_CallMethodObjArgs(self, str__of__, inst, NULL);

  Py_INCREF(self);
  return self;
}

PyObject *
Base_getattro(PyObject *obj, PyObject *name)
{
  /* This is a modified copy of PyObject_GenericGetAttr.
     See the change note below. */

	PyTypeObject *tp = obj->ob_type;
	PyObject *descr = NULL;
	PyObject *res = NULL;
	descrgetfunc f;
	long dictoffset;
	PyObject **dictptr;

	if (!PyString_Check(name)){
#ifdef Py_USING_UNICODE
		/* The Unicode to string conversion is done here because the
		   existing tp_setattro slots expect a string object as name
		   and we wouldn't want to break those. */
		if (PyUnicode_Check(name)) {
			name = PyUnicode_AsEncodedString(name, NULL, NULL);
			if (name == NULL)
				return NULL;
		}
		else
#endif
		{
			PyErr_SetString(PyExc_TypeError,
					"attribute name must be string");
			return NULL;
		}
	}
	else
		Py_INCREF(name);

	if (tp->tp_dict == NULL) {
		if (PyType_Ready(tp) < 0)
			goto done;
	}

	/* Inline _PyType_Lookup */
	{
		int i, n;
		PyObject *mro, *base, *dict;

		/* Look in tp_dict of types in MRO */
		mro = tp->tp_mro;
		assert(mro != NULL);
		assert(PyTuple_Check(mro));
		n = PyTuple_GET_SIZE(mro);
		for (i = 0; i < n; i++) {
			base = PyTuple_GET_ITEM(mro, i);
			if (PyClass_Check(base))
				dict = ((PyClassObject *)base)->cl_dict;
			else {
				assert(PyType_Check(base));
				dict = ((PyTypeObject *)base)->tp_dict;
			}
			assert(dict && PyDict_Check(dict));
			descr = PyDict_GetItem(dict, name);
			if (descr != NULL)
				break;
		}
	}

	f = NULL;
	if (descr != NULL &&
	    PyType_HasFeature(descr->ob_type, Py_TPFLAGS_HAVE_CLASS)) {
		f = descr->ob_type->tp_descr_get;
		if (f != NULL && PyDescr_IsData(descr)) {
			res = f(descr, obj, (PyObject *)obj->ob_type);
			goto done;
		}
	}

	/* Inline _PyObject_GetDictPtr */
	dictoffset = tp->tp_dictoffset;
	if (dictoffset != 0) {
		PyObject *dict;
		if (dictoffset < 0) {
			int tsize;
			size_t size;

			tsize = ((PyVarObject *)obj)->ob_size;
			if (tsize < 0)
				tsize = -tsize;
			size = _PyObject_VAR_SIZE(tp, tsize);

			dictoffset += (long)size;
			assert(dictoffset > 0);
			assert(dictoffset % SIZEOF_VOID_P == 0);
		}
		dictptr = (PyObject **) ((char *)obj + dictoffset);
		dict = *dictptr;
		if (dict != NULL) {
			res = PyDict_GetItem(dict, name);
			if (res != NULL) {

                          /* CHANGED!
                             If the tp_descr_get of res is of_get, 
                             then call it. */

                          if (PyType_HasFeature(res->ob_type, 
                                                Py_TPFLAGS_HAVE_CLASS)
                              && res->ob_type->tp_descr_get == of_get
                              ) 
                            res = of_get(res, obj, NULL);
                          else
                            Py_INCREF(res);
                          goto done;
			}
		}
	}

	if (f != NULL) {
		res = f(descr, obj, (PyObject *)obj->ob_type);
		goto done;
	}

	if (descr != NULL) {
		Py_INCREF(descr);
		res = descr;
		goto done;
	}

	PyErr_Format(PyExc_AttributeError,
		     "'%.50s' object has no attribute '%.400s'",
		     tp->tp_name, PyString_AS_STRING(name));
  done:
	Py_DECREF(name);
	return res;
}




static EC BaseType = {
  {
    {
	PyObject_HEAD_INIT(NULL)
	/* ob_size           */ 0,
	/* tp_name           */ "ExtensionClass."
                                "Base",
	/* tp_basicsize      */ 0, /* set below */
	/* tp_itemsize       */ 0,
	/* tp_dealloc        */ (destructor)0,
	/* tp_print          */ (printfunc)0,
	/* tp_getattr        */ (getattrfunc)0,
	/* tp_setattr        */ (setattrfunc)0,
	/* tp_compare        */ (cmpfunc)0,
	/* tp_repr           */ (reprfunc)0,
	/* tp_as_number      */ 0,
	/* tp_as_sequence    */ 0,
	/* tp_as_mapping     */ 0,
	/* tp_hash           */ (hashfunc)0,
	/* tp_call           */ (ternaryfunc)0,
	/* tp_str            */ (reprfunc)0,
        /* tp_getattro       */ (getattrofunc)Base_getattro,
        /* tp_setattro       */ (setattrofunc)0,
        /* tp_as_buffer      */ 0,
        /* tp_flags          */ Py_TPFLAGS_DEFAULT 
                                | Py_TPFLAGS_HAVE_GC
				| Py_TPFLAGS_BASETYPE
                                ,
	/* tp_doc            */ "Standard ExtensionClass base type",
    },
  },
};

static PyObject *
EC_new(PyTypeObject *self, PyObject *args, PyObject *kw)
{
  PyObject *name, *bases=NULL, *dict=NULL, *__class_init__;
  PyObject *new_bases=NULL, *new_args, *result;
  int have_base = 0, i;

  if (kw && PyObject_IsTrue(kw))
    {
      PyErr_SetString(PyExc_TypeError, 
                      "Keyword arguments are not supported");
        return NULL;
    }

  if (!PyArg_ParseTuple(args, "O|O!O!", &name,
                        &PyTuple_Type, &bases, &PyDict_Type, &dict))
    return NULL;

  /* Handle __class_init__ */
  if (dict)
    {
      __class_init__ = PyDict_GetItem(dict, str__class_init__);
      if (__class_init__)
        {                       /* Convert to class meth */
          __class_init__ = PyClassMethod_New(__class_init__);
          if (! __class_init__)
            return NULL;
          PyDict_SetItem(dict, str__class_init__, __class_init__);
        }
    }

  /* Make sure Base is in bases */
  if (bases)
    {
      for (i = 0; i < PyTuple_GET_SIZE(bases); i++)
        {
          if (PyObject_TypeCheck(PyTuple_GET_ITEM(bases, i), 
                                 &ExtensionClassType))
            {
              have_base = 1;
              break;
            }
        }
      if (! have_base)
        {
          new_bases = PyTuple_New(PyTuple_GET_SIZE(bases) + 1);
          if (new_bases == NULL)
            return NULL;
          for (i = 0; i < PyTuple_GET_SIZE(bases); i++)
            {
              Py_XINCREF(PyTuple_GET_ITEM(bases, i));
              PyTuple_SET_ITEM(new_bases, i, PyTuple_GET_ITEM(bases, i));
            }
          Py_INCREF(OBJECT(&BaseType));
          PyTuple_SET_ITEM(new_bases, PyTuple_GET_SIZE(bases), 
                           OBJECT(&BaseType));
        }
    }
  else
    {
      new_bases = Py_BuildValue("(O)", &BaseType);
      if (new_bases == NULL)
        return NULL;
    }

  if (new_bases)
    {
      if (dict)
        new_args = Py_BuildValue("OOO", name, new_bases, dict);
      else
        new_args = Py_BuildValue("OO", name, new_bases);

      Py_DECREF(new_bases);

      if (new_args == NULL)
        return NULL;

      result = PyType_Type.tp_new(self, new_args, kw);
      Py_DECREF(new_args);
    }
  else
    result = PyType_Type.tp_new(self, args, kw);
  
  return result;
}

static int
EC_init(PyTypeObject *self, PyObject *args, PyObject *kw)
{
  PyObject *__class_init__, *__of__, *r;

  if (PyType_Type.tp_init(OBJECT(self), args, kw) < 0) 
    return -1; 

  /* set up __get__, if necessary */
  if (self->tp_descr_get != of_get)
    {
      __of__ = PyObject_GetAttr(OBJECT(self), str__of__);
      if (__of__)
        {
          Py_DECREF(__of__);
          if (self->tp_descr_get)
            {
              PyErr_SetString(PyExc_TypeError,
                              "Can't mix __of__ and descriptors");
              return -1;
            }
          self->tp_descr_get = of_get;
        }
      else
        PyErr_Clear();
    }

  /* Call __class_init__ */
  __class_init__ = PyObject_GetAttr(OBJECT(self), str__class_init__);
  if (__class_init__)
    {
      r = PyObject_CallFunctionObjArgs(__class_init__, NULL);
      Py_DECREF(__class_init__);

      if (r)
        {
          Py_DECREF(r);
        }
      else
        return -1;
    }
  else
    PyErr_Clear();

  return 0;
}

static PyObject *
inheritedAttribute(PyTypeObject *self, PyObject *name)
{
  int i;
  PyObject *v;

  for (i = 0; i < PyTuple_GET_SIZE(self->tp_bases); i++)
    {
      v = PyObject_GetAttr(PyTuple_GET_ITEM(self->tp_bases, i), name);
      if (v)
        return v;
      PyErr_Clear();
    }
  PyErr_SetObject(PyExc_AttributeError, name);
  return NULL;
}

static struct PyMethodDef EC_methods[] = {
  {"inheritedAttribute", (PyCFunction)inheritedAttribute, METH_O, 
   "Look up an inherited attribute"},
  {NULL,	 (PyCFunction)NULL, 0, NULL}		/* sentinel */
  };


static PyTypeObject ExtensionClassType = {
	PyObject_HEAD_INIT(NULL)
	/* ob_size           */ 0,
	/* tp_name           */ "ExtensionClass."
                                "ExtensionClass",
	/* tp_basicsize      */ sizeof(EC),
	/* tp_itemsize       */ 0,
	/* tp_dealloc        */ (destructor)0,
	/* tp_print          */ (printfunc)0,
	/* tp_getattr        */ (getattrfunc)0,
	/* tp_setattr        */ (setattrfunc)0,
	/* tp_compare        */ (cmpfunc)0,
	/* tp_repr           */ (reprfunc)0,
	/* tp_as_number      */ 0,
	/* tp_as_sequence    */ 0,
	/* tp_as_mapping     */ 0,
	/* tp_hash           */ (hashfunc)0,
	/* tp_call           */ (ternaryfunc)0,
	/* tp_str            */ (reprfunc)0,
        /* tp_getattro       */ (getattrofunc)0,
        /* tp_setattro       */ (setattrofunc)0,
        /* tp_as_buffer      */ 0,
        /* tp_flags          */ Py_TPFLAGS_DEFAULT
                                | Py_TPFLAGS_HAVE_GC
                                ,
	/* tp_doc            */ "Meta-class for extension classes",
        /* tp_traverse       */ (traverseproc)0,
        /* tp_clear          */ (inquiry)0,
        /* tp_richcompare    */ (richcmpfunc)0,
        /* tp_weaklistoffset */ (long)0,
        /* tp_iter           */ (getiterfunc)0,
        /* tp_iternext       */ (iternextfunc)0,
        /* tp_methods        */ EC_methods,
        /* tp_members        */ 0,
        /* tp_getset         */ 0,
        /* tp_base           */ 0,
        /* tp_dict           */ 0, /* internal use */
        /* tp_descr_get      */ (descrgetfunc)0,
        /* tp_descr_set      */ (descrsetfunc)0,
        /* tp_dictoffset     */ 0,
        /* tp_init           */ (initproc)EC_init,
        /* tp_alloc          */ (allocfunc)0,
        /* tp_new            */ (newfunc)EC_new,
	/* tp_free           */ 0, /* Low-level free-mem routine */
	/* tp_is_gc          */ (inquiry)0, /* For PyObject_IS_GC */
};

static PyObject *
debug(PyObject *self, PyObject *o)
{
  Py_INCREF(Py_None);
  return Py_None;
}


/* List of methods defined in the module */

static struct PyMethodDef ec_methods[] = {
  {"debug", (PyCFunction)debug, METH_O, ""},
  {NULL,	 (PyCFunction)NULL, 0, NULL}		/* sentinel */
  };

#ifndef PyMODINIT_FUNC	/* declarations for DLL import/export */
#define PyMODINIT_FUNC void
#endif
PyMODINIT_FUNC
init_ExtensionClass(void)
{
  PyObject *m;

#define DEFINE_STRING(S) \
  if(! (str ## S = PyString_FromString(# S))) return

  DEFINE_STRING(__of__);
  DEFINE_STRING(__get__);
  DEFINE_STRING(__class_init__);

  ExtensionClassType.ob_type = &PyType_Type;
  ExtensionClassType.tp_base = &PyType_Type;
  ExtensionClassType.tp_traverse = PyType_Type.tp_traverse;
  ExtensionClassType.tp_clear = PyType_Type.tp_clear;
  
  /* Initialize types: */
  if (PyType_Ready(&ExtensionClassType) < 0)
    return;
  
  
  TYPE(&BaseType)->tp_basicsize = PyBaseObject_Type.tp_basicsize;
  TYPE(&BaseType)->ob_type = &ExtensionClassType;
  TYPE(&BaseType)->tp_base = &PyBaseObject_Type;
  TYPE(&BaseType)->tp_new = PyType_GenericNew;
  
  if (PyType_Ready(TYPE(&BaseType)) < 0)
    return;
  
  /* Create the module and add the functions */
  m = Py_InitModule3("_ExtensionClass", ec_methods,
                     _extensionclass_module_documentation);

  if (m == NULL)
    return;

        
  /* Add types: */
  if (PyModule_AddObject(m, "ExtensionClass", 
                         (PyObject *)&ExtensionClassType) < 0)
    return;
  if (PyModule_AddObject(m, "Base", (PyObject *)&BaseType) < 0)
    return;
}



=== Added File Zope/lib/python/ExtensionClass/__init__.py ===
##############################################################################
#
# Copyright (c) 2003 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.
#
##############################################################################
"""ExtensionClass

$Id: __init__.py,v 1.1.2.1 2003/10/19 21:25:41 jim Exp $
"""

from _ExtensionClass import ExtensionClass, Base


=== Added File Zope/lib/python/ExtensionClass/setup.py ===
from distutils.core import setup, Extension
setup(name="ExtensionClass", version="2.0",
      ext_modules=[
         Extension("_ExtensionClass", ["_ExtensionClass.c"]),
         ])





More information about the Zope-Checkins mailing list