Add --exclude option to pip freeze and pip list commands

This commit is contained in:
Xavier Fernandez 2020-10-30 21:50:59 +01:00
parent cdc5422ed5
commit 9725229888
7 changed files with 68 additions and 2 deletions

1
news/4256.feature.rst Normal file
View File

@ -0,0 +1 @@
Add ``--exclude`` option to ``pip freeze`` and ``pip list`` commands to explicitly exclude packages from the output.

2
news/4256.removal.rst Normal file
View File

@ -0,0 +1,2 @@
``pip freeze`` will stop filtering the ``pip``, ``setuptools``, ``distribute`` and ``wheel`` packages from ``pip freeze`` output in a future version.
To keep the previous behavior, users should use the new ``--exclude`` option.

View File

@ -20,6 +20,8 @@ from functools import partial
from optparse import SUPPRESS_HELP, Option, OptionGroup
from textwrap import dedent
from pip._vendor.packaging.utils import canonicalize_name
from pip._internal.cli.progress_bars import BAR_TYPES
from pip._internal.exceptions import CommandError
from pip._internal.locations import USER_CACHE_DIR, get_src_prefix
@ -133,9 +135,15 @@ def _path_option_check(option, opt, value):
return os.path.expanduser(value)
def _package_name_option_check(option, opt, value):
# type: (Option, str, str) -> str
return canonicalize_name(value)
class PipOption(Option):
TYPES = Option.TYPES + ("path",)
TYPES = Option.TYPES + ("path", "package_name")
TYPE_CHECKER = Option.TYPE_CHECKER.copy()
TYPE_CHECKER["package_name"] = _package_name_option_check
TYPE_CHECKER["path"] = _path_option_check
@ -866,6 +874,17 @@ def check_list_path_option(options):
)
list_exclude = partial(
PipOption,
'--exclude',
dest='excludes',
action='append',
metavar='package',
type='package_name',
help="Exclude specified package from the output",
) # type: Callable[..., Option]
no_python_version_warning = partial(
Option,
'--no-python-version-warning',

View File

@ -74,6 +74,7 @@ class FreezeCommand(Command):
dest='exclude_editable',
action='store_true',
help='Exclude editable package from output.')
self.cmd_opts.add_option(cmdoptions.list_exclude())
self.parser.insert_option_group(0, self.cmd_opts)
@ -85,6 +86,9 @@ class FreezeCommand(Command):
if not options.freeze_all:
skip.update(DEV_PKGS)
if options.excludes:
skip.update(options.excludes)
cmdoptions.check_list_path_option(options)
if options.find_links:

View File

@ -12,6 +12,7 @@ from pip._internal.exceptions import CommandError
from pip._internal.index.collector import LinkCollector
from pip._internal.index.package_finder import PackageFinder
from pip._internal.models.selection_prefs import SelectionPreferences
from pip._internal.utils.compat import stdlib_pkgs
from pip._internal.utils.misc import (
dist_is_editable,
get_installed_distributions,
@ -114,6 +115,7 @@ class ListCommand(IndexGroupCommand):
help='Include editable package from output.',
default=True,
)
self.cmd_opts.add_option(cmdoptions.list_exclude())
index_opts = cmdoptions.make_option_group(
cmdoptions.index_group, self.parser
)
@ -147,12 +149,17 @@ class ListCommand(IndexGroupCommand):
cmdoptions.check_list_path_option(options)
skip = set(stdlib_pkgs)
if options.excludes:
skip.update(options.excludes)
packages = get_installed_distributions(
local_only=options.local,
user_only=options.user,
editables_only=options.editable,
include_editables=options.include_editable,
paths=options.path,
skip=skip,
)
# get_not_required must be called firstly in order to find and

View File

@ -16,6 +16,7 @@ from tests.lib import (
need_mercurial,
need_svn,
path_to_url,
wheel,
)
distribute_re = re.compile('^distribute==[0-9.]+\n', re.MULTILINE)
@ -80,6 +81,25 @@ def test_freeze_with_pip(script):
assert 'pip==' in result.stdout
def test_exclude_and_normalization(script, tmpdir):
req_path = wheel.make_wheel(
name="Normalizable_Name", version="1.0").save_to_dir(tmpdir)
script.pip("install", "--no-index", req_path)
result = script.pip("freeze")
assert "Normalizable-Name" in result.stdout
result = script.pip("freeze", "--exclude", "normalizablE-namE")
assert "Normalizable-Name" not in result.stdout
def test_freeze_multiple_exclude_with_all(script, with_wheel):
result = script.pip('freeze', '--all')
assert 'pip==' in result.stdout
assert 'wheel==' in result.stdout
result = script.pip('freeze', '--all', '--exclude', 'pip', '--exclude', 'wheel')
assert 'pip==' not in result.stdout
assert 'wheel==' not in result.stdout
def test_freeze_with_invalid_names(script):
"""
Test that invalid names produce warnings and are passed over gracefully.

View File

@ -3,7 +3,7 @@ import os
import pytest
from tests.lib import create_test_package_with_setup
from tests.lib import create_test_package_with_setup, wheel
from tests.lib.path import Path
@ -94,6 +94,19 @@ def test_local_columns_flag(simple_script):
assert 'simple 1.0' in result.stdout, str(result)
def test_multiple_exclude_and_normalization(script, tmpdir):
req_path = wheel.make_wheel(
name="Normalizable_Name", version="1.0").save_to_dir(tmpdir)
script.pip("install", "--no-index", req_path)
result = script.pip("list")
print(result.stdout)
assert "Normalizable-Name" in result.stdout
assert "pip" in result.stdout
result = script.pip("list", "--exclude", "normalizablE-namE", "--exclude", "pIp")
assert "Normalizable-Name" not in result.stdout
assert "pip" not in result.stdout
@pytest.mark.network
@pytest.mark.incompatible_with_test_venv
def test_user_flag(script, data):