diff options
author | Michael Howitz <mh@gocept.com> | 2022-11-29 08:34:22 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-11-29 08:34:22 +0100 |
commit | 149e734d2db75f37c72d49a5509c07de91f97074 (patch) | |
tree | 1a5da7211f6a48ecfad2fc2041fe393d8aada2f3 | |
parent | 4cf2ac83e12e7722851495acb2d4c500bc9ccdcf (diff) | |
parent | 46fd0d4ef67fc95df706880542d162a42e8ac922 (diff) | |
download | zope-location-149e734d2db75f37c72d49a5509c07de91f97074.tar.gz |
Merge pull request #8 from zopefoundation/config-with-pure-python
* Config with pure python
* Add support for Python 3.8, 3.9, 3.10, 3.11.
* Drop support for Python 3.4.
-rw-r--r-- | .coveragerc | 11 | ||||
-rw-r--r-- | .editorconfig | 39 | ||||
-rw-r--r-- | .github/workflows/tests.yml | 66 | ||||
-rw-r--r-- | .gitignore | 40 | ||||
-rw-r--r-- | .meta.toml | 33 | ||||
-rw-r--r-- | .travis.yml | 26 | ||||
-rw-r--r-- | CHANGES.rst | 4 | ||||
-rw-r--r-- | CONTRIBUTING.md | 23 | ||||
-rw-r--r-- | MANIFEST.in | 23 | ||||
-rw-r--r-- | README.rst | 6 | ||||
-rw-r--r-- | bootstrap.py | 210 | ||||
-rw-r--r-- | setup.cfg | 36 | ||||
-rw-r--r-- | setup.py | 17 | ||||
-rw-r--r-- | src/zope/__init__.py | 2 | ||||
-rw-r--r-- | src/zope/location/__init__.py | 7 | ||||
-rw-r--r-- | src/zope/location/interfaces.py | 7 | ||||
-rw-r--r-- | src/zope/location/location.py | 10 | ||||
-rw-r--r-- | src/zope/location/pickling.py | 8 | ||||
-rw-r--r-- | src/zope/location/tests/__init__.py | 2 | ||||
-rw-r--r-- | src/zope/location/tests/test_configure.py | 6 | ||||
-rw-r--r-- | src/zope/location/tests/test_location.py | 38 | ||||
-rw-r--r-- | src/zope/location/tests/test_pickling.py | 8 | ||||
-rw-r--r-- | src/zope/location/tests/test_traversing.py | 32 | ||||
-rw-r--r-- | src/zope/location/traversing.py | 7 | ||||
-rw-r--r-- | tox.ini | 99 |
25 files changed, 412 insertions, 348 deletions
diff --git a/.coveragerc b/.coveragerc deleted file mode 100644 index 51ab167..0000000 --- a/.coveragerc +++ /dev/null @@ -1,11 +0,0 @@ -[run] -source = zope.location - -[report] -precision = 2 -exclude_lines = - pragma: no cover - if __name__ == '__main__': - raise NotImplementedError - self.fail - raise AssertionError diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..c5508b9 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,39 @@ +# Generated from: +# https://github.com/zopefoundation/meta/tree/master/config/pure-python +# +# EditorConfig Configuration file, for more details see: +# http://EditorConfig.org +# EditorConfig is a convention description, that could be interpreted +# by multiple editors to enforce common coding conventions for specific +# file types + +# top-most EditorConfig file: +# Will ignore other EditorConfig files in Home directory or upper tree level. +root = true + + +[*] # For All Files +# Unix-style newlines with a newline ending every file +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +# Set default charset +charset = utf-8 +# Indent style default +indent_style = space +# Max Line Length - a hard line wrap, should be disabled +max_line_length = off + +[*.{py,cfg,ini}] +# 4 space indentation +indent_size = 4 + +[*.{yml,zpt,pt,dtml,zcml}] +# 2 space indentation +indent_size = 2 + +[{Makefile,.gitmodules}] +# Tab indentation (no size specified, but view as 4 spaces) +indent_style = tab +indent_size = unset +tab_width = unset diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..3c40fa5 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,66 @@ +# Generated from: +# https://github.com/zopefoundation/meta/tree/master/config/pure-python +name: tests + +on: + push: + pull_request: + schedule: + - cron: '0 12 * * 0' # run once a week on Sunday + # Allow to run this workflow manually from the Actions tab + workflow_dispatch: + +jobs: + build: + strategy: + # We want to see all failures: + fail-fast: false + matrix: + os: + - ubuntu + 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"] + - ["3.9", "docs"] + - ["3.9", "coverage"] + + runs-on: ${{ matrix.os }}-latest + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name + name: ${{ matrix.config[1] }} + steps: + - uses: actions/checkout@v3 + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.config[0] }} + - name: Pip cache + uses: actions/cache@v3 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ matrix.config[0] }}-${{ hashFiles('setup.*', 'tox.ini') }} + restore-keys: | + ${{ runner.os }}-pip-${{ matrix.config[0] }}- + ${{ runner.os }}-pip- + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install tox + - name: Test + run: tox -e ${{ matrix.config[1] }} + - name: Coverage + if: matrix.config[1] == 'coverage' + run: | + pip install coveralls coverage-python-version + coveralls --service=github + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -1,14 +1,32 @@ +# Generated from: +# https://github.com/zopefoundation/meta/tree/master/config/pure-python +*.dll +*.egg-info/ +*.profraw *.pyc -__pycache__ -*.egg-info -.installed.cfg -bin -develop-eggs -eggs -parts -docs/_build -.tox +*.pyo +*.so .coverage -nosetests.xml +.coverage.* +.eggs/ +.installed.cfg +.mr.developer.cfg +.tox/ +.vscode/ +__pycache__/ +bin/ +build/ coverage.xml -htmlcov/ +develop-eggs/ +develop/ +dist/ +docs/_build +eggs/ +etc/ +lib/ +lib64 +log/ +parts/ +pyvenv.cfg +testing.log +var/ diff --git a/.meta.toml b/.meta.toml new file mode 100644 index 0000000..ef6abe6 --- /dev/null +++ b/.meta.toml @@ -0,0 +1,33 @@ +# Generated from: +# https://github.com/zopefoundation/meta/tree/master/config/pure-python +[meta] +template = "pure-python" +commit-id = "90a5c439bc150722699aff9fa7cd96f6e59db536" + +[python] +with-macos = false +with-windows = false +with-pypy = true +with-future-python = false +with-legacy-python = true +with-docs = true +with-sphinx-doctests = true + +[tox] +use-flake8 = true + +[coverage] +fail-under = 100 + +[flake8] +additional-config = [ + "# F401 imported but unused", + "per-file-ignores =", + " src/zope/location/__init__.py: F401", + ] + +[manifest] +additional-rules = [ + "recursive-include docs *.bat", + "recursive-include src *.zcml", + ] diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index b2ff47d..0000000 --- a/.travis.yml +++ /dev/null @@ -1,26 +0,0 @@ -language: python -sudo: false -python: - - 2.7 - - 3.4 - - 3.5 - - 3.6 - - pypy - - pypy3 -matrix: - include: - - python: "3.7" - dist: xenial - sudo: true -install: - - pip install -U pip setuptools - - pip install -U coverage coveralls - - pip install -U -e .[test,docs] -script: - - coverage run -m zope.testrunner --test-path=src - - coverage run -a -m sphinx -b doctest -d docs/_build/doctrees docs docs/_build/doctest -after_success: - - coveralls -notifications: - email: false -cache: pip diff --git a/CHANGES.rst b/CHANGES.rst index 4850898..f98e012 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -5,7 +5,9 @@ 4.3 (unreleased) ================ -- Nothing changed yet. +- Add support for Python 3.8, 3.9, 3.10, 3.11. + +- Drop support for Python 3.4. 4.2 (2018-10-09) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..31d95f0 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,23 @@ +<!-- +Generated from: +https://github.com/zopefoundation/meta/tree/master/config/pure-python +--> +# Contributing to zopefoundation projects + +The projects under the zopefoundation GitHub organization are open source and +welcome contributions in different forms: + +* bug reports +* code improvements and bug fixes +* documentation improvements +* pull request reviews + +For any changes in the repository besides trivial typo fixes you are required +to sign the contributor agreement. See +https://www.zope.dev/developer/becoming-a-committer.html for details. + +Please visit our [Developer +Guidelines](https://www.zope.dev/developer/guidelines.html) if you'd like to +contribute code changes and our [guidelines for reporting +bugs](https://www.zope.dev/developer/reporting-bugs.html) if you want to file a +bug report. diff --git a/MANIFEST.in b/MANIFEST.in index 312397b..1762883 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,19 +1,16 @@ +# Generated from: +# https://github.com/zopefoundation/meta/tree/master/config/pure-python +include *.md include *.rst include *.txt -include *.py -include .coveragerc include buildout.cfg include tox.ini -include .travis.yml -recursive-include docs * -recursive-include src * +recursive-include docs *.py +recursive-include docs *.rst +recursive-include docs *.txt +recursive-include docs Makefile -exclude .coverage -exclude nosetests.xml -exclude src/coverage.xml - -global-exclude *.dll -global-exclude *.pyc -global-exclude *.pyo -global-exclude *.so +recursive-include src *.py +recursive-include docs *.bat +recursive-include src *.zcml @@ -10,8 +10,8 @@ :target: https://pypi.org/project/zope.location/ :alt: Supported Python versions -.. image:: https://travis-ci.com/zopefoundation/zope.location.svg?branch=master - :target: https://travis-ci.com/zopefoundation/zope.location +.. image:: https://github.com/zopefoundation/zope.location/actions/workflows/tests.yml/badge.svg + :target: https://github.com/zopefoundation/zope.location/actions/workflows/tests.yml .. image:: https://coveralls.io/repos/github/zopefoundation/zope.location/badge.svg?branch=master :target: https://coveralls.io/github/zopefoundation/zope.location?branch=master @@ -20,7 +20,7 @@ :target: http://zopelocation.readthedocs.org/en/latest/ :alt: Documentation Status -In Zope3, "locations" are special objects that have a structural +In Zope 3, "locations" are special objects that have a structural location, indicated with ``__name__`` and ``__parent__`` attributes. See `zope.container <https://zopecontainer.readthedocs.io/en/latest>`_ diff --git a/bootstrap.py b/bootstrap.py deleted file mode 100644 index a459921..0000000 --- a/bootstrap.py +++ /dev/null @@ -1,210 +0,0 @@ -############################################################################## -# -# Copyright (c) 2006 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. -# -############################################################################## -"""Bootstrap a buildout-based project - -Simply run this script in a directory containing a buildout.cfg. -The script accepts buildout command-line options, so you can -use the -c option to specify an alternate configuration file. -""" - -import os -import shutil -import sys -import tempfile - -from optparse import OptionParser - -__version__ = '2015-07-01' -# See zc.buildout's changelog if this version is up to date. - -tmpeggs = tempfile.mkdtemp(prefix='bootstrap-') - -usage = '''\ -[DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options] - -Bootstraps a buildout-based project. - -Simply run this script in a directory containing a buildout.cfg, using the -Python that you want bin/buildout to use. - -Note that by using --find-links to point to local resources, you can keep -this script from going over the network. -''' - -parser = OptionParser(usage=usage) -parser.add_option("--version", - action="store_true", default=False, - help=("Return bootstrap.py version.")) -parser.add_option("-t", "--accept-buildout-test-releases", - dest='accept_buildout_test_releases', - action="store_true", default=False, - help=("Normally, if you do not specify a --version, the " - "bootstrap script and buildout gets the newest " - "*final* versions of zc.buildout and its recipes and " - "extensions for you. If you use this flag, " - "bootstrap and buildout will get the newest releases " - "even if they are alphas or betas.")) -parser.add_option("-c", "--config-file", - help=("Specify the path to the buildout configuration " - "file to be used.")) -parser.add_option("-f", "--find-links", - help=("Specify a URL to search for buildout releases")) -parser.add_option("--allow-site-packages", - action="store_true", default=False, - help=("Let bootstrap.py use existing site packages")) -parser.add_option("--buildout-version", - help="Use a specific zc.buildout version") -parser.add_option("--setuptools-version", - help="Use a specific setuptools version") -parser.add_option("--setuptools-to-dir", - help=("Allow for re-use of existing directory of " - "setuptools versions")) - -options, args = parser.parse_args() -if options.version: - print("bootstrap.py version %s" % __version__) - sys.exit(0) - - -###################################################################### -# load/install setuptools - -try: - from urllib.request import urlopen -except ImportError: - from urllib2 import urlopen - -ez = {} -if os.path.exists('ez_setup.py'): - exec(open('ez_setup.py').read(), ez) -else: - exec(urlopen('https://bootstrap.pypa.io/ez_setup.py').read(), ez) - -if not options.allow_site_packages: - # ez_setup imports site, which adds site packages - # this will remove them from the path to ensure that incompatible versions - # of setuptools are not in the path - import site - # inside a virtualenv, there is no 'getsitepackages'. - # We can't remove these reliably - if hasattr(site, 'getsitepackages'): - for sitepackage_path in site.getsitepackages(): - # Strip all site-packages directories from sys.path that - # are not sys.prefix; this is because on Windows - # sys.prefix is a site-package directory. - if sitepackage_path != sys.prefix: - sys.path[:] = [x for x in sys.path - if sitepackage_path not in x] - -setup_args = dict(to_dir=tmpeggs, download_delay=0) - -if options.setuptools_version is not None: - setup_args['version'] = options.setuptools_version -if options.setuptools_to_dir is not None: - setup_args['to_dir'] = options.setuptools_to_dir - -ez['use_setuptools'](**setup_args) -import setuptools -import pkg_resources - -# This does not (always?) update the default working set. We will -# do it. -for path in sys.path: - if path not in pkg_resources.working_set.entries: - pkg_resources.working_set.add_entry(path) - -###################################################################### -# Install buildout - -ws = pkg_resources.working_set - -setuptools_path = ws.find( - pkg_resources.Requirement.parse('setuptools')).location - -# Fix sys.path here as easy_install.pth added before PYTHONPATH -cmd = [sys.executable, '-c', - 'import sys; sys.path[0:0] = [%r]; ' % setuptools_path + - 'from setuptools.command.easy_install import main; main()', - '-mZqNxd', tmpeggs] - -find_links = os.environ.get( - 'bootstrap-testing-find-links', - options.find_links or - ('http://downloads.buildout.org/' - if options.accept_buildout_test_releases else None) - ) -if find_links: - cmd.extend(['-f', find_links]) - -requirement = 'zc.buildout' -version = options.buildout_version -if version is None and not options.accept_buildout_test_releases: - # Figure out the most recent final version of zc.buildout. - import setuptools.package_index - _final_parts = '*final-', '*final' - - def _final_version(parsed_version): - try: - return not parsed_version.is_prerelease - except AttributeError: - # Older setuptools - for part in parsed_version: - if (part[:1] == '*') and (part not in _final_parts): - return False - return True - - index = setuptools.package_index.PackageIndex( - search_path=[setuptools_path]) - if find_links: - index.add_find_links((find_links,)) - req = pkg_resources.Requirement.parse(requirement) - if index.obtain(req) is not None: - best = [] - bestv = None - for dist in index[req.project_name]: - distv = dist.parsed_version - if _final_version(distv): - if bestv is None or distv > bestv: - best = [dist] - bestv = distv - elif distv == bestv: - best.append(dist) - if best: - best.sort() - version = best[-1].version -if version: - requirement = '=='.join((requirement, version)) -cmd.append(requirement) - -import subprocess -if subprocess.call(cmd) != 0: - raise Exception( - "Failed to execute command:\n%s" % repr(cmd)[1:-1]) - -###################################################################### -# Import and run buildout - -ws.add_entry(tmpeggs) -ws.require(requirement) -import zc.buildout.buildout - -if not [a for a in args if '=' not in a]: - args.append('bootstrap') - -# if -c was provided, we push it back into args for buildout' main function -if options.config_file is not None: - args[0:0] = ['-c', options.config_file] - -zc.buildout.buildout.main(args) -shutil.rmtree(tmpeggs) @@ -1,14 +1,28 @@ -[nosetests] -nocapture=1 -cover-package=zope.location -cover-erase=1 -with-doctest=0 -where=src +# Generated from: +# https://github.com/zopefoundation/meta/tree/master/config/pure-python +[bdist_wheel] +universal = 1 -[aliases] -dev = develop easy_install zope.location[testing] -docs = easy_install zope.location[docs] +[flake8] +doctests = 1 +# F401 imported but unused +per-file-ignores = + src/zope/location/__init__.py: F401 +[check-manifest] +ignore = + .editorconfig + .meta.toml + docs/_build/html/_sources/* + docs/_build/doctest/* -[bdist_wheel] -universal = 1 +[isort] +force_single_line = True +combine_as_imports = True +sections = FUTURE,STDLIB,THIRDPARTY,ZOPE,FIRSTPARTY,LOCALFOLDER +known_third_party = six, docutils, pkg_resources +known_zope = +known_first_party = +default_section = ZOPE +line_length = 79 +lines_after_imports = 2 @@ -19,12 +19,16 @@ """Setup for zope.location package """ import os -from setuptools import setup, find_packages + +from setuptools import find_packages +from setuptools import setup + def read(*rnames): with open(os.path.join(os.path.dirname(__file__), *rnames)) as f: return f.read() + ZCML_REQUIRES = [ 'zope.configuration', ] @@ -41,7 +45,7 @@ TESTS_REQUIRE = ZCML_REQUIRES + COMPONENT_REQUIRES + [ DOCS_REQUIRE = [ 'Sphinx', 'repoze.sphinx.autointerface', -] + ZCML_REQUIRES + COMPONENT_REQUIRES # doctest snippets need these +] + ZCML_REQUIRES + COMPONENT_REQUIRES # doctest snippets need these setup(name='zope.location', version='4.3.dev0', @@ -64,10 +68,13 @@ setup(name='zope.location', '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 :: 3.9', + 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: 3.11', 'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: PyPy', 'Natural Language :: English', @@ -78,7 +85,7 @@ setup(name='zope.location', url='http://github.com/zopefoundation/zope.location/', packages=find_packages('src'), package_dir={'': 'src'}, - namespace_packages=['zope',], + namespace_packages=['zope', ], install_requires=[ 'setuptools', 'zope.interface>=4.0.2', @@ -94,4 +101,4 @@ setup(name='zope.location', test_suite='zope.location.tests', include_package_data=True, zip_safe=False, -) + ) diff --git a/src/zope/__init__.py b/src/zope/__init__.py index 2cdb0e4..656dc0f 100644 --- a/src/zope/__init__.py +++ b/src/zope/__init__.py @@ -1 +1 @@ -__import__('pkg_resources').declare_namespace(__name__) # pragma: no cover +__import__('pkg_resources').declare_namespace(__name__) # pragma: no cover diff --git a/src/zope/location/__init__.py b/src/zope/location/__init__.py index 104c1ac..ca0e267 100644 --- a/src/zope/location/__init__.py +++ b/src/zope/location/__init__.py @@ -16,5 +16,8 @@ __docformat__ = 'restructuredtext' from zope.location.interfaces import ILocation -from zope.location.location import Location, locate, LocationIterator -from zope.location.location import inside, LocationProxy +from zope.location.location import Location +from zope.location.location import LocationIterator +from zope.location.location import LocationProxy +from zope.location.location import inside +from zope.location.location import locate diff --git a/src/zope/location/interfaces.py b/src/zope/location/interfaces.py index b490a09..c706934 100644 --- a/src/zope/location/interfaces.py +++ b/src/zope/location/interfaces.py @@ -15,8 +15,8 @@ """ __docformat__ = 'restructuredtext' -from zope.interface import Interface from zope.interface import Attribute +from zope.interface import Interface from zope.schema import TextLine @@ -52,9 +52,11 @@ class ILocation(Interface): # used within this package, but is depended upon by external # consumers. + class IContained(ILocation): """Objects contained in containers.""" + class ILocationInfo(Interface): """Provides supplemental information for located objects. @@ -121,12 +123,13 @@ class IRoot(Interface): class LocationError(KeyError, LookupError): """There is no object for a given location.""" + # Soft dependency on zope.component. # # Also, these interfaces used to be defined here directly, so this provides # backward-compatibility try: from zope.component.interfaces import ISite -except ImportError: # pragma: no cover +except ImportError: # pragma: no cover class ISite(Interface): pass diff --git a/src/zope/location/location.py b/src/zope/location/location.py index 3554c51..857ad6f 100644 --- a/src/zope/location/location.py +++ b/src/zope/location/location.py @@ -23,6 +23,7 @@ from zope.proxy.decorator import DecoratorSpecificationDescriptor from zope.location.interfaces import ILocation + @implementer(ILocation) class Location(object): """Mix-in that implements ILocation. @@ -70,6 +71,7 @@ def inside(l1, l2): l1 = getattr(l1, '__parent__', None) return False + class ClassAndInstanceDescr(object): def __init__(self, *args): @@ -93,8 +95,8 @@ class LocationProxy(ProxyBase): __doc__ = ClassAndInstanceDescr( lambda inst: getProxiedObject(inst).__doc__, - lambda cls, __doc__ = __doc__: __doc__, - ) + lambda cls, __doc__=__doc__: __doc__, + ) def __new__(self, ob, container=None, name=None): return ProxyBase.__new__(self, ob) @@ -111,10 +113,10 @@ class LocationProxy(ProxyBase): def __setattr__(self, name, value): if name in self.__slots__ + getattr(ProxyBase, '__slots__', ()): - #('_wrapped', '__parent__', '__name__'): + # ('_wrapped', '__parent__', '__name__'): try: return object.__setattr__(self, name, value) - except TypeError: #pragma NO COVER C Optimization + except TypeError: # pragma NO COVER C Optimization return ProxyBase.__setattr__(self, name, value) return ProxyBase.__setattr__(self, name, value) diff --git a/src/zope/location/pickling.py b/src/zope/location/pickling.py index 46e6217..47181eb 100644 --- a/src/zope/location/pickling.py +++ b/src/zope/location/pickling.py @@ -16,11 +16,14 @@ __docformat__ = 'restructuredtext' from zope.interface import implementer + from zope.location.location import inside + try: - from zope.copy.interfaces import ICopyHook, ResumeCopy -except ImportError: # pragma: no cover + from zope.copy.interfaces import ICopyHook + from zope.copy.interfaces import ResumeCopy +except ImportError: # pragma: no cover raise NotImplementedError("zope.location.pickling is not supported " "because zope.copy is not available") @@ -30,6 +33,7 @@ class LocationCopyHook(object): """Copy hook to preserve copying referenced objects that are not located inside object that's being copied. """ + def __init__(self, context): self.context = context diff --git a/src/zope/location/tests/__init__.py b/src/zope/location/tests/__init__.py index d3173e6..5bb534f 100644 --- a/src/zope/location/tests/__init__.py +++ b/src/zope/location/tests/__init__.py @@ -1 +1 @@ -#package +# package diff --git a/src/zope/location/tests/test_configure.py b/src/zope/location/tests/test_configure.py index ec31efb..332faa5 100644 --- a/src/zope/location/tests/test_configure.py +++ b/src/zope/location/tests/test_configure.py @@ -15,14 +15,16 @@ """ import unittest + class Test_ZCML_loads(unittest.TestCase): def test_it(self): - import zope.component # no registrations made if not present + import zope.component # no registrations made if not present ADAPTERS_REGISTERED = 4 + from zope.configuration.xmlconfig import XMLConfig from zope.configuration.xmlconfig import _clearContext from zope.configuration.xmlconfig import _getContext - from zope.configuration.xmlconfig import XMLConfig + import zope.location _clearContext() diff --git a/src/zope/location/tests/test_location.py b/src/zope/location/tests/test_location.py index ea60099..635a2d9 100644 --- a/src/zope/location/tests/test_location.py +++ b/src/zope/location/tests/test_location.py @@ -18,11 +18,13 @@ class ConformsToILocation(object): def test_class_conforms_to_ILocation(self): from zope.interface.verify import verifyClass + from zope.location.interfaces import ILocation verifyClass(ILocation, self._getTargetClass()) def test_instance_conforms_to_ILocation(self): from zope.interface.verify import verifyObject + from zope.location.interfaces import ILocation verifyObject(ILocation, self._makeOne()) @@ -75,7 +77,9 @@ class Test_located(unittest.TestCase): def test_wo_name_obj_implements_ILocation(self): from zope.interface import implementer + from zope.location.interfaces import ILocation + @implementer(ILocation) class Dummy(object): __parent__ = None @@ -88,11 +92,14 @@ class Test_located(unittest.TestCase): def test_w_name_adaptable_to_ILocation(self): from zope.interface.interface import adapter_hooks + from zope.location.interfaces import ILocation _hooked = [] + def _hook(iface, obj): _hooked.append((iface, obj)) return obj + class Dummy(object): pass parent = Dummy() @@ -206,13 +213,16 @@ class ClassAndInstanceDescrTests(unittest.TestCase): def _makeScaffold(self): _inst_called = [] + def _inst(*args, **kw): _inst_called.append((args, kw)) return 'INST' _class_called = [] + def _class(*args, **kw): _class_called.append((args, kw)) return 'CLASS' + class Foo(object): descr = self._makeOne(_inst, _class) return Foo, _class_called, _inst_called @@ -220,7 +230,7 @@ class ClassAndInstanceDescrTests(unittest.TestCase): def test_fetched_from_class(self): Foo, _class_called, _inst_called = self._makeScaffold() self.assertEqual(Foo.descr, 'CLASS') - self.assertEqual(_class_called, [((Foo,),{})]) + self.assertEqual(_class_called, [((Foo,), {})]) self.assertEqual(_inst_called, []) def test_fetched_from_instance(self): @@ -228,7 +238,7 @@ class ClassAndInstanceDescrTests(unittest.TestCase): foo = Foo() self.assertEqual(foo.descr, 'INST') self.assertEqual(_class_called, []) - self.assertEqual(_inst_called, [((foo,),{})]) + self.assertEqual(_inst_called, [((foo,), {})]) _MARKER = object() @@ -250,13 +260,13 @@ class LocationProxyTests(unittest.TestCase, ConformsToILocation): return self._getTargetClass()(obj, container, name) def test_ctor_defaults(self): - dummy = object() # can't setattr + dummy = object() # can't setattr proxy = self._makeOne(dummy) self.assertEqual(proxy.__parent__, None) self.assertEqual(proxy.__name__, None) def test_ctor_explicit(self): - dummy = object() # can't setattr + dummy = object() # can't setattr parent = object() proxy = self._makeOne(dummy, parent, 'name') self.assertTrue(proxy.__parent__ is parent) @@ -279,19 +289,18 @@ class LocationProxyTests(unittest.TestCase, ConformsToILocation): def test___doc___from_derived_class(self): klass = self._getTargetClass() + class Derived(klass): """DERIVED""" self.assertEqual(Derived.__doc__, 'DERIVED') def test___doc___from_target_class(self): - klass = self._getTargetClass() class Context(object): """CONTEXT""" proxy = self._makeOne(Context()) self.assertEqual(proxy.__doc__, 'CONTEXT') def test___doc___from_target_instance(self): - klass = self._getTargetClass() class Context(object): """CONTEXT""" context = Context() @@ -309,6 +318,7 @@ class LocationProxyTests(unittest.TestCase, ConformsToILocation): def test___reduce___via_pickling(self): import pickle + class Context(object): def __reduce__(self): raise AssertionError("This is not called") @@ -323,10 +333,13 @@ class LocationProxyTests(unittest.TestCase, ConformsToILocation): from zope.interface import implementer from zope.interface import providedBy from zope.interface import provider + class IProxyFactory(Interface): pass + class IProxy(Interface): pass + @provider(IProxyFactory) @implementer(IProxy) class Foo(self._getTargetClass()): @@ -338,26 +351,34 @@ class LocationProxyTests(unittest.TestCase, ConformsToILocation): from zope.interface import implementer from zope.interface import providedBy from zope.interface import provider + from zope.location.interfaces import ILocation + class IProxyFactory(Interface): pass + class IProxy(Interface): pass + class IContextFactory(Interface): pass + class IContext(Interface): pass + @provider(IProxyFactory) @implementer(IProxy) class Proxy(self._getTargetClass()): pass + @provider(IContextFactory) @implementer(IContext) class Context(object): pass context = Context() proxy = Proxy(context) - self.assertEqual(list(providedBy(proxy)), [IContext, IProxy, ILocation]) + self.assertEqual(list(providedBy(proxy)), [ + IContext, IProxy, ILocation]) class LocationPyProxyTests(LocationProxyTests): @@ -368,7 +389,7 @@ class LocationPyProxyTests(LocationProxyTests): 'zope.proxy.decorator'): try: del sys.modules[mod] - except KeyError: # pragma: no cover + except KeyError: # pragma: no cover pass import zope.proxy self.orig = (zope.proxy.ProxyBase, @@ -390,7 +411,6 @@ class LocationPyProxyTests(LocationProxyTests): zope.proxy.removeAllProxies = zope.proxy.py_removeAllProxies zope.proxy.non_overridable = zope.proxy.PyNonOverridable - def tearDown(self): import zope.proxy (zope.proxy.ProxyBase, diff --git a/src/zope/location/tests/test_pickling.py b/src/zope/location/tests/test_pickling.py index 063c9f6..bd1923a 100644 --- a/src/zope/location/tests/test_pickling.py +++ b/src/zope/location/tests/test_pickling.py @@ -14,8 +14,6 @@ import unittest -import zope.copy - class LocationCopyHookTests(unittest.TestCase): def _getTargetClass(self): @@ -28,17 +26,18 @@ class LocationCopyHookTests(unittest.TestCase): return self._getTargetClass()(obj) def test_class_conforms_to_ICopyHook(self): - from zope.interface.verify import verifyClass from zope.copy.interfaces import ICopyHook + from zope.interface.verify import verifyClass verifyClass(ICopyHook, self._getTargetClass()) def test_instance_conforms_to_ICopyHook(self): - from zope.interface.verify import verifyObject from zope.copy.interfaces import ICopyHook + from zope.interface.verify import verifyObject verifyObject(ICopyHook, self._makeOne()) def test___call___w_context_inside_toplevel(self): from zope.copy.interfaces import ResumeCopy + class Dummy(object): __parent__ = __name__ = None top_level = Dummy() @@ -56,6 +55,5 @@ class LocationCopyHookTests(unittest.TestCase): self.assertTrue(hook(top_level, object()) is context) - def test_suite(): return unittest.defaultTestLoader.loadTestsFromName(__name__) diff --git a/src/zope/location/tests/test_traversing.py b/src/zope/location/tests/test_traversing.py index ed82e4b..f4505be 100644 --- a/src/zope/location/tests/test_traversing.py +++ b/src/zope/location/tests/test_traversing.py @@ -18,17 +18,19 @@ class ConformsToILocationInfo(object): def test_class_conforms_to_ILocationInfo(self): from zope.interface.verify import verifyClass + from zope.location.interfaces import ILocationInfo verifyClass(ILocationInfo, self._getTargetClass()) def test_instance_conforms_to_ILocationInfo(self): from zope.interface.verify import verifyObject + from zope.location.interfaces import ILocationInfo verifyObject(ILocationInfo, self._makeOne()) class LocationPhysicallyLocatableTests( - unittest.TestCase, ConformsToILocationInfo): + unittest.TestCase, ConformsToILocationInfo): def _getTargetClass(self): from zope.location.traversing import LocationPhysicallyLocatable @@ -51,7 +53,9 @@ class LocationPhysicallyLocatableTests( def test_getRoot_wo_cycle(self): from zope.interface import directlyProvides + from zope.location.interfaces import IRoot + class Dummy(object): __parent__ = None one = Dummy() @@ -87,7 +91,9 @@ class LocationPhysicallyLocatableTests( def test_getPath_at_root(self): from zope.interface import directlyProvides + from zope.location.interfaces import IRoot + class Dummy(object): __parent__ = __name__ = None one = Dummy() @@ -97,7 +103,9 @@ class LocationPhysicallyLocatableTests( def test_getPath_wo_cycle(self): from zope.interface import directlyProvides + from zope.location.interfaces import IRoot + class Dummy(object): __parent__ = __name__ = None one = Dummy() @@ -137,7 +145,9 @@ class LocationPhysicallyLocatableTests( def test_getParent_at_root(self): from zope.interface import directlyProvides + from zope.location.interfaces import IRoot + class Dummy(object): __parent__ = __name__ = None one = Dummy() @@ -147,7 +157,9 @@ class LocationPhysicallyLocatableTests( def test_getParent_wo_cycle(self): from zope.interface import directlyProvides + from zope.location.interfaces import IRoot + class Dummy(object): __parent__ = __name__ = None one = Dummy() @@ -173,7 +185,9 @@ class LocationPhysicallyLocatableTests( def test_getParents_at_root(self): from zope.interface import directlyProvides + from zope.location.interfaces import IRoot + class Dummy(object): __parent__ = __name__ = None one = Dummy() @@ -183,7 +197,9 @@ class LocationPhysicallyLocatableTests( def test_getParents_wo_cycle(self): from zope.interface import directlyProvides + from zope.location.interfaces import IRoot + class Dummy(object): __parent__ = __name__ = None one = Dummy() @@ -214,8 +230,11 @@ class LocationPhysicallyLocatableTests( self.assertEqual(proxy.getName(), 'name') def test_getNearestSite_context_is_site(self): - from zope.location.interfaces import ISite # zope.component, if present from zope.interface import directlyProvides + + from zope.location.interfaces import \ + ISite # zope.component, if present + class Dummy(object): pass context = Dummy() @@ -224,9 +243,12 @@ class LocationPhysicallyLocatableTests( self.assertTrue(proxy.getNearestSite() is context) def test_getNearestSite_ancestor_is_site(self): - from zope.location.interfaces import ISite # zope.component, if present from zope.interface import directlyProvides + from zope.location.interfaces import IRoot + from zope.location.interfaces import \ + ISite # zope.component, if present + class Dummy(object): pass one = Dummy() @@ -242,7 +264,9 @@ class LocationPhysicallyLocatableTests( def test_getNearestSite_no_site(self): from zope.interface import directlyProvides + from zope.location.interfaces import IRoot + class Dummy(object): __parent__ = __name__ = None one = Dummy() @@ -258,7 +282,7 @@ class LocationPhysicallyLocatableTests( class RootPhysicallyLocatableTests( - unittest.TestCase, ConformsToILocationInfo): + unittest.TestCase, ConformsToILocationInfo): def _getTargetClass(self): from zope.location.traversing import RootPhysicallyLocatable diff --git a/src/zope/location/traversing.py b/src/zope/location/traversing.py index 2e6836c..0b49c9d 100644 --- a/src/zope/location/traversing.py +++ b/src/zope/location/traversing.py @@ -19,13 +19,14 @@ from zope.interface import implementer from zope.location.interfaces import ILocationInfo from zope.location.interfaces import IRoot -from zope.location.interfaces import ISite # zope.component, if present +from zope.location.interfaces import ISite # zope.component, if present @implementer(ILocationInfo) class LocationPhysicallyLocatable(object): """Provide location information for location objects """ + def __init__(self, context): self.context = context @@ -84,7 +85,7 @@ class LocationPhysicallyLocatable(object): # from zope.traversing. parents = [] w = self.context - while 1: + while True: w = getattr(w, '__parent__', None) if w is None: break @@ -110,6 +111,7 @@ class LocationPhysicallyLocatable(object): return parent return self.getRoot() + @implementer(ILocationInfo) class RootPhysicallyLocatable(object): """Provide location information for the root object @@ -118,6 +120,7 @@ class RootPhysicallyLocatable(object): for parents and nearest sites, so we are only working with context object, knowing that its the root object already. """ + def __init__(self, context): self.context = context @@ -1,39 +1,92 @@ +# Generated from: +# https://github.com/zopefoundation/meta/tree/master/config/pure-python [tox] +minversion = 3.18 envlist = -# Jython support pending 2.7 support, due 2012-07-15 or so. See: -# http://fwierzbicki.blogspot.com/2012/03/adconion-to-fund-jython-27.html -# py27,jython,pypy,coverage - py27,py34,py35,py36,py37,pypy,pypy3,coverage + lint + py27 + py35 + py36 + py37 + py38 + py39 + py310 + py311 + pypy + pypy3 + docs + coverage [testenv] -commands = - zope-testrunner --test-path=src [] - sphinx-build -b doctest -d {envdir}/.cache/doctrees docs {envdir}/.cache/doctest +usedevelop = true deps = - .[test,docs] - -[testenv:jython] commands = - jython setup.py test -q + zope-testrunner --test-path=src {posargs:-vc} + !py27-!pypy: sphinx-build -b doctest -d {envdir}/.cache/doctrees docs {envdir}/.cache/doctest +extras = + test + docs -[testenv:coverage] -usedevelop = true -basepython = - python3.7 +[testenv:lint] +basepython = python3 +skip_install = true commands = - coverage run -m zope.testrunner --test-path=src - coverage run -a -m sphinx -b doctest -d {envdir}/.cache/doctrees docs {envdir}/.cache/doctest - coverage report + isort --check-only --diff {toxinidir}/src {toxinidir}/setup.py + flake8 src setup.py + check-manifest + check-python-versions deps = - {[testenv]deps} - coverage + check-manifest + check-python-versions >= 0.19.1 + wheel + flake8 + isort +[testenv:isort-apply] +basepython = python3 +commands_pre = +deps = + isort +commands = + isort {toxinidir}/src {toxinidir}/setup.py [] [testenv:docs] -basepython = - python3.7 +basepython = python3 +skip_install = false +commands_pre = commands = sphinx-build -b html -d docs/_build/doctrees docs docs/_build/html sphinx-build -b doctest -d docs/_build/doctrees docs docs/_build/doctest + +[testenv:coverage] +basepython = python3 +allowlist_externals = + mkdir deps = - .[docs] + coverage + coverage-python-version +commands = + mkdir -p {toxinidir}/parts/htmlcov + coverage run -m zope.testrunner --test-path=src {posargs:-vc} + coverage run -a -m sphinx -b doctest -d {envdir}/.cache/doctrees docs {envdir}/.cache/doctest + coverage html + coverage report -m --fail-under=100 + +[coverage:run] +branch = True +plugins = coverage_python_version +source = zope.location + +[coverage:report] +precision = 2 +exclude_lines = + pragma: no cover + pragma: nocover + except ImportError: + raise NotImplementedError + if __name__ == '__main__': + self.fail + raise AssertionError + +[coverage:html] +directory = parts/htmlcov |