Repository navigation
Expand file tree
/
Copy pathequable.py
More file actions
76 lines (60 loc) · 1.83 KB
/
Copy pathequable.py
File metadata and controls
76 lines (60 loc) · 1.83 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
from abc import abstractmethod
from collections.abc import Sequence
from typing import ClassVar, TypeVar, final
from returns.primitives.laws import (
Law,
Law1,
Law2,
Law3,
Lawful,
LawSpecDef,
law_definition,
)
_EqualType = TypeVar('_EqualType', bound='Equable')
@final
class _LawSpec(LawSpecDef):
"""
Equality laws.
Description: https://bit.ly/34D40iT
"""
__slots__ = ()
@law_definition
def reflexive_law(
first: _EqualType,
) -> None:
"""Value should be equal to itself."""
assert first.equals(first)
@law_definition
def symmetry_law(
first: _EqualType,
second: _EqualType,
) -> None:
"""If ``A == B`` then ``B == A``."""
assert first.equals(second) == second.equals(first)
@law_definition
def transitivity_law(
first: _EqualType,
second: _EqualType,
third: _EqualType,
) -> None:
"""If ``A == B`` and ``B == C`` then ``A == C``."""
# We use this notation, because `first` might be equal to `third`,
# but not to `second`. Example: Some(1), Some(2), Some(1)
if first.equals(second) and second.equals(third):
assert first.equals(third)
class Equable(Lawful['Equable']):
"""
Interface for types that can be compared with real values.
Not all types can, because some don't have the value at a time:
- ``Future`` has to be awaited to get the value
- ``Reader`` has to be called to get the value
"""
__slots__ = ()
_laws: ClassVar[Sequence[Law]] = (
Law1(_LawSpec.reflexive_law),
Law2(_LawSpec.symmetry_law),
Law3(_LawSpec.transitivity_law),
)
@abstractmethod
def equals(self: _EqualType, other: _EqualType) -> bool:
"""Type-safe equality check for values of the same type."""