py-predicate 0.6__tar.gz → 0.7__tar.gz
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.
- {py_predicate-0.6 → py_predicate-0.7}/PKG-INFO +16 -1
- {py_predicate-0.6 → py_predicate-0.7}/README.md +15 -0
- {py_predicate-0.6 → py_predicate-0.7}/predicate/__init__.py +10 -47
- {py_predicate-0.6 → py_predicate-0.7}/predicate/all_predicate.py +6 -4
- py_predicate-0.7/predicate/always_false_predicate.py +26 -0
- py_predicate-0.7/predicate/always_true_predicate.py +22 -0
- {py_predicate-0.6 → py_predicate-0.7}/predicate/any_predicate.py +4 -1
- {py_predicate-0.6 → py_predicate-0.7}/predicate/comp_predicate.py +4 -1
- {py_predicate-0.6 → py_predicate-0.7}/predicate/constructor/construct.py +13 -2
- {py_predicate-0.6 → py_predicate-0.7}/predicate/dict_of_predicate.py +32 -13
- {py_predicate-0.6 → py_predicate-0.7}/predicate/eq_predicate.py +1 -1
- {py_predicate-0.6 → py_predicate-0.7}/predicate/fn_predicate.py +2 -2
- py_predicate-0.7/predicate/formatter/__init__.py +9 -0
- {py_predicate-0.6 → py_predicate-0.7}/predicate/formatter/format_dot.py +14 -19
- {py_predicate-0.6 → py_predicate-0.7}/predicate/formatter/format_json.py +4 -4
- py_predicate-0.7/predicate/formatter/format_latex.py +86 -0
- py_predicate-0.7/predicate/formatter/helpers.py +4 -0
- {py_predicate-0.6 → py_predicate-0.7}/predicate/ge_predicate.py +1 -1
- {py_predicate-0.6 → py_predicate-0.7}/predicate/generator/generate_false.py +108 -67
- {py_predicate-0.6 → py_predicate-0.7}/predicate/generator/generate_true.py +113 -57
- {py_predicate-0.6 → py_predicate-0.7}/predicate/generator/helpers.py +56 -8
- {py_predicate-0.6 → py_predicate-0.7}/predicate/gt_predicate.py +1 -1
- {py_predicate-0.6 → py_predicate-0.7}/predicate/has_key_predicate.py +1 -1
- {py_predicate-0.6 → py_predicate-0.7}/predicate/has_length_predicate.py +1 -1
- py_predicate-0.7/predicate/has_path_predicate.py +50 -0
- py_predicate-0.7/predicate/helpers.py +18 -0
- {py_predicate-0.6 → py_predicate-0.7}/predicate/implies.py +26 -2
- py_predicate-0.7/predicate/implies_predicate.py +26 -0
- py_predicate-0.7/predicate/in_predicate_predicate.py +25 -0
- py_predicate-0.7/predicate/is_callable_predicate.py +55 -0
- {py_predicate-0.6 → py_predicate-0.7}/predicate/is_empty_predicate.py +2 -2
- py_predicate-0.7/predicate/is_falsy_predicate.py +19 -0
- {py_predicate-0.6 → py_predicate-0.7}/predicate/is_instance_predicate.py +1 -1
- py_predicate-0.7/predicate/is_lambda_predicate.py +55 -0
- {py_predicate-0.6 → py_predicate-0.7}/predicate/is_none_predicate.py +1 -1
- {py_predicate-0.6 → py_predicate-0.7}/predicate/is_not_none_predicate.py +1 -1
- py_predicate-0.7/predicate/is_truthy_predicate.py +19 -0
- {py_predicate-0.6 → py_predicate-0.7}/predicate/le_predicate.py +1 -1
- {py_predicate-0.6 → py_predicate-0.7}/predicate/list_of_predicate.py +8 -6
- {py_predicate-0.6 → py_predicate-0.7}/predicate/lt_predicate.py +1 -1
- {py_predicate-0.6 → py_predicate-0.7}/predicate/ne_predicate.py +1 -1
- {py_predicate-0.6 → py_predicate-0.7}/predicate/negate.py +18 -17
- {py_predicate-0.6 → py_predicate-0.7}/predicate/optimizer/all_optimizer.py +3 -7
- {py_predicate-0.6 → py_predicate-0.7}/predicate/optimizer/and_optimizer.py +3 -9
- {py_predicate-0.6 → py_predicate-0.7}/predicate/optimizer/any_optimizer.py +3 -8
- {py_predicate-0.6 → py_predicate-0.7}/predicate/optimizer/in_optimizer.py +3 -1
- {py_predicate-0.6 → py_predicate-0.7}/predicate/optimizer/or_optimizer.py +2 -8
- {py_predicate-0.6 → py_predicate-0.7}/predicate/optimizer/xor_optimizer.py +2 -4
- {py_predicate-0.6 → py_predicate-0.7}/predicate/parser.py +19 -11
- {py_predicate-0.6 → py_predicate-0.7}/predicate/predicate.py +26 -70
- {py_predicate-0.6 → py_predicate-0.7}/predicate/property_predicate.py +3 -3
- {py_predicate-0.6 → py_predicate-0.7}/predicate/range_predicate.py +3 -4
- {py_predicate-0.6 → py_predicate-0.7}/predicate/regex_predicate.py +5 -0
- {py_predicate-0.6 → py_predicate-0.7}/predicate/root_predicate.py +1 -2
- py_predicate-0.7/predicate/set_of_predicate.py +27 -0
- {py_predicate-0.6 → py_predicate-0.7}/predicate/standard_predicates.py +11 -6
- py_predicate-0.7/predicate/this_predicate.py +33 -0
- {py_predicate-0.6 → py_predicate-0.7}/predicate/truth_table.py +14 -4
- {py_predicate-0.6 → py_predicate-0.7}/predicate/tuple_of_predicate.py +4 -7
- {py_predicate-0.6 → py_predicate-0.7}/pyproject.toml +1 -1
- py_predicate-0.6/predicate/optimizer/__init__.py +0 -0
- py_predicate-0.6/predicate/set_of_predicate.py +0 -25
- py_predicate-0.6/predicate/this_predicate.py +0 -58
- {py_predicate-0.6 → py_predicate-0.7}/predicate/constructor/__init__.py +0 -0
- {py_predicate-0.6 → py_predicate-0.7}/predicate/explain.py +0 -0
- {py_predicate-0.6 → py_predicate-0.7}/predicate/generator/__init__.py +0 -0
- {py_predicate-0.6 → py_predicate-0.7}/predicate/ip_address_predicates.py +0 -0
- {py_predicate-0.6 → py_predicate-0.7}/predicate/lazy_predicate.py +0 -0
- {py_predicate-0.6 → py_predicate-0.7}/predicate/named_predicate.py +0 -0
- {py_predicate-0.6/predicate/formatter → py_predicate-0.7/predicate/optimizer}/__init__.py +0 -0
- {py_predicate-0.6 → py_predicate-0.7}/predicate/optimizer/not_optimizer.py +0 -0
- {py_predicate-0.6 → py_predicate-0.7}/predicate/optimizer/predicate_optimizer.py +0 -0
- {py_predicate-0.6 → py_predicate-0.7}/predicate/set_predicates.py +0 -0
- {py_predicate-0.6 → py_predicate-0.7}/predicate/str_predicates.py +0 -0
- {py_predicate-0.6 → py_predicate-0.7}/predicate/tee_predicate.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: py_predicate
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7
|
|
4
4
|
Summary: Module to create composable predicates
|
|
5
5
|
Author-email: Maurits Rijk <maurits.rijk@gmail.com>
|
|
6
6
|
Requires-Python: >=3.10
|
|
@@ -81,6 +81,21 @@ filtered = [x for x in range(10) if between_2_and_3(x)]
|
|
|
81
81
|
Of course this example looks way more complicated than the original version. The point here is that you can build
|
|
82
82
|
reusable predicates that can be used in multiple locations.
|
|
83
83
|
|
|
84
|
+
So lets do just that, reuse our predicate to create a generator. The ``generate_false`` will create an infinite
|
|
85
|
+
series of integers for which the predicate ``between_2_and_3`` is False. The ``generate_true`` will create an
|
|
86
|
+
infinite (well, with lots of duplicates obviously) series of integers for which the predicate is True.
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
from predicate import generate_false, generate_true
|
|
90
|
+
from more_itertools import take
|
|
91
|
+
|
|
92
|
+
take(5, generate_true(between_2_and_3))
|
|
93
|
+
|
|
94
|
+
take(5, generate_false(between_2_and_3))
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
This might be useful for example in unit tests.
|
|
98
|
+
|
|
84
99
|
# Example 2
|
|
85
100
|
|
|
86
101
|
A unique (?) py-predicate feature is that you can define self referencing predicates.
|
|
@@ -38,6 +38,21 @@ filtered = [x for x in range(10) if between_2_and_3(x)]
|
|
|
38
38
|
Of course this example looks way more complicated than the original version. The point here is that you can build
|
|
39
39
|
reusable predicates that can be used in multiple locations.
|
|
40
40
|
|
|
41
|
+
So lets do just that, reuse our predicate to create a generator. The ``generate_false`` will create an infinite
|
|
42
|
+
series of integers for which the predicate ``between_2_and_3`` is False. The ``generate_true`` will create an
|
|
43
|
+
infinite (well, with lots of duplicates obviously) series of integers for which the predicate is True.
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
from predicate import generate_false, generate_true
|
|
47
|
+
from more_itertools import take
|
|
48
|
+
|
|
49
|
+
take(5, generate_true(between_2_and_3))
|
|
50
|
+
|
|
51
|
+
take(5, generate_false(between_2_and_3))
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
This might be useful for example in unit tests.
|
|
55
|
+
|
|
41
56
|
# Example 2
|
|
42
57
|
|
|
43
58
|
A unique (?) py-predicate feature is that you can define self referencing predicates.
|
|
@@ -2,37 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
__version__ = "0.0.1"
|
|
4
4
|
|
|
5
|
-
from predicate.
|
|
6
|
-
from predicate.
|
|
7
|
-
from predicate.eq_predicate import EqPredicate
|
|
5
|
+
from predicate.always_false_predicate import always_false_p, never_p
|
|
6
|
+
from predicate.always_true_predicate import always_p, always_true_p
|
|
8
7
|
from predicate.explain import explain
|
|
9
|
-
from predicate.formatter
|
|
10
|
-
from predicate.formatter.format_json import to_json
|
|
11
|
-
from predicate.ge_predicate import GePredicate
|
|
8
|
+
from predicate.formatter import to_dot, to_json, to_latex
|
|
12
9
|
from predicate.generator.generate_false import generate_false
|
|
13
10
|
from predicate.generator.generate_true import generate_true
|
|
14
|
-
from predicate.
|
|
15
|
-
from predicate.
|
|
16
|
-
from predicate.is_none_predicate import IsNonePredicate
|
|
17
|
-
from predicate.is_not_none_predicate import IsNotNonePredicate
|
|
18
|
-
from predicate.le_predicate import LePredicate
|
|
19
|
-
from predicate.lt_predicate import LtPredicate
|
|
20
|
-
from predicate.ne_predicate import NePredicate
|
|
11
|
+
from predicate.is_empty_predicate import is_empty_p, is_not_empty_p
|
|
12
|
+
from predicate.is_lambda_predicate import is_lambda_p, is_lambda_with_signature_p
|
|
21
13
|
from predicate.optimizer.predicate_optimizer import can_optimize, optimize
|
|
22
|
-
from predicate.predicate import (
|
|
23
|
-
AlwaysFalsePredicate,
|
|
24
|
-
AlwaysTruePredicate,
|
|
25
|
-
AndPredicate,
|
|
26
|
-
NotPredicate,
|
|
27
|
-
OrPredicate,
|
|
28
|
-
Predicate,
|
|
29
|
-
XorPredicate,
|
|
30
|
-
always_false_p,
|
|
31
|
-
always_true_p,
|
|
32
|
-
)
|
|
33
14
|
from predicate.set_predicates import (
|
|
34
|
-
InPredicate,
|
|
35
|
-
NotInPredicate,
|
|
36
15
|
in_p,
|
|
37
16
|
is_real_subset_p,
|
|
38
17
|
is_real_superset_p,
|
|
@@ -100,29 +79,9 @@ from predicate.standard_predicates import (
|
|
|
100
79
|
)
|
|
101
80
|
|
|
102
81
|
__all__ = [
|
|
103
|
-
"AllPredicate",
|
|
104
|
-
"AlwaysFalsePredicate",
|
|
105
|
-
"AlwaysTruePredicate",
|
|
106
|
-
"AndPredicate",
|
|
107
|
-
"AnyPredicate",
|
|
108
|
-
"EqPredicate",
|
|
109
|
-
"GePredicate",
|
|
110
|
-
"GtPredicate",
|
|
111
|
-
"LePredicate",
|
|
112
|
-
"LtPredicate",
|
|
113
|
-
"InPredicate",
|
|
114
|
-
"IsEmptyPredicate",
|
|
115
|
-
"IsNonePredicate",
|
|
116
|
-
"IsNotEmptyPredicate",
|
|
117
|
-
"IsNotNonePredicate",
|
|
118
|
-
"NePredicate",
|
|
119
|
-
"NotInPredicate",
|
|
120
|
-
"NotPredicate",
|
|
121
|
-
"OrPredicate",
|
|
122
|
-
"Predicate",
|
|
123
|
-
"XorPredicate",
|
|
124
82
|
"all_p",
|
|
125
83
|
"always_false_p",
|
|
84
|
+
"always_p",
|
|
126
85
|
"always_true_p",
|
|
127
86
|
"any_p",
|
|
128
87
|
"can_optimize",
|
|
@@ -165,6 +124,8 @@ __all__ = [
|
|
|
165
124
|
"is_int_p",
|
|
166
125
|
"is_iterable_of_p",
|
|
167
126
|
"is_iterable_p",
|
|
127
|
+
"is_lambda_p",
|
|
128
|
+
"is_lambda_with_signature_p",
|
|
168
129
|
"is_list_of_p",
|
|
169
130
|
"is_list_p",
|
|
170
131
|
"is_lower_p",
|
|
@@ -192,6 +153,7 @@ __all__ = [
|
|
|
192
153
|
"lt_p",
|
|
193
154
|
"ne_p",
|
|
194
155
|
"neg_p",
|
|
156
|
+
"never_p",
|
|
195
157
|
"not_in_p",
|
|
196
158
|
"optimize",
|
|
197
159
|
"pos_p",
|
|
@@ -201,6 +163,7 @@ __all__ = [
|
|
|
201
163
|
"this_p",
|
|
202
164
|
"to_dot",
|
|
203
165
|
"to_json",
|
|
166
|
+
"to_latex",
|
|
204
167
|
"zero_p",
|
|
205
168
|
]
|
|
206
169
|
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
from dataclasses import dataclass
|
|
2
2
|
from typing import Iterable, override
|
|
3
3
|
|
|
4
|
-
from
|
|
5
|
-
|
|
4
|
+
from predicate.helpers import first_false
|
|
6
5
|
from predicate.predicate import Predicate
|
|
7
6
|
|
|
8
7
|
|
|
@@ -15,11 +14,14 @@ class AllPredicate[T](Predicate[T]):
|
|
|
15
14
|
def __call__(self, iterable: Iterable[T]) -> bool:
|
|
16
15
|
return all(self.predicate(x) for x in iterable)
|
|
17
16
|
|
|
17
|
+
def __contains__(self, predicate: Predicate[T]) -> bool:
|
|
18
|
+
return predicate in self.predicate
|
|
19
|
+
|
|
18
20
|
def __repr__(self) -> str:
|
|
19
21
|
return f"all({repr(self.predicate)})"
|
|
20
22
|
|
|
21
23
|
@override
|
|
22
24
|
def explain_failure(self, iterable: Iterable[T]) -> dict:
|
|
23
|
-
fail =
|
|
25
|
+
fail = first_false(iterable, self.predicate)
|
|
24
26
|
|
|
25
|
-
return {"
|
|
27
|
+
return {"reason": f"Item '{fail}' didn't match predicate {repr(self.predicate)}"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from typing import Final, override
|
|
3
|
+
|
|
4
|
+
from predicate.predicate import Predicate
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass
|
|
8
|
+
class AlwaysFalsePredicate(Predicate):
|
|
9
|
+
"""A predicate class that models the 'False' predicate."""
|
|
10
|
+
|
|
11
|
+
def __call__(self, *args, **kwargs):
|
|
12
|
+
return False
|
|
13
|
+
|
|
14
|
+
def __repr__(self) -> str:
|
|
15
|
+
return "always_false_p"
|
|
16
|
+
|
|
17
|
+
@override
|
|
18
|
+
def explain_failure(self, *args, **kwargs) -> dict:
|
|
19
|
+
return {"reason": "Always returns False"}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
always_false_p: Final[AlwaysFalsePredicate] = AlwaysFalsePredicate()
|
|
23
|
+
"""Predicate that always evaluates to False."""
|
|
24
|
+
|
|
25
|
+
never_p = always_false_p
|
|
26
|
+
"""Synonym for always_false_p."""
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from typing import Final
|
|
3
|
+
|
|
4
|
+
from predicate.predicate import Predicate
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass
|
|
8
|
+
class AlwaysTruePredicate(Predicate):
|
|
9
|
+
"""A predicate class that models the 'True' predicate."""
|
|
10
|
+
|
|
11
|
+
def __call__(self, *args, **kwargs):
|
|
12
|
+
return True
|
|
13
|
+
|
|
14
|
+
def __repr__(self) -> str:
|
|
15
|
+
return "always_true_p"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
always_true_p: Final[AlwaysTruePredicate] = AlwaysTruePredicate()
|
|
19
|
+
"""Predicate that always evaluates to True."""
|
|
20
|
+
|
|
21
|
+
always_p = always_true_p
|
|
22
|
+
"""Synonym for always_true_p."""
|
|
@@ -13,9 +13,12 @@ class AnyPredicate[T](Predicate[T]):
|
|
|
13
13
|
def __call__(self, iterable: Iterable[T]) -> bool:
|
|
14
14
|
return any(self.predicate(x) for x in iterable)
|
|
15
15
|
|
|
16
|
+
def __contains__(self, predicate: Predicate[T]) -> bool:
|
|
17
|
+
return predicate in self.predicate
|
|
18
|
+
|
|
16
19
|
def __repr__(self) -> str:
|
|
17
20
|
return f"any({repr(self.predicate)})"
|
|
18
21
|
|
|
19
22
|
@override
|
|
20
23
|
def explain_failure(self, iterable: Iterable[T]) -> dict:
|
|
21
|
-
return {"
|
|
24
|
+
return {"reason": f"No item matches predicate {repr(self.predicate)}"}
|
|
@@ -17,6 +17,9 @@ class CompPredicate[S, T](Predicate[T]):
|
|
|
17
17
|
def __repr__(self) -> str:
|
|
18
18
|
return f"comp_p({repr(self.predicate)})"
|
|
19
19
|
|
|
20
|
+
def __contains__(self, predicate: Predicate[T]) -> bool:
|
|
21
|
+
return predicate in self.predicate
|
|
22
|
+
|
|
20
23
|
@override
|
|
21
24
|
def explain_failure(self, x: S) -> dict:
|
|
22
|
-
return {"
|
|
25
|
+
return {"reason": self.predicate.explain(x)}
|
|
@@ -2,8 +2,19 @@ from typing import Iterator
|
|
|
2
2
|
|
|
3
3
|
from more_itertools import gray_product
|
|
4
4
|
|
|
5
|
-
from predicate import
|
|
6
|
-
|
|
5
|
+
from predicate import (
|
|
6
|
+
always_false_p,
|
|
7
|
+
always_true_p,
|
|
8
|
+
is_datetime_p,
|
|
9
|
+
is_falsy_p,
|
|
10
|
+
is_float_p,
|
|
11
|
+
is_int_p,
|
|
12
|
+
is_not_none_p,
|
|
13
|
+
is_set_p,
|
|
14
|
+
is_str_p,
|
|
15
|
+
is_truthy_p,
|
|
16
|
+
)
|
|
17
|
+
from predicate.predicate import Predicate
|
|
7
18
|
from predicate.standard_predicates import all_p, is_bool_p, is_dict_p, is_list_p, is_none_p
|
|
8
19
|
|
|
9
20
|
# TODO: this is very much work under construction (pun intended) and not ready for public consumption
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from dataclasses import dataclass
|
|
2
2
|
from typing import Any, override
|
|
3
3
|
|
|
4
|
+
from predicate.eq_predicate import EqPredicate
|
|
4
5
|
from predicate.predicate import Predicate
|
|
5
6
|
|
|
6
7
|
|
|
@@ -11,15 +12,6 @@ class DictOfPredicate[T](Predicate[T]):
|
|
|
11
12
|
key_value_predicates: list[tuple[Predicate, Predicate]]
|
|
12
13
|
|
|
13
14
|
def __init__(self, key_value_predicates: list[tuple[Predicate | str, Predicate]]):
|
|
14
|
-
def to_key_p(key_p: Predicate | str) -> Predicate:
|
|
15
|
-
from predicate.standard_predicates import eq_p
|
|
16
|
-
|
|
17
|
-
match key_p:
|
|
18
|
-
case str(s):
|
|
19
|
-
return eq_p(s)
|
|
20
|
-
case _:
|
|
21
|
-
return key_p
|
|
22
|
-
|
|
23
15
|
self.key_value_predicates = [(to_key_p(key_p), value_p) for key_p, value_p in key_value_predicates]
|
|
24
16
|
|
|
25
17
|
def __call__(self, x: Any) -> bool:
|
|
@@ -42,10 +34,37 @@ class DictOfPredicate[T](Predicate[T]):
|
|
|
42
34
|
return True
|
|
43
35
|
|
|
44
36
|
def __repr__(self) -> str:
|
|
45
|
-
|
|
46
|
-
|
|
37
|
+
def to_key_value_str(key_p: Predicate, value_p: Predicate) -> str:
|
|
38
|
+
return f"({repr(from_key_p(key_p))}, {repr(value_p)})"
|
|
39
|
+
|
|
40
|
+
key_value_predicates = ", ".join(
|
|
41
|
+
to_key_value_str(key_p, value_p) for key_p, value_p in self.key_value_predicates
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
return f"is_dict_of_p({key_value_predicates})"
|
|
47
45
|
|
|
48
46
|
@override
|
|
49
47
|
def explain_failure(self, x: Any) -> dict:
|
|
50
|
-
|
|
51
|
-
|
|
48
|
+
match x:
|
|
49
|
+
case dict():
|
|
50
|
+
return {"key_value_predicates": []}
|
|
51
|
+
case _:
|
|
52
|
+
return {"reason": f"{x} is not an instance of a dict"}
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def to_key_p(key_p: Predicate | str) -> Predicate:
|
|
56
|
+
from predicate.standard_predicates import eq_p
|
|
57
|
+
|
|
58
|
+
match key_p:
|
|
59
|
+
case str(s):
|
|
60
|
+
return eq_p(s)
|
|
61
|
+
case _:
|
|
62
|
+
return key_p
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def from_key_p(key_p: Predicate) -> Predicate | str:
|
|
66
|
+
match key_p:
|
|
67
|
+
case EqPredicate(v):
|
|
68
|
+
return v
|
|
69
|
+
case _:
|
|
70
|
+
return key_p
|
|
@@ -14,8 +14,8 @@ class FnPredicate[T](Predicate[T]):
|
|
|
14
14
|
return self.predicate_fn(x)
|
|
15
15
|
|
|
16
16
|
def __repr__(self) -> str:
|
|
17
|
-
return "fn_p"
|
|
17
|
+
return f"fn_p(predicate_fn={self.predicate_fn.__name__})"
|
|
18
18
|
|
|
19
19
|
@override
|
|
20
20
|
def explain_failure(self, x: T) -> dict:
|
|
21
|
-
return {"
|
|
21
|
+
return {"reason": f"Function returned False for value {x}"}
|
|
@@ -6,15 +6,21 @@ import graphviz # type: ignore
|
|
|
6
6
|
from more_itertools import first
|
|
7
7
|
|
|
8
8
|
from predicate.all_predicate import AllPredicate
|
|
9
|
+
from predicate.always_false_predicate import AlwaysFalsePredicate
|
|
10
|
+
from predicate.always_true_predicate import AlwaysTruePredicate
|
|
9
11
|
from predicate.any_predicate import AnyPredicate
|
|
10
12
|
from predicate.comp_predicate import CompPredicate
|
|
11
13
|
from predicate.dict_of_predicate import DictOfPredicate
|
|
12
14
|
from predicate.eq_predicate import EqPredicate
|
|
13
15
|
from predicate.fn_predicate import FnPredicate
|
|
16
|
+
from predicate.formatter.helpers import set_to_str
|
|
14
17
|
from predicate.ge_predicate import GePredicate
|
|
15
18
|
from predicate.gt_predicate import GtPredicate
|
|
19
|
+
from predicate.implies import Implies
|
|
20
|
+
from predicate.is_falsy_predicate import IsFalsyPredicate
|
|
16
21
|
from predicate.is_instance_predicate import IsInstancePredicate
|
|
17
22
|
from predicate.is_none_predicate import IsNonePredicate
|
|
23
|
+
from predicate.is_truthy_predicate import IsTruthyPredicate
|
|
18
24
|
from predicate.lazy_predicate import LazyPredicate, find_predicate_by_ref
|
|
19
25
|
from predicate.le_predicate import LePredicate
|
|
20
26
|
from predicate.lt_predicate import LtPredicate
|
|
@@ -22,11 +28,7 @@ from predicate.named_predicate import NamedPredicate
|
|
|
22
28
|
from predicate.ne_predicate import NePredicate
|
|
23
29
|
from predicate.optimizer.predicate_optimizer import optimize
|
|
24
30
|
from predicate.predicate import (
|
|
25
|
-
AlwaysFalsePredicate,
|
|
26
|
-
AlwaysTruePredicate,
|
|
27
31
|
AndPredicate,
|
|
28
|
-
IsFalsyPredicate,
|
|
29
|
-
IsTruthyPredicate,
|
|
30
32
|
NotPredicate,
|
|
31
33
|
OrPredicate,
|
|
32
34
|
Predicate,
|
|
@@ -69,12 +71,6 @@ def to_dot(predicate: Predicate, predicate_string: str | None = None, show_optim
|
|
|
69
71
|
return dot
|
|
70
72
|
|
|
71
73
|
|
|
72
|
-
def set_to_str(v: set) -> str:
|
|
73
|
-
# TODO: truncate if too many items.
|
|
74
|
-
items = ", ".join(str(item) for item in v)
|
|
75
|
-
return f"{{{items}}}"
|
|
76
|
-
|
|
77
|
-
|
|
78
74
|
def render(dot, predicate: Predicate, node_nr: count):
|
|
79
75
|
node_predicate_mapping: dict[str, Predicate] = {}
|
|
80
76
|
|
|
@@ -147,6 +143,8 @@ def render(dot, predicate: Predicate, node_nr: count):
|
|
|
147
143
|
dot.edge(kv, to_value(key), label="key")
|
|
148
144
|
dot.edge(kv, to_value(value), label="value")
|
|
149
145
|
return node
|
|
146
|
+
case Implies(left, right):
|
|
147
|
+
return add_node_left_right("implies", label="=>", left=left, right=right)
|
|
150
148
|
case IsInstancePredicate(klass):
|
|
151
149
|
name = klass[0].__name__ # type: ignore
|
|
152
150
|
return add_node("instance", label=f"is_{name}_p")
|
|
@@ -209,15 +207,12 @@ def render_lazy_references(dot, node_predicate_mapping) -> None:
|
|
|
209
207
|
|
|
210
208
|
for node, predicate in node_predicate_mapping.items():
|
|
211
209
|
match predicate:
|
|
212
|
-
case LazyPredicate():
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
case ThisPredicate():
|
|
219
|
-
if this := find_this_predicate(frame, predicate):
|
|
220
|
-
add_dashed_line(node, this)
|
|
210
|
+
case LazyPredicate() if reference := find_predicate_by_ref(frame, predicate.ref):
|
|
211
|
+
add_dashed_line(node, reference)
|
|
212
|
+
case RootPredicate() if root := find_root_predicate(frame, predicate):
|
|
213
|
+
add_dashed_line(node, root)
|
|
214
|
+
case ThisPredicate() if this := find_this_predicate(frame, predicate):
|
|
215
|
+
add_dashed_line(node, this)
|
|
221
216
|
|
|
222
217
|
|
|
223
218
|
def render_original(dot, predicate: Predicate, node_nr) -> None:
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
from typing import Any
|
|
2
2
|
|
|
3
3
|
from predicate.all_predicate import AllPredicate
|
|
4
|
+
from predicate.always_false_predicate import AlwaysFalsePredicate
|
|
5
|
+
from predicate.always_true_predicate import AlwaysTruePredicate
|
|
4
6
|
from predicate.any_predicate import AnyPredicate
|
|
5
7
|
from predicate.fn_predicate import FnPredicate
|
|
8
|
+
from predicate.is_falsy_predicate import IsFalsyPredicate
|
|
9
|
+
from predicate.is_truthy_predicate import IsTruthyPredicate
|
|
6
10
|
from predicate.named_predicate import NamedPredicate
|
|
7
11
|
from predicate.ne_predicate import NePredicate
|
|
8
12
|
from predicate.predicate import (
|
|
9
|
-
AlwaysFalsePredicate,
|
|
10
|
-
AlwaysTruePredicate,
|
|
11
13
|
AndPredicate,
|
|
12
|
-
IsFalsyPredicate,
|
|
13
|
-
IsTruthyPredicate,
|
|
14
14
|
NotPredicate,
|
|
15
15
|
OrPredicate,
|
|
16
16
|
Predicate,
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
from predicate.all_predicate import AllPredicate
|
|
2
|
+
from predicate.always_false_predicate import AlwaysFalsePredicate
|
|
3
|
+
from predicate.always_true_predicate import AlwaysTruePredicate
|
|
4
|
+
from predicate.any_predicate import AnyPredicate
|
|
5
|
+
from predicate.eq_predicate import EqPredicate
|
|
6
|
+
from predicate.ge_predicate import GePredicate
|
|
7
|
+
from predicate.gt_predicate import GtPredicate
|
|
8
|
+
from predicate.implies_predicate import ImpliesPredicate
|
|
9
|
+
from predicate.le_predicate import LePredicate
|
|
10
|
+
from predicate.lt_predicate import LtPredicate
|
|
11
|
+
from predicate.ne_predicate import NePredicate
|
|
12
|
+
from predicate.predicate import (
|
|
13
|
+
AndPredicate,
|
|
14
|
+
NotPredicate,
|
|
15
|
+
OrPredicate,
|
|
16
|
+
Predicate,
|
|
17
|
+
XorPredicate,
|
|
18
|
+
)
|
|
19
|
+
from predicate.range_predicate import GeLePredicate, GeLtPredicate, GtLePredicate, GtLtPredicate
|
|
20
|
+
from predicate.set_predicates import (
|
|
21
|
+
InPredicate,
|
|
22
|
+
IsRealSubsetPredicate,
|
|
23
|
+
IsRealSupersetPredicate,
|
|
24
|
+
IsSubsetPredicate,
|
|
25
|
+
IsSupersetPredicate,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def set_to_latex_set(v: set) -> str:
|
|
30
|
+
items = ", ".join(str(item) for item in v)
|
|
31
|
+
return f"\\{{{items}\\}}"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def to_latex(predicate: Predicate) -> str:
|
|
35
|
+
"""Format predicate as LaTeX."""
|
|
36
|
+
match predicate:
|
|
37
|
+
case AllPredicate(all_predicate):
|
|
38
|
+
return f"\\forall x \\in S, {to_latex(all_predicate)}"
|
|
39
|
+
case AlwaysFalsePredicate():
|
|
40
|
+
return "False"
|
|
41
|
+
case AlwaysTruePredicate():
|
|
42
|
+
return "True"
|
|
43
|
+
case AndPredicate(left, right):
|
|
44
|
+
return f"{to_latex(left)} \\wedge {to_latex(right)}"
|
|
45
|
+
case AnyPredicate(all_predicate):
|
|
46
|
+
return f"\\exists x \\in S, {to_latex(all_predicate)}"
|
|
47
|
+
case EqPredicate(v):
|
|
48
|
+
return f"x = {v}"
|
|
49
|
+
case GePredicate(v):
|
|
50
|
+
return f"x \\ge {v}"
|
|
51
|
+
case GeLePredicate(lower, upper):
|
|
52
|
+
return f"{lower} \\le x \\le {upper}"
|
|
53
|
+
case GeLtPredicate(lower, upper):
|
|
54
|
+
return f"{lower} \\le x \\lt {upper}"
|
|
55
|
+
case GtLePredicate(lower, upper):
|
|
56
|
+
return f"{lower} \\lt x \\le {upper}"
|
|
57
|
+
case GtLtPredicate(lower, upper):
|
|
58
|
+
return f"{lower} \\lt x \\lt {upper}"
|
|
59
|
+
case GtPredicate(v):
|
|
60
|
+
return f"x \\gt {v}"
|
|
61
|
+
case ImpliesPredicate(p):
|
|
62
|
+
return f"p \\implies {to_latex(p)}"
|
|
63
|
+
case InPredicate(v):
|
|
64
|
+
return f"x \\in {set_to_latex_set(v)}"
|
|
65
|
+
case IsRealSubsetPredicate(v):
|
|
66
|
+
return f"x \\subseteq {set_to_latex_set(v)}"
|
|
67
|
+
case IsSubsetPredicate(v):
|
|
68
|
+
return f"x \\subset {set_to_latex_set(v)}"
|
|
69
|
+
case IsRealSupersetPredicate(v):
|
|
70
|
+
return f"x \\supseteq {set_to_latex_set(v)}"
|
|
71
|
+
case IsSupersetPredicate(v):
|
|
72
|
+
return f"x \\supset {set_to_latex_set(v)}"
|
|
73
|
+
case LePredicate(v):
|
|
74
|
+
return f"x \\le {v}"
|
|
75
|
+
case LtPredicate(v):
|
|
76
|
+
return f"x \\lt {v}"
|
|
77
|
+
case NePredicate(v):
|
|
78
|
+
return f"x \\neq {v}"
|
|
79
|
+
case NotPredicate(child):
|
|
80
|
+
return f"\\neg {to_latex(child)}"
|
|
81
|
+
case OrPredicate(left, right):
|
|
82
|
+
return f"{to_latex(left)} \\vee {to_latex(right)}"
|
|
83
|
+
case XorPredicate(left, right):
|
|
84
|
+
return f"{to_latex(left)} \\oplus {to_latex(right)}"
|
|
85
|
+
case _:
|
|
86
|
+
raise ValueError(f"Unknown predicate type {predicate}")
|