AllTradesJack
AllTradesJack

Reputation: 2892

Python: is the current directory automatically included in path?

Python 3.4: From reading some other SO questions it seems that if a moduleName.py file is outside of your current directory, if you want to import it you must add it to the path with sys.path.insert(0, '/path/to/application/app/folder'), otherwise an import moduelName statement results in this error:

ImportError: No module named moduleName

Does this imply that python automatically adds all other .py files in the same directory to the path? What's going on underneath the surface that allows you to import local files without appending the Python's path? And what does an __init__.py file do under the surface?

Upvotes: 34

Views: 28076

Answers (3)

Austin
Austin

Reputation: 8585

The local directory of the initial script is included in the path; however, I often want my current working directory to be added, as well. This is especially useful when you use subfolders to organize a workspace (see example below).

To handle this, create a small wrapper function to always add the current working directory to the PYTHONPATH before running any Python script. By adding it to your bash/fish config, it'll always be available to you.

Here's how to accomplish this:

Setup

For Fish users: Add the following line to your ~/.config/fish/config.fish then reload your terminal or use source ~/.config/fish/config.fish:

function run_python --description 'This function temporarily sets the PYTHONPATH to include the current working directory and then runs the python command with any provided arguments.'
   set -lx PYTHONPATH $PYTHONPATH (pwd)
   python $argv
end

For Bash users: Add the following to your ~/.bashrc then reload your terminal or use source ~/.bashrc:

run_python() {
   # Temporarily sets the PYTHONPATH to include the current working directory
   # and then runs the python command with any provided arguments.
   PYTHONPATH="$PYTHONPATH:$(pwd)" python "$@"
}

Usage:

Just call run_python rather than calling python whenever you want the CWD added to your PYTHONPATH. For instance, if my directory structure is:

~/workspace
    package1/
        __init__.py
        module1.py
    package2/
        __init__.py
        module2.py
    data_prep/
      prepare_data.py
    model_training/
      train.py

where train.py has the following import statement:

from package1.module1 import foo
from package2.module2 import bar

You can run your script with run_python model_training/train.py and the imports will work just fine.

Upvotes: 1

Vitalii Shechkov
Vitalii Shechkov

Reputation: 11

I have faced same problem when running python script from Intellij Idea. There is a script in a

C:\Users\user\IdeaProjects\Meshtastic-python\meshtastic

It uses

from meshtastic import portnums_pb2, channel_pb2, config_pb2

and fails. I have realized that it looks for

C:\Users\user\IdeaProjects\Meshtastic-python\meshtastic\meshtastic

and changed working directory of this script in Run Configuration from

C:\Users\user\IdeaProjects\Meshtastic-python\meshtastic

to

C:\Users\user\IdeaProjects\Meshtastic-python

so it can find this module UNDERNEATH workdir during execution

C:\Users\user\IdeaProjects\Meshtastic-python\meshtastic

Upvotes: 1

Martijn Pieters
Martijn Pieters

Reputation: 1124718

Python adds the directory where the initial script resides as first item to sys.path:

As initialized upon program startup, the first item of this list, path[0], is the directory containing the script that was used to invoke the Python interpreter. If the script directory is not available (e.g. if the interpreter is invoked interactively or if the script is read from standard input), path[0] is the empty string, which directs Python to search modules in the current directory first. Notice that the script directory is inserted before the entries inserted as a result of PYTHONPATH.

So what goes on underneath the surface is that Python appends (or rather, prepends) the 'local' directory to sys.path for you.

This simply means that the directory the script lives in is the first port of call when searching for a module.

__init__.py has nothing to do with all this. __init__.py is needed to make a directory a (regular) package; any such directory that is found on the Python module search path is treated as a module.

Upvotes: 31

Related Questions