A dependency management tool for Python projects.
Project description
module-dependency
A dependency injection framework for embedded Python applications.
Overview
The goal of this project is to provide a comprehensive framework for managing structure for complex Python applications. The framework is designed to be modular, allowing developers to define components, interfaces, and instances that can be easily managed and injected into applications.
Declare components with interfaces, provide multiple implementations of them, and manage which implementation to use at runtime. Multiple components can be organized and composed together to form complex behaviors using modular design principles.
This repository includes a working example of a simple application that demonstrates these concepts in action. Based on a real-world use case, the example showcases how to effectively manage dependencies and implement modular design patterns in an embedded Python environment.
Install
This project is available on PyPI on module_dependency. It can be installed using pip:
pip install module-dependency
Core Components
The project is built around three components that implement different aspects of dependency management:
1. Module
- Acts as a container for organizing and grouping related dependencies
- Facilitates modular design and hierarchical structuring of application components
from dependency.core import Module, module
@module()
class SomeModule(Module):
"""This is a module class. Use this to group related components.
"""
pass
2. Component
- Defines abstract interfaces or contracts for dependencies
- Promotes loose coupling and enables easier testing and maintenance
from abc import ABC, abstractmethod
from dependency.core import Component, component
from ...plugin.........module import SomeModule
class SomeService(ABC):
"""This is the interface for a new component.
"""
@abstractmethod
def method(self, ...) -> ...:
pass
@component(
module=SomeModule, # Declares the module or plugin this component belongs to
interface=SomeService, # Declares the interface used by the component
)
class SomeServiceComponent(Component):
"""This is the component class. A instance will be injected here.
Components are only started when provided or bootstrapped.
"""
pass
3. Instance
- Delivers concrete implementations of Components
- Manages the lifecycle and injection of dependency objects
from dependency_injector.wiring import Provide, inject
from dependency.core import instance, providers
from ...plugin.........component import SomeService, SomeServiceComponent
from ...plugin...other_component import OtherService, OtherServiceComponent
@instance(
component=SomeServiceComponent, # Declares the component to be provided
imports=[OtherService, ...], # List of dependencies (components) that are needed
products=[SomeProduct, ...], # List of products that this instance will create
provider=providers.Singleton, # Provider type (Singleton, Factory)
bootstrap=False, # Whether to bootstrap on application start
)
class ImplementedSomeService(SomeService):
"""This is a instance class. Here the component is implemented.
Instances are injected into the respective components when provided.
"""
def __init__(self) -> None:
"""Init method will be called when the instance is stared.
This will happen once for singleton and every time for factories.
"""
# Once declared, i can use the dependencies for the class
self.dependency: OtherService = OtherServiceComponent.provide()
@inject
def method(self,
# Dependencies also can be used in this way
dependency: OtherService = Provide[OtherServiceComponent.reference],
...) -> ...:
"""Methods declared in the interface must be implemented.
"""
# Once declared, i can safely create any product
# Products are just normal classes (see next section)
product = SomeProduct()
# You can do anything here
do_something()
These components work together to create a powerful and flexible dependency injection system, allowing for more maintainable and testable Python applications.
Extra Components
The project has additional components that enhance its functionality and organization. These components include:
1. Entrypoint
- Represents a entry point for the application
- Responsible for initializing and starting the application
from dependency.core import Entrypoint, Container
from ...plugin...... import SomePlugin
class SomeApplication(Entrypoint):
"""This is an application entry point.
Plugins included here will be loaded and initialized.
"""
def __init__(self) -> None:
# Import the instances that will be used on the application
# This will generate the internal provider structure
import ...plugin.........component
# This is the main container, it will hold all the providers
container = Container.from_dict(config={...}, required=True)
super().__init__(
container,
plugins=[
SomePlugin,
...
])
def main_loop(self) -> None:
"""Main application loop.
"""
pass
2. Plugin
- Represents a special module that can be included in the application
- Provides additional functionality or features to the application
from pydantic import BaseModel
from dependency.core import Plugin, PluginMeta, module
class SomePluginConfig(BaseModel):
"""Include configuration options for the plugin.
"""
pass
@module()
class SomePlugin(Plugin):
"""This is a plugin class. Plugins can be included in the application.
Plugins are modules that provide additional functionality.
"""
meta = PluginMeta(name="SomePlugin", version="0.0.1")
@property
def config(self) -> SomePluginConfig:
"""Plugins can have their own configuration options.
Instantiates the model using the container config.
"""
return SomePluginConfig(**self.container.config())
3. Product
- Represents a class produced by a Provider that requires dependencies
- Allows to provide standalone classes without the need to define new providers
from dependency.core import Product, product
@product(
imports=[SomeComponent, ...], # List of dependencies (components) that are needed
)
class SomeProduct(Interface, Product):
"""This is the product class. This class will check for its dependencies.
Products must be declared in some instance and can be instantiated as normal classes.
"""
def __init__(self, ...) -> None:
# Dependencies can be used in the same way as before
self.dependency: OtherService = OtherServiceComponent.provide()
def method(self, ...) -> ...:
pass
Important Notes
- Declare all the dependencies (components) on Instances and Products to avoid injection issues.
- Read the documentation carefully and refer to the examples to understand the framework's behavior.
Usage Examples
This repository includes a practical example demonstrating how to use the framework. You can find this example in the example directory. It showcases the implementation of the core components and how they interact to manage dependencies effectively in a sample application.
This example requires the module-injection package to be installed and the library folder to be present in the project root.
Future Work
This project is a work in progress, and there are several improvements and enhancements planned for the future. Some of the areas that will be explored include:
- Improve component registration and resolution strategies
- Explore more advanced dependency injection patterns and use cases
- Enhance static and dynamic error handling mechanisms of the framework
- Improve testing and validation for projects using this framework
Aknowledgements
This project depends on dependency-injector. This library provides a robust and flexible framework for managing dependencies in Python projects.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file module_dependency-0.4.2.tar.gz.
File metadata
- Download URL: module_dependency-0.4.2.tar.gz
- Upload date:
- Size: 32.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: python-httpx/0.28.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4106b02d283e2eceb86bfd55707be2238121d2db7fb47d3321ac8dbd4d8e3b5a
|
|
| MD5 |
813cbcbb4182946fe5ec66216ba9e3d4
|
|
| BLAKE2b-256 |
471fe07ca1d9eb05bd623696c802e021a4d68c08762b52d6311ea16d10462dbf
|
File details
Details for the file module_dependency-0.4.2-py3-none-any.whl.
File metadata
- Download URL: module_dependency-0.4.2-py3-none-any.whl
- Upload date:
- Size: 31.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: python-httpx/0.28.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d2662dc20702ed03cd67a3b71ece071ce861e0e5c561ae756314826b50178454
|
|
| MD5 |
a17de29c01c1d4acd5680356bae61795
|
|
| BLAKE2b-256 |
d4d7879310f8a546a6fae43e4700c30dad47e83955f36fcbd1ccda2a6e6971c7
|