diff --git a/.travis.yml b/.travis.yml index 809b6e1..4022aa0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,7 +26,10 @@ install: - if [[ -z "$MINIMAL" ]]; then pip install -U -e ".[test,docs]"; fi script: - - coverage run -m zope.testrunner --test-path=src +# Temporary workaround. Pending +# https://github.com/zopefoundation/zope.security/issues/71 +# avoid zope.testrunner. + - coverage run -m unittest -s src - if [[ -z "$MINIMAL" ]]; then sphinx-build -b html -d docs/_build/doctrees docs docs/_build/html; fi - if [[ -z "$MINIMAL" ]]; then coverage run -a -m sphinx -b doctest -d docs/_build/doctrees docs docs/_build/doctest; fi diff --git a/docs/conf.py b/docs/conf.py index 8275192..b41fa9c 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -12,11 +12,26 @@ # serve to show the default. import sys, os +# We get better doc strings and signatures from the Python components. +# XXX: Except CPython 2.7 produces some warnings from CFFI with persistent 4.6.3: +# From callback for ffi.gc : +# Traceback (most recent call last): +# File "//.tox/docs/lib/python2.7/site-packages/persistent/picklecache.py", line 105, in cleanup_hook +# oid = self._addr_to_oid.pop(cdata.pobj_id, None) +# AttributeError: '_WeakValueDictionary' object has no attribute '_addr_to_oid' +#os.environ['PURE_PYTHON'] = "1" + +# Prior to https://github.com/zopefoundation/zope.security/issues/71, +# zope.security cannot be imported in zope.interface's strict IRO mode. +os.environ['ZOPE_INTERFACE_STRICT_IRO'] = "0" # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. #sys.path.insert(0, os.path.abspath('.')) +sys.path.append(os.path.abspath('../src')) +import pkg_resources +rqmt = pkg_resources.require('zope.component')[0] # -- General configuration ----------------------------------------------------- @@ -54,9 +69,9 @@ # built documents. # # The short X.Y version. -version = '4.3' +version = '%s.%s' % tuple(map(int, rqmt.version.split('.')[:2])) # The full version, including alpha/beta/rc tags. -release = '4.3' +release = rqmt.version # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -246,3 +261,8 @@ # How to display URL addresses: 'footnote', 'no', or 'inline'. #texinfo_show_urls = 'footnote' +intersphinx_mapping = { + 'https://docs.python.org/': None, + 'https://zopeinterface.readthedocs.io/': None, + 'https://zopesecurity.readthedocs.io/': None, +} diff --git a/src/zope/component/_compat.py b/src/zope/component/_compat.py index 42057f3..3fe42b9 100644 --- a/src/zope/component/_compat.py +++ b/src/zope/component/_compat.py @@ -32,3 +32,19 @@ PYTHON3 = True PYTHON2 = False + + +# Prior to https://github.com/zopefoundation/zope.security/issues/71 +# zope.security cannot be imported if zope.interface is enforcing +# strict resolution orders. But because zope.security has a dependency +# on this library, and older versions of this library also have problems +# with strict resolution orders, we have a chicken-and-egg scenario. In the +# interim, our only choice is to skip it. (But we don't want a hard dependency +# on zope.interface 5.0, so we do a conditional import.) +ZOPE_SECURITY_NOT_AVAILABLE_EX = (ImportError,) +try: + from zope.interface.ro import InconsistentResolutionOrderError +except ImportError: + pass +else: + ZOPE_SECURITY_NOT_AVAILABLE_EX += (InconsistentResolutionOrderError,) diff --git a/src/zope/component/hooks.py b/src/zope/component/hooks.py index 2f14c77..466d092 100644 --- a/src/zope/component/hooks.py +++ b/src/zope/component/hooks.py @@ -18,9 +18,11 @@ import contextlib import threading +from zope.component._compat import ZOPE_SECURITY_NOT_AVAILABLE_EX + try: from zope.security.proxy import removeSecurityProxy -except ImportError: #pragma NO COVER +except ZOPE_SECURITY_NOT_AVAILABLE_EX: # pragma: no cover def removeSecurityProxy(x): return x diff --git a/src/zope/component/security.py b/src/zope/component/security.py index 5c9707e..7b8023d 100644 --- a/src/zope/component/security.py +++ b/src/zope/component/security.py @@ -16,13 +16,29 @@ from zope.interface import providedBy from zope.proxy import ProxyBase from zope.proxy import getProxiedObject -from zope.security.adapter import LocatingTrustedAdapterFactory -from zope.security.adapter import LocatingUntrustedAdapterFactory -from zope.security.adapter import TrustedAdapterFactory -from zope.security.checker import Checker -from zope.security.checker import CheckerPublic -from zope.security.checker import InterfaceChecker -from zope.security.proxy import Proxy + +from zope.component._compat import ZOPE_SECURITY_NOT_AVAILABLE_EX + +try: + from zope.security.adapter import LocatingTrustedAdapterFactory + from zope.security.adapter import LocatingUntrustedAdapterFactory + from zope.security.adapter import TrustedAdapterFactory + from zope.security.checker import Checker + from zope.security.checker import CheckerPublic + from zope.security.checker import InterfaceChecker + from zope.security.proxy import Proxy +except ZOPE_SECURITY_NOT_AVAILABLE_EX: # pragma: no cover + def _no_security(*args, **kw): + raise TypeError( + "security proxied components are not " + "supported because zope.security is not available") + + LocatingTrustedAdapterFactory = _no_security + LocatingUntrustedAdapterFactory = _no_security + TrustedAdapterFactory = _no_security + Checker = _no_security + CheckerPublic = _no_security + InterfaceChecker = _no_security PublicPermission = 'zope.Public' @@ -42,7 +58,7 @@ def _checker(_context, permission, allowed_interface, allowed_attributes): if permission == PublicPermission: permission = CheckerPublic - require={} + require = {} if allowed_attributes: for name in allowed_attributes: require[name] = permission @@ -63,7 +79,7 @@ def proxify(ob, checker=None, provides=None, permission=None): if checker is None: if provides is None or permission is None: raise ValueError('Required arguments: ' - 'checker or both provides and permissions') + 'checker or both provides and permissions') if permission == PublicPermission: permission = CheckerPublic checker = InterfaceChecker(provides, permission) diff --git a/src/zope/component/tests/__init__.py b/src/zope/component/tests/__init__.py index bc508bb..724fa59 100644 --- a/src/zope/component/tests/__init__.py +++ b/src/zope/component/tests/__init__.py @@ -1,9 +1,11 @@ import unittest def skipIfNoSecurity(testfunc): + from zope.component._compat import ZOPE_SECURITY_NOT_AVAILABLE_EX + try: import zope.security - except ImportError: # pragma: no cover + except ZOPE_SECURITY_NOT_AVAILABLE_EX: # pragma: no cover return unittest.skip("zope.security not installed")(testfunc) return testfunc diff --git a/src/zope/component/tests/test___init__.py b/src/zope/component/tests/test___init__.py index f9553e6..2ffda83 100644 --- a/src/zope/component/tests/test___init__.py +++ b/src/zope/component/tests/test___init__.py @@ -82,11 +82,3 @@ def __init__(self, context): adapted = IFoo(ctx) self.assertTrue(adapted.__class__ is Baz) self.assertTrue(adapted.context is ctx) - - - -def test_suite(): - return unittest.TestSuite(( - unittest.makeSuite(Test_package), - unittest.makeSuite(Test_Interface_call), - )) diff --git a/src/zope/component/tests/test_event.py b/src/zope/component/tests/test_event.py index 2bede84..c6d93ca 100644 --- a/src/zope/component/tests/test_event.py +++ b/src/zope/component/tests/test_event.py @@ -55,11 +55,3 @@ def __init__(self, object): event = _ObjectEvent(context) objectEventNotify(event) self.assertEqual(_adapted, [(context, event)]) - - - -def test_suite(): - return unittest.TestSuite(( - unittest.makeSuite(Test_dispatch), - unittest.makeSuite(Test_objectEventNotify), - )) diff --git a/src/zope/component/tests/test_hooks.py b/src/zope/component/tests/test_hooks.py index 8242726..f588005 100644 --- a/src/zope/component/tests/test_hooks.py +++ b/src/zope/component/tests/test_hooks.py @@ -336,17 +336,3 @@ def __enter__(self): def __exit__(self, exc_type, exc_val, exc_tb): for key, value in self.to_restore.items(): setattr(self.module, key, value) - - -def test_suite(): - return unittest.TestSuite(( - unittest.makeSuite(Test_read_property), - unittest.makeSuite(SiteInfoTests), - unittest.makeSuite(Test_setSite), - unittest.makeSuite(Test_getSite), - unittest.makeSuite(Test_site), - unittest.makeSuite(Test_getSiteManager), - unittest.makeSuite(Test_adapter_hook), - unittest.makeSuite(Test_setHooks), - unittest.makeSuite(Test_resetHooks), - )) diff --git a/src/zope/component/tests/test_interface.py b/src/zope/component/tests/test_interface.py index e1d1711..e7580e0 100644 --- a/src/zope/component/tests/test_interface.py +++ b/src/zope/component/tests/test_interface.py @@ -380,17 +380,3 @@ class IFoo(Interface): gsm.registerUtility(IFoo, IInterface, 'foo') self.assertEqual(self._callFUT(object(), IFoo), 'zope.component.tests.test_interface.IFoo') - - -def test_suite(): - return unittest.TestSuite(( - unittest.makeSuite(Test_provideInterface), - unittest.makeSuite(Test_getInterface), - unittest.makeSuite(Test_queryInterface), - unittest.makeSuite(Test_searchInterface), - unittest.makeSuite(Test_searchInterfaceIds), - unittest.makeSuite(Test_searchInterfaceUtilities), - unittest.makeSuite(Test_getInterfaceAllDocs), - unittest.makeSuite(Test_nameToInterface), - unittest.makeSuite(Test_interfaceToName), - )) diff --git a/src/zope/component/zcml.py b/src/zope/component/zcml.py index f381767..bfaab20 100644 --- a/src/zope/component/zcml.py +++ b/src/zope/component/zcml.py @@ -26,16 +26,18 @@ from zope.schema import TextLine from zope.component._api import getSiteManager +from zope.component._compat import ZOPE_SECURITY_NOT_AVAILABLE_EX from zope.component._declaration import adaptedBy, getName from zope.component.interface import provideInterface try: from zope.security.zcml import Permission -except ImportError: #pragma NO COVER +except ZOPE_SECURITY_NOT_AVAILABLE_EX: # pragma: no cover def _no_security(*args, **kw): - raise ConfigurationError("security proxied components are not " + raise ConfigurationError( + "security proxied components are not " "supported because zope.security is not available") - _checker = proxify = protectedFactory = security =_no_security + _checker = proxify = protectedFactory = security = _no_security Permission = TextLine else: from zope.component.security import _checker @@ -104,9 +106,9 @@ class IAdapterDirective(Interface): description=_("This should be a list of interfaces or classes"), required=False, value_type=GlobalObject( - missing_value=object(), - ), - ) + missing_value=object(), + ), + ) permission = Permission( title=_("Permission"), diff --git a/tox.ini b/tox.ini index 2264788..1be7c66 100644 --- a/tox.ini +++ b/tox.ini @@ -13,39 +13,19 @@ deps = .[test] [testenv] +usedevelop = true deps = - {[fulldeps]deps} + !minimal: {[fulldeps]deps} + minimal: {[mindeps]deps} .[docs] commands = - zope-testrunner --test-path=src - sphinx-build -b doctest -d {envdir}/.cache/doctrees docs {envdir}/.cache/doctest +# Temporary workaround. Avoid zope.testrunner pending +# IRO fixes in zope.security. https://github.com/zopefoundation/zope.security/issues/71 + python -m unittest discover -s src + !minimal: sphinx-build -b doctest -d {envdir}/.cache/doctrees docs {envdir}/.cache/doctest setenv = ZOPE_INTERFACE_STRICT_IRO = 1 - -[testenv:py27-minimal] -basepython = - python2.7 -deps = - {[mindeps]deps} -commands = - zope-testrunner --test-path=src - - -[testenv:py35-pure] -basepython = - python3.5 -setenv = - {[testenv]setenv} - PURE_PYTHON = 1 - PIP_CACHE_DIR = {envdir}/.cache - -[testenv:py27-pure] -basepython = - python3.4 -setenv = - {[testenv]setenv} - PURE_PYTHON = 1 - PIP_CACHE_DIR = {envdir}/.cache + pure: PURE_PYTHON = 1 [testenv:docs] basepython = @@ -56,14 +36,16 @@ commands = deps = {[fulldeps]deps} .[docs] +setenv = + ZOPE_INTERFACE_STRICT_IRO = 0 [testenv:coverage] basepython = - python3.6 + python3 usedevelop = true commands = - coverage run -m zope.testrunner --test-path=src - coverage run -a -m sphinx.cmd.build -b doctest -d docs/_build/doctrees docs docs/_build/doctest + coverage run -m unittest discover -s src + coverage run -a -m sphinx -b doctest -d docs/_build/doctrees docs docs/_build/doctest coverage report --fail-under=100 deps = {[testenv]deps}