From 5be8d35f84f3f96887f2a4e628fc3b8012a7d367 Mon Sep 17 00:00:00 2001 From: Kelton Bassingthwaite Date: Wed, 25 Jan 2023 13:50:02 -0800 Subject: [PATCH 1/8] feat(cli): Add '--top-level' flag to show command. --- src/poetry/console/commands/show.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/poetry/console/commands/show.py b/src/poetry/console/commands/show.py index b0248f7df77..968bf2b775b 100644 --- a/src/poetry/console/commands/show.py +++ b/src/poetry/console/commands/show.py @@ -64,6 +64,7 @@ class ShowCommand(GroupCommand, EnvCommand): "a", "Show all packages (even those not compatible with current system).", ), + option("top-level", "T", "Show only top-level dependencies."), ] help = """The show command displays detailed information about a package, or @@ -77,6 +78,20 @@ def handle(self) -> int: if self.option("tree"): self.init_styles(self.io) + if self.option("top-level"): + if self.option("tree"): + self.line_error( + "Error: Cannot use --tree and --top-level at the same" + " time." + ) + return 1 + if package is not None: + self.line_error( + "Error: Cannot use --top-level when displaying a single" + " package." + ) + return 1 + if self.option("why"): if self.option("tree") and package is None: self.line_error( @@ -303,6 +318,10 @@ def _display_packages_information( color = "cyan" name = locked.pretty_name install_marker = "" + + if self.option("top-level") and reverse_deps(locked, locked_repository): + continue + if locked not in required_locked_packages: if not show_all: continue From 4d93ea795aa97b03aed0baac68162f430b55fc83 Mon Sep 17 00:00:00 2001 From: Kelton Bassingthwaite Date: Wed, 25 Jan 2023 13:51:54 -0800 Subject: [PATCH 2/8] feat(cli): Add documentation for new show '--top-level'. --- docs/cli.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/cli.md b/docs/cli.md index a4c682a757d..144bba9285d 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -484,6 +484,7 @@ required by * `--latest (-l)`: Show the latest version. * `--outdated (-o)`: Show the latest version but only for packages that are outdated. * `--all (-a)`: Show all packages (even those not compatible with current system). +* `--top-level (-T)`: Only show packages **not** required by any other package. {{% note %}} When `--only` is specified, `--with` and `--without` options are ignored. From 30b2e67b0d1e41300bc781123579734401367ed9 Mon Sep 17 00:00:00 2001 From: Kelton Bassingthwaite Date: Wed, 25 Jan 2023 15:25:16 -0800 Subject: [PATCH 3/8] feat(cli): Added tests for show top-level flag. --- tests/console/commands/test_show.py | 103 ++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/tests/console/commands/test_show.py b/tests/console/commands/test_show.py index a927cee5bf3..866ba633007 100644 --- a/tests/console/commands/test_show.py +++ b/tests/console/commands/test_show.py @@ -2140,3 +2140,106 @@ def test_url_dependency_is_not_outdated_by_repository_package( # version in the repository. tester.execute("--outdated") assert tester.io.fetch_output() == "" + + +def test_show_top_level(tester: CommandTester, poetry: Poetry, installed: Repository): + poetry.package.add_dependency(Factory.create_dependency("cachy", "^0.2.0")) + + cachy2 = get_package("cachy", "0.2.0") + cachy2.add_dependency(Factory.create_dependency("msgpack-python", ">=0.5 <0.6")) + + installed.add_package(cachy2) + + poetry.locker.mock_lock_data( + { + "package": [ + { + "name": "cachy", + "version": "0.2.0", + "description": "", + "category": "main", + "optional": False, + "platform": "*", + "python-versions": "*", + "checksum": [], + "dependencies": {"msgpack-python": ">=0.5 <0.6"}, + }, + { + "name": "msgpack-python", + "version": "0.5.1", + "description": "", + "category": "main", + "optional": False, + "platform": "*", + "python-versions": "*", + "checksum": [], + }, + ], + "metadata": { + "python-versions": "*", + "platform": "*", + "content-hash": "123456789", + "files": {"cachy": [], "msgpack-python": []}, + }, + } + ) + + tester.execute("--top-level") + + expected = """cachy 0.2.0 \n""" + + assert tester.io.fetch_output() == expected + + +def test_show_top_level_with_explicitly_defined_depenancy( + tester: CommandTester, poetry: Poetry, installed: Repository +): + poetry.package.add_dependency(Factory.create_dependency("a", "^0.1.0")) + poetry.package.add_dependency(Factory.create_dependency("b", "^0.2.0")) + + a = get_package("a", "0.1.0") + a.add_dependency(Factory.create_dependency("b", "0.2.0")) + b = get_package("b", "0.2.0") + + installed.add_package(a) + installed.add_package(b) + + poetry.locker.mock_lock_data( + { + "package": [ + { + "name": "a", + "version": "0.1.0", + "description": "", + "category": "main", + "optional": False, + "platform": "*", + "python-versions": "*", + "checksum": [], + "dependencies": {"b": "0.2.0"}, + }, + { + "name": "b", + "version": "0.2.0", + "description": "", + "category": "main", + "optional": False, + "platform": "*", + "python-versions": "*", + "checksum": [], + }, + ], + "metadata": { + "python-versions": "*", + "platform": "*", + "content-hash": "123456789", + "files": {"a": [], "b": []}, + }, + } + ) + + tester.execute("--top-level") + + expected = """a 0.1.0 \n""" + + assert tester.io.fetch_output() == expected From a8e7367ecb847a0d6f3bb91bac788bb615d5fefa Mon Sep 17 00:00:00 2001 From: Kelton Bassingthwaite Date: Wed, 25 Jan 2023 16:19:35 -0800 Subject: [PATCH 4/8] feat(cli): "show --top-level" displays explicitly defined deps. Previously it only showed deps not required by any other deps. --- src/poetry/console/commands/show.py | 4 +++- tests/console/commands/test_show.py | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/poetry/console/commands/show.py b/src/poetry/console/commands/show.py index 968bf2b775b..a8d2417c071 100644 --- a/src/poetry/console/commands/show.py +++ b/src/poetry/console/commands/show.py @@ -319,7 +319,9 @@ def _display_packages_information( name = locked.pretty_name install_marker = "" - if self.option("top-level") and reverse_deps(locked, locked_repository): + if self.option("top-level") and not any( + locked.is_same_package_as(r) for r in root.all_requires + ): continue if locked not in required_locked_packages: diff --git a/tests/console/commands/test_show.py b/tests/console/commands/test_show.py index 866ba633007..ba7127bcd24 100644 --- a/tests/console/commands/test_show.py +++ b/tests/console/commands/test_show.py @@ -2240,6 +2240,6 @@ def test_show_top_level_with_explicitly_defined_depenancy( tester.execute("--top-level") - expected = """a 0.1.0 \n""" + expected = """a 0.1.0 \nb 0.2.0 \n""" assert tester.io.fetch_output() == expected From 85cfe3b09f08af1efe97d2162fb001e6d3e76f58 Mon Sep 17 00:00:00 2001 From: Kelton Bassingthwaite Date: Wed, 25 Jan 2023 17:05:32 -0800 Subject: [PATCH 5/8] Reworded documentation to be more clear. --- docs/cli.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/cli.md b/docs/cli.md index 144bba9285d..7fe97e50334 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -484,7 +484,7 @@ required by * `--latest (-l)`: Show the latest version. * `--outdated (-o)`: Show the latest version but only for packages that are outdated. * `--all (-a)`: Show all packages (even those not compatible with current system). -* `--top-level (-T)`: Only show packages **not** required by any other package. +* `--top-level (-T)`: Only show explicitly defined packages. {{% note %}} When `--only` is specified, `--with` and `--without` options are ignored. From f93ca34c7f7e93f84ef8c898059aa56e99e8425d Mon Sep 17 00:00:00 2001 From: Kelton Bassingthwaite Date: Tue, 18 Apr 2023 15:19:54 -0700 Subject: [PATCH 6/8] Added tests for new error messages. Also added return types on previous tests. --- tests/console/commands/test_show.py | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/tests/console/commands/test_show.py b/tests/console/commands/test_show.py index 321ffc8bb36..5d136aeade8 100644 --- a/tests/console/commands/test_show.py +++ b/tests/console/commands/test_show.py @@ -2149,7 +2149,9 @@ def test_url_dependency_is_not_outdated_by_repository_package( assert tester.io.fetch_output() == "" -def test_show_top_level(tester: CommandTester, poetry: Poetry, installed: Repository): +def test_show_top_level( + tester: CommandTester, poetry: Poetry, installed: Repository +) -> None: poetry.package.add_dependency(Factory.create_dependency("cachy", "^0.2.0")) cachy2 = get_package("cachy", "0.2.0") @@ -2200,7 +2202,7 @@ def test_show_top_level(tester: CommandTester, poetry: Poetry, installed: Reposi def test_show_top_level_with_explicitly_defined_depenancy( tester: CommandTester, poetry: Poetry, installed: Repository -): +) -> None: poetry.package.add_dependency(Factory.create_dependency("a", "^0.1.0")) poetry.package.add_dependency(Factory.create_dependency("b", "^0.2.0")) @@ -2252,6 +2254,22 @@ def test_show_top_level_with_explicitly_defined_depenancy( assert tester.io.fetch_output() == expected +def test_show_error_top_level_with_tree( + tester: CommandTester, +) -> None: + expected = "Error: Cannot use --tree and --top-level at the same time.\n" + tester.execute("--top-level --tree") + assert tester.io.fetch_error() == expected + assert tester.status_code == 1 + + +def test_show_error_top_level_with_single_package(tester: CommandTester) -> None: + expected = "Error: Cannot use --top-level when displaying a single package.\n" + tester.execute("--top-level some_package_name") + assert tester.io.fetch_error() == expected + assert tester.status_code == 1 + + @pytest.mark.parametrize( ("project_directory", "required_fixtures"), [ From 5512f3d875863248619fe28dcf73e2fb542aceb5 Mon Sep 17 00:00:00 2001 From: Kelton Bassingthwaite Date: Wed, 19 Apr 2023 07:53:55 -0700 Subject: [PATCH 7/8] Defined show top_level option and root.all_requires outside of the loop. --- src/poetry/console/commands/show.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/poetry/console/commands/show.py b/src/poetry/console/commands/show.py index 5a1e8f95484..1b8b03e718b 100644 --- a/src/poetry/console/commands/show.py +++ b/src/poetry/console/commands/show.py @@ -230,6 +230,7 @@ def _display_packages_information( show_latest = self.option("latest") show_all = self.option("all") + show_top_level = self.option("top-level") width = shutil.get_terminal_size().columns name_length = version_length = latest_length = required_by_length = 0 latest_packages = {} @@ -311,13 +312,15 @@ def _display_packages_information( write_why = self.option("why") and (why_end_column + 3) <= width write_description = (why_end_column + 24) <= width + requires = root.all_requires + for locked in locked_packages: color = "cyan" name = locked.pretty_name install_marker = "" - if self.option("top-level") and not any( - locked.is_same_package_as(r) for r in root.all_requires + if show_top_level and not any( + locked.is_same_package_as(r) for r in requires ): continue From c0fa007eafda09f7b7ededbf4e903b65be728a05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Randy=20D=C3=B6ring?= <30527984+radoering@users.noreply.github.com> Date: Wed, 19 Apr 2023 17:33:38 +0200 Subject: [PATCH 8/8] Update tests/console/commands/test_show.py --- tests/console/commands/test_show.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/console/commands/test_show.py b/tests/console/commands/test_show.py index 2cbaa27e8ea..821e5b87c85 100644 --- a/tests/console/commands/test_show.py +++ b/tests/console/commands/test_show.py @@ -2187,9 +2187,7 @@ def test_show_top_level_with_explicitly_defined_depenancy( assert tester.io.fetch_output() == expected -def test_show_error_top_level_with_tree( - tester: CommandTester, -) -> None: +def test_show_error_top_level_with_tree(tester: CommandTester) -> None: expected = "Error: Cannot use --tree and --top-level at the same time.\n" tester.execute("--top-level --tree") assert tester.io.fetch_error() == expected