diff --git a/.github/workflows/setup.yml b/.github/workflows/setup.yml new file mode 100644 index 00000000..c17e74c6 --- /dev/null +++ b/.github/workflows/setup.yml @@ -0,0 +1,42 @@ +# This workflow will install Python dependencies, run tests and lint with a single version of Python +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python + +name: CI + +on: + push: + branches: [ "develop" ] + pull_request: + branches: [ "develop" ] + +jobs: + cpython: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: + - ubuntu-latest + python-version: + - "3.10" + - "3.11" + - "3.12" + + steps: + - uses: actions/checkout@v3 + - name: Set up ${{ matrix.python-version }} on ${{ matrix.os }} + uses: actions/setup-python@v3 + with: + python-version: ${{ matrix.python-version }} + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install . -r requirements_dev.txt + + - name: Run ruff + run: | + ruff check . + + - name: Run tests + run: | + pytest diff --git a/.ruff.toml b/.ruff.toml new file mode 100644 index 00000000..f102c3b4 --- /dev/null +++ b/.ruff.toml @@ -0,0 +1,26 @@ +line-length = 79 +src = ["src"] +include = ["src/**.py", "tests/**.py"] + +select = [ + "E", + "F", + "BLE", + "B", + "COM", + "C4", + "ERA", + "T20", + "I", + "N", + "ASYNC", + "PIE", + "RUF", +] + + +[isort] +no-lines-before = ["local-folder"] + +[flake8-tidy-imports] +ban-relative-imports = "parents" \ No newline at end of file diff --git a/requirements_dev.txt b/requirements_dev.txt new file mode 100644 index 00000000..27de1df4 --- /dev/null +++ b/requirements_dev.txt @@ -0,0 +1,3 @@ +ruff +pytest +pytest-asyncio diff --git a/src/dishka/async_container.py b/src/dishka/async_container.py index 22af4fab..f381100e 100644 --- a/src/dishka/async_container.py +++ b/src/dishka/async_container.py @@ -112,17 +112,17 @@ async def _get_unlocked(self, dependency_type: Type[T]) -> T: async def close(self): e = None - for exit in self.exits: + for exit_generator in self.exits: try: - if exit.type is ProviderType.ASYNC_GENERATOR: - await anext(exit.callable) - elif exit.type is ProviderType.GENERATOR: - next(exit.callable) + if exit_generator.type is ProviderType.ASYNC_GENERATOR: + await anext(exit_generator.callable) + elif exit_generator.type is ProviderType.GENERATOR: + next(exit_generator.callable) except StopIteration: pass except StopAsyncIteration: pass - except Exception as err: + except Exception as err: # noqa: BLE001 e = err if e: raise e @@ -150,5 +150,5 @@ def make_async_container( for scope in scopes ] return AsyncContextWrapper( - AsyncContainer(*registries, context=context, with_lock=with_lock) + AsyncContainer(*registries, context=context, with_lock=with_lock), ) diff --git a/src/dishka/container.py b/src/dishka/container.py index aec2b444..6e239724 100644 --- a/src/dishka/container.py +++ b/src/dishka/container.py @@ -98,12 +98,12 @@ def _get_unlocked(self, dependency_type: Type[T]) -> T: def close(self): e = None - for exit in self.exits: + for exit_generator in self.exits: try: - next(exit) + next(exit_generator) except StopIteration: pass - except Exception as err: + except Exception as err: # noqa: BLE001 e = err if e: raise e @@ -131,5 +131,5 @@ def make_container( for scope in scopes ] return ContextWrapper( - Container(*registries, context=context, with_lock=with_lock) + Container(*registries, context=context, with_lock=with_lock), ) diff --git a/src/dishka/inject.py b/src/dishka/inject.py index aa7eacea..0b661fb1 100644 --- a/src/dishka/inject.py +++ b/src/dishka/inject.py @@ -1,6 +1,11 @@ from inspect import Parameter, Signature, signature from typing import ( - Annotated, Any, Callable, Sequence, get_args, get_origin, + Annotated, + Any, + Callable, + Sequence, + get_args, + get_origin, get_type_hints, ) diff --git a/src/dishka/provider.py b/src/dishka/provider.py index d56932c2..5bf73916 100644 --- a/src/dishka/provider.py +++ b/src/dishka/provider.py @@ -1,12 +1,21 @@ from collections.abc import AsyncIterable, Iterable from enum import Enum from inspect import ( - isasyncgenfunction, isclass, iscoroutinefunction, + isasyncgenfunction, + isclass, + iscoroutinefunction, isgeneratorfunction, ) from typing import ( - Any, Callable, Optional, Sequence, Type, Union, get_args, - get_origin, get_type_hints, + Any, + Callable, + Optional, + Sequence, + Type, + Union, + get_args, + get_origin, + get_type_hints, ) from .scope import BaseScope @@ -33,7 +42,7 @@ def __init__( result_type: Type, scope: Optional[BaseScope], type: ProviderType, - is_to_bound: bool + is_to_bound: bool, ): self.dependencies = dependencies self.callable = callable diff --git a/tests/test_container.py b/tests/test_container.py index 981303d0..21ff9edc 100644 --- a/tests/test_container.py +++ b/tests/test_container.py @@ -1,12 +1,20 @@ import pytest from dishka import ( - Provider, Scope, make_async_container, make_container, + Provider, + Scope, + make_async_container, + make_container, provide, ) from .sample_providers import ( - ClassA, async_func_a, async_gen_a, async_iter_a, - sync_func_a, sync_gen_a, sync_iter_a, + ClassA, + async_func_a, + async_gen_a, + async_iter_a, + sync_func_a, + sync_gen_a, + sync_iter_a, ) @@ -16,7 +24,7 @@ (sync_func_a, False), (sync_iter_a, True), (sync_gen_a, True), - ] + ], ) def test_sync(factory, closed): class MyProvider(Provider): @@ -42,7 +50,7 @@ def get_int(self) -> int: (async_func_a, False), (async_iter_a, True), (async_gen_a, True), - ] + ], ) @pytest.mark.asyncio async def test_async(factory, closed): diff --git a/tests/test_privider.py b/tests/test_privider.py index 8f84de67..612df89e 100644 --- a/tests/test_privider.py +++ b/tests/test_privider.py @@ -3,8 +3,13 @@ from dishka import Provider, Scope, alias, provide from dishka.provider import ProviderType from .sample_providers import ( - ClassA, async_func_a, async_gen_a, async_iter_a, - sync_func_a, sync_gen_a, sync_iter_a, + ClassA, + async_func_a, + async_gen_a, + async_iter_a, + sync_func_a, + sync_gen_a, + sync_iter_a, ) @@ -31,7 +36,7 @@ def foo(self, x: bool) -> str: (async_func_a, ProviderType.ASYNC_FACTORY, True), (async_iter_a, ProviderType.ASYNC_GENERATOR, True), (async_gen_a, ProviderType.ASYNC_GENERATOR, True), - ] + ], ) def test_parse_provider(factory, provider_type, is_to_bound): dep_provider = provide(factory, scope=Scope.REQUEST)