I'm running into an issue where I'm trying to run a Django application within a virtual environment but it kept showing me errors regarding missing packages that need installation although I did install them previously using pip install <package-name>
.
The issues couldn't be resolved until I used python -m pip install <package-name>
to install the missing packages.
My question is what is the difference between the two commands? Does one of the commands install packages to the virtual environment and the other one does that globally? I'm confused.
Side Note: Also when running pip freeze
shows different installed packages than those showing when I run python -m pip freeze
.
Update:
Running pip list -v
shows that the packages installed using pip install <package-name>
are located inside the virtual environment under lib/python3.8/site-packages
directory, while running python -m pip list -v
shows that the packages installed using python -m pip <package-name>
are located under /usr/lib/<python3 or python3.8>/<site-packages or dist-packages>
directory.
CodePudding user response:
There is no difference typically.
The python -m
flag allows you to run a specific module. For example you can run python -m http.server
to start a simple server in the current directory.
Python includes a "scripts" directory. Depending on your system setup, modules from the scripts
directory can be run directly from the shell without the python -m
prefix. For example, typically you run black
directly from the shell.
However, there are various reasons you might not want to trust running python modules directly from the shell, including:
- Running a specific python version. You can do
py -3.6 -m pip install something
to specify a python version - You don't want to add the scripts folder to your PATH for whatever reason. Maybe because some names conflict with other programs on your computer.
Inside a virtualenv both commands will typically do the same thing, since virtualenv
will properly set your PATH
CodePudding user response:
Welcome to the world of symlinks, binary discoverability with PATH
, and shebang #!/...
(*nix).
Before getting into the weaves of it all, let's talk about what pip
is:
pip
is both a python module (i.e python -m pip
(the -m
mean module)) and a binary $ pip
. pip
as a binary (the program) is optional, it's not required. pip
as the module (inside site-packages
where all the python modules are installed) is ABSOLUTELY required! Without it nothing will work, or worse yet you would use the pip
module from another python version you have installed and then you're really going to slam your head against the wall...
PATH variable
echo $PATH
(*nix) will show you something like this:
$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
That means that the system, through the terminal will look for the binaries first inside /usr/local/bin
then /usr/bin
then ... so on. If it found it in the first place it looked, great, it's done, no need to keep searching. You can have the same binary name in different directories, the order of PATH
is what matters, the second one will never be executed, EVER.
Why am I mentioning this? Well let's say you installed multiple versions of python
or pip
, and you installed it in the wrong place? Where the order is wrong? Well that binary will not run as expected.
Symlinks
You can have different versions of pip
and python
-- they're independent from one another, meaning just because you're using python
with version 3.8, does not mean your pip
is pointing to the same python binary.
A quick way to check is to do: (this applies to pip
)
$ ls -ls $(which python)
0 lrwxr-xr-x 1 root wheel 75 Jan 1 2020 /usr/bin/python -> ../../System/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7
You can see it's using the system version of python
and any other version I have are being ignored if I just run python
, I can "fix" this by specifying the version number such as python3.8
...
You can fix this one by first figuring out what binaries you have available to you:
$ echo $PATH | sed 's/:/ /g' | xargs -n1 -I{} find {} -name 'python*' | grep -v 'config$'
/usr/local/bin/python3
/usr/local/bin/python3.9
/usr/local/bin/python3.8
/usr/bin/python3
/usr/bin/python
/usr/bin/python2
/usr/bin/pythonw
/usr/bin/pythonw2.7
/usr/bin/python2.7
Say I want my default python
to be python3.8
, then do:
$ ln -s /usr/local/bin/python3.8 /usr/local/bin/python
$ hash -r
hash -r
tells the the terminal to forget all the banaries it found before, otheriwise your new symlink will not work
Q. Why not just override it?
The astute among you might ask, if the default python
is inside /usr/bin/python
why not just override it using?
$ ln -sf /usr/local/bin/python3.8 /usr/bin/python
/usr/bin/
is protected, and it's bad form to mess around with system prefernces. It's best not to touch it, /usr/local/bin
is yours (the user of the machine) to mess with.
Shebang #!/...
For the most part you will find the pip
binary file (thats just plain text by the way) to start like this:
#!/usr/bin/env python
or
#!/usr/local/bin/python3.9
This says, i'm a text file that needs to be ran with the following executable. In the first example, it's using the system to fin the binary python
the same way you would find it in the terminal, see PATH
variable above. The second example is a direct path to the binary for the system to use.
Remember pip
is a module, the binary pip
literaly says this: (this is slighly modified to make it as basic as possible and illustrate a point)
#!/usr/bin/env python
import sys
from pip._internal.cli.main import main
sys.exit(main())
- use the
python
binary - import the
sys
module to be used later... - import the
main
function from thepip
module - run
main
, what ever code it returns pass it tosys.exit(..)
usually will return0
but thats neighter here nor there.. just an FYI