Skip to content

Commit

Permalink
Beginnig of check contract, marked ignores with the corresponding myp…
Browse files Browse the repository at this point in the history
…y bug

python/mypy#14806 8 times
python/mypy#14785 2 times
  • Loading branch information
magwas committed Mar 1, 2023
1 parent 2f364ba commit 13ea527
Show file tree
Hide file tree
Showing 16 changed files with 51 additions and 48 deletions.
5 changes: 2 additions & 3 deletions src/Shall.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@

from typing import Callable, Concatenate, Generic, ParamSpec, Self, TypeVar
from typing import Callable, Generic

from shall.SideEffectChecker import SideEffectChecker
from shall.ShallEntity import ShallEntity, P, R
from shall.ShallEntity import P, R
from shall.When import When
from shall.IfCalledWith import IfCalledWith
from shall.ThenReturn import ThenReturn
Expand Down
7 changes: 1 addition & 6 deletions src/shall/Check.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
from typing import TypeVar, ParamSpec, Self

from shall.ShallEntity import ShallEntity

P = ParamSpec("P")
R = TypeVar("R")

from shall.ShallEntity import ShallEntity, P, R

class Check(ShallEntity[P, R]):
def check(self) -> None:
Expand Down
2 changes: 1 addition & 1 deletion src/shall/IfCalledWith.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import TypeVar, ParamSpec, Self
from typing_extensions import Self

from shall.ShallEntity import ShallEntity, P, R

Expand Down
2 changes: 1 addition & 1 deletion src/shall/MeanWhile.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import TypeVar, ParamSpec, Self
from typing_extensions import Self

from shall.ShallEntity import ShallEntity, P, R
from shall.SideEffectChecker import SideEffectChecker
Expand Down
2 changes: 1 addition & 1 deletion src/shall/ShallConstructor.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import TypeVar, ParamSpec, Self, Callable
from typing import Callable

from shall.ShallEntity import ShallEntity, P, R

Expand Down
5 changes: 3 additions & 2 deletions src/shall/ShallEntity.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from typing import Callable, Concatenate, Generic, ParamSpec, TypeVar, TypedDict
from typing import Callable, Generic, TypeVar
from typing_extensions import ParamSpec, Concatenate

from shall.SideEffectChecker import SideEffectChecker

Expand All @@ -9,6 +10,6 @@ class ShallEntity(Generic[P, R]):
callable: Callable[P, R]
returnConstraints: list[tuple[str, Callable[Concatenate[R, P], bool]]]
sideEffectCheckers: list[tuple[str, SideEffectChecker[P, R]]]
parameters: tuple[P.args, P.kwargs] #type:ignore
parameters: tuple[P.args, P.kwargs]
returnValue: R
explanation: str
4 changes: 2 additions & 2 deletions src/shall/SideEffectChecker.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from typing import Callable, Generic, ParamSpec, TypeVar
from typing import Callable, Generic, TypeVar
from typing_extensions import ParamSpec

P = ParamSpec("P")
R = TypeVar("R")


class SideEffectChecker(Generic[P, R]):

def setUp(self, service: Callable[P, R], *
Expand Down
3 changes: 2 additions & 1 deletion src/shall/SuchThat.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from typing import TypeVar, ParamSpec, Self, Callable, Concatenate
from typing import Callable
from typing_extensions import Self, Concatenate

from shall.ShallEntity import ShallEntity, P, R

Expand Down
3 changes: 2 additions & 1 deletion src/shall/ThenReturn.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from typing import TypeVar, ParamSpec, Self

from typing_extensions import Self

from shall.ShallEntity import ShallEntity, P, R

Expand Down
2 changes: 1 addition & 1 deletion src/shall/When.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import TypeVar, ParamSpec, Self
from typing_extensions import Self

from shall.ShallEntity import ShallEntity, P, R

Expand Down
17 changes: 12 additions & 5 deletions test/CheckContract.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,29 @@
from typing import Callable, cast
from unittest.mock import Mock
from Shall import Shall
from shall.Check import Check
from shall.ShallConstructor import ShallConstructor

def callable(a:int)-> str:
return str(a)
def check(returnValue: None, self: Check[[int],str] ) -> bool:
mock = cast(Mock,self.callable)
mock.assert_called_once()
return True

class CheckContract:
callableMock:Callable[[int], str] = Mock()
cast(Mock,callableMock).return_value="2"
selfMock= Mock()
selfMock.callable = callable
selfMock.callable = callableMock
selfMock.parameters = ((2,),{})
selfMock.returnValue = "2"
selfMock.explanation = "explanation"
selfMock.returnConstraints = list()
selfMock.sideEffectCheckers = list()

rules = [(
Shall("checks the contract", Check[[int],str].check)
Shall[[Check[[int],str]],None]("checks the contract", Check[[int],str].check) #type:ignore #https://github.com/python/mypy/issues/14806
.ifCalledWith(selfMock)
.thenReturn(None)
)]
.suchThat("the callable is called", check)
)]

2 changes: 1 addition & 1 deletion test/ExampleContract.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class ExampleContract:
"The return value is twice the input",
lambda returnValue, self, value: returnValue == 2 * value)
# mypy does not think that "ExampleChecker" is a SideEffectChecker[[ExampleService, int], int]
.meanWhile("Prints the result", ExampleChecker()) #type:ignore
.meanWhile("Prints the result", ExampleChecker()) #type:ignore #https://github.com/python/mypy/issues/14785

)
]
15 changes: 8 additions & 7 deletions test/IfCalledWithContract.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
from typing import Any, Callable, List, Self, Unpack
from typing import Any
from unittest.mock import MagicMock
from Shall import Shall
from shall.IfCalledWith import IfCalledWith
from shall.ShallEntity import ShallEntity, P, R

