Skip to content

Commit

Permalink
Update the handling of PURE_PYTHON to match zope.interface and persis…
Browse files Browse the repository at this point in the history
…tent

Also stop using the deprecated, untested,
``zope.interafce.declarations.ObjectSpecification`` function in favor
of ``Provides``.
  • Loading branch information
jamadden committed Apr 1, 2020
1 parent 52279a6 commit 8a59227
Show file tree
Hide file tree
Showing 11 changed files with 315 additions and 139 deletions.
6 changes: 6 additions & 0 deletions .coveragerc
Expand Up @@ -8,3 +8,9 @@ exclude_lines =
raise NotImplementedError
self.fail
raise AssertionError

[paths]
source =
src/
.tox/*/lib/python*/site-packages/
.tox/pypy*/site-packages/
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -10,6 +10,7 @@ __pycache__
*.so
.tox
.coverage
.coverage.*
htmlcov/
nosetests.xml
coverage.xml
Expand Down
19 changes: 14 additions & 5 deletions .travis.yml
Expand Up @@ -5,20 +5,26 @@ env:
TWINE_USERNAME: zope.wheelbuilder
TWINE_PASSWORD:
secure: "G1ORcUIV439Iws2toGhxPvYvQKQt6L1wyXfIMspz2xtjJvQ2D1XrqK8dRYyQ0YaGLY/OAI8BrEdTp/l7jrhiG0gXMeAs0k1KFbp7ATahcVT8rWOzvcLGMAiYRVloQ3rz5x5HjMm0CWpDjo1MAeJMmesyq8RlmYzaMu4aw1mBd/Y="
jobs:
# We want to require the C extensions to build and function
# everywhere (except where we specifically opt-out)
- PURE_PYTHON: 0
- PURE_PYTHON: 1

python:
- 2.7
- 3.5
- 3.6
- 3.7
- 3.8
- pypy
- pypy3

jobs:
include:
- name: "Python: 2.7, pure (no C extensions)"
python: 2.7
# Don't test C extensions on PyPy.
- python: pypy
env: PURE_PYTHON=1

- python: pypy3
env: PURE_PYTHON=1

# manylinux wheel builds
Expand Down Expand Up @@ -73,7 +79,10 @@ install:
- pip install -U pip setuptools
- pip install -U coverage coveralls
- pip install -U -e .[test]
- if [[ $PURE_PYTHON ]]; then pip install -U -e .[zodb,zcml]; fi
- |
if [[ "$PURE_PYTHON" == "0" || ${TRAVIS_PYTHON_VERSION} == pypy* ]]; then
pip install -U -e .[zodb,zcml];
fi
script:
- python --version
Expand Down
11 changes: 8 additions & 3 deletions CHANGES.rst
Expand Up @@ -2,10 +2,15 @@
Changes
=========

4.3.1 (unreleased)
4.4.0 (unreleased)
==================

- Nothing changed yet.
- Support the ``PURE_PYTHON`` environment variable at runtime instead
of just at wheel build time. A value of 0 forces the C extensions to
be used failing if they aren't present. Any other value forces the
Python implementation to be used, ignoring the C extensions.

- Drop support for the deprecated ``python setup.py test`` command.


4.3.0 (2019-11-11)
Expand Down Expand Up @@ -73,7 +78,7 @@
4.1.0 (2015-05-22)
==================

- Make ``zope.container._proxy.PytContainedProxyBase`` inherit
- Make ``zope.container._proxy.PyContainedProxyBase`` inherit
directly from ``zope.proxy.AbstractProxyBase`` as well as
``persistent.Persistent``, removing a bunch of redundant code, and
fixing bugs in interaction with pure-Python persistence. See:
Expand Down
53 changes: 17 additions & 36 deletions setup.py
Expand Up @@ -19,7 +19,6 @@
"""Setup for zope.container package
"""
import os
import platform

from setuptools import setup, find_packages, Extension

Expand All @@ -29,39 +28,14 @@ def read(*rnames):
return f.read()


def alltests():
import sys
import unittest
# use the zope.testrunner machinery to find all the
# test suites we've put under ourselves
import zope.testrunner.find
import zope.testrunner.options
here = os.path.abspath(os.path.join(os.path.dirname(__file__), 'src'))
args = sys.argv[:]
defaults = ["--test-path", here]
options = zope.testrunner.options.get_options(args, defaults)
suites = list(zope.testrunner.find.find_suites(options))
return unittest.TestSuite(suites)


