Init
Use the init
command to turn a configuration file into a ready to use project.
By default instant-python
will look for ipy.yml in the current directory. A different file can be provided with --config
or -c
flags.
Additionally, a custom template for your project structure can be used, you tell ipy
to use that
template with the --template
or -t
flag and providing the path to the template file.
Important
When using a custom template, the possibility of using out-of-the-box implementations is not available. The custom template will only create the folder structure and files defined in it.
Overview
The command performs the following steps:
- Creates the project folder structure based on the selected template or your custom template.
- Only when the template is not custom, writes boilerplate code for any built‑in features enabled in the configuration.
- Sets up the chosen dependency manager and installs dependencies under the selected Python version.
- Initializes a git repository if requested and configures your username and email.
- Moves the configuration file inside the new project folder for future reference.
Configuring a dependency manager
Choose between two of the most popular dependencies and project manager for Python:
Instant Python will automatically download the selected dependency manager and create a virtual environment. This will allow you to install your dependencies and run tasks out of the box.
Creating a git repository
You will be able to configure your project as a git repository automatically. Instant Python will use the username
and
email
fields from the configuration file to set up your git identity.
If you choose to create a git repository, it will create a README.md file and the .gitignore file configured for Python projects.
Default templates
There are some project templates already configured that you can use to create your project. These templates will create the folder structure of your project following a specific pattern.
Important
These templates do not reflect your architecture, but the folder structure of your project. There is a key difference between these concepts.
Domain Driven Design
Follows DDD pattern and screaming architecture organization.
Separates the source code and test folder in bounded contexts and aggregates. Each aggregate will contain the known domain, application and infra layers. This template will allow you to create your first bounded context and aggregate.
├── src
│ ├── bounded_context_name
│ │ └── aggregate_name
│ │ │ ├── application
│ │ │ ├── domain
│ │ │ └── infra
│ │ └── shared
│ ├── shared
│ └── delivery
│ └── api
└── tests
├── bounded_context_name
│ └── aggregate_name
│ │ ├── application
│ │ ├── domain
│ │ └── infra
│ └── shared
├── shared
└── delivery
└── api
Clean Architecture
Will create your folders following the clean architecture pattern.
Separates the source code and test folder in domain, application, infrastructure and delivery layers.
├── src
│ ├── application
│ ├── domain
│ ├── infra
│ └── delivery
│ └── api
└── tests
├── acceptance
├── unit
└── integration
Standard project
Will create your project with the common pattern of source code and test folder.
Out-of-the-box implementations
When creating a new project, you will be able to include some boilerplate and implementation code that will help you to start your project.
Tip
These implementations are completely subjective and personal. This does not mean that you must implement them in the same way or that they are the best way to implement them. You can use them as a starting point and iterate them as you need.
Warning
These implementations are only available when using one of the default templates.
Value objects and exceptions
Value objects are a common pattern to encapsulate primitives and encapsulate domain logic. If you choose this option, it will include the following value objects:
Base ValueObject
class ValueObject[T](ABC):
_value: T
def __init__(self, value: T) -> None:
self._validate(value)
self._value = value
@abstractmethod
def _validate(self, value: T) -> None: ...
@property
def value(self) -> T:
return self._value
@override
def __eq__(self, other: object) -> bool:
if not isinstance(other, ValueObject):
return False
return self.value == other.value
UUID
StringValueObject
IntValueObject
Along with these value objects, it will include a base exception class that you can use to create your own exceptions and some common exceptions that you can use in your project:
Base DomainError
class DomainError(Exception, ABC):
def __init__(self, message: str, error_type: str) -> None:
self._message = message
self._type = error_type
super().__init__(self._message)
@property
def type(self) -> str:
return self._type
@property
def message(self) -> str:
return self._message
def to_primitives(self) -> dict[str, str]:
return {
"type": self.type,
"message": self.message,
}
IncorrectValueTypeError
InvalidIdFormatError
InvalidNegativeValueError
RequiredValueError
Makefile
A Makefile is a common tool to run tasks in your project. This feature is specially useful when automating tasks and avoid remembering all the commands.
Warning
If you are running instant-python
in a Windows environment, the Makefile will not work out of the box. You would need
to install a tool like GNU Make for Windows or use a different task runner.
The default Makefile will include the following commands:
Command | Description |
---|---|
make help |
Show available commands |
make test |
Run all tests |
make unit |
Run all unit tests |
make integration |
Run all integration tests |
make acceptance |
Run all acceptance tests |
make coverage |
Run coverage tests |
make install |
Install all dependencies |
make update |
Update all dependencies |
make add-dep |
Add a new dependency |
make remove-dep |
Remove a dependency |
make check-typing |
Runs type checker |
make check-lint |
Checks lint code with Ruff |
make lint |
Fixes lint errors code with Ruff |
make check-format |
Checks format code with Ruff |
make format |
Format code with Ruff |
make local-setup |
Set up the local development environment |
make show |
Show all installed dependencies |
make search |
Show details of a specific package |
Info
The commands unit
, integration
and acceptance
are defined based on the assumption that you will mark your tests with
the @pytest.mark.unit
, @pytest.mark.integration
and @pytest.mark.acceptance
decorators.
If this is not your case, you change the commands as needed in the Makefile to match your test structure.
GitHub actions and workflows
Info
When selecting this feature, by default, the library will include mypy
as a type checker, ruff
as a linter and formatter, and
pytest
as a test runner. If you want to use different tools, you can change them later in the workflow file.
A common feature in projects is to have a CI/CD pipeline that will run some tasks. This option will include the following:
- A GitHub action that will set up your Python environment in your pipeline using the dependency manager you selected.
- A workflow that will execute all lint, type and code formatting checks.
- A workflow that will run all tests in your project.
Info
The test workflow will use unit
, integration
and acceptance
make commands presented in the previous section.
These commands are defined based on the assumption that you will mark your tests with the @pytest.mark.unit
, @pytest.mark.integration
and @pytest.mark.acceptance
decorators.
If this is not your case, you change the commands in the workflow file to match your test structure.
Logger
Logging messages in an application it's a common task.
This boilerplate will include a basic logger that creates a handler for production with logging ERROR level and a handler for development with logging DEBUG level. These handlers will be logging messages into a file that will be rotated every day.
It will also include a json formatter that formats the message with the time the logg was made, the level, the name or title of the message and the message itself.
FastAPI
FastAPI has become one of the most popular frameworks to create APIs in Python. This boilerplate will include:
- A main file where the FastAPI is created
- Two error handlers configured, one that captures unexpected errors that will raise a 500 status code, and another
handler that catches
DomainError
instances and raises a 400 status code by default. - A lifespan that will execute the migrations with alembic when the application starts.
- A decoupled implementation to model your status codes and http responses.
Info
When selecting this feature, you will need to have the logger boilerplate included.
Asynchronous SQL Alchemy
SQL Alchemy is a popular ORM for Python, and with the introduction of async and await in Python, it has become a powerful tool to manage databases. This boilerplate will include:
- A basic implementation of a repository pattern that will allow you to create a repository for each entity in your project.
- A class to encapsulate postgres settings
Asynchronous migrations
Along with SQL Alchemy it's typical to use Alembic to manage database migrations. This boilerplate will include everything needed to configure the migrations and run them asynchronously.
Event bus
In complex applications, it's common to use an event bus to communicate between different parts of the application. This boilerplate will set up a decoupled implementation of an event bus using RabbitMQ. This implementation will include:
- An
AggregateRoot
class that will allow you to create your aggregates and publish events automatically. - Modeled domain events that will be published through the event bus.
- Interface for the event bus and subscriber.
- Concrete implementation of the event bus using RabbitMQ
Using custom template
You can create a new project using a custom template instead of one of the default templates.
Important
When using a custom template, the possibility of using out-of-the-box implementations is not available.
This custom template must follow a specific structure and syntax to be able to generate the project correctly.
- You must use a yml file to define the folder structure.
- The hierarchy of your project will be declared as a list of elements with the following structure:
name
: The name of the folder or file to create.type
: The type of the element, which can bedirectory
orfile
.python
: Only for directories. Set its value to True if the directory is a python module to include the__init__.py
file, otherwise ignore this field.extension
: Only for files. The extension of the file to create. If the file do not have an extension, you can ignore this field.children
: A list of elements that will be created inside the folder. This can be either another directory or files.