Module Structure and Exports¶
When generating models to a directory structure, datamodel-code-generator can automatically create __init__.py files with __all__ exports. This page explains how to control this behavior.
Quick Overview¶
| Option | Description |
|---|---|
--all-exports-scope |
Control which modules get __all__ exports |
--all-exports-collision-strategy |
Handle name collisions in recursive exports |
--treat-dot-as-module |
Convert dots in names to nested modules |
--all-exports-scope¶
Controls the scope of __all__ generation in __init__.py files.
| Value | Description |
|---|---|
none |
No __all__ generation (default) |
local |
Export only the module's own definitions |
recursive |
Export all definitions from child modules |
Example: none (default)¶
Example: local¶
Example: recursive¶
# models/__init__.py
from .user import User
from .order import Order
from .common.status import Status
from .common.types import ID, Timestamp
__all__ = ["User", "Order", "Status", "ID", "Timestamp"]
--all-exports-collision-strategy¶
When using --all-exports-scope recursive, name collisions can occur if multiple modules define the same class name. This option controls how to handle them.
| Value | Description |
|---|---|
minimal-prefix |
Add minimum module path prefix to disambiguate |
full-prefix |
Use complete module path for all exports |
The Problem¶
Both modules define ID, causing a collision when exporting recursively.
Solution: minimal-prefix¶
datamodel-codegen --input schemas/ --output models/ \
--all-exports-scope recursive \
--all-exports-collision-strategy minimal-prefix
# models/__init__.py
from .user.types import ID as user_ID
from .order.types import ID as order_ID
__all__ = ["user_ID", "order_ID"]
Only colliding names get prefixed.
Solution: full-prefix¶
datamodel-codegen --input schemas/ --output models/ \
--all-exports-scope recursive \
--all-exports-collision-strategy full-prefix
# models/__init__.py
from .user.types import ID as user_types_ID
from .order.types import ID as order_types_ID
__all__ = ["user_types_ID", "order_types_ID"]
All names use the full module path prefix.
--treat-dot-as-module¶
Converts dots in schema names to nested module directories.
Without --treat-dot-as-module¶
Schema with title: "api.v1.User" generates:
With --treat-dot-as-module¶
Schema with title: "api.v1.User" generates:
models/
├── __init__.py
└── api/
├── __init__.py
└── v1/
├── __init__.py
└── user.py # contains class User
This is useful for: - Organizing large schemas by namespace - Mirroring API versioning structure - Keeping related models together
Common Patterns¶
Pattern 1: Flat output with local exports¶
Best for small to medium projects with a single output file or simple structure.
Pattern 2: Hierarchical with recursive exports¶
Best for large projects with many schemas organized by domain.
datamodel-codegen --input schemas/ --output models/ \
--all-exports-scope recursive \
--all-exports-collision-strategy minimal-prefix \
--treat-dot-as-module
Pattern 3: OpenAPI with module structure¶
Best for OpenAPI schemas with versioned endpoints.
datamodel-codegen --input openapi.yaml --output models/ \
--treat-dot-as-module \
--all-exports-scope recursive
Troubleshooting¶
Import errors after generation¶
If you see ImportError: cannot import name 'X':
- Check if
__all__is generated correctly - Verify the module structure matches your imports
- Try
--all-exports-scope localfirst, thenrecursive
Name collisions¶
If you see duplicate class names:
- Use
--all-exports-collision-strategy minimal-prefix - Or use
--all-exports-collision-strategy full-prefixfor maximum clarity - Consider restructuring your schemas to avoid collisions
Circular imports¶
If you encounter circular import errors:
- Check the generated
__init__.pyfiles - Consider using
--all-exports-scope localinstead ofrecursive - Use lazy imports in your application code