Commit 5438ceaf authored by Jason Madden's avatar Jason Madden

Add support for PyPy and Python 3.4 using a pure-python port of the C extension code.

All tests continue to pass under 2.6 and 2.7.

The pure-python code currently raises AttributeError instead of RuntimeError in the
recursive-parent cases, though I'm not sure why that is. There may also be some issues
with the proxying of some methods, but those aren't covered by current test cases.
parent 48c7341c
......@@ -3,6 +3,8 @@ sudo: false
python:
- 2.6
- 2.7
- 3.4
- pypy
install:
- python bootstrap.py
- bin/buildout
......
Changelog
=========
4.2 (unreleased)
----------------
- Add support for PyPy and Python 3.
4.1 (2014-12-18)
----------------
......@@ -62,7 +67,7 @@ Changelog
- Add ``aq_explicit`` to ``IAcquisitionWrapper``.
- Fixed bug: ``unicode(wrapped)`` was not calling a ``__unicode__``
- Fixed bug: ``unicode(wrapped)`` was not calling a ``__unicode__``
method on wrapped objects.
2.13.5 (2010-09-29)
......@@ -133,7 +138,7 @@ Changelog
2.12.2 (2009-08-02)
-------------------
- Fixed 64-bit compatibility issues for Python 2.5.x / 2.6.x. See
- Fixed 64-bit compatibility issues for Python 2.5.x / 2.6.x. See
http://www.python.org/dev/peps/pep-0353/ for details.
2.12.1 (2009-04-15)
......
......@@ -34,7 +34,7 @@ class. For example::
>>> class A(Acquisition.Implicit):
... def report(self):
... print self.color
... print(self.color)
...
>>> a = A()
>>> c = C()
......@@ -107,7 +107,7 @@ When explicit acquisition is used, attributes are not automatically
obtained from the environment. Instead, the method aq_acquire must be
used. For example::
>>> print c.a.aq_acquire('color')
>>> print(c.a.aq_acquire('color'))
red
To support explicit acquisition, your class should inherit from the
......@@ -178,7 +178,7 @@ Here's an example::
>>> class E(Explicit, HandyForTesting): pass
...
>>> class Nice(HandyForTesting):
... isNice = 1
... isNice = 1
... def __str__(self):
... return HandyForTesting.__str__(self)+' and I am nice!'
... __repr__ = __str__
......@@ -192,7 +192,7 @@ Here's an example::
>>> def find_nice(self, ancestor, name, object, extra):
... return hasattr(object,'isNice') and object.isNice
>>> print a.b.c.aq_acquire('p', find_nice)
>>> print(a.b.c.aq_acquire('p', find_nice))
spam(Nice) and I am nice!
The filtered acquisition in the last line skips over the first
......@@ -221,7 +221,7 @@ method. For example::
>>> a = C()
>>> b = C()
>>> a.color = "red"
>>> print b.__of__(a).color
>>> print(b.__of__(a).color)
red
In this case, ``a`` does not contain ``b``, but it is put in ``b``'s
......@@ -241,7 +241,7 @@ acquisition context that includes non-container objects::
>>> a.b.color = "red"
>>> a.x = C("x")
>>> print a.b.x.color
>>> print(a.b.x.color)
red
Even though ``b`` does not contain ``x``, ``x`` can acquire the color
......@@ -262,7 +262,7 @@ If in the example above suppose both a and b have an color attribute::
>>> a.b.color = "red"
>>> a.x = C("x")
>>> print a.b.x.color
>>> print(a.b.x.color)
green
Why does ``a.b.x.color`` acquire color from ``a`` and not from ``b``?
......
......@@ -14,6 +14,8 @@
"""Setup for the Acquisition distribution
"""
import os
import platform
import sys
from setuptools import setup, find_packages, Extension
with open('README.rst') as f:
......@@ -22,6 +24,21 @@ with open('README.rst') as f:
with open('CHANGES.rst') as f:
CHANGES = f.read()
# PyPy won't build the extension.
py_impl = getattr(platform, 'python_implementation', lambda: None)
is_pypy = py_impl() == 'PyPy'
is_pure = 'PURE_PYTHON' in os.environ
py3k = sys.version_info >= (3, )
if is_pypy or is_pure or py3k:
ext_modules = []
else:
ext_modules=[Extension("Acquisition._Acquisition",
[os.path.join('src', 'Acquisition',
'_Acquisition.c')],
include_dirs=['include', 'src']),
]
setup(
name='Acquisition',
version='4.1',
......@@ -41,16 +58,15 @@ setup(
"License :: OSI Approved :: Zope Public License",
"Operating System :: OS Independent",
"Programming Language :: Python",
"Programming Language :: Python :: 2 :: Only",
"Programming Language :: Python :: 2",
"Programming Language :: Python :: 2.6",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.4",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy",
],
ext_modules=[Extension("Acquisition._Acquisition",
[os.path.join('src', 'Acquisition',
'_Acquisition.c')],
include_dirs=['include', 'src']),
],
ext_modules=ext_modules,
install_requires=[
'ExtensionClass >= 4.1a1',
'zope.interface',
......
This diff is collapsed.
##############################################################################
#
# 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.
#
##############################################################################
"""Taken from zope.proxy to support acquisition wrappers.
"""
import operator
import pickle
import sys
import ExtensionClass
_MARKER = object()
class PyProxyBase(ExtensionClass.Base):
"""Reference implementation.
"""
__slots__ = ('_obj', )
def __new__(cls, value):
inst = super(PyProxyBase, cls).__new__(cls)
inst._obj = value
return inst
def __init__(self, obj):
self._obj = obj
def __call__(self, *args, **kw):
return self._obj(*args, **kw)
def __repr__(self):
return repr(self._obj)
def __str__(self):
return str(self._obj)
def __unicode__(self):
return unicode(self._obj)
def __reduce__(self): #pragma NO COVER (__reduce_ex__ prevents normal)
raise pickle.PicklingError
def __reduce_ex__(self, proto):
raise pickle.PicklingError
# Rich comparison protocol
def __lt__(self, other):
return self._obj < other
def __le__(self, other):
return self._obj <= other
def __eq__(self, other):
return self._obj == other
def __ne__(self, other):
return self._obj != other
def __gt__(self, other):
return self._obj > other
def __ge__(self, other):
return self._obj >= other
def __nonzero__(self):
return bool(self._obj)
__bool__ = __nonzero__ # Python3 compat
def __hash__(self):
return hash(self._obj)
# Attribute protocol
# Left for the _Wrapper subclass
# Container protocols
def __len__(self):
return len(self._obj)
def __getitem__(self, key):
if isinstance(key, slice):
if isinstance(self._obj, (list, tuple)):
return self._obj[key]
start, stop = key.start, key.stop
if start is None:
start = 0
if start < 0:
start += len(self._obj)
if stop is None:
stop = getattr(sys, 'maxint', None) # PY2
elif stop < 0:
stop += len(self._obj)
if hasattr(operator, 'setslice'): # PY2
return operator.getslice(self._obj, start, stop)
return self._obj[start:stop]
return self._obj[key]
def __setitem__(self, key, value):
self._obj[key] = value
def __delitem__(self, key):
del self._obj[key]
def __iter__(self):
# This handles a custom __iter__ and generator support at the same time.
return iter(self._obj)
def next(self):
# Called when we wrap an iterator itself.
return self._obj.next()
def __next__(self): #pragma NO COVER Python3
return self._obj.__next__()
# Python 2.7 won't let the C wrapper support __reversed__ :(
#def __reversed__(self):
# return reversed(self._obj)
def __contains__(self, item):
return item in self._obj
# Numeric protocol: unary operators
def __neg__(self):
return -self._obj
def __pos__(self):
return +self._obj
def __abs__(self):
return abs(self._obj)
def __invert__(self):
return ~self._obj
# Numeric protocol: unary conversions
def __complex__(self):
return complex(self._obj)
def __int__(self):
return int(self._obj)
def __long__(self):
return long(self._obj)
def __float__(self):
return float(self._obj)
def __oct__(self):
return oct(self._obj)
def __hex__(self):
return hex(self._obj)
def __index__(self):
return operator.index(self._obj)
# Numeric protocol: binary coercion
def __coerce__(self, other):
left, right = coerce(self._obj, other)
if left == self._obj and type(left) is type(self._obj):
left = self
return left, right
# Numeric protocol: binary arithmetic operators
def __add__(self, other):
return self._obj + other
def __sub__(self, other):
return self._obj - other
def __mul__(self, other):
return self._obj * other
def __floordiv__(self, other):
return self._obj // other
def __truediv__(self, other): #pragma NO COVER
# Only one of __truediv__ and __div__ is meaningful at any one time.
return self._obj / other
def __div__(self, other): #pragma NO COVER
# Only one of __truediv__ and __div__ is meaningful at any one time.
return self._obj / other
def __mod__(self, other):
return self._obj % other
def __divmod__(self, other):
return divmod(self._obj, other)
def __pow__(self, other, modulus=None):
if modulus is None:
return pow(self._obj, other)
return pow(self._obj, other, modulus)
def __radd__(self, other):
return other + self._obj
def __rsub__(self, other):
return other - self._obj
def __rmul__(self, other):
return other * self._obj
def __rfloordiv__(self, other):
return other // self._obj
def __rtruediv__(self, other): #pragma NO COVER
# Only one of __rtruediv__ and __rdiv__ is meaningful at any one time.
return other / self._obj
def __rdiv__(self, other): #pragma NO COVER
# Only one of __rtruediv__ and __rdiv__ is meaningful at any one time.
return other / self._obj
def __rmod__(self, other):
return other % self._obj
def __rdivmod__(self, other):
return divmod(other, self._obj)
def __rpow__(self, other, modulus=None):
if modulus is None:
return pow(other, self._obj)
# We can't actually get here, because we can't lie about our type()
return pow(other, self._obj, modulus) #pragma NO COVER
# Numeric protocol: binary bitwise operators
def __lshift__(self, other):
return self._obj << other
def __rshift__(self, other):
return self._obj >> other
def __and__(self, other):
return self._obj & other
def __xor__(self, other):
return self._obj ^ other
def __or__(self, other):
return self._obj | other
def __rlshift__(self, other):
return other << self._obj
def __rrshift__(self, other):
return other >> self._obj
def __rand__(self, other):
return other & self._obj
def __rxor__(self, other):
return other ^ self._obj
def __ror__(self, other):
return other | self._obj
# Numeric protocol: binary in-place operators
def __iadd__(self, other):
self._obj += other
return self
def __isub__(self, other):
self._obj -= other
return self
def __imul__(self, other):
self._obj *= other
return self
def __idiv__(self, other): #pragma NO COVER
# Only one of __itruediv__ and __idiv__ is meaningful at any one time.
self._obj /= other
return self
def __itruediv__(self, other): #pragma NO COVER
# Only one of __itruediv__ and __idiv__ is meaningful at any one time.
self._obj /= other
return self
def __ifloordiv__(self, other):
self._obj //= other
return self
def __imod__(self, other):
self._obj %= other
return self
def __ilshift__(self, other):
self._obj <<= other
return self
def __irshift__(self, other):
self._obj >>= other
return self
def __iand__(self, other):
self._obj &= other
return self
def __ixor__(self, other):
self._obj ^= other
return self
def __ior__(self, other):
self._obj |= other
return self
def __ipow__(self, other, modulus=None):
if modulus is None:
self._obj **= other
else: #pragma NO COVER
# There is no syntax which triggers in-place pow w/ modulus
self._obj = pow(self._obj, other, modulus)
return self
This diff is collapsed.
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