From 25e76cb59448a2e0b4c43af2316ebd71a784f5d9 Mon Sep 17 00:00:00 2001 From: Michael Howitz Date: Wed, 3 May 2023 09:07:10 +0200 Subject: Config with pure python template (#59) * Bumped version for breaking release. * Drop support for Python 2.7, 3.5, 3.6. * Fix problem with building the docs. --- .github/workflows/tests.yml | 8 +- .meta.toml | 3 +- CHANGES.rst | 4 +- docs/conf.py | 7 +- docs/narr.rst | 1 - setup.cfg | 4 +- setup.py | 11 +-- src/zope/configuration/_compat.py | 42 +---------- src/zope/configuration/config.py | 87 ++++++++++------------ src/zope/configuration/exceptions.py | 6 +- src/zope/configuration/fields.py | 16 ++-- src/zope/configuration/interfaces.py | 4 +- src/zope/configuration/tests/conditions.py | 4 +- src/zope/configuration/tests/directives.py | 10 +-- src/zope/configuration/tests/nested.py | 42 +++++------ .../tests/samplepackage/NamedForClass.py | 2 +- src/zope/configuration/tests/samplepackage/foo.py | 2 +- src/zope/configuration/tests/simple.py | 12 +-- src/zope/configuration/tests/test_config.py | 40 +++++----- src/zope/configuration/tests/test_docs.py | 21 +----- src/zope/configuration/tests/test_docutils.py | 4 +- src/zope/configuration/tests/test_fields.py | 34 ++++----- src/zope/configuration/tests/test_xmlconfig.py | 30 ++++---- src/zope/configuration/tests/test_zopeconfigure.py | 2 +- .../configuration/tests/unicode_all/__init__.py | 3 - src/zope/configuration/tests/victim.py | 2 - src/zope/configuration/xmlconfig.py | 51 ++++++------- src/zope/configuration/zopeconfigure.py | 22 +++--- tox.ini | 8 +- 29 files changed, 198 insertions(+), 284 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index cedf24b..d8889f3 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -21,16 +21,12 @@ jobs: config: # [Python version, tox env] - ["3.9", "lint"] - - ["2.7", "py27"] - - ["3.5", "py35"] - - ["3.6", "py36"] - ["3.7", "py37"] - ["3.8", "py38"] - ["3.9", "py39"] - ["3.10", "py310"] - ["3.11", "py311"] - - ["pypy-2.7", "pypy"] - - ["pypy-3.7", "pypy3"] + - ["pypy-3.9", "pypy3"] - ["3.9", "docs"] - ["3.9", "coverage"] @@ -60,7 +56,7 @@ jobs: - name: Coverage if: matrix.config[1] == 'coverage' run: | - pip install coveralls coverage-python-version + pip install coveralls coveralls --service=github env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.meta.toml b/.meta.toml index 4b50c90..f07736d 100644 --- a/.meta.toml +++ b/.meta.toml @@ -2,11 +2,10 @@ # https://github.com/zopefoundation/meta/tree/master/config/pure-python [meta] template = "pure-python" -commit-id = "200573eb414d2228d463da3de7d71a6d6335a704" +commit-id = "fe63cb4c" [python] with-pypy = true -with-legacy-python = true with-docs = true with-sphinx-doctests = true with-windows = false diff --git a/CHANGES.rst b/CHANGES.rst index a7309e1..17d5e6b 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,9 +1,11 @@ Changes ======= -4.5 (unreleased) +5.0 (unreleased) ---------------- +- Drop support for Python 2.7, 3.5, 3.6. + - Add support for Python 3.11. diff --git a/docs/conf.py b/docs/conf.py index ac65d4b..6c74cbf 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -252,10 +252,9 @@ texinfo_documents = [ # How to display URL addresses: 'footnote', 'no', or 'inline'. #texinfo_show_urls = 'footnote' -intersphinx_mapping = { - 'https://docs.python.org/': None, - 'https://zopeschema.readthedocs.io/en/latest': None, -} +# intersphinx_mapping = { +# 'python': ('https://docs.python.org/', None), +# } autodoc_default_flags = [ 'members', diff --git a/docs/narr.rst b/docs/narr.rst index aa7815c..1208bf4 100644 --- a/docs/narr.rst +++ b/docs/narr.rst @@ -1169,7 +1169,6 @@ redefine our directives: Traceback (most recent call last): ... zope.configuration.exceptions.ConfigurationError: The directive ('http://sample.namespaces.zope.org/schema', 'text') cannot be used in this context - File "", line 1.0 Let's see what happens if we declare duplicate fields: diff --git a/setup.cfg b/setup.cfg index 9dd98cb..870ce05 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,7 +1,7 @@ # Generated from: # https://github.com/zopefoundation/meta/tree/master/config/pure-python [bdist_wheel] -universal = 1 +universal = 0 [flake8] doctests = 1 @@ -21,7 +21,7 @@ ignore = force_single_line = True combine_as_imports = True sections = FUTURE,STDLIB,THIRDPARTY,ZOPE,FIRSTPARTY,LOCALFOLDER -known_third_party = six, docutils, pkg_resources +known_third_party = docutils, pkg_resources, pytz known_zope = known_first_party = default_section = ZOPE diff --git a/setup.py b/setup.py index 3cc4a7d..24add8f 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ # ############################################################################## # This package is developed by the Zope Toolkit project, documented here: -# http://docs.zope.org/zopetoolkit +# https://zopetoolkit.readthedocs.io/ # When developing and releasing this package, please follow the documented # Zope Toolkit policies as described by this documentation. ############################################################################## @@ -39,9 +39,9 @@ TESTS_REQUIRE = [ ] setup(name='zope.configuration', - version='4.5.dev0', + version='5.0.dev0', author='Zope Foundation and Contributors', - author_email='zope-dev@zope.org', + author_email='zope-dev@zope.dev', description='Zope Configuration Markup Language (ZCML)', long_description=( read('README.rst') @@ -55,11 +55,7 @@ setup(name='zope.configuration', 'Intended Audience :: Developers', 'License :: OSI Approved :: Zope Public License', 'Programming Language :: Python', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', @@ -77,6 +73,7 @@ setup(name='zope.configuration', packages=find_packages('src'), package_dir={'': 'src'}, namespace_packages=['zope'], + python_requires='>=3.7', extras_require={ 'docs': ['Sphinx', 'repoze.sphinx.autointerface'], 'test': TESTS_REQUIRE, diff --git a/src/zope/configuration/_compat.py b/src/zope/configuration/_compat.py index 05a5e61..de0a69b 100644 --- a/src/zope/configuration/_compat.py +++ b/src/zope/configuration/_compat.py @@ -11,48 +11,8 @@ # FOR A PARTICULAR PURPOSE. # ############################################################################## -import sys - -PY3 = sys.version_info[0] >= 3 - -if PY3: # pragma: PY3 - - import builtins - - string_types = (str,) - text_type = str - - # borrowed from 'six' - def reraise(tp, value, tb=None): - try: # pragma: no cover - if value is None: - value = tp - if value.__traceback__ is not tb: - raise value.with_traceback(tb) - raise value - finally: - value = None - tb = None - -else: # pragma: PY2 - - import __builtin__ as builtins # noqa: F401 imported but unused - - text_type = unicode # noqa: F821 undefined name - string_types = (basestring,) # noqa: F821 undefined name - - # borrowed from 'six' - exec("""\ -def reraise(tp, value, tb=None): - try: - raise tp, value, tb - finally: - tb = None -""") - - -class implementer_if_needed(object): +class implementer_if_needed: # 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 diff --git a/src/zope/configuration/config.py b/src/zope/configuration/config.py index c3eedd3..65a83a3 100644 --- a/src/zope/configuration/config.py +++ b/src/zope/configuration/config.py @@ -13,6 +13,7 @@ ############################################################################## """Configuration processor """ +import builtins import operator import os.path import sys @@ -26,11 +27,7 @@ from zope.schema import URI from zope.schema import TextLine from zope.schema import ValidationError -from zope.configuration._compat import builtins from zope.configuration._compat import implementer_if_needed -from zope.configuration._compat import reraise -from zope.configuration._compat import string_types -from zope.configuration._compat import text_type from zope.configuration.exceptions import ConfigurationError from zope.configuration.exceptions import ConfigurationWrapperError from zope.configuration.fields import GlobalInterface @@ -75,7 +72,7 @@ metans = 'http://namespaces.zope.org/meta' testns = 'http://namespaces.zope.org/test' -class ConfigurationContext(object): +class ConfigurationContext: """ Mix-in for implementing. :class:`zope.configuration.interfaces.IConfigurationContext`. @@ -130,7 +127,7 @@ class ConfigurationContext(object): # pylint:disable=no-member def __init__(self): - super(ConfigurationContext, self).__init__() + super().__init__() self._seen_files = set() self._features = set() @@ -230,7 +227,7 @@ class ConfigurationContext(object): # ImportError was caused deeper raise raise ConfigurationError( - "ImportError: Couldn't import %s, %s" % (mname, v)) + f"ImportError: Couldn't import {mname}, {v}") if not oname: # see not mname case above @@ -250,7 +247,7 @@ class ConfigurationContext(object): # ImportError was caused deeper raise raise ConfigurationError( - "ImportError: Module %s has no global %s" % (mname, oname)) + f"ImportError: Module {mname} has no global {oname}") def path(self, filename): """ @@ -545,7 +542,7 @@ class ConfigurationContext(object): self._features.add(feature) -class ConfigurationAdapterRegistry(object): +class ConfigurationAdapterRegistry: """ Simple adapter registry that manages directives as adapters. @@ -600,7 +597,7 @@ class ConfigurationAdapterRegistry(object): """ def __init__(self): - super(ConfigurationAdapterRegistry, self).__init__() + super().__init__() self._registry = {} # Stores tuples of form: # (namespace, name), schema, usedIn, info, parent @@ -615,7 +612,7 @@ class ConfigurationAdapterRegistry(object): r.register([interface], Interface, '', factory) def document(self, name, schema, usedIn, handler, info, parent=None): - if isinstance(name, string_types): + if isinstance(name, str): name = ('', name) self._docRegistry.append((name, schema, usedIn, handler, info, parent)) @@ -631,7 +628,7 @@ class ConfigurationAdapterRegistry(object): f = r.lookup1(providedBy(context), Interface) if f is None: raise ConfigurationError( - "The directive %s cannot be used in this context" % (name, )) + f"The directive {name} cannot be used in this context") return f @@ -685,7 +682,7 @@ class ConfigurationMachine(ConfigurationAdapterRegistry, ConfigurationContext): pass_through_exceptions = () def __init__(self): - super(ConfigurationMachine, self).__init__() + super().__init__() self.actions = [] self.stack = [RootStackItem(self)] self.i18n_strings = {} @@ -797,9 +794,7 @@ class ConfigurationMachine(ConfigurationAdapterRegistry, ConfigurationContext): raise except Exception: # Wrap it up and raise. - reraise( - ConfigurationExecutionError(info, sys.exc_info()[1]), - None, sys.exc_info()[2]) + raise ConfigurationExecutionError(info, sys.exc_info()[1]) finally: if clear: del self.actions[:] @@ -841,7 +836,7 @@ class IStackItem(Interface): @implementer(IStackItem) -class SimpleStackItem(object): +class SimpleStackItem: """ Simple stack item @@ -881,7 +876,7 @@ class SimpleStackItem(object): @implementer(IStackItem) -class RootStackItem(object): +class RootStackItem: """ A root stack item. """ @@ -1062,7 +1057,7 @@ class GroupingStackItem(RootStackItem): """ def __init__(self, context): - super(GroupingStackItem, self).__init__(context) + super().__init__(context) def __callBefore(self): actions = self.context.before() @@ -1092,7 +1087,7 @@ def noop(): @implementer(IStackItem) -class ComplexStackItem(object): +class ComplexStackItem: """ Complex stack item @@ -1308,10 +1303,10 @@ class IDirectivesInfo(Interface): """ namespace = URI( - title=u"Namespace", + title="Namespace", description=( - u"The namespace in which directives' names " - u"will be defined"), + "The namespace in which directives' names " + "will be defined"), ) @@ -1334,13 +1329,13 @@ class IDirectiveInfo(Interface): """ name = TextLine( - title=u"Directive name", - description=u"The name of the directive being defined", + title="Directive name", + description="The name of the directive being defined", ) schema = DirectiveSchema( - title=u"Directive handler", - description=u"The dotted name of the directive handler", + title="Directive handler", + description="The dotted name of the directive handler", ) @@ -1350,15 +1345,15 @@ class IFullInfo(IDirectiveInfo): """ handler = GlobalObject( - title=u"Directive handler", - description=u"The dotted name of the directive handler", + title="Directive handler", + description="The dotted name of the directive handler", ) usedIn = GlobalInterface( - title=u"The directive types the directive can be used in", + title="The directive types the directive can be used in", description=( - u"The interface of the directives that can contain " - u"the directive" + "The interface of the directives that can contain " + "the directive" ), default=IConfigurationContext, ) @@ -1540,8 +1535,8 @@ class IProvidesDirectiveInfo(Interface): """Information for a directive""" feature = TextLine( - title=u"Feature name", - description=u"""The name of the feature being provided + title="Feature name", + description="""The name of the feature being provided You can test available features with zcml:condition="have featurename". """, @@ -1696,26 +1691,22 @@ def toargs(context, schema, data): s = data.get(n, data) if s is not data: - s = text_type(s) + s = str(s) del data[n] try: args[str(name)] = field.fromUnicode(s) except ValidationError as v: - reraise( - ConfigurationError( - "Invalid value for %r" % (n)).add_details(v), - None, sys.exc_info()[2]) + raise ConfigurationError( + "Invalid value for %r" % (n)).add_details(v) elif field.required: # if the default is valid, we can use that: default = field.default try: field.validate(default) except ValidationError as v: - reraise( - ConfigurationError( - "Missing parameter: %r" % (n,)).add_details(v), - None, sys.exc_info()[2]) + raise ConfigurationError( + f"Missing parameter: {n!r}").add_details(v) args[str(name)] = default if data: @@ -1839,19 +1830,19 @@ def resolveConflicts(actions): class ConfigurationConflictError(ConfigurationError): def __init__(self, conflicts): - super(ConfigurationConflictError, self).__init__() + super().__init__() self._conflicts = conflicts def _with_details(self, opening, detail_formatter): r = ["Conflicting configuration actions"] for discriminator, infos in sorted(self._conflicts.items()): - r.append(" For: %s" % (discriminator, )) + r.append(f" For: {discriminator}") for info in infos: - for line in text_type(info).rstrip().split(u'\n'): - r.append(u" " + line) + for line in str(info).rstrip().split('\n'): + r.append(" " + line) opening = "\n".join(r) - return super(ConfigurationConflictError, self)._with_details( + return super()._with_details( opening, detail_formatter) diff --git a/src/zope/configuration/exceptions.py b/src/zope/configuration/exceptions.py index faa9bfb..350d905 100644 --- a/src/zope/configuration/exceptions.py +++ b/src/zope/configuration/exceptions.py @@ -49,11 +49,11 @@ class ConfigurationError(Exception): return '\n'.join(lines) def __str__(self): - s = super(ConfigurationError, self).__str__() + s = super().__str__() return self._with_details(s, str) def __repr__(self): - s = super(ConfigurationError, self).__repr__() + s = super().__repr__() return self._with_details(s, repr) @@ -62,7 +62,7 @@ class ConfigurationWrapperError(ConfigurationError): USE_INFO_REPR = False def __init__(self, info, exception): - super(ConfigurationWrapperError, self).__init__( + super().__init__( repr(info) if self.USE_INFO_REPR else info) self.add_details(exception) diff --git a/src/zope/configuration/fields.py b/src/zope/configuration/fields.py index c2dbbe5..34b8a3f 100644 --- a/src/zope/configuration/fields.py +++ b/src/zope/configuration/fields.py @@ -89,7 +89,7 @@ class PythonIdentifier(schema_PythonIdentifier): """ def _validate(self, value): - super(PythonIdentifier, self)._validate(value) + super()._validate(value) if not value: raise ValidationError(value).with_field_and_value(self, value) @@ -107,10 +107,10 @@ class GlobalObject(Field): def __init__(self, value_type=None, **kw): self.value_type = value_type - super(GlobalObject, self).__init__(**kw) + super().__init__(**kw) def _validate(self, value): - super(GlobalObject, self)._validate(value) + super()._validate(value) if self.value_type is not None: self.value_type.validate(value) @@ -216,7 +216,7 @@ class GlobalInterface(GlobalObject): """ def __init__(self, **kw): - super(GlobalInterface, self).__init__(InterfaceField(), **kw) + super().__init__(InterfaceField(), **kw) @implementer(IFromUnicode) @@ -272,7 +272,7 @@ class Tokens(List): v = vt.fromUnicode(s) except ValidationError as ex: raise InvalidToken( - "%s in %r" % (ex, value)).with_field_and_value( + f"{ex} in {value!r}").with_field_and_value( self, s) else: values.append(v) @@ -284,7 +284,7 @@ class Tokens(List): return values -class PathProcessor(object): +class PathProcessor: # Internal helper for manipulations on paths @classmethod @@ -540,13 +540,13 @@ class MessageID(Text): ) if not isinstance(domain, str): # IZopeConfigure specifies i18n_domain as a BytesLine, but that's - # wrong on Python 3, where the filesystem uses str, and hence + # wrong as the filesystem uses str, and hence # zope.i18n registers ITranslationDomain utilities with str names. # If we keep bytes, we can't find those utilities. enc = sys.getfilesystemencoding() or sys.getdefaultencoding() domain = domain.decode(enc) - v = super(MessageID, self).fromUnicode(value) + v = super().fromUnicode(value) # Check whether there is an explicit message is specified default = None diff --git a/src/zope/configuration/interfaces.py b/src/zope/configuration/interfaces.py index 0d29239..224230a 100644 --- a/src/zope/configuration/interfaces.py +++ b/src/zope/configuration/interfaces.py @@ -39,8 +39,8 @@ class IConfigurationContext(Interface): """ package = BytesLine( - title=(u"The current package name"), - description=(u"""\ + title=("The current package name"), + description=("""\ This is the name of the package containing the configuration file being executed. If the configuration file was not included by package, then this is None. diff --git a/src/zope/configuration/tests/conditions.py b/src/zope/configuration/tests/conditions.py index 8068e48..293860e 100644 --- a/src/zope/configuration/tests/conditions.py +++ b/src/zope/configuration/tests/conditions.py @@ -21,8 +21,8 @@ class IRegister(Interface): """Trivial sample registry.""" id = Id( - title=u"Identifier", - description=u"Some identifier that can be checked.", + title="Identifier", + description="Some identifier that can be checked.", required=True, ) diff --git a/src/zope/configuration/tests/directives.py b/src/zope/configuration/tests/directives.py index 832ec01..497f7d3 100644 --- a/src/zope/configuration/tests/directives.py +++ b/src/zope/configuration/tests/directives.py @@ -23,7 +23,7 @@ from zope.configuration.fields import GlobalObject from zope.configuration.interfaces import IConfigurationContext -class F(object): +class F: def __repr__(self): return 'f' @@ -41,11 +41,11 @@ class ISimple(Interface): c = NativeStringLine() -def simple(context, a=None, c=None, b=u"xxx"): +def simple(context, a=None, c=None, b="xxx"): return [(('simple', a, b, c), f, (a, b, c))] -def newsimple(context, a, c, b=u"xxx"): +def newsimple(context, a, c, b="xxx"): context.action(('newsimple', a, b, c), f, (a, b, c)) @@ -72,9 +72,9 @@ def factory(context, factory): context.action(('factory', 1, 2), factory) -class Complex(object): +class Complex: - def __init__(self, context, a, c, b=u"xxx"): + def __init__(self, context, a, c, b="xxx"): self.a, self.b, self.c = a, b, c context.action("Complex.__init__") diff --git a/src/zope/configuration/tests/nested.py b/src/zope/configuration/tests/nested.py index bf6da1c..e9a4c25 100644 --- a/src/zope/configuration/tests/nested.py +++ b/src/zope/configuration/tests/nested.py @@ -35,11 +35,11 @@ class ISchemaInfo(Interface): """ name = TextLine( - title=u"The schema name", - description=u"This is a descriptive name for the schema.", + title="The schema name", + description="This is a descriptive name for the schema.", ) - id = Id(title=u"The unique id for the schema") + id = Id(title="The unique id for the schema") class ISchema(Interface): @@ -75,24 +75,24 @@ class Schema(GroupingContextDecorator): class IFieldInfo(Interface): name = NativeStringLine( - title=u"The field name", + title="The field name", ) title = TextLine( - title=u"Title", - description=u"A short summary or label", - default=u"", + title="Title", + description="A short summary or label", + default="", required=False, ) required = Bool( - title=u"Required", - description=u"Determines whether a value is required.", + title="Required", + description="Determines whether a value is required.", default=True) readonly = Bool( - title=u"Read Only", - description=u"Can the value be modified?", + title="Read Only", + description="Can the value be modified?", required=False, default=False) @@ -100,22 +100,22 @@ class IFieldInfo(Interface): class ITextInfo(IFieldInfo): min_length = Int( - title=u"Minimum length", + title="Minimum length", description=( - u"Value after whitespace processing cannot have less than " - u"min_length characters. If min_length is None, there is " - u"no minimum." + "Value after whitespace processing cannot have less than " + "min_length characters. If min_length is None, there is " + "no minimum." ), required=False, min=0, # needs to be a positive number default=0) max_length = Int( - title=u"Maximum length", + title="Maximum length", description=( - u"Value after whitespace processing cannot have greater " - u"or equal than max_length characters. If max_length is " - u"None, there is no maximum." + "Value after whitespace processing cannot have greater " + "or equal than max_length characters. If max_length is " + "None, there is no maximum." ), required=False, min=0, # needs to be a positive number @@ -141,13 +141,13 @@ def textField(context, **kw): class IIntInfo(IFieldInfo): min = Int( - title=u"Start of the range", + title="Start of the range", required=False, default=None ) max = Int( - title=u"End of the range (excluding the value itself)", + title="End of the range (excluding the value itself)", required=False, default=None ) diff --git a/src/zope/configuration/tests/samplepackage/NamedForClass.py b/src/zope/configuration/tests/samplepackage/NamedForClass.py index f3d710d..895a6c5 100644 --- a/src/zope/configuration/tests/samplepackage/NamedForClass.py +++ b/src/zope/configuration/tests/samplepackage/NamedForClass.py @@ -1,3 +1,3 @@ # Test the "repeat" feature of zope.configuration.name.resolve. -class NamedForClass(object): +class NamedForClass: pass diff --git a/src/zope/configuration/tests/samplepackage/foo.py b/src/zope/configuration/tests/samplepackage/foo.py index e01bc78..f834233 100644 --- a/src/zope/configuration/tests/samplepackage/foo.py +++ b/src/zope/configuration/tests/samplepackage/foo.py @@ -26,7 +26,7 @@ class S1(Interface): y = schema.Int() -class stuff(object): +class stuff: def __init__(self, args, info, basepath, package, includepath): (self.args, self.info, self.basepath, self.package, self.includepath ) = args, info, basepath, package, includepath diff --git a/src/zope/configuration/tests/simple.py b/src/zope/configuration/tests/simple.py index 17aa7d7..7aba55f 100644 --- a/src/zope/configuration/tests/simple.py +++ b/src/zope/configuration/tests/simple.py @@ -23,18 +23,18 @@ from zope.configuration.fields import Path class IRegisterFile(Interface): path = Path( - title=u"File path", - description=u"This is the path name of the file to be registered.", + title="File path", + description="This is the path name of the file to be registered.", ) title = Text( - title=u"Short summary of the file", - description=u"This will be used in file listings", + title="Short summary of the file", + description="This will be used in file listings", required=False ) -class FileInfo(object): +class FileInfo: def __init__(self, path, title, description, info): (self.path, self.title, self.description, self.info @@ -44,7 +44,7 @@ class FileInfo(object): file_registry = [] -def registerFile(context, path, title=u""): +def registerFile(context, path, title=""): info = context.info description = info.text.strip() context.action(discriminator=('RegisterFile', path), diff --git a/src/zope/configuration/tests/test_config.py b/src/zope/configuration/tests/test_config.py index cf215ad..044e77d 100644 --- a/src/zope/configuration/tests/test_config.py +++ b/src/zope/configuration/tests/test_config.py @@ -75,7 +75,7 @@ class ConfigurationContextTests(unittest.TestCase): c.resolve('.nonesuch') def test_resolve_relative_miss_w_package_too_many_dots(self): - class FauxPackage(object): + class FauxPackage: __name__ = None from zope.configuration.exceptions import ConfigurationError c = self._makeOne() @@ -470,7 +470,7 @@ class ConfigurationAdapterRegistryTests(unittest.TestCase): pass @implementer(IFoo) - class Context(object): + class Context: pass NS = 'http://namespace.example.com/' NAME = 'testing' @@ -490,7 +490,7 @@ class ConfigurationAdapterRegistryTests(unittest.TestCase): pass @implementer(IFoo) - class Context(object): + class Context: pass NS = 'http://namespace.example.com/' NAME = 'testing' @@ -521,7 +521,7 @@ class ConfigurationAdapterRegistryTests(unittest.TestCase): reg.factory(context, (NS, NAME)) -class _ConformsToIConfigurationContext(object): +class _ConformsToIConfigurationContext: def _getTargetClass(self): raise NotImplementedError @@ -677,7 +677,7 @@ class ConfigurationMachineTests(_ConformsToIConfigurationContext, def test_end(self): from zope.configuration.config import RootStackItem - class FauxItem(object): + class FauxItem: _finished = False def finish(self): @@ -703,7 +703,7 @@ class ConfigurationMachineTests(_ConformsToIConfigurationContext, class IUsedIn(Interface): pass - class FauxItem(object): + class FauxItem: _finished = False def finish(self): @@ -750,7 +750,7 @@ class ConfigurationMachineTests(_ConformsToIConfigurationContext, self.assertEqual(cm.getInfo(), 'INFO') def test_getInfo_w_item(self): - class FauxItem(object): + class FauxItem: info = 'FAUX' def __init__(self): @@ -765,7 +765,7 @@ class ConfigurationMachineTests(_ConformsToIConfigurationContext, self.assertEqual(cm.info, 'INFO') def test_setInfo_w_item(self): - class FauxItem(object): + class FauxItem: info = 'FAUX' def __init__(self): @@ -889,7 +889,7 @@ class ConfigurationMachineTests(_ConformsToIConfigurationContext, schema=".Ik", handler=".k") machine((ns, "k"), "yee ha", - **{"for": u"f", "class": u"c", "x": u"x"}) + **{"for": "f", "class": "c", "x": "x"}) self.assertEqual(len(machine.actions), 1) self.assertEqual(machine.actions[0], @@ -903,7 +903,7 @@ class ConfigurationMachineTests(_ConformsToIConfigurationContext, }) -class _ConformsToIStackItem(object): +class _ConformsToIStackItem: def _getTargetClass(self): raise NotImplementedError @@ -1058,7 +1058,7 @@ class RootStackItemTests(_ConformsToIStackItem, def test_contained_context_factory_fails(self): from zope.configuration.exceptions import ConfigurationError - class _Context(object): + class _Context: def factory(self, context, name): "does nothing" rsi = self._makeOne(_Context()) @@ -1073,7 +1073,7 @@ class RootStackItemTests(_ConformsToIStackItem, _called_with.append((context, data, info)) return _adapter - class _Context(object): + class _Context: def factory(self, context, name): return _factory context = _Context() @@ -1282,7 +1282,7 @@ class ComplexStackItemTests(_ConformsToIStackItem, class ISubSchema(Interface): pass - class WithName(object): + class WithName: def testing(self, *args): raise AssertionError("should not be called") meta = self._makeMeta() @@ -1376,7 +1376,7 @@ class ComplexStackItemTests(_ConformsToIStackItem, }) -class _ConformsToIGroupingContext(object): +class _ConformsToIGroupingContext: def _getTargetClass(self): raise NotImplementedError @@ -1441,7 +1441,7 @@ class GroupingContextDecoratorTests(_ConformsToIConfigurationContext, gcd.after() # noraise -class _ConformsToIDirectivesContext(object): +class _ConformsToIDirectivesContext: def _getTargetClass(self): raise NotImplementedError @@ -1660,7 +1660,7 @@ class Test_defineGroupingDirective(unittest.TestCase): (NAME, ISchema, IUsedIn, _handler, 'INFO')) -class _ConformsToIComplexDirectiveContext(object): +class _ConformsToIComplexDirectiveContext: def _getTargetClass(self): raise NotImplementedError @@ -1764,7 +1764,7 @@ class Test_subdirective(unittest.TestCase): def _makeContext(self, package=None, namespace=None, name=None, schema=None, handler=None, usedIn=None): - class _Context(object): + class _Context: def __init__(self): self.context = {} self._documented = [] @@ -1823,7 +1823,7 @@ class Test_subdirective(unittest.TestCase): class IUsedIn(Interface): pass - class Handler(object): + class Handler: sub = object() NS = 'http://namespace.example.com/' NAME = 'testing' @@ -1942,7 +1942,7 @@ class Test_toargs(unittest.TestCase): from zope.schema import Text class ISchema(Interface): - w_default = Text(default=u'default') + w_default = Text(default='default') context = FauxContext() self.assertEqual(self._callFUT(context, ISchema, {}), {'w_default': 'default'}) @@ -2176,7 +2176,7 @@ class Test_resolveConflicts(unittest.TestCase): [_b, _d, _c, _a]) -class FauxContext(object): +class FauxContext: def __init__(self): self.actions = [] diff --git a/src/zope/configuration/tests/test_docs.py b/src/zope/configuration/tests/test_docs.py index 92e40eb..12abd98 100644 --- a/src/zope/configuration/tests/test_docs.py +++ b/src/zope/configuration/tests/test_docs.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- ############################################################################## # # Copyright (c) 2018 Zope Foundation and Contributors. @@ -15,13 +14,9 @@ """ Tests for the documentation. """ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function import doctest import os.path -import re import unittest import manuel.capture @@ -29,18 +24,8 @@ import manuel.codeblock import manuel.doctest import manuel.ignore import manuel.testing -from zope.testing import renormalizing -checker = renormalizing.RENormalizing([ - # Python 3 unicode removed the "u". - (re.compile("u('.*?')"), r"\1"), - (re.compile('u(".*?")'), r"\1"), - # Python 3 bytes added the "b". - (re.compile("b('.*?')"), r"\1"), - (re.compile('b(".*?")'), r"\1"), -]) - optionflags = ( doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS @@ -63,7 +48,8 @@ def test_suite(): pass suite.addTest( - unittest.makeSuite(SkippedDocTests)) # pragma: no cover + unittest.defaultTestLoader.loadTestsFromTestCase( + SkippedDocTests)) # pragma: no cover return suite # pragma: no cover docs = os.path.join(here, 'docs') @@ -95,7 +81,7 @@ def test_suite(): paths += [os.path.join(api_docs, f) for f in api_files_to_test] m = manuel.ignore.Manuel() - m += manuel.doctest.Manuel(checker=checker, optionflags=optionflags) + m += manuel.doctest.Manuel(optionflags=optionflags) m += manuel.codeblock.Manuel() m += manuel.capture.Manuel() @@ -111,7 +97,6 @@ def test_suite(): suite.addTest( doctest.DocTestSuite( mod_name, - checker=checker, optionflags=optionflags ) ) diff --git a/src/zope/configuration/tests/test_docutils.py b/src/zope/configuration/tests/test_docutils.py index 22fb36d..56a9fce 100644 --- a/src/zope/configuration/tests/test_docutils.py +++ b/src/zope/configuration/tests/test_docutils.py @@ -46,7 +46,7 @@ class Test_makeDocStructures(unittest.TestCase): return makeDocStructures(*args, **kw) def _makeContext(self): - class _Context(object): + class _Context: def __init__(self): self._docRegistry = [] return _Context() @@ -111,7 +111,7 @@ class Test_makeDocStructures(unittest.TestCase): def _three(): raise AssertionError("should not be called") - class Parent(object): + class Parent: namespace = PNS name = 'parent' parent1 = Parent() diff --git a/src/zope/configuration/tests/test_fields.py b/src/zope/configuration/tests/test_fields.py index 998ca0e..2b8bd9a 100644 --- a/src/zope/configuration/tests/test_fields.py +++ b/src/zope/configuration/tests/test_fields.py @@ -19,7 +19,7 @@ import unittest # pylint:disable=protected-access -class _ConformsToIFromUnicode(object): +class _ConformsToIFromUnicode: def _getTargetClass(self): raise NotImplementedError @@ -49,14 +49,14 @@ class GlobalObjectTests(unittest.TestCase, _ConformsToIFromUnicode): def test__validate_wo_value_type(self): go = self._makeOne(value_type=None) - for value in [0, 0.0, (), [], set(), frozenset(), u'', b'']: + for value in [0, 0.0, (), [], set(), frozenset(), '', b'']: go._validate(value) # noraise def test__validate_w_value_type(self): from zope.schema import Text from zope.schema.interfaces import WrongType go = self._makeOne(value_type=Text()) - go.validate(u'') + go.validate('') for value in [0, 0.0, (), [], set(), frozenset(), b'']: with self.assertRaises(WrongType): go._validate(value) @@ -70,7 +70,7 @@ class GlobalObjectTests(unittest.TestCase, _ConformsToIFromUnicode): from zope.configuration.config import ConfigurationError - class Context(object): + class Context: _resolved = None def resolve(self, name): @@ -89,7 +89,7 @@ class GlobalObjectTests(unittest.TestCase, _ConformsToIFromUnicode): def test_fromUnicode_w_resolve_success(self): _target = object() - class Context(object): + class Context: _resolved = None def resolve(self, name): @@ -105,7 +105,7 @@ class GlobalObjectTests(unittest.TestCase, _ConformsToIFromUnicode): def test_fromUnicode_w_resolve_dots(self): _target = object() - class Context(object): + class Context: _resolved = None def resolve(self, name): @@ -130,7 +130,7 @@ class GlobalObjectTests(unittest.TestCase, _ConformsToIFromUnicode): from zope.schema import ValidationError _target = object() - class Context(object): + class Context: _resolved = None def resolve(self, name): @@ -184,8 +184,8 @@ class TokensTests(unittest.TestCase, _ConformsToIFromUnicode): def test_fromUnicode_strips_ws(self): from zope.schema import Text tok = self._makeOne(value_type=Text()) - self.assertEqual(tok.fromUnicode(u' one two three '), - [u'one', u'two', u'three']) + self.assertEqual(tok.fromUnicode(' one two three '), + ['one', 'two', 'three']) def test_fromUnicode_invalid(self): from zope.schema import Int @@ -193,7 +193,7 @@ class TokensTests(unittest.TestCase, _ConformsToIFromUnicode): from zope.configuration.interfaces import InvalidToken tok = self._makeOne(value_type=Int(min=0)) with self.assertRaises(InvalidToken) as exc: - tok.fromUnicode(u' 1 -1 3 ') + tok.fromUnicode(' 1 -1 3 ') ex = exc.exception self.assertIs(ex.field, tok) @@ -215,7 +215,7 @@ class PathTests(unittest.TestCase, _ConformsToIFromUnicode): self.assertEqual(path.fromUnicode('/'), os.path.normpath('/')) def test_fromUnicode_relative(self): - class Context(object): + class Context: _pathed = None def path(self, value): @@ -271,11 +271,11 @@ class MessageIDTests(unittest.TestCase, _ConformsToIFromUnicode): return self._getTargetClass()(*args, **kw) def _makeContext(self, domain='testing_domain'): - class Info(object): + class Info: file = 'test_file' line = 42 - class Context(object): + class Context: i18n_domain = domain def __init__(self): @@ -289,7 +289,7 @@ class MessageIDTests(unittest.TestCase, _ConformsToIFromUnicode): context = self._makeContext(None) bound = mid.bind(context) with warnings.catch_warnings(record=True) as log: - msgid = bound.fromUnicode(u'testing') + msgid = bound.fromUnicode('testing') self.assertEqual(len(log), 1) self.assertTrue(str(log[0].message).startswith( 'You did not specify an i18n translation domain')) @@ -305,7 +305,7 @@ class MessageIDTests(unittest.TestCase, _ConformsToIFromUnicode): context = self._makeContext() bound = mid.bind(context) with warnings.catch_warnings(record=True) as log: - msgid = bound.fromUnicode(u'[] testing') + msgid = bound.fromUnicode('[] testing') self.assertEqual(len(log), 0) self.assertEqual(msgid, 'testing') self.assertEqual(msgid.default, None) @@ -319,7 +319,7 @@ class MessageIDTests(unittest.TestCase, _ConformsToIFromUnicode): context = self._makeContext() bound = mid.bind(context) with warnings.catch_warnings(record=True) as log: - msgid = bound.fromUnicode(u'[testing] default') + msgid = bound.fromUnicode('[testing] default') self.assertEqual(len(log), 0) self.assertEqual(msgid, 'testing') self.assertEqual(msgid.default, 'default') @@ -331,6 +331,6 @@ class MessageIDTests(unittest.TestCase, _ConformsToIFromUnicode): mid = self._makeOne() context = self._makeContext(domain=b'domain') bound = mid.bind(context) - msgid = bound.fromUnicode(u'msgid') + msgid = bound.fromUnicode('msgid') self.assertIsInstance(msgid.domain, str) self.assertEqual(msgid.domain, 'domain') diff --git a/src/zope/configuration/tests/test_xmlconfig.py b/src/zope/configuration/tests/test_xmlconfig.py index 48b6479..342d1ff 100644 --- a/src/zope/configuration/tests/test_xmlconfig.py +++ b/src/zope/configuration/tests/test_xmlconfig.py @@ -16,15 +16,15 @@ import unittest -NS = u'ns' -FOO = u'foo' -XXX = u'xxx' -SPLAT = u'splat' -SPLATV = u'splatv' -A = u'a' -AVALUE = u'avalue' -B = u'b' -BVALUE = u'bvalue' +NS = 'ns' +FOO = 'foo' +XXX = 'xxx' +SPLAT = 'splat' +SPLATV = 'splatv' +A = 'a' +AVALUE = 'avalue' +B = 'b' +BVALUE = 'bvalue' # pylint:disable=protected-access @@ -175,7 +175,7 @@ class ConfigurationHandlerTests(unittest.TestCase): raise raises("xxx") begin = end - class Info(object): + class Info: _line = _col = None def end(self, line, col): @@ -366,7 +366,7 @@ class ConfigurationHandlerTests(unittest.TestCase): "Invalid ZCML condition: 'nonesuch'") def test_endElementNS_normal(self): - class Info(object): + class Info: _line = _col = None def end(self, line, col): @@ -1079,7 +1079,7 @@ class Test_testxmlconfig(unittest.TestCase): self.assertEqual(data.info.ecolumn, 29) -class FauxLocator(object): +class FauxLocator: def __init__(self, file, line, column): self.file, self.line, self.column = file, line, column @@ -1093,7 +1093,7 @@ class FauxLocator(object): return self.column -class FauxContext(object): +class FauxContext: includepath = () _features = () _end_called = False @@ -1166,7 +1166,7 @@ def _packageFile(package, filename): return os.path.join(os.path.dirname(package.__file__), filename) -class _Monkey(object): +class _Monkey: def __init__(self, module, **replacements): self.module = module @@ -1188,7 +1188,7 @@ class _Monkey(object): delattr(self.module, k) -class LoggerStub(object): +class LoggerStub: debugs = errors = warnings = infos = () diff --git a/src/zope/configuration/tests/test_zopeconfigure.py b/src/zope/configuration/tests/test_zopeconfigure.py index f5f34b2..d11f924 100644 --- a/src/zope/configuration/tests/test_zopeconfigure.py +++ b/src/zope/configuration/tests/test_zopeconfigure.py @@ -37,5 +37,5 @@ class ZopeConfigureTests(unittest.TestCase): self.assertEqual(zc.basepath, os.path.dirname(zct.__file__)) -class Context(object): +class Context: basepath = None diff --git a/src/zope/configuration/tests/unicode_all/__init__.py b/src/zope/configuration/tests/unicode_all/__init__.py index 994e0c3..23c2e0b 100644 --- a/src/zope/configuration/tests/unicode_all/__init__.py +++ b/src/zope/configuration/tests/unicode_all/__init__.py @@ -1,6 +1,3 @@ -from __future__ import unicode_literals - - __all__ = ['foo'] foo = 'sentinel' diff --git a/src/zope/configuration/tests/victim.py b/src/zope/configuration/tests/victim.py index 0c5b2fe..d2a2bc7 100644 --- a/src/zope/configuration/tests/victim.py +++ b/src/zope/configuration/tests/victim.py @@ -1,3 +1 @@ -from __future__ import absolute_import - from zope.configuration.tests import bad # pylint:disable=unused-import diff --git a/src/zope/configuration/xmlconfig.py b/src/zope/configuration/xmlconfig.py index 3192f22..cd012c6 100644 --- a/src/zope/configuration/xmlconfig.py +++ b/src/zope/configuration/xmlconfig.py @@ -34,7 +34,6 @@ from xml.sax.xmlreader import InputSource from zope.interface import Interface from zope.schema import NativeStringLine -from zope.configuration._compat import reraise from zope.configuration.config import ConfigurationMachine from zope.configuration.config import GroupingContextDecorator from zope.configuration.config import GroupingStackItem @@ -68,7 +67,7 @@ __all__ = [ logger = logging.getLogger("config") ZCML_NAMESPACE = "http://namespaces.zope.org/zcml" -ZCML_CONDITION = (ZCML_NAMESPACE, u"condition") +ZCML_CONDITION = (ZCML_NAMESPACE, "condition") class ZopeXMLConfigurationError(ConfigurationWrapperError): @@ -105,7 +104,7 @@ class ZopeSAXParseException(ConfigurationWrapperError): """ -class ParserInfo(object): +class ParserInfo: r""" Information about a directive based on parser data @@ -141,7 +140,7 @@ class ParserInfo(object): """ - text = u'' + text = '' def __init__(self, file, line, column): self.file, self.line, self.column = file, line, column @@ -152,15 +151,15 @@ class ParserInfo(object): def __repr__(self): if (self.line, self.column) == (self.eline, self.ecolumn): - return 'File "%s", line %s.%s' % ( + return 'File "{}", line {}.{}'.format( self.file, self.line, self.column) - return 'File "%s", line %s.%s-%s.%s' % ( + return 'File "{}", line {}.{}-{}.{}'.format( self.file, self.line, self.column, self.eline, self.ecolumn) def __str__(self): if (self.line, self.column) == (self.eline, self.ecolumn): - return 'File "%s", line %s.%s' % ( + return 'File "{}", line {}.{}'.format( self.file, self.line, self.column) file = self.file @@ -172,7 +171,7 @@ class ParserInfo(object): try: with open(file) as f: lines = f.readlines()[self.line - 1:self.eline] - except IOError: + except OSError: src = " Could not read source." else: ecolumn = self.ecolumn @@ -190,8 +189,8 @@ class ParserInfo(object): # Remove text before start if it's noy whitespace lines[0] = lines[0][self.column:] - pad = u' ' - blank = u'' + pad = ' ' + blank = '' try: src = blank.join([pad + line for line in lines]) except UnicodeDecodeError: # pragma: no cover @@ -203,7 +202,7 @@ class ParserInfo(object): # unicode won't be printable, at least on my console src = src.encode('ascii', 'replace') - return "%s\n%s" % (repr(self), src) + return f"{repr(self)}\n{src}" def characters(self, characters): self.text += characters @@ -235,8 +234,7 @@ class ConfigurationHandler(ContentHandler): ex.add_details(repr(info)) raise - exc = ZopeXMLConfigurationError(info, ex) - reraise(exc, None, sys.exc_info()[2]) + raise ZopeXMLConfigurationError(info, ex) def startElementNS(self, name, qname, attrs): if self.ignore_depth: @@ -410,8 +408,7 @@ def processxmlfile(file, context, testing=False): try: parser.parse(src) except SAXParseException: - reraise(ZopeSAXParseException(file, sys.exc_info()[1]), - None, sys.exc_info()[2]) + raise ZopeSAXParseException(file, sys.exc_info()[1]) def openInOrPlain(filename): @@ -420,9 +417,9 @@ def openInOrPlain(filename): If the requested file does not exist and filename.in does, fall back to filename.in. If opening the original filename fails for - any other reason, allow the failure to propogate. + any other reason, allow the failure to propagate. - For example, the tests/samplepackage dirextory has files: + For example, the tests/samplepackage directory has files: - configure.zcml @@ -466,7 +463,7 @@ def openInOrPlain(filename): """ try: return open(filename) - except IOError as e: + except OSError as e: code, msg = e.args if code == errno.ENOENT: fn = filename + ".in" @@ -485,18 +482,18 @@ class IInclude(Interface): """ file = NativeStringLine( - title=u"Configuration file name", + title="Configuration file name", description=( - u"The name of a configuration file to be included/" - u"excluded, relative to the directive containing the " - u"including configuration file." + "The name of a configuration file to be included/" + "excluded, relative to the directive containing the " + "including configuration file." ), required=False, ) files = NativeStringLine( - title=u"Configuration file name pattern", - description=u""" + title="Configuration file name pattern", + description=""" The names of multiple configuration files to be included/excluded, expressed as a file-name pattern, relative to the directive containing the including or excluding configuration file. @@ -517,8 +514,8 @@ class IInclude(Interface): ) package = GlobalObject( - title=u"Include or exclude package", - description=u""" + title="Include or exclude package", + description=""" Include or exclude the named file (or configure.zcml) from the directory of this package. """, @@ -713,7 +710,7 @@ def _getContext(): return _context -class XMLConfig(object): +class XMLConfig: """Provide high-level handling of configuration files. See examples in tests/text_xmlconfig.py diff --git a/src/zope/configuration/zopeconfigure.py b/src/zope/configuration/zopeconfigure.py index a21faa7..d5f0807 100644 --- a/src/zope/configuration/zopeconfigure.py +++ b/src/zope/configuration/zopeconfigure.py @@ -129,22 +129,22 @@ class IZopeConfigure(Interface): """ package = GlobalObject( - title=u"Package", + title="Package", description=( - u"The package to be used for evaluating relative imports " - u"and file names." + "The package to be used for evaluating relative imports " + "and file names." ), required=False) i18n_domain = BytesLine( - title=u"Internationalization domain", + title="Internationalization domain", description=( - u"This is a name for the software project. It must be a " - u"legal file-system name as it will be used to contruct " - u"names for directories containing translation data. " - u"\n" - u"The domain defines a namespace for the message ids " - u"used by a project." + "This is a name for the software project. It must be a " + "legal file-system name as it will be used to contruct " + "names for directories containing translation data. " + "\n" + "The domain defines a namespace for the message ids " + "used by a project." ), required=False ) @@ -156,7 +156,7 @@ class ZopeConfigure(GroupingContextDecorator): """ def __init__(self, context, **kw): - super(ZopeConfigure, self).__init__(context, **kw) + super().__init__(context, **kw) if 'package' in kw: # if we have a package, we want to also define basepath # so we don't acquire one diff --git a/tox.ini b/tox.ini index ccdf371..ac3fe69 100644 --- a/tox.ini +++ b/tox.ini @@ -4,15 +4,11 @@ minversion = 3.18 envlist = lint - py27 - py35 - py36 py37 py38 py39 py310 py311 - pypy pypy3 docs coverage @@ -22,7 +18,7 @@ usedevelop = true deps = commands = zope-testrunner --test-path=src {posargs:-vc} - !py27-!pypy: sphinx-build -b doctest -d {envdir}/.cache/doctrees docs {envdir}/.cache/doctest + sphinx-build -b doctest -d {envdir}/.cache/doctrees docs {envdir}/.cache/doctest extras = test docs @@ -65,7 +61,6 @@ allowlist_externals = mkdir deps = coverage - coverage-python-version commands = mkdir -p {toxinidir}/parts/htmlcov coverage run -m zope.testrunner --test-path=src {posargs:-vc} @@ -75,7 +70,6 @@ commands = [coverage:run] branch = True -plugins = coverage_python_version source = zope.configuration [coverage:report] -- cgit v1.2.1