Repository: ansible-collections/community.general

Issue:
pipx module should expose control of install directories
### Summary

pipx honours some environment variables which control where it's environment is created, and where the stub commands are installed. These settings are essential to allow site-wide installation.

https://pypa.github.io/pipx/installation/#installation-options



### Issue Type

Feature Idea

### Component Name

pipx

### Additional Information

```
PIPX_HOME=/opt/pipx PIPX_BIN_DIR=/usr/local/bin pipx install PACKAGE
```

### Code of Conduct

- [X] I agree to follow the Ansible Code of Conduct


Discussion:
Files identified in the description:
* [`plugins/modules/pipx.py`](https://github.com/ansible-collections/community.general/blob/main/plugins/modules/pipx.py)

If these files are incorrect, please update the `component name` section of the description or use the `!component` bot command.

[click here for bot help](https://github.com/ansible/ansibullbot/blob/devel/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->
cc @russoz
[click here for bot help](https://github.com/ansible/ansibullbot/blob/devel/ISSUE_HELP.md)
<!--- boilerplate: notify --->
Hi @gdevenyi, thanks for reporting this issue.

When I first saw it I thought we might be able to solve the problem by using `environment`, an Ansible keyword available to any module. I wrote PR #5845 adding a test for that and it seems that it indeed works.

Please let me know whether this solution does not work for you.

Cheers,
AZ

Resolving patch:
diff --git a/plugins/modules/pipx.py b/plugins/modules/pipx.py
--- a/plugins/modules/pipx.py
+++ b/plugins/modules/pipx.py
@@ -95,6 +95,9 @@
 notes:
     - This module does not install the C(pipx) python package, however that can be easily done with the module M(ansible.builtin.pip).
     - This module does not require C(pipx) to be in the shell C(PATH), but it must be loadable by Python as a module.
+    - >
+      This module will honor C(pipx) environment variables such as but not limited to C(PIPX_HOME) and C(PIPX_BIN_DIR)
+      passed using the R(environment Ansible keyword, playbooks_environment).
     - Please note that C(pipx) requires Python 3.6 or above.
     - >
       This first implementation does not verify whether a specified version constraint has been installed or not.
diff --git a/plugins/modules/pipx_info.py b/plugins/modules/pipx_info.py
--- a/plugins/modules/pipx_info.py
+++ b/plugins/modules/pipx_info.py
@@ -50,6 +50,9 @@
 notes:
     - This module does not install the C(pipx) python package, however that can be easily done with the module M(ansible.builtin.pip).
     - This module does not require C(pipx) to be in the shell C(PATH), but it must be loadable by Python as a module.
+    - >
+      This module will honor C(pipx) environment variables such as but not limited to C(PIPX_HOME) and C(PIPX_BIN_DIR)
+      passed using the R(environment Ansible keyword, playbooks_environment).
     - Please note that C(pipx) requires Python 3.6 or above.
     - See also the C(pipx) documentation at U(https://pypa.github.io/pipx/).
 author:


Test patch:
diff --git a/tests/integration/targets/pipx/tasks/main.yml b/tests/integration/targets/pipx/tasks/main.yml
--- a/tests/integration/targets/pipx/tasks/main.yml
+++ b/tests/integration/targets/pipx/tasks/main.yml
@@ -230,3 +230,30 @@
         that:
           - install_jupyter is changed
           - '"ipython" in install_jupyter.stdout'
+
+##############################################################################
+- name: ensure /opt/pipx
+  ansible.builtin.file:
+    path: /opt/pipx
+    state: directory
+    mode: 0755
+
+- name: install tox site-wide
+  community.general.pipx:
+    name: tox
+    state: latest
+  register: install_tox_sitewide
+  environment:
+    PIPX_HOME: /opt/pipx
+    PIPX_BIN_DIR: /usr/local/bin
+
+- name: stat /usr/local/bin/tox
+  ansible.builtin.stat:
+    path: /usr/local/bin/tox
+  register: usrlocaltox
+
+- name: check assertions
+  ansible.builtin.assert:
+    that:
+      - install_tox_sitewide is changed
+      - usrlocaltox.stat.exists