PyConstructor is a command-line tool that helps developers quickly create a project structure following Domain-Driven Design (DDD) principles. The tool generates architecture based on a YAML configuration that defines bounded contexts, entities, repositories, services, use cases, and other DDD elements.
# Install via pip
pip install pyconstructor
# Install via uv
uv add pyconstructor
# Generate YAML file with example data
pyc init
# Edit the generated ddd-config.yaml file
# ...
# Generate structure
pyc run- Initialize a new project with a preset configuration:
pyc init --preset <PresetType(Optional argument, default to Standard)>- Validate your configuration (Optional command):
pyc validate- Preview the project structure (Optional command):
pyc preview --file <file_name> (Optional argument)- Generate the project:
pyc run --file <file_name> (Optional argument)| Command | Description | Example |
|---|---|---|
init |
Initialize a new project with a preset configuration | pyc init --preset standard |
validate |
Validate your YAML configuration | pyc validate --file custom-config.yaml |
preview |
Preview the project structure without generating files | pyc preview --file custom-config.yaml |
run |
Generate the project structure | pyc run --file custom-config.yaml |
# Create project with standard preset
pyc init --preset standard
# Force overwrite existing config
pyc init --preset standard --force# Validate default config (ddd-config.yaml)
pyc validate
# Validate specific config file
pyc validate --file custom-config.yaml# Preview default config
pyc preview
# Preview specific config
pyc preview --file custom-config.yamlOutput:
- Displays the project structure tree in the console
- Generates a
structure.mdfile with the same tree view for future reference
Example output:
app/
├── domain/
│ ├── user/
│ │ ├── entities/
│ │ │ └── user.py
│ │ └── value_objects/
│ │ └── email.py
│ └── catalog/
│ └── entities/
│ └── product.py
├── application/
│ └── user/
│ └── use_cases/
│ └── register_user.py
└── infrastructure/
└── repositories/
└── user_repository.py
# Generate from default config
pyc run
# Generate from specific config
pyc run --file custom-config.yamlPyConstructor comes with three built-in presets:
Basic DDD structure without bounded contexts:
pyc init --preset simpleDefault preset with bounded contexts:
pyc init --preset standardComplex structure with nested contexts:
pyc init --preset advancedThe tool uses YAML configuration files to define your project structure.
Example configurations are provided in the src/templates/config_templates directory.
settings:
preset: "standard" # One of: "simple", "standard", "advanced"
use_contexts: true # Whether to use bounded contexts
contexts_layout: "flat" # One of: "flat", "nested"
group_components: true # Group similar components in directories
init_imports: false # Initialize imports in __init__.py files
root_name: "src" # Root directory namesettings:
preset: "simple"
layers:
domain:
entities: User, Product
value_objects: Email, Pricesettings:
preset: "standard"
layers:
domain:
contexts:
- name: user
entities: [User, Profile]
value_objects: [Email, Password]
- name: catalog
entities: [Product, Category]settings:
preset: "advanced"
layers:
contexts:
- name: user_context
domain:
entities: User
value_objects: Email
application:
use_cases: CreateUser
infrastructure:
repositories: UserRepository
- name: payment_context
domain:
entities: Payment
application:
use_cases: ProcessPayment
infrastructure:
repositories: TransactionRepository
Here's a complete example showing all available options:
settings:
preset: "advanced"
use_contexts: true
contexts_layout: "nested"
group_components: true
init_imports: true
root_name: "src"
layers:
contexts:
- name: user_context
domain:
entities: User, Profile
value_objects: Email, Password, UserRole
aggregates: UserAggregate
repositories: UserRepository
services: UserService
application:
use_cases: CreateUser, UpdateUser, DeleteUser
commands: CreateUserCommand, UpdateUserCommand
queries: GetUserQuery, ListUsersQuery
events: UserCreatedEvent, UserUpdatedEvent
dtos: UserDTO, UserCreateDTO
mappers: UserMapper
infrastructure:
repositories: UserRepositoryImpl
services: UserServiceImpl
interface:
controllers: [UserController]
middleware: AuthMiddleware
- name: order_context
domain:
entities: Order, OrderItem
value_objects: Money, OrderStatus
aggregates: OrderAggregate
repositories: OrderRepository
services: OrderService
application:
use_cases: CreateOrder, UpdateOrder
commands: CreateOrderCommand
queries: GetOrderQuery
events: OrderCreatedEvent
dtos: OrderDTO
mappers: OrderMapper
infrastructure:
repositories: OrderRepositoryImpl
interface:
controllers: OrderControllerWhen using the advanced configuration above, the tool will generate a structure like this:
src/
├── user_context/
│ ├── domain/
│ │ ├── entities/
│ │ │ ├── user.py
│ │ │ └── profile.py
│ │ ├── value_objects/
│ │ │ ├── email.py
│ │ │ ├── password.py
│ │ │ └── user_role.py
│ │ ├── aggregates/
│ │ │ └── user_aggregate.py
│ │ ├── repositories/
│ │ │ └── user_repository.py
│ │ └── services/
│ │ └── user_service.py
│ ├── application/
│ │ ├── use_cases/
│ │ │ ├── create_user.py
│ │ │ ├── update_user.py
│ │ │ └── delete_user.py
│ │ ├── commands/
│ │ │ ├── create_user_command.py
│ │ │ └── update_user_command.py
│ │ ├── queries/
│ │ │ ├── get_user_query.py
│ │ │ └── list_users_query.py
│ │ ├── events/
│ │ │ ├── user_created_event.py
│ │ │ └── user_updated_event.py
│ │ ├── dtos/
│ │ │ ├── user_dto.py
│ │ │ └── user_create_dto.py
│ │ └── mappers/
│ │ └── user_mapper.py
│ ├── infrastructure/
│ │ ├── repositories/
│ │ │ └── user_repository_impl.py
│ │ └── services/
│ │ └── user_service_impl.py
│ └── interface/
│ ├── controllers/
│ │ └── user_controller.py
│ └── middleware/
│ └── auth_middleware.py
└── order_context/
└── ... (similar structure)
You can customize the generated files by modifying the templates in the src/templates directory. Each component type has its own template file that you can modify to suit your needs.
Q: Which preset should I choose for my project? A:
- Simple: Perfect for learning DDD or small projects without complex contexts
- Standard: Best for most real-world projects with clear bounded contexts
- Advanced: Use for microservices architecture or when you need maximum flexibility
Q: What happens if files already exist in my project? A: PyConstructor adds new files and directories to your existing structure without touching existing files. This means:
- New components will be created alongside existing ones
- Existing
__init__.pyfiles won't be modified - You can safely run it on existing projects
Q: Can I see what will be generated before actually creating files? A: Yes! Use the preview command:
pyc preview
# or
pyc preview --file your-config.yaml
This shows the complete directory structure in console and generates a structure.md file.
Q: How do I add more components after initial generation? A: Simply:
- Edit your YAML configuration file to add new components
- Run
pyc runagain - it will add only the new components - Existing files remain untouched
Q: Can I customize the generated code templates?
A: Yes, but it's not officially supported yet. Templates are located in src/templates/. Modifying them directly will affect all generations. Official template customization API is planned.
Q: What's the difference between 'flat' and 'nested' context layouts? A:
- Flat:
src/domain/user_context/entities/(contexts inside layers) - Nested:
src/user_context/domain/entities/(layers inside contexts)
Q: I get "Configuration file not found" error
A: Make sure you have a ddd-config.yaml file in your current directory, or specify the path:
pyc run --file path/to/your/config.yamlQ: YAML validation fails with cryptic errors A: Common issues:
- Incorrect indentation (use spaces, not tabs)
- Missing quotes around special characters
- Empty values should be written as
[]or omitted entirely
Q: Generated code doesn't follow my coding standards A: Currently, PyConstructor generates basic templates. You can:
- Modify templates in
src/templates/(advanced users) - Use code formatters (black, ruff) after generation
Q: Can I use this with existing projects? A: Yes! PyConstructor safely adds new structure to existing projects:
- Creates new directories and files without touching existing ones
- Preserves your current codebase
- Perfect for gradually introducing DDD structure
- Just make sure your config doesn't conflict with existing file names
Q: What features are planned for future releases? A:
- Custom template support
- Framework-specific generators (FastAPI, Django)
- Interactive configuration builder
- Migration tools for existing codebases
- Advanced DDD patterns support
Contributions are welcome. Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git switch -c feature/amazing-feature) - Run tests (
pytest) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License—see the LICENSE file for details.
Grigoriy Sokolov (Sokolov_Gr@proton.me)