Skip to content

Comments

Fix _remove to catch EnvCommandError instead of CalledProcessError#10740

Merged
radoering merged 1 commit intopython-poetry:mainfrom
bysiber:fix/remove-catch-correct-exception
Feb 21, 2026
Merged

Fix _remove to catch EnvCommandError instead of CalledProcessError#10740
radoering merged 1 commit intopython-poetry:mainfrom
bysiber:fix/remove-catch-correct-exception

Conversation

@bysiber
Copy link
Contributor

@bysiber bysiber commented Feb 20, 2026

Problem

Executor._remove() catches CalledProcessError, but run_pip() never raises that — it wraps it inside EnvCommandError:

def run_pip(self, *args, **kwargs) -> int:
    try:
        self._env.run_pip(*args, **kwargs)
    except EnvCommandError as e:
        ...
        raise  # re-raises EnvCommandError, not CalledProcessError
    return 0

So the handler in _remove():

except CalledProcessError as e:
    if "not installed" in str(e):
        return 0

is dead code. When pip reports "not installed", the EnvCommandError propagates to _execute_operation, which treats it as a fatal error and sets self._shutdown = True, aborting the entire installation.

This can happen during poetry update if a package was already removed externally (e.g. pip uninstall by hand).

Fix

Catch EnvCommandError instead of CalledProcessError, and remove the now-unused import.

Summary by Sourcery

Bug Fixes:

  • Prevent poetry installations from aborting when attempting to uninstall packages that are already not installed by catching EnvCommandError instead of CalledProcessError in the removal logic.

run_pip() wraps CalledProcessError inside EnvCommandError, so the
except CalledProcessError handler in _remove() was dead code.  If
pip exited non-zero with 'not installed' in its output, the
EnvCommandError would propagate uncaught to _execute_operation,
which treats it as a fatal error and aborts the entire installation.

This matters when removing a package that was already uninstalled
externally — e.g. via pip directly — while Poetry is performing
an update.
@sourcery-ai
Copy link

sourcery-ai bot commented Feb 20, 2026

Reviewer's guide (collapsed on small PRs)

Reviewer's Guide

Adjusts the uninstall path in the installer executor to catch the correct exception type from pip invocations so that missing packages during removal are treated as non-fatal, and removes the now-unused import.

Sequence diagram for uninstall flow with EnvCommandError handling

sequenceDiagram
    actor User
    participant Executor
    participant Environment
    participant Pip

    User->>Executor: uninstall package
    Executor->>Executor: _remove(package)
    Executor->>Executor: run_pip("uninstall", package.name, "-y")
    Executor->>Environment: run_pip("uninstall", package.name, "-y")
    Environment->>Pip: pip uninstall package -y

    alt package_not_installed
        Pip-->>Environment: error "not installed"
        Environment-->>Executor: EnvCommandError("not installed")
        Executor-->>Executor: catch EnvCommandError in _remove
        Executor-->>User: return 0 (treat as success)
    else other_uninstall_error
        Pip-->>Environment: error
        Environment-->>Executor: EnvCommandError
        Executor-->>Executor: _remove does not handle, rethrow
        Executor->>Executor: _execute_operation handles EnvCommandError
        Executor-->>User: installation aborted, shutdown set True
    end
Loading

Updated class diagram for Executor uninstall error handling

classDiagram
    class Executor {
        bool _shutdown
        run_pip(args, kwargs) int
        _remove(package) int
        _execute_operation(operation) None
    }

    class EnvCommandError {
        str message
    }

    class Package {
        str name
    }

    Executor ..> EnvCommandError : raises
    Executor ..> Package : removes

    Executor : run_pip(args, kwargs) catches EnvCommandError
    Executor : _remove(package) calls run_pip
    Executor : _remove(package) catches EnvCommandError
    Executor : _execute_operation(operation) may set _shutdown on EnvCommandError
Loading

File-Level Changes

Change Details Files
Handle pip uninstall 'not installed' errors by catching EnvCommandError instead of CalledProcessError in the executor removal path.
  • Change the exception handler in the package removal helper to catch EnvCommandError raised by the pip wrapper.
  • Preserve the special-case handling where a 'not installed' message results in a no-op success return instead of a fatal error.
  • Remove the unused CalledProcessError import from the executor module.
src/poetry/installation/executor.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 - I've left some high level feedback:

  • Catching EnvCommandError and then checking for the substring "not installed" is somewhat brittle (e.g. locale-dependent); if possible, consider using a more structured signal from EnvCommandError (exit code, reason, or parsed stderr) rather than matching on the human-readable message.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Catching `EnvCommandError` and then checking for the substring `"not installed"` is somewhat brittle (e.g. locale-dependent); if possible, consider using a more structured signal from `EnvCommandError` (exit code, reason, or parsed stderr) rather than matching on the human-readable message.

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.

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.

Good catch.

This might still be dead code due to changes in pip - it seems to just print a warning if the package is not installed nowadays - but it cannot hurt to keep it for robustness.

@radoering radoering merged commit 6ae3c28 into python-poetry:main Feb 21, 2026
54 checks passed
@dosubot
Copy link

dosubot bot commented Feb 21, 2026

Related Documentation

Checked 0 published document(s) in 1 knowledge base(s). No updates required.

How did I do? Any feedback?  Join Discord

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.

2 participants