Skip to content

feat(show): show wanted version for outdated packages - #10961

Open
Yijian6 wants to merge 1 commit into
python-poetry:mainfrom
Yijian6:show-outdated-wanted-version
Open

feat(show): show wanted version for outdated packages#10961
Yijian6 wants to merge 1 commit into
python-poetry:mainfrom
Yijian6:show-outdated-wanted-version

Conversation

@Yijian6

@Yijian6 Yijian6 commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

What

Adds a wanted version to poetry show --outdated text output and JSON output.

Why

Closes #9495. poetry show --outdated currently reports the installed version and the latest version, but it does not show the highest version that still satisfies the project's dependency constraint. This makes it harder to tell whether a dependency can be updated with the current constraint or needs a constraint change.

How

When --outdated is used, the command now resolves a constraint-compatible candidate from the active root dependency constraints and displays it between the installed and latest versions. Direct-origin dependencies keep their direct-origin display behavior, and transitive dependencies without a root constraint continue to use the latest version.

Testing

  • python -m pytest tests\console\commands\test_show.py -q -k "outdated and not local_dependencies"
  • python -m pytest tests\console\commands\test_show.py::test_show_latest_non_decorated tests\console\commands\test_show.py::test_show_latest_decorated -q
  • ruff check src\poetry\console\commands\show.py tests\console\commands\test_show.py
  • mypy src\poetry\console\commands\show.py

Breaking changes

None. The JSON output gains a wanted_version field for --outdated results.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey - I've found 2 issues, and left some high level feedback:

  • In find_wanted_package, you construct a new VersionSelector on every call; consider instantiating it once (e.g. as a cached attribute on the command) and reusing it to avoid repeated allocations during show --outdated on larger dependency sets.
  • When --outdated is used without --latest, wanted_packages is still populated but never read; you can skip computing wanted (and wanted_length) unless show_latest is true to reduce unnecessary work.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `find_wanted_package`, you construct a new `VersionSelector` on every call; consider instantiating it once (e.g. as a cached attribute on the command) and reusing it to avoid repeated allocations during `show --outdated` on larger dependency sets.
- When `--outdated` is used without `--latest`, `wanted_packages` is still populated but never read; you can skip computing `wanted` (and `wanted_length`) unless `show_latest` is true to reduce unnecessary work.

## Individual Comments

### Comment 1
<location path="tests/console/commands/test_show.py" line_range="902-899" />
<code_context>
+@output_format_parametrize
</code_context>
<issue_to_address>
**suggestion (testing):** Add a test case for transitive dependencies without root constraints where `wanted_version` should fall back to the latest version

The new test covers the capped-by-root-constraint case well, but there’s no test for the transitive-only case where no root requirement matches and `find_wanted_package` should set `wanted` to `latest`.

Please add a companion test that:
- Omits the `poetry.package.add_dependency(...)` call (making the dependency transitive-only).
- Asserts `wanted_version == 0.3.0` (the latest) instead of `0.2.0`.
- Uses `@output_format_parametrize` to cover both JSON and text output.

This will exercise the "no root constraint" branch and protect against regressions where `wanted_version` might incorrectly fall back to the installed version for transitive dependencies.

Suggested implementation:

```python
@output_format_parametrize
def test_show_outdated_wanted_version_transitive_dependency_uses_latest(
    output_format: str,
    tester: CommandTester,
    poetry: Poetry,
    installed: Repository,
    repo: DummyRepository,
) -> None:
    # Note: no poetry.package.add_dependency(...) here – cachy is only a transitive dependency

    # Ensure the repository has a higher version available so that "latest" is 0.3.0
    # (the concrete way to add packages should mirror the surrounding tests)
    repo.add_package(Package("cachy", "0.3.0"))

    if output_format == "json":
        tester.execute("show cachy --outdated --format=json")

        expected = {
            "name": "cachy",
            "current_version": "0.1.0",
            "wanted_version": "0.3.0",
            "latest_version": "0.3.0",
            "description": "Cachy package",
            "latest_status": "latest",
            "installed_status": "installed",
        }
        assert json.loads(tester.io.fetch_output()) == expected
    else:
        tester.execute("show cachy --outdated")

        expected = """\
cachy 0.1.0 0.3.0 0.3.0 Cachy package
"""
        assert tester.io.fetch_output() == expected


@output_format_parametrize
def test_show_outdated_wanted_version_respects_dependency_constraint(
    output_format: str,
    tester: CommandTester,
    poetry: Poetry,
    installed: Repository,
    repo: DummyRepository,
) -> None:
    poetry.package.add_dependency(
        Factory.create_dependency("cachy", ">=0.1.0,<0.3.0")
    )

```

To integrate this cleanly with the existing test suite, you should:

1. Align the way the `Package("cachy", "0.3.0")` object is constructed with the rest of the file.  
   - If other tests use a helper like `get_package("cachy", "0.3.0")` or `Factory.create_poetry_package(...)`, use that instead of directly instantiating `Package`.
   - If `Package` is not already imported in this file, either import it or adjust `repo.add_package(...)` to use the same factory/helper as the surrounding tests.

2. Ensure the CLI invocation matches the rest of the show/outdated tests:
   - If other tests use `tester.execute("show cachy --outdated --format {}".format(output_format))` or `["show", "cachy", "--outdated", f"--format={output_format}"]`, mirror that pattern instead of the bare string used here.
   - If the command is invoked without the package name for these scenarios (e.g. `show --outdated` lists all packages), adapt the `tester.execute(...)` call and the expected output accordingly so that we still assert `wanted_version == "0.3.0"` for `cachy`.

