diff --git a/README.md b/README.md index e89e15f..6f118bd 100644 --- a/README.md +++ b/README.md @@ -118,22 +118,23 @@ bar('world') ## Usage with Django Django can load some modules multiple times which can lead to -`InjectorException: Injector is already configured`. You can use `configure_once` which +`InjectorException: Injector is already configured`. You can use `configure(once=True)` which is guaranteed to run only once when the injector is absent: ```python import inject -inject.configure_once(my_config) +inject.configure(my_config, once=True) ``` ## Testing -In tests use `inject.clear_and_configure(callable)` to create a new injector on setup, +In tests use `inject.configure(callable, clear=True)` to create a new injector on setup, and optionally `inject.clear()` to clean up on tear down: ```python class MyTest(unittest.TestCase): def setUp(self): - inject.clear_and_configure(lambda binder: binder + inject.configure(lambda binder: binder .bind(Cache, MockCache()) \ - .bind(Validator, TestValidator())) + .bind(Validator, TestValidator()), + clear=True) def tearDown(self): inject.clear() @@ -155,7 +156,7 @@ You can reuse configurations and override already registered dependencies to fit binder.bind(Validator, TestValidator()) binder.bind(Cache, MockCache()) - inject.clear_and_configure(tests_config, allow_override=True) + inject.configure(tests_config, allow_override=True, clear=True) ``` @@ -220,8 +221,7 @@ to bind an instance to a class, `inject` will try to implicitly instantiate it. If an instance is unintentionally created with default arguments it may lead to hard-to-debug bugs. To disable runtime binding and make sure that only -explicitly bound instances are injected, pass `bind_in_runtime=False` -to `inject.configure`, `inject.configure_once` or `inject.clear_and_configure`. +explicitly bound instances are injected, pass `bind_in_runtime=False` to `inject.configure`. In this case `inject` immediately raises `InjectorException` when the code tries to get an unbound instance. diff --git a/src/inject/__init__.py b/src/inject/__init__.py index 7100b1c..ebdac22 100644 --- a/src/inject/__init__.py +++ b/src/inject/__init__.py @@ -362,14 +362,26 @@ def injection_wrapper(*args: Any, **kwargs: Any) -> T: def configure( - config: Optional[BinderCallable] = None, bind_in_runtime: bool = True, allow_override: bool = False + config: Optional[BinderCallable] = None, + bind_in_runtime: bool = True, + allow_override: bool = False, + clear: bool = False, + once: bool = False ) -> Injector: """Create an injector with a callable config or raise an exception when already configured.""" global _INJECTOR + if clear and once: + raise InjectorException('clear and once are mutually exclusive, only one can be True') + with _INJECTOR_LOCK: if _INJECTOR: - raise InjectorException('Injector is already configured') + if clear: + _clear_injector() + elif once: + return _INJECTOR + else: + raise InjectorException('Injector is already configured') _INJECTOR = Injector(config, bind_in_runtime=bind_in_runtime, allow_override=allow_override) logger.debug('Created and configured an injector, config=%s', config) @@ -377,9 +389,14 @@ def configure( def configure_once( - config: Optional[BinderCallable] = None, bind_in_runtime: bool = True, allow_override: bool = False + config: Optional[BinderCallable] = None, + bind_in_runtime: bool = True, + allow_override: bool = False ) -> Injector: - """Create an injector with a callable config if not present, otherwise, do nothing.""" + """Create an injector with a callable config if not present, otherwise, do nothing. + + Deprecated, use `configure(once=True)` instead. + """ with _INJECTOR_LOCK: if _INJECTOR: return _INJECTOR @@ -388,11 +405,16 @@ def configure_once( def clear_and_configure( - config: Optional[BinderCallable] = None, bind_in_runtime: bool = True, allow_override: bool = False + config: Optional[BinderCallable] = None, + bind_in_runtime: bool = True, + allow_override: bool = False ) -> Injector: - """Clear an existing injector and create another one with a callable config.""" + """Clear an existing injector and create another one with a callable config. + + Deprecated, use configure(clear=True) instead. + """ with _INJECTOR_LOCK: - clear() + _clear_injector() return configure(config, bind_in_runtime=bind_in_runtime, allow_override=allow_override) @@ -403,6 +425,11 @@ def is_configured() -> bool: def clear() -> None: + """Clear an existing injector if present.""" + _clear_injector() + + +def _clear_injector() -> None: """Clear an existing injector if present.""" global _INJECTOR @@ -413,6 +440,7 @@ def clear() -> None: _INJECTOR = None logger.debug('Cleared an injector') + @overload def instance(cls: Type[T]) -> T: ...