Python adding lots of things to PATH. How do I stop? - python

I'm finding that python is modifying my path in problematic ways -- in particular, it's pre-pending the path to my github development folder, which results in the wrong libraries being loaded.
In my terminal session, if I run echo $PATH I get:
~$echo $PATH
/Users/Nick/anaconda/bin:/usr/local/bin:/usr/bin:
/bin:/usr/sbin:/sbin:/opt/X11/bin:/usr/local/git/bin:/usr/texbin
Which is perfect. But when I launch python from that same terminal session (either as python or ipython) and check my PATH from within python, I'm getting:
>>> print(sys.path)
['', '/Users/Nick/anaconda/lib/python3.4/site-packages/Cython-0.22.1-py3.4-
macosx-10.5-x86_64.egg', '/Users/Nick/github/pandas',
'/Users/Nick/anaconda/lib/python34.zip', '/Users/Nick/anaconda/lib/python3.4',
'/Users/Nick/anaconda/lib/python3.4/plat-darwin',
'/Users/Nick/anaconda/lib/python3.4/lib-dynload',
'/Users/Nick/anaconda/lib/python3.4/site-packages',
'/Users/Nick/anaconda/lib/python3.4/site-packages/Sphinx-1.3.1-py3.4.egg',
'/Users/Nick/anaconda/lib/python3.4/site-packages/aeosa',
'/Users/Nick/anaconda/lib/python3.4/site-packages/setuptools-18.0.1-py3.4.egg']
Where are these coming from and how do I stop them?
Thanks!

PATH has nothing to do with the Python module search path; that environment variable is used by your shell to find executables, instead.
You need to look at the PYTHONPATH variable here.
If that variable doesn't contain your extra elements, start Python with the -S command line switch to disable loading site.py; it may be that the extra elements are set by a .pth file. Also see the site module documentation:
A path configuration file is a file whose name has the form name.pth and exists in one of the four directories mentioned above; its contents are additional items (one per line) to be added to sys.path.

While $PATH seems like it may be used by Python, what you actually want to look at is your $PYTHONPATH -- which is used by the import machinery and logic.
You should look into using virtualenvironments to control the pathing of Python module lookups.

Related

Prevent a Python-embedded to look in my default path C:\Python38 for modules

I'm using Cython in --embed mode to produce a .exe. I'm evaluating the Minimal set of files required to distribute an embed-Cython-compiled code and make it work on any machine. To do this, I only copy a minimal number of files from the Python Windows embeddable package.
In order to check this, I need to be sure that the current process I'm testing doesn't in fact use my system default Python install, i.e. C:\Python38.
To do this, I open a new cmd.exe and do set PATH= which temporarily removes everything from the PATH. Then I can test any self-compiled app.exe and make sure it doesn't reuse C:\Python38's files under the hood.
It works, except for the modules. Even after doing set PATH=, my code app.py
import json
print(json.dumps({"a":"b"}))
when Cython---embed-compiled into a .exe works, but it still uses C:\Python38\Lib\json\__init__.py! I know this for sure, because if I temporarily remove this file, my .exe now fails, because it cannot find the json module.
How to completely remove any link to C:\Python38 when debugging a Python program which shouldn't use these files?
Why isn't set PATH= enough? Which other environment variable does it use for modules? I checked all my system variables and I think I don't find any which seems related to Python.
Python has a quite complicated heuristic for finding its "installation" (see for example this SO-question or this description), so probably it doesn't find the installation you are providing but the "default" installation.
Probably the most simple way is to set the environment variable PYTHONPATH pointing to the desired installation prior to start of the embedded interpreter.
By examination of sys.path one can check whether the correct installation was found.
Thanks to #ead's answer and his link getpath.c finally redirecting to getpathp.c in the case of Windows, we can learn that the rule for building the path for module etc. is:
current directory first
PYTHONPATH env. variable
registry key HKEY_LOCAL_MACHINE\SOFTWARE\Python or the same in HKCU
PYTHONHOME env. variable
finally:
Iff - we can not locate the Python Home, have not had a PYTHONPATH
specified, and can't locate any Registry entries (ie, we have nothing
we can assume is a good path), a default path with relative entries is
used (eg. .\Lib;.\DLLs, etc)
Conclusion: in order to debug an embedded version of Python, without interfering with the default system install (C:\Python38 in my case), I finally solved it by temporarily renaming the registry key HKEY_LOCAL_MACHINE\SOFTWARE\Python to HKEY_LOCAL_MACHINE\SOFTWARE\PythonOld.
Side note: I'm not sure I will ever revert this registry key back to normal: my normal Python install shouldn't need it anyway to find its path, since when I run python.exe from anywhere (it is in the PATH for everyday use), it will automatically look in .\Lib\ and .\DLL\ which is correct. I don't see a single use case in which my normal install python.exe wouldn't find its subdir .\Lib\ or .\DLL\ and requiring the registry for this. In which use case would the registry be necessary? if python.exe is started then its path has been found, and it can take its .\Lib subfolder, without help from registry. I think 99,99% of the time this registry feature is doing more harm than good, preventing a Python install to be really "portable" (i.e. that we can move from one folder to another).
Notes:
To be 100% sure, I also did this in command line, but I don't think it's necessary:
set PATH=
set PYTHONPATH=
set PYTHONHOME=
Might be helpful to do debugging of an embedded Python: import ctypes. If you haven't _ctypes.pyd and libffi-7.dll in your embedded install folder, it should fail. If it doesn't, this means it looks somewhere else (probably in your default system-wide Python install).

