Commit c3e8651f authored by Dom Sekotill's avatar Dom Sekotill
Browse files

Merge branch '1-enable-paramspec-usage' into 'main'

Switch to ParamSpec in behave.fixture stub

Closes #1

See merge request !3
parents 0b8483dc c2dfeb6d
Loading
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -87,7 +87,7 @@ repos:
    - flake8-sfs

- repo: https://github.com/pre-commit/mirrors-mypy
  rev: v0.942
  rev: v0.950
  hooks:
  - id: mypy
    args: [--follow-imports=silent]
+2 −3
Original line number Diff line number Diff line
#  Copyright 2021  Dominik Sekotill <dom.sekotill@kodo.org.uk>
#  Copyright 2021, 2022  Dominik Sekotill <dom.sekotill@kodo.org.uk>
#
#  This Source Code Form is subject to the terms of the Mozilla Public
#  License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -14,7 +14,6 @@ from contextlib import contextmanager
from pathlib import Path
from time import sleep
from typing import TYPE_CHECKING
from typing import Any
from typing import Iterator
from typing import Sequence

@@ -108,7 +107,7 @@ class Mysql(Container):


@fixture
def snapshot_rollback(context: FeatureContext, /, database: Mysql|None = None, *a: Any, **k: Any) -> Iterator[None]:
def snapshot_rollback(context: FeatureContext, /, database: Mysql|None = None) -> Iterator[None]:
	"""
	Manage the state of a database as a revertible fixture

+20 −61
Original line number Diff line number Diff line
from typing import Any
from collections.abc import Callable
from typing import Iterator
from typing import Protocol
from typing import TypeVar
from typing import overload

from .runner import Context

C = TypeVar("C", bound=Context)
C_con = TypeVar("C_con", bound=Context, contravariant=True)

R = TypeVar("R")
R_co = TypeVar("R_co", covariant=True)

P = TypeVar("P", bound=None)
P_co = TypeVar("P_co", covariant=True)  # unused


# There's a lot of @overload-ed functions here as fixtures come in two varieties:
# 1) A @contextlib.contextmanager-like generator that yields an arbitrary object once.
# 2) A simple function that returns an arbitrary object
#
# "use_fixture" allows both types of fixture callables to be used in the same way
from typing_extensions import Concatenate
from typing_extensions import ParamSpec

# Without ParamSpec no checking is done to ensure the arguments passed to use_fixture
# match the fixture's arguments; fixtures must be able to handle arguments not being
# supplied (except the context); and fixtures must accept ANY arbitrary keyword
# arguments.


class FixtureCoroutine(Protocol[C_con, P_co, R_co]):
	def __call__(self, _: C_con, /, *__a: Any, **__k: Any) -> Iterator[R_co]: ...
from .runner import Context

class FixtureFunction(Protocol[C_con, P_co, R_co]):
	def __call__(self, _: C_con, /, *__a: Any, **__k: Any) -> R_co: ...
ContextT = TypeVar("ContextT", bound=Context, contravariant=True)
ReturnT = TypeVar("ReturnT", covariant=True)
Params = ParamSpec("Params")


@overload
def use_fixture(
	fixture_func: FixtureCoroutine[C_con, P_co, R_co],
	context: C_con,
	*a: Any,
	**k: Any,
) -> R_co: ...
	fixture_func: Callable[Concatenate[ContextT, Params], Iterator[ReturnT]],
	context: ContextT,
	*args: Params.args,
	**kwargs: Params.kwargs,
) -> ReturnT: ...

@overload
def use_fixture(
	fixture_func: FixtureFunction[C_con, P_co, R_co],
	context: C_con,
	*a: Any,
	**k: Any,
) -> R_co: ...
	fixture_func: Callable[Concatenate[ContextT, Params], ReturnT],
	context: ContextT,
	*args: Params.args,
	**kwargs: Params.kwargs,
) -> ReturnT: ...


# "fixture" is a decorator used to mark both types of fixture callables. It can also return
# a decorator, when called without the "func" argument.

@overload
def fixture(
	func: FixtureCoroutine[C, P, R],
	func: Callable[Params, ReturnT],
	name: str = ...,
	pattern: str = ...,
) -> FixtureCoroutine[C, P, R]: ...
) -> Callable[Params, ReturnT]: ...

@overload
def fixture(
	func: FixtureFunction[C, P, R],
	name: str = ...,
	pattern: str = ...,
) -> FixtureFunction[C, P, R]: ...

@overload
def fixture(
	name: str = ...,
	pattern: str = ...,
) -> FixtureDecorator: ...


class FixtureDecorator(Protocol):

	@overload
	def __call__(self, _: FixtureCoroutine[C, P, R], /) -> FixtureCoroutine[C, P, R]: ...

	@overload
	def __call__(self, _: FixtureFunction[C, P, R], /) -> FixtureFunction[C, P, R]: ...
) -> Callable[[Callable[Params, ReturnT]], Callable[Params, ReturnT]]: ...