tested django-newsletter
This commit is contained in:
@@ -0,0 +1,247 @@
|
||||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1996-2002 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
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
|
||||
$Id$
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef EXTENSIONCLASS_H
|
||||
#define EXTENSIONCLASS_H
|
||||
|
||||
#include "Python.h"
|
||||
#include "import.h"
|
||||
|
||||
/* Declarations for objects of type ExtensionClass */
|
||||
|
||||
#define EC PyTypeObject
|
||||
#define PyExtensionClass PyTypeObject
|
||||
|
||||
#define EXTENSIONCLASS_BINDABLE_FLAG 1 << 2
|
||||
#define EXTENSIONCLASS_NOINSTDICT_FLAG 1 << 5
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
} _emptyobject;
|
||||
|
||||
static struct ExtensionClassCAPIstruct {
|
||||
|
||||
/*****************************************************************************
|
||||
|
||||
WARNING: THIS STRUCT IS PRIVATE TO THE EXTENSION CLASS INTERFACE
|
||||
IMPLEMENTATION AND IS SUBJECT TO CHANGE !!!
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
PyObject *(*EC_findiattrs_)(PyObject *self, char *cname);
|
||||
int (*PyExtensionClass_Export_)(PyObject *dict, char *name,
|
||||
PyTypeObject *typ);
|
||||
PyObject *(*PyECMethod_New_)(PyObject *callable, PyObject *inst);
|
||||
PyExtensionClass *ECBaseType_;
|
||||
PyExtensionClass *ECExtensionClassType_;
|
||||
} *PyExtensionClassCAPI = NULL;
|
||||
|
||||
#define ECBaseType (PyExtensionClassCAPI->ECBaseType_)
|
||||
#define ECExtensionClassType (PyExtensionClassCAPI->ECExtensionClassType_)
|
||||
|
||||
/* Following are macros that are needed or useful for defining extension
|
||||
classes:
|
||||
*/
|
||||
|
||||
/* This macro redefines Py_FindMethod to do attribute for an attribute
|
||||
name given by a C string lookup using extension class meta-data.
|
||||
This is used by older getattr implementations.
|
||||
|
||||
This macro is used in base class implementations of tp_getattr to
|
||||
lookup methods or attributes that are not managed by the base type
|
||||
directly. The macro is generally used to search for attributes
|
||||
after other attribute searches have failed.
|
||||
|
||||
Note that in Python 1.4, a getattr operation may be provided that
|
||||
uses an object argument. Classes that support this new operation
|
||||
should use Py_FindAttr.
|
||||
*/
|
||||
|
||||
#define EC_findiattrs (PyExtensionClassCAPI->EC_findiattrs_)
|
||||
|
||||
#define Py_FindMethod(M,SELF,NAME) (EC_findiattrs((SELF),(NAME)))
|
||||
|
||||
/* Do method or attribute lookup for an attribute name given by a C
|
||||
string using extension class meta-data.
|
||||
|
||||
This macro is used in base class implementations of tp_getattro to
|
||||
lookup methods or attributes that are not managed by the base type
|
||||
directly. The macro is generally used to search for attributes
|
||||
after other attribute searches have failed.
|
||||
|
||||
Note that in Python 1.4, a getattr operation may be provided that
|
||||
uses an object argument. Classes that support this new operation
|
||||
should use Py_FindAttr.
|
||||
*/
|
||||
#define Py_FindAttrString(SELF,NAME) (EC_findiattrs((SELF),(NAME)))
|
||||
|
||||
/* Do method or attribute lookup using extension class meta-data.
|
||||
|
||||
This macro is used in base class implementations of tp_getattr to
|
||||
lookup methods or attributes that are not managed by the base type
|
||||
directly. The macro is generally used to search for attributes
|
||||
after other attribute searches have failed. */
|
||||
#define Py_FindAttr (ECBaseType->tp_getattro)
|
||||
|
||||
/* Do attribute assignment for an attribute.
|
||||
|
||||
This macro is used in base class implementations of tp_setattro to
|
||||
set attributes that are not managed by the base type directly. The
|
||||
macro is generally used to assign attributes after other attribute
|
||||
attempts to assign attributes have failed.
|
||||
*/
|
||||
#define PyEC_SetAttr(SELF,NAME,V) (ECBaseType->tp_setattro(SELF, NAME, V))
|
||||
|
||||
|
||||
/* Convert a method list to a method chain. */
|
||||
#define METHOD_CHAIN(DEF) (traverseproc)(DEF)
|
||||
|
||||
/* The following macro checks whether a type is an extension class: */
|
||||
#define PyExtensionClass_Check(TYPE) \
|
||||
PyObject_TypeCheck((PyObject*)(TYPE), ECExtensionClassType)
|
||||
|
||||
/* The following macro checks whether an instance is an extension instance: */
|
||||
#define PyExtensionInstance_Check(INST) \
|
||||
PyObject_TypeCheck(Py_TYPE(INST), ECExtensionClassType)
|
||||
|
||||
#define CHECK_FOR_ERRORS(MESS)
|
||||
|
||||
/* 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 = { 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, }
|
||||
|
||||
/* The following macros provide limited access to extension-class
|
||||
method facilities. */
|
||||
|
||||
/* Test for an ExtensionClass method: */
|
||||
#define PyECMethod_Check(O) PyMethod_Check((O))
|
||||
|
||||
/* Create a method object that wraps a callable object and an
|
||||
instance. Note that if the callable object is an extension class
|
||||
method, then the new method will wrap the callable object that is
|
||||
wrapped by the extension class method. Also note that if the
|
||||
callable object is an extension class method with a reference
|
||||
count of 1, then the callable object will be rebound to the
|
||||
instance and returned with an incremented reference count.
|
||||
*/
|
||||
#define PyECMethod_New(CALLABLE, INST) \
|
||||
PyExtensionClassCAPI->PyECMethod_New_((CALLABLE),(INST))
|
||||
|
||||
/* Return the instance that is bound by an extension class method. */
|
||||
#define PyECMethod_Self(M) (PyMethod_Check((M)) ? PyMethod_GET_SELF(M) : NULL)
|
||||
|
||||
/* Check whether an object has an __of__ method for returning itself
|
||||
in the context of it's container. */
|
||||
#define has__of__(O) (PyExtensionInstance_Check(O) && Py_TYPE(O)->tp_descr_get != NULL)
|
||||
|
||||
/* The following macros are used to check whether an instance
|
||||
or a class' instanses have instance dictionaries: */
|
||||
#define HasInstDict(O) (_PyObject_GetDictPtr(O) != NULL)
|
||||
|
||||
#define ClassHasInstDict(C) ((C)->tp_dictoffset > 0)
|
||||
|
||||
/* Get an object's instance dictionary. Use with caution */
|
||||
#define INSTANCE_DICT(inst) (_PyObject_GetDictPtr(O))
|
||||
|
||||
/* Test whether an ExtensionClass, S, is a subclass of ExtensionClass C. */
|
||||
#define ExtensionClassSubclass_Check(S,C) PyType_IsSubtype((S), (C))
|
||||
|
||||
/* Test whether an ExtensionClass instance , I, is a subclass of
|
||||
ExtensionClass C. */
|
||||
#define ExtensionClassSubclassInstance_Check(I,C) PyObject_TypeCheck((I), (C))
|
||||
|
||||
|
||||
/* Export an Extension Base class in a given module dictionary with a
|
||||
given name and ExtensionClass structure.
|
||||
*/
|
||||
|
||||
#define PyExtensionClass_Export(D,N,T) \
|
||||
if (! ExtensionClassImported || \
|
||||
PyExtensionClassCAPI->PyExtensionClass_Export_((D),(N),&(T)) < 0) return NULL;
|
||||
|
||||
|
||||
#define ExtensionClassImported \
|
||||
((PyExtensionClassCAPI != NULL) || \
|
||||
(PyExtensionClassCAPI = PyCapsule_Import("ExtensionClass.CAPI2", 0)))
|
||||
|
||||
#endif /* EXTENSIONCLASS_H */
|
||||
File diff suppressed because it is too large
Load Diff
Executable
BIN
Binary file not shown.
@@ -0,0 +1,343 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2003 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""ExtensionClass
|
||||
|
||||
Extension Class exists to support types derived from the old ExtensionType
|
||||
meta-class that preceeded Python 2.2 and new-style classes.
|
||||
|
||||
As a meta-class, ExtensionClass provides the following features:
|
||||
|
||||
- Support for a class initialiser:
|
||||
|
||||
>>> from ExtensionClass import ExtensionClass, Base
|
||||
|
||||
>>> class C(Base):
|
||||
... def __class_init__(self):
|
||||
... print('class init called')
|
||||
... print(self.__name__)
|
||||
... def bar(self):
|
||||
... return 'bar called'
|
||||
class init called
|
||||
C
|
||||
>>> c = C()
|
||||
>>> int(c.__class__ is C)
|
||||
1
|
||||
>>> int(c.__class__ is type(c))
|
||||
1
|
||||
|
||||
- Making sure that every instance of the meta-class has Base as a base class:
|
||||
|
||||
>>> X = ExtensionClass('X', (), {})
|
||||
>>> Base in X.__mro__
|
||||
1
|
||||
|
||||
- Provide an inheritedAttribute method for looking up attributes in
|
||||
base classes:
|
||||
|
||||
>>> class C2(C):
|
||||
... def bar(*a):
|
||||
... return C2.inheritedAttribute('bar')(*a), 42
|
||||
class init called
|
||||
C2
|
||||
>>> o = C2()
|
||||
>>> o.bar()
|
||||
('bar called', 42)
|
||||
|
||||
This is for compatability with old code. New code should use super
|
||||
instead.
|
||||
|
||||
The base class, Base, exists mainly to support the __of__ protocol.
|
||||
The __of__ protocol is similar to __get__ except that __of__ is called
|
||||
when an implementor is retrieved from an instance as well as from a
|
||||
class:
|
||||
|
||||
>>> class O(Base):
|
||||
... def __of__(*a):
|
||||
... return a
|
||||
|
||||
>>> o1 = O()
|
||||
>>> o2 = O()
|
||||
>>> C.o1 = o1
|
||||
>>> c.o2 = o2
|
||||
>>> c.o1 == (o1, c)
|
||||
1
|
||||
>>> C.o1 == o1
|
||||
1
|
||||
>>> int(c.o2 == (o2, c))
|
||||
1
|
||||
|
||||
We accomplish this by making a class that implements __of__ a
|
||||
descriptor and treating all descriptor ExtensionClasses this way. That
|
||||
is, if an extension class is a descriptor, it's __get__ method will be
|
||||
called even when it is retrieved from an instance.
|
||||
|
||||
>>> class O(Base):
|
||||
... def __get__(*a):
|
||||
... return a
|
||||
...
|
||||
>>> o1 = O()
|
||||
>>> o2 = O()
|
||||
>>> C.o1 = o1
|
||||
>>> c.o2 = o2
|
||||
>>> int(c.o1 == (o1, c, type(c)))
|
||||
1
|
||||
>>> int(C.o1 == (o1, None, type(c)))
|
||||
1
|
||||
>>> int(c.o2 == (o2, c, type(c)))
|
||||
1
|
||||
"""
|
||||
|
||||
import inspect
|
||||
import os
|
||||
import platform
|
||||
import sys
|
||||
|
||||
if sys.version_info > (3, ):
|
||||
import copyreg as copy_reg
|
||||
else: # pragma: no cover
|
||||
import copy_reg
|
||||
|
||||
_IS_PYPY = platform.python_implementation() == 'PyPy'
|
||||
_IS_PURE = 'PURE_PYTHON' in os.environ
|
||||
C_EXTENSION = not (_IS_PYPY or _IS_PURE)
|
||||
|
||||
|
||||
def of_get(self, inst, type_=None):
|
||||
if not issubclass(type(type_), ExtensionClass):
|
||||
return self
|
||||
if inst is not None:
|
||||
return self.__of__(inst)
|
||||
return self
|
||||
|
||||
|
||||
def pmc_init_of(cls):
|
||||
# set up __get__ if __of__ is implemented
|
||||
of = getattr(cls, '__of__', None)
|
||||
if of is not None:
|
||||
cls.__get__ = of_get
|
||||
else:
|
||||
get = getattr(cls, '__get__', None)
|
||||
if (get is not None and
|
||||
(get is of_get or getattr(get, '__func__', None) is of_get)):
|
||||
del cls.__get__
|
||||
|
||||
|
||||
_Base = type('dummy', (), {})
|
||||
_NoInstanceDictionaryBase = type('dummy', (), {})
|
||||
|
||||
|
||||
def _add_classic_mro(mro, cls):
|
||||
if cls not in mro:
|
||||
mro.append(cls)
|
||||
for base in cls.__bases__:
|
||||
if base not in mro:
|
||||
mro.append(base)
|
||||
_add_classic_mro(mro, base)
|
||||
|
||||
|
||||
class ExtensionClass(type):
|
||||
|
||||
def __new__(cls, name, bases=(), attrs=None):
|
||||
attrs = {} if attrs is None else attrs
|
||||
# Make sure we have an ExtensionClass instance as a base
|
||||
if (name != 'Base' and
|
||||
not any(isinstance(b, ExtensionClass) for b in bases)):
|
||||
bases += (_Base,)
|
||||
if ('__slots__' not in attrs and
|
||||
any(issubclass(b, _NoInstanceDictionaryBase) for b in bases)):
|
||||
attrs['__slots__'] = []
|
||||
|
||||
cls = type.__new__(cls, name, bases, attrs)
|
||||
|
||||
# Inherit docstring
|
||||
if not cls.__doc__:
|
||||
cls.__doc__ = super(cls, cls).__doc__
|
||||
|
||||
# set up __get__ if __of__ is implemented
|
||||
pmc_init_of(cls)
|
||||
|
||||
# call class init method
|
||||
if hasattr(cls, '__class_init__'):
|
||||
class_init = cls.__class_init__
|
||||
if hasattr(class_init, '__func__'):
|
||||
class_init = class_init.__func__
|
||||
class_init(cls)
|
||||
return cls
|
||||
|
||||
def __basicnew__(self):
|
||||
"""Create a new empty object"""
|
||||
return self.__new__(self)
|
||||
|
||||
|
||||
def mro(self):
|
||||
"""Compute an mro using the 'encapsulated base' scheme"""
|
||||
mro = [self]
|
||||
for base in self.__bases__:
|
||||
if hasattr(base, '__mro__'):
|
||||
for c in base.__mro__:
|
||||
if c in (_Base, _NoInstanceDictionaryBase, object):
|
||||
continue
|
||||
if c in mro:
|
||||
continue
|
||||
mro.append(c)
|
||||
else: # pragma: no cover (python 2 only)
|
||||
_add_classic_mro(mro, base)
|
||||
|
||||
if _NoInstanceDictionaryBase in self.__bases__:
|
||||
mro.append(_NoInstanceDictionaryBase)
|
||||
elif self.__name__ != 'Base':
|
||||
mro.append(_Base)
|
||||
mro.append(object)
|
||||
return mro
|
||||
|
||||
def inheritedAttribute(self, name):
|
||||
"""Look up an inherited attribute"""
|
||||
return getattr(super(self, self), name)
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
if name not in ('__get__', '__doc__', '__of__'):
|
||||
if (name.startswith('__') and name.endswith('__') and
|
||||
name.count('_') == 4):
|
||||
raise TypeError(
|
||||
"can't set attributes of built-in/extension type '%s.%s' "
|
||||
"if the attribute name begins and ends with __ and "
|
||||
"contains only 4 _ characters" %
|
||||
(self.__module__, self.__name__))
|
||||
return type.__setattr__(self, name, value)
|
||||
|
||||
|
||||
# Base and object are always moved to the last two positions
|
||||
# in a subclasses mro, no matter how they are declared in the
|
||||
# hierarchy. This means the Base_* methods effectively don't have
|
||||
# to care or worry about using super(): it's always object.
|
||||
|
||||
def Base_getattro(self, name):
|
||||
descr = None
|
||||
|
||||
for base in type(self).__mro__:
|
||||
if name in base.__dict__:
|
||||
descr = base.__dict__[name]
|
||||
break
|
||||
|
||||
if descr is not None and inspect.isdatadescriptor(descr):
|
||||
return descr.__get__(self, type(self))
|
||||
|
||||
try:
|
||||
# Don't do self.__dict__ otherwise you get recursion.
|
||||
inst_dict = object.__getattribute__(self, '__dict__')
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
if name in inst_dict:
|
||||
descr = inst_dict[name]
|
||||
# If the tp_descr_get of res is of_get, then call it.
|
||||
if name == '__parent__' or not isinstance(descr, Base):
|
||||
return descr
|
||||
|
||||
if descr is not None:
|
||||
descr_get = getattr(descr, '__get__', None)
|
||||
if descr_get is None:
|
||||
return descr
|
||||
|
||||
return descr_get(self, type(self))
|
||||
|
||||
raise AttributeError(
|
||||
"'%.50s' object has not attribute '%s'",
|
||||
type(self).__name__, name)
|
||||
|
||||
|
||||
def _slotnames(self):
|
||||
slotnames = copy_reg._slotnames(type(self))
|
||||
return [x for x in slotnames
|
||||
if not x.startswith('_p_') and
|
||||
not x.startswith('_v_')]
|
||||
|
||||
|
||||
def Base__getstate__(self):
|
||||
idict = getattr(self, '__dict__', None)
|
||||
slotnames = _slotnames(self)
|
||||
if idict is not None:
|
||||
d = dict([x for x in idict.items()
|
||||
if not x[0].startswith('_p_') and
|
||||
not x[0].startswith('_v_')])
|
||||
else:
|
||||
d = None
|
||||
if slotnames:
|
||||
s = {}
|
||||
for slotname in slotnames:
|
||||
value = getattr(self, slotname, self)
|
||||
if value is not self:
|
||||
s[slotname] = value
|
||||
return d, s
|
||||
return d
|
||||
|
||||
|
||||
def Base__setstate__(self, state):
|
||||
""" See IPersistent.
|
||||
"""
|
||||
try:
|
||||
inst_dict, slots = state
|
||||
except:
|
||||
inst_dict, slots = state, ()
|
||||
idict = getattr(self, '__dict__', None)
|
||||
if inst_dict is not None:
|
||||
if idict is None:
|
||||
raise TypeError('No instance dict') # pragma no cover
|
||||
idict.clear()
|
||||
idict.update(inst_dict)
|
||||
slotnames = _slotnames(self)
|
||||
if slotnames:
|
||||
for k, v in slots.items():
|
||||
setattr(self, k, v)
|
||||
|
||||
|
||||
def Base__reduce__(self):
|
||||
gna = getattr(self, '__getnewargs__', lambda: ())
|
||||
return (copy_reg.__newobj__,
|
||||
(type(self),) + gna(), self.__getstate__())
|
||||
|
||||
|
||||
def Base__new__(cls, *args, **kw):
|
||||
return object.__new__(cls)
|
||||
|
||||
|
||||
Base = ExtensionClass("Base", (object, ), {
|
||||
'__slots__': (),
|
||||
'__getattribute__': Base_getattro,
|
||||
'__getstate__': Base__getstate__,
|
||||
'__setstate__': Base__setstate__,
|
||||
'__reduce__': Base__reduce__,
|
||||
'__new__': Base__new__,
|
||||
})
|
||||
|
||||
_Base = Base
|
||||
|
||||
|
||||
class NoInstanceDictionaryBase(Base):
|
||||
__slots__ = ()
|
||||
|
||||
|
||||
_NoInstanceDictionaryBase = NoInstanceDictionaryBase
|
||||
|
||||
|
||||
if C_EXTENSION: # pragma no cover
|
||||
from ._ExtensionClass import * # NOQA
|
||||
|
||||
# We always want to get the CAPI2 value (if possible) so that
|
||||
# MethodObject and anything else using the PyExtensionClass_Export
|
||||
# macro from ExtensionClass.h doesn't break with an AttributeError
|
||||
try:
|
||||
from ._ExtensionClass import CAPI2
|
||||
except ImportError: # pragma: no cover
|
||||
pass
|
||||
@@ -0,0 +1,53 @@
|
||||
/*****************************************************************************
|
||||
|
||||
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)
|
||||
|
||||
#define HAS_TP_DESCR_GET(ob) 1
|
||||
|
||||
#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)
|
||||
|
||||
#define HAS_TP_DESCR_GET(ob) PyType_HasFeature(Py_TYPE(ob), Py_TPFLAGS_HAVE_CLASS)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,432 @@
|
||||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 2001, 2002 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
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
/* Strings initialized by init_strings() below. */
|
||||
static PyObject *py___slotnames__, *copy_reg_slotnames, *__newobj__;
|
||||
static PyObject *py___getnewargs__, *py___getstate__;
|
||||
|
||||
|
||||
static int
|
||||
pickle_setup(void)
|
||||
{
|
||||
PyObject* copy_reg;
|
||||
|
||||
#define INIT_STRING(S) if (!(py_ ## S = INTERN(#S))) return -1;
|
||||
INIT_STRING(__slotnames__);
|
||||
INIT_STRING(__getnewargs__);
|
||||
INIT_STRING(__getstate__);
|
||||
#undef INIT_STRING
|
||||
|
||||
#ifdef PY3K
|
||||
copy_reg = PyImport_ImportModule("copyreg");
|
||||
#else
|
||||
copy_reg = PyImport_ImportModule("copy_reg");
|
||||
#endif
|
||||
|
||||
if (!copy_reg) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
copy_reg_slotnames = PyObject_GetAttrString(copy_reg, "_slotnames");
|
||||
if (!copy_reg_slotnames)
|
||||
{
|
||||
Py_DECREF(copy_reg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
__newobj__ = PyObject_GetAttrString(copy_reg, "__newobj__");
|
||||
if (!__newobj__)
|
||||
{
|
||||
Py_DECREF(copy_reg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyObject * pickle_slotnames(PyTypeObject *cls);
|
||||
static PyObject * convert_name(PyObject *name);
|
||||
|
||||
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
|
||||
static PyObject *
|
||||
pickle_slotnames(PyTypeObject *cls)
|
||||
{
|
||||
PyObject *slotnames;
|
||||
|
||||
slotnames = PyDict_GetItem(cls->tp_dict, py___slotnames__);
|
||||
if (slotnames)
|
||||
{
|
||||
int n = PyObject_Not(slotnames);
|
||||
if (n < 0)
|
||||
return NULL;
|
||||
if (n)
|
||||
slotnames = Py_None;
|
||||
|
||||
Py_INCREF(slotnames);
|
||||
return slotnames;
|
||||
}
|
||||
|
||||
slotnames = PyObject_CallFunctionObjArgs(copy_reg_slotnames,
|
||||
(PyObject*)cls, NULL);
|
||||
if (slotnames && !(slotnames == Py_None || PyList_Check(slotnames)))
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"copy_reg._slotnames didn't return a list or None");
|
||||
Py_DECREF(slotnames);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return slotnames;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
pickle_copy_dict(PyObject *state)
|
||||
{
|
||||
PyObject *copy, *key, *value;
|
||||
char *ckey;
|
||||
Py_ssize_t pos = 0;
|
||||
|
||||
copy = PyDict_New();
|
||||
if (!copy)
|
||||
return NULL;
|
||||
|
||||
if (!state)
|
||||
return copy;
|
||||
|
||||
while (PyDict_Next(state, &pos, &key, &value))
|
||||
{
|
||||
int is_special;
|
||||
#ifdef PY3K
|
||||
if (key && PyUnicode_Check(key))
|
||||
{
|
||||
PyObject *converted = convert_name(key);
|
||||
ckey = PyBytes_AS_STRING(converted);
|
||||
#else
|
||||
if (key && PyBytes_Check(key))
|
||||
{
|
||||
ckey = PyBytes_AS_STRING(key);
|
||||
#endif
|
||||
is_special = (*ckey == '_' &&
|
||||
(ckey[1] == 'v' || ckey[1] == 'p') &&
|
||||
ckey[2] == '_');
|
||||
#ifdef PY3K
|
||||
Py_DECREF(converted);
|
||||
#endif
|
||||
if (is_special) /* skip volatile and persistent */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (PyObject_SetItem(copy, key, value) < 0)
|
||||
goto err;
|
||||
}
|
||||
|
||||
return copy;
|
||||
err:
|
||||
Py_DECREF(copy);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static char pickle___getstate__doc[] =
|
||||
"Get the object serialization state\n"
|
||||
"\n"
|
||||
"If the object has no assigned slots and has no instance dictionary, then \n"
|
||||
"None is returned.\n"
|
||||
"\n"
|
||||
"If the object has no assigned slots and has an instance dictionary, then \n"
|
||||
"the a copy of the instance dictionary is returned. The copy has any items \n"
|
||||
"with names starting with '_v_' or '_p_' ommitted.\n"
|
||||
"\n"
|
||||
"If the object has assigned slots, then a two-element tuple is returned. \n"
|
||||
"The first element is either None or a copy of the instance dictionary, \n"
|
||||
"as described above. The second element is a dictionary with items \n"
|
||||
"for each of the assigned slots.\n"
|
||||
;
|
||||
|
||||
static PyObject *
|
||||
pickle___getstate__(PyObject *self)
|
||||
{
|
||||
PyObject *slotnames=NULL, *slots=NULL, *state=NULL;
|
||||
PyObject **dictp;
|
||||
int n=0;
|
||||
|
||||
slotnames = pickle_slotnames(Py_TYPE(self));
|
||||
if (!slotnames)
|
||||
return NULL;
|
||||
|
||||
dictp = _PyObject_GetDictPtr(self);
|
||||
if (dictp)
|
||||
state = pickle_copy_dict(*dictp);
|
||||
else
|
||||
{
|
||||
state = Py_None;
|
||||
Py_INCREF(state);
|
||||
}
|
||||
|
||||
if (slotnames != Py_None)
|
||||
{
|
||||
int i;
|
||||
|
||||
slots = PyDict_New();
|
||||
if (!slots)
|
||||
goto end;
|
||||
|
||||
for (i = 0; i < PyList_GET_SIZE(slotnames); i++)
|
||||
{
|
||||
PyObject *name, *value;
|
||||
char *cname;
|
||||
int is_special;
|
||||
|
||||
name = PyList_GET_ITEM(slotnames, i);
|
||||
#ifdef PY3K
|
||||
if (PyUnicode_Check(name))
|
||||
{
|
||||
PyObject *converted = convert_name(name);
|
||||
cname = PyBytes_AS_STRING(converted);
|
||||
#else
|
||||
if (PyBytes_Check(name))
|
||||
{
|
||||
cname = PyBytes_AS_STRING(name);
|
||||
#endif
|
||||
is_special = (*cname == '_' &&
|
||||
(cname[1] == 'v' || cname[1] == 'p') &&
|
||||
cname[2] == '_');
|
||||
#ifdef PY3K
|
||||
Py_DECREF(converted);
|
||||
#endif
|
||||
if (is_special) /* skip volatile and persistent */
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Unclear: Will this go through our getattr hook? */
|
||||
value = PyObject_GetAttr(self, name);
|
||||
if (value == NULL)
|
||||
PyErr_Clear();
|
||||
else
|
||||
{
|
||||
int err = PyDict_SetItem(slots, name, value);
|
||||
Py_DECREF(value);
|
||||
if (err < 0)
|
||||
goto end;
|
||||
n++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (n)
|
||||
state = Py_BuildValue("(NO)", state, slots);
|
||||
|
||||
end:
|
||||
Py_XDECREF(slotnames);
|
||||
Py_XDECREF(slots);
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
static int
|
||||
pickle_setattrs_from_dict(PyObject *self, PyObject *dict)
|
||||
{
|
||||
PyObject *key, *value;
|
||||
Py_ssize_t pos = 0;
|
||||
|
||||
if (!PyDict_Check(dict))
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, "Expected dictionary");
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (PyDict_Next(dict, &pos, &key, &value))
|
||||
{
|
||||
if (PyObject_SetAttr(self, key, value) < 0)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char pickle___setstate__doc[] =
|
||||
"Set the object serialization state\n\n"
|
||||
"The state should be in one of 3 forms:\n\n"
|
||||
"- None\n\n"
|
||||
" Ignored\n\n"
|
||||
"- A dictionary\n\n"
|
||||
" In this case, the object's instance dictionary will be cleared and \n"
|
||||
" updated with the new state.\n\n"
|
||||
"- A two-tuple with a string as the first element. \n\n"
|
||||
" In this case, the method named by the string in the first element will\n"
|
||||
" be called with the second element.\n\n"
|
||||
" This form supports migration of data formats.\n\n"
|
||||
"- A two-tuple with None or a Dictionary as the first element and\n"
|
||||
" with a dictionary as the second element.\n\n"
|
||||
" If the first element is not None, then the object's instance dictionary \n"
|
||||
" will be cleared and updated with the value.\n\n"
|
||||
" The items in the second element will be assigned as attributes.\n"
|
||||
;
|
||||
|
||||
static PyObject *
|
||||
pickle___setstate__(PyObject *self, PyObject *state)
|
||||
{
|
||||
PyObject *slots=NULL;
|
||||
|
||||
if (PyTuple_Check(state))
|
||||
{
|
||||
if (!PyArg_ParseTuple(state, "OO:__setstate__", &state, &slots))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (state != Py_None)
|
||||
{
|
||||
PyObject **dict;
|
||||
PyObject *d_key, *d_value;
|
||||
Py_ssize_t i;
|
||||
|
||||
dict = _PyObject_GetDictPtr(self);
|
||||
|
||||
if (!dict)
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"this object has no instance dictionary");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!*dict)
|
||||
{
|
||||
*dict = PyDict_New();
|
||||
if (!*dict)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyDict_Clear(*dict);
|
||||
|
||||
i = 0;
|
||||
while (PyDict_Next(state, &i, &d_key, &d_value)) {
|
||||
/* normally the keys for instance attributes are
|
||||
interned. we should try to do that here. */
|
||||
if (NATIVE_CHECK_EXACT(d_key)) {
|
||||
Py_INCREF(d_key);
|
||||
INTERN_INPLACE(&d_key);
|
||||
Py_DECREF(d_key);
|
||||
}
|
||||
if (PyObject_SetItem(*dict, d_key, d_value) < 0)
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (slots && pickle_setattrs_from_dict(self, slots) < 0)
|
||||
return NULL;
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static char pickle___reduce__doc[] =
|
||||
"Reduce an object to contituent parts for serialization\n"
|
||||
;
|
||||
|
||||
static PyObject *
|
||||
pickle___reduce__(PyObject *self)
|
||||
{
|
||||
PyObject *args=NULL, *bargs=NULL, *state=NULL, *getnewargs=NULL;
|
||||
int l, i;
|
||||
|
||||
getnewargs = PyObject_GetAttr(self, py___getnewargs__);
|
||||
if (getnewargs)
|
||||
{
|
||||
bargs = PyObject_CallFunctionObjArgs(getnewargs, NULL);
|
||||
Py_DECREF(getnewargs);
|
||||
if (!bargs)
|
||||
return NULL;
|
||||
l = PyTuple_Size(bargs);
|
||||
if (l < 0)
|
||||
goto end;
|
||||
}
|
||||
else
|
||||
{
|
||||
PyErr_Clear();
|
||||
l = 0;
|
||||
}
|
||||
|
||||
args = PyTuple_New(l+1);
|
||||
if (args == NULL)
|
||||
goto end;
|
||||
|
||||
Py_INCREF(Py_TYPE(self));
|
||||
PyTuple_SET_ITEM(args, 0, (PyObject*)(Py_TYPE(self)));
|
||||
for (i = 0; i < l; i++)
|
||||
{
|
||||
Py_INCREF(PyTuple_GET_ITEM(bargs, i));
|
||||
PyTuple_SET_ITEM(args, i+1, PyTuple_GET_ITEM(bargs, i));
|
||||
}
|
||||
|
||||
state = PyObject_CallMethodObjArgs(self, py___getstate__, NULL);
|
||||
if (!state)
|
||||
goto end;
|
||||
|
||||
state = Py_BuildValue("(OON)", __newobj__, args, state);
|
||||
|
||||
end:
|
||||
Py_XDECREF(bargs);
|
||||
Py_XDECREF(args);
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
/* convert_name() returns a new reference to a string name
|
||||
or sets an exception and returns NULL.
|
||||
*/
|
||||
|
||||
static PyObject *
|
||||
convert_name(PyObject *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);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (!PyBytes_Check(name))
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, "attribute name must be a string");
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
Py_INCREF(name);
|
||||
return name;
|
||||
}
|
||||
|
||||
#define PICKLE_GETSTATE_DEF \
|
||||
{"__getstate__", (PyCFunction)pickle___getstate__, METH_NOARGS, \
|
||||
pickle___getstate__doc},
|
||||
|
||||
#define PICKLE_SETSTATE_DEF \
|
||||
{"__setstate__", (PyCFunction)pickle___setstate__, METH_O, \
|
||||
pickle___setstate__doc},
|
||||
|
||||
#define PICKLE_GETNEWARGS_DEF
|
||||
|
||||
#define PICKLE_REDUCE_DEF \
|
||||
{"__reduce__", (PyCFunction)pickle___reduce__, METH_NOARGS, \
|
||||
pickle___reduce__doc},
|
||||
|
||||
#define PICKLE_METHODS PICKLE_GETSTATE_DEF PICKLE_SETSTATE_DEF \
|
||||
PICKLE_GETNEWARGS_DEF PICKLE_REDUCE_DEF
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user