def checker(returnValue:Any, self:ShallEntity[P,R], otherparam: int, foo: str) -> bool:
def checker(returnValue:IfCalledWith[[int, str], None], self:IfCalledWith[[int, str], None], otherparam: int, foo: str) -> bool:
expected = ((1,), {'foo': 'bar'})
return self.parameters == expected

class IfCalledWithContract:
mockSelf:IfCalledWith[[int, str], None] = MagicMock()
rules = [(
Shall("defines the parameters with which the SUT is called",
IfCalledWith[[int,str], None].ifCalledWith) #type:ignore
.ifCalledWith(mockSelf,1,foo="bar") #type:ignore
.thenReturn(mockSelf) #type:ignore
.suchThat("registers the return value", checker) #type:ignore
Shall[IfCalledWith[[int,str], None],IfCalledWith[[int,str], None]](
"defines the parameters with which the SUT is called",
IfCalledWith[[int,str], None].ifCalledWith) #type: ignore #https://github.com/python/mypy/issues/14806
.ifCalledWith(mockSelf,1,foo="bar") #type:ignore # https://github.com/python/mypy/issues/14806
.thenReturn(mockSelf)
.suchThat("registers the return value", checker) #type: ignore # https://github.com/python/mypy/issues/14806
)]

18 changes: 8 additions & 10 deletions test/MeanWhileContract.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,18 @@
from shall.ShallEntity import ShallEntity
from shall.SideEffectChecker import SideEffectChecker

# crashes mypy
#def checker(returned: int, self:ShallEntity[[int], int], explanation: str, checker: SideEffectChecker[[ExampleService, int], int]) -> bool:
# return self.sideEffectCheckers == [(explanation, checker)]

def checker(returned: int, self:Any, explanation: str, checker: Any) -> bool:
return self.sideEffectCheckers == [(explanation, checker)] #type:ignore

def checker(returned: ShallEntity[[int], int], self:ShallEntity[[int], int], explanation: str, checker: SideEffectChecker[[ExampleService, int], int]) -> bool:
return self.sideEffectCheckers == [(explanation, checker)]

class MeanWhileContract:
selfMock:ShallEntity[[int], int] = Mock()
selfMock.sideEffectCheckers = []
rules = [(
Shall("Registers side effects", MeanWhile[[int],int].meanWhile) #type:ignore
.ifCalledWith(selfMock, "explanation", ExampleChecker) #type:ignore
Shall("Registers side effects", MeanWhile[[int],int].meanWhile)
.ifCalledWith(selfMock, "explanation", ExampleChecker) #type: ignore # https://github.com/python/mypy/issues/14785
.thenReturn(selfMock)
.suchThat("registers the side efect checker", checker) #type:ignore
.suchThat("registers the side effect checker", checker) #type: ignore #
)]

#"Callable[[ShallEntity[[int], int], ShallEntity[[int], int], str, SideEffectChecker[[ExampleService, int], int]], bool]"; expected
#"Callable[[ShallEntity[[int], int], ShallEntity[[int], int], str, SideEffectChecker[[ShallEntity[[int], int], str, SideEffectChecker[[ShallEntity[[int], int], str, SideEffectChecker[[ShallEntity[[int], int], str, SideEffectChecker[P, R]], R]], R]], R]], bool]"
6 changes: 3 additions & 3 deletions test/SuchThatContract.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ def realChecker(returnValue:str, self:SuchThat[[int],int], explanation: str, che


class SuchThatContract:
selfMock = Mock()
selfMock:SuchThat[[int],str] = Mock()
selfMock.returnConstraints = []
rules = [(
Shall("Registers side effects", SuchThat[[int],str].suchThat)
.ifCalledWith(selfMock, "explanation", checkerTestArtifact) #type:ignore
.ifCalledWith(selfMock, "explanation", checkerTestArtifact) #type:ignore #https://github.com/python/mypy/issues/14806
.thenReturn(selfMock)
.suchThat("Registers the side effect check and explanation", realChecker) #type:ignore
.suchThat("Registers the side effect check and explanation", realChecker) #type:ignore #https://github.com/python/mypy/issues/14806
)]
6 changes: 3 additions & 3 deletions test/ThenreturnContract.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
class ThenreturnContract:
mockSelf:ThenReturn[[int],str] = Mock()
rules = [(
Shall("Registers the return value", ThenReturn[[int],str].thenReturn) #type:ignore
.ifCalledWith(mockSelf,"42") #type: ignore
Shall("Registers the return value", ThenReturn[[int],str].thenReturn)
.ifCalledWith(mockSelf,"42") #type:ignore #https://github.com/python/mypy/issues/14806
.thenReturn(mockSelf)
.suchThat("the return value is registered", lambda returnValue, self, givenValue: self.returnValue == givenValue) #type:ignore
.suchThat("the return value is registered", lambda returnValue, self, givenValue: self.returnValue == givenValue) #type:ignore #https://github.com/python/mypy/issues/14806
)]

0 comments on commit 13ea527

Please sign in to comment.