Skip to content

Conversation

@Aearsears
Copy link
Contributor

@Aearsears Aearsears commented Aug 1, 2025

Pull Request Check List

Resolves: #10451

Adds a --output option to the poetry show command for text and json outputs.

poetry self show is not updated and there is some test duplication in test_show.py but this PR doesn't update them as I wanted to keep changes as contained as possible.

Duplicated test coverage:

  • test_show_non_dev_with_basic_installed_packages captured in test_show_basic_with_group_options --without test
  • test_show_with_group_only captured in test_show_basic_with_group_options --only {MAIN_GROUP}
  • test_show_with_optional_group captured in test_show_basic_with_group_options --with time

I will open another PR for the duplicated tests.

  • Added tests for changed code.
  • Updated documentation for changed code.

Summary by Sourcery

Implement an --output flag for poetry show that enables JSON output alongside the existing text format, add validation for invalid or conflicting options, serialize package data to JSON in appropriate code paths, update tests accordingly, and document the new flag.

New Features:

  • Add an --output option to the poetry show command to select between text and JSON output
  • Support JSON formatting for both single-package and multi-package show invocations

Enhancements:

  • Validate the output format and disallow combining JSON output with the --tree option
  • Serialize package information to JSON in both single and list display modes

Documentation:

  • Document the --output option in the CLI reference and note supported formats and constraints

Tests:

  • Extend existing show command tests to verify JSON output across all options and edge cases
  • Add tests for invalid output formats and tree/JSON incompatibility errors

Summary by Sourcery

Add an --output flag to the poetry show command to support JSON output alongside text, with validation for invalid formats and conflicting --tree usage

New Features:

  • Add --output option for the poetry show command to choose between text and JSON formats
  • Enable JSON output for both single-package and multi-package displays, including group filters, top-level, outdated, latest, and reverse-dependency views

Enhancements:

  • Validate the --output argument and emit errors for unsupported formats or invalid --tree combinations
  • Refactor the show command to handle JSON serialization early and streamline display logic

Documentation:

  • Document the new --output option in the CLI reference with supported formats and constraints

Tests:

  • Parameterize existing show tests to cover both text and JSON output across all modes
  • Add tests for invalid --output values and JSON/--tree incompatibility errors

@sourcery-ai
Copy link

sourcery-ai bot commented Aug 1, 2025

Reviewer's Guide

This PR adds a new --output option to the poetry show command, defines and enforces supported formats, and extends the display routines to serialize package data as JSON for both single-package and list outputs. The changes include validation of invalid format values and incompatible flags, a JSON serialization branch in the command logic, comprehensive test refactoring to parameterize and verify both text and JSON outputs (including error cases), and an update to the CLI documentation.

Sequence diagram for poetry show command with --output option

sequenceDiagram
    actor User
    participant CLI as Poetry CLI
    participant ShowCmd as ShowCommand
    participant Output as OutputFormatter

    User->>CLI: poetry show [options]
    CLI->>ShowCmd: parse arguments
    ShowCmd->>ShowCmd: validate --output value
    alt Invalid --output
        ShowCmd->>CLI: print error and exit
    else --output=json and --tree
        ShowCmd->>CLI: print error and exit
    else --output=json
        ShowCmd->>Output: serialize package(s) to JSON
        Output-->>ShowCmd: JSON string
        ShowCmd->>CLI: print JSON output
    else --output=text
        ShowCmd->>Output: format package(s) as text
        Output-->>ShowCmd: text output
        ShowCmd->>CLI: print text output
    end
Loading

Class diagram for ShowCommand with --output option

classDiagram
    class ShowCommand {
        +name: str
        +description: str
        +options: list
        +handle() int
        +_display_single_package_information()
        +_display_packages_information()
    }
    ShowCommand o-- OutputFormatter
    class OutputFormatter {
        +serialize_to_json()
        +format_as_text()
    }
Loading

File-Level Changes

Change Details Files
Add and validate the --output CLI option
  • Introduce OUTPUT_FORMATS constant
  • Declare output option on ShowCommand with default text
  • Reject unsupported formats and disallow JSON + --tree in handle()
src/poetry/console/commands/show.py
Implement JSON serialization for single-package output
  • Branch on output == 'json' in single-package display
  • Build a dict with name/version/description/dependencies/required_by
  • Dump JSON and return early
src/poetry/console/commands/show.py
Implement JSON serialization for multi-package output
  • Branch on output == 'json' in list display
  • Accumulate package dicts with status/version/latest/dependencies/description
  • Dump JSON array and return early
src/poetry/console/commands/show.py
Refactor tests to cover text and JSON outputs
  • Add output_format_parametrize decorator to test suite
  • Modify existing tests to assert JSON vs text based on format
  • Introduce tests for invalid format and JSON+tree errors
tests/console/commands/test_show.py
Update CLI documentation for --output option
  • Document --output usage, default, supported formats, and tree constraint