How to access my custom python scripts from CLI in order for them to act on any file?

I am having difficulty accessing my custom scripts from the command line (python3 unzipit.py "C:\Users\Me\downloads\zipfilehome"). I want to have my scripts act on any file, no matter where they are. I don't want to have the script file in the same directory in order for it to work. I followed this question's top answer to no avail. Note: I am using Windows 10 and all my python versions are in the path with no issues accessing them.
What I did (I always refresh my CLI with every change)
In the system environmental variables:
Path: (unchanged since installation) C:\Path2Python27;C:\Path2Python27\scripts;C:\Path2Python37;C:\Path2Python37\scripts;
PYTHONPATH: C:\Path2Python37;C:\Path2Python37\scripts;C:\Users\Me\myscripts\py
Things I also tried
system environmental variables
Path: C:\Path2Python27;C:\Path2Python27\scripts;C:\Path2Python37;C:\Path2Python37\scripts;C:\Users\Me\myscripts\py
moving the same stuff to user env's Path
moving the above-shown system PYTHONPATH to the user env
What else am I missing? I don't understand.
All in all, what I needed to get this working:
system environmental variables
Path: C:\Path2Python27;C:\Path2Python27\scripts;C:\Path2Python37;C:\Path2Python37\scripts;
PYTHONPATH: C:\Users\Me\myscripts\py
and
making sure to use Andriy's comment. It won't work using python3 unzipit.py "C:\link\to\folder".
In order to achieve what you want you have to specify -m flag and the module name, so python will retrieve module by looking up python module path. See more here in interface-options. The command shall be:
python3 -m unzipit "C:\Users\Me\downloads\zipfilehome"

Is there a way to always execute a script when python starts? (similar site.profile in R)

In the R programming language, there is a site.profile file that defines some code that R processes execute on start up. Is there similar functionality in Python?
Edit: to clarify, this script should be executed if the user calls python from the command line, but also if python is spawned from another process (e.g. if the user's script uses subprocess to spawn another python).
If you only want this for interactive sessions (as opposed to also happening every time you run a script with python myscript.py or ./myscript or a module with python -m mymodule), what you want is the environment variable PYTHONSTARTUP:
If this is the name of a readable file, the Python commands in that file are executed before the first prompt is displayed in interactive mode. The file is executed in the same namespace where interactive commands are executed so that objects defined or imported in it can be used without qualification in the interactive session…
If you want this to always happen forever, of course, you need to set this environment variable in some appropriate global place—e.g., your shell profile on most *nix platforms, or both your shell profile and your launchd profile on macOS, or the appropriate part of the Control Panel on Windows (the appropriate part changes with almost every new version of Windows, but it usually has "System" in the name).
If you want this to happen for all users, not just the current user… the details for how to set a system-wide environment variable are more platform-specific, but otherwise the idea is the same.
If you want this to happen for every Python session, even when some other program is running a Python script and you didn't even know it was doing that… what you want is either usercustomize or sitecustomize, as documented in the site documentation:
This module is automatically imported during initialization. The automatic import can be suppressed using the interpreter’s -S option.
…
After these path manipulations, an attempt is made to import a module named sitecustomize, which can perform arbitrary site-specific customizations. It is typically created by a system administrator in the site-packages directory.
After this, an attempt is made to import a module named usercustomize, which can perform arbitrary user-specific customizations, if ENABLE_USER_SITE is true. This file is intended to be created in the user site-packages directory (see below), which is part of sys.path unless disabled by -s…
So, you want to find an appropriate place to override this. First try this:
python3 -m site
Then, if this didn't give you sys.path (probably only on pretty old Python, but just in case…), also do this:
python3 -c 'import sys; print('\n'.join(sys.path))'
If you want this customization to happen only for the current user, you want to create a usercustomize.py file in the USER_SITE directory listed by python3 -m site. If the directory doesn't exist, create it.
If you want it to happen for all users, you want a sitecustomize.py file in one of the sys.path directories. The problem is that there may already be one. For example, most linux distros' builtin Python packages have their own sitecustomize modules. If there is, python3 -c 'import sitecustomize; print(sitecustomize.__file__) will tell you where it is. Then, you can edit, or you can copy it, edit that copy, and place that copy somewhere that comes earlier in sys.path than the original. As a general rule, /usr/local is probably better than /usr, and site-packages is probably better than dist-packages is probably better than anything else.
The Python mechanism is called... site. It is a module that is automatically imported and sets up your environment. If it finds modules sitecustomize.py and usercustomize.py, it will import them as well. So these two are where you would put site-wide and personal customizations that you want to be a permanent part of your Python environment. See the site documentation for more details.
File pointed by your environmental variable PYTHONSTARTUP would be run on starting an interactive python session
And USER_SITE/usercustomize.py will be run for non-interactive python session.
Run python -c "import site; print(site.USER_SITE)" to find the USER_SITE dir location

What is the best way to organize my local python scripts?

I have a bunch of useful scripts that I want to import from time to time. How to best organize them? I would want them to be on my /home/ folder -- is that possible? Is that the best way?
On a related note, when my other scripts import my local scripts, is there a best practice to make them portable? Should I include notes in my script to alert readers / myself that I'm importing from self-written script?
Thank you!
In your .bashrc you can specify the $PYTHONSTARTUP and $PYTHONPATH parameters. I have the following in my own .bashrc:
export PYTHONSTARTUP=$HOME/.config/python/pythonrc.py
export PYTHONPATH=$PYTHONPATH:$HOME/.config/python/path
Note that The .bashrc file is for bash specifically. Other shells may have other files loaded at startup.
The $PYTHONSTARTUP script is run every time you start a python console. This is useful if you want to add tab completion for example. For example in the case I specified, whenever you run python from the terminal, the script .config/python/pythonrc.py is executed before the console starts.
You can put python packages which should be importable anywhere in the $PYTHONPATH you specified. So basically $PYTHONPATH for python has some similarities to $PATH for bash. Note this is not $PATH. I do not recommend messing with the $PYTHONPATH though. I think it is better to append the paths to sys.path in the $PYTHONSTARTUP script.
And then there is the usercustomize module. If there is a module named usercustomize anywhere in the path, it will be imported by all python processes. For usercustomize to work you do need to make sure that this is in your $PYTHONPATH. For usercustomize you do need to set it in $PYTHONPATH, but you could append more paths in usercustomize.py just like in $PYTHONSTARTUP, so you only need to add 1 more directory to the $PYTHONPATH.
How to add a folder to your path for Mac
You may want to organize your custom scripts into a folder that is not mixed in with the Anaconda modules
1) Find your bash profile. In Terminal on the command line type (without the $ sign, which is the prompt)
$ cd
$ ls -a
This means "change directory to my home folder, list all files including hidden files". You should see a file called .bash_profile listed there
2) Edit your bash profile.Into the command line type
$ open .bash_profile
This should open in TextEdit. Add two lines to the text file:
# Added by My Name on My Date
export PYTHONPATH="/Users/myusername/path/to/folder:$PYTHONPATH"
3) Check that this worked. Open a python session:
>>> import sys
>>> sys.path
The new folder should now be listed in your path

Add a directory to Python sys.path so that it's included each time I use Python

Currently, when trying to reference some library code, I'm doing this at the top of my python file:
import sys
sys.path.append('''C:\code\my-library''')
from my-library import my-library
Then, my-library will be part of sys.path for as long as the session is active. If I start a new file, I have to remember to include sys.path.append again.
I feel like there must be a much better way of doing this. How can I make my-library available to every python script on my windows machine without having to use sys.path.append each time?
Simply add this path to your PYTHONPATH environment variable. To do this, go to Control Panel / System / Advanced / Environment variable, and in the "User variables" sections, check if you already have PYTHONPATH. If yes, select it and click "Edit", if not, click "New" to add it.
Paths in PYTHONPATH should be separated with ";".
You should use
os.path.join
to make your code more reliable.
You have already used __my-library__ in the path. So don't use it the second time in import.
If you have a directory structure like this
C:\code\my-library\lib.py and a function in there, e.g.:
def main():
print("Hello, world")
then your resulting code should be
import sys
sys.path.append(os.path.join('C:/', 'code', 'my-library'))
from lib import main
If this is a library that you use throughout your code, you should install it as such. Package it up properly, and either install it in your site-packages directory - or, if it's specific to certain projects, use virtualenv and install it just within the relevant virtualenvs.
To do such a thing, you'll have to use a sitecustomize.py (or usercustomize.py) file where you'll do your sys.path modifications (source python docs).
Create the sitecustomize.py file into the \Lib\site-packages directory of your python installation, and it will be imported each time a python interpreter is launched.
If you are doing this interactively, the best thing to do would be to install ipython and configure your startup settings to include that code. If you intend to have it be part of a script you run from the interpreter, the same thing applies, since it will have access to your namespace.
On the other hand, a stand alone script should not include that automatically. In the future, you or some other maintainer will come along, and all the code should be obvious, and not dependent upon a specific machine setup. The best thing to do would be to set up a skeleton file for new projects that includes all of the basic functionality you need. That, along with oft-used snippets will handle the problem.
All of your code to run the script, will be in the script, and you won't have to think about adding that code every time.
Using jupyter with multiple environments, adding the path to .bashrc didn't work. I had to edit the kernel.json file for that particular kernel and append it to the PYTHONPATH in env section.
This only worked in that kernel but maybe this can help someone else.

Categories