diff options
author | Jason Madden <jamadden@gmail.com> | 2020-03-22 09:50:40 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-03-22 09:50:40 -0500 |
commit | 55e6c06eb8ad553dbd457a1177ac8b6734a35456 (patch) | |
tree | a812c20c7dc09e1f66881909fbfb7011c1d120da | |
parent | 0194dd6143049d319774dd56b53ef21384c6ef27 (diff) | |
parent | c2cf3f6f4fad8b5ab8fb6e4a20138098454c3524 (diff) | |
download | zope-configuration-55e6c06eb8ad553dbd457a1177ac8b6734a35456.tar.gz |
Merge pull request #50 from zopefoundation/issue49
Ensure consistent IRO for all objects.
-rw-r--r-- | .travis.yml | 29 | ||||
-rw-r--r-- | CHANGES.rst | 7 | ||||
-rw-r--r-- | setup.py | 2 | ||||
-rw-r--r-- | src/zope/configuration/_compat.py | 24 | ||||
-rw-r--r-- | src/zope/configuration/config.py | 3 | ||||
-rw-r--r-- | src/zope/configuration/fields.py | 15 | ||||
-rw-r--r-- | src/zope/configuration/tests/nested.py | 2 | ||||
-rw-r--r-- | src/zope/configuration/tests/test___init__.py | 5 | ||||
-rw-r--r-- | src/zope/configuration/tests/test_docs.py | 6 | ||||
-rw-r--r-- | src/zope/configuration/tests/test_docutils.py | 7 | ||||
-rw-r--r-- | src/zope/configuration/tests/test_fields.py | 3 | ||||
-rw-r--r-- | src/zope/configuration/tests/test_zopeconfigure.py | 5 | ||||
-rw-r--r-- | tox.ini | 14 |
13 files changed, 83 insertions, 39 deletions
diff --git a/.travis.yml b/.travis.yml index 05ad82f..3c93078 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,19 +1,36 @@ language: python sudo: false + +env: + global: + ZOPE_INTERFACE_STRICT_IRO: 1 + python: - 2.7 - - 3.4 - 3.5 - 3.6 + - 3.7 + - 3.8 - pypy - pypy3 -matrix: +jobs: include: - - python: "3.7" - dist: xenial - sudo: true + - name: Documentation + python: 3.8 + install: + - pip install -U -e .[docs] + env: ZOPE_INTERFACE_STRICT_IRO=0 + script: + - sphinx-build -b html -d docs/_build/doctrees docs docs/_build/html + - sphinx-build -b doctest -d docs/_build/doctrees docs docs/_build/doctest + after_success: + + script: - - coverage run -m zope.testrunner --test-path=src --auto-color --auto-progress +# Temporary work around. Avoid zope.testrunner +# pending https://github.com/zopefoundation/zope.security/issues/71 +# due to cyclic dependency. + - coverage run -m unittest discover -s src after_success: - coveralls diff --git a/CHANGES.rst b/CHANGES.rst index ad1b358..b083fb9 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -4,7 +4,12 @@ Changes 4.4.0 (unreleased) ------------------ -- Nothing changed yet. +- Ensure a consistent interface resolution order for all objects. See + `issue 49 <https://github.com/zopefoundation/zope.configuration/issues/49>`_. + +- Drop support for Python 3.4. + +- Add support for Python 3.8. 4.3.1 (2019-02-12) @@ -54,10 +54,10 @@ setup(name='zope.configuration', "Programming Language :: Python :: 2", 'Programming Language :: Python :: 2.7', "Programming Language :: Python :: 3", - 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: PyPy', 'Natural Language :: English', diff --git a/src/zope/configuration/_compat.py b/src/zope/configuration/_compat.py index a7d8286..e8b1b51 100644 --- a/src/zope/configuration/_compat.py +++ b/src/zope/configuration/_compat.py @@ -42,3 +42,27 @@ else: # pragma: no cover def reraise(tp, value, tb=None): raise tp, value, tb """) + + +class implementer_if_needed(object): + # Helper to make sure we don't redundantly implement + # interfaces already inherited. Doing so tends to produce + # problems with the C3 order. In this package, we could easily + # statically determine to elide the relevant interfaces, but + # this is a defense against changes in parent classes and lessens + # the testing burden. + def __init__(self, *ifaces): + self._ifaces = ifaces + + def __call__(self, cls): + from zope.interface import implementedBy + from zope.interface import implementer + + ifaces_needed = [] + implemented = implementedBy(cls) + ifaces_needed = [ + iface + for iface in self._ifaces + if not implemented.isOrExtends(iface) + ] + return implementer(*ifaces_needed)(cls) diff --git a/src/zope/configuration/config.py b/src/zope/configuration/config.py index 0123021..30a7566 100644 --- a/src/zope/configuration/config.py +++ b/src/zope/configuration/config.py @@ -37,6 +37,7 @@ from zope.configuration._compat import builtins from zope.configuration._compat import reraise from zope.configuration._compat import string_types from zope.configuration._compat import text_type +from zope.configuration._compat import implementer_if_needed __all__ = [ 'ConfigurationContext', @@ -897,7 +898,7 @@ class RootStackItem(object): def finish(self): pass -@implementer(IStackItem) +@implementer_if_needed(IStackItem) class GroupingStackItem(RootStackItem): """ Stack item for a grouping directive diff --git a/src/zope/configuration/fields.py b/src/zope/configuration/fields.py index c4af0ad..4a83103 100644 --- a/src/zope/configuration/fields.py +++ b/src/zope/configuration/fields.py @@ -31,6 +31,7 @@ from zope.schema.interfaces import InvalidValue from zope.configuration.exceptions import ConfigurationError from zope.configuration.interfaces import InvalidToken +from zope.configuration._compat import implementer_if_needed __all__ = [ 'Bool', @@ -91,7 +92,7 @@ class PythonIdentifier(schema_PythonIdentifier): raise ValidationError(value).with_field_and_value(self, value) -@implementer(IFromUnicode) +@implementer_if_needed(IFromUnicode) class GlobalObject(Field): """ An object that can be accessed as a module global. @@ -176,7 +177,7 @@ class GlobalObject(Field): return value -@implementer(IFromUnicode) +@implementer_if_needed(IFromUnicode) class GlobalInterface(GlobalObject): """ An interface that can be accessed from a module. @@ -297,7 +298,7 @@ class PathProcessor(object): return filename, True -@implementer(IFromUnicode) +@implementer_if_needed(IFromUnicode) class Path(Text): """ A file path name, which may be input as a relative path @@ -376,7 +377,7 @@ class Path(Text): return filename -@implementer(IFromUnicode) +@implementer_if_needed(IFromUnicode) class Bool(schema_Bool): """ A boolean value. @@ -428,7 +429,7 @@ class Bool(schema_Bool): -@implementer(IFromUnicode) +@implementer_if_needed(IFromUnicode) class MessageID(Text): """ Text string that should be translated. @@ -439,7 +440,7 @@ class MessageID(Text): __factories = {} - def fromUnicode(self, u): + def fromUnicode(self, value): """ Translate a string to a MessageID. @@ -539,7 +540,7 @@ class MessageID(Text): enc = sys.getfilesystemencoding() or sys.getdefaultencoding() domain = domain.decode(enc) - v = super(MessageID, self).fromUnicode(u) + v = super(MessageID, self).fromUnicode(value) # Check whether there is an explicit message is specified default = None diff --git a/src/zope/configuration/tests/nested.py b/src/zope/configuration/tests/nested.py index f9f930c..3a108aa 100644 --- a/src/zope/configuration/tests/nested.py +++ b/src/zope/configuration/tests/nested.py @@ -48,7 +48,7 @@ class ISchema(Interface): fields = Attribute("Dictionary of field definitions") -@implementer(IConfigurationContext, ISchema) +@implementer(ISchema) class Schema(GroupingContextDecorator): """Handle schema directives """ diff --git a/src/zope/configuration/tests/test___init__.py b/src/zope/configuration/tests/test___init__.py index 92c5da0..d86faa8 100644 --- a/src/zope/configuration/tests/test___init__.py +++ b/src/zope/configuration/tests/test___init__.py @@ -29,8 +29,3 @@ class Test_namespace(unittest.TestCase): def test_non_empty(self): self.assertEqual(self._callFUT('test'), 'http://namespaces.zope.org/test') - -def test_suite(): - return unittest.TestSuite(( - unittest.makeSuite(Test_namespace), - )) diff --git a/src/zope/configuration/tests/test_docs.py b/src/zope/configuration/tests/test_docs.py index f81de55..4d10540 100644 --- a/src/zope/configuration/tests/test_docs.py +++ b/src/zope/configuration/tests/test_docs.py @@ -48,6 +48,7 @@ optionflags = ( ) def test_suite(): + # zope.testrunner suite = unittest.TestSuite() here = os.path.dirname(os.path.abspath(__file__)) while not os.path.exists(os.path.join(here, 'setup.py')): @@ -115,3 +116,8 @@ def test_suite(): ) return suite + + +def load_tests(loader, standard_tests, pattern): + # Pure unittest protocol. + return test_suite() diff --git a/src/zope/configuration/tests/test_docutils.py b/src/zope/configuration/tests/test_docutils.py index 1b69874..7583369 100644 --- a/src/zope/configuration/tests/test_docutils.py +++ b/src/zope/configuration/tests/test_docutils.py @@ -121,10 +121,3 @@ class Test_makeDocStructures(unittest.TestCase): (NS, 'three', ISchema, _three, 'THREE')]) self.assertEqual(subdirs[(PNS, 'parent2')], [(NS2, 'two', ISchema, _two, 'TWO')]) - - -def test_suite(): - return unittest.TestSuite(( - unittest.makeSuite(Test_wrap), - unittest.makeSuite(Test_makeDocStructures), - )) diff --git a/src/zope/configuration/tests/test_fields.py b/src/zope/configuration/tests/test_fields.py index baa4023..bbcc7f0 100644 --- a/src/zope/configuration/tests/test_fields.py +++ b/src/zope/configuration/tests/test_fields.py @@ -319,6 +319,3 @@ class MessageIDTests(unittest.TestCase, _ConformsToIFromUnicode): msgid = bound.fromUnicode(u'msgid') self.assertIsInstance(msgid.domain, str) self.assertEqual(msgid.domain, 'domain') - -def test_suite(): - return unittest.defaultTestLoader.loadTestsFromName(__name__) diff --git a/src/zope/configuration/tests/test_zopeconfigure.py b/src/zope/configuration/tests/test_zopeconfigure.py index ac7870f..92575f2 100644 --- a/src/zope/configuration/tests/test_zopeconfigure.py +++ b/src/zope/configuration/tests/test_zopeconfigure.py @@ -38,8 +38,3 @@ class ZopeConfigureTests(unittest.TestCase): class Context(object): basepath = None - -def test_suite(): - return unittest.TestSuite(( - unittest.makeSuite(ZopeConfigureTests), - )) @@ -1,12 +1,15 @@ [tox] envlist = - py27,py34,py35,py36,py37,pypy,pypy3,coverage,docs + py27,py35,py36,py37,py38,pypy,pypy3,coverage,docs [testenv] +usedevelop = true deps = .[test] commands = - zope-testrunner --test-path=src --all [] + python -m unittest discover -s src +setenv = + ZOPE_INTERFACE_STRICT_IRO = 1 [testenv:coverage] usedevelop = true @@ -18,6 +21,10 @@ commands = deps = {[testenv]deps} coverage +# Disabling STRICT IRO is temporary. +setenv = + ZOPE_INTERFACE_STRICT_IRO = 0 + [testenv:docs] basepython = @@ -29,3 +36,6 @@ deps = {[testenv]deps} Sphinx repoze.sphinx.autointerface +# Disabling STRICT IRO is temporary. +setenv = + ZOPE_INTERFACE_STRICT_IRO = 0 |