docs/cli.md

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@Aearsears Aearsears force-pushed the feat/poetry-show-json branch from 7942b4c to c1522c0 Compare August 1, 2025 21:51
@Aearsears
Copy link
Contributor Author

@sourcery-ai review

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @Aearsears - I've reviewed your changes - here's some feedback:

  • A lot of the JSON vs text test scaffolding is very repetitive—consider extracting a helper or fixture to DRY up the parameterized tests and assertions.
  • In show.py you import json inside multiple blocks; moving it to the module scope would remove duplicate imports and improve readability.
  • There’s a typo in the --tree error message ('the the text output'); you might want to correct it to something like 'can only be used with the text output.'
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- A lot of the JSON vs text test scaffolding is very repetitive—consider extracting a helper or fixture to DRY up the parameterized tests and assertions.
- In show.py you import `json` inside multiple blocks; moving it to the module scope would remove duplicate imports and improve readability.
- There’s a typo in the `--tree` error message ('the the text output'); you might want to correct it to something like 'can only be used with the text output.'

## Individual Comments

### Comment 1
<location> `src/poetry/console/commands/show.py:135` </location>
<code_context>
+
+            return 1
+
+        if self.option("output") != "text" and self.option("tree"):
+            self.line_error(
+                "<error>Error: --tree option can only be used the the text output.</error>"
</code_context>

<issue_to_address>
Typo in error message: 'the the text output'.

Please correct the error message to remove the duplicate 'the'.
</issue_to_address>

<suggested_fix>
<<<<<<< SEARCH
                "<error>Error: --tree option can only be used the the text output.</error>"
=======
                "<error>Error: --tree option can only be used with the text output.</error>"
>>>>>>> REPLACE

</suggested_fix>

### Comment 2
<location> `src/poetry/console/commands/show.py:397` </location>
<code_context>
+                if show_why:
+                    required_by = reverse_deps(locked, locked_repository)
+                    if required_by:
+                        content = ",".join(required_by.keys())
+                        package["required_by"] = content
+
</code_context>

<issue_to_address>
Joining required_by keys with ',' may be ambiguous if package names contain commas.

Consider outputting 'required_by' as a list rather than a comma-separated string to avoid ambiguity if package names include commas.
</issue_to_address>

<suggested_fix>
<<<<<<< SEARCH
                    if required_by:
                        content = ",".join(required_by.keys())
                        package["required_by"] = content
=======
                    if required_by:
                        package["required_by"] = list(required_by.keys())
>>>>>>> REPLACE

</suggested_fix>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

)

tester.execute("--latest")
tester.execute("--latest" if not output_format else "--latest " + output_format)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (code-quality): Swap if/else branches of if expression to remove negation (swap-if-expression)

Suggested change
tester.execute("--latest" if not output_format else "--latest " + output_format)
tester.execute("--latest " + output_format if output_format else "--latest")


ExplanationNegated conditions are more difficult to read than positive ones, so it is best
to avoid them where we can. By swapping the if and else conditions around we
can invert the condition and make it positive.

)

tester.execute("--outdated")
tester.execute("--outdated" if not output_format else "--outdated " + output_format)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (code-quality): Swap if/else branches of if expression to remove negation (swap-if-expression)

Suggested change
tester.execute("--outdated" if not output_format else "--outdated " + output_format)
tester.execute("--outdated " + output_format if output_format else "--outdated")


ExplanationNegated conditions are more difficult to read than positive ones, so it is best
to avoid them where we can. By swapping the if and else conditions around we
can invert the condition and make it positive.

)

tester.execute("--outdated")
tester.execute("--outdated" if not output_format else "--outdated " + output_format)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (code-quality): Swap if/else branches of if expression to remove negation (swap-if-expression)

Suggested change
tester.execute("--outdated" if not output_format else "--outdated " + output_format)
tester.execute("--outdated " + output_format if output_format else "--outdated")


ExplanationNegated conditions are more difficult to read than positive ones, so it is best
to avoid them where we can. By swapping the if and else conditions around we
can invert the condition and make it positive.

cachy 0.1.0 0.2.0 Cachy package
pendulum 2.0.0 2.0.1 Pendulum package
"""
tester.execute("--outdated" if not output_format else "--outdated " + output_format)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (code-quality): Use f-string instead of string concatenation (use-fstring-for-concatenation)

Suggested change
tester.execute("--outdated" if not output_format else "--outdated " + output_format)
tester.execute(
"--outdated" if not output_format else f"--outdated {output_format}"
)

)

tester.execute("--outdated")
tester.execute("--outdated" if not output_format else "--outdated " + output_format)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (code-quality): Use f-string instead of string concatenation (use-fstring-for-concatenation)

Suggested change
tester.execute("--outdated" if not output_format else "--outdated " + output_format)
tester.execute(
"--outdated" if not output_format else f"--outdated {output_format}"
)

cachy 0.1.0 0.2.0 Cachy package
demo 0.1.1 9cf87a2 0.1.2 9cf87a2 Demo package
"""
tester.execute("--outdated" if not output_format else "--outdated " + output_format)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (code-quality): Use f-string instead of string concatenation (use-fstring-for-concatenation)

