Skip to content

Commit

Permalink
Use ExtensionClass 4.2 with a Py3-compatible C extension.
Browse files Browse the repository at this point in the history
  • Loading branch information
hannosch committed Jan 20, 2017
1 parent 3815300 commit 7c8fc0f
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 50 deletions.
6 changes: 5 additions & 1 deletion buildout.cfg
Expand Up @@ -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
Expand Down
22 changes: 11 additions & 11 deletions include/Acquisition/Acquisition.h
Expand Up @@ -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
Expand Down
76 changes: 38 additions & 38 deletions include/ExtensionClass/ExtensionClass.h
Expand Up @@ -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.
*/

Expand Down Expand Up @@ -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, }

Expand All @@ -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)

Expand Down Expand Up @@ -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
Expand All @@ -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));

Expand Down
49 changes: 49 additions & 0 deletions 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

0 comments on commit 7c8fc0f

Please sign in to comment.