diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1a56259db..7ea14b372 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,10 +23,9 @@ jobs: - macOS python-version: - "3.10" - - 3.9 - - 3.6 - - 3.7 - - 3.8 + - "3.9" + - "3.8" + - "3.7" pip-version: - "latest" - "previous" diff --git a/.github/workflows/cron.yml b/.github/workflows/cron.yml index eecb557db..178c3c67e 100644 --- a/.github/workflows/cron.yml +++ b/.github/workflows/cron.yml @@ -17,10 +17,10 @@ jobs: - Windows - MacOS python-version: - - 3.9 - - 3.6 - - 3.7 - - 3.8 + - "3.10" + - "3.9" + - "3.8" + - "3.7" pip-version: - main env: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2be80487b..baeb5767a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -12,7 +12,7 @@ repos: rev: v2.29.0 hooks: - id: pyupgrade - args: [--py36-plus] + args: [--py37-plus] - repo: https://github.com/PyCQA/flake8 rev: 4.0.1 hooks: diff --git a/README.rst b/README.rst index 3b51277b4..8c4dd7b80 100644 --- a/README.rst +++ b/README.rst @@ -454,7 +454,7 @@ then yes, you should commit both ``requirements.in`` and ``requirements.txt`` to Note that if you are deploying on multiple Python environments (read the section below), then you must commit a seperate output file for each Python environment. We suggest to use the ``{env}-requirements.txt`` format -(ex: ``win32-py3.7-requirements.txt``, ``macos-py3.6-requirements.txt``, etc.). +(ex: ``win32-py3.7-requirements.txt``, ``macos-py3.10-requirements.txt``, etc.). Cross-environment usage of ``requirements.in``/``requirements.txt`` and ``pip-compile`` @@ -462,7 +462,7 @@ Cross-environment usage of ``requirements.in``/``requirements.txt`` and ``pip-co The dependencies of a package can change depending on the Python environment in which it is installed. Here, we define a Python environment as the combination of Operating -System, Python version (3.6, 3.7, etc.), and Python implementation (CPython, PyPy, +System, Python version (3.7, 3.8, etc.), and Python implementation (CPython, PyPy, etc.). For an exact definition, refer to the possible combinations of `PEP 508 environment markers`_. @@ -527,5 +527,7 @@ versions as the required ``pip`` versions. +---------------+----------------+----------------+ | 6.0.0 - 6.3.1 | 20.3 - 21.2.* | 3.6 - 3.9 | +---------------+----------------+----------------+ -| 6.4.0+ | 21.2+ | 3.6 - 3.10 | +| 6.4.0 | 21.2 - 21.3.* | 3.6 - 3.10 | ++---------------+----------------+----------------+ +| 6.5.0+ | 21.2+ | 3.7 - 3.10 | +---------------+----------------+----------------+ diff --git a/piptools/_compat/contextlib.py b/piptools/_compat/contextlib.py deleted file mode 100644 index 8f0c5c863..000000000 --- a/piptools/_compat/contextlib.py +++ /dev/null @@ -1,31 +0,0 @@ -# Ported from python 3.7 contextlib.py -from types import TracebackType -from typing import Optional, Type, TypeVar - -_T = TypeVar("_T") - - -class nullcontext: - """Context manager that does no additional processing. - Used as a stand-in for a normal context manager, when a particular - block of code is only sometimes used with a normal context manager: - cm = optional_cm if condition else nullcontext() - with cm: - # Perform operation, using optional_cm if condition is True - - TODO: replace with `contextlib.nullcontext()` after Python 3.6 being dropped - """ - - def __init__(self, enter_result: _T) -> None: - self.enter_result = enter_result - - def __enter__(self) -> _T: - return self.enter_result - - def __exit__( - self, - exc_type: Optional[Type[BaseException]], - exc_val: Optional[BaseException], - exc_tb: Optional[TracebackType], - ) -> Optional[bool]: - pass diff --git a/piptools/repositories/pypi.py b/piptools/repositories/pypi.py index 1c59201df..ffaad4187 100644 --- a/piptools/repositories/pypi.py +++ b/piptools/repositories/pypi.py @@ -1,3 +1,4 @@ +import contextlib import hashlib import itertools import logging @@ -39,7 +40,7 @@ from pip._vendor.packaging.version import _BaseVersion from pip._vendor.requests import RequestException, Session -from .._compat import contextlib +from .._compat import PIP_VERSION from ..exceptions import NoCandidateFound from ..logging import log from ..utils import ( @@ -103,7 +104,8 @@ def __init__(self, pip_args: List[str], cache_dir: str): self._cache_dir = normalize_path(str(cache_dir)) self._download_dir = os.path.join(self._cache_dir, "pkgs") - self._setup_logging() + if PIP_VERSION[0] < 22: + self._setup_logging() def clear_caches(self) -> None: rmtree(self._download_dir, ignore_errors=True) @@ -439,7 +441,8 @@ def _wheel_support_index_min(self: Wheel, tags: List[Tag]) -> int: def _setup_logging(self) -> None: """ Setup pip's logger. Ensure pip is verbose same as pip-tools and sync - pip's log stream with LogContext.stream. + pip's log stream with LogContext.stream. This is only necessary for + pip<22.0. """ # Default pip's logger is noisy, so decrease it's verbosity setup_logging( diff --git a/piptools/utils.py b/piptools/utils.py index 3134a5091..dc254a80e 100644 --- a/piptools/utils.py +++ b/piptools/utils.py @@ -1,4 +1,5 @@ import collections +import copy import itertools import json import os @@ -26,6 +27,7 @@ from pip._internal.vcs import is_url from pip._vendor.packaging.markers import Marker from pip._vendor.packaging.specifiers import SpecifierSet +from pip._vendor.packaging.utils import canonicalize_name from pip._vendor.packaging.version import Version from pip._vendor.pkg_resources import Distribution, Requirement, get_distribution @@ -121,7 +123,11 @@ def format_requirement( elif is_url_requirement(ireq): line = _build_direct_reference_best_efforts(ireq) else: - line = str(ireq.req).lower() + # Canonicalize the requirement name + # https://packaging.pypa.io/en/latest/utils.html#packaging.utils.canonicalize_name + req = copy.copy(ireq.req) + req.name = canonicalize_name(req.name) + line = str(req) if marker: line = f"{line} ; {marker}" diff --git a/setup.cfg b/setup.cfg index 54d0ed9ef..9e9215efe 100644 --- a/setup.cfg +++ b/setup.cfg @@ -15,7 +15,6 @@ classifiers = Programming Language :: Python Programming Language :: Python :: 3 Programming Language :: Python :: 3 :: Only - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 @@ -25,7 +24,7 @@ classifiers = Topic :: System :: Systems Administration [options] -python_requires = >=3.6 +python_requires = >=3.7 setup_requires = setuptools_scm packages = find: zip_safe = false diff --git a/tests/test_cli_compile.py b/tests/test_cli_compile.py index 585165908..63544bb13 100644 --- a/tests/test_cli_compile.py +++ b/tests/test_cli_compile.py @@ -610,7 +610,7 @@ def test_url_package(runner, line, dependency, generate_hashes): ), pytest.param( path_to_url(os.path.join(PACKAGES_PATH, "small_fake_with_subdir")) - + "#subdirectory=subdir&egg=small_fake_a", + + "#subdirectory=subdir&egg=small-fake-a", "small-fake-a @ " + path_to_url(os.path.join(PACKAGES_PATH, "small_fake_with_subdir")) + "#subdirectory=subdir", diff --git a/tests/test_writer.py b/tests/test_writer.py index 196cd12ed..7884a4532 100644 --- a/tests/test_writer.py +++ b/tests/test_writer.py @@ -381,7 +381,8 @@ def test_write_find_links(writer, find_links, expected_lines): def test_write_order(writer, from_line): """ - Order of packages should match that of `pip freeze`. + Order of packages should match that of `pip freeze`, with the exception + that requirement names should be canonicalized. """ writer.emit_header = False @@ -393,7 +394,7 @@ def test_write_order(writer, from_line): ] expected_lines = [ "package==5.6", - "package_a==0.1", + "package-a==0.1", "package-b==2.3.4", "package2==7.8.9", ] diff --git a/tox.ini b/tox.ini index fac40a2e3..9206cc5e6 100644 --- a/tox.ini +++ b/tox.ini @@ -1,7 +1,7 @@ [tox] envlist = # NOTE: keep this in sync with the env list in .github/workflows/ci.yml. - py{36,37,38,39,310,311,py3}-pip{previous,latest,main}-coverage + py{37,38,39,310,311,py3}-pip{previous,latest,main}-coverage checkqa readme skip_missing_interpreters = True @@ -11,7 +11,7 @@ extras = testing coverage: coverage deps = - pipprevious: pip==21.2.* + pipprevious: pip==21.3.* piplatest: pip pipmain: -e git+https://github.com/pypa/pip.git@main#egg=pip setenv =