diff --git a/_distutils_hack/__init__.py b/_distutils_hack/__init__.py index b951c2defd..c9d1e24790 100644 --- a/_distutils_hack/__init__.py +++ b/_distutils_hack/__init__.py @@ -3,16 +3,9 @@ import os -is_pypy = '__pypy__' in sys.builtin_module_names - - def warn_distutils_present(): if 'distutils' not in sys.modules: return - if is_pypy and sys.version_info < (3, 7): - # PyPy for 3.6 unconditionally imports distutils, so bypass the warning - # https://foss.heptapod.net/pypy/pypy/-/blob/be829135bc0d758997b3566062999ee8b23872b4/lib-python/3/site.py#L250 - return import warnings warnings.warn( diff --git a/conftest.py b/conftest.py index 8dcf7e6805..90b653146f 100644 --- a/conftest.py +++ b/conftest.py @@ -41,11 +41,6 @@ def pytest_configure(config): ] -if sys.version_info < (3, 6): - collect_ignore.append('docs/conf.py') # uses f-strings - collect_ignore.append('pavement.py') - - if sys.version_info < (3, 9) or sys.platform == 'cygwin': collect_ignore.append('tools/finalize.py') diff --git a/docs/userguide/declarative_config.rst b/docs/userguide/declarative_config.rst index 047e08c6ef..c297c4d35f 100644 --- a/docs/userguide/declarative_config.rst +++ b/docs/userguide/declarative_config.rst @@ -39,10 +39,10 @@ boilerplate code in some cases. zip_safe = False include_package_data = True packages = find: - python_requires = >=3.7 + python_requires = >=3.8 install_requires = requests - importlib-metadata; python_version<"3.8" + importlib-metadata; python_version<"3.10" [options.package_data] * = *.txt, *.rst @@ -271,11 +271,11 @@ data_files section 40.6.0 [# [options] install_requires = - importlib-metadata; python_version<"3.8" + importlib-metadata; python_version<"3.10" [options.extras_require] all = - importlib-metadata; python_version < "3.8" + importlib-metadata; python_version<"3.10" .. [#opt-3] The ``find:`` and ``find_namespace:`` directive can be further configured in a dedicated subsection ``options.packages.find``. This subsection accepts the diff --git a/docs/userguide/entry_point.rst b/docs/userguide/entry_point.rst index 4aa7f9a27c..c8022c3d4f 100644 --- a/docs/userguide/entry_point.rst +++ b/docs/userguide/entry_point.rst @@ -486,9 +486,10 @@ entry points remains the same as for console/GUI scripts, and is discussed in th .. tip:: The recommended approach for loading and importing entry points is the :mod:`importlib.metadata` module, - which is a part of the standard library since Python 3.8. For older versions of - Python, its backport :pypi:`importlib_metadata` should be used. While using the - backport, the only change that has to be made is to replace ``importlib.metadata`` + which is a part of the standard library since Python 3.8 and is non-provisional + since Python 3.10. For older versions of Python, its backport + :pypi:`importlib_metadata` should be used. While using the backport, the only + change that has to be made is to replace ``importlib.metadata`` with ``importlib_metadata``, i.e. .. code-block:: python diff --git a/docs/userguide/pyproject_config.rst b/docs/userguide/pyproject_config.rst index 2529bf1ba8..379d41b03b 100644 --- a/docs/userguide/pyproject_config.rst +++ b/docs/userguide/pyproject_config.rst @@ -47,7 +47,7 @@ The ``project`` table contains metadata fields as described by the ] description = "My package description" readme = "README.rst" - requires-python = ">=3.7" + requires-python = ">=3.8" keywords = ["one", "two"] license = {text = "BSD-3-Clause"} classifiers = [ @@ -56,7 +56,7 @@ The ``project`` table contains metadata fields as described by the ] dependencies = [ "requests", - 'importlib-metadata; python_version<"3.8"', + 'importlib-metadata; python_version<"3.10"', ] dynamic = ["version"] diff --git a/docs/userguide/quickstart.rst b/docs/userguide/quickstart.rst index b4e8bf00e1..3a8e2a3ed4 100644 --- a/docs/userguide/quickstart.rst +++ b/docs/userguide/quickstart.rst @@ -85,7 +85,7 @@ The following example demonstrates a minimum configuration version = "0.0.1" dependencies = [ "requests", - 'importlib-metadata; python_version<"3.8"', + 'importlib-metadata; python_version<"3.10"', ] See :doc:`/userguide/pyproject_config` for more information. @@ -101,7 +101,8 @@ The following example demonstrates a minimum configuration [options] install_requires = requests - importlib-metadata; python_version < "3.8" + importlib-metadata; python_version<"3.10" + See :doc:`/userguide/declarative_config` for more information. @@ -116,7 +117,7 @@ The following example demonstrates a minimum configuration version='0.0.1', install_requires=[ 'requests', - 'importlib-metadata; python_version == "3.8"', + 'importlib-metadata; python_version<"3.10"', ], ) diff --git a/newsfragments/4096.doc.rst b/newsfragments/4096.doc.rst new file mode 100644 index 0000000000..b5b5206704 --- /dev/null +++ b/newsfragments/4096.doc.rst @@ -0,0 +1 @@ +Updated documentation referencing obsolete Python 3.7 code. -- by :user:`Avasam` diff --git a/newsfragments/4096.feature.rst b/newsfragments/4096.feature.rst new file mode 100644 index 0000000000..89b3a465bb --- /dev/null +++ b/newsfragments/4096.feature.rst @@ -0,0 +1 @@ +Updated and removed obsolete Python < 3.8 code and comments. -- by :user:`Avasam` diff --git a/pkg_resources/__init__.py b/pkg_resources/__init__.py index 288280c78d..5bee50539d 100644 --- a/pkg_resources/__init__.py +++ b/pkg_resources/__init__.py @@ -18,6 +18,10 @@ """ import sys + +if sys.version_info < (3, 8): + raise RuntimeError("Python 3.8 or later is required") + import os import io import time @@ -43,16 +47,7 @@ import importlib from pkgutil import get_importer -try: - import _imp -except ImportError: - # Python 3.2 compatibility - import imp as _imp - -try: - FileExistsError -except NameError: - FileExistsError = OSError +import _imp # capture these to bypass sandboxing from os import utime @@ -91,9 +86,6 @@ __import__('pkg_resources.extern.packaging.markers') __import__('pkg_resources.extern.packaging.utils') -if sys.version_info < (3, 5): - raise RuntimeError("Python 3.5 or later is required") - # declare some globals that will be defined later to # satisfy the linters. require = None diff --git a/pkg_resources/tests/test_pkg_resources.py b/pkg_resources/tests/test_pkg_resources.py index c90dca7ff3..0883642080 100644 --- a/pkg_resources/tests/test_pkg_resources.py +++ b/pkg_resources/tests/test_pkg_resources.py @@ -4,7 +4,6 @@ import os import zipfile import datetime -import time import plistlib import subprocess import stat @@ -24,17 +23,6 @@ import pkg_resources -def timestamp(dt): - """ - Return a timestamp for a local, naive datetime instance. - """ - try: - return dt.timestamp() - except AttributeError: - # Python 3.2 and earlier - return time.mktime(dt.timetuple()) - - class EggRemover(str): def __call__(self): if self in sys.path: @@ -125,7 +113,7 @@ def test_resource_filename_rewrites_on_change(self): f = open(filename, 'w') f.write('hello, world?') f.close() - ts = timestamp(self.ref_time) + ts = self.ref_time.timestamp() os.utime(filename, (ts, ts)) filename = zp.get_resource_filename(manager, 'data.dat') with open(filename) as f: @@ -243,9 +231,6 @@ def make_distribution_no_version(tmpdir, basename): # will detect it and yield it. dist_dir.join('temp.txt').ensure() - if sys.version_info < (3, 6): - dist_dir = str(dist_dir) - dists = list(pkg_resources.distributions_from_metadata(dist_dir)) assert len(dists) == 1 (dist,) = dists diff --git a/pkg_resources/tests/test_resources.py b/pkg_resources/tests/test_resources.py index c90584a882..5b2308aea7 100644 --- a/pkg_resources/tests/test_resources.py +++ b/pkg_resources/tests/test_resources.py @@ -21,7 +21,7 @@ ) -# from Python 3.6 docs. +# from Python 3.6 docs. Available from itertools on Python 3.10 def pairwise(iterable): "s -> (s0,s1), (s1,s2), (s2, s3), ..." a, b = itertools.tee(iterable) diff --git a/setuptools/command/bdist_egg.py b/setuptools/command/bdist_egg.py index a4b683f66e..8aaf155833 100644 --- a/setuptools/command/bdist_egg.py +++ b/setuptools/command/bdist_egg.py @@ -369,10 +369,7 @@ def scan_module(egg_dir, base, name, stubs): return True # Extension module pkg = base[len(egg_dir) + 1 :].replace(os.sep, '.') module = pkg + (pkg and '.' or '') + os.path.splitext(name)[0] - if sys.version_info < (3, 7): - skip = 12 # skip magic & date & file size - else: - skip = 16 # skip magic & reserved? & date & file size + skip = 16 # skip magic & reserved? & date & file size f = open(filename, 'rb') f.read(skip) code = marshal.load(f) diff --git a/setuptools/command/build.py b/setuptools/command/build.py index 0f1d688e17..afda7e3be9 100644 --- a/setuptools/command/build.py +++ b/setuptools/command/build.py @@ -1,17 +1,8 @@ -import sys -from typing import TYPE_CHECKING, List, Dict +from typing import Dict, List, Protocol from distutils.command.build import build as _build from ..warnings import SetuptoolsDeprecationWarning -if sys.version_info >= (3, 8): - from typing import Protocol -elif TYPE_CHECKING: - from typing_extensions import Protocol -else: - from abc import ABC as Protocol - - _ORIGINAL_SUBCOMMANDS = {"build_py", "build_clib", "build_ext", "build_scripts"} diff --git a/setuptools/command/dist_info.py b/setuptools/command/dist_info.py index 5ef322168c..f5061afaaf 100644 --- a/setuptools/command/dist_info.py +++ b/setuptools/command/dist_info.py @@ -5,7 +5,6 @@ import os import shutil -import sys from contextlib import contextmanager from distutils import log from distutils.core import Command @@ -77,7 +76,7 @@ def _maybe_bkp_dir(self, dir_path: str, requires_bkp: bool): if requires_bkp: bkp_name = f"{dir_path}.__bkp__" _rm(bkp_name, ignore_errors=True) - _copy(dir_path, bkp_name, dirs_exist_ok=True, symlinks=True) + shutil.copytree(dir_path, bkp_name, dirs_exist_ok=True, symlinks=True) try: yield finally: @@ -103,9 +102,3 @@ def run(self): def _rm(dir_name, **opts): if os.path.isdir(dir_name): shutil.rmtree(dir_name, **opts) - - -def _copy(src, dst, **opts): - if sys.version_info < (3, 8): - opts.pop("dirs_exist_ok", None) - shutil.copytree(src, dst, **opts) diff --git a/setuptools/command/easy_install.py b/setuptools/command/easy_install.py index 4de28bb98f..f73d857f08 100644 --- a/setuptools/command/easy_install.py +++ b/setuptools/command/easy_install.py @@ -250,12 +250,13 @@ def finalize_options(self): # noqa: C901 # is too complex (25) # FIXME 'dist_version': self.distribution.get_version(), 'dist_fullname': self.distribution.get_fullname(), 'py_version': py_version, - 'py_version_short': (f'{sys.version_info.major}.{sys.version_info.minor}'), + 'py_version_short': f'{sys.version_info.major}.{sys.version_info.minor}', 'py_version_nodot': f'{sys.version_info.major}{sys.version_info.minor}', 'sys_prefix': self.config_vars['prefix'], 'sys_exec_prefix': self.config_vars['exec_prefix'], - # Only python 3.2+ has abiflags + # Only POSIX systems have abiflags 'abiflags': getattr(sys, 'abiflags', ''), + # Only python 3.9+ has platlibdir 'platlibdir': getattr(sys, 'platlibdir', 'lib'), }) with contextlib.suppress(AttributeError): diff --git a/setuptools/command/editable_wheel.py b/setuptools/command/editable_wheel.py index c1f9899dfe..8a4ae7928f 100644 --- a/setuptools/command/editable_wheel.py +++ b/setuptools/command/editable_wheel.py @@ -30,6 +30,7 @@ List, Mapping, Optional, + Protocol, Tuple, TypeVar, Union, @@ -54,13 +55,6 @@ if TYPE_CHECKING: from wheel.wheelfile import WheelFile # noqa -if sys.version_info >= (3, 8): - from typing import Protocol -elif TYPE_CHECKING: - from typing_extensions import Protocol -else: - from abc import ABC as Protocol - _Path = Union[str, Path] _P = TypeVar("_P", bound=_Path) _logger = logging.getLogger(__name__) diff --git a/setuptools/command/sdist.py b/setuptools/command/sdist.py index 86ec048280..d455f44c5e 100644 --- a/setuptools/command/sdist.py +++ b/setuptools/command/sdist.py @@ -1,7 +1,6 @@ from distutils import log import distutils.command.sdist as orig import os -import sys import contextlib from itertools import chain @@ -71,14 +70,6 @@ def run(self): def initialize_options(self): orig.sdist.initialize_options(self) - self._default_to_gztar() - - def _default_to_gztar(self): - # only needed on Python prior to 3.6. - if sys.version_info >= (3, 6, 0, 'beta', 1): - return - self.formats = ['gztar'] - def make_distribution(self): """ Workaround for #516 diff --git a/setuptools/monkey.py b/setuptools/monkey.py index 3d5edb6bd2..da0993506c 100644 --- a/setuptools/monkey.py +++ b/setuptools/monkey.py @@ -66,21 +66,6 @@ def patch_all(): # we can't patch distutils.cmd, alas distutils.core.Command = setuptools.Command - has_issue_12885 = sys.version_info <= (3, 5, 3) - - if has_issue_12885: - # fix findall bug in distutils (https://bugs.python.org/issue12885) - distutils.filelist.findall = setuptools.findall - - needs_warehouse = (3, 4) < sys.version_info < (3, 4, 6) or ( - 3, - 5, - ) < sys.version_info <= (3, 5, 3) - - if needs_warehouse: - warehouse = 'https://upload.pypi.org/legacy/' - distutils.config.PyPIRCCommand.DEFAULT_REPOSITORY = warehouse - _patch_distribution_metadata() # Install Distribution throughout the distutils @@ -138,8 +123,7 @@ def patch_for_msvc_specialized_compiler(): Patch functions in distutils to use standalone Microsoft Visual C++ compilers. """ - # import late to avoid circular imports on Python < 3.5 - msvc = import_module('setuptools.msvc') + from . import msvc if platform.system() != 'Windows': # Compilers only available on Microsoft Windows diff --git a/setuptools/namespaces.py b/setuptools/namespaces.py index 3332f864ae..e8f2941d45 100644 --- a/setuptools/namespaces.py +++ b/setuptools/namespaces.py @@ -42,12 +42,11 @@ def _get_target(self): _nspkg_tmpl = ( "import sys, types, os", - "has_mfs = sys.version_info > (3, 5)", "p = os.path.join(%(root)s, *%(pth)r)", - "importlib = has_mfs and __import__('importlib.util')", - "has_mfs and __import__('importlib.machinery')", + "importlib = __import__('importlib.util')", + "__import__('importlib.machinery')", ( - "m = has_mfs and " + "m = " "sys.modules.setdefault(%(pkg)r, " "importlib.util.module_from_spec(" "importlib.machinery.PathFinder.find_spec(%(pkg)r, " diff --git a/setuptools/tests/test_distutils_adoption.py b/setuptools/tests/test_distutils_adoption.py index b371a5d353..e180547f0d 100644 --- a/setuptools/tests/test_distutils_adoption.py +++ b/setuptools/tests/test_distutils_adoption.py @@ -1,6 +1,5 @@ import os import sys -import functools import platform import textwrap @@ -10,17 +9,6 @@ IS_PYPY = '__pypy__' in sys.builtin_module_names -def popen_text(call): - """ - Augment the Popen call with the parameters to ensure unicode text. - """ - return ( - functools.partial(call, universal_newlines=True) - if sys.version_info < (3, 7) - else functools.partial(call, text=True) - ) - - def win_sr(env): """ On Windows, SYSTEMROOT must be present to avoid @@ -38,7 +26,7 @@ def win_sr(env): def find_distutils(venv, imports='distutils', env=None, **kwargs): py_cmd = 'import {imports}; print(distutils.__file__)'.format(**locals()) cmd = ['python', '-c', py_cmd] - return popen_text(venv.run)(cmd, env=win_sr(env), **kwargs) + return venv.run(cmd, env=win_sr(env), text=True, **kwargs) def count_meta_path(venv, env=None): @@ -50,7 +38,7 @@ def count_meta_path(venv, env=None): """ ) cmd = ['python', '-c', py_cmd] - return int(popen_text(venv.run)(cmd, env=win_sr(env))) + return int(venv.run(cmd, env=win_sr(env), text=True)) skip_without_stdlib_distutils = pytest.mark.skipif( @@ -96,7 +84,7 @@ def test_pip_import(venv): Regression test for #3002. """ cmd = ['python', '-c', 'import pip'] - popen_text(venv.run)(cmd) + venv.run(cmd, text=True) def test_distutils_has_origin(): @@ -144,7 +132,7 @@ def test_modules_are_not_duplicated_on_import( env = dict(SETUPTOOLS_USE_DISTUTILS=distutils_version) script = ENSURE_IMPORTS_ARE_NOT_DUPLICATED.format(imported_module=imported_module) cmd = ['python', '-c', script] - output = popen_text(venv.run)(cmd, env=win_sr(env)).strip() + output = venv.run(cmd, env=win_sr(env), text=True).strip() assert output == "success" @@ -168,5 +156,5 @@ def test_modules_are_not_duplicated_on_import( def test_log_module_is_not_duplicated_on_import(distutils_version, tmpdir_cwd, venv): env = dict(SETUPTOOLS_USE_DISTUTILS=distutils_version) cmd = ['python', '-c', ENSURE_LOG_IMPORT_IS_NOT_DUPLICATED] - output = popen_text(venv.run)(cmd, env=win_sr(env)).strip() + output = venv.run(cmd, env=win_sr(env), text=True).strip() assert output == "success" diff --git a/setuptools/tests/test_editable_install.py b/setuptools/tests/test_editable_install.py index 43beb2954b..987c2fd67c 100644 --- a/setuptools/tests/test_editable_install.py +++ b/setuptools/tests/test_editable_install.py @@ -61,7 +61,6 @@ def editable_opts(request): "Intended Audience :: Developers" ] urls = {Homepage = "https://github.com"} - dependencies = ['importlib-metadata; python_version<"3.8"'] [tool.setuptools] package-dir = {"" = "src"} @@ -90,11 +89,7 @@ def editable_opts(request): "__init__.py": dedent( """\ import sys - - if sys.version_info[:2] >= (3, 8): - from importlib.metadata import PackageNotFoundError, version - else: - from importlib_metadata import PackageNotFoundError, version + from importlib.metadata import PackageNotFoundError, version try: __version__ = version(__name__) @@ -439,8 +434,6 @@ def test_editable_with_prefix(tmp_path, sample_project, editable_opts): # now run 'sample' with the prefix on the PYTHONPATH bin = 'Scripts' if platform.system() == 'Windows' else 'bin' exe = prefix / bin / 'sample' - if sys.version_info < (3, 8) and platform.system() == 'Windows': - exe = str(exe) subprocess.check_call([exe], env=env) diff --git a/setuptools/tests/test_find_packages.py b/setuptools/tests/test_find_packages.py index 7af5bb76cb..cb1900df3d 100644 --- a/setuptools/tests/test_find_packages.py +++ b/setuptools/tests/test_find_packages.py @@ -1,10 +1,8 @@ """Tests for automatic package discovery""" import os -import sys import shutil import tempfile -import platform import pytest @@ -28,14 +26,6 @@ def can_symlink(): return can -def has_symlink(): - bad_symlink = ( - # Windows symlink directory detection is broken on Python 3.2 - platform.system() == 'Windows' and sys.version_info[:2] == (3, 2) - ) - return can_symlink() and not bad_symlink - - class TestFindPackages: def setup_method(self, method): self.dist_dir = tempfile.mkdtemp() @@ -134,7 +124,7 @@ def test_dir_with_packages_in_subdir_is_excluded(self): packages = find_packages(self.dist_dir) assert 'build.pkg' not in packages - @pytest.mark.skipif(not has_symlink(), reason='Symlink support required') + @pytest.mark.skipif(not can_symlink(), reason='Symlink support required') def test_symlinked_packages_are_included(self): """ A symbolically-linked directory should be treated like any other diff --git a/setuptools/tests/test_find_py_modules.py b/setuptools/tests/test_find_py_modules.py index 9d4b0edb61..c110f8f561 100644 --- a/setuptools/tests/test_find_py_modules.py +++ b/setuptools/tests/test_find_py_modules.py @@ -6,7 +6,7 @@ from setuptools.discovery import FlatLayoutModuleFinder, ModuleFinder -from .test_find_packages import ensure_files, has_symlink +from .test_find_packages import can_symlink, ensure_files class TestModuleFinder: @@ -39,7 +39,7 @@ def test_finder(self, tmp_path, example): ensure_files(tmp_path, files) assert self.find(tmp_path, **kwargs) == set(expected_modules) - @pytest.mark.skipif(not has_symlink(), reason='Symlink support required') + @pytest.mark.skipif(not can_symlink(), reason='Symlink support required') def test_symlinked_packages_are_included(self, tmp_path): src = "_myfiles/file.py" ensure_files(tmp_path, [src]) diff --git a/setuptools/tests/test_namespaces.py b/setuptools/tests/test_namespaces.py index cc54cc9f73..76b5af296a 100644 --- a/setuptools/tests/test_namespaces.py +++ b/setuptools/tests/test_namespaces.py @@ -1,17 +1,11 @@ import sys import subprocess -import pytest - from . import namespaces from setuptools.command import test class TestNamespaces: - @pytest.mark.skipif( - sys.version_info < (3, 5), - reason="Requires importlib.util.module_from_spec", - ) def test_mixed_site_and_non_site(self, tmpdir): """ Installing two packages sharing the same namespace, one installed diff --git a/setuptools/tests/test_packageindex.py b/setuptools/tests/test_packageindex.py index 0ec2f85a4c..f27a5c63e9 100644 --- a/setuptools/tests/test_packageindex.py +++ b/setuptools/tests/test_packageindex.py @@ -84,16 +84,6 @@ def test_bad_url_double_scheme(self): return raise RuntimeError("Did not raise") - def test_bad_url_screwy_href(self): - index = setuptools.package_index.PackageIndex(hosts=('www.example.com',)) - - # issue #160 - if sys.version_info[0] == 2 and sys.version_info[1] == 7: - # this should not fail - url = 'http://example.com' - page = '' - index.process_index(url, page) - def test_url_ok(self): index = setuptools.package_index.PackageIndex(hosts=('www.example.com',)) url = 'file:///tmp/test_package_index'