diff --git a/src/pip/_internal/commands/freeze.py b/src/pip/_internal/commands/freeze.py index eb7f29b3e1f..3816004a28a 100644 --- a/src/pip/_internal/commands/freeze.py +++ b/src/pip/_internal/commands/freeze.py @@ -87,6 +87,15 @@ def add_options(self) -> None: action="store_true", help="Exclude dependency packages from output.", ) + self.cmd_opts.add_option( + "--user-requested", + dest="user_requested", + action="store_true", + help=( + "List packages that were explicitly requested by user, either directly " + "via a command line argument or indirectly via a requirements file." + ), + ) self.cmd_opts.add_option(cmdoptions.list_exclude()) self.parser.insert_option_group(0, self.cmd_opts) @@ -110,6 +119,7 @@ def run(self, options: Values, args: List[str]) -> int: skip=skip, exclude_editable=options.exclude_editable, exclude_dependencies=options.exclude_dependencies, + user_requested=options.user_requested, ): sys.stdout.write(line + "\n") return SUCCESS diff --git a/src/pip/_internal/commands/list.py b/src/pip/_internal/commands/list.py index 0bbe26c0402..06cdce6a6d1 100644 --- a/src/pip/_internal/commands/list.py +++ b/src/pip/_internal/commands/list.py @@ -135,6 +135,15 @@ def add_options(self) -> None: action="store_true", help="Exclude dependency packages from output.", ) + self.cmd_opts.add_option( + "--user-requested", + dest="user_requested", + action="store_true", + help=( + "List packages that were explicitly requested by user, either directly " + "via a command line argument or indirectly via a requirements file." + ), + ) self.cmd_opts.add_option(cmdoptions.list_exclude()) index_opts = cmdoptions.make_option_group(cmdoptions.index_group, self.parser) @@ -183,6 +192,7 @@ def run(self, options: Values, args: List[str]) -> int: editables_only=options.editable, include_editables=options.include_editable, exclude_dependencies=options.exclude_dependencies, + user_requested=options.user_requested, skip=skip, ) ] diff --git a/src/pip/_internal/metadata/base.py b/src/pip/_internal/metadata/base.py index cba7dab7c3d..d30e5895a17 100644 --- a/src/pip/_internal/metadata/base.py +++ b/src/pip/_internal/metadata/base.py @@ -650,6 +650,7 @@ def iter_installed_distributions( editables_only: bool = False, user_only: bool = False, exclude_dependencies: bool = False, + user_requested: bool = False, ) -> Iterator[BaseDistribution]: """Return a list of installed distributions. @@ -668,6 +669,9 @@ def iter_installed_distributions( site directory. :param exclude_dependencies: If True, dont't report distributions that are dependencies of other installed distributions. + :param user_requested: If True, report only distributions that were + explicitly requested by user, either directly via a command line argument + or indirectly via a requirements file. """ if exclude_dependencies: dists = list(self.iter_all_distributions()) @@ -680,6 +684,8 @@ def iter_installed_distributions( it = (d for d in it if d.canonical_name not in dep_keys) else: it = self.iter_all_distributions() + if user_requested: + it = (d for d in it if d.requested) if local_only: it = (d for d in it if d.local) if not include_editables: diff --git a/src/pip/_internal/operations/freeze.py b/src/pip/_internal/operations/freeze.py index a0e5a572ad8..b7dab2f1d0c 100644 --- a/src/pip/_internal/operations/freeze.py +++ b/src/pip/_internal/operations/freeze.py @@ -31,6 +31,7 @@ def freeze( isolated: bool = False, exclude_editable: bool = False, exclude_dependencies: bool = False, + user_requested: bool = False, skip: Container[str] = (), ) -> Generator[str, None, None]: installations: Dict[str, FrozenRequirement] = {} @@ -40,6 +41,7 @@ def freeze( skip=(), user_only=user_only, exclude_dependencies=exclude_dependencies, + user_requested=user_requested, ) for dist in dists: req = FrozenRequirement.from_dist(dist)