Skip to content

Conversation

@radoering
Copy link
Member

@radoering radoering commented Nov 2, 2025

  • bump required pbs-installer version so that free-threaded Python uses a different directory for installation (cf fix: Use different version_dir for free-threaded Python and standard Python frostming/pbs-installer#11)
  • do not use an upper bound for pbs-installer because it uses calver
  • do not complain that a python version is already installed when trying to install a free-threaded python with the same version
  • list free-threaded python versions with a trailing "t"
  • allow to request a free-threaded version with a trailing "t" instead of the command option
  • add support for removing free-threaded python versions
  • fix removing Python versions with patch version "0"

Pull Request Check List

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

Summary by Sourcery

Add comprehensive support for free-threaded Python versions by extending version tracking, commands, and providers, updating documentation, tests, and bumping the pbs-installer dependency.

New Features:

  • Enable management of free-threaded Python installations via a --free-threaded (-t) flag or trailing "t" suffix.

Bug Fixes:

  • Fix removal of Python installations when the patch version is "0".

Enhancements:

  • Update installer.exists to consider free-threaded status and avoid false "already installed" errors.
  • Extend providers, manager, and installers to track a free_threaded attribute and append "t" in listings for free-threaded versions.
  • Enhance install, list, and and remove commands to handle free-threaded variants with consistent request titles.

Build:

  • Bump pbs-installer dependency to >=2025.6.10 and remove the upper version bound for calver compatibility.

Documentation:

  • Document new free-threaded option, trailing suffix behavior, and shorthand flags in the CLI guide.

Tests:

  • Add and update tests for free-threaded version handling across installation, listing, and removal workflows.

@sourcery-ai
Copy link

sourcery-ai bot commented Nov 2, 2025

Reviewer's Guide

This pull request integrates free-threaded Python support throughout Poetry's environment management by introducing a dedicated free_threaded flag, adapting path naming conventions, extending CLI commands and documentation, refining filtering and removal logic, and updating the test suite to cover all new scenarios.

Sequence diagram for Python installation with free-threaded support

sequenceDiagram
    actor User
    participant CLI as "Poetry CLI"
    participant InstallCmd as "PythonInstallCommand"
    participant PathProvider as "PoetryPythonPathProvider"
    participant Installer as "PythonInstaller"
    User->>CLI: poetry python install 3.12.0t
    CLI->>InstallCmd: handle(request="3.12.0t")
    InstallCmd->>InstallCmd: Detect trailing "t", set free_threaded=True
    InstallCmd->>PathProvider: installation_dir(version, implementation, free_threaded)
    InstallCmd->>Installer: Check if exists (with free_threaded)
    alt Already installed
        InstallCmd->>CLI: Error: Python version already installed
    else Not installed
        InstallCmd->>Installer: Download and install
        Installer->>PathProvider: installation_dir(..., free_threaded)
        Installer->>CLI: Success message
    end
Loading

Sequence diagram for Python removal with free-threaded support

sequenceDiagram
    actor User
    participant CLI as "Poetry CLI"
    participant RemoveCmd as "PythonRemoveCommand"
    participant PathProvider as "PoetryPythonPathProvider"
    User->>CLI: poetry python remove 3.12.0t
    CLI->>RemoveCmd: handle(request="3.12.0t")
    RemoveCmd->>RemoveCmd: Detect trailing "t", set free_threaded=True
    RemoveCmd->>PathProvider: installation_dir(version, implementation, free_threaded)
    RemoveCmd->>RemoveCmd: Remove installation directory
    RemoveCmd->>CLI: Success/Error message
Loading

ER diagram for Python installation directory naming

erDiagram
    PYTHON_INSTALLATION_DIR ||--o| PYTHON_VERSION : contains
    PYTHON_VERSION {
        string implementation
        string version
        boolean free_threaded
    }
    PYTHON_INSTALLATION_DIR {
        string path
    }
Loading

Class diagram for updated PythonInfo and related classes

classDiagram
    class PythonInfo {
        +int major
        +int minor
        +int patch
        +str implementation
        +bool free_threaded
        +Path|None executable
    }
    class Python {
        +property major: int
        +property minor: int
        +property patch: int
        +property implementation: str
        +property free_threaded: bool
        +property executable: Path
    }
    PythonInfo <|-- Python
Loading

Class diagram for updated PoetryPythonPathProvider methods

classDiagram
    class PoetryPythonPathProvider {
        +installation_dir(version: Version, implementation: str, free_threaded: bool): Path
        +installation_bin_paths(version: Version, implementation: str, free_threaded: bool = False): list[Path]
    }
Loading

Flow diagram for CLI option handling for free-threaded Python

flowchart TD
    A["User enters CLI command"] --> B{"Command type?"}
    B -->|install| C["Check for trailing 't' or --free-threaded"]
    B -->|remove| C
    B -->|list| C
    C --> D["Set free_threaded flag"]
    D --> E["Pass flag to logic and path provider"]
    E --> F["Perform action (install/list/remove)"]
Loading

File-Level Changes

Change Details Files
Add free-threaded installation support and bump pbs-installer dependency
  • Introduce free_threaded attribute in PythonInfo, manager, installer, and version wrappers
  • Adapt PoetryPythonPathProvider to append a trailing “t” to installation directory names for free-threaded builds
  • Update pyproject.toml to require pbs-installer >=2025.6.10 without an upper bound
src/poetry/utils/env/python/providers.py
src/poetry/utils/env/python/manager.py
src/poetry/utils/env/python/installer.py
pyproject.toml
Enhance CLI to handle free-threaded mode and trailing “t” suffix
  • Add --free-threaded (-t) option to install, list, and remove commands
  • Detect a trailing “t” in version strings to enable free-threaded mode without the flag
  • Extract get_request_title helper to uniformly format version strings with free-threaded info
  • Update CLI documentation to reflect shorthand options and new behaviors
src/poetry/console/commands/python/install.py
src/poetry/console/commands/python/list.py
src/poetry/console/commands/python/remove.py
src/poetry/console/commands/python/__init__.py
docs/cli.md
Refine version filtering and removal logic
  • Filter existing installations by matching the free_threaded flag in exists() and find_all_versions()
  • Adjust version validation to properly reject missing minor/patch components instead of checking only truthiness
  • Use PoetryPythonPathProvider.installation_dir(version, implementation, free_threaded) for correct removal paths
src/poetry/utils/env/python/manager.py
src/poetry/utils/env/python/installer.py
src/poetry/console/commands/python/remove.py
Extend and refactor tests for free-threaded scenarios
  • Add and parametrize tests covering free-threaded vs. standard installs in installer, manager, list, remove, and install modules
  • Update test fixtures (conftest.py, types.py) to support a free_threaded flag
  • Modify provider tests to validate installation_bin_paths for free-threaded builds
tests/utils/env/python/test_python_installer.py
tests/utils/env/python/test_manager.py
tests/utils/env/python/test_python_providers.py
tests/conftest.py
tests/types.py
tests/console/commands/python/test_python_install.py
tests/console/commands/python/test_python_list.py
tests/console/commands/python/test_python_remove.py

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

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 there - I've reviewed your changes - here's some feedback:

  • Extract the trailing-’t’ suffix parsing logic from both the install and remove commands into a shared helper to DRY up the code and keep behavior consistent.
  • Add validation to error out or warn when both a trailing ‘t’ in the request and the --free-threaded flag are provided so users aren’t sending redundant or conflicting options.
  • Consider pinning an upper bound for the pbs-installer dependency (e.g. <2026.0) even when using calver to guard against future breaking changes.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Extract the trailing-’t’ suffix parsing logic from both the install and remove commands into a shared helper to DRY up the code and keep behavior consistent.
- Add validation to error out or warn when both a trailing ‘t’ in the request and the --free-threaded flag are provided so users aren’t sending redundant or conflicting options.
- Consider pinning an upper bound for the pbs-installer dependency (e.g. <2026.0) even when using calver to guard against future breaking changes.

## Individual Comments

### Comment 1
<location> `src/poetry/console/commands/python/remove.py:100-110` </location>
<code_context>
    def handle(self) -> int:
        implementation = self.option("implementation").lower()
        free_threaded = self.option("free-threaded")

        result = 0

        for request in self.argument("python"):
            result += self.remove_python_installation(
                request, implementation, free_threaded, self.io
            )

        return result

</code_context>

<issue_to_address>
**issue (code-quality):** We've found these issues:

- Convert for loop into call to sum() ([`sum-comprehension`](https://docs.sourcery.ai/Reference/Default-Rules/refactorings/sum-comprehension/))
- Inline variable that is immediately returned ([`inline-immediately-returned-variable`](https://docs.sourcery.ai/Reference/Default-Rules/refactorings/inline-immediately-returned-variable/))
</issue_to_address>

### Comment 2
<location> `tests/console/commands/python/test_python_remove.py:110-114` </location>
<code_context>
@pytest.mark.parametrize("free_threaded", [True, False])
@pytest.mark.parametrize("option", [True, False])
def test_remove_version_free_threaded(
    tester: CommandTester,
    config: Config,
    mocked_poetry_managed_python_register: MockedPoetryPythonRegister,
    free_threaded: bool,
    option: bool,
) -> None:
    standard_path = mocked_poetry_managed_python_register("3.14.0", "cpython")
    free_threaded_path = mocked_poetry_managed_python_register(
        "3.14.0", "cpython", free_threaded=True
    )

    args = "3.14.0"
    if free_threaded:
        if option:
            args += " --free-threaded"
        else:
            args += "t"

    assert tester.execute(args) == 0, tester.io.fetch_error()

    details = "cpython"
    if free_threaded:
        details += ", free-threaded"
    assert (
        tester.io.fetch_output()
        == f"Removing installation 3.14.0 ({details}) ... Done\n"
    )
    if free_threaded:
        assert not free_threaded_path.exists()
        assert standard_path.exists()
    else:
        assert not standard_path.exists()
        assert free_threaded_path.exists()

</code_context>

<issue_to_address>
**suggestion (code-quality):** We've found these issues:

- Swap positions of nested conditionals ([`swap-nested-ifs`](https://docs.sourcery.ai/Reference/Default-Rules/refactorings/swap-nested-ifs/))
- Hoist nested repeated code outside conditional statements ([`hoist-similar-statement-from-if`](https://docs.sourcery.ai/Reference/Default-Rules/refactorings/hoist-similar-statement-from-if/))
- Replace if statement with if expression ([`assign-if-exp`](https://docs.sourcery.ai/Reference/Default-Rules/refactorings/assign-if-exp/))

```suggestion
        args += " --free-threaded" if option else "t"
```
</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.

@radoering radoering force-pushed the python-management-free-threaded branch from 073abd1 to 4a48a8a Compare November 2, 2025 09:27
* bump required pbs-installer version so that free-threaded Python uses a different directory for installation (cf frostming/pbs-installer#11)
* do not use an upper bound for pbs-installer because it uses calver
* do not complain that a python version is already installed when trying to install a free-threaded python with the same version
* list free-threaded python versions with a trailing "t"
* allow to request a free-threaded version with a trailing "t" instead of the command option
* add support for removing free-threaded python versions
* fix removing Python versions with patch version "0"
@radoering radoering force-pushed the python-management-free-threaded branch from 4a48a8a to a79a19f Compare November 2, 2025 10:26
@radoering radoering added the impact/docs Contains or requires documentation changes label Nov 3, 2025
@github-actions
Copy link

github-actions bot commented Nov 3, 2025

Deploy preview for website ready!

✅ Preview
https://website-6d46tlqdy-python-poetry.vercel.app

Built with commit a79a19f.
This pull request is being automatically deployed with vercel-action

@radoering radoering merged commit d4fb687 into python-poetry:main Nov 15, 2025
66 checks passed
@radoering radoering mentioned this pull request Dec 7, 2025
@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 Dec 16, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

impact/docs Contains or requires documentation changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant