The Wombelix Post - piphttps://dominik.wombacher.cc/2021-09-23T00:00:00+02:00pipx behave different than pip if package already exists2021-09-23T00:00:00+02:002021-09-23T00:00:00+02:00Dominik Wombachertag:dominik.wombacher.cc,2021-09-23:/posts/pipx-behave-different-than-pip-if-package-already-exists.html<!-- SPDX-FileCopyrightText: 2023 Dominik Wombacher <dominik@wombacher.cc> -->
<!-- -->
<!-- SPDX-License-Identifier: CC-BY-SA-4.0 -->
<p>I decided to put as much as possible of my local config into an Ansible Playbook.
Makes it easier to track what I install and change, also to setup from ... <a class="read-more" href="/posts/pipx-behave-different-than-pip-if-package-already-exists.html"> [read more]</a></p><!-- SPDX-FileCopyrightText: 2023 Dominik Wombacher <dominik@wombacher.cc> -->
<!-- -->
<!-- SPDX-License-Identifier: CC-BY-SA-4.0 -->
<p>I decided to put as much as possible of my local config into an Ansible Playbook.
Makes it easier to track what I install and change, also to setup from scratch should it necessary.</p>
<p>In the past I mainly used <cite>pip</cite> in combination with <cite>venv</cite> to install Python stuff.
Changing for most of it to <cite>pipx</cite> seems logical, it will take care about the necessary <em>venvs</em> on it's own.</p>
<p>Just had to learn that the return code of <cite>pip</cite> is <strong>0</strong> but from <cite>pipx</cite> it's <strong>1</strong> in case a package already exists.</p>
<p>Why does it matter? Not the most elegant solution but I decided to just use <cite>command</cite> to trigger <em>pip</em> / <em>pipx</em> from my Playbook:</p>
<pre class="code yaml literal-block">
<span class="pygments-p-Indicator">-</span><span class="pygments-w"> </span><span class="pygments-nt">name</span><span class="pygments-p">:</span><span class="pygments-w"> </span><span class="pygments-l-Scalar-Plain">Python Package Installation (pip)</span><span class="pygments-w">
</span><span class="pygments-nt">command</span><span class="pygments-p">:</span><span class="pygments-w"> </span><span class="pygments-s">"python3</span><span class="pygments-nv"> </span><span class="pygments-s">-m</span><span class="pygments-nv"> </span><span class="pygments-s">pip</span><span class="pygments-nv"> </span><span class="pygments-s">install</span><span class="pygments-nv"> </span><span class="pygments-s">--user</span><span class="pygments-nv"> </span><span class="pygments-s">{{</span><span class="pygments-nv"> </span><span class="pygments-s">item</span><span class="pygments-nv"> </span><span class="pygments-s">}}"</span><span class="pygments-w">
</span><span class="pygments-nt">changed_when</span><span class="pygments-p">:</span><span class="pygments-w"> </span><span class="pygments-l-Scalar-Plain">false</span><span class="pygments-w">
</span><span class="pygments-nt">loop</span><span class="pygments-p">:</span><span class="pygments-w">
</span><span class="pygments-p-Indicator">-</span><span class="pygments-w"> </span><span class="pygments-l-Scalar-Plain">pipx</span><span class="pygments-w">
</span><span class="pygments-p-Indicator">-</span><span class="pygments-w"> </span><span class="pygments-l-Scalar-Plain">nox</span><span class="pygments-w">
</span><span class="pygments-p-Indicator">-</span><span class="pygments-w"> </span><span class="pygments-nt">name</span><span class="pygments-p">:</span><span class="pygments-w"> </span><span class="pygments-l-Scalar-Plain">Python Package Installation (pipx)</span><span class="pygments-w">
</span><span class="pygments-nt">command</span><span class="pygments-p">:</span><span class="pygments-w"> </span><span class="pygments-s">"pipx</span><span class="pygments-nv"> </span><span class="pygments-s">install</span><span class="pygments-nv"> </span><span class="pygments-s">{{</span><span class="pygments-nv"> </span><span class="pygments-s">item</span><span class="pygments-nv"> </span><span class="pygments-s">}}"</span><span class="pygments-w">
</span><span class="pygments-nt">changed_when</span><span class="pygments-p">:</span><span class="pygments-w"> </span><span class="pygments-l-Scalar-Plain">false</span><span class="pygments-w">
</span><span class="pygments-nt">loop</span><span class="pygments-p">:</span><span class="pygments-w">
</span><span class="pygments-p-Indicator">-</span><span class="pygments-w"> </span><span class="pygments-l-Scalar-Plain">poetry</span><span class="pygments-w">
</span><span class="pygments-p-Indicator">-</span><span class="pygments-w"> </span><span class="pygments-l-Scalar-Plain">duplicity</span><span class="pygments-w">
</span><span class="pygments-p-Indicator">-</span><span class="pygments-w"> </span><span class="pygments-l-Scalar-Plain">pre-commit</span><span class="pygments-w">
</span>
</pre>
<p>No problem with <cite>pip</cite>, but <cite>pipx</cite> failed after the first run.</p>
<p>There was an older <a class="reference external" href="https://github.com/pypa/pipx/issues/125">GitHub Issue</a>, based on the comments,
<cite>pipx</cite> was supposed to behave smilar as <cite>pip</cite> and also use return code 0 since v0.13 already.
After some research I found the <a class="reference external" href="https://github.com/pypa/pipx/pull/560">Pull Request</a>
that reverted the earlier change during some re-factoring.</p>
<p>Thanks to the great improvements in that PR, it was just a very small change necessary to restore the
functionality introduced in <a class="reference external" href="https://github.com/pypa/pipx/commit/11b853e9c6926b32133b27822516b2a5b4f35411">Commit 11b853e</a>:</p>
<pre class="code diff literal-block">
<span class="pygments-gh">diff --git a/docs/changelog.md b/docs/changelog.md</span><span class="pygments-w">
</span><span class="pygments-gh">index 0a95ce15..67d14929 100644</span><span class="pygments-w">
</span><span class="pygments-gd">--- a/docs/changelog.md</span><span class="pygments-w">
</span><span class="pygments-gi">+++ b/docs/changelog.md</span><span class="pygments-w">
</span><span class="pygments-gu">@@ -1,6 +1,7 @@</span><span class="pygments-w">
</span>dev<span class="pygments-w">
</span>- Fixed `pipx list` output phrasing to convey that python version displayed is the one with which package was installed.<span class="pygments-w">
</span><span class="pygments-gi">+- Fixed `pipx install` to provide return code 0 if venv already exists, similar to pip’s behavior. (#736)</span><span class="pygments-w">
</span>0.16.4<span class="pygments-w">
</span><span class="pygments-gh">diff --git a/src/pipx/constants.py b/src/pipx/constants.py</span><span class="pygments-w">
</span><span class="pygments-gh">index 4fe2d58b..11fc013f 100644</span><span class="pygments-w">
</span><span class="pygments-gd">--- a/src/pipx/constants.py</span><span class="pygments-w">
</span><span class="pygments-gi">+++ b/src/pipx/constants.py</span><span class="pygments-w">
</span><span class="pygments-gu">@@ -21,7 +21,7 @@</span><span class="pygments-w">
</span># pipx shell exit codes<span class="pygments-w">
</span>EXIT_CODE_OK = ExitCode(0)<span class="pygments-w">
</span>EXIT_CODE_INJECT_ERROR = ExitCode(1)<span class="pygments-w">
</span><span class="pygments-gd">-EXIT_CODE_INSTALL_VENV_EXISTS = ExitCode(1)</span><span class="pygments-w">
</span><span class="pygments-gi">+EXIT_CODE_INSTALL_VENV_EXISTS = ExitCode(0)</span><span class="pygments-w">
</span>EXIT_CODE_LIST_PROBLEM = ExitCode(1)<span class="pygments-w">
</span>EXIT_CODE_UNINSTALL_VENV_NONEXISTENT = ExitCode(1)<span class="pygments-w">
</span>EXIT_CODE_UNINSTALL_ERROR = ExitCode(1)<span class="pygments-w">
</span><span class="pygments-gh">diff --git a/tests/test_install.py b/tests/test_install.py</span><span class="pygments-w">
</span><span class="pygments-gh">index 941f4c01..0eb2d9cc 100644</span><span class="pygments-w">
</span><span class="pygments-gd">--- a/tests/test_install.py</span><span class="pygments-w">
</span><span class="pygments-gi">+++ b/tests/test_install.py</span><span class="pygments-w">
</span><span class="pygments-gu">@@ -109,7 +109,7 @@ def test_install_no_packages_found(pipx_temp_env, capsys):</span><span class="pygments-w">
</span>def test_install_same_package_twice_no_force(pipx_temp_env, capsys):<span class="pygments-w">
</span> assert not run_pipx_cli(["install", "pycowsay"])<span class="pygments-w">
</span><span class="pygments-gd">- assert run_pipx_cli(["install", "pycowsay"])</span><span class="pygments-w">
</span><span class="pygments-gi">+ assert not run_pipx_cli(["install", "pycowsay"])</span><span class="pygments-w">
</span> captured = capsys.readouterr()<span class="pygments-w">
</span> assert (<span class="pygments-w">
</span> "'pycowsay' already seems to be installed. Not modifying existing installation"<span class="pygments-w">
</span>
</pre>
<p>Related Pull Request: <a class="reference external" href="https://github.com/pypa/pipx/pull/736">https://github.com/pypa/pipx/pull/736</a></p>
<p>Merged into <cite>pipx/main</cite> on 25th September 2021</p>
<p>That's a good example why I love and prefer Open Source, I could fix the Problem on my own and share the improvement with the community, within a few days it was already merged and will be part of the next Release.</p>