Python Modules, Packages, and uv
Structuring large Python codebases requires understanding how Python’s import system resolves names, how sys.modules caches loaded files, and how modern tooling like Astral’s uv handles dependency management.
1. How Python Finds and Caches Modules (sys.path & sys.modules)
When you write import my_module, Python executes a two-step process:
- Cache Inspection: It checks the
sys.modulesdictionary. Ifmy_moduleis already loaded, it immediately returns the cached module object without re-executing the file. - Path Search: If not cached, it searches the directories listed in
sys.pathin order:- The directory of the entrypoint script being executed.
- The
PYTHONPATHenvironment variable directories. - The standard library directories.
- The virtual environment’s
site-packagesdirectory.
import sys
# 1. Inspect loaded modules in memory:
print("Is 'sys' already cached?", "sys" in sys.modules) # Output: True
# 2. Inspect module search order:
print("\nFirst 3 search paths in sys.path:")
for idx, p in enumerate(sys.path[:3], start=1):
print(f"[{idx}] {p}")2. Circular Import Traps and the TYPE_CHECKING Pattern
A circular import happens when Module A imports Module B, but Module B imports Module A before Module A has finished executing its top-level statements.
# 💥 THE TRAP:
# user_service.py: from order_service import Order
# order_service.py: from user_service import User
# -> Raises ImportError: cannot import name 'User' from partially initialized module!
# ✅ SOLUTION: The TYPE_CHECKING Guard
# In order_service.py:
from typing import TYPE_CHECKING
if TYPE_CHECKING:
# This block executes ONLY during static type checking (mypy/pyright),
# NEVER during runtime! Circular import is completely avoided!
from user_service import User
class Order:
def __init__(self, owner: "User"):
self.owner = owner3. Package Layout and Explicit Exports (__all__)
Recommended cloud-native service repository layout:
payment_service/
├── pyproject.toml # Project dependencies and build metadata
├── uv.lock # Deterministic cryptographic lockfile
├── src/
│ └── payment_service/
│ ├── __init__.py # Defines the public API via __all__
│ ├── config.py # Pydantic Settings
│ ├── api/
│ │ ├── __init__.py
│ │ └── routes.py # FastAPI APIRouter
│ └── core/
│ ├── __init__.py
│ └── processor.py
└── tests/
├── conftest.py
└── test_api.py
In src/payment_service/__init__.py:
# Expose only explicit public symbols to external callers:
from payment_service.config import AppSettings
from payment_service.core.processor import process_payment
# If a user runs 'from payment_service import *', only these 2 symbols are exported:
__all__ = ["AppSettings", "process_payment"]4. Modern Dependency Management with Astral’s uv
Astral’s uv is written in Rust and is 10x–100x faster than legacy pip, poetry, and pipenv. It handles Python versions, virtual environments, lockfiles, and script execution in a single binary.
Essential uv Workflows
# 1. Initialize a new project with pyproject.toml
uv init payment-service
cd payment-service
# 2. Pin and install a specific Python runtime version (no pyenv needed!)
uv python install 3.12
uv venv --python 3.12
# 3. Add production dependencies (auto-resolves uv.lock and updates pyproject.toml)
uv add fastapi "pydantic>=2.7.0" uvicorn
# 4. Add development-only dependencies
uv add --dev pytest ruff mypy
# 5. Run commands directly inside the project virtualenv without manual 'source activate':
uv run python -m payment_service
uv run pytestStandard pyproject.toml (PEP 621)
[project]
name = "payment-service"
version = "0.1.0"
description = "Cloud-native payment service"
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
"fastapi>=0.111.0",
"pydantic>=2.7.0",
"uvicorn>=0.30.0",
]
[project.optional-dependencies]
dev = [
"pytest>=8.2.0",
"ruff>=0.4.0",
"mypy>=1.10.0",
]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"Next Steps
- 08: Classes, OOP, and Dunder Methods — Object-oriented architecture and magic methods.
- 24: Production Packaging, Docker, and Deployment — Multi-stage Docker builds using
uv.