Suggested change
tester.execute("--outdated" if not output_format else "--outdated " + output_format)
tester.execute(
"--outdated" if not output_format else f"--outdated {output_format}"
)

tester.execute(
"--outdated"
if not output_format
else "--outdated --without dev " + output_format
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (code-quality): Use f-string instead of string concatenation (use-fstring-for-concatenation)

Suggested change
else "--outdated --without dev " + output_format
else f"--outdated --without dev {output_format}"

cachy 0.1.0 Cachy package
pendulum 2.0.0 Pendulum package
"""
tester.execute("--all" if not output_format else "--all " + output_format)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (code-quality): Use f-string instead of string concatenation (use-fstring-for-concatenation)

Suggested change
tester.execute("--all" if not output_format else "--all " + output_format)
tester.execute("--all" if not output_format else f"--all {output_format}")

@Aearsears
Copy link
Contributor Author

question for the reviewer on the ai bot's comment: In show.py you import json inside multiple blocks; moving it to the module scope would remove duplicate imports and improve readability.

On line 257 and then on line 638, it imports from cleo.io.null_io import NullIO twice. for the json package is it fine to import it on the module scope? will this affect poetry's performance?

@radoering
Copy link
Member

for the json package is it fine to import it on the module scope? will this affect poetry's performance?

It should be fine. Unfortunately, there is no documentation about which imports are expensive and should not be done at top level. The only way to tell for sure is to do some measurements: Run time poetry show -h (which imports the command but does not actually execute it) multiple times with local/global imports and check if there are significant differences. python -X importtime might also be useful to assess if an import is expensive.

@Aearsears Aearsears force-pushed the feat/poetry-show-json branch from 2c7ff8a to a1650cd Compare August 2, 2025 22:34
@Aearsears Aearsears marked this pull request as ready for review August 2, 2025 22:44
Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @Aearsears - I've reviewed your changes and they look great!

Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments

### Comment 1
<location> `src/poetry/console/commands/show.py:394` </location>
<code_context>
+                if show_why:
+                    required_by = reverse_deps(locked, locked_repository)
+                    if required_by:
+                        content = ",".join(required_by.keys())
+                        package["required_by"] = content
+
</code_context>

<issue_to_address>
Joining required_by keys with a comma may cause ambiguity if package names contain commas.

Returning required_by as a list of strings would prevent ambiguity and enhance machine-readability.
</issue_to_address>

<suggested_fix>
<<<<<<< SEARCH
                    if required_by:
                        content = ",".join(required_by.keys())
                        package["required_by"] = content
=======
                    if required_by:
                        package["required_by"] = list(required_by.keys())
>>>>>>> REPLACE

</suggested_fix>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@Aearsears
Copy link
Contributor Author

for single package its a single json object

{
"name": "requests", "version": "2.32.3", "description": "Python HTTP for Humans.", 
"dependencies": {"certifi": ">=2017.4.17", "charset-normalizer": ">=2,<4", "idna": ">=2.5,<4", "urllib3": ">=1.21.1,<3"}, 
"required_by": {"cachecontrol": ">=2.16.0", "requests-toolbelt": ">=2.0.1,<3.0.0"}
}

for all the packages it will output a list of objects like

[
{"name": "virtualenv", "installed_status": "installed", "version": "20.30.0", "latest_version": "20.32.0", "description": "Virtual Python Environment builder"}, 
{"name": "zstandard", "installed_status": "installed", "version": "0.23.0", "latest_version": "0.23.0", "description": "Zstandard bindings for Python"}
]

@Aearsears Aearsears force-pushed the feat/poetry-show-json branch 3 times, most recently from 35b06ad to 1420ff3 Compare August 9, 2025 17:07
Copy link
Contributor

@colindean colindean left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for undertaking this!

I add one little nit, a personal preference for Enums over lists of strings for enumerations of valid options. I always gently guide folks toward Enums in these situations.

Copy link
Member

@radoering radoering left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your contribution. It looks quite good to me. Just some minor remarks.

@Aearsears Aearsears force-pushed the feat/poetry-show-json branch 2 times, most recently from 8786523 to 95b337e Compare August 16, 2025 17:28
@Aearsears Aearsears force-pushed the feat/poetry-show-json branch from a26cffa to 218e80f Compare August 19, 2025 00:32
@radoering radoering merged commit 4b7fb9d into python-poetry:main Aug 19, 2025
54 checks passed
@colindean
Copy link
Contributor

@Aearsears thank you so very much for picking this up and running with it. This is great work and I can't wait to put it into use.

@radoering thanks again for doing what you do! I recently onboarded a team of about 50 people to Poetry :-)

@github-actions
Copy link

This pull request has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Sep 21, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

'poetry show' could output more easily machine-readable output

3 participants