Question

Python Relative Imports Explained: Fixing "attempted relative import with no known parent package"

pythonpython-importrelative-pathpython-packagingrelative-import

Question

I want to understand why Python raises this error:

ImportError: attempted relative import with no known parent package

Suppose I have this package structure:

package/
    __init__.py
    subpackage1/
        __init__.py
        moduleX.py
        moduleY.py
    subpackage2/
        __init__.py
        moduleZ.py
    moduleA.py

I created simple functions such as spam() and eggs() inside the appropriate modules and tried importing them from the console, but the relative imports did not work.

I have read multiple explanations of PEP 328, packages, and relative imports, but I still do not clearly understand:

  • Why Python says attempted relative import in non-package
  • What no known parent package means
  • What Python means by a package
  • Why running a file directly often breaks relative imports
  • How using python -m ... solves the problem

In short, how should relative imports be used correctly in Python, and why does this error happen?

Short Answer

By the end of this page, you will understand what Python packages are, how relative imports work, why running a module directly often causes import errors, and how to use python -m correctly. You will also see practical examples of package layouts, import syntax, and the most common mistakes that lead to attempted relative import with no known parent package.

Concept

In Python, a relative import means importing something based on the current module's position inside a package.

For example:

from . import moduleY
from ..subpackage2 import moduleZ

The dots mean:

  • . = current package
  • .. = parent package
  • ... = grandparent package

For Python to resolve those dots, it must know where the current module lives inside the package hierarchy.

That is the key idea.

If Python runs a file as a plain script, that file is treated as a top-level module, usually with:

__name__ == "__main__"

In that situation, Python does not reliably know the module's package context, so a statement like this cannot be resolved:

from . import moduleY

Python then raises:

ImportError: attempted relative import with no known parent package

What is a package?

A package is a directory of Python modules that Python can treat as part of a module hierarchy.

Traditionally, a package contains an __init__.py file:

package/
    __init__.py

That tells Python that the directory should be treated as a package. In modern Python, namespace packages can also exist without __init__.py, but for beginners, it is best to think of a package as:

  • a folder of Python code
  • usually containing __init__.py
  • importable using dotted names like package.moduleA

Why the error mentions a "non-package"

When Python says "non-package", it means the module being executed is not currently being treated as part of a package import path.

Even if the file physically sits inside a package folder, Python may still treat it like a standalone script if you launch it directly:

python package/subpackage1/moduleX.py

In that case, moduleX.py is not loaded as package.subpackage1.moduleX. It is loaded as a script, so relative imports fail.

Why -m helps

When you run a module with -m, Python loads it using its full package name:

python -m package.subpackage1.moduleX

Now Python knows:

  • the module is package.subpackage1.moduleX
  • its parent package is package.subpackage1
  • relative imports can be resolved correctly

That is why -m often fixes the problem instantly.

Mental Model

Think of a relative import like giving directions inside a building.

  • . means "this room"
  • .. means "go up one floor"

But those directions only work if you know where you currently are.

If someone drops you in a building and says only, "You are here," then go up one floor makes sense.

But if you are standing in an empty field with no building map, "go up one floor" is meaningless.

That is what happens with Python:

  • When a module is run as part of a package, Python has the building map.
  • When a file is run directly as a script, Python often loses that map.

So a relative import is like saying:

Go to the sibling room next to me.

Python answers:

I do not know what building you are in, so I cannot follow that instruction.

That is the meaning of no known parent package.

Take Quiz

Syntax and Examples

Basic relative import syntax

from . import moduleY
from .moduleY import spam
from ..subpackage2 import moduleZ
from ..subpackage2.moduleZ import eggs

Example package

package/
    __init__.py
    subpackage1/
        __init__.py
        moduleX.py
        moduleY.py
    subpackage2/
        __init__.py
        moduleZ.py

Example code

package/subpackage1/moduleY.py

def spam():
    return "spam from moduleY"

package/subpackage1/moduleX.py

from .moduleY import spam

print(spam())

Wrong way to run it

python package/subpackage1/moduleX.py

This often fails because moduleX.py is being run as a standalone script, not as part of package.subpackage1.

Correct way to run it

Run this from the directory containing package:

python -m package.subpackage1.moduleX

Now Python knows the full module path and can resolve:

from .moduleY import spam

Absolute import alternative

You can also write:

from package.subpackage1.moduleY import spam

Absolute imports are often easier to read in larger projects, especially when files may be executed in different contexts.

Step by Step Execution

Consider this file:

package/subpackage1/moduleX.py

from .moduleY import spam

print(spam())

And this file:

package/subpackage1/moduleY.py

def spam():
    return "hello"

Case 1: Run the file directly

python package/subpackage1/moduleX.py

What happens:

  1. Python starts executing moduleX.py as a script.
  2. Its module name becomes __main__.
  3. Python does not treat it as package.subpackage1.moduleX.
  4. The line from .moduleY import spam means "import moduleY from my current package".
  5. But Python does not know the current package.
  6. It raises:
ImportError: attempted relative import with no known parent package

Case 2: Run with -m

python -m package.subpackage1.moduleX

What happens:

  1. Python starts from the parent directory of package.
  2. It loads moduleX using the full name package.subpackage1.moduleX.
  3. Python now knows the parent package is package.subpackage1.
  4. The relative import from .moduleY import spam can be resolved.
  5. spam() is imported and called.
  6. Output:
hello

Important detail

The problem is usually not the import statement itself.

The problem is how the module was executed.

Real World Use Cases

Relative imports are useful when code is organized into packages and subpackages.

Common scenarios

  • Utility modules inside a package
    • Example: from .helpers import format_date
  • Feature folders in web apps
    • Example: routes importing validators or services from the same package
  • Data processing packages
    • One module imports parsers, cleaners, or exporters from nearby modules
  • Libraries distributed on PyPI
    • Internal modules often use package-relative imports to reference sibling files

Example: API package

myapp/
    api/
        __init__.py
        routes.py
        validators.py

routes.py might contain:

from .validators import validate_user_payload

This keeps imports tied to the package structure instead of depending on the current working directory.

When relative imports help most

  • When modules in the same package need to talk to each other
  • When you want to avoid repeating a long absolute path
  • When code may be moved within the project without changing every import
Take Quiz

Real Codebase Usage

In real projects, developers usually combine absolute imports for clarity and relative imports for internal package relationships.

Common patterns

1. Internal helpers

from .utils import parse_config
from .errors import ConfigError

This is common when files are tightly related inside one package.

2. Absolute imports at package boundaries

from myapp.database.connection import connect

This makes it clear where code comes from, especially in larger applications.

3. Guarded script entry points

Instead of running package files directly, developers often add an entry point:

def main():
    print("Run app")

if __name__ == "__main__":
    main()

Then they execute it with:

python -m package.subpackage1.moduleX

4. Separation between library code and runnable code

A common pattern is:

  • package modules contain reusable logic
  • a separate top-level script calls into the package

Example:

project/
    run_app.py
    package/
        __init__.py
        service.py

run_app.py

from package.service import start

start()

This avoids many relative import issues.

5. Test code and imports

Tests often fail when developers run files from the wrong directory. Real codebases usually run tests from the project root so imports resolve consistently.

Common Mistakes

1. Running a package module as a plain script

Broken:

python package/subpackage1/moduleX.py

If moduleX.py contains:

from .moduleY import spam

it may fail because Python does not know its package context.

Avoid it by running:

python -m package.subpackage1.moduleX

2. Forgetting the package root

If you run -m from the wrong directory, Python may not find the package.

Suppose your structure is:

project/
    package/
        __init__.py

You should usually run this from project/, not from inside package/:

python -m package.moduleA

3. Mixing direct execution and package imports

Broken pattern:

# inside moduleX.py
from .moduleY import spam

if __name__ == "__main__":
    print(spam())

Then running:

python moduleX.py

This often fails if moduleX.py depends on package-relative imports.

Avoid it by either:

  • running with -m
  • using a separate launcher script
  • using absolute imports where appropriate

4. Confusing filesystem layout with import context

A file being inside a package folder is not enough by itself.

Python must import or execute it as part of that package.

5. Using relative imports in top-level scripts

