Skip to main content

06.2 - Creating & Structuring Packages

Theory 20 min Intermediate

What is a Package?

A package is a directory containing Python modules, with an __init__.py file.

mypackage/
├── __init__.py # Makes it a package
├── utils.py # Module
├── validators.py # Module
└── subpackage/
├── __init__.py
└── helpers.py

__init__.py

__init__.py runs when the package is imported. It can:

  • Be empty (minimal package)
  • Import from submodules to create a clean public API
  • Set __all__ for the package
# mypackage/__init__.py
from .utils import format_date, format_currency
from .validators import validate_email

__version__ = "1.0.0"
__all__ = ["format_date", "format_currency", "validate_email"]

Now users can do:

from mypackage import format_date   # clean import!

Relative vs Absolute Imports

# Absolute (from project root)
from mypackage.utils import format_date
from mypackage.subpackage.helpers import helper_func

# Relative (within the package)
from .utils import format_date # same package
from ..validators import validate_email # parent package

Rule: Use relative imports within a package, absolute imports from outside.


Modern Project Structure

my_project/
├── src/
│ └── mypackage/
│ ├── __init__.py
│ ├── core.py
│ └── utils.py
├── tests/
│ ├── __init__.py
│ └── test_core.py
├── pyproject.toml # build config
├── README.md
└── requirements.txt

pyproject.toml

Modern Python projects use pyproject.toml instead of setup.py:

[build-system]
requires = ["setuptools>=68"]
build-backend = "setuptools.backends.legacy:build"

[project]
name = "mypackage"
version = "1.0.0"
description = "A sample Python package"
requires-python = ">=3.10"
dependencies = [
"requests>=2.31",
"pydantic>=2.0",
]

[project.optional-dependencies]
dev = [
"pytest>=7.0",
"black>=23.0",
"ruff>=0.1",
]

[tool.black]
line-length = 88

[tool.ruff]
select = ["E", "W", "F"]

Key Vocabulary

TermDefinition
PackageDirectory with __init__.py containing modules
__init__.pyMakes a directory a Python package
Relative importfrom .module import x — relative to current package
Absolute importfrom package.module import x — from project root
pyproject.tomlModern project configuration file
src layoutKeeps package under src/ to avoid import confusion

Summary

  • A package is a directory with __init__.py and module files
  • __init__.py defines the package's public API using relative imports
  • Use relative imports (from .x import y) within a package
  • Modern projects use pyproject.toml for configuration
  • Organize large projects with src/ layout