summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Howitz <mh@gocept.com>2023-01-09 16:38:40 +0100
committerGitHub <noreply@github.com>2023-01-09 16:38:40 +0100
commitae3a111230d0fd6e7c95fdf9f1cb33d7c3584ea7 (patch)
tree45fb0fa9ebbeacf6cbb772abf78a4a3376a9d8a9
parent65064f94db2680cb694dd94688221c529061e48e (diff)
downloadzope-traversing-ae3a111230d0fd6e7c95fdf9f1cb33d7c3584ea7.tar.gz
Config with pure python template (#19)
* Drop support for Python 2.7, 3.5, 3.6. * Add support for Python 3.11.
-rw-r--r--.github/workflows/tests.yml17
-rw-r--r--.meta.toml4
-rw-r--r--CHANGES.rst6
-rw-r--r--setup.cfg2
-rw-r--r--setup.py17
-rw-r--r--src/zope/traversing/adapters.py25
-rw-r--r--src/zope/traversing/api.py38
-rw-r--r--src/zope/traversing/browser/absoluteurl.py19
-rw-r--r--src/zope/traversing/browser/interfaces.py8
-rw-r--r--src/zope/traversing/browser/tests.py33
-rw-r--r--src/zope/traversing/namespace.py19
-rw-r--r--src/zope/traversing/publicationtraverse.py6
-rw-r--r--src/zope/traversing/testing.py4
-rw-r--r--src/zope/traversing/tests/test_conveniencefunctions.py70
-rw-r--r--src/zope/traversing/tests/test_lang.py2
-rw-r--r--src/zope/traversing/tests/test_namespacetrversal.py24
-rw-r--r--src/zope/traversing/tests/test_presentation.py6
-rw-r--r--src/zope/traversing/tests/test_publicationtraverse.py12
-rw-r--r--src/zope/traversing/tests/test_skin.py4
-rw-r--r--src/zope/traversing/tests/test_traverser.py31
-rw-r--r--src/zope/traversing/tests/test_vh.py8
-rw-r--r--src/zope/traversing/tests/test_vhosting.py32
-rw-r--r--tox.ini12
23 files changed, 143 insertions, 256 deletions
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index f9f622d..2ca497a 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -17,33 +17,30 @@ jobs:
fail-fast: false
matrix:
os:
- - ubuntu
+ - ["ubuntu", "ubuntu-20.04"]
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"]
- - ["pypy-2.7", "pypy"]
+ - ["3.11", "py311"]
- ["pypy-3.7", "pypy3"]
- ["3.9", "docs"]
- ["3.9", "coverage"]
- runs-on: ${{ matrix.os }}-latest
+ runs-on: ${{ matrix.os[1] }}
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@v2
+ - uses: actions/checkout@v3
- name: Set up Python
- uses: actions/setup-python@v2
+ uses: actions/setup-python@v4
with:
python-version: ${{ matrix.config[0] }}
- name: Pip cache
- uses: actions/cache@v2
+ uses: actions/cache@v3
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ matrix.config[0] }}-${{ hashFiles('setup.*', 'tox.ini') }}
@@ -59,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 1c0c52d..5a70e7f 100644
--- a/.meta.toml
+++ b/.meta.toml
@@ -2,15 +2,15 @@
# https://github.com/zopefoundation/meta/tree/master/config/pure-python
[meta]
template = "pure-python"
-commit-id = "d5b6c610d0ec7f0b8f6bbba49353eb89288f62b1"
+commit-id = "d03ad585"
[python]
with-windows = false
with-pypy = true
with-future-python = false
-with-legacy-python = true
with-docs = true
with-sphinx-doctests = false
+with-macos = false
[tox]
use-flake8 = true
diff --git a/CHANGES.rst b/CHANGES.rst
index 2b009e8..203b28b 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -2,9 +2,13 @@
Changes
=========
-4.5 (unreleased)
+5.0 (unreleased)
================
+- Add support for Python 3.11.
+
+- Drop support for Python 2.7, 3.5, 3.6.
+
- Add support for Python 3.9, 3.10.
diff --git a/setup.cfg b/setup.cfg
index 04032f5..043841c 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
diff --git a/setup.py b/setup.py
index c2164ff..fc38030 100644
--- a/setup.py
+++ b/setup.py
@@ -46,7 +46,7 @@ TESTS_REQUIRE = [
setup(
name='zope.traversing',
- version='4.5.dev0',
+ version='5.0.dev0',
url='https://github.com/zopefoundation/zope.traversing',
license='ZPL 2.1',
author='Zope Foundation and Contributors',
@@ -59,15 +59,12 @@ setup(
'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',
'Programming Language :: Python :: 3.10',
+ 'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: Implementation :: CPython',
'Programming Language :: Python :: Implementation :: PyPy',
'Natural Language :: English',
@@ -87,7 +84,6 @@ setup(
},
install_requires=[
'setuptools',
- 'six',
'transaction',
'zope.component',
'zope.i18n',
@@ -101,12 +97,5 @@ setup(
tests_require=TESTS_REQUIRE,
include_package_data=True,
zip_safe=False,
- python_requires=', '.join([
- '>=2.7',
- '!=3.0.*',
- '!=3.1.*',
- '!=3.2.*',
- '!=3.3.*',
- '!=3.4.*',
- ]),
+ python_requires='>=3.7',
)
diff --git a/src/zope/traversing/adapters.py b/src/zope/traversing/adapters.py
index 3ce5aee..2deae8f 100644
--- a/src/zope/traversing/adapters.py
+++ b/src/zope/traversing/adapters.py
@@ -15,8 +15,6 @@
Adapters for the traversing mechanism.
"""
-import six
-
import zope.interface
from zope.location.interfaces import ILocationInfo
from zope.location.interfaces import LocationError
@@ -32,7 +30,7 @@ _marker = object() # opaque marker that doesn't get security proxied
@zope.interface.implementer(ITraversable)
-class DefaultTraversable(object):
+class DefaultTraversable:
"""
Traverses objects via attribute and item lookup.
@@ -45,14 +43,7 @@ class DefaultTraversable(object):
def traverse(self, name, furtherPath):
subject = self._subject
__traceback_info__ = (subject, name, furtherPath)
- try:
- attr = getattr(subject, name, _marker)
- except UnicodeEncodeError:
- # If we're on Python 2, and name was a unicode string the
- # name would have been encoded using the system encoding
- # (usually ascii). Failure to encode means invalid
- # attribute name.
- attr = _marker
+ attr = getattr(subject, name, _marker)
if attr is not _marker:
return attr
if hasattr(subject, '__getitem__'):
@@ -64,7 +55,7 @@ class DefaultTraversable(object):
@zope.interface.implementer(ITraverser)
-class Traverser(object):
+class Traverser:
"""
Provide traverse features.
@@ -80,7 +71,7 @@ class Traverser(object):
if not path:
return self.context
- if isinstance(path, six.string_types):
+ if isinstance(path, str):
path = path.split('/')
if len(path) > 1 and not path[-1]:
# Remove trailing slash
@@ -156,14 +147,6 @@ def traversePathElement(obj, name, further_path, default=_marker,
try:
return traversable.traverse(nm, further_path)
- except UnicodeEncodeError:
- # If we're on Python 2, and nm was a unicode string, and the
- # traversable tried to do an attribute lookup, the nm would have been
- # encoded using the system encoding (usually ascii). Failure to encode
- # means invalid attribute name.
- if default is not _marker:
- return default
- raise LocationError(obj, name)
except LocationError:
if default is not _marker:
return default
diff --git a/src/zope/traversing/api.py b/src/zope/traversing/api.py
index 0f7ec65..89ad786 100644
--- a/src/zope/traversing/api.py
+++ b/src/zope/traversing/api.py
@@ -16,12 +16,11 @@ Convenience functions for traversing the object tree.
This module provides :class:`zope.traversing.interfaces.ITraversalAPI`
"""
-import six
-
from zope.interface import moduleProvides
from zope.location.interfaces import ILocationInfo
from zope.location.interfaces import IRoot
+from zope.traversing.adapters import traversePathElement
from zope.traversing.interfaces import ITraversalAPI
from zope.traversing.interfaces import ITraverser
@@ -43,16 +42,15 @@ def joinPath(path, *args):
"""
if not args:
- # Concatenating u'' is much quicker than unicode(path)
- return u'' + path
+ return path
if path != '/' and path.endswith('/'):
raise ValueError('path must not end with a "/": %s' % path)
if path != '/':
- path += u'/'
+ path += '/'
for arg in args:
if arg.startswith('/') or arg.endswith('/'):
raise ValueError("Leading or trailing slashes in path elements")
- return _normalizePath(path + u'/'.join(args))
+ return _normalizePath(path + '/'.join(args))
def getPath(obj):
@@ -155,19 +153,19 @@ def _normalizePath(path):
"""Normalize a path by resolving '.' and '..' path elements."""
# Special case for the root path.
- if path == u'/':
+ if path == '/':
return path
new_segments = []
- prefix = u''
+ prefix = ''
if path.startswith('/'):
- prefix = u'/'
+ prefix = '/'
path = path[1:]
- for segment in path.split(u'/'):
- if segment == u'.':
+ for segment in path.split('/'):
+ if segment == '.':
continue
- if segment == u'..':
+ if segment == '..':
new_segments.pop() # raises IndexError if there is nothing to pop
continue
if not segment:
@@ -175,7 +173,7 @@ def _normalizePath(path):
% path)
new_segments.append(segment)
- return prefix + u'/'.join(new_segments)
+ return prefix + '/'.join(new_segments)
def canonicalPath(path_or_object):
@@ -185,32 +183,28 @@ def canonicalPath(path_or_object):
See `ITraversalAPI` for details.
"""
- if isinstance(path_or_object, six.string_types):
+ if isinstance(path_or_object, str):
path = path_or_object
if not path:
raise ValueError("path must be non-empty: %s" % path)
else:
path = getPath(path_or_object)
- path = u'' + path
+ path = '' + path
# Special case for the root path.
- if path == u'/':
+ if path == '/':
return path
- if path[0] != u'/':
+ if path[0] != '/':
raise ValueError('canonical path must start with a "/": %s' % path)
- if path[-1] == u'/':
+ if path[-1] == '/':
raise ValueError('path must not end with a "/": %s' % path)
# Break path into segments. Process '.' and '..' segments.
return _normalizePath(path)
-# import this down here to avoid circular imports
-from zope.traversing.adapters import traversePathElement
-
-
# Synchronize the documentation.
for name in ITraversalAPI.names():
if name in globals():
diff --git a/src/zope/traversing/browser/absoluteurl.py b/src/zope/traversing/browser/absoluteurl.py
index 0cdddae..7be68f5 100644
--- a/src/zope/traversing/browser/absoluteurl.py
+++ b/src/zope/traversing/browser/absoluteurl.py
@@ -18,15 +18,8 @@ These are registered as views and named views (``absolute_url``) if
you load this package's ``configure.zcml`` with
:mod:`zope.configuration.xmlconfig`.
"""
-try:
- from urllib.parse import quote_from_bytes as quote
-except ImportError:
- from urllib import quote
-
-try:
- from urllib.parse import unquote_to_bytes as unquote
-except ImportError:
- from urllib import unquote
+from urllib.parse import quote_from_bytes as quote
+from urllib.parse import unquote_to_bytes as unquote
import zope.component
from zope.i18nmessageid import MessageFactory
@@ -133,8 +126,8 @@ class AbsoluteURL(_EncodedUnicode,
base += (
{
'name': name,
- 'url': ("%s/%s" % (base[-1]['url'],
- quote(name.encode('utf-8'), _safe)))
+ 'url': ("{}/{}".format(base[-1]['url'],
+ quote(name.encode('utf-8'), _safe)))
},
)
@@ -181,8 +174,8 @@ class SiteAbsoluteURL(_EncodedUnicode,
base += (
{
'name': name,
- 'url': ("%s/%s" % (base[-1]['url'],
- quote(name.encode('utf-8'), _safe)))
+ 'url': ("{}/{}".format(base[-1]['url'],
+ quote(name.encode('utf-8'), _safe)))
},
)
diff --git a/src/zope/traversing/browser/interfaces.py b/src/zope/traversing/browser/interfaces.py
index 21a6a24..2d4f0d8 100644
--- a/src/zope/traversing/browser/interfaces.py
+++ b/src/zope/traversing/browser/interfaces.py
@@ -25,16 +25,16 @@ class IAbsoluteURL(Interface):
"""
def __unicode__():
- """Returns the URL as a unicode string."""
+ """Return the URL as unquoted str."""
def __str__():
- """Returns an ASCII string with all unicode characters url quoted."""
+ """Return a ASCII string with all non-ASCII characters url quoted."""
def __repr__():
- """Get a string representation """
+ """Get a string representation."""
def __call__():
- """Returns an ASCII string with all unicode characters url quoted."""
+ """Return an ASCII string with all non-ASCII characters url quoted."""
def breadcrumbs():
"""Returns a tuple like ({'name':name, 'url':url}, ...)
diff --git a/src/zope/traversing/browser/tests.py b/src/zope/traversing/browser/tests.py
index dde3eeb..0430880 100644
--- a/src/zope/traversing/browser/tests.py
+++ b/src/zope/traversing/browser/tests.py
@@ -46,21 +46,21 @@ class Root(Contained):
pass
-class TrivialContent(object):
+class TrivialContent:
"""Trivial content object, used because instances of object are rocks."""
-class AdaptedContent(object):
+class AdaptedContent:
"""A simple content object that has an ILocation adapter for it."""
-class FooContent(object):
+class FooContent:
"""Class whose location will be provided by an adapter."""
@implementer(ILocation)
@adapter(FooContent)
-class FooLocation(object):
+class FooLocation:
"""Adapts FooAdapter to the ILocation protocol."""
def __init__(self, context):
@@ -77,11 +77,6 @@ class FooLocation(object):
class TestAbsoluteURL(PlacelessSetup, unittest.TestCase):
- assertRaisesRegex = getattr(
- unittest.TestCase,
- 'assertRaisesRegex',
- getattr(unittest.TestCase, 'assertRaisesRegexp')) # PY2
-
def setUp(self):
PlacelessSetup.setUp(self)
from zope.traversing.browser import AbsoluteURL
@@ -195,11 +190,11 @@ class TestAbsoluteURL(PlacelessSetup, unittest.TestCase):
# Tests so that AbsoluteURL handle unicode names as well
request = TestRequest()
root = Root()
- root.__name__ = u'\u0439'
+ root.__name__ = '\u0439'
- content = contained(TrivialContent(), root, name=u'\u0442')
- content = contained(TrivialContent(), content, name=u'\u0435')
- content = contained(TrivialContent(), content, name=u'\u0441')
+ content = contained(TrivialContent(), root, name='\u0442')
+ content = contained(TrivialContent(), content, name='\u0435')
+ content = contained(TrivialContent(), content, name='\u0441')
view = getMultiAdapter((content, request), name='absolute_url')
self.assertEqual(str(view),
'http://127.0.0.1/%D0%B9/%D1%82/%D0%B5/%D1%81')
@@ -215,13 +210,13 @@ class TestAbsoluteURL(PlacelessSetup, unittest.TestCase):
breadcrumbs, (
{'name': '',
'url': 'http://127.0.0.1'},
- {'name': u'\u0439',
+ {'name': '\u0439',
'url': 'http://127.0.0.1/%D0%B9'},
- {'name': u'\u0442',
+ {'name': '\u0442',
'url': 'http://127.0.0.1/%D0%B9/%D1%82'},
- {'name': u'\u0435',
+ {'name': '\u0435',
'url': 'http://127.0.0.1/%D0%B9/%D1%82/%D0%B5'},
- {'name': u'\u0441',
+ {'name': '\u0441',
'url': 'http://127.0.0.1/%D0%B9/%D1%82/%D0%B5/%D1%81'}))
def testRetainSkin(self):
@@ -323,11 +318,11 @@ class TestAbsoluteURL(PlacelessSetup, unittest.TestCase):
def test_nameless_context(self):
@implementer(ILocation)
- class Context(object):
+ class Context:
__parent__ = self
__name__ = None
- class DummyAbsoluteURL(object):
+ class DummyAbsoluteURL:
# Our implementation of IAbsoluteURL
# for our parent
diff --git a/src/zope/traversing/namespace.py b/src/zope/traversing/namespace.py
index 31f4ef4..08609e2 100644
--- a/src/zope/traversing/namespace.py
+++ b/src/zope/traversing/namespace.py
@@ -63,8 +63,6 @@ __docformat__ = 'restructuredtext'
import re
-import six
-
import zope.component
import zope.interface
from zope.i18n.interfaces import IModifiableUserPreferredLanguages
@@ -125,7 +123,7 @@ def namespaceLookup(ns, name, object, request=None):
>>> namespaceLookup('fiz', 'bar', C()) # doctest: +ELLIPSIS
Traceback (most recent call last):
...
- LocationError: (<zope.traversing.namespace.C object at 0x...>, '++fiz++bar')
+ zope.location.interfaces.LocationError: (<zope.traversing.namespace.C object at 0x...>, '++fiz++bar')
We'll get the same thing if we provide a request::
@@ -134,7 +132,7 @@ def namespaceLookup(ns, name, object, request=None):
>>> namespaceLookup('foo', 'bar', C(), request) # doctest: +ELLIPSIS
Traceback (most recent call last):
...
- LocationError: (<zope.traversing.namespace.C object at 0x...>, '++foo++bar')
+ zope.location.interfaces.LocationError: (<zope.traversing.namespace.C object at 0x...>, '++foo++bar')
We need to provide a view::
@@ -161,7 +159,7 @@ def namespaceLookup(ns, name, object, request=None):
traverser = zope.component.queryAdapter(object, ITraversable, ns)
if traverser is None:
- raise LocationError(object, "++%s++%s" % (ns, name))
+ raise LocationError(object, "++{}++{}".format(ns, name))
return traverser.traverse(name, ())
@@ -236,7 +234,7 @@ def queryResource(context, name, request, default=None):
# ---- namespace processors below ----
@zope.interface.implementer(ITraversable)
-class SimpleHandler(object):
+class SimpleHandler:
def __init__(self, context, request=None):
"""
@@ -295,7 +293,7 @@ class acquire(SimpleHandler):
>>> adapter.traverse('d', ())
Traceback (most recent call last):
...
- LocationError: (splat, 'd')
+ zope.location.interfaces.LocationError: (splat, 'd')
"""
i = 0
ob = self.context
@@ -400,7 +398,7 @@ class etc(SimpleHandler):
@zope.interface.implementer(ITraversable)
-class view(object):
+class view:
"""
Traversal adapter for the ``view`` (``@@``) namespace.
@@ -500,11 +498,6 @@ class vh(view):
request = self.request
- if not six.PY3:
- # `name` comes in as unicode, we need to make it a string
- # so absolute URLs don't all become unicode.
- name = name.encode('utf-8')
-
if name:
try:
proto, host, port = name.split(":")
diff --git a/src/zope/traversing/publicationtraverse.py b/src/zope/traversing/publicationtraverse.py
index 301d939..437e2de 100644
--- a/src/zope/traversing/publicationtraverse.py
+++ b/src/zope/traversing/publicationtraverse.py
@@ -15,8 +15,6 @@
"""
__docformat__ = 'restructuredtext'
-import six
-
from zope.component import queryMultiAdapter
from zope.publisher.interfaces import IPublishTraverse
from zope.publisher.interfaces import NotFound
@@ -28,7 +26,7 @@ from zope.traversing.namespace import namespaceLookup
from zope.traversing.namespace import nsParse
-class PublicationTraverser(object):
+class PublicationTraverser:
"""Traversal used for publication.
The significant differences from
@@ -83,7 +81,7 @@ class PublicationTraverser(object):
def traversePath(self, request, ob, path):
- if isinstance(path, six.string_types):
+ if isinstance(path, str):
path = path.split('/')
if len(path) > 1 and not path[-1]:
# Remove trailing slash
diff --git a/src/zope/traversing/testing.py b/src/zope/traversing/testing.py
index 5a54f33..adbc0a7 100644
--- a/src/zope/traversing/testing.py
+++ b/src/zope/traversing/testing.py
@@ -35,13 +35,13 @@ from zope.traversing.namespace import etc
@zope.interface.implementer(IContained)
-class Contained(object):
+class Contained:
__parent__ = None
__name__ = None
@zope.interface.implementer(IContained)
-class ContainedProxy(object):
+class ContainedProxy:
__parent__ = None
__name__ = None
__obj__ = None
diff --git a/src/zope/traversing/tests/test_conveniencefunctions.py b/src/zope/traversing/tests/test_conveniencefunctions.py
index 1f8baf7..9354cf4 100644
--- a/src/zope/traversing/tests/test_conveniencefunctions.py
+++ b/src/zope/traversing/tests/test_conveniencefunctions.py
@@ -31,7 +31,7 @@ from zope.traversing.interfaces import ITraverser
from zope.traversing.testing import contained
-class C(object):
+class C:
__parent__ = None
__name__ = None
@@ -136,23 +136,6 @@ class TestFunctional(PlacelessSetup, unittest.TestCase):
self.folder, './item'
)
- def testTraverseNameUnicode(self):
- from zope.interface import implementer
-
- from zope.traversing.api import traverseName
-
- @implementer(ITraversable)
- class BrokenTraversable(object):
- def traverse(self, name, furtherPath):
- getattr(self, u'\u2019', None)
- # The above actually works on Python 3
- raise unittest.SkipTest("Unicode attrs legal on Py3")
-
- self.assertRaises(
- LocationError,
- traverseName,
- BrokenTraversable(), '')
-
def testGetName(self):
from zope.traversing.api import getName
self.assertEqual(
@@ -209,21 +192,21 @@ class TestFunctional(PlacelessSetup, unittest.TestCase):
from zope.traversing.api import getPath
self.assertEqual(
getPath(self.item),
- u'/folder/item'
+ '/folder/item'
)
def testGetPathOfRoot(self):
from zope.traversing.api import getPath
self.assertEqual(
getPath(self.root),
- u'/',
+ '/',
)
def testGetNameOfRoot(self):
from zope.traversing.api import getName
self.assertEqual(
getName(self.root),
- u'',
+ '',
)
def testGetRoot(self):
@@ -259,18 +242,18 @@ class TestFunctional(PlacelessSetup, unittest.TestCase):
_good_locations = (
# location returned as string
- (u'/xx/yy/zz',
+ ('/xx/yy/zz',
# arguments to try in addition to the above
'/xx/yy/zz',
'/xx/./yy/ww/../zz',
),
- (u'/xx/yy/zz',
+ ('/xx/yy/zz',
'/xx/yy/zz',
),
- (u'/xx',
+ ('/xx',
'/xx',
),
- (u'/',
+ ('/',
'/',
self.root,
),
@@ -339,7 +322,7 @@ class TestFunctional(PlacelessSetup, unittest.TestCase):
def test_joinPath_slashes(self):
from zope.traversing.api import joinPath
- path = u'/'
+ path = '/'
args = ('/test', 'bla', '/foo', 'bar')
self.assertRaises(ValueError, joinPath, path, *args)
@@ -348,56 +331,51 @@ class TestFunctional(PlacelessSetup, unittest.TestCase):
def test_joinPath(self):
from zope.traversing.api import joinPath
- path = u'/bla'
+ path = '/bla'
args = ('foo', 'bar', 'baz', 'bone')
- self.assertEqual(joinPath(path, *args), u'/bla/foo/bar/baz/bone')
+ self.assertEqual(joinPath(path, *args), '/bla/foo/bar/baz/bone')
- path = u'bla'
+ path = 'bla'
args = ('foo', 'bar', 'baz', 'bone')
- self.assertEqual(joinPath(path, *args), u'bla/foo/bar/baz/bone')
+ self.assertEqual(joinPath(path, *args), 'bla/foo/bar/baz/bone')
- path = u'bla'
+ path = 'bla'
args = ('foo', 'bar/baz', 'bone')
- self.assertEqual(joinPath(path, *args), u'bla/foo/bar/baz/bone')
+ self.assertEqual(joinPath(path, *args), 'bla/foo/bar/baz/bone')
- path = u'bla/'
+ path = 'bla/'
args = ('foo', 'bar', 'baz', 'bone')
self.assertRaises(ValueError, joinPath, path, *args)
def test_joinPath_normalize(self):
from zope.traversing.api import joinPath
- path = u'/bla'
+ path = '/bla'
args = ('foo', 'bar', '..', 'baz', 'bone')
- self.assertEqual(joinPath(path, *args), u'/bla/foo/baz/bone')
+ self.assertEqual(joinPath(path, *args), '/bla/foo/baz/bone')
- path = u'bla'
+ path = 'bla'
args = ('foo', 'bar', '.', 'baz', 'bone')
- self.assertEqual(joinPath(path, *args), u'bla/foo/bar/baz/bone')
+ self.assertEqual(joinPath(path, *args), 'bla/foo/bar/baz/bone')
- path = u'/'
+ path = '/'
args = ('foo', 'bar', '.', 'baz', 'bone')
- self.assertEqual(joinPath(path, *args), u'/foo/bar/baz/bone')
+ self.assertEqual(joinPath(path, *args), '/foo/bar/baz/bone')
def test_joinPath_empty_args(self):
from zope.traversing.api import joinPath
path = 'abc'
- self.assertEqual(joinPath(path), u'abc')
+ self.assertEqual(joinPath(path), 'abc')
class TestStandalone(unittest.TestCase):
# Unlike TestFunctional, we don't register gobs of
# adapters, making these tests more self-contained
- assertRaisesRegex = getattr(
- unittest.TestCase,
- 'assertRaisesRegex',
- getattr(unittest.TestCase, 'assertRaisesRegexp')) # PY2
-
def test_getParent_no_location_info(self):
from zope.traversing.api import getParent
test = self
- class Context(object):
+ class Context:
called = False
def __conform__(self, iface):
diff --git a/src/zope/traversing/tests/test_lang.py b/src/zope/traversing/tests/test_lang.py
index 8590161..e667e14 100644
--- a/src/zope/traversing/tests/test_lang.py
+++ b/src/zope/traversing/tests/test_lang.py
@@ -38,7 +38,7 @@ class TestRequest(test_browserlanguages.TestRequest):
class Test(CleanUp, unittest.TestCase):
def setUp(self):
- super(Test, self).setUp()
+ super().setUp()
self.request = TestRequest("en")
directlyProvides(self.request, IHTTPRequest, IAttributeAnnotatable)
diff --git a/src/zope/traversing/tests/test_namespacetrversal.py b/src/zope/traversing/tests/test_namespacetrversal.py
index cadbd78..1303954 100644
--- a/src/zope/traversing/tests/test_namespacetrversal.py
+++ b/src/zope/traversing/tests/test_namespacetrversal.py
@@ -13,7 +13,6 @@
##############################################################################
"""Traversal Namespace Tests
"""
-import re
import unittest
from doctest import DocTestSuite
@@ -21,7 +20,6 @@ from zope.component.testing import PlacelessSetup
from zope.component.testing import setUp
from zope.component.testing import tearDown
from zope.location.interfaces import LocationError
-from zope.testing.renormalizing import RENormalizing
from zope import component
from zope import interface
@@ -52,7 +50,7 @@ class TestAcquire(unittest.TestCase):
from zope.traversing.namespace import ExcessiveDepth
@interface.implementer(ITraversable)
- class Context(object):
+ class Context:
max_call_count = 200
@@ -78,7 +76,7 @@ class TestEtc(PlacelessSetup, unittest.TestCase):
def test_traverse_site_no_manager(self):
test = self
- class Context(object):
+ class Context:
def __getattribute__(self, name):
test.assertEqual(name, 'getSiteManager')
return None
@@ -91,7 +89,7 @@ class TestEtc(PlacelessSetup, unittest.TestCase):
self.assertEqual((context, 'site'), ex.args)
def test_traverse_site_lookup_error(self):
- class Context(object):
+ class Context:
called = False
def getSiteManager(self):
@@ -128,27 +126,15 @@ class TestView(unittest.TestCase):
class TestVh(unittest.TestCase):
- assertRaisesRegex = getattr(
- unittest.TestCase,
- 'assertRaisesRegex',
- getattr(unittest.TestCase, 'assertRaisesRegexp')) # PY2
-
def test_invalid_vh(self):
with self.assertRaisesRegex(ValueError,
'Vhost directive should have the form'):
- namespace.vh(None, None).traverse(u'invalid name', ())
+ namespace.vh(None, None).traverse('invalid name', ())
def test_suite():
- checker = RENormalizing([
- # Python 3 includes module name in exceptions
- (re.compile(r"zope.location.interfaces.LocationError"),
- "LocationError"),
- ])
-
suite = unittest.defaultTestLoader.loadTestsFromName(__name__)
suite.addTest(DocTestSuite(
'zope.traversing.namespace',
- setUp=setUp, tearDown=tearDown,
- checker=checker))
+ setUp=setUp, tearDown=tearDown))
return suite
diff --git a/src/zope/traversing/tests/test_presentation.py b/src/zope/traversing/tests/test_presentation.py
index 17b9df6..b8fa189 100644
--- a/src/zope/traversing/tests/test_presentation.py
+++ b/src/zope/traversing/tests/test_presentation.py
@@ -31,17 +31,17 @@ class IContent(Interface):
@implementer(IContent)
-class Content(object):
+class Content:
pass
-class Resource(object):
+class Resource:
def __init__(self, request):
pass
-class View(object):
+class View:
def __init__(self, content, request):
self.content = content
diff --git a/src/zope/traversing/tests/test_publicationtraverse.py b/src/zope/traversing/tests/test_publicationtraverse.py
index 8218314..731d4a7 100644
--- a/src/zope/traversing/tests/test_publicationtraverse.py
+++ b/src/zope/traversing/tests/test_publicationtraverse.py
@@ -175,7 +175,7 @@ class TestPublicationTraverser(CleanUp, unittest.TestCase):
def traversePath(self, request, ob, path):
return ob
- class Context(object):
+ class Context:
called = False
def __conform__(self, iface):
@@ -212,17 +212,17 @@ class IContent(Interface):
@implementer(IContent)
-class Content(object):
+class Content:
pass
-class View(object):
+class View:
def __init__(self, name):
self.name = name
@implementer(ITraversable)
-class DummyViewTraverser(object):
+class DummyViewTraverser:
def __init__(self, content, request):
self.content = content
@@ -232,7 +232,7 @@ class DummyViewTraverser(object):
@implementer(IPublishTraverse)
-class DummyPublishTraverse(object):
+class DummyPublishTraverse:
def __init__(self, context, request):
pass
@@ -242,7 +242,7 @@ class DummyPublishTraverse(object):
@implementer(IBrowserPublisher)
-class DummyBrowserPublisher(object):
+class DummyBrowserPublisher:
def __init__(self, context):
self.context = removeSecurityProxy(context)
diff --git a/src/zope/traversing/tests/test_skin.py b/src/zope/traversing/tests/test_skin.py
index 8460428..91b8d7b 100644
--- a/src/zope/traversing/tests/test_skin.py
+++ b/src/zope/traversing/tests/test_skin.py
@@ -22,7 +22,7 @@ from zope.publisher.interfaces.browser import IBrowserSkinType
from zope.testing.cleanup import CleanUp
-class FauxRequest(object):
+class FauxRequest:
def shiftNameToApplication(self):
self.shifted = 1
@@ -37,7 +37,7 @@ directlyProvides(IFoo, IBrowserSkinType)
class Test(CleanUp, unittest.TestCase):
def setUp(self):
- super(Test, self).setUp()
+ super().setUp()
zope.component.provideUtility(IFoo, IBrowserSkinType, name='foo')
def test(self):
diff --git a/src/zope/traversing/tests/test_traverser.py b/src/zope/traversing/tests/test_traverser.py
index 69ff88b..3d4a4ef 100644
--- a/src/zope/traversing/tests/test_traverser.py
+++ b/src/zope/traversing/tests/test_traverser.py
@@ -42,7 +42,7 @@ from zope.traversing.testing import Contained
from zope.traversing.testing import contained
-class ParticipationStub(object):
+class ParticipationStub:
def __init__(self, principal):
self.principal = principal
@@ -126,9 +126,9 @@ class UnrestrictedTraverseTests(PlacelessSetup, unittest.TestCase):
tr = self.tr
item = self.item
- self.assertEqual(tr.traverse(u'/folder/item'), item)
- self.assertEqual(tr.traverse(u'folder/item'), item)
- self.assertEqual(tr.traverse(u'/folder/item/'), item)
+ self.assertEqual(tr.traverse('/folder/item'), item)
+ self.assertEqual(tr.traverse('folder/item'), item)
+ self.assertEqual(tr.traverse('/folder/item/'), item)
def testSimplePathTuple(self):
tr = self.tr
@@ -294,32 +294,13 @@ class DefaultTraversableTests(unittest.TestCase):
def testUnicodeTraversal(self):
df = DefaultTraversable(object())
- self.assertRaises(LocationError, df.traverse, u'\u2019', ())
+ self.assertRaises(LocationError, df.traverse, '\u2019', ())
class TestFunctions(unittest.TestCase):
- def test_traversePathElement_UnicodeEncodeError_with_default(self):
- test = self
-
- class Traversable(object):
- called = False
- fail = test.fail
-
- def traverse(self, nm, further_path):
- self.called = True
- u'\xff'.encode("ascii")
- self.fail("Should not be reached")
-
- t = Traversable()
- self.assertIs(self,
- adapters.traversePathElement(None, None, (),
- default=self,
- traversable=t))
- self.assertTrue(t.called)
-
def test_traversePathElement_LocationError_with_default(self):
- class Traversable(object):
+ class Traversable:
called = False
def traverse(self, nm, further_path):
diff --git a/src/zope/traversing/tests/test_vh.py b/src/zope/traversing/tests/test_vh.py
index d70c408..99e284c 100644
--- a/src/zope/traversing/tests/test_vh.py
+++ b/src/zope/traversing/tests/test_vh.py
@@ -16,7 +16,7 @@
import unittest
-class TestRequest(object):
+class TestRequest:
def __init__(self, names=None, stack=None):
self._traversal_stack = stack
@@ -31,9 +31,9 @@ class TestRequest(object):
self._traversal_stack[:] = list(stack)
def setApplicationServer(self, host, proto='http', port=None):
- host = "%s://%s" % (proto, host)
+ host = f"{proto}://{host}"
if port:
- host = "%s:%s" % (host, port)
+ host = f"{host}:{port}"
self._app_server = host
def setVirtualHostRoot(self, names=None):
@@ -82,7 +82,7 @@ class TestVHNamespace(unittest.TestCase):
request = TestRequest(['folder1'], ['folder1_1', '++'])
ob = object()
- vh(ob, request).traverse(u'http:www.fubarco.com:80', ())
+ vh(ob, request).traverse('http:www.fubarco.com:80', ())
self.assertTrue(
isinstance(request._app_server, str),
repr(request._app_server))
diff --git a/src/zope/traversing/tests/test_vhosting.py b/src/zope/traversing/tests/test_vhosting.py
index df35500..c049291 100644
--- a/src/zope/traversing/tests/test_vhosting.py
+++ b/src/zope/traversing/tests/test_vhosting.py
@@ -76,7 +76,7 @@ class RootFolder(Folder):
# Copy some code from zope.pagetemplate to avoid the depedency (break circle)
-class ZopeTraverser(object):
+class ZopeTraverser:
def __call__(self, object, path_items, econtext):
request = econtext._vars_stack[0].get('request', None)
@@ -97,7 +97,7 @@ zopeTraverser = ZopeTraverser()
class PathExpr(expressions.PathExpr):
def __init__(self, name, expr, engine):
- super(PathExpr, self).__init__(name, expr, engine, zopeTraverser)
+ super().__init__(name, expr, engine, zopeTraverser)
def Engine():
@@ -110,7 +110,7 @@ def Engine():
Engine = Engine()
-class MyTalesPage(object):
+class MyTalesPage:
def __init__(self, source):
self.source = source
@@ -173,7 +173,7 @@ class TestVirtualHosting(unittest.TestCase):
if len(p) == 1:
env['PATH_INFO'] = p[0]
- request = BrowserRequest(StringIO(u''), env)
+ request = BrowserRequest(StringIO(''), env)
request.setPublication(DummyPublication(self.app))
setDefaultSkin(request)
return request
@@ -182,7 +182,7 @@ class TestVirtualHosting(unittest.TestCase):
return publish(self.makeRequest(path)).response
def test_request_url(self):
- self.addPage('/pt', u'request/URL')
+ self.addPage('/pt', 'request/URL')
self.verify('/pt', 'http://localhost/pt/index.html')
self.verify('/++vh++/++/pt',
'http://localhost/pt/index.html')
@@ -191,7 +191,7 @@ class TestVirtualHosting(unittest.TestCase):
self.verify('/++vh++https:localhost:443/fake/folders/++/pt',
'https://localhost/fake/folders/pt/index.html')
- self.addPage('/foo/bar/pt', u'request/URL')
+ self.addPage('/foo/bar/pt', 'request/URL')
self.verify('/foo/bar/pt', 'http://localhost/foo/bar/pt/index.html')
self.verify('/foo/bar/++vh++/++/pt',
'http://localhost/pt/index.html')
@@ -201,7 +201,7 @@ class TestVirtualHosting(unittest.TestCase):
'https://localhost/fake/folders/bar/pt/index.html')
def test_request_redirect(self):
- self.addPage('/foo/index.html', u'Spam')
+ self.addPage('/foo/index.html', 'Spam')
self.verifyRedirect('/foo', 'http://localhost/foo/index.html')
self.verifyRedirect('/++vh++https:localhost:443/++/foo',
'https://localhost/foo/index.html')
@@ -209,7 +209,7 @@ class TestVirtualHosting(unittest.TestCase):
'https://localhost/bar/index.html')
def test_absolute_url(self):
- self.addPage('/pt', u'context/@@absolute_url')
+ self.addPage('/pt', 'context/@@absolute_url')
self.verify('/pt', 'http://localhost')
self.verify('/++vh++/++/pt',
'http://localhost')
@@ -219,7 +219,7 @@ class TestVirtualHosting(unittest.TestCase):
'https://localhost/fake/folders')
self.addPage('/foo/bar/pt',
- u'context/@@absolute_url')
+ 'context/@@absolute_url')
self.verify('/foo/bar/pt', 'http://localhost/foo/bar')
self.verify('/foo/bar/++vh++/++/pt',
'http://localhost')
@@ -231,7 +231,7 @@ class TestVirtualHosting(unittest.TestCase):
def test_absolute_url_absolute_traverse(self):
self.createObject('/foo/bar/obj', MyObj())
self.addPage('/foo/bar/pt',
- u'container/obj/pt/@@absolute_url')
+ 'container/obj/pt/@@absolute_url')
self.verify('/foo/bar/pt', 'http://localhost/foo/bar/pt')
self.verify('/foo/++vh++https:localhost:443/++/bar/pt',
'https://localhost/bar/pt')
@@ -241,11 +241,11 @@ class TestVirtualHosting(unittest.TestCase):
# Only register the checker once, so that multiple test runs pass.
if Resource not in _checkers:
defineChecker(Resource, NamesChecker(['__call__']))
- self.addPage(u'/foo/bar/pt',
- u'context/++resource++quux')
- self.verify(u'/foo/bar/pt', u'http://localhost/@@/quux')
- self.verify(u'/foo/++vh++https:localhost:443/fake/folders/++/bar/pt',
- u'https://localhost/fake/folders/@@/quux')
+ self.addPage('/foo/bar/pt',
+ 'context/++resource++quux')
+ self.verify('/foo/bar/pt', 'http://localhost/@@/quux')
+ self.verify('/foo/++vh++https:localhost:443/fake/folders/++/bar/pt',
+ 'https://localhost/fake/folders/@@/quux')
def createFolders(self, path):
"""addFolders('/a/b/c/d') would traverse and/or create three nested
@@ -283,7 +283,7 @@ class TestVirtualHosting(unittest.TestCase):
self.assertEqual(result.getHeader('Location'), location)
-class DummyPublication(object):
+class DummyPublication:
def __init__(self, app):
self.app = app
diff --git a/tox.ini b/tox.ini
index a20b472..60cbcc7 100644
--- a/tox.ini
+++ b/tox.ini
@@ -4,14 +4,11 @@
minversion = 3.18
envlist =
lint
- py27
- py35
- py36
py37
py38
py39
py310
- pypy
+ py311
pypy3
docs
coverage
@@ -41,6 +38,7 @@ deps =
[testenv:isort-apply]
basepython = python3
+skip_install = true
commands_pre =
deps =
isort
@@ -62,16 +60,14 @@ allowlist_externals =
mkdir
deps =
coverage
- coverage-python-version
commands =
mkdir -p {toxinidir}/parts/htmlcov
coverage run -m zope.testrunner --test-path=src {posargs:-vc}
- coverage html
- coverage report -m --fail-under=99
+ coverage html --ignore-errors
+ coverage report --ignore-errors --show-missing --fail-under=99
[coverage:run]
branch = True
-plugins = coverage_python_version
source = zope.traversing
[coverage:report]