Skip to content

Commit 62b57b9

Browse files
authored
Merge pull request #5350 from pypa/issue-5349
Safer usages of pkg_resources
2 parents 9572c31 + 4f49739 commit 62b57b9

File tree

30 files changed

+123
-284
lines changed

30 files changed

+123
-284
lines changed

news/5349.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Modernize ``pipenv`` path patch with ``importlib.util`` to eliminate import of ``pkg_resources``

pipenv/environment.py

Lines changed: 3 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import contextlib
44
import importlib
5+
import importlib.util
56
import itertools
67
import json
78
import operator
@@ -11,12 +12,11 @@
1112
from pathlib import Path
1213
from sysconfig import get_paths, get_python_version, get_scheme_names
1314

14-
import pkg_resources
15-
1615
import pipenv
1716
from pipenv.patched.pip._internal.commands.install import InstallCommand
1817
from pipenv.patched.pip._internal.index.package_finder import PackageFinder
1918
from pipenv.patched.pip._internal.req.req_uninstall import UninstallPathSet
19+
from pipenv.patched.pip._vendor import pkg_resources
2020
from pipenv.patched.pip._vendor.packaging.utils import canonicalize_name
2121
from pipenv.utils.constants import is_type_checking
2222
from pipenv.utils.indexes import prepare_pip_source_args
@@ -41,7 +41,6 @@
4141
from pipenv.project import Project, TPipfile, TSource
4242

4343
BASE_WORKING_SET = pkg_resources.WorkingSet(sys.path)
44-
# TODO: Unittests for this class
4544

4645

4746
class Environment:
@@ -863,7 +862,7 @@ def run_activate_this(self):
863862
exec(code, dict(__file__=activate_this))
864863

865864
@contextlib.contextmanager
866-
def activated(self, include_extras=True, extra_dists=None):
865+
def activated(self):
867866
"""Helper context manager to activate the environment.
868867
869868
This context manager will set the following variables for the duration
@@ -882,16 +881,8 @@ def activated(self, include_extras=True, extra_dists=None):
882881
to `os.environ["PATH"]` to ensure that calls to `~Environment.run()` use the
883882
environment's path preferentially.
884883
"""
885-
886-
if not extra_dists:
887-
extra_dists = []
888884
original_path = sys.path
889885
original_prefix = sys.prefix
890-
parent_path = Path(__file__).absolute().parent
891-
vendor_dir = parent_path.joinpath("vendor").as_posix()
892-
patched_dir = parent_path.joinpath("patched").as_posix()
893-
parent_path = parent_path.as_posix()
894-
self.add_dist("pip")
895886
prefix = self.prefix.as_posix()
896887
with vistir.contextmanagers.temp_environ(), vistir.contextmanagers.temp_path():
897888
os.environ["PATH"] = os.pathsep.join(
@@ -914,21 +905,6 @@ def activated(self, include_extras=True, extra_dists=None):
914905
os.environ.pop("PYTHONHOME", None)
915906
sys.path = self.sys_path
916907
sys.prefix = self.sys_prefix
917-
site.addsitedir(self.base_paths["purelib"])
918-
pip = self.safe_import("pip") # noqa
919-
pip_vendor = self.safe_import("pip._vendor")
920-
pep517_dir = os.path.join(os.path.dirname(pip_vendor.__file__), "pep517")
921-
site.addsitedir(pep517_dir)
922-
os.environ["PYTHONPATH"] = os.pathsep.join(
923-
[os.environ.get("PYTHONPATH", self.base_paths["PYTHONPATH"]), pep517_dir]
924-
)
925-
if include_extras:
926-
site.addsitedir(parent_path)
927-
sys.path.extend([parent_path, patched_dir, vendor_dir])
928-
extra_dists = list(self.extra_dists) + extra_dists
929-
for extra_dist in extra_dists:
930-
if extra_dist not in self.get_working_set():
931-
extra_dist.activate(self.sys_path)
932908
try:
933909
yield
934910
finally:

pipenv/patched/pip/_vendor/pkg_resources/LICENSE

Lines changed: 0 additions & 19 deletions
This file was deleted.

pipenv/patched/safety/cli.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ def check(key, db, json, full_report, bare, stdin, files, cache, ignore, output,
6161
elif stdin:
6262
packages = list(read_requirements(sys.stdin))
6363
else:
64-
import pkg_resources
64+
import pipenv.patched.pip._vendor.pkg_resources as pkg_resources
6565
packages = [
6666
d for d in pkg_resources.working_set
6767
if d.key not in {"python", "wsgiref", "argparse"}
@@ -150,7 +150,7 @@ def license(key, db, json, bare, cache, files, proxyprotocol, proxyhost, proxypo
150150
if files:
151151
packages = list(itertools.chain.from_iterable(read_requirements(f, resolve=True) for f in files))
152152
else:
153-
import pkg_resources
153+
import pipenv.patched.pip._vendor.pkg_resources as pkg_resources
154154
packages = [
155155
d for d in pkg_resources.working_set
156156
if d.key not in {"python", "wsgiref", "argparse"}

pipenv/project.py

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
# -*- coding: utf-8 -*-
21
from __future__ import annotations
32

43
import base64
@@ -23,6 +22,7 @@
2322
from pipenv.environment import Environment
2423
from pipenv.environments import Setting, is_in_virtualenv, normalize_pipfile_path
2524
from pipenv.patched.pip._internal.commands.install import InstallCommand
25+
from pipenv.patched.pip._vendor import pkg_resources
2626
from pipenv.utils.constants import is_type_checking
2727
from pipenv.utils.dependencies import (
2828
get_canonical_names,
@@ -37,6 +37,7 @@
3737
find_windows_executable,
3838
get_workon_home,
3939
is_virtual_environment,
40+
load_path,
4041
looks_like_dir,
4142
safe_expandvars,
4243
system_which,
@@ -55,8 +56,6 @@
5556
if is_type_checking():
5657
from typing import Dict, List, Optional, Set, Text, Tuple, Union
5758

58-
import pkg_resources
59-
6059
TSource = Dict[Text, Union[Text, bool]]
6160
TPackageEntry = Dict[str, Union[bool, str, List[str]]]
6261
TPackage = Dict[str, TPackageEntry]
@@ -243,11 +242,7 @@ def get_location_for_virtualenv(self) -> str:
243242

244243
@property
245244
def working_set(self) -> pkg_resources.WorkingSet:
246-
from pipenv.utils.shell import load_path
247-
248245
sys_path = load_path(self.which("python"))
249-
import pkg_resources
250-
251246
return pkg_resources.WorkingSet(sys_path)
252247

253248
@property

pipenv/resolver.py

Lines changed: 9 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import importlib.util
12
import json
23
import logging
34
import os
@@ -6,65 +7,13 @@
67
os.environ["PIP_PYTHON_PATH"] = str(sys.executable)
78

89

9-
def find_site_path(pkg, site_dir=None):
10-
import pkg_resources
11-
12-
if site_dir is None:
13-
site_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
14-
working_set = pkg_resources.WorkingSet([site_dir] + sys.path[:])
15-
for dist in working_set:
16-
root = dist.location
17-
base_name = dist.project_name if dist.project_name else dist.key
18-
name = None
19-
if "top_level.txt" in dist.metadata_listdir(""):
20-
name = next(
21-
iter(
22-
[
23-
line.strip()
24-
for line in dist.get_metadata_lines("top_level.txt")
25-
if line is not None
26-
]
27-
),
28-
None,
29-
)
30-
if name is None:
31-
name = pkg_resources.safe_name(base_name).replace("-", "_")
32-
if not any(pkg == _ for _ in [base_name, name]):
33-
continue
34-
path_options = [name, f"{name}.py"]
35-
path_options = [os.path.join(root, p) for p in path_options if p is not None]
36-
path = next(iter(p for p in path_options if os.path.exists(p)), None)
37-
if path is not None:
38-
return dist, path
39-
return None, None
40-
41-
42-
def _patch_path(pipenv_site=None):
43-
import site
44-
45-
pipenv_libdir = os.path.dirname(os.path.abspath(__file__))
46-
pipenv_site_dir = os.path.dirname(pipenv_libdir)
47-
if pipenv_site is not None:
48-
pipenv_dist, pipenv_path = find_site_path("pipenv", site_dir=pipenv_site)
49-
else:
50-
pipenv_dist, pipenv_path = find_site_path("pipenv", site_dir=pipenv_site_dir)
51-
if pipenv_dist is not None:
52-
pipenv_dist.activate()
53-
else:
54-
site.addsitedir(
55-
next(
56-
iter(
57-
sitedir
58-
for sitedir in (pipenv_site, pipenv_site_dir)
59-
if sitedir is not None
60-
),
61-
None,
62-
)
63-
)
64-
if pipenv_path is not None:
65-
pipenv_libdir = pipenv_path
66-
for _dir in ("vendor", "patched", pipenv_libdir):
67-
sys.path.insert(0, os.path.join(pipenv_libdir, _dir))
10+
def _ensure_modules():
11+
spec = importlib.util.spec_from_file_location(
12+
"pipenv", location=os.path.join(os.path.dirname(__file__), "__init__.py")
13+
)
14+
pipenv = importlib.util.module_from_spec(spec)
15+
sys.modules["pipenv"] = pipenv
16+
spec.loader.exec_module(pipenv)
6817

6918

7019
def get_parser():
@@ -838,7 +787,7 @@ def _main(
838787
def main(argv=None):
839788
parser = get_parser()
840789
parsed, remaining = parser.parse_known_args(argv)
841-
_patch_path(pipenv_site=parsed.pipenv_site)
790+
_ensure_modules()
842791
import warnings
843792

844793
from pipenv.vendor.vistir.misc import replace_with_text_stream

pipenv/utils/resolver.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
from pipenv.patched.pip._internal.req.req_file import parse_requirements
2424
from pipenv.patched.pip._internal.utils.hashes import FAVORITE_HASH
2525
from pipenv.patched.pip._internal.utils.temp_dir import global_tempdir_manager
26+
from pipenv.patched.pip._vendor import pkg_resources
2627
from pipenv.project import Project
2728
from pipenv.vendor import click
2829
from pipenv.vendor.requirementslib import Requirement
@@ -1147,8 +1148,6 @@ def resolve_deps(
11471148

11481149
@lru_cache()
11491150
def get_pipenv_sitedir() -> Optional[str]:
1150-
import pkg_resources
1151-
11521151
site_dir = next(
11531152
iter(d for d in pkg_resources.working_set if d.key.lower() == "pipenv"), None
11541153
)

pipenv/vendor/cerberus/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
from __future__ import absolute_import
1212

13-
from pkg_resources import get_distribution, DistributionNotFound
13+
from pipenv.patched.pip._vendor.pkg_resources import get_distribution, DistributionNotFound
1414

1515
from pipenv.vendor.cerberus.validator import DocumentError, Validator
1616
from pipenv.vendor.cerberus.schema import rules_set_registry, schema_registry, SchemaError

pipenv/vendor/cerberus/tests/test_assorted.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# -*- coding: utf-8 -*-
22

33
from decimal import Decimal
4-
from pkg_resources import Distribution, DistributionNotFound
4+
from pipenv.patched.pip._vendor.pkg_resources import Distribution, DistributionNotFound
55

66
from pytest import mark
77

pipenv/vendor/requirementslib/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from .models.pipfile import Pipfile
66
from .models.requirements import Requirement
77

8-
__version__ = "2.0.1"
8+
__version__ = "2.0.2"
99

1010

1111
logger = logging.getLogger(__name__)

0 commit comments

Comments
 (0)