Broken:

from .helpers import func

This only works inside a package module, not in a standalone top-level script.

6. Shadowing package names

If you name a file the same as a package or standard library module, imports can become confusing.

Examples:

  • email.py
  • json.py
  • package.py

Avoid using names that conflict with existing modules.

Comparisons

ConceptWhat it meansExampleBest used when
Relative importImport based on current package positionfrom .moduleY import spamImporting nearby modules inside the same package
Absolute importImport from the full package pathfrom package.subpackage1.moduleY import spamLarge projects where clarity matters
Direct script executionRun a file by pathpython package/subpackage1/moduleX.pySimple standalone scripts
Module execution with -mRun using module pathpython -m package.subpackage1.moduleXPackage modules that use relative imports

Relative imports vs absolute imports

Relative imports

Pros:

  • shorter inside a package
  • easier when moving a whole package subtree

Cons:

  • harder for beginners to understand
  • break when the module is run incorrectly

Absolute imports

Pros:

  • clear and explicit
  • easier to search and read in large codebases

Cons:

  • longer to write
  • may need updates if the top-level package name changes

Package module vs standalone script

SituationRelative imports work?Why
Imported as package.subpackage1.moduleXYesPython knows the parent package
Run as python package/subpackage1/moduleX.pyUsually noPython treats it as a standalone script
Run as python -m package.subpackage1.moduleXYesPython loads it with full package context
Take Quiz

Cheat Sheet

Quick rules

  • Relative imports use dots:
    • . current package
    • .. parent package
  • Relative imports only work when Python knows the module's package name.
  • Running a file directly often removes that package context.
  • Use python -m package.module instead of python path/to/file.py for package modules.

Common syntax

from . import moduleY
from .moduleY import spam
from ..subpackage2 import moduleZ
from package.subpackage1.moduleY import spam  # absolute import

Typical package layout

project/
    package/
        __init__.py
        subpackage1/
            __init__.py
            moduleX.py
            moduleY.py

Correct run command

From project/:

python -m package.subpackage1.moduleX

Common error meaning

ImportError: attempted relative import with no known parent package

Meaning:

  • Python saw a relative import like from .moduleY import spam
  • but it did not know what package the current module belongs to

Good practice

  • Use absolute imports for clarity in bigger projects
  • Use relative imports for nearby internal modules when appropriate
  • Do not run package files directly if they depend on relative imports
  • Keep runnable entry points separate when possible

FAQ

Why does Python say "attempted relative import with no known parent package"?

Because the module uses a relative import like from .x import y, but Python does not know what package the current file belongs to.

What is a parent package in Python?

It is the package that contains the current module. For example, the parent package of package.subpackage1.moduleX is package.subpackage1.

Why does running a file directly break relative imports?

Because Python usually loads that file as __main__ instead of by its full package name, so the package hierarchy is lost.

How does python -m fix relative imports?

It runs the module by its dotted module name, so Python knows its package context and can resolve relative imports.

Do I always need __init__.py for a package?

In modern Python, not always, because namespace packages exist. But for most beginner learning and many projects, including __init__.py makes package behavior clearer.

Should I use relative or absolute imports?

Use absolute imports when you want clarity and consistency. Use relative imports for nearby internal modules when that makes the package easier to maintain.

Can a top-level script use relative imports?

Usually no. Relative imports are meant for modules inside packages, not standalone scripts.

What is the safest project structure for avoiding this error?

Keep application logic inside packages, and run modules with python -m ... or from a separate top-level entry script.

Take Quiz

Mini Project

Description

Build a small Python package with two modules in the same subpackage and one runnable module that uses a relative import correctly. This project demonstrates the exact situation that causes the attempted relative import with no known parent package error and shows the proper way to run the code.

Goal

Create a package that uses relative imports successfully and run it with python -m from the project root.

Requirements

  1. Create a package directory with __init__.py files.
  2. Add one helper module that defines a function.
  3. Add one runner module that imports the helper with a relative import.
  4. Print the helper function result when the runner module executes.
  5. Run the project using python -m from the parent directory of the package.
Take Quiz

Keep learning

Related questions

View more