Resolving intra-project imports in Python — A simple guide — Text Editor and Terminal
Please click here if you wish to return to the parent article.
This article provides a minimal step-by-step guide on how to set up intra-project Python imports correctly, using a regular text editor and terminal only.
This article will use the “simple” project structure from the parent article, where source folders and test folders are all at the same level directly under the project root folder.
project
│
├─── folder1
│ │ __init__.py
│ │ file1.py
│
├─── folder2
│ │ __init__.py
│ │ file2.py
│
└─── tests
│ test_file.py
N.B. This project structure is fine for anyone who has no plans to distribute their code. If, however, you plan to distribute your code to others, e.g. through PyPI, you should consider using a
src
project structure instead. Follow this link (coming soon) for a step-by-step guide to project file import setup using asrc
project structure.
Import Statements
Ensure all import statements are written correctly. All imports should be absolute imports starting from under the project root.
Consider project/folder1/file1.py
which contains a simple add()
function.
# project/folder1/file1.pydef add(num1, num2):
return num1 + num2
We want to use this function in project/folder2/file2.py
. Our import is simply from folder1 import file1
— an absolute import that starts from under the project root.
# project/folder2/file2.pyfrom folder1 import file1print('1 + 2 =', file1.add(1, 2))
Ensure all imports in your project are set up like this.
Setting up imports for the Terminal
In order for imports to work correctly, you will need to turn the project into a proper Python package and install it.
You will need to do a number of things:
- Create a venv (if you haven’t already)
- Upgrade package tools in your venv
- Set up a package for your project
- Install your project
Create a venv
If you already have a venv created and activated, and have configured VS Code to use your venv, feel free to skip this section.
You will need to create a venv (short for virtual environment) to install your project to. A venv is a lightweight version of Python separated from your system installation of Python, and is typically created for each new Python project. Installing packages to a venv means that packages for each Python project are isolated from each other.
Open a new terminal and ensure the terminal directory is set to the project root folder. Then, run the following command in the shell:
- Windows:
py -m venv venv
- macOS/Linux:
python3 -m venv venv
C:\...\project> py -m venv venv
This command tells the venv
package to create a new virtual environment for us with the directory name of venv
.
project
│
├─── folder1
│ │ __init__.py
│ │ file1.py
│
├─── folder2
│ │ __init__.py
│ │ file2.py
│
└─── tests
│ │ test_file.py
│
└─── venv
Activate the venv. To do this, run activate.bat
on Windows CMD shells, activate.ps1
on Windows Powershells, or activate
on macOS/Linux shells. You will be able to tell the venv is correctly activated if you see the (venv)
prefix on your interpreter.
C:\...\project> c:/.../project/venv/Scripts/activate.bat(venv) C:\...\project>
(For more information on virtual environments, please visit the following link: https://docs.python.org/3/tutorial/venv.html )
Upgrade package tools in your venv
We will be using setuptools
to create a Python package from your project and pip
to install it locally. In order to ensure everything goes as smoothly as possible, it’s recommended to have both packages up to date.
With the terminal open and the venv active, run the following command:
- Windows:
py -m pip install --upgrade pip setuptools
- macOS/Linux:
python3 -m pip install --upgrade pip setuptools
When you get the message that both pip
and setuptools
have been successfully installed, continue onwards.
Set up a package for your project
Now, you will need to create a package for your project. This is done by creating a setup.py
file using the setuptools package, which should already be available to you in your Python installation.
Under your project root folder, create a file called setup.py
.
project
│ setup.py
│
├─── folder1
│ │ __init__.py
│ │ file1.py
│
├─── folder2
│ │ __init__.py
│ │ file2.py
│
└─── tests
│ │ test_file.py
│
└─── venv
Populate setup.py
like so:
# /project/setup.pyfrom setuptools import setup, find_packagessetup(
name='project',
packages=find_packages(),
)
The contents of this file can be left like this for now for our purpose, which is getting imports working locally. If you plan to distribute your code later, you will need to return to this file and change it as necessary.
Installing your project
Now, install your project to your venv. The project will be installed in “editable” mode — this is so that any changes to the installation will automatically update as your project code changes.
Go to the Terminal. Make sure that your venv is active and that the directory is set to the project root. Then, run the following command in the shell:
- Windows:
py -m pip install -e .
- macOS/Linux:
python3 -m pip install -e .
(venv) C:\...\project> py -m pip install -e .
Once the shell says that the project has been successfully installed, you are good to go.
(venv) C:\...\project> py -m pip install -e .
Obtaining file:///C:/.../project
Installing collecting packages: project
Running setup.py develop for project
Successfully installed project
Further confirmation of the installation of your project will be the appearance of a .egg-info
folder in your project folder.
project
│ setup.py
│
├─── folder1
│ │ __init__.py
│ │ file1.py
│
├─── folder2
│ │ __init__.py
│ │ file2.py
│
├─── project.egg-info
│
├─── tests
│ │ test_file.py
│
└─── venv
And we’re done!
It was a roundabout trip, but we got there! If you now run your code or your tests from the shell, everything should just work.
project/folder1/file1.py
:
def add(num1, num2):
return num1 + num2
project/folder2/file2.py
:
from folder1 import file1print('1 + 2 =', file1.add(1, 2))
Running code through the terminal:
(venv) C:\...\project> py folder2\file2.py
1 + 2 = 3
Running tests through the terminal:
# output trimmed for brevityC:\...\project> pytestcollected 1 item.tests\test_file.py1 passed in 0.02s