Programmatically determine pip 'user install' location Scripts directory

Viewed 2083

As explained in pip's documentation a user can install packages in his personal account using pip install --user <pkg>.

How can I programmatically determine the user install location for scripts installed like this? I am talking about the directory that should be added to the PATH so that installed packages can be invoked from command line.

For example, in Windows when installing pip install -U pylint --user I get the following warning because I don't have 'C:\Users\myusername\AppData\Roaming\Python\Python37\Scripts' in my PATH:

...
Installing collected packages: wrapt, six, typed-ast, lazy-object-proxy, astroid, mccabe, isort, colorama, toml, pylint
  Running setup.py install for wrapt ... done
  WARNING: The script isort.exe is installed in 'C:\Users\myusername\AppData\Roaming\Python\Python37\Scripts' which is not on PATH.
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
  WARNING: The scripts epylint.exe, pylint.exe, pyreverse.exe and symilar.exe are installed in 'C:\Users\myusername\AppData\Roaming\Python\Python37\Scripts' which is not on PATH.

Is there some python code I can use to determine that location programmatically (that will work on Windows/Linux/Darwin/etc)? Something like:

def get_user_install_scripts_dir():
    ...
    # would return 'C:\Users\myusername\AppData\Roaming\Python\Python37\Scripts'
    # on Windows with Python 3.7.x, '/home/myusername/.local/bin' in Linux, etc
    return platform_scripts_dir

As a fallback, is there some command I can run to obtain this location? Something like (but for the script location not the site's base directory):

PS C:\Users\myusername\> python -m site --user-base
C:\Users\myusername\AppData\Roaming\Python

$ python -m site --user-base
/home/myusername/.local
2 Answers

I believe the following should give the expected result

import os
import sysconfig

user_scripts_path = sysconfig.get_path('scripts', f'{os.name}_user')
print(user_scripts_path)

Command-line:

python -c 'import os,sysconfig;print(sysconfig.get_path("scripts",f"{os.name}_user"))'

But it might be that pip uses a different logic internally (probably based on distutils), but the results should still be the same.

Update: Since pip 21.3 released on 2021-10-11, pip moved to using sysconfig to compute paths.

References

Command-line:

python -c "import os, site; print(os.path.join(site.USER_BASE, 'Scripts' if os.name == 'nt' else 'bin'))"

Function:

import os, site

if os.name == 'nt':
    bin_dir = 'Scripts'
else:
    bin_dir = 'bin'

def get_user_install_bin_dir():
    return os.path.join(site.USER_BASE, bin_dir)
Related