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.
Files changed (68) hide show
  1. panda_pytest_assertions/__init__.py +0 -0
  2. panda_pytest_assertions/assert_context/__init__.py +15 -0
  3. panda_pytest_assertions/assert_context/_assert_context.py +128 -0
  4. panda_pytest_assertions/assert_object/__init__.py +41 -0
  5. panda_pytest_assertions/assert_object/_assert_object.py +36 -0
  6. panda_pytest_assertions/assert_object/_asserter_factories/__init__.py +8 -0
  7. panda_pytest_assertions/assert_object/_asserter_factories/asserter_factory.py +66 -0
  8. panda_pytest_assertions/assert_object/_asserter_factories/built_in_asserter_factory.py +29 -0
  9. panda_pytest_assertions/assert_object/_converters/__init__.py +10 -0
  10. panda_pytest_assertions/assert_object/_converters/expectation_from_yaml.py +114 -0
  11. panda_pytest_assertions/assert_object/_converters/expectation_to_yaml.py +78 -0
  12. panda_pytest_assertions/assert_object/_expectation_modificators/__init__.py +15 -0
  13. panda_pytest_assertions/assert_object/_expectation_modificators/mapping_subset.py +15 -0
  14. panda_pytest_assertions/assert_object/_expectation_modificators/object_attibutes.py +15 -0
  15. panda_pytest_assertions/assert_object/_expectation_modificators/stringified.py +11 -0
  16. panda_pytest_assertions/assert_object/_expectation_modificators/unordered.py +18 -0
  17. panda_pytest_assertions/assert_object/_expectation_modificators/with_type.py +135 -0
  18. panda_pytest_assertions/assert_object/_objects_asserters/__init__.py +36 -0
  19. panda_pytest_assertions/assert_object/_objects_asserters/asserter.py +35 -0
  20. panda_pytest_assertions/assert_object/_objects_asserters/equality_asserter.py +33 -0
  21. panda_pytest_assertions/assert_object/_objects_asserters/mapping_asserter.py +55 -0
  22. panda_pytest_assertions/assert_object/_objects_asserters/mapping_subset_asserter.py +53 -0
  23. panda_pytest_assertions/assert_object/_objects_asserters/object_attributes_asserter.py +52 -0
  24. panda_pytest_assertions/assert_object/_objects_asserters/ordered_elements_asserter.py +55 -0
  25. panda_pytest_assertions/assert_object/_objects_asserters/stringified_asserter.py +36 -0
  26. panda_pytest_assertions/assert_object/_objects_asserters/unordered_elements_asserter.py +77 -0
  27. panda_pytest_assertions/assert_object/_objects_asserters/with_type_asserter.py +57 -0
  28. panda_pytest_assertions/assert_object/_protocols.py +93 -0
  29. panda_pytest_assertions/assert_object/generators/__init__.py +41 -0
  30. panda_pytest_assertions/assert_object/generators/_expectation_definitions/__init__.py +30 -0
  31. panda_pytest_assertions/assert_object/generators/_expectation_definitions/equality.py +6 -0
  32. panda_pytest_assertions/assert_object/generators/_expectation_definitions/mapping.py +14 -0
  33. panda_pytest_assertions/assert_object/generators/_expectation_definitions/mapping_subset.py +14 -0
  34. panda_pytest_assertions/assert_object/generators/_expectation_definitions/object_attributes.py +12 -0
  35. panda_pytest_assertions/assert_object/generators/_expectation_definitions/of_type.py +13 -0
  36. panda_pytest_assertions/assert_object/generators/_expectation_definitions/stringified.py +4 -0
  37. panda_pytest_assertions/assert_object/generators/_expectation_definitions/uniform_mapping.py +13 -0
  38. panda_pytest_assertions/assert_object/generators/_expectation_definitions/uniform_mapping_subset.py +13 -0
  39. panda_pytest_assertions/assert_object/generators/_expectation_definitions/uniform_ordered.py +39 -0
  40. panda_pytest_assertions/assert_object/generators/_expectation_definitions/uniform_unordered.py +11 -0
  41. panda_pytest_assertions/assert_object/generators/_expectation_definitions/union.py +13 -0
  42. panda_pytest_assertions/assert_object/generators/_expectation_definitions/with_type.py +30 -0
  43. panda_pytest_assertions/assert_object/generators/_generate_expectation.py +23 -0
  44. panda_pytest_assertions/assert_object/generators/_generator_factories/__init__.py +8 -0
  45. panda_pytest_assertions/assert_object/generators/_generator_factories/built_in_generator_factory.py +39 -0
  46. panda_pytest_assertions/assert_object/generators/_generator_factories/generator_factory.py +66 -0
  47. panda_pytest_assertions/assert_object/generators/_generators/__init__.py +34 -0
  48. panda_pytest_assertions/assert_object/generators/_generators/equality_generator.py +35 -0
  49. panda_pytest_assertions/assert_object/generators/_generators/equality_key_mapping_generator.py +54 -0
  50. panda_pytest_assertions/assert_object/generators/_generators/exceptions.py +1 -0
  51. panda_pytest_assertions/assert_object/generators/_generators/generator.py +35 -0
  52. panda_pytest_assertions/assert_object/generators/_generators/mapping_generator.py +60 -0
  53. panda_pytest_assertions/assert_object/generators/_generators/mapping_subset_generator.py +57 -0
  54. panda_pytest_assertions/assert_object/generators/_generators/object_attributes_generator.py +53 -0
  55. panda_pytest_assertions/assert_object/generators/_generators/of_type_generator.py +47 -0
  56. panda_pytest_assertions/assert_object/generators/_generators/ordered_generator.py +55 -0
  57. panda_pytest_assertions/assert_object/generators/_generators/stringified_generator.py +35 -0
  58. panda_pytest_assertions/assert_object/generators/_generators/uniform_mapping_generator.py +50 -0
  59. panda_pytest_assertions/assert_object/generators/_generators/uniform_mapping_subset_generator.py +52 -0
  60. panda_pytest_assertions/assert_object/generators/_generators/uniform_ordered_generator.py +49 -0
  61. panda_pytest_assertions/assert_object/generators/_generators/union_generator.py +51 -0
  62. panda_pytest_assertions/assert_object/generators/_generators/unordered_generator.py +46 -0
  63. panda_pytest_assertions/assert_object/generators/_generators/with_type_generator.py +46 -0
  64. panda_pytest_assertions/py.typed +0 -0
  65. panda_pytest_assertions-0.1.0.dist-info/LICENSE +201 -0
  66. panda_pytest_assertions-0.1.0.dist-info/METADATA +32 -0
  67. panda_pytest_assertions-0.1.0.dist-info/RECORD +68 -0
  68. 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,6 @@
1
+ class EqualityDef:
2
+ """
3
+ Defines equality expectation where expectation is just the object itself.
4
+
5
+ Mostly useful for primitive types.
6
+ """
@@ -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
@@ -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,4 @@
1
+ class StringifiedDef:
2
+ """
3
+ Defines stringified expectation.
4
+ """
@@ -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
@@ -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
@@ -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_)
@@ -0,0 +1,8 @@
1
+ from .built_in_generator_factory import BuiltInGeneratorFactory
2
+ from .generator_factory import GeneratorFactory
3
+
4
+
5
+ __all__ = [
6
+ 'BuiltInGeneratorFactory',
7
+ 'GeneratorFactory',
8
+ ]
@@ -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_
@@ -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
+ """