diff --git a/README.md b/README.md index 543ad0e..f8af596 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/inject_it/__init__.py b/inject_it/__init__.py index 6193e39..fc7b8d7 100644 --- a/inject_it/__init__.py +++ b/inject_it/__init__.py @@ -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, +) diff --git a/inject_it/register.py b/inject_it/register.py index 6bcf58d..ebd0e1b 100644 --- a/inject_it/register.py +++ b/inject_it/register.py @@ -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: @@ -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?" + ) diff --git a/pyproject.toml b/pyproject.toml index 4d13dfb..a90051c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -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"}, ] @@ -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] diff --git a/tests/test_register.py b/tests/test_register.py index 5a7ea55..006e33b 100644 --- a/tests/test_register.py +++ b/tests/test_register.py @@ -5,6 +5,7 @@ provider, requires, additional_kwargs_to_provider, + register_provider_modules, ) from tests.conftest import T @@ -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")