# How to Fix "ImportError: attempted relative import with no known parent package"


`ImportError: attempted relative import with no known parent package` means Python ran a file that uses a relative import, but that file had no parent package to resolve the import against. It almost always comes from launching the file the wrong way, not from a mistake in the import itself.

{{< callout type="info" >}}
**Quick fix:** from the project root, run the file as a module instead of a script. Use `python -m mypackage.app` (dotted path, no `.py`), not `python mypackage/app.py`. The rest of this guide explains why, offers an alternative, and shows how to make the fix permanent with an entry point.
{{< /callout >}}

## Reproduce the error

Create a small package with two files. `helpers.py` holds a function, and `app.py` imports it with a relative import:

{{< /filetree/folder >}}
  {{< /filetree/folder >}}
{{< /filetree/container >}}

```python {filename="mypackage/app.py"}
from .helpers import greeting


def main():
    print(greeting())


if __name__ == "__main__":
    main()
```

Run the file directly, the way you would run any script, and it fails:

```console
$ python mypackage/app.py
Traceback (most recent call last):
  File "mypackage/app.py", line 1, in <module>
    from .helpers import greeting
ImportError: attempted relative import with no known parent package
```

The `from .helpers` line is correct. The problem is how the file was launched. An editor's Run button does the same thing: VS Code's "Run Python File" and PyCharm's run arrow both execute the current file by its path, so they raise this error too.

## Why does running a file directly break relative imports?

When you run `python mypackage/app.py`, Python loads `app.py` as the top-level script and sets its `__package__` to `None`. A relative import like `from .helpers` needs `__package__` to name a parent package, and `None` gives it nothing to resolve against. See [what a Python module is](https://pydevtools.com/handbook/explanation/what-is-a-python-module.md) for how Python assigns `__name__` and `__package__`.

## Run the module with `python -m`

Run the file as a module instead of a script. From the project root (the directory that contains `mypackage/`), use the `-m` flag with the dotted import path and no `.py` extension:

```console
$ python -m mypackage.app
hello from helpers
```

`python -m mypackage.app` imports `app` as a submodule of `mypackage`, so Python sets `__package__` to `"mypackage"` and the relative import resolves. Point `-m` at the specific module (`mypackage.app`), not the package (`mypackage`). Running `python -m mypackage` requires a `__main__.py` inside the package and fails without one.

The folder does not strictly need an `__init__.py` for this to work. Python treats a directory without one as a namespace package, so `python -m mypackage.app` runs either way. Add an empty `__init__.py` when you want an explicit package, which most tools and the entry-point setup below expect.

## Run the file directly with an absolute import

To keep launching the file as a script, change its relative import to an absolute one:

```python {filename="mypackage/app.py"}
from helpers import greeting
```

Running `python mypackage/app.py` puts the file's own directory on Python's import path, so the sibling `helpers` module resolves by its bare name. This works only while you launch from inside the package directory. The moment the same code is imported as part of a package, `import helpers` fails because `helpers` is no longer a top-level module. For anything you package or share, prefer `python -m` or an entry point.

## Give the program a permanent entry point

Typing `python -m mypackage.app` works, but it forces you and your users to know the internal module path and to stand in the right directory. A published entry point removes both requirements. Declare one in [`pyproject.toml`](https://pydevtools.com/handbook/reference/pyproject.toml.md) under `[project.scripts]`, pointing at the module and function to call:

```toml {filename="pyproject.toml"}
[project.scripts]
greet = "mypackage.app:main"
```

The value `"mypackage.app:main"` names the module (`mypackage.app`) and the function (`main`). Once the package is installed, running `greet` calls `main()` through the package, so `__package__` is set and the relative import resolves.

[uv](https://pydevtools.com/handbook/reference/uv.md) scaffolds this layout for you. `uv init --package` creates a project with a `[project.scripts]` entry point already wired to a starter `main()`:

```console
$ uv init --package --name mytool myproject
$ cd myproject
$ uv run mytool
Hello from mytool!
```

The scaffold writes `mytool = "mytool:main"`, pointing at a `main()` in `src/mytool/__init__.py`. Replace that placeholder with your own code. `uv run` installs the package into the project's [virtual environment](https://pydevtools.com/handbook/explanation/what-is-a-virtual-environment.md) as an [editable install](https://pydevtools.com/handbook/explanation/what-is-an-editable-install.md), then runs the console script. Because the code runs through the installed package, `__package__` is always set and relative imports resolve from any directory.

## Structure imports in a src-layout project

`uv init --package` uses the [src layout](https://pydevtools.com/handbook/explanation/src-layout-vs-flat-layout.md), which places the package under a `src/` directory:

{{< /filetree/folder >}}
    {{< /filetree/folder >}}
  {{< /filetree/folder >}}
{{< /filetree/container >}}

`src/` is not on Python's import path, so the package is only importable after `uv sync` installs it. That installed package is what makes relative imports inside `mytool` resolve. Modules within the package import each other with relative imports (`from .helpers import greeting`) or with the package name (`from mytool.helpers import greeting`); both work once the package is installed.

Running a file by its path still fails, even in a src layout:

```console
$ uv run python src/mytool/__init__.py
ImportError: attempted relative import with no known parent package
```

The rule holds regardless of layout: for code you package or share, reach it through the package with an entry point or `python -m`, rather than by file path. That is the launch method that keeps working as the project grows.

## Learn More

- [What is a Python module?](https://pydevtools.com/handbook/explanation/what-is-a-python-module.md) explains `__name__` and `__package__`
- [src layout vs flat layout](https://pydevtools.com/handbook/explanation/src-layout-vs-flat-layout.md) covers when to nest a package under `src/`
- [What is an editable install?](https://pydevtools.com/handbook/explanation/what-is-an-editable-install.md) explains how `uv sync` links your source into the environment
- [How to create and distribute a Python CLI tool](https://pydevtools.com/handbook/how-to/how-to-create-and-distribute-a-python-cli-tool.md) builds on `[project.scripts]` entry points
- [Python docs: the `import` system](https://docs.python.org/3/reference/import.html#package-relative-imports)
