Post

Doing imports in a Python project

When running scripts, PYTHONPATH is set to the parent directory of the executed script.

Import statements that include the full path from the project root (absolute imports - e.g. import mypackage.mysubpackage.mymodule) therefore won’t work without any further modification – when running a script interactively in VS Code, in a GitHub Actions workflow, or from the command line.

Changing the imports to be relative imports – e.g. import ..mysubpackage.mymodule) isn’t the solution. It is less readable and won’t in all cases work anyway (ImportError: attempted relative import with no known parent package).

There are options for solving this:

  1. [Best for VS Code] Run the scripts from the project root

    In VS Code this is done by adding a settings.json file in a .vscode directory in the project root containing:

    1
    2
    3
    
     {
         "jupyter.notebookFileRoot": "${workspaceFolder}"
     }
    
  2. [Best for GitHub Actions1] (Temporarily) add the project root to PYTHONPATH

    In GitHub Actions this is done using steps such as these:

    1
    2
    3
    4
    5
    6
    
     - name: Set PYTHONPATH to root directory
       run: echo "PYTHONPATH=$(pwd)" >> $GITHUB_ENV
     - name: Run script
       run: |
         echo %PYTHONPATH%
         python mypackage/mysubpackage/my_module.py
    

    In the command line this is done using:

     set PYTHONPATH=%PYTHONPATH%;%cd% && python mypackage/mysubpackage/my_module.py
    

    (Ref. 1, 2)

  3. [Best for Windows command line] Invoke the script as a module

    In the command line this is done by running e.g. python -m mypackage.mysubpackage.mymodule.py. (Note both the -m flag and the full stops between directory levels.)

  4. [Best for simple projects, platform-agnostic] Move the scripts to the project root

    Though The Hitchiker’s Guide to Python suggests only using this where the module consists of a single file.

Further reading

  1. Setting the working directory to the project root in GitHub Actions doesn’t solve things in GitHub Actions, as this is what the default working directory is in an case. ↩︎

This post is licensed under CC BY 4.0 by the author.