Skip to content

Commit

Permalink
Merge pull request #1 from plathanus-tech/feature/provider-modules
Browse files Browse the repository at this point in the history
Feature/provider modules
  • Loading branch information
leandrodesouzadev committed Jun 29, 2022
2 parents 17d5b3a + b27eeea commit a14e5e5
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 7 deletions.
36 changes: 36 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -230,9 +230,45 @@ def provider_func():

```

When one defines a `provider` this provider function requires to be imported so that inject-it is aware of this provider. Usually, you can do this on your application entrypoint, a `main.py` file for example. However, it may feel weird importing a module only for registering purposes, and your IDE will tell you that you imported a module, but never used it. For example:

```python
# main.py
from your_application import providers # <- Imported, but unused in this scope

def main():
print("Do stuff")
...

main()
```

`inject-it` allows you to register your providers in a more fashion way. It's similar to what's Django does with applications.

## Register Providers Modules

Since importing a provider file in runtime just for registering may feel ackward, as mentioned above, `inject-it` exposes a `register_provider_modules` function that one can use to register all its providers on a single call. Using the same example from above, it will look like:

```python
from inject_it import register_provider_modules

def main():
print("Do stuff")
...

register_provider_modules(
"your_application.providers",
"your_application.another_module.my_providers",
)
main()
```

`register_provider_modules` any number of providers modules, it will look for any function decorated with `provider` in those modules. If no provider is found an exception is raised.

## Limitations

For the moment, you can only have one dependency for each type. So you can't have like two different `str` dependencies. When you register the second `str` you will be overriding the first. You can work around this by using specific types, instead of primitive types.
In the moment, you can't use functions as dependencies.

## Testing

Expand Down
6 changes: 5 additions & 1 deletion inject_it/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,8 @@
InvalidFunctionSignature,
InjectedKwargAlreadyGiven,
)
from .register import register_dependency, additional_kwargs_to_provider
from .register import (
register_dependency,
additional_kwargs_to_provider,
register_provider_modules,
)
21 changes: 19 additions & 2 deletions inject_it/register.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import importlib
from contextlib import contextmanager
import contextlib
from functools import partial
from typing import Any, Optional

from .objects import Provider
from .stubs import Class, Function
from .exceptions import DependencyNotRegistered, InvalidDependency
from .exceptions import InvalidDependency


def register_dependency(obj: Any, bound_type: Optional[Class] = None) -> None:
Expand Down Expand Up @@ -62,3 +63,19 @@ def additional_kwargs_to_provider(type_: Class, **kwargs):
)
yield
providers[type_] = provider


def register_provider_modules(*modules: str):
"""Shortcut to register all given modules with providers functions.
The given modules are passed directly to `importlib.import_module', so it must be a valid namespace.
If no `provider` is registered in a module, then raises `InvalidDependency`.
"""
from ._injector import providers

for mod in modules:
n_of_providers = len(providers)
importlib.import_module(mod)
if len(providers) == n_of_providers:
raise InvalidDependency(
f"No provider was registered on {mod=} Did you forgot the `provider` decorator?"
)
8 changes: 4 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
[project]
name = "inject-it"
version = "0.2.2"
version = "0.3.0"
description = """\
Dependency injection done easy using python decorators! `inject-it` it's a python pure injection system.\
You can checkout the extended version of the documentation on [GitHub](https://github.com/plathanus-tech/python-inject-it)\
Dependency injection done easy using python decorators!
"""
readme = "README.md"
authors = [
{name = "Leandro de Souza", email = "leandrodesouzadev@gmail.com"},
]
Expand All @@ -14,7 +14,7 @@ requires-python = ">=3.9"

[project.urls]
Homepage = "https://github.com/plathanus-tech/python-inject-it"
download_url = "https://github.com/plathanus-tech/python-inject-it/releases/tag/v0.2.2"
download_url = "https://github.com/plathanus-tech/python-inject-it/releases/tag/v0.3.0"

[project.optional-dependencies]
[tool.pdm]
Expand Down
6 changes: 6 additions & 0 deletions tests/test_register.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
provider,
requires,
additional_kwargs_to_provider,
register_provider_modules,
)
from tests.conftest import T

Expand Down Expand Up @@ -45,3 +46,8 @@ def f(c: Client):
# should fail.
with pytest.raises(exc.InvalidDependency):
f()


def test_register_provider_modules_raises_for_no_provider_in_module():
with pytest.raises(exc.InvalidDependency):
register_provider_modules("tests.test_decorators")

0 comments on commit a14e5e5

Please sign in to comment.