Skip to content

Commit feb8199

Browse files
Merge pull request #89 from r1chardj0n3s/3.11-tests
Add support for Python 3.11
2 parents ec86842 + bcfd93c commit feb8199

File tree

8 files changed

+73
-68
lines changed

8 files changed

+73
-68
lines changed

.github/workflows/ci.yml

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,13 @@ jobs:
2222
# These versions match the minimum and maximum versions of pip in
2323
# requirements.txt.
2424
# An empty string here represents the latest version.
25-
pip-version: ['==10.0.1', '==21.2.4', '']
26-
python-version: [3.6, 3.7, 3.8, 3.9]
25+
pip-version: ['==21.2.4', '']
26+
python-version: ["3.8", "3.9", "3.10", "3.11"]
2727

2828
steps:
29-
- uses: actions/checkout@v2
29+
- uses: actions/checkout@v3
3030
- name: "Set up Python"
31-
uses: actions/setup-python@v1
31+
uses: actions/setup-python@v4
3232
with:
3333
python-version: ${{ matrix.python-version }}
3434

@@ -48,7 +48,9 @@ jobs:
4848
# We use '--ignore-installed' to avoid GitHub's cache which can cause
4949
# issues - we have seen packages from this cache be cause trouble with
5050
# pip-extra-reqs.
51-
python -m pip install --ignore-installed --upgrade --editable .[dev]
51+
#
52+
# We avoid "--upgrade" as we do version tests for the "pip" dependency.
53+
python -m pip install --ignore-installed --editable .[dev]
5254
python -m pip install flake8
5355
5456
- name: "Lint"
@@ -62,4 +64,4 @@ jobs:
6264
pytest -s -vvv --cov-fail-under 100 --cov=pip_check_reqs/ --cov=tests tests/ --cov-report=xml
6365
6466
- name: "Upload coverage to Codecov"
65-
uses: "codecov/codecov-action@v1"
67+
uses: "codecov/codecov-action@v3"

pip_check_reqs/common.py

Lines changed: 2 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import sys
88

99
from pathlib import Path
10-
from typing import Container, Optional, List, cast
1110

1211
from packaging.utils import canonicalize_name
1312
from packaging.markers import Marker
@@ -20,47 +19,6 @@
2019
except ImportError: # pragma: no cover
2120
from pip._internal.download import PipSession
2221
from pip._internal.req.req_file import parse_requirements
23-
try:
24-
from pip._internal.utils.misc import get_installed_distributions
25-
except ImportError: # pip>=21.3
26-
from pip._internal.utils.compat import stdlib_pkgs
27-
from pip._internal.metadata import get_default_environment, get_environment
28-
from pip._internal.metadata.pkg_resources import Distribution as _Dist
29-
from pip._vendor.pkg_resources import Distribution
30-
31-
# get_installed_distributions was removed in pip 21.3.
32-
# This is a copy from pip.
33-
# See
34-
# https://github.com/pypa/pip/commit/d051a00fc57037104fca85ad8ebf2cdbd1e32d24#diff-058e40cb3a9ea705f655937e48f3a053f5dc7c500b7f1b2aae76e9bd673faf64.
35-
#
36-
# This is mocked in all tests (unfortunately) and so we do not cover this
37-
# function.
38-
def get_installed_distributions(
39-
local_only: bool = True,
40-
skip: Container[str] = stdlib_pkgs,
41-
include_editables: bool = True,
42-
editables_only: bool = False,
43-
user_only: bool = False,
44-
paths: Optional[List[str]] = None,
45-
) -> List[Distribution]: # pragma: no cover
46-
"""Return a list of installed Distribution objects.
47-
48-
Left for compatibility until direct pkg_resources uses are refactored
49-
out.
50-
"""
51-
if paths is None:
52-
env = get_default_environment()
53-
else:
54-
env = get_environment(paths)
55-
56-
dists = env.iter_installed_distributions(
57-
local_only=local_only,
58-
skip=skip,
59-
include_editables=include_editables,
60-
editables_only=editables_only,
61-
user_only=user_only,
62-
)
63-
return [cast(_Dist, dist)._dist for dist in dists]
6422

6523

6624
log = logging.getLogger(__name__)
@@ -120,8 +78,8 @@ def __addModule(self, modname, lineno):
12078

12179
# we might have previously seen a useful path though...
12280
if modpath is None: # pragma: no cover
123-
# the sys module will hit this code path on py3k - possibly
124-
# others will, but I've not discovered them
81+
# the sys module will hit this code path, and os will on 3.11+.
82+
# possibly others will, but I've not discovered them.
12583
modpath = last_modpath
12684
break
12785

pip_check_reqs/find_extra_reqs.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import collections
2+
import importlib.metadata
23
import logging
34
import pathlib
45
import optparse
@@ -8,7 +9,7 @@
89
from packaging.utils import canonicalize_name
910
from pip._internal.commands.show import search_packages_info
1011
from pip_check_reqs import common
11-
from pip_check_reqs.common import get_installed_distributions, version_info
12+
from pip_check_reqs.common import version_info
1213

1314
log = logging.getLogger(__name__)
1415

@@ -20,7 +21,11 @@ def find_extra_reqs(options, requirements_filename):
2021

2122
# 2. find which packages provide which files
2223
installed_files = {}
23-
all_pkgs = (pkg.project_name for pkg in get_installed_distributions())
24+
all_pkgs = (
25+
dist.metadata["Name"] for dist
26+
in importlib.metadata.distributions()
27+
)
28+
2429
for package in search_packages_info(all_pkgs):
2530
if isinstance(package, dict): # pragma: no cover
2631
package_name = package['name']

pip_check_reqs/find_missing_reqs.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import collections
2+
import importlib.metadata
23
import logging
34
import optparse
45
import os
@@ -15,7 +16,7 @@
1516
from pip._internal.req.req_file import parse_requirements
1617

1718
from pip_check_reqs import common
18-
from pip_check_reqs.common import get_installed_distributions, version_info
19+
from pip_check_reqs.common import version_info
1920

2021
log = logging.getLogger(__name__)
2122

@@ -27,7 +28,11 @@ def find_missing_reqs(options, requirements_filename):
2728

2829
# 2. find which packages provide which files
2930
installed_files = {}
30-
all_pkgs = (pkg.project_name for pkg in get_installed_distributions())
31+
all_pkgs = (
32+
dist.metadata["Name"] for dist
33+
in importlib.metadata.distributions()
34+
)
35+
3136
for package in search_packages_info(all_pkgs):
3237
if isinstance(package, dict): # pragma: no cover
3338
package_name = package['name']

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
packaging >= 16.0
22
# Pinned pip versions are matched in the GitHub workflows CI matrix.
3-
pip >= 10.0.1
3+
pip >= 21.2.4

tests/test_common.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,20 @@ def test_pyfiles_package(monkeypatch):
8989
['spam/__init__.py', 'spam/ham.py', 'spam/dub/bass.py']
9090

9191

92+
# Beware - using "sys" or "os" here can have weird results.
93+
# See the comment in the implementation.
94+
# We don't mind so much as we only really use this for third party packages.
9295
@pytest.mark.parametrize(["ignore_ham", "ignore_hashlib", "expect", "locs"], [
93-
(False, False, ['ast', 'os', 'hashlib'], [('spam.py', 2), ('ham.py', 2)]),
94-
(False, True, ['ast', 'os'], [('spam.py', 2), ('ham.py', 2)]),
96+
(
97+
False,
98+
False,
99+
['ast', 'pathlib', 'hashlib'],
100+
[
101+
('spam.py', 2),
102+
('ham.py', 2),
103+
],
104+
),
105+
(False, True, ['ast', 'pathlib'], [('spam.py', 2), ('ham.py', 2)]),
95106
(True, False, ['ast'], [('spam.py', 2)]),
96107
(True, True, ['ast'], [('spam.py', 2)]),
97108
])
@@ -110,7 +121,7 @@ def test_find_imported_modules(caplog, ignore_ham, ignore_hashlib,
110121
)
111122
ham_file_contents = textwrap.dedent(
112123
"""\
113-
from os import path
124+
from pathlib import Path
114125
import ast, hashlib
115126
""",
116127
)

tests/test_find_extra_reqs.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
from __future__ import absolute_import
2+
from dataclasses import dataclass
3+
import importlib
4+
from typing import Dict, Optional
25

3-
import collections
46
import logging
57
import optparse
68
from pathlib import Path
@@ -51,10 +53,20 @@ def test_find_extra_reqs(monkeypatch, tmp_path: Path):
5153
monkeypatch.setattr(common, 'find_imported_modules',
5254
pretend.call_recorder(lambda a: imported_modules))
5355

54-
FakeDist = collections.namedtuple('FakeDist', ['project_name'])
55-
installed_distributions = map(FakeDist, ['spam', 'pass'])
56-
monkeypatch.setattr(find_extra_reqs, 'get_installed_distributions',
57-
pretend.call_recorder(lambda: installed_distributions))
56+
@dataclass
57+
class FakePathDistribution:
58+
metadata: Dict
59+
name: Optional[str] = None
60+
61+
installed_distributions = map(
62+
FakePathDistribution,
63+
[{'Name': 'spam'}, {'Name': 'pass'}],
64+
)
65+
monkeypatch.setattr(
66+
importlib.metadata,
67+
'distributions',
68+
pretend.call_recorder(lambda **kwargs: installed_distributions),
69+
)
5870
packages_info = [
5971
dict(name='spam',
6072
location='site-spam',

tests/test_find_missing_reqs.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
from __future__ import absolute_import
2+
from dataclasses import dataclass
3+
import importlib
4+
from typing import Dict, Optional
25

3-
import collections
46
import logging
57
import optparse
68
from pathlib import Path
@@ -50,10 +52,20 @@ def test_find_missing_reqs(monkeypatch, tmp_path: Path):
5052
monkeypatch.setattr(common, 'find_imported_modules',
5153
pretend.call_recorder(lambda a: imported_modules))
5254

53-
FakeDist = collections.namedtuple('FakeDist', ['project_name'])
54-
installed_distributions = map(FakeDist, ['spam', 'pass'])
55-
monkeypatch.setattr(find_missing_reqs, 'get_installed_distributions',
56-
pretend.call_recorder(lambda: installed_distributions))
55+
@dataclass
56+
class FakePathDistribution:
57+
metadata: Dict
58+
name: Optional[str] = None
59+
60+
installed_distributions = map(
61+
FakePathDistribution,
62+
[{'Name': 'spam'}, {'Name': 'pass'}],
63+
)
64+
monkeypatch.setattr(
65+
importlib.metadata,
66+
'distributions',
67+
pretend.call_recorder(lambda **kwargs: installed_distributions),
68+
)
5769
packages_info = [
5870
dict(name='spam',
5971
location='site-spam',

0 commit comments

Comments
 (0)