panda-pytest-assertions 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- panda_pytest_assertions/__init__.py +0 -0
- panda_pytest_assertions/assert_context/__init__.py +15 -0
- panda_pytest_assertions/assert_context/_assert_context.py +128 -0
- panda_pytest_assertions/assert_object/__init__.py +41 -0
- panda_pytest_assertions/assert_object/_assert_object.py +36 -0
- panda_pytest_assertions/assert_object/_asserter_factories/__init__.py +8 -0
- panda_pytest_assertions/assert_object/_asserter_factories/asserter_factory.py +66 -0
- panda_pytest_assertions/assert_object/_asserter_factories/built_in_asserter_factory.py +29 -0
- panda_pytest_assertions/assert_object/_converters/__init__.py +10 -0
- panda_pytest_assertions/assert_object/_converters/expectation_from_yaml.py +114 -0
- panda_pytest_assertions/assert_object/_converters/expectation_to_yaml.py +78 -0
- panda_pytest_assertions/assert_object/_expectation_modificators/__init__.py +15 -0
- panda_pytest_assertions/assert_object/_expectation_modificators/mapping_subset.py +15 -0
- panda_pytest_assertions/assert_object/_expectation_modificators/object_attibutes.py +15 -0
- panda_pytest_assertions/assert_object/_expectation_modificators/stringified.py +11 -0
- panda_pytest_assertions/assert_object/_expectation_modificators/unordered.py +18 -0
- panda_pytest_assertions/assert_object/_expectation_modificators/with_type.py +135 -0
- panda_pytest_assertions/assert_object/_objects_asserters/__init__.py +36 -0
- panda_pytest_assertions/assert_object/_objects_asserters/asserter.py +35 -0
- panda_pytest_assertions/assert_object/_objects_asserters/equality_asserter.py +33 -0
- panda_pytest_assertions/assert_object/_objects_asserters/mapping_asserter.py +55 -0
- panda_pytest_assertions/assert_object/_objects_asserters/mapping_subset_asserter.py +53 -0
- panda_pytest_assertions/assert_object/_objects_asserters/object_attributes_asserter.py +52 -0
- panda_pytest_assertions/assert_object/_objects_asserters/ordered_elements_asserter.py +55 -0
- panda_pytest_assertions/assert_object/_objects_asserters/stringified_asserter.py +36 -0
- panda_pytest_assertions/assert_object/_objects_asserters/unordered_elements_asserter.py +77 -0
- panda_pytest_assertions/assert_object/_objects_asserters/with_type_asserter.py +57 -0
- panda_pytest_assertions/assert_object/_protocols.py +93 -0
- panda_pytest_assertions/assert_object/generators/__init__.py +41 -0
- panda_pytest_assertions/assert_object/generators/_expectation_definitions/__init__.py +30 -0
- panda_pytest_assertions/assert_object/generators/_expectation_definitions/equality.py +6 -0
- panda_pytest_assertions/assert_object/generators/_expectation_definitions/mapping.py +14 -0
- panda_pytest_assertions/assert_object/generators/_expectation_definitions/mapping_subset.py +14 -0
- panda_pytest_assertions/assert_object/generators/_expectation_definitions/object_attributes.py +12 -0
- panda_pytest_assertions/assert_object/generators/_expectation_definitions/of_type.py +13 -0
- panda_pytest_assertions/assert_object/generators/_expectation_definitions/stringified.py +4 -0
- panda_pytest_assertions/assert_object/generators/_expectation_definitions/uniform_mapping.py +13 -0
- panda_pytest_assertions/assert_object/generators/_expectation_definitions/uniform_mapping_subset.py +13 -0
- panda_pytest_assertions/assert_object/generators/_expectation_definitions/uniform_ordered.py +39 -0
- panda_pytest_assertions/assert_object/generators/_expectation_definitions/uniform_unordered.py +11 -0
- panda_pytest_assertions/assert_object/generators/_expectation_definitions/union.py +13 -0
- panda_pytest_assertions/assert_object/generators/_expectation_definitions/with_type.py +30 -0
- panda_pytest_assertions/assert_object/generators/_generate_expectation.py +23 -0
- panda_pytest_assertions/assert_object/generators/_generator_factories/__init__.py +8 -0
- panda_pytest_assertions/assert_object/generators/_generator_factories/built_in_generator_factory.py +39 -0
- panda_pytest_assertions/assert_object/generators/_generator_factories/generator_factory.py +66 -0
- panda_pytest_assertions/assert_object/generators/_generators/__init__.py +34 -0
- panda_pytest_assertions/assert_object/generators/_generators/equality_generator.py +35 -0
- panda_pytest_assertions/assert_object/generators/_generators/equality_key_mapping_generator.py +54 -0
- panda_pytest_assertions/assert_object/generators/_generators/exceptions.py +1 -0
- panda_pytest_assertions/assert_object/generators/_generators/generator.py +35 -0
- panda_pytest_assertions/assert_object/generators/_generators/mapping_generator.py +60 -0
- panda_pytest_assertions/assert_object/generators/_generators/mapping_subset_generator.py +57 -0
- panda_pytest_assertions/assert_object/generators/_generators/object_attributes_generator.py +53 -0
- panda_pytest_assertions/assert_object/generators/_generators/of_type_generator.py +47 -0
- panda_pytest_assertions/assert_object/generators/_generators/ordered_generator.py +55 -0
- panda_pytest_assertions/assert_object/generators/_generators/stringified_generator.py +35 -0
- panda_pytest_assertions/assert_object/generators/_generators/uniform_mapping_generator.py +50 -0
- panda_pytest_assertions/assert_object/generators/_generators/uniform_mapping_subset_generator.py +52 -0
- panda_pytest_assertions/assert_object/generators/_generators/uniform_ordered_generator.py +49 -0
- panda_pytest_assertions/assert_object/generators/_generators/union_generator.py +51 -0
- panda_pytest_assertions/assert_object/generators/_generators/unordered_generator.py +46 -0
- panda_pytest_assertions/assert_object/generators/_generators/with_type_generator.py +46 -0
- panda_pytest_assertions/py.typed +0 -0
- panda_pytest_assertions-0.1.0.dist-info/LICENSE +201 -0
- panda_pytest_assertions-0.1.0.dist-info/METADATA +32 -0
- panda_pytest_assertions-0.1.0.dist-info/RECORD +68 -0
- panda_pytest_assertions-0.1.0.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
from typing import Any, Protocol
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class AsserterProtocol(Protocol):
|
|
5
|
+
"""
|
|
6
|
+
Asserter checking that the given expectation is fulfilled by the object.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
expectation: Any
|
|
10
|
+
asserter_factory: 'type[AsserterFactoryProtocol]'
|
|
11
|
+
|
|
12
|
+
def __init__(
|
|
13
|
+
self,
|
|
14
|
+
asserter_factory: 'type[AsserterFactoryProtocol]',
|
|
15
|
+
expectation: Any, # noqa: ANN401
|
|
16
|
+
) -> None: ...
|
|
17
|
+
|
|
18
|
+
@classmethod
|
|
19
|
+
def matches(cls, expectation: Any) -> bool: # noqa: ANN401
|
|
20
|
+
"""
|
|
21
|
+
Decide whether provided expectation can be handled by this asserter.
|
|
22
|
+
|
|
23
|
+
:param expectation: expectation to be tested
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
def assert_object(self, object_: Any) -> None: # noqa: ANN401
|
|
27
|
+
"""
|
|
28
|
+
Assert if the expectation is fulfilled by an object.
|
|
29
|
+
|
|
30
|
+
:param object_: an object to be tested
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class AsserterFactoryProtocol(Protocol):
|
|
35
|
+
"""
|
|
36
|
+
Factory for registered asserters.
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
@classmethod
|
|
40
|
+
def create(cls, expectation: Any) -> AsserterProtocol: # noqa: ANN401
|
|
41
|
+
"""
|
|
42
|
+
Create asserter object for given expectation.
|
|
43
|
+
|
|
44
|
+
The function goes through all registered asserter types and creates the first one that matches.
|
|
45
|
+
|
|
46
|
+
:param expectation: expectation to create asserter for
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class GeneratorProtocol(Protocol):
|
|
51
|
+
"""
|
|
52
|
+
Generates expectation from given object according to a definition.
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
definition: Any
|
|
56
|
+
generator_factory: 'type[GeneratorFactoryProtocol]'
|
|
57
|
+
|
|
58
|
+
def __init__(
|
|
59
|
+
self,
|
|
60
|
+
generator_factory: 'type[GeneratorFactoryProtocol]',
|
|
61
|
+
definition: Any, # noqa: ANN401
|
|
62
|
+
) -> None: ...
|
|
63
|
+
|
|
64
|
+
@classmethod
|
|
65
|
+
def matches(cls, definition: Any) -> bool: # noqa: ANN401
|
|
66
|
+
"""
|
|
67
|
+
Decide whether provided definition can be handled by this generator.
|
|
68
|
+
|
|
69
|
+
:param definition: definition to be tested
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
def generate_expectation(self, object_: Any) -> Any: # noqa: ANN401
|
|
73
|
+
"""
|
|
74
|
+
Generate expectation from given object.
|
|
75
|
+
|
|
76
|
+
:param object_: an object to generate expectation from
|
|
77
|
+
"""
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class GeneratorFactoryProtocol(Protocol):
|
|
81
|
+
"""
|
|
82
|
+
Factory for registered generators.
|
|
83
|
+
"""
|
|
84
|
+
|
|
85
|
+
@classmethod
|
|
86
|
+
def create(cls, definition: Any) -> GeneratorProtocol: # noqa: ANN401
|
|
87
|
+
"""
|
|
88
|
+
Create expectation generator for given definition.
|
|
89
|
+
|
|
90
|
+
The method goes through all registered generator types and uses the first one that matches.
|
|
91
|
+
|
|
92
|
+
:param definition: expectation definition
|
|
93
|
+
"""
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
from ._expectation_definitions import (
|
|
2
|
+
EqualityDef,
|
|
3
|
+
MappingDef,
|
|
4
|
+
MappingSubsetDef,
|
|
5
|
+
ObjectAttributesDef,
|
|
6
|
+
OfTypeDef,
|
|
7
|
+
StringifiedDef,
|
|
8
|
+
uniform_ordered_def,
|
|
9
|
+
UniformMappingDef,
|
|
10
|
+
UniformMappingSubsetDef,
|
|
11
|
+
UniformOrderedDef,
|
|
12
|
+
UniformUnorderedDef,
|
|
13
|
+
UnionDef,
|
|
14
|
+
with_type_def,
|
|
15
|
+
WithTypeDef,
|
|
16
|
+
)
|
|
17
|
+
from ._generate_expectation import generate_expectation
|
|
18
|
+
from ._generator_factories import BuiltInGeneratorFactory, GeneratorFactory
|
|
19
|
+
from ._generators import Generator
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
__all__ = [
|
|
23
|
+
'EqualityDef',
|
|
24
|
+
'MappingDef',
|
|
25
|
+
'MappingSubsetDef',
|
|
26
|
+
'ObjectAttributesDef',
|
|
27
|
+
'OfTypeDef',
|
|
28
|
+
'StringifiedDef',
|
|
29
|
+
'uniform_ordered_def',
|
|
30
|
+
'UniformMappingDef',
|
|
31
|
+
'UniformMappingSubsetDef',
|
|
32
|
+
'UniformOrderedDef',
|
|
33
|
+
'UniformUnorderedDef',
|
|
34
|
+
'UnionDef',
|
|
35
|
+
'with_type_def',
|
|
36
|
+
'WithTypeDef',
|
|
37
|
+
'generate_expectation',
|
|
38
|
+
'BuiltInGeneratorFactory',
|
|
39
|
+
'GeneratorFactory',
|
|
40
|
+
'Generator',
|
|
41
|
+
]
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from .equality import EqualityDef
|
|
2
|
+
from .mapping import MappingDef
|
|
3
|
+
from .mapping_subset import MappingSubsetDef
|
|
4
|
+
from .object_attributes import ObjectAttributesDef
|
|
5
|
+
from .of_type import OfTypeDef
|
|
6
|
+
from .stringified import StringifiedDef
|
|
7
|
+
from .uniform_mapping import UniformMappingDef
|
|
8
|
+
from .uniform_mapping_subset import UniformMappingSubsetDef
|
|
9
|
+
from .uniform_ordered import uniform_ordered_def, UniformOrderedDef
|
|
10
|
+
from .uniform_unordered import UniformUnorderedDef
|
|
11
|
+
from .union import UnionDef
|
|
12
|
+
from .with_type import with_type_def, WithTypeDef
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
__all__ = [
|
|
16
|
+
'EqualityDef',
|
|
17
|
+
'MappingDef',
|
|
18
|
+
'MappingSubsetDef',
|
|
19
|
+
'ObjectAttributesDef',
|
|
20
|
+
'OfTypeDef',
|
|
21
|
+
'StringifiedDef',
|
|
22
|
+
'UniformMappingDef',
|
|
23
|
+
'UniformMappingSubsetDef',
|
|
24
|
+
'uniform_ordered_def',
|
|
25
|
+
'UniformOrderedDef',
|
|
26
|
+
'UniformUnorderedDef',
|
|
27
|
+
'UnionDef',
|
|
28
|
+
'with_type_def',
|
|
29
|
+
'WithTypeDef',
|
|
30
|
+
]
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from collections.abc import Mapping
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class MappingDef:
|
|
6
|
+
"""
|
|
7
|
+
Defines mapping expectation where all keys share common definition and each have definition for its value.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
def __init__(self, keys_definition: Any, items_definitions: Mapping[str, Any], /) -> None: # noqa: ANN401
|
|
11
|
+
#: definition for mapping keys
|
|
12
|
+
self.keys_definition = keys_definition
|
|
13
|
+
#: mapping of items definitions
|
|
14
|
+
self.items_definitions = items_definitions
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from collections.abc import Mapping
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class MappingSubsetDef:
|
|
6
|
+
"""
|
|
7
|
+
Defines mapping subset expectation where keys share definition and each have definition for its value.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
def __init__(self, keys_definition: Any, items_definitions: Mapping[Any, Any], /) -> None: # noqa: ANN401
|
|
11
|
+
#: definition for mapping keys
|
|
12
|
+
self.keys_definition = keys_definition
|
|
13
|
+
#: mapping of items definitions
|
|
14
|
+
self.items_definitions = items_definitions
|
panda_pytest_assertions/assert_object/generators/_expectation_definitions/object_attributes.py
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from collections.abc import Mapping
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class ObjectAttributesDef:
|
|
6
|
+
"""
|
|
7
|
+
Defines expectation for object attributes.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
def __init__(self, attributes_definitions: Mapping[str, Any], /) -> None:
|
|
11
|
+
#: mapping of attributes definitions
|
|
12
|
+
self.attributes_definitions = attributes_definitions
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class OfTypeDef:
|
|
5
|
+
"""
|
|
6
|
+
Defines expectation that will only be generated if object is of a specific type.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
def __init__(self, expected_type: type[Any] | None, object_definition: Any, /) -> None: # noqa: ANN401
|
|
10
|
+
#: type that the object needs to match for the expectation to be generated
|
|
11
|
+
self.expected_type = expected_type
|
|
12
|
+
#: definition for object itself
|
|
13
|
+
self.object_definition = object_definition
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class UniformMappingDef:
|
|
5
|
+
"""
|
|
6
|
+
Defines mapping expectation where all keys and values share common definitions.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
def __init__(self, keys_definition: Any, values_definition: Any, /) -> None: # noqa: ANN401
|
|
10
|
+
#: definition for mapping keys
|
|
11
|
+
self.keys_definition = keys_definition
|
|
12
|
+
#: definition for mapping values
|
|
13
|
+
self.values_definition = values_definition
|
panda_pytest_assertions/assert_object/generators/_expectation_definitions/uniform_mapping_subset.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class UniformMappingSubsetDef:
|
|
5
|
+
"""
|
|
6
|
+
Defines mapping subset expectation where all keys and values share common definitions.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
def __init__(self, keys_definition: Any, values_definition: Any, /) -> None: # noqa: ANN401
|
|
10
|
+
#: definition for mapping keys
|
|
11
|
+
self.keys_definition = keys_definition
|
|
12
|
+
#: definition for mapping values
|
|
13
|
+
self.values_definition = values_definition
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
from collections.abc import Callable
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class UniformOrderedDef:
|
|
6
|
+
"""
|
|
7
|
+
Defines expectation for ordered collection using the same definition for each element.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
def __init__(
|
|
11
|
+
self,
|
|
12
|
+
elements_definition: Any, # noqa: ANN401
|
|
13
|
+
/,
|
|
14
|
+
*,
|
|
15
|
+
expectation_type: type[list[Any]] | type[tuple[Any, ...]] = list,
|
|
16
|
+
) -> None:
|
|
17
|
+
#: definition for elements
|
|
18
|
+
self.elements_definition = elements_definition
|
|
19
|
+
#: type of expectation to be generated
|
|
20
|
+
self.expectation_type = expectation_type
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def uniform_ordered_def(
|
|
24
|
+
*,
|
|
25
|
+
expectation_type: type[list[Any]] | type[tuple[Any, ...]] = list,
|
|
26
|
+
) -> Callable[[Any], UniformOrderedDef]:
|
|
27
|
+
"""
|
|
28
|
+
Return the function that will accept elements definition and create expectation for ordered collection.
|
|
29
|
+
|
|
30
|
+
Returned function accepts any kind of value that will be treated as elements definition for collection.
|
|
31
|
+
|
|
32
|
+
:param expectation_type: defines which expectation type will be used
|
|
33
|
+
:return: function creating definition
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
def _creator(elements_definition: Any, /) -> UniformOrderedDef: # noqa: ANN401
|
|
37
|
+
return UniformOrderedDef(elements_definition, expectation_type=expectation_type)
|
|
38
|
+
|
|
39
|
+
return _creator
|
panda_pytest_assertions/assert_object/generators/_expectation_definitions/uniform_unordered.py
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class UniformUnorderedDef:
|
|
5
|
+
"""
|
|
6
|
+
Defines expectation for unordered collection.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
def __init__(self, elements_definition: Any, /) -> None: # noqa: ANN401
|
|
10
|
+
#: definition for elements
|
|
11
|
+
self.elements_definition = elements_definition
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class UnionDef:
|
|
5
|
+
"""
|
|
6
|
+
Definition that accepts multiple definitions in case a place in object can have multiple types of values.
|
|
7
|
+
|
|
8
|
+
The first definition that matches a value during expectation generation will be used.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
def __init__(self, *definitions: Any) -> None: # noqa: ANN401
|
|
12
|
+
#: allowed union definitions
|
|
13
|
+
self.definitions = definitions
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from collections.abc import Callable
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class WithTypeDef:
|
|
6
|
+
"""
|
|
7
|
+
Defines expectation validating object type.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
def __init__(self, object_definition: Any, /, *, include_module: bool = True) -> None: # noqa: ANN401
|
|
11
|
+
#: definition for object itself
|
|
12
|
+
self.object_definition = object_definition
|
|
13
|
+
#: indicator whether module shall be included in WithType expectation
|
|
14
|
+
self.include_module = include_module
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def with_type_def(*, include_module: bool = True) -> Callable[[Any], WithTypeDef]:
|
|
18
|
+
"""
|
|
19
|
+
Return the function that will accept an object definition and create expectation definition with type.
|
|
20
|
+
|
|
21
|
+
Returned function accepts any kind of value that will be treated as expectation definition for object.
|
|
22
|
+
|
|
23
|
+
:param include_module: whether the module of the type shall be included in the expectation
|
|
24
|
+
:return: function creating definition
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def _creator(object_definition: Any, /) -> WithTypeDef: # noqa: ANN401
|
|
28
|
+
return WithTypeDef(object_definition, include_module=include_module)
|
|
29
|
+
|
|
30
|
+
return _creator
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from panda_pytest_assertions.assert_object._protocols import GeneratorFactoryProtocol
|
|
4
|
+
|
|
5
|
+
from ._generator_factories import BuiltInGeneratorFactory
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def generate_expectation(
|
|
9
|
+
object_: Any, # noqa: ANN401
|
|
10
|
+
definition: Any, # noqa: ANN401
|
|
11
|
+
*,
|
|
12
|
+
generator_factory: type[GeneratorFactoryProtocol] = BuiltInGeneratorFactory,
|
|
13
|
+
) -> Any: # noqa: ANN401
|
|
14
|
+
"""
|
|
15
|
+
Generate expectation for given object according to definition.
|
|
16
|
+
|
|
17
|
+
:param object_: object to generate expectation from
|
|
18
|
+
:param definition: expectation definition
|
|
19
|
+
:param generator_factory: factory used to create generators
|
|
20
|
+
:return: generated expectation
|
|
21
|
+
"""
|
|
22
|
+
generator = generator_factory.create(definition)
|
|
23
|
+
return generator.generate_expectation(object_)
|
panda_pytest_assertions/assert_object/generators/_generator_factories/built_in_generator_factory.py
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
from .._generators import ( # noqa: TID252
|
|
2
|
+
EqualityGenerator,
|
|
3
|
+
EqualityKeyMappingGenerator,
|
|
4
|
+
MappingGenerator,
|
|
5
|
+
MappingSubsetGenerator,
|
|
6
|
+
ObjectAttributesGenerator,
|
|
7
|
+
OfTypeGenerator,
|
|
8
|
+
OrderedGenerator,
|
|
9
|
+
StringifiedGenerator,
|
|
10
|
+
UniformMappingGenerator,
|
|
11
|
+
UniformMappingSubsetGenerator,
|
|
12
|
+
UniformOrderedGenerator,
|
|
13
|
+
UnionGenerator,
|
|
14
|
+
UnorderedGenerator,
|
|
15
|
+
WithTypeGenerator,
|
|
16
|
+
)
|
|
17
|
+
from .generator_factory import GeneratorFactory
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class BuiltInGeneratorFactory(GeneratorFactory):
|
|
21
|
+
"""
|
|
22
|
+
Factory that has all built-in generators registered.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
BuiltInGeneratorFactory.register_generator(EqualityGenerator)
|
|
27
|
+
BuiltInGeneratorFactory.register_generator(EqualityKeyMappingGenerator)
|
|
28
|
+
BuiltInGeneratorFactory.register_generator(MappingGenerator)
|
|
29
|
+
BuiltInGeneratorFactory.register_generator(MappingSubsetGenerator)
|
|
30
|
+
BuiltInGeneratorFactory.register_generator(ObjectAttributesGenerator)
|
|
31
|
+
BuiltInGeneratorFactory.register_generator(OfTypeGenerator)
|
|
32
|
+
BuiltInGeneratorFactory.register_generator(OrderedGenerator)
|
|
33
|
+
BuiltInGeneratorFactory.register_generator(StringifiedGenerator)
|
|
34
|
+
BuiltInGeneratorFactory.register_generator(UniformOrderedGenerator)
|
|
35
|
+
BuiltInGeneratorFactory.register_generator(UniformMappingGenerator)
|
|
36
|
+
BuiltInGeneratorFactory.register_generator(UniformMappingSubsetGenerator)
|
|
37
|
+
BuiltInGeneratorFactory.register_generator(UnionGenerator)
|
|
38
|
+
BuiltInGeneratorFactory.register_generator(UnorderedGenerator)
|
|
39
|
+
BuiltInGeneratorFactory.register_generator(WithTypeGenerator)
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
from collections import deque
|
|
2
|
+
from typing import Any, ClassVar
|
|
3
|
+
|
|
4
|
+
from panda_pytest_assertions.assert_object._protocols import GeneratorProtocol
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class GeneratorFactory:
|
|
8
|
+
"""
|
|
9
|
+
Factory for registered generators.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
#: list of registered gnerator classes
|
|
13
|
+
_GENERATOR_TYPES: ClassVar[deque[type[GeneratorProtocol]]] = deque()
|
|
14
|
+
|
|
15
|
+
@classmethod
|
|
16
|
+
def create(cls, definition: Any) -> Any: # noqa: ANN401
|
|
17
|
+
"""
|
|
18
|
+
Create expectation generator for given definition.
|
|
19
|
+
|
|
20
|
+
The method goes through all registered generator types and uses the first one that matches.
|
|
21
|
+
|
|
22
|
+
:param definition: expectation definition
|
|
23
|
+
:return: generated expectation
|
|
24
|
+
"""
|
|
25
|
+
for generator_type in cls._GENERATOR_TYPES:
|
|
26
|
+
if generator_type.matches(definition):
|
|
27
|
+
return generator_type(cls, definition)
|
|
28
|
+
msg = (
|
|
29
|
+
f'None of the registered generators matches definition "{definition}" '
|
|
30
|
+
f'of type "{type(definition)}".'
|
|
31
|
+
)
|
|
32
|
+
raise ValueError(msg)
|
|
33
|
+
|
|
34
|
+
@classmethod
|
|
35
|
+
def register_generator(
|
|
36
|
+
cls,
|
|
37
|
+
generator: type[GeneratorProtocol],
|
|
38
|
+
*,
|
|
39
|
+
after: type[GeneratorProtocol] | None = None,
|
|
40
|
+
before: type[GeneratorProtocol] | None = None,
|
|
41
|
+
) -> None:
|
|
42
|
+
"""
|
|
43
|
+
Register the provided generator to be used.
|
|
44
|
+
|
|
45
|
+
The generator is registered at the earliest possible position. If `after` and `before`
|
|
46
|
+
parameters are not set, it is registered at the beginning of the list to be matched
|
|
47
|
+
when creating generator for expectations.
|
|
48
|
+
|
|
49
|
+
:param generator: generator to be registered
|
|
50
|
+
:param after: registered generator must be matched after this one
|
|
51
|
+
:param before: registered generator must be matched before this one
|
|
52
|
+
"""
|
|
53
|
+
if '_GENERATOR_TYPES' not in cls.__dict__:
|
|
54
|
+
cls._GENERATOR_TYPES = cls._GENERATOR_TYPES.copy()
|
|
55
|
+
|
|
56
|
+
after_position = cls._GENERATOR_TYPES.index(after) if after is not None else -1
|
|
57
|
+
before_position = (
|
|
58
|
+
cls._GENERATOR_TYPES.index(before) if before is not None else len(cls._GENERATOR_TYPES) + 1
|
|
59
|
+
)
|
|
60
|
+
if after_position >= before_position:
|
|
61
|
+
msg = (
|
|
62
|
+
f'Cannot register generator between "{after}" and "{before}" as their '
|
|
63
|
+
f'respective positions are: "{after_position}" and "{before_position}"'
|
|
64
|
+
)
|
|
65
|
+
raise ValueError(msg)
|
|
66
|
+
cls._GENERATOR_TYPES.insert(after_position + 1, generator)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from .equality_generator import EqualityGenerator
|
|
2
|
+
from .equality_key_mapping_generator import EqualityKeyMappingGenerator
|
|
3
|
+
from .generator import Generator
|
|
4
|
+
from .mapping_generator import MappingGenerator
|
|
5
|
+
from .mapping_subset_generator import MappingSubsetGenerator
|
|
6
|
+
from .object_attributes_generator import ObjectAttributesGenerator
|
|
7
|
+
from .of_type_generator import OfTypeGenerator
|
|
8
|
+
from .ordered_generator import OrderedGenerator
|
|
9
|
+
from .stringified_generator import StringifiedGenerator
|
|
10
|
+
from .uniform_mapping_generator import UniformMappingGenerator
|
|
11
|
+
from .uniform_mapping_subset_generator import UniformMappingSubsetGenerator
|
|
12
|
+
from .uniform_ordered_generator import UniformOrderedGenerator
|
|
13
|
+
from .union_generator import UnionGenerator
|
|
14
|
+
from .unordered_generator import UnorderedGenerator
|
|
15
|
+
from .with_type_generator import WithTypeGenerator
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
__all__ = [
|
|
19
|
+
'Generator',
|
|
20
|
+
'EqualityGenerator',
|
|
21
|
+
'EqualityKeyMappingGenerator',
|
|
22
|
+
'MappingGenerator',
|
|
23
|
+
'MappingSubsetGenerator',
|
|
24
|
+
'ObjectAttributesGenerator',
|
|
25
|
+
'OfTypeGenerator',
|
|
26
|
+
'OrderedGenerator',
|
|
27
|
+
'StringifiedGenerator',
|
|
28
|
+
'UniformOrderedGenerator',
|
|
29
|
+
'UniformMappingGenerator',
|
|
30
|
+
'UniformMappingSubsetGenerator',
|
|
31
|
+
'UnionGenerator',
|
|
32
|
+
'UnorderedGenerator',
|
|
33
|
+
'WithTypeGenerator',
|
|
34
|
+
]
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from .._expectation_definitions import EqualityDef # noqa: TID252
|
|
4
|
+
from .generator import Generator
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class EqualityGenerator(Generator):
|
|
8
|
+
"""
|
|
9
|
+
Generated expectation is just the specific object.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
@classmethod
|
|
13
|
+
def matches(cls, definition: Any) -> bool: # noqa: ANN401
|
|
14
|
+
"""
|
|
15
|
+
Decide whether provided definiton can be handled by this generator.
|
|
16
|
+
|
|
17
|
+
This generator can handle EqualityDef definition.
|
|
18
|
+
|
|
19
|
+
:param definition: definition to be tested
|
|
20
|
+
:return: whether definition can be handled by this generator
|
|
21
|
+
"""
|
|
22
|
+
return isinstance(definition, EqualityDef) or (
|
|
23
|
+
isinstance(definition, type) and issubclass(definition, EqualityDef)
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
def generate_expectation(self, object_: Any) -> Any: # noqa: ANN401
|
|
27
|
+
"""
|
|
28
|
+
Generate expectation from given object.
|
|
29
|
+
|
|
30
|
+
Return object itself.
|
|
31
|
+
|
|
32
|
+
:param object_: an object to generate expectation from
|
|
33
|
+
:return: generated expectation
|
|
34
|
+
"""
|
|
35
|
+
return object_
|
panda_pytest_assertions/assert_object/generators/_generators/equality_key_mapping_generator.py
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
from collections.abc import Mapping
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from panda_pytest_assertions.assert_object import GeneratorFactoryProtocol
|
|
5
|
+
|
|
6
|
+
from .exceptions import ObjectNotMatchingDefinitionError
|
|
7
|
+
from .generator import Generator
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class EqualityKeyMappingGenerator(Generator):
|
|
11
|
+
"""
|
|
12
|
+
Generates Mapping expectation using keys' values as keys' expectations.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
@classmethod
|
|
16
|
+
def matches(cls, definition: Any) -> bool: # noqa: ANN401
|
|
17
|
+
"""
|
|
18
|
+
Decide whether provided definiton can be handled by this generator.
|
|
19
|
+
|
|
20
|
+
This generator can handle any Mapping as definition.
|
|
21
|
+
|
|
22
|
+
:param definition: definition to be tested
|
|
23
|
+
:return: whether definition can be handled by this generator
|
|
24
|
+
"""
|
|
25
|
+
return isinstance(definition, Mapping)
|
|
26
|
+
|
|
27
|
+
def __init__(
|
|
28
|
+
self,
|
|
29
|
+
generator_factory: type[GeneratorFactoryProtocol],
|
|
30
|
+
definition: Mapping[Any, Any],
|
|
31
|
+
) -> None:
|
|
32
|
+
super().__init__(generator_factory, definition)
|
|
33
|
+
self.items_generators = {key: generator_factory.create(value) for key, value in definition.items()}
|
|
34
|
+
|
|
35
|
+
def generate_expectation(self, object_: Any) -> Mapping[Any, Any]: # noqa: ANN401
|
|
36
|
+
"""
|
|
37
|
+
Generate expectation from given object.
|
|
38
|
+
|
|
39
|
+
:param object_: an object to generate expectation from
|
|
40
|
+
:return: generated expectation
|
|
41
|
+
"""
|
|
42
|
+
if not isinstance(object_, Mapping):
|
|
43
|
+
msg = f'Expected mapping, got {type(object_)}'
|
|
44
|
+
raise ObjectNotMatchingDefinitionError(msg)
|
|
45
|
+
if object_.keys() != self.items_generators.keys():
|
|
46
|
+
msg = (
|
|
47
|
+
f'Object has invalid keys. '
|
|
48
|
+
f'Expected: {set(self.items_generators.keys())}, got {set(object_.keys())}.'
|
|
49
|
+
)
|
|
50
|
+
raise ObjectNotMatchingDefinitionError(msg)
|
|
51
|
+
return {
|
|
52
|
+
key: value_generator.generate_expectation(object_[key])
|
|
53
|
+
for key, value_generator in self.items_generators.items()
|
|
54
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
class ObjectNotMatchingDefinitionError(Exception): ...
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import abc
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from panda_pytest_assertions.assert_object._protocols import GeneratorFactoryProtocol
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Generator(abc.ABC):
|
|
8
|
+
"""
|
|
9
|
+
Generates expectation for given object according to a provided definition.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
@classmethod
|
|
13
|
+
@abc.abstractmethod
|
|
14
|
+
def matches(cls, definition: Any) -> bool: # noqa: ANN401
|
|
15
|
+
"""
|
|
16
|
+
Decide whether provided definition can be handled by this generator.
|
|
17
|
+
|
|
18
|
+
:param definition: definition to be tested
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
def __init__(
|
|
22
|
+
self,
|
|
23
|
+
generator_factory: type[GeneratorFactoryProtocol],
|
|
24
|
+
definition: Any, # noqa: ANN401
|
|
25
|
+
) -> None:
|
|
26
|
+
self.generator_factory = generator_factory
|
|
27
|
+
self.definition = definition
|
|
28
|
+
|
|
29
|
+
@abc.abstractmethod
|
|
30
|
+
def generate_expectation(self, object_: Any) -> Any: # noqa: ANN401
|
|
31
|
+
"""
|
|
32
|
+
Generate expectation from given object.
|
|
33
|
+
|
|
34
|
+
:param object_: an object to generate expectation from
|
|
35
|
+
"""
|