If a Python file inside a package raises ImportError: attempted relative import with no known parent package when you run it directly, start it as a module from the directory above the package. On macOS, change to the project root in Terminal, then run python3 -m package.module. This gives Python the package context that a direct file path does not provide.
Why does a relative import fail when I run a file directly?
A relative import such as from .helpers import format_result depends on the module’s package name. Python uses leading dots to identify the current package and its parents. When you run a file with python3 path/to/file.py, Python runs that file as the top-level __main__ module; it does not give it the package metadata needed to resolve the dot. The import can therefore fail even though helpers.py is beside the file. Python’s import reference describes relative imports and the special handling of __main__.
For example, suppose your project is arranged like this:
project/
└── myapp/
├── __init__.py
├── cli.py
└── helpers.py
If cli.py contains from .helpers import format_result, running python3 myapp/cli.py from project is the wrong invocation. The problem is how Python was asked to run the file, not necessarily that the relative import or file location is wrong.
Run the module from the project root on macOS
Open Terminal and change to the directory that contains myapp. Replace the example path with your project’s actual location. Quote the path so spaces are handled by the shell; macOS Terminal’s default shell is zsh. Apple’s Terminal guide documents that default.
cd "/Users/yourname/Projects/project"
python3 -m myapp.cli
The -m option asks Python to find and run the module by its dotted package name. Keep the package name in the command and omit .py and filesystem slashes. Python’s module search path starts with the current directory when invoked with -m, which is why running from the project root matters. Python’s sys.path documentation explains this starting path.
If the command uses the wrong Python installation, activate the project’s existing virtual environment first, then use the same python -m pattern. For a typical .venv in the project root:
cd "/Users/yourname/Projects/project"
source .venv/bin/activate
python -m myapp.cli
Using python after activation selects the environment’s interpreter. If your environment has a different name or location, adjust the activation path; do not assume .venv exists. You can check the selected interpreter with python -c 'import sys; print(sys.executable)'.
If you want to run the package itself
For a command intended to launch the package, add __main__.py inside the package and keep the entry point small:
myapp/
├── __init__.py
├── __main__.py
├── cli.py
└── helpers.py
In myapp/__main__.py, import and call the package’s entry function. Then run python3 -m myapp from the project root. Python executes the package’s __main__.py for this form of -m invocation, and that file can use package-relative imports. The Python __main__ documentation explains this package entry-point pattern.
Check these details if the error remains
- Confirm your working directory. Run
pwdin Terminal and make sure it prints the project root, the directory containingmyapp. If the package is nested undersrc, for example, use the importable package name and ensure the project’s configured environment makes it available; simply changing to the wrong parent folder will not fix module discovery. - Use the real package name. In
python3 -m myapp.cli,myappmust be the package directory name (or its import name), andclithe module filename without.py. - Check the traceback line. If the relative import resolves but a later import fails, that may be a different missing module or dependency. Fixing the launch context only addresses the package-context failure.
- Avoid
PYTHONPATHas the first fix. It changes Python’s import search path, but it does not by itself turn a directly executed file into a properly named package module. Python also cautions thatPYTHONPATHcan affect multiple Python versions and environments. Python’s path initialization reference describes its scope. - If direct file execution is a requirement, consider changing the code to use an appropriate absolute import and ensure the package is installed or otherwise importable in that environment. That is a different setup choice; do not mix a package-relative import with the expectation that the file behaves like a standalone script.
The practical rule is to match the command to the import style: for a package-relative import, run the module from the package’s parent directory with python -m. For a package command, provide __main__.py and run the package with -m.
Sources
- 5. The import system — Python Software Foundation
- The initialization of the sys.path module search path — Python Software Foundation
- main — Top-level code environment — Python Software Foundation
- Change the default shell in Terminal on Mac — Apple