# PyPy cannot correctly build the C optimizations, and even if it
# could they would be anti-optimizations (the C extension
# compatibility layer is known-slow, and defeats JIT opportunities).
py_impl = getattr(platform, 'python_implementation', lambda: None)
pure_python = os.environ.get('PURE_PYTHON', False)
is_pypy = py_impl() == 'PyPy'

if pure_python or is_pypy:
ext_modules = []
else:
ext_modules = [
Extension(
"zope.container._zope_container_contained",
[os.path.join("src", "zope", "container",
"_zope_container_contained.c")],
include_dirs=['include'],
),
]
ext_modules = [
Extension(
"zope.container._zope_container_contained",
[os.path.join("src", "zope", "container",
"_zope_container_contained.c")],
include_dirs=['include'],
),
]

install_requires = [
'BTrees',
Expand Down Expand Up @@ -117,7 +91,7 @@ def alltests():
'Topic :: Internet :: WWW/HTTP',
'Framework :: Zope :: 3',
],
url='http://github.com/zopefoundation/zope.container',
url='https://github.com/zopefoundation/zope.container',
license='ZPL 2.1',
packages=find_packages('src'),
package_dir={'': 'src'},
Expand Down Expand Up @@ -146,7 +120,14 @@ def alltests():
'zope.testing',
'zope.testrunner',
],
test_suite='__main__.alltests',
include_package_data=True,
zip_safe=False,
python_requires=', '.join([
'>=2.7',
'!=3.0.*',
'!=3.1.*',
'!=3.2.*',
'!=3.3.*',
'!=3.4.*',
]),
)
39 changes: 25 additions & 14 deletions src/zope/container/_proxy.py
Expand Up @@ -13,31 +13,34 @@
##############################################################################

from zope.proxy import AbstractPyProxyBase

_MARKER = object()
from zope.container._util import use_c_impl

from persistent import Persistent


_MARKER = object()

def _special_name(name):
"attribute names we delegate to Persistent for"
return (name.startswith('_Persistent')
or name.startswith('_p_')
or name.startswith('_v_')
or name in PyContainedProxyBase.__slots__)
or name in ContainedProxyBase.__slots__)

class PyContainedProxyBase(AbstractPyProxyBase, Persistent):
@use_c_impl
class ContainedProxyBase(AbstractPyProxyBase, Persistent):
"""Persistent proxy
"""
__slots__ = ('_wrapped', '__parent__', '__name__', '__weakref__')

def __new__(cls, obj):
inst = super(PyContainedProxyBase, cls).__new__(cls, obj)
inst = super(ContainedProxyBase, cls).__new__(cls, obj)
inst.__parent__ = None
inst.__name__ = None
return inst

def __init__(self, obj):
super(PyContainedProxyBase, self).__init__(obj)
super(ContainedProxyBase, self).__init__(obj)
self.__parent__ = None
self.__name__ = None

Expand All @@ -57,7 +60,7 @@ def __getstate__(self):
return (self.__parent__, self.__name__)

def __getnewargs__(self):
return self._wrapped,
return (self._wrapped,)

def _p_invalidate(self):
# The superclass wants to clear the __dict__, which
Expand All @@ -80,28 +83,36 @@ def __getattribute__(self, name):
# activated
return Persistent.__getattribute__(self, name)

if name in ('__reduce__', '__reduce_ex__', '__getstate__', '__setstate__', '__getnewargs__'):
if name in (
'__reduce__',
'__reduce_ex__',
'__getstate__',
'__setstate__',
'__getnewargs__',
):
return object.__getattribute__(self, name)

return super(PyContainedProxyBase,self).__getattribute__(name)
return super(ContainedProxyBase, self).__getattribute__(name)

def __setattr__(self, name, value):
if _special_name(name):
# Our own attribute names need to go directly to Persistent
# so that _p_changed gets set, in addition to the _p values themselves
return Persistent.__setattr__(self, name, value)

return super(PyContainedProxyBase, self).__setattr__(name, value)
return super(ContainedProxyBase, self).__setattr__(name, value)


def py_getProxiedObject(obj):
if isinstance(obj, PyContainedProxyBase):
@use_c_impl
def getProxiedObject(obj):
if isinstance(obj, ContainedProxyBase):
return obj._wrapped
return obj


def py_setProxiedObject(obj, new_value):
if not isinstance(obj, PyContainedProxyBase):
@use_c_impl
def setProxiedObject(obj, new_value):
if not isinstance(obj, ContainedProxyBase):
raise TypeError('Not a proxy')
old, obj._wrapped = obj._wrapped, new_value
return old

0 comments on commit 8a59227

Please sign in to comment.