PYTHONPATH Tricks
What is PYTHONPATH
PYTHONPATH is an environment variable that defines where python looks for importable modules
In bash, running echo $PYTHONPATH
will show you the current path
Python then adds the directories in that path to sys.path
at runtime
Handling of dependencies with multiple versions
If there are multiple versions of a package in sys.path
, python searches sys.path
in order and uses the first one found
Experiment
To prove this, setup the following scenario
File: ~/package1/package.py def version(): return “Version 1”
File: ~/package2/package.py def version(): return “Version 2”
bash: PYTHONPATH=~/package1/package.py:~/package2/package.py python
Inside the python interpreter: import package; package.version()
Output: Version 1
This makes sense, running import sys; sys.path
shows us that package1 is listed first hence it was loaded
Overriding default resolution behaviors
### Changing default behavior, using path above, package.version() will output Version 1import osimport sysMODULE = 'package'
def printPackageVersion(): import package print(f"Currently loaded package version {package.version()}")
if 'package' in sys.modules.keys(): # If already imported from somewhere else, remove printPackageVersion() del sys.modules[MODULE]
# Changing to Version 2 of our package# sys.path was ["", "package1" "package2"] but will be ["", "package2", "package1"] nowsys.path.insert(1, os.path.abspath("~/package2"))printPackageVersion() # outputs Version2
# What if we wanted to use both versions of the package and use them both in the same fileimport importlib.utilspec = importlib.util.spec_from_file_location('package', '~/package1/package.py')mod = importlib.util.module_from_spec(spec)spec.loader.exec_module(mod)
mod.version() # Outputs Version 1package.version() # Outputs Version 2
# What about overriding the already loaded version of the module with our new version# Now our module versions are out of sync, to hack in Version 1 again globallydel sys.modules[MODULE]sys.modules[MODULE] = mod
mod.version() # Outputs Version 1package.version() # Outputs Version 1