File: how-pipx-works.md

package info (click to toggle)
python-pipx 1.8.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,776 kB
  • sloc: python: 9,653; makefile: 17; sh: 7
file content (133 lines) | stat: -rw-r--r-- 5,176 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
## How it Works

When installing a package and its binaries on linux (`pipx install package`) pipx will

- create directory `~/.local/share/pipx/venvs/PACKAGE`
- create or reuse a shared virtual environment that contains shared packaging library `pip` in
  `~/.local/share/pipx/shared/`
- ensure the library is updated to its latest version
- create a Virtual Environment in `~/.local/share/pipx/venvs/PACKAGE` that uses the shared pip mentioned above but
  otherwise is isolated (pipx uses a [.pth file](https://docs.python.org/3/library/site.html) to do this)
- install the desired package in the Virtual Environment
- expose binaries at `~/.local/bin` that point to new binaries in `~/.local/share/pipx/venvs/PACKAGE/bin` (such as
  `~/.local/bin/black` -> `~/.local/share/pipx/venvs/black/bin/black`)
- expose manual pages at `~/.local/share/man/man[1-9]` that point to new manual pages in
  `~/.local/pipx/venvs/PACKAGE/share/man/man[1-9]`
- as long as `~/.local/bin/` is on your PATH, you can now invoke the new binaries globally
- on operating systems which have the `man` command, as long as `~/.local/share/man` is a recognized search path of man,
  you can now view the new manual pages globally
- adding `--global` flag to any `pipx` command will execute the action in global scope which will expose app to all
  users - [reference](installation.md#global-installation). Note that this is not available on Windows.

When running a binary (`pipx run BINARY`), pipx will

- create or reuse a shared virtual environment that contains the shared packaging library `pip`
- ensure the library is updated to its latest version
- create a temporary directory (or reuse a cached virtual environment for this package) with a name based on a hash of
  the attributes that make the run reproducible. This includes things like the package name, spec, python version, and
  pip arguments.
- create a Virtual Environment inside it with `python -m venv`
- install the desired package in the Virtual Environment
- invoke the binary

These are all things you can do yourself, but pipx automates them for you. If you are curious as to what pipx is doing
behind the scenes, you can always pass the `--verbose` flag to see every single command and argument being run.

## Developing for pipx

If you are a developer and want to be able to run

```
pipx install MY_PACKAGE
```

make sure you include `scripts` and, optionally for Windows GUI applications `gui-scripts`, sections under your main table[^1] in `pyproject.toml` or their legacy equivalents for `setup.cfg` and `setup.py`.

[^1]: This is often the `[project]` table, but might also be differently named. Read more in the [PyPUG](https://packaging.python.org/en/latest/guides/writing-pyproject-toml/#writing-your-pyproject-toml).

=== "pyproject.toml"

    ```ini
    [project.scripts]
    foo = "my_package.some_module:main_func"
    bar = "other_module:some_func"

    [project.gui-scripts]
    baz = "my_package_gui:start_func"
    ```

=== "setup.cfg"

    ```ini
    [options.entry_points]
    console_scripts =
        foo = my_package.some_module:main_func
        bar = other_module:some_func
    gui_scripts =
        baz = my_package_gui:start_func
    ```

=== "setup.py"

    ```python
    setup(
        # other arguments here...
        entry_points={
            'console_scripts': [
                'foo = my_package.some_module:main_func',
                'bar = other_module:some_func',
            ],
            'gui_scripts': [
                'baz = my_package_gui:start_func',
            ]
        },
    )
    ```

In this case `foo` and `bar` (and `baz` on Windows) would be available as "applications" to pipx after installing the above example package, invoking their corresponding entry point functions.

### Manual pages

If you wish to provide documentation via `man` pages on UNIX-like systems then these can be added as data files:

=== "setuptools"

    ```toml title="pyproject.toml"
    [tool.setuptools.data-files]
    "share/man/man1" = [
      "manpage.1",
    ]
    ```

    ```ini title="setup.cfg"
    [options.data_files]
    share/man/man1 =
        manpage.1
    ```

    ```python title="setup.py"
    setup(
        # other arguments here...
        data_files=[('share/man/man1', ['manpage.1'])]
    )
    ```

WARNING: The `data-files` keyword is "discouraged" in the [setuptools documentation](https://setuptools.pypa.io/en/latest/userguide/pyproject_config.html#setuptools-specific-configuration) but there is no alternative if `man` pages are a requirement.

=== "pdm-backend"

    ```toml title="pyproject.toml"
    [tool.pdm.build]
    source-includes = ["share"]

    [tool.pdm.build.wheel-data]
    data = [
        {path = "share/man/man1/*", relative-to = "."},
    ]
    ```

In this case the manual page `manpage.1` could be accessed by the user after installing the above example package.

For a real-world example, see [pycowsay](https://github.com/cs01/pycowsay/blob/master/setup.py)'s `setup.py` source code.

You can read more about entry points [here](https://setuptools.pypa.io/en/latest/userguide/quickstart.html#entry-points-and-automatic-script-creation).