From 6448bb05507a9f0404b3323f2d02007c91e76222 Mon Sep 17 00:00:00 2001 From: Laszlo Kiss-Kollar Date: Wed, 24 Apr 2019 23:17:44 +0100 Subject: [PATCH] Add support for --path in pip freeze --- news/6404.feature | 2 ++ src/pip/_internal/commands/freeze.py | 12 +++++++ src/pip/_internal/operations/freeze.py | 4 ++- src/pip/_internal/utils/misc.py | 24 +++++++++---- tests/functional/test_freeze.py | 49 ++++++++++++++++++++++++++ 5 files changed, 83 insertions(+), 8 deletions(-) create mode 100644 news/6404.feature diff --git a/news/6404.feature b/news/6404.feature new file mode 100644 index 00000000000..f2f1db58bd1 --- /dev/null +++ b/news/6404.feature @@ -0,0 +1,2 @@ +Support ``--target`` installations with ``pip freeze`` with the ``--path`` +argument. diff --git a/src/pip/_internal/commands/freeze.py b/src/pip/_internal/commands/freeze.py index dc9c53a6b5d..90c246aaa13 100644 --- a/src/pip/_internal/commands/freeze.py +++ b/src/pip/_internal/commands/freeze.py @@ -4,6 +4,7 @@ from pip._internal.cache import WheelCache from pip._internal.cli.base_command import Command +from pip._internal.exceptions import CommandError from pip._internal.models.format_control import FormatControl from pip._internal.operations.freeze import freeze from pip._internal.utils.compat import stdlib_pkgs @@ -56,6 +57,11 @@ def __init__(self, *args, **kw): action='store_true', default=False, help='Only output packages installed in user-site.') + self.cmd_opts.add_option( + '--path', + dest='path', + action='append', + help='Use the specified installation path for listing packages') self.cmd_opts.add_option( '--all', dest='freeze_all', @@ -77,11 +83,17 @@ def run(self, options, args): if not options.freeze_all: skip.update(DEV_PKGS) + if options.path and (options.user or options.local): + raise CommandError( + "Cannot combine '--path' with '--user' or '--local'" + ) + freeze_kwargs = dict( requirement=options.requirements, find_links=options.find_links, local_only=options.local, user_only=options.user, + paths=options.path, skip_regex=options.skip_requirements_regex, isolated=options.isolated_mode, wheel_cache=wheel_cache, diff --git a/src/pip/_internal/operations/freeze.py b/src/pip/_internal/operations/freeze.py index 0c4c76107c9..bfb45a0835e 100644 --- a/src/pip/_internal/operations/freeze.py +++ b/src/pip/_internal/operations/freeze.py @@ -39,6 +39,7 @@ def freeze( find_links=None, # type: Optional[List[str]] local_only=None, # type: Optional[bool] user_only=None, # type: Optional[bool] + paths=None, # type: Optional[List[str]] skip_regex=None, # type: Optional[str] isolated=False, # type: bool wheel_cache=None, # type: Optional[WheelCache] @@ -57,7 +58,8 @@ def freeze( installations = {} # type: Dict[str, FrozenRequirement] for dist in get_installed_distributions(local_only=local_only, skip=(), - user_only=user_only): + user_only=user_only, + paths=paths): try: req = FrozenRequirement.from_dist(dist) except RequirementParseError: diff --git a/src/pip/_internal/utils/misc.py b/src/pip/_internal/utils/misc.py index ca7a529387c..fb16795531e 100644 --- a/src/pip/_internal/utils/misc.py +++ b/src/pip/_internal/utils/misc.py @@ -369,12 +369,15 @@ def dist_is_editable(dist): return False -def get_installed_distributions(local_only=True, - skip=stdlib_pkgs, - include_editables=True, - editables_only=False, - user_only=False): - # type: (bool, Container[str], bool, bool, bool) -> List[Distribution] +def get_installed_distributions( + local_only=True, # type: bool + skip=stdlib_pkgs, # type: Container[str] + include_editables=True, # type: bool + editables_only=False, # type: bool + user_only=False, # type: bool + paths=None # type: Optional[List[str]] +): + # type: (...) -> List[Distribution] """ Return a list of installed Distribution objects. @@ -391,7 +394,14 @@ def get_installed_distributions(local_only=True, If ``user_only`` is True , only report installations in the user site directory. + If ``paths`` is set, only report the distributions present at the + specified list of locations. """ + if paths: + working_set = pkg_resources.WorkingSet(paths) + else: + working_set = pkg_resources.working_set + if local_only: local_test = dist_is_local else: @@ -419,7 +429,7 @@ def user_test(d): return True # because of pkg_resources vendoring, mypy cannot find stub in typeshed - return [d for d in pkg_resources.working_set # type: ignore + return [d for d in working_set # type: ignore if local_test(d) and d.key not in skip and editable_test(d) and diff --git a/tests/functional/test_freeze.py b/tests/functional/test_freeze.py index 735d71f4ebc..f5422483655 100644 --- a/tests/functional/test_freeze.py +++ b/tests/functional/test_freeze.py @@ -652,3 +652,52 @@ def test_freeze_user(script, virtualenv, data): """) _check_output(result.stdout, expected) assert 'simple2' not in result.stdout + + +def test_freeze_path(tmpdir, script, data): + """ + Test freeze with --path. + """ + script.pip('install', '--find-links', data.find_links, + '--target', tmpdir, 'simple==2.0') + result = script.pip('freeze', '--path', tmpdir) + expected = textwrap.dedent("""\ + simple==2.0 + """) + _check_output(result.stdout, expected) + + +def test_freeze_path_exclude_user(tmpdir, script, data): + """ + Test freeze with --path and make sure packages from --user are not picked + up. + """ + script.pip_install_local('--find-links', data.find_links, + '--user', 'simple2') + script.pip('install', '--find-links', data.find_links, + '--target', tmpdir, 'simple==2.0') + result = script.pip('freeze', '--path', tmpdir) + expected = textwrap.dedent("""\ + simple==2.0 + """) + _check_output(result.stdout, expected) + + +def test_freeze_path_multiple(tmpdir, script, data): + """ + Test freeze with multiple --path arguments. + """ + path1 = tmpdir / "path1" + os.mkdir(path1) + path2 = tmpdir / "path2" + os.mkdir(path2) + script.pip('install', '--find-links', data.find_links, + '--target', path1, 'simple==2.0') + script.pip('install', '--find-links', data.find_links, + '--target', path2, 'simple2==3.0') + result = script.pip('freeze', '--path', path1, '--path', path2) + expected = textwrap.dedent("""\ + simple==2.0 + simple2==3.0 + """) + _check_output(result.stdout, expected)