问题
I can determine where pip installs package binaries/scripts with pip3 install --user mypackage using:
$(python3 -m site --user-base)/bin
Is there a mechanism for determining where non-user binaries/scripts get installed (e.g. pip3 install mypackage) get installed?
Note that I'm only interested in where the binaries/scripts get installed and NOT where the library code gets installed.
Update:
The objective is to ensure that that the PATH environment variable contains the folder where the binaries/scripts get installed as this has caused some issues in the past for me.
Update 2:
$ python3 -c "import sysconfig; print(sysconfig.get_path('scripts'))"
/usr/local/Cellar/python@3.8/3.8.5/Frameworks/Python.framework/Versions/3.8/bin
$ python3 -c "from pip._internal.locations import bin_py; print(bin_py)"
/usr/local/Cellar/python@3.8/3.8.5/Frameworks/Python.framework/Versions/3.8/bin
However, pip3 installs into /usr/local/bin
Note that:
$ which pip3
/usr/local/bin/pip3
$ which python3
/usr/local/bin/python3
回答1:
This has already been answered here (but I can't "close as duplicate", since there is a bounty):
https://stackoverflow.com/a/62167797
I believe the canonical way (going forward) is to use sysconfig.get_path(...). Depending on what is needed exactly, it is possible to combine scheme and name. So maybe for your exact use case:
import sysconfig
scripts_path = sysconfig.get_path('scripts')
print(scripts_path)
As a one-liner from the shell:
python -c "import sysconfig; print(sysconfig.get_path('scripts'))"
Other things that might help identify the correct directory:
python -m site
python -m sysconfig
References:
- https://docs.python.org/3.8/library/sysconfig.html#installation-paths
- https://docs.python.org/3.8/library/sysconfig.html#using-sysconfig-as-a-script
- https://docs.python.org/3.8/library/site.html#command-line-interface
回答2:
pip's Source
pip's source code at _internal/locations.py shows how the system bin path is resolved:
https://github.com/pypa/pip/blob/3fe826c699d85eccc7ebf16f4d86c851b2a1e705/src/pip/_internal/locations.py#L63-L91
if WINDOWS:
bin_py = os.path.join(sys.prefix, 'Scripts')
bin_user = os.path.join(user_site, 'Scripts')
# buildout uses 'bin' on Windows too?
if not os.path.exists(bin_py):
bin_py = os.path.join(sys.prefix, 'bin')
bin_user = os.path.join(user_site, 'bin')
else:
bin_py = os.path.join(sys.prefix, 'bin')
bin_user = os.path.join(user_site, 'bin')
# Forcing to use /usr/local/bin for standard macOS framework installs
# Also log to ~/Library/Logs/ for use with the Console.app log viewer
if sys.platform[:6] == 'darwin' and sys.prefix[:16] == '/System/Library/':
bin_py = '/usr/local/bin'
Some additional documentation on sys.prefix is available here: https://docs.python.org/3/library/sys.html#sys.prefix
According to the Git History, this resolution behavior has not been touched since some time in 2017. Trying to trace the usage of this variable does not seem to indicate this variable is exposed using pip directly through a command.
A Solution
Since this does not appear to be exposed directly in the CLI, you could import the script to access the resolved bin location:
python -c "from pip._internal.locations import bin_py; print(bin_py)"
For example:
On Linux:
$ python -c "from pip._internal.locations import bin_py; print(bin_py)" /usr/local/binThis appears to match the location of where scripts are installed packages that have a script/bin. E.g.
- system-installed:
$ pip install uvicorn >/dev/null && which uvicorn /usr/local/bin/uvicorn- user-installed:
$ pip install --user uvicorn >/dev/null && find "$(python3 -m site --user-base)/bin" /root/.local/bin /root/.local/bin/uvicornOn Windows:
$ python -c "from pip._internal.locations import bin_py; print(bin_py)" C:\Users\[REDACTED]\AppData\Local\Programs\Python\Python38\Scripts
This method also works for finding the bin directory of a virtual environment.
来源:https://stackoverflow.com/questions/64183571/how-to-determine-where-pip3-installs-binaries-scripts-for-non-user-installs