See Varshita Sher's article how to import packages and modules (and the
difference between the two):
Understanding Python imports, __init__.py and pythonpath — once and for all (Oct 7, 2021)
Turn the utils directory into a package by adding __init__.py in this directory.
Optionally add the following contents to it:
# [python]
from utils.lower import to_lower
from utils.upper import to_upper
from utils.length import get_length
PYTHONPATH is an environment variable that specifies additional directories
where Python should look for modules and packages when importing them. It allows
users to extend Python's search path beyond the default locations, making it
useful for custom libraries or project-specific dependencies.
The only reason to set PYTHONPATH is to maintain directories of custom
Python libraries that you do not want to install in the global default location
(i.e. the site-packages directory).
See
Importing your Local Package with PYTHONPATH
(Sep 21, 2023) by James Kabbes
and
What is PYTHONPATH environment variable in Python? (Aug 26, 2023) by Rajendra Dharmkar
For example, to set the PYTHONPATH environment variable to include the utils directory
# [bash]
echo $PYTHONPATH
export PYTHONPATH=$PYTHONPATH:$( pwd )/utils
echo $PYTHONPATH
To persist the above addition to PYTHONPATH, you could put the export statement
into a script and run it to initialise the project (or configure your system to
run it automatically on startup, e.g. in .bashrc or .zshrc).