Skip to content

Feature/next version #6

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 23 commits into from
Jun 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 21 additions & 16 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ HOME := $(shell echo ~)
PWD := $(shell pwd)
SRC := $(PWD)/src
TESTS := $(PWD)/tests
DOCS := $(PWD)/docs

# Load env file
include env.make
Expand All @@ -29,7 +30,7 @@ help:

.PHONY: test
test: ## run test suite
PYTHONPATH=./src:./tests pipenv run pytest -n 1 $(TESTS)
PYTHONPATH=$(SRC):$(TESTS) pipenv run pytest $(TESTS)

################################################################################
# RELEASE
Expand All @@ -42,8 +43,10 @@ build: ## build the python package
.PHONY: clean
clean: ## clean the build
python setup.py clean
rm -rf build dist py_dependency_injection.egg-info
find . -type f -name '*.py[co]' -delete -o -type d -name __pycache__ -delete
rm -rf build dist
find . -type f -name '*.py[co]' -delete
find . -type d -name __pycache__ -exec rm -rf {} +
find . -type d -name '*.egg-info' -exec rm -rf {} +

.PHONY: bump_version
bump_version: ## Bump the version
Expand All @@ -67,23 +70,25 @@ sphinx-html: ## build the sphinx html

.PHONY: sphinx-rebuild
sphinx-rebuild: ## re-build the sphinx docs
make -C docs clean && make -C docs html
cd $(DOCS) && \
pipenv run make clean && pipenv run make html

.PHONY: sphinx-autobuild
sphinx-autobuild: ## activate autobuild of docs
pipenv run sphinx-autobuild docs docs/_build/html --watch $(SRC)
cd $(DOCS) && \
pipenv run sphinx-autobuild . _build/html --watch $(SRC)

################################################################################
# FORMAT & LINT
# PRE-COMMIT HOOKS
################################################################################

.PHONY: black
black: ## run black auto-formatting
pipenv run black $(SRC) $(TESTS) --line-length=88
pipenv run black $(SRC) $(TESTS)

.PHONY: black-check
black-check: ## check code don't violate black formatting rules
pipenv run black --check $(SRC) --line-length=88
pipenv run black --check $(SRC)

.PHONY: flake
flake: ## lint code with flake
Expand All @@ -105,12 +110,12 @@ pre-commit-run: ## run the pre-commit hooks
pipenv-install: ## setup the virtual environment
pipenv install --dev

.PHONY: pipenv-packages-install
pipenv-packages-install: ## install a package (uses PACKAGE)
.PHONY: pipenv-install-package
pipenv-install-package: ## install a package (uses PACKAGE)
pipenv install $(PACKAGE)

.PHONY: pipenv-packages-install-dev
pipenv-packages-install-dev: ## install a dev package (uses PACKAGE)
.PHONY: pipenv-install-package-dev
pipenv-install-package-dev: ## install a dev package (uses PACKAGE)
pipenv install --dev $(PACKAGE)

.PHONY: pipenv-packages-graph
Expand All @@ -121,12 +126,12 @@ pipenv-packages-graph: ## Check installed packages
pipenv-requirements-generate: ## Check a requirements.txt
pipenv lock -r > requirements.txt

.PHONY: pipenv-venv-activate
pipenv-venv-activate: ## Activate the virtual environment
.PHONY: pipenv-shell
pipenv-shell: ## Activate the virtual environment
pipenv shell

.PHONY: pipenv-venv-path
pipenv-venv-path: ## Show the path to the venv
.PHONY: pipenv-venv
pipenv-venv: ## Show the path to the venv
pipenv --venv

.PHONY: pipenv-lock-and-install
Expand Down
159 changes: 45 additions & 114 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,21 @@

# py-dependency-injection

A dependency injection library for Python.
A prototypical dependency injection library for Python.

## Features

- **Dependency Container:** Manage and resolve object dependencies with a flexible and easy-to-use container.
- **Dependency Scopes:** Define different scopes for dependencies, allowing for fine-grained control over their lifecycle.
- **Constructor Injection:** Inject dependencies into constructors, promoting cleaner and more modular code.
- **Method Injection:** Inject dependencies into methods, enabling more flexible dependency management within class instances.
- **Tags:** Register and resolve dependencies using tags, facilitating flexible and dynamic dependency management.
- **Factory Registration:** Register dependencies using factory functions for dynamic instantiation.
- **Instance Registration:** Register existing instances as dependencies, providing more control over object creation.
- **Python Compatibility:** Compatible with Python versions 3.7 to 3.12, ensuring broad compatibility with existing and future Python projects.
- **Scoped Registrations:** Define the lifetime of your dependencies as transient, scoped, or singleton.
- **Constructor Injection:** Automatically resolve and inject dependencies when creating instances.
- **Method Injection:** Inject dependencies into methods using a simple decorator.
- **Factory Functions:** Register factory functions, classes, or lambdas to create dependencies.
- **Instance Registration:** Register existing instances as dependencies.
- **Tag-Based Registration and Resolution:** Organize and resolve dependencies based on tags.
- **Multiple Containers:** Support for using multiple dependency containers.

## Compatibility

This library is compatible with the following Python versions:
The library is compatible with the following Python versions:

- 3.7, 3.8, 3.9, 3.10, 3.11, 3.12

Expand All @@ -29,138 +28,70 @@ This library is compatible with the following Python versions:
$ pip install py-dependency-injection
```

## Basic Usage
## Quick Start

The following examples demonstrates how to use the library.

### Creating a Dependency Container
Here's a quick example to get you started:

```python
# Get the default dependency container
dependency_container = DependencyContainer.get_instance()

# Create additional named containers if needed
another_container = DependencyContainer.get_instance(name="another_container")
```
from dependency_injection.container import DependencyContainer

### Registering Dependencies with Scopes

```python
# Register a transient dependency (a new instance every time)
dependency_container.register_transient(Connection, PostgresConnection)
# Define an abstract Connection
class Connection:
pass

# Register a scoped dependency (a new instance per scope)
dependency_container.register_scoped(Connection, PostgresConnection, scope_name="http_request")
# Define a specific implementation of the Connection
class PostgresConnection(Connection):
def connect(self):
print("Connecting to PostgreSQL database...")

# Register a singleton dependency (a single instance for the container's lifetime)
dependency_container.register_singleton(Connection, PostgresConnection)
```

### Using Constructor Arguments

```python
# Register a dependency with constructor arguments
dependency_container.register_transient(
Connection,
PostgresConnection,
constructor_args={"host": "localhost", "port": 5432}
)
```

### Using Factory Functions

```python
# Define a factory function
def create_connection(host: str, port: int) -> Connection:
return PostgresConnection(host=host, port=port)
# Define a repository that depends on some type of Connection
class UserRepository:
def __init__(self, connection: Connection):
self._connection = connection

# Register the factory function
dependency_container.register_factory(Connection, create_connection, factory_args={"host": "localhost", "port": 5432})
```
def fetch_users(self):
self._connection.connect()
print("Fetching users from the database...")

Besides functions, you can also use lambdas and class functions. Read more in the [documentation](https://py-dependency-injection.readthedocs.io/en/latest/userguide.html#using-factory-functions).
# Get an instance of the (default) DependencyContainer
container = DependencyContainer.get_instance()

### Registering and Using Instances
# Register the specific connection type as a singleton instance
container.register_singleton(Connection, PostgresConnection)

```python
# Create an instance
my_connection = PostgresConnection(host="localhost", port=5432)
# Register UserRepository as a transient (new instance every time)
container.register_transient(UserRepository)

# Register the instance
dependency_container.register_instance(Connection, my_connection)
# Resolve an instance of UserRepository, automatically injecting the required Connection
user_repository = container.resolve(UserRepository)

# Resolve the instance
resolved_connection = dependency_container.resolve(Connection)
print(resolved_connection.host) # Output: localhost
# Use the resolved user_repository to perform an operation
user_repository.find_all()
```

### Registering and Resolving with Tags

```python
# Register dependencies with tags
dependency_container.register_transient(Connection, PostgresConnection, tags={"Querying", "Startable"})
dependency_container.register_scoped(BusConnection, KafkaBusConnection, tags={"Publishing", "Startable"})

# Resolve dependencies by tags
startable_dependencies = dependency_container.resolve_all(tags={"Startable"})
for dependency in startable_dependencies:
dependency.start()
```

### Using Constructor Injection

```python
class OrderRepository:
def __init__(self, connection: Connection):
self.connection = connection

# Register dependencies
dependency_container.register_transient(OrderRepository)
dependency_container.register_singleton(Connection, PostgresConnection)

# Resolve the OrderRepository with injected dependencies
repository = dependency_container.resolve(OrderRepository)
print(repository.connection.__class__.__name__) # Output: PostgresConnection
```
## Documentation

### Using Method Injection
For more advanced usage and examples, please visit our [readthedocs](https://py-dependency-injection.readthedocs.io/en/latest/) page.

```python
class OrderController:
@staticmethod
@inject()
def place_order(order: Order, repository: OrderRepository):
order.status = "placed"
repository.save(order)

# Register the dependency
dependency_container.register_transient(OrderRepository)
dependency_container.register_singleton(Connection, PostgresConnection)

# Use method injection to inject the dependency
my_order = Order.create()
OrderController.place_order(order=my_order) # The repository instance will be automatically injected
```
## License

You can also specify container and scope using the decorator arguments `container_name` and `scope_name`.
`py-dependency-injection` is released under the GPL 3 license. See [LICENSE](LICENSE) for more details.

## Documentation
## Source Code

For the latest documentation, visit [readthedocs](https://py-dependency-injection.readthedocs.io/en/latest/).
You can find the source code for `py-dependency-injection` on [GitHub](https://github.com/runemalm/py-dependency-injection).

## Contribution
## Release Notes

To contribute, create a pull request on the develop branch following the [git flow](https://nvie.com/posts/a-successful-git-branching-model/) branching model.
### [1.0.0-alpha.8](https://github.com/runemalm/py-dependency-injection/releases/tag/v1.0.0-alpha.8) (2024-06-07)

## Release Notes
- Bug Fix: Fixed an issue in the dependency resolution logic where registered constructor arguments were not properly merged with automatically injected dependencies. This ensures that constructor arguments specified during registration are correctly combined with dependencies resolved by the container.

### [1.0.0-alpha.7](https://github.com/runemalm/py-dependency-injection/releases/tag/v1.0.0-alpha.7) (2024-03-24)

- Documentation Update: Updated the documentation to provide clearer instructions and more comprehensive examples.
- Preparing for Beta Release: Made necessary adjustments and refinements in preparation for the upcoming first beta release.

This release focuses on enhancing the documentation and making final preparations for the transition to the beta phase. If you have any more updates or need further assistance, feel free to reach out!

### [1.0.0-alpha.6](https://github.com/runemalm/py-dependency-injection/releases/tag/v1.0.0-alpha.6) (2024-03-23)

- Factory Registration: Added support for registering dependencies using factory functions for dynamic instantiation.
Expand Down
67 changes: 0 additions & 67 deletions docs/concepts.rst

This file was deleted.

4 changes: 2 additions & 2 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
version = "1.0"

# The full version, including alpha/beta/rc tags
release = "1.0.0-alpha.7"
release = "1.0.0-alpha.8"


# -- General configuration ---------------------------------------------------
Expand Down Expand Up @@ -84,6 +84,6 @@
html_static_path = ["_static"]

intersphinx_mapping = {
"python": ("https://docs.python.org/", None),
"python": ("https://docs.python.org/3", None),
"sqlalchemy": ("http://docs.sqlalchemy.org/en/latest/", None),
}
Loading
Loading