pipx icon indicating copy to clipboard operation
pipx copied to clipboard

Handling manpages

Open CharString opened this issue 3 years ago • 6 comments

How would this feature be useful? Some packages, like ipython and ranger-fm come with man pages. It would be nice to provide these, such that man ipython will work.

Describe the solution you'd like

Much like we ask users to ensure ~/.local/bin is on their PATH and we manage symlinks there. We could manage symlinks to man pages in a location and ask them to add a MANDATORY_MANPATH or MANPATH_MAP line to their .manpath file.

Describe alternatives you've considered

I tried globbing ~/.local/pipx/venvs/*/share/man in my man config. But didn't succeed. Adding a line for each installed package does work as expected, so that's why I think automating the process would be ideal.

I'm willing and able to implement this. I just wanted to open discussion first instead of immediately coming with an elaborate PR.

CharString avatar Jun 23 '22 10:06 CharString

The lack of accessible man pages was my first stumble when trying pipx for the first time just now. In my case I'm testing with the glances package. And, yes, I just listened to the TPTM podcast. :smile:

Well, it's a long walk for a short command but I did this:

❯ source .local/pipx/venvs/glances/bin/activate.fish
❯ man glances
❯ deactivate

In addition to finding and symlinking man pages and other types of files, perhaps the above dance could be wrapped into a general purpose exec subcommand to pipx. Eg to enable something like this hypothetical command:

pipx exec glances man glances

brettviren avatar Jul 16 '22 11:07 brettviren

Unfortunately there is not a standard way to find man pages from Python packages (or any non-system package manager, as far as I am aware). This would require a standard, and a big push to make packages adhere to it.

uranusjr avatar Jul 17 '22 20:07 uranusjr

That sounds like a great standard to have.

Quote from related issue https://github.com/pypa/packaging-problems/issues/72

This is hard is because pip does not focus on trying to be able to correctly handle installing packages on a system level.

Given that pipx does focus on this, perhaps this is the right project to be building up a grassroots standard? Two options immediately spring to mind:

  1. Grab any shipped data file with the correct extension and path (/share/man?)
  2. Add a custom pipx section to the package metadata

I'm sure both of these have significant downsides that will be obvious to people who know packaging better than me (e.g. 1 seems like it might have false positives, 2 relies on the metadata file being extensible which I can't see any indication about either way from the PEP)

alicederyn avatar Jul 18 '22 08:07 alicederyn

Option 1 is probably the easiest path for now since there’s no suitable metadata for specifying file location now (entry point is close but it’s designed for Python files and I’m not sure if people would think it’s a good idea for us to use it like this). If enough projects catch on, we’d have more ground to push for a metadata standard.

So the next steps for anyone interested in implementing this would be:

  1. Add documentation that pipx would look for man page files inside ${DATA_DIRECTORY}/data/share/man/.
  2. Implement logic for the above; more specifically, the installation process would install those as wheel data files into the environment, and pipx should pick those up and symlink/copy them into (say) ${PIPX_HOME}/share/man, like we do for entry points (inside ${PIPX_HOME}/bin).
  3. Tell projects they can put man page files there for pipx to pick up. Listen to feedback and improve things, eventually producing an Informational PEP to make this into a standard.

uranusjr avatar Jul 18 '22 08:07 uranusjr

The symlinking into ~/.local/bin/ that pipx does now is a narrow implementation of the more general "view" or "union" pattern implemented in stow, conda, spack, nix, etc.

Adding the full "view" pattern to pipx would mean doing a mkdir in the "view directory" (eg ~/.local/) for every subdir in every package that pipx installs and doing a ln -s (or optionally ln or cp) for every file.

The view still requires the user to add to their environment variables. This is something they can do right now but the user faces an O(Npackages * Ntypes) problem. A "view" makes it an O(Npackages + Ntypes) problem of which only O(Ntypes) is exposed to the user.

A view also happens to play nice with direnv via its load_prefix command.

Such a view/union directory tree is easy to populate. The only decision the code need to make is what to do with collisions. In practice, "first one wins" is usually sufficient.

Things get more tricky when these features are considered in scope:

  • pruning a view of a package
  • pruning of dependencies and/or dependents
  • synchronizing a pipx uninstall with pruning
  • tracking location of target directories

Anyways, I hope at least this is some food for thought.

brettviren avatar Jul 18 '22 13:07 brettviren

The following script seems to work for me. I called it pipx-manpage-install.

You need to have stow installed. For man to find the manpages, ~/.local/share/man needs to be in the output of the manpath command. It is there on my debian system by default, though I'm not sure how it got there.

The --ignore pattern comes from https://unix.stackexchange.com/a/293676/261949.

#!/bin/bash
# Create links from `~/.local/share` to the files in `share` subdirectories
# of virtual environments installed with `pipx`.

# Run with `-n` option for a dry run, with `-D` to undo.
# You may have to resolve conflicts manually.
# Assumes there are only directories in the venv dir.

cd $(pipx environment -v PIPX_LOCAL_VENVS)
stow --ignore='^((?!share).)*$' --target=$(realpath ~/.local) -v $@ *

ilyagr avatar Aug 20 '22 04:08 ilyagr

A random new pipx user passing by.

After reading some stackoverflow and man pages, I'm using this in my zshrc for now:

# For example
export PATH="$HOME/.local/bin:$PATH"

# This need to be after PATH setting because manpath references PATH
if [ -d "$HOME/.local/pipx/venvs" ]; then
    export MANPATH="$(find $HOME/.local/pipx/venvs -type d -name man | tr '\n' ':')$(manpath)"
fi

A stackoverflow answer suggested to NOT modify MANPATH, but currently I don't have better solution, besides ~/.manpath doesn't seem to work on macOS.

Hope this helps another random pipx user.

pi314 avatar Apr 09 '23 14:04 pi314

I think that configuration could be added by pipx when installed? Since the PATH is already modified?

chrysle avatar Apr 11 '23 09:04 chrysle

I think what is needed is a proposal for what exactly one needs to do in a pipx-installable module to package and identify a set of man pages, in a manner that won't cause problems if that module is installed by another pip-based system. For instance, putting them into a single "directory" like share.man might cause conflicts if multiple such modules were installed in a venv (my expertise level here is low), and would potentially cause other man pages from dependencies to be installed by pipx by mistake since pipx doesn't have any module metadata to use (as it does for entrypoints) to determine which man pages were part of the installed module and which were transitive.

alicederyn avatar Apr 11 '23 12:04 alicederyn

On linux, at least, the path that man searches is generated automatically, unless it is explicitly set. Many people don't have the MANPATH variable at all. I have no MANPATH, but the man command on my Arch system finds an entry for $HOME/.local/share/man . I created that directory manually to access the ipython manpage (which is symlinked there). However, I didn't have to do anything regarding manpath. It was picked up automatically. The program that generates the MANPATH is simply called manpath. See manpath(5) in the "SEARCH PATH" section to see how it finds entries to add (it doesn't search everywhere).

If pipx could link manpages into /home/user_name/.local/share/man/ just like it links executables, that would work for a lot of people.

syntaxman avatar May 15 '23 11:05 syntaxman

I think that this is a important issue, considering that at least some Linux distributions such as Debian 12 and derivatives stopped supporting installation of packages with pip into user's home directory. With pip, it was possible to install manual pages to ~/.local/share/man/man[1-9], and they were immediatly available through man <page>, as @syntaxman mentions above. I also think that creating symlinks to manual pages in ~/.local/share/man/man[1-9] would be very helpful, in the same way that pipx already creates symlinks in ~/.local/bin for executable files.

peterkuma avatar Aug 21 '23 13:08 peterkuma

@peterkuma Could you link a Python project that works this way when installed with pip?

alicederyn avatar Aug 21 '23 16:08 alicederyn

@alicederyn For example sympy and yt-dlp.

peterkuma avatar Aug 21 '23 16:08 peterkuma

sympy uses the following in setup.py:

data_files=[('share/man/man1', ['doc/man/isympy.1'])]

This puts the following in the wheel:

  • a file called sympy-1.12.data/data/share/man/man1/isympy1
  • an entry for ../../../share/man/man1/isympy.1 in the dist-info/RECORD

We could use the RECORD to determine what share files were intentionally included with the installed package, and which were picked up accidentally from dependencies. Unlike trying to create a new standard, this has the advantage of working with existing workflows.

@peterkuma As a workaround, you can always append ":$HOME/.local/pipx/venvs/sympy/share/man" (or equivalent for other packages) to your MANPATH.

alicederyn avatar Aug 22 '23 19:08 alicederyn

Just so people are aware, a pull request is always welcomed and would be infinitely more helpful than repeating the request.

uranusjr avatar Aug 23 '23 02:08 uranusjr

@uranusjr @alicederyn ok I have started working on a patch. I have decided to implement a behavior very similar to the existing bin "app" symlinks. It is slightly complicated because the related code is located across many different places.

peterkuma avatar Aug 24 '23 11:08 peterkuma

BTW, pipx can generate an own manpage since #744.

Maybe you could add some logic to the script to install it to the local manpath as well?

chrysle avatar Aug 24 '23 16:08 chrysle

@chrysle I think it would be better to leave this as a next step. From my (narrow) understanding of the code there isn't too much overlap between this issue and your feature request.

peterkuma avatar Aug 24 '23 19:08 peterkuma

I have created a draft pull request (#1047) for this feature. The changes were relatively extensive, and it would be great if someone wants to provide any feedback. There are still things to be done such as testing on Windows and macOS, more comprehensive testing and updating of test cases.

peterkuma avatar Aug 24 '23 20:08 peterkuma

https://github.com/pypa/pipx/pull/1047 is live now.

gaborbernat avatar Dec 02 '23 17:12 gaborbernat