From 7c8fc0f7774b25acbb3d63474aa411d84029df0f Mon Sep 17 00:00:00 2001 From: Hanno Schlichting Date: Fri, 20 Jan 2017 13:53:03 +0100 Subject: [PATCH] Use ExtensionClass 4.2 with a Py3-compatible C extension. --- buildout.cfg | 6 +- include/Acquisition/Acquisition.h | 22 +++---- include/ExtensionClass/ExtensionClass.h | 76 ++++++++++++------------- include/ExtensionClass/_compat.h | 49 ++++++++++++++++ 4 files changed, 103 insertions(+), 50 deletions(-) create mode 100644 include/ExtensionClass/_compat.h diff --git a/buildout.cfg b/buildout.cfg index 44305f6..5ac2844 100644 --- a/buildout.cfg +++ b/buildout.cfg @@ -5,11 +5,15 @@ parts = interpreter test coverage [versions] AccessControl = +# Use newer ExtensionClass with C Extension compatible with Python 3 +ExtensionClass = 4.2.0 [interpreter] recipe = zc.recipe.egg interpreter = python -eggs = AccessControl +eggs = + AccessControl + tox [test] recipe = zc.recipe.testrunner diff --git a/include/Acquisition/Acquisition.h b/include/Acquisition/Acquisition.h index f230e56..acc9611 100644 --- a/include/Acquisition/Acquisition.h +++ b/include/Acquisition/Acquisition.h @@ -16,17 +16,17 @@ #define __ACQUISITION_H_ typedef struct { - PyObject *(*AQ_Acquire) (PyObject *obj, PyObject *name, PyObject *filter, - PyObject *extra, int explicit, PyObject *deflt, - int containment); - PyObject *(*AQ_Get) (PyObject *obj, PyObject *name, PyObject *deflt, - int containment); - int (*AQ_IsWrapper) (PyObject *obj); - PyObject *(*AQ_Base) (PyObject *obj); - PyObject *(*AQ_Parent) (PyObject *obj); - PyObject *(*AQ_Self) (PyObject *obj); - PyObject *(*AQ_Inner) (PyObject *obj); - PyObject *(*AQ_Chain) (PyObject *obj, int containment); + PyObject *(*AQ_Acquire) (PyObject *obj, PyObject *name, PyObject *filter, + PyObject *extra, int explicit, PyObject *deflt, + int containment); + PyObject *(*AQ_Get) (PyObject *obj, PyObject *name, PyObject *deflt, + int containment); + int (*AQ_IsWrapper) (PyObject *obj); + PyObject *(*AQ_Base) (PyObject *obj); + PyObject *(*AQ_Parent) (PyObject *obj); + PyObject *(*AQ_Self) (PyObject *obj); + PyObject *(*AQ_Inner) (PyObject *obj); + PyObject *(*AQ_Chain) (PyObject *obj, int containment); } ACQUISITIONCAPI; #ifndef _IN_ACQUISITION_C diff --git a/include/ExtensionClass/ExtensionClass.h b/include/ExtensionClass/ExtensionClass.h index fc8e6a2..d944f29 100644 --- a/include/ExtensionClass/ExtensionClass.h +++ b/include/ExtensionClass/ExtensionClass.h @@ -26,54 +26,54 @@ - The include file, 'ExtensionClass.h', must be included. - The type structure is declared to be of type - 'PyExtensionClass', rather than of type 'PyTypeObject'. + '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.) + 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. + '__init__' method that initializes, but does not create storage for + instances. - The extension class must be initialized and exported to the module - with:: + with:: - PyExtensionClass_Export(d,"name",type); + PyExtensionClass_Export(d,"name",type); - where 'name' is the module name and 'type' is the extension class - type object. + 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:: + 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); + 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'. + 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. + 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. */ @@ -186,7 +186,7 @@ static struct ExtensionClassCAPIstruct { /* The following macro can be used to define an extension base class that only provides method and that is used as a pure mix-in class. */ #define PURE_MIXIN_CLASS(NAME,DOC,METHODS) \ -static PyExtensionClass NAME ## Type = { PyObject_HEAD_INIT(NULL) 0, # NAME, \ +static PyExtensionClass NAME ## Type = { PyVarObject_HEAD_INIT(NULL, 0) # NAME, \ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ 0 , DOC, (traverseproc)METHODS, } @@ -212,7 +212,7 @@ static PyExtensionClass NAME ## Type = { PyObject_HEAD_INIT(NULL) 0, # NAME, \ (PyMethod_Check((M)) ? ((PyMethodObject*)(M))->im_self : NULL) /* Check whether an object has an __of__ method for returning itself - in the context of its container. */ + in the context of it's container. */ #define has__of__(O) (PyObject_TypeCheck((O)->ob_type, ECExtensionClassType) \ && Py_TYPE(O)->tp_descr_get != NULL) @@ -244,7 +244,7 @@ static PyExtensionClass NAME ## Type = { PyObject_HEAD_INIT(NULL) 0, # NAME, \ #define ExtensionClassImported \ ((PyExtensionClassCAPI != NULL) || \ - (PyExtensionClassCAPI = PyCObject_Import("ExtensionClass","CAPI2"))) + (PyExtensionClassCAPI = PyCapsule_Import("ExtensionClass.CAPI2", 0))) /* These are being overridded to use tp_free when used with @@ -256,9 +256,9 @@ static PyExtensionClass NAME ## Type = { PyObject_HEAD_INIT(NULL) 0, # NAME, \ #undef PyObject_DEL #define PyMem_DEL(O) \ - if ((Py_TYPE(O)->tp_flags & Py_TPFLAGS_HAVE_CLASS) \ - && (Py_TYPE(O)->tp_free != NULL)) \ - Py_TYPE(O)->tp_free((PyObject*)(O)); \ + if ((Py_TYPE(O)->tp_flags & Py_TPFLAGS_HAVE_CLASS) \ + && (Py_TYPE(O)->tp_free != NULL)) \ + Py_TYPE(O)->tp_free((PyObject*)(O)); \ else \ PyObject_FREE((O)); diff --git a/include/ExtensionClass/_compat.h b/include/ExtensionClass/_compat.h new file mode 100644 index 0000000..9f4cd0b --- /dev/null +++ b/include/ExtensionClass/_compat.h @@ -0,0 +1,49 @@ +/***************************************************************************** + + Copyright (c) 2012 Zope Foundation and Contributors. + All Rights Reserved. + + This software is subject to the provisions of the Zope Public License, + Version 2.1 (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 + + ****************************************************************************/ + +#ifndef PERSISTENT__COMPAT_H +#define PERSISTENT__COMPAT_H + +#include "Python.h" + +#if PY_MAJOR_VERSION >= 3 +#define PY3K +#endif + +#ifdef PY3K +#define INTERN PyUnicode_InternFromString +#define INTERN_INPLACE PyUnicode_InternInPlace +#define NATIVE_CHECK PyUnicode_Check +#define NATIVE_CHECK_EXACT PyUnicode_CheckExact +#define NATIVE_FROM_STRING PyUnicode_FromString +#define NATIVE_FROM_STRING_AND_SIZE PyUnicode_FromStringAndSize + +#define INT_FROM_LONG(x) PyLong_FromLong(x) +#define INT_CHECK(x) PyLong_Check(x) +#define INT_AS_LONG(x) PyLong_AS_LONG(x) + +#else +#define INTERN PyString_InternFromString +#define INTERN_INPLACE PyString_InternInPlace +#define NATIVE_CHECK PyString_Check +#define NATIVE_CHECK_EXACT PyString_CheckExact +#define NATIVE_FROM_STRING PyString_FromString +#define NATIVE_FROM_STRING_AND_SIZE PyString_FromStringAndSize + +#define INT_FROM_LONG(x) PyInt_FromLong(x) +#define INT_CHECK(x) PyInt_Check(x) +#define INT_AS_LONG(x) PyInt_AS_LONG(x) +#endif + +#endif