Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: Protocol support #54

Merged
merged 10 commits into from
Apr 15, 2024
10 changes: 5 additions & 5 deletions .github/workflows/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python 3.7
- name: Set up Python 3.8
uses: actions/setup-python@v2
with:
python-version: 3.7
python-version: 3.8
- name: Install dependencies
run: |
python -m pip install --upgrade pip
Expand All @@ -25,19 +25,19 @@ jobs:
- name: Linting
run: |
poetry run isort -c setup.cfg
poetry run black --line-length=120 --target-version py37 kink
poetry run black --line-length=120 --target-version py38 kink
poetry run mypy kink

tests:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [ 3.7, 3.8, 3.9 ]
python-version: [ "3.7", "3.8", "3.9", "3.10", "3.11", "3.12" ]
jarey marked this conversation as resolved.
Show resolved Hide resolved

steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
Expand Down
6 changes: 2 additions & 4 deletions kink/container.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,10 @@ def add_alias(self, name: Union[str, Type], target: Union[str, Type]):
self._aliases[name].append(target)

@overload
def __getitem__(self, key: str) -> Any:
...
def __getitem__(self, key: str) -> Any: ...

@overload
def __getitem__(self, key: Type[T]) -> T:
...
def __getitem__(self, key: Type[T]) -> T: ...

def __getitem__(self, key):
if key in self._factories:
Expand Down
15 changes: 8 additions & 7 deletions kink/inject.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from abc import ABC
from functools import wraps
from inspect import Parameter as InspectParameter, isclass, signature
from typing import Any, Callable, Dict, NewType, Tuple, Type, TypeVar, Union, ForwardRef # type: ignore
from typing import Any, Callable, Dict, NewType, Tuple, Type, TypeVar, Union, ForwardRef, Optional # type: ignore

from typing_extensions import Protocol

Expand Down Expand Up @@ -101,9 +101,10 @@ def _resolve_function_kwargs(
def _decorate(binding: Dict[str, Any], service: ServiceDefinition, container: Container) -> ServiceResult:

# ignore abstract class initialiser and protocol initialisers
if (
service in [ABC.__init__, _no_init] or service.__name__ == "_no_init"
): # FIXME: fix this when typing_extensions library gets fixed
if service in [ABC.__init__, _no_init] or service.__name__ in [
"_no_init",
"_no_init_or_replace_init",
]: # FIXME: fix this when typing_extensions library gets fixed
return service

# Add class definition to dependency injection
Expand Down Expand Up @@ -166,9 +167,9 @@ async def _async_decorated(*args, **kwargs):


def inject(
_service: ServiceDefinition = None,
alias: Any = None,
bind: Dict[str, Any] = None,
_service: Optional[ServiceDefinition] = None,
alias: Optional[Any] = None,
bind: Optional[Dict[str, Any]] = None,
container: Container = di,
use_factory: bool = False,
) -> Union[ServiceResult, Callable[[ServiceDefinition], ServiceResult]]:
Expand Down
781 changes: 375 additions & 406 deletions poetry.lock

Large diffs are not rendered by default.

19 changes: 10 additions & 9 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,18 @@ include = ["kink/py.typed"]

# Requirements
[tool.poetry.dependencies]
python = "^3.7"
typing_extensions = "^4.1.1"
python = "^3.8"
typing_extensions = "^4.9.0"


[tool.poetry.dev-dependencies]
isort = "^5.7.0"
pytest = "^5.4.3"
pytest-asyncio = "^0.14.0"
pytest-cov = "^2.5"
isort = "^5.13.2"
pytest = "^8.0.0"
pytest-asyncio = "^0.23.5"
pytest-cov = "^4.1.0"
requests = "^2.31.0"
starlette = "^0.13.4"
black = "^22.3.0"
mypy = "^0.961"
starlette = "^0.37.1"
httpx = "^0.26.0"
black = "^24.2.0"
mypy = "^1.8.0"

1 change: 0 additions & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
[tool:pytest]
testpaths = tests
timeout = 10

[black]
line_length=120
Expand Down
40 changes: 33 additions & 7 deletions tests/test_issue_aliased_factory.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,42 @@
from abc import ABC
from typing import Protocol, List

from kink import inject, di

class Repository:
pass

class Repository(Protocol):
def __init__(self) -> None:
pass


@inject(alias=Repository, use_factory=True)
class PerInstanceRepository(Repository):
pass
pass


@inject(alias=Repository)
class Repository1(Repository):
pass


@inject(alias=Repository)
class Repository2(Repository):
repo: Repository1 = di[Repository1]


@inject
class Service:
def __init__(self, repository: Repository):
pass

def __init__(self, repositories: List[Repository]):
self._repositories = repositories


def test_can_inject_aliased_factory_services():
di[Service]
service: Service = di[Service]
assert service is not None
assert service._repositories is not None
assert len(service._repositories) == 3
repository: Repository = di[Repository2]
assert repository.repo is not None
repositories: List[Repository] = di[List[Repository]]
assert repositories is not None
assert len(repositories) == 3