3. Adjust the expected JSON/text structure to match the actual schema used in this file:
   - If the JSON payload uses different keys (e.g. `"version"` vs `"wanted_version"`) or nests package info in a list, update the `expected` structure and assertions accordingly, ensuring the test explicitly checks that the *wanted* version for `cachy` is `"0.3.0"`.
   - Similarly, if the text output format uses a different column order, update the string so the “wanted” column is `0.3.0`, while “latest” still reflects the true latest (here also `0.3.0`).

These adjustments will make the new test a true companion to `test_show_outdated_wanted_version_respects_dependency_constraint` and ensure it exercises the “no root constraint / transitive-only” branch of `find_wanted_package`.
</issue_to_address>

### Comment 2
<location path="tests/console/commands/test_show.py" line_range="1280-1281" />
<code_context>
         expected = """\
-cachy    0.1.0 0.2.0 Cachy package
-pendulum 2.0.0 2.0.1 Pendulum package
+cachy    0.1.0 0.1.0 0.2.0 Cachy package
+pendulum 2.0.0 2.0.1 2.0.1 Pendulum package
 """
         assert tester.io.fetch_output() == expected
</code_context>
<issue_to_address>
**suggestion (testing):** Consider adding a narrow-terminal-width test to exercise the `write_wanted` and alignment logic

Since the new layout logic (`write_wanted`, `wanted_column_length`, updated `write_latest`, `why_end_column`, truncation) behaves differently on narrow terminals, it would be good to add a test that forces a small terminal width (e.g. via monkeypatching `shutil.get_terminal_size`) and verifies that when `write_wanted` is false, the `wanted_version` column is omitted while `latest_version` and descriptions still render with correct alignment/truncation.

Suggested implementation:

```python
        expected = """\



@output_format_parametrize
def test_show_outdated_omits_wanted_column_on_narrow_terminal(
    output_format: str,
    tester: CommandTester,
    poetry: Poetry,
    installed: Repository,
    repo: DummyRepository,
    monkeypatch,
) -> None:
    import os
    import shutil
    import pytest

    # Only the human-readable text output exercises the column-width logic.
    if output_format != "text":
        pytest.skip("narrow-terminal layout is only relevant for text output")

    # Force a very narrow terminal width so that the wanted column is dropped.
    monkeypatch.setattr(
        shutil,
        "get_terminal_size",
        lambda fallback=(80, 20): os.terminal_size((40, fallback[1])),
    )

    # Execute the `show outdated` command; fixtures set up outdated packages.
    tester.execute("show", "outdated", "--format", output_format)
    output = tester.io.fetch_output()

    # When the terminal is narrow, the wanted column should be omitted while
    # latest versions are still shown. We assert this structurally without
    # depending on exact spacing.
    lines = [line for line in output.splitlines() if line.strip()]

    # Find lines corresponding to our known packages.
    cachy_line = next(line for line in lines if "cachy" in line)
    pendulum_line = next(line for line in lines if "pendulum" in line)

    # Ensure that the "wanted" versions are not rendered, while installed/latest
    # versions still appear. The concrete version values come from the fixtures.
    # We rely on the fact that wanted_version != latest_version for these
    # dependencies, so if the wanted column was rendered we'd see both.
    assert cachy_line.count(".") <= 2
    assert pendulum_line.count(".") <= 2

    # Descriptions should still be aligned even when the wanted column is dropped.
    # We approximate this by checking that the descriptions for different packages
    # start at the same column.
    # The description strings come from the repo fixtures, e.g. "Cachy package".
    cachy_desc_token = "Cachy"
    pendulum_desc_token = "Pendulum"

    assert cachy_desc_token in cachy_line
    assert pendulum_desc_token in pendulum_line

    cachy_desc_start = cachy_line.index(cachy_desc_token)
    pendulum_desc_start = pendulum_line.index(pendulum_desc_token)
    assert cachy_desc_start == pendulum_desc_start



@output_format_parametrize
def test_show_outdated_wanted_version_respects_dependency_constraint(
    output_format: str,
    tester: CommandTester,
    poetry: Poetry,
    installed: Repository,
    repo: DummyRepository,
) -> None:

```

1. Ensure that the fixtures used in this file always create outdated entries for `cachy` and `pendulum` with distinct `wanted_version` and `latest_version` values so that the `count(".")` heuristic correctly distinguishes between layouts with and without the wanted column.
2. If `shutil.get_terminal_size` is imported or referenced through a different module path inside the show command implementation (for example, `poetry.console.commands.show.shutil` or `poetry.console.commands.show_command.shutil`), adjust the `monkeypatch.setattr` target accordingly to patch the exact object used by the command.
3. If this test file does not currently import `pytest`, you may prefer to add a single top-level `import pytest` and remove the inline import inside the test function to match existing style in the file.
4. If the version strings or description tokens differ from those used in this test (`"Cachy"` and `"Pendulum"`), update the token strings to match the actual descriptions used by the fixtures so that the alignment assertion remains valid.
</issue_to_address>

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.

Comment thread tests/console/commands/test_show.py
Comment thread tests/console/commands/test_show.py
@Yijian6
Yijian6 force-pushed the show-outdated-wanted-version branch 2 times, most recently from 7af72cb to 96285ae Compare June 24, 2026 04:22
@Yijian6
Yijian6 force-pushed the show-outdated-wanted-version branch from 96285ae to fc3d9c5 Compare June 24, 2026 04:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

poetry show --outdated: also show latest "wanted" version

1 participant