Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Drop support for Python 3.7 #308

Merged
merged 3 commits into from
May 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 10 additions & 26 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ jobs:
matrix:
python-version:
- "pypy-3.10"
- "3.7"
- "3.8"
- "3.9"
- "3.10"
Expand All @@ -106,13 +105,8 @@ jobs:
- "3.13"
os: [ubuntu-latest, macos-latest, windows-latest]
exclude:
- os: macos-latest
python-version: "3.7"
- os: macos-latest
python-version: "pypy-3.10"
include:
- python-version: "3.7"
os: macos-12

steps:
- name: checkout
Expand Down Expand Up @@ -169,11 +163,10 @@ jobs:
pip install -U pip
pip install -U "setuptools<69" wheel twine

- name: Build zope.interface (macOS x86_64, Python 3.8+)
- name: Build zope.interface (macOS x86_64)
if: >
startsWith(runner.os, 'Mac')
&& !(startsWith(matrix.python-version, 'pypy')
|| matrix.python-version == '3.7')
&& !startsWith(matrix.python-version, 'pypy')
env:
MACOSX_DEPLOYMENT_TARGET: 10.9
_PYTHON_HOST_PLATFORM: macosx-10.9-x86_64
Expand All @@ -183,11 +176,10 @@ jobs:
# output (pip install uses a random temporary directory, making this difficult).
python setup.py build_ext -i
python setup.py bdist_wheel
- name: Build zope.interface (macOS arm64, Python 3.8+)
- name: Build zope.interface (macOS arm64)
if: >
startsWith(runner.os, 'Mac')
&& !(startsWith(matrix.python-version, 'pypy')
|| matrix.python-version == '3.7')
&& !startsWith(matrix.python-version, 'pypy')
env:
MACOSX_DEPLOYMENT_TARGET: 11.0
_PYTHON_HOST_PLATFORM: macosx-11.0-arm64
Expand All @@ -201,7 +193,6 @@ jobs:
if: >
!startsWith(runner.os, 'Mac')
|| startsWith(matrix.python-version, 'pypy')
|| matrix.python-version == '3.7'
run: |
# Next, build the wheel *in place*. This helps ccache, and also lets us cache the configure
# output (pip install uses a random temporary directory, making this difficult).
Expand Down Expand Up @@ -230,19 +221,18 @@ jobs:
startsWith(runner.os, 'Mac')
uses: actions/upload-artifact@v4
with:
name: zope.interface-${{ runner.os }}-${{ matrix.python-version }}.whl
# The x86_64 wheel is uploaded with a different name just so it can be
# manually downloaded when desired. The wheel itself *cannot* be tested
# on the GHA runner, which uses arm64 architecture.
name: zope.interface-${{ runner.os }}-${{ matrix.python-version }}-x86_64.whl
path: dist/*x86_64.whl
- name: Upload zope.interface wheel (macOS arm64)
if: >
startsWith(runner.os, 'Mac')
&& !(startsWith(matrix.python-version, 'pypy')
|| matrix.python-version == '3.7')
&& !startsWith(matrix.python-version, 'pypy')
uses: actions/upload-artifact@v4
with:
# The arm64 wheel is uploaded with a different name just so it can be
# manually downloaded when desired. The wheel itself *cannot* be tested
# on the GHA runner, which uses x86_64 architecture.
name: zope.interface-${{ runner.os }}-${{ matrix.python-version }}-arm64.whl
name: zope.interface-${{ runner.os }}-${{ matrix.python-version }}.whl
path: dist/*arm64.whl
- name: Upload zope.interface wheel (all other platforms)
if: >
Expand Down Expand Up @@ -274,7 +264,6 @@ jobs:
matrix:
python-version:
- "pypy-3.10"
- "3.7"
- "3.8"
- "3.9"
- "3.10"
Expand All @@ -283,13 +272,8 @@ jobs:
- "3.13"
os: [ubuntu-latest, macos-latest, windows-latest]
exclude:
- os: macos-latest
python-version: "3.7"
- os: macos-latest
python-version: "pypy-3.10"
include:
- python-version: "3.7"
os: macos-12

steps:
- name: checkout
Expand Down
2 changes: 0 additions & 2 deletions .manylinux-install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ yum -y install libffi-devel
tox_env_map() {
case $1 in
*"cp313"*) echo 'py313';;
*"cp37"*) echo 'py37';;
*"cp38"*) echo 'py38';;
*"cp39"*) echo 'py39';;
*"cp310"*) echo 'py310';;
Expand All @@ -45,7 +44,6 @@ for PYBIN in /opt/python/*/bin; do
[[ "${PYBIN}" == *"cp313/"* ]] || \
[[ "${PYBIN}" == *"cp311/"* ]] || \
[[ "${PYBIN}" == *"cp312/"* ]] || \
[[ "${PYBIN}" == *"cp37/"* ]] || \
[[ "${PYBIN}" == *"cp38/"* ]] || \
[[ "${PYBIN}" == *"cp39/"* ]] || \
[[ "${PYBIN}" == *"cp310/"* ]] ; then
Expand Down
2 changes: 1 addition & 1 deletion .meta.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# https://github.com/zopefoundation/meta/tree/master/config/c-code
[meta]
template = "c-code"
commit-id = "1c0f31f5"
commit-id = "8d837c89"

[python]
with-appveyor = true
Expand Down
2 changes: 2 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
6.5 (unreleased)
================

- Drop support for Python 3.7.


6.4.post2 (2024-05-24)
======================
Expand Down
26 changes: 13 additions & 13 deletions docs/verify.rst
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ defined.
.. doctest::

>>> verify_foo()
The object <Foo...> has failed to implement interface ...IFoo:
The object <...Foo...> has failed to implement interface ...IFoo:
Does not declaratively implement the interface
The base.IBase.x attribute was not provided
The module.IFoo.y attribute was not provided
Expand All @@ -61,7 +61,7 @@ declaring the correct interface.

>>> Foo.x = Foo.y = 42
>>> verify_foo()
The object <Foo...> has failed to implement interface ...IFoo: Does not declaratively implement the interface.
The object <...Foo...> has failed to implement interface ...IFoo: Does not declaratively implement the interface.

If we want to only check the structure of the object, without examining
its declarations, we can use the ``tentative`` argument.
Expand Down Expand Up @@ -125,13 +125,13 @@ exception.
... class Foo(object):
... x = 1
>>> verify_foo()
The object <Foo...> has failed to implement interface ...IFoo: The module.IFoo.y attribute was not provided.
The object <...Foo...> has failed to implement interface ...IFoo: The module.IFoo.y attribute was not provided.
>>> @implementer(IFoo)
... class Foo(object):
... def __init__(self):
... self.y = 2
>>> verify_foo()
The object <Foo...> has failed to implement interface ...IFoo: The base.IBase.x attribute was not provided.
The object <...Foo...> has failed to implement interface ...IFoo: The base.IBase.x attribute was not provided.

If both attributes are missing, an exception is raised reporting
both errors.
Expand All @@ -142,7 +142,7 @@ both errors.
... class Foo(object):
... pass
>>> verify_foo()
The object <Foo ...> has failed to implement interface ...IFoo:
The object <...Foo ...> has failed to implement interface ...IFoo:
The base.IBase.x attribute was not provided
The module.IFoo.y attribute was not provided

Expand All @@ -161,7 +161,7 @@ when trying to get its value, the attribute is considered missing:
... def x(self):
... raise AttributeError
>>> verify_foo()
The object <Foo...> has failed to implement interface ...IFoo: The module.IFoo.x attribute was not provided.
The object <...Foo...> has failed to implement interface ...IFoo: The module.IFoo.x attribute was not provided.


Any other exception raised by a property will propagate to the caller of
Expand Down Expand Up @@ -209,7 +209,7 @@ that takes one argument. If we don't provide it, we get an error.
... class Foo(object):
... pass
>>> verify_foo()
The object <Foo...> has failed to implement interface ...IFoo: The module.IFoo.simple(arg1) attribute was not provided.
The object <...Foo...> has failed to implement interface ...IFoo: The module.IFoo.simple(arg1) attribute was not provided.

Once they exist, they are checked to be callable, and for compatible signatures.

Expand All @@ -219,7 +219,7 @@ Not being callable is an error.

>>> Foo.simple = 42
>>> verify_foo()
The object <Foo...> has failed to implement interface ...IFoo: The contract of module.IFoo.simple(arg1) is violated because '42' is not a method.
The object <...Foo...> has failed to implement interface ...IFoo: The contract of module.IFoo.simple(arg1) is violated because '42' is not a method.

Taking too few arguments is an error. (Recall that the ``self``
argument is implicit.)
Expand All @@ -228,15 +228,15 @@ argument is implicit.)

>>> Foo.simple = lambda self: "I take no arguments"
>>> verify_foo()
The object <Foo...> has failed to implement interface ...IFoo: The contract of module.IFoo.simple(arg1) is violated because '<lambda>()' doesn't allow enough arguments.
The object <...Foo...> has failed to implement interface ...IFoo: The contract of module.IFoo.simple(arg1) is violated because '<lambda>()' doesn't allow enough arguments.

Requiring too many arguments is an error.

.. doctest::

>>> Foo.simple = lambda self, a, b: "I require two arguments"
>>> verify_foo()
The object <Foo...> has failed to implement interface ...IFoo: The contract of module.IFoo.simple(arg1) is violated because '<lambda>(a, b)' requires too many arguments.
The object <...Foo...> has failed to implement interface ...IFoo: The contract of module.IFoo.simple(arg1) is violated because '<lambda>(a, b)' requires too many arguments.

Variable arguments can be used to implement the required number, as
can arguments with defaults.
Expand All @@ -263,7 +263,7 @@ variable keyword arguments, the implementation must also accept them.
... class Foo(object):
... def needs_kwargs(self, a=1, b=2): pass
>>> verify_foo()
The object <Foo...> has failed to implement interface ...IFoo: The contract of module.IFoo.needs_kwargs(**kwargs) is violated because 'Foo.needs_kwargs(a=1, b=2)' doesn't support keyword arguments.
The object <...Foo...> has failed to implement interface ...IFoo: The contract of module.IFoo.needs_kwargs(**kwargs) is violated because 'Foo.needs_kwargs(a=1, b=2)' doesn't support keyword arguments.

>>> oname, __name__ = __name__, 'module'
>>> class IFoo(Interface):
Expand All @@ -273,7 +273,7 @@ variable keyword arguments, the implementation must also accept them.
... class Foo(object):
... def needs_varargs(self, **kwargs): pass
>>> verify_foo()
The object <Foo...> has failed to implement interface ...IFoo: The contract of module.IFoo.needs_varargs(*args) is violated because 'Foo.needs_varargs(**kwargs)' doesn't support variable arguments.
The object <...Foo...> has failed to implement interface ...IFoo: The contract of module.IFoo.needs_varargs(*args) is violated because 'Foo.needs_varargs(**kwargs)' doesn't support variable arguments.

Of course, missing attributes are also found and reported, and the
source interface of the missing attribute is included. Similarly, when
Expand All @@ -294,7 +294,7 @@ the failing method is from a parent class, that is also reported.
... class Foo(Base):
... pass
>>> verify_foo()
The object <Foo...> has failed to implement interface ...IFoo:
The object <...Foo...> has failed to implement interface ...IFoo:
The contract of base.IBase.method(arg1) is violated because 'Base.method()' doesn't allow enough arguments
The module.IFoo.x attribute was not provided

Expand Down
3 changes: 1 addition & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,6 @@ def read(*rnames):
"Operating System :: OS Independent",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
Expand All @@ -135,7 +134,7 @@ def read(*rnames):
zip_safe=False,
tests_require=tests_require,
install_requires=['setuptools'],
python_requires='>=3.7',
python_requires='>=3.8',
extras_require={
'docs': ['Sphinx',
'repoze.sphinx.autointerface',
Expand Down
4 changes: 2 additions & 2 deletions src/zope/interface/common/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ def __optional_methods_to_docs(attrs):
return ''

docs = "\n\nThe following methods are optional:\n - " + "\n-".join(
"{}\n{}".format(k, v.__doc__) for k, v in optionals.items()
f"{k}\n{v.__doc__}" for k, v in optionals.items()
)
return docs

Expand All @@ -181,7 +181,7 @@ def ref(c):
return "`%s`" % name
if mod == '_io':
mod = 'io'
return "`{}.{}`".format(mod, name)
return f"`{mod}.{name}`"

implementations_doc = "\n - ".join(
ref(c)
Expand Down
6 changes: 3 additions & 3 deletions src/zope/interface/declarations.py
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ def __repr__(self):
declared_names = self._argument_names_for_repr(self.declared)
if declared_names:
declared_names = ', ' + declared_names
return 'classImplements({}{})'.format(name, declared_names)
return f'classImplements({name}{declared_names})'

def __reduce__(self):
return implementedBy, (self.inherit, )
Expand Down Expand Up @@ -772,7 +772,7 @@ def __repr__(self):
if len(mod_names) == 1:
mod_names = "sys.modules[%r]" % mod_names[0]
ordered_names = (
'{}, '.format(mod_names)
f'{mod_names}, '
) + ordered_names
return "{}({})".format(
function_name,
Expand Down Expand Up @@ -937,7 +937,7 @@ def __repr__(self):
# Thus, as our repr, we go with the ``directlyProvides()`` syntax.
interfaces = (self._cls, ) + self.__args[2:]
ordered_names = self._argument_names_for_repr(interfaces)
return "directlyProvides({})".format(ordered_names)
return f"directlyProvides({ordered_names})"

def __reduce__(self):
return self.__class__, self.__args
Expand Down
4 changes: 2 additions & 2 deletions src/zope/interface/document.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def asStructuredText(iface, munge=0, rst=False):

if rst:
def inline_literal(s):
return "``{}``".format(s)
return f"``{s}``"
else:
def inline_literal(s):
return s
Expand Down Expand Up @@ -76,7 +76,7 @@ def inline_literal(s):
level += 1
for name, desc in namesAndDescriptions:
if hasattr(desc, 'getSignatureString'): # ugh...
_call = "{}{}".format(desc.getName(), desc.getSignatureString())
_call = f"{desc.getName()}{desc.getSignatureString()}"
item = "{} -- {}".format(
inline_literal(_call),
desc.getDoc() or 'no documentation'
Expand Down
2 changes: 1 addition & 1 deletion src/zope/interface/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ def _str_subject(self):
target = self.target
if target is self._NOT_GIVEN:
return "An object"
return "The object {!r}".format(target)
return f"The object {target!r}"

@property
def _str_description(self):
Expand Down
6 changes: 3 additions & 3 deletions src/zope/interface/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -793,7 +793,7 @@ def __init__(
Specification.__init__(self, bases)
self.__attrs = self.__compute_attrs(attrs)

self.__identifier__ = "{}.{}".format(__module__, name)
self.__identifier__ = f"{__module__}.{name}"

def __compute_attrs(self, attrs):
# Make sure that all recorded attributes (and methods) are of type
Expand Down Expand Up @@ -938,15 +938,15 @@ def __repr__(self):
return self._v_repr
except AttributeError:
name = str(self)
r = "<{} {}>".format(self.__class__.__name__, name)
r = f"<{self.__class__.__name__} {name}>"
self._v_repr = r # pylint:disable=attribute-defined-outside-init
return r

def __str__(self):
name = self.__name__
m = self.__ibmodule__
if m:
name = '{}.{}'.format(m, name)
name = f'{m}.{name}'
return name

def _call_conform(self, conform):
Expand Down
2 changes: 1 addition & 1 deletion src/zope/interface/interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -1157,7 +1157,7 @@ class RegistrationEvent(ObjectEvent):
"""There has been a change in a registration
"""
def __repr__(self):
return "{} event:\n{!r}".format(self.__class__.__name__, self.object)
return f"{self.__class__.__name__} event:\n{self.object!r}"


class IRegistered(IRegistrationEvent):
Expand Down
2 changes: 1 addition & 1 deletion src/zope/interface/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ def __init__(self, name='', bases=()):
self._v_utility_registrations_cache = None

def __repr__(self):
return "<{} {}>".format(self.__class__.__name__, self.__name__)
return f"<{self.__class__.__name__} {self.__name__}>"

def __reduce__(self):
# Mimic what a persistent.Persistent object does and elide
Expand Down
2 changes: 1 addition & 1 deletion src/zope/interface/ro.py
Original file line number Diff line number Diff line change
Expand Up @@ -625,7 +625,7 @@ def __str__(self):
max_left = max(len(x) for x in left_lines)
max_right = max(len(x) for x in right_lines)

left_title = 'Legacy RO (len={})'.format(len(self.legacy_ro))
left_title = f'Legacy RO (len={len(self.legacy_ro)})'

right_title = 'C3 RO (len={}; inconsistent={})'.format(
len(self.c3_ro),
Expand Down
Loading
Loading