From 91c81056883ab88706a1a99febb88c6077dd7cac Mon Sep 17 00:00:00 2001 From: yakimka Date: Wed, 24 Apr 2024 00:45:46 +0300 Subject: [PATCH] Fix context manager error (#10) --- CHANGELOG.md | 4 ++++ Dockerfile | 2 +- picodi/picodi.py | 33 ++++++++++++++++++++++++--------- pyproject.toml | 2 +- 4 files changed, 30 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 511d572..0801852 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,3 +6,7 @@ We follow [Semantic Versions](https://semver.org/). ## Version 0.1.0 - Initial release + +## Version 0.1.1 + +- Fix context manager error diff --git a/Dockerfile b/Dockerfile index 753b09b..9d0ae59 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ FROM python:3.11-slim-bullseye as builder -ARG WHEEL=picodi-0.1.0-py3-none-any.whl +ARG WHEEL=picodi-0.1.1-py3-none-any.whl ENV VENV=/venv ENV PATH="$VENV/bin:$PATH" diff --git a/picodi/picodi.py b/picodi/picodi.py index 066135a..3af9bc2 100644 --- a/picodi/picodi.py +++ b/picodi/picodi.py @@ -163,7 +163,7 @@ def get_db(): return fn -def init_resources() -> Awaitable: +def init_resources() -> Awaitable | None: """ Call this function to close all resources. Usually, it should be called when your application is shutting down. @@ -177,23 +177,30 @@ def init_resources() -> Awaitable: else: _get_value_from_depends(depends, _exit_stack) - return asyncio.gather(*async_resources) + if _is_async_environment(): + return asyncio.gather(*async_resources) + return None -def shutdown_resources() -> Awaitable: +def shutdown_resources() -> Awaitable | None: """ Call this function to close all resources. Usually, it should be called when your application is shutting down. """ _exit_stack.close() - return _async_exit_stack.aclose() + if _is_async_environment(): + return _async_exit_stack.aclose() + return None + + +CallableManager = Callable[..., AsyncContextManager | ContextManager] @dataclass(frozen=True) class Depends: dependency: Dependency use_cache: bool - context_manager: ContextManager | AsyncContextManager | None = field(compare=False) + context_manager: CallableManager | None = field(compare=False) is_async: bool = field(compare=False) def get_scope_name(self) -> str: @@ -201,18 +208,18 @@ def get_scope_name(self) -> str: def value_as_context_manager(self) -> Any: if self.context_manager: - return self.context_manager + return self.context_manager() return nullcontext(self.dependency()) @classmethod def from_dependency(cls, dependency: Dependency, use_cache: bool) -> Depends: - context_manager: ContextManager | AsyncContextManager | None = None + context_manager: Callable | None = None is_async = False if inspect.isasyncgenfunction(dependency): - context_manager = asynccontextmanager(dependency)() + context_manager = asynccontextmanager(dependency) is_async = True elif inspect.isgeneratorfunction(dependency): - context_manager = contextmanager(dependency)() + context_manager = contextmanager(dependency) return cls(dependency, use_cache, context_manager, is_async) @@ -280,3 +287,11 @@ async def _get_value_from_depends_async( value = exit_stack.enter_context(context_manager) scope.set(depends.dependency, value) return value + + +def _is_async_environment() -> bool: + try: + asyncio.get_running_loop() + except RuntimeError: + return False + return True diff --git a/pyproject.toml b/pyproject.toml index ce6e483..4ddf354 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ build-backend = "poetry.core.masonry.api" [tool.poetry] name = "picodi" description = "Simple Dependency Injection for Python" -version = "0.1.0" +version = "0.1.1" license = "MIT" authors = [ "yakimka"