py-predicate 0.4__tar.gz → 0.5__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.4 → py_predicate-0.5}/PKG-INFO +3 -3
- {py_predicate-0.4 → py_predicate-0.5}/README.md +2 -2
- {py_predicate-0.4 → py_predicate-0.5}/predicate/__init__.py +44 -11
- {py_predicate-0.4 → py_predicate-0.5}/predicate/all_predicate.py +2 -5
- {py_predicate-0.4 → py_predicate-0.5}/predicate/any_predicate.py +2 -5
- {py_predicate-0.4 → py_predicate-0.5}/predicate/formatter/format_dot.py +51 -46
- {py_predicate-0.4 → py_predicate-0.5}/predicate/generator/generate_false.py +55 -3
- {py_predicate-0.4 → py_predicate-0.5}/predicate/generator/generate_true.py +50 -6
- {py_predicate-0.4 → py_predicate-0.5}/predicate/generator/helpers.py +8 -9
- {py_predicate-0.4 → py_predicate-0.5}/predicate/has_key_predicate.py +1 -5
- py_predicate-0.5/predicate/has_length_predicate.py +19 -0
- {py_predicate-0.4 → py_predicate-0.5}/predicate/implies.py +48 -3
- py_predicate-0.5/predicate/ip_address_predicates.py +47 -0
- {py_predicate-0.4 → py_predicate-0.5}/predicate/is_instance_predicate.py +0 -3
- {py_predicate-0.4 → py_predicate-0.5}/predicate/named_predicate.py +0 -3
- {py_predicate-0.4 → py_predicate-0.5}/predicate/optimizer/and_optimizer.py +5 -12
- py_predicate-0.5/predicate/optimizer/in_optimizer.py +24 -0
- {py_predicate-0.4 → py_predicate-0.5}/predicate/optimizer/or_optimizer.py +12 -9
- {py_predicate-0.4 → py_predicate-0.5}/predicate/optimizer/predicate_optimizer.py +6 -2
- {py_predicate-0.4 → py_predicate-0.5}/predicate/optimizer/xor_optimizer.py +7 -2
- {py_predicate-0.4 → py_predicate-0.5}/predicate/predicate.py +0 -76
- py_predicate-0.5/predicate/property_predicate.py +20 -0
- {py_predicate-0.4 → py_predicate-0.5}/predicate/range_predicate.py +0 -12
- py_predicate-0.5/predicate/set_of_predicate.py +16 -0
- py_predicate-0.5/predicate/set_predicates.py +120 -0
- {py_predicate-0.4 → py_predicate-0.5}/predicate/standard_predicates.py +8 -22
- py_predicate-0.5/predicate/str_predicates.py +55 -0
- py_predicate-0.5/predicate/tuple_of_predicate.py +19 -0
- {py_predicate-0.4 → py_predicate-0.5}/pyproject.toml +1 -1
- py_predicate-0.4/predicate/optimizer/in_optimizer.py +0 -13
- {py_predicate-0.4 → py_predicate-0.5}/predicate/comp_predicate.py +0 -0
- {py_predicate-0.4 → py_predicate-0.5}/predicate/constructor/__init__.py +0 -0
- {py_predicate-0.4 → py_predicate-0.5}/predicate/constructor/construct.py +0 -0
- {py_predicate-0.4 → py_predicate-0.5}/predicate/formatter/__init__.py +0 -0
- {py_predicate-0.4 → py_predicate-0.5}/predicate/formatter/format_json.py +0 -0
- {py_predicate-0.4 → py_predicate-0.5}/predicate/generator/__init__.py +0 -0
- {py_predicate-0.4 → py_predicate-0.5}/predicate/lazy_predicate.py +0 -0
- {py_predicate-0.4 → py_predicate-0.5}/predicate/negate.py +0 -0
- {py_predicate-0.4 → py_predicate-0.5}/predicate/optimizer/__init__.py +0 -0
- {py_predicate-0.4 → py_predicate-0.5}/predicate/optimizer/all_optimizer.py +0 -0
- {py_predicate-0.4 → py_predicate-0.5}/predicate/optimizer/any_optimizer.py +0 -0
- {py_predicate-0.4 → py_predicate-0.5}/predicate/optimizer/not_optimizer.py +0 -0
- {py_predicate-0.4 → py_predicate-0.5}/predicate/optimizer/rules.py +0 -0
- {py_predicate-0.4 → py_predicate-0.5}/predicate/parser.py +0 -0
- {py_predicate-0.4 → py_predicate-0.5}/predicate/regex_predicate.py +0 -0
- {py_predicate-0.4 → py_predicate-0.5}/predicate/root_predicate.py +0 -0
- {py_predicate-0.4 → py_predicate-0.5}/predicate/tee_predicate.py +0 -0
- {py_predicate-0.4 → py_predicate-0.5}/predicate/this_predicate.py +0 -0
- {py_predicate-0.4 → py_predicate-0.5}/predicate/truth_table.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: py_predicate
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5
|
|
4
4
|
Summary: Module to create composable predicates
|
|
5
5
|
Author-email: Maurits Rijk <maurits.rijk@gmail.com>
|
|
6
6
|
Requires-Python: >=3.10
|
|
@@ -91,9 +91,9 @@ either a string, or a list of data that can again either be a string or a list o
|
|
|
91
91
|
data. Ad infinitum.
|
|
92
92
|
|
|
93
93
|
```python
|
|
94
|
-
from predicate import all_p, is_list_p, is_str_p,
|
|
94
|
+
from predicate import all_p, is_list_p, is_str_p, root_p
|
|
95
95
|
|
|
96
|
-
str_or_list_of_str = is_str_p | (is_list_p & all_p(
|
|
96
|
+
str_or_list_of_str = is_str_p | (is_list_p & all_p(root_p))
|
|
97
97
|
```
|
|
98
98
|
|
|
99
99
|
Using plain Python, the above one-liner would have to be coded as a (recursive) function.
|
|
@@ -48,9 +48,9 @@ either a string, or a list of data that can again either be a string or a list o
|
|
|
48
48
|
data. Ad infinitum.
|
|
49
49
|
|
|
50
50
|
```python
|
|
51
|
-
from predicate import all_p, is_list_p, is_str_p,
|
|
51
|
+
from predicate import all_p, is_list_p, is_str_p, root_p
|
|
52
52
|
|
|
53
|
-
str_or_list_of_str = is_str_p | (is_list_p & all_p(
|
|
53
|
+
str_or_list_of_str = is_str_p | (is_list_p & all_p(root_p))
|
|
54
54
|
```
|
|
55
55
|
|
|
56
56
|
Using plain Python, the above one-liner would have to be coded as a (recursive) function.
|
|
@@ -17,14 +17,12 @@ from predicate.predicate import (
|
|
|
17
17
|
FnPredicate,
|
|
18
18
|
GePredicate,
|
|
19
19
|
GtPredicate,
|
|
20
|
-
InPredicate,
|
|
21
20
|
IsEmptyPredicate,
|
|
22
21
|
IsNonePredicate,
|
|
23
22
|
IsNotNonePredicate,
|
|
24
23
|
LePredicate,
|
|
25
24
|
LtPredicate,
|
|
26
25
|
NePredicate,
|
|
27
|
-
NotInPredicate,
|
|
28
26
|
NotPredicate,
|
|
29
27
|
OrPredicate,
|
|
30
28
|
Predicate,
|
|
@@ -33,6 +31,16 @@ from predicate.predicate import (
|
|
|
33
31
|
always_true_p,
|
|
34
32
|
is_empty_p,
|
|
35
33
|
)
|
|
34
|
+
from predicate.set_predicates import (
|
|
35
|
+
InPredicate,
|
|
36
|
+
NotInPredicate,
|
|
37
|
+
in_p,
|
|
38
|
+
is_real_subset_p,
|
|
39
|
+
is_real_superset_p,
|
|
40
|
+
is_subset_p,
|
|
41
|
+
is_superset_p,
|
|
42
|
+
not_in_p,
|
|
43
|
+
)
|
|
36
44
|
from predicate.standard_predicates import (
|
|
37
45
|
all_p,
|
|
38
46
|
any_p,
|
|
@@ -47,7 +55,7 @@ from predicate.standard_predicates import (
|
|
|
47
55
|
gt_le_p,
|
|
48
56
|
gt_lt_p,
|
|
49
57
|
gt_p,
|
|
50
|
-
|
|
58
|
+
has_length_p,
|
|
51
59
|
is_bool_p,
|
|
52
60
|
is_callable_p,
|
|
53
61
|
is_complex_p,
|
|
@@ -68,6 +76,7 @@ from predicate.standard_predicates import (
|
|
|
68
76
|
is_none_p,
|
|
69
77
|
is_not_none_p,
|
|
70
78
|
is_predicate_p,
|
|
79
|
+
is_range_p,
|
|
71
80
|
is_set_of_p,
|
|
72
81
|
is_set_p,
|
|
73
82
|
is_str_p,
|
|
@@ -80,7 +89,6 @@ from predicate.standard_predicates import (
|
|
|
80
89
|
lt_p,
|
|
81
90
|
ne_p,
|
|
82
91
|
neg_p,
|
|
83
|
-
not_in_p,
|
|
84
92
|
pos_p,
|
|
85
93
|
regex_p,
|
|
86
94
|
root_p,
|
|
@@ -90,9 +98,9 @@ from predicate.standard_predicates import (
|
|
|
90
98
|
)
|
|
91
99
|
|
|
92
100
|
__all__ = [
|
|
101
|
+
"AllPredicate",
|
|
93
102
|
"AlwaysFalsePredicate",
|
|
94
103
|
"AlwaysTruePredicate",
|
|
95
|
-
"AllPredicate",
|
|
96
104
|
"AndPredicate",
|
|
97
105
|
"AnyPredicate",
|
|
98
106
|
"EqPredicate",
|
|
@@ -120,7 +128,6 @@ __all__ = [
|
|
|
120
128
|
"eq_false_p",
|
|
121
129
|
"eq_p",
|
|
122
130
|
"eq_true_p",
|
|
123
|
-
"is_falsy_p",
|
|
124
131
|
"fn_p",
|
|
125
132
|
"ge_le_p",
|
|
126
133
|
"ge_lt_p",
|
|
@@ -130,33 +137,48 @@ __all__ = [
|
|
|
130
137
|
"gt_le_p",
|
|
131
138
|
"gt_lt_p",
|
|
132
139
|
"gt_p",
|
|
140
|
+
"has_length_p",
|
|
133
141
|
"in_p",
|
|
142
|
+
"is_alnum_p",
|
|
143
|
+
"is_alpha_p",
|
|
144
|
+
"is_ascii_p",
|
|
134
145
|
"is_bool_p",
|
|
135
146
|
"is_callable_p",
|
|
136
147
|
"is_complex_p",
|
|
137
148
|
"is_container_p",
|
|
138
149
|
"is_datetime_p",
|
|
150
|
+
"is_decimal_p",
|
|
139
151
|
"is_dict_p",
|
|
140
152
|
"is_empty_p",
|
|
153
|
+
"is_falsy_p",
|
|
141
154
|
"is_finite_p",
|
|
142
155
|
"is_float_p",
|
|
143
156
|
"is_hashable_p",
|
|
144
|
-
"
|
|
157
|
+
"is_identifier_p",
|
|
145
158
|
"is_inf_p",
|
|
159
|
+
"is_instance_p",
|
|
146
160
|
"is_int_p",
|
|
147
|
-
"is_iterable_p",
|
|
148
161
|
"is_iterable_of_p",
|
|
149
|
-
"
|
|
162
|
+
"is_iterable_p",
|
|
150
163
|
"is_list_of_p",
|
|
164
|
+
"is_list_p",
|
|
165
|
+
"is_lower_p",
|
|
151
166
|
"is_none_p",
|
|
152
167
|
"is_not_none_p",
|
|
153
168
|
"is_predicate_p",
|
|
154
|
-
"
|
|
169
|
+
"is_range_p",
|
|
155
170
|
"is_set_of_p",
|
|
171
|
+
"is_set_p",
|
|
156
172
|
"is_str_p",
|
|
173
|
+
"is_subset_p",
|
|
174
|
+
"is_superset_p",
|
|
175
|
+
"is_real_subset_p",
|
|
176
|
+
"is_real_superset_p",
|
|
177
|
+
"is_title_p",
|
|
157
178
|
"is_truthy_p",
|
|
158
|
-
"is_tuple_p",
|
|
159
179
|
"is_tuple_of_p",
|
|
180
|
+
"is_tuple_p",
|
|
181
|
+
"is_upper_p",
|
|
160
182
|
"is_uuid_p",
|
|
161
183
|
"lazy_p",
|
|
162
184
|
"le_p",
|
|
@@ -174,3 +196,14 @@ __all__ = [
|
|
|
174
196
|
"to_json",
|
|
175
197
|
"zero_p",
|
|
176
198
|
]
|
|
199
|
+
|
|
200
|
+
from predicate.str_predicates import (
|
|
201
|
+
is_alnum_p,
|
|
202
|
+
is_alpha_p,
|
|
203
|
+
is_ascii_p,
|
|
204
|
+
is_decimal_p,
|
|
205
|
+
is_identifier_p,
|
|
206
|
+
is_lower_p,
|
|
207
|
+
is_title_p,
|
|
208
|
+
is_upper_p,
|
|
209
|
+
)
|
|
@@ -10,11 +10,8 @@ class AllPredicate[T](Predicate[T]):
|
|
|
10
10
|
|
|
11
11
|
predicate: Predicate[T]
|
|
12
12
|
|
|
13
|
-
def __call__(self,
|
|
14
|
-
return all(self.predicate(x) for x in
|
|
15
|
-
|
|
16
|
-
def __eq__(self, other: object) -> bool:
|
|
17
|
-
return isinstance(other, AllPredicate) and self.predicate == other.predicate
|
|
13
|
+
def __call__(self, iterable: Iterable[T]) -> bool:
|
|
14
|
+
return all(self.predicate(x) for x in iterable)
|
|
18
15
|
|
|
19
16
|
def __repr__(self) -> str:
|
|
20
17
|
return f"all({repr(self.predicate)})"
|
|
@@ -10,11 +10,8 @@ class AnyPredicate[T](Predicate[T]):
|
|
|
10
10
|
|
|
11
11
|
predicate: Predicate[T]
|
|
12
12
|
|
|
13
|
-
def __call__(self,
|
|
14
|
-
return any(self.predicate(x) for x in
|
|
15
|
-
|
|
16
|
-
def __eq__(self, other: object) -> bool:
|
|
17
|
-
return isinstance(other, AnyPredicate) and self.predicate == other.predicate
|
|
13
|
+
def __call__(self, iterable: Iterable[T]) -> bool:
|
|
14
|
+
return any(self.predicate(x) for x in iterable)
|
|
18
15
|
|
|
19
16
|
def __repr__(self) -> str:
|
|
20
17
|
return f"any({repr(self.predicate)})"
|
|
@@ -25,17 +25,23 @@ from predicate.predicate import (
|
|
|
25
25
|
)
|
|
26
26
|
from predicate.range_predicate import GeLePredicate, GeLtPredicate, GtLePredicate, GtLtPredicate
|
|
27
27
|
from predicate.root_predicate import RootPredicate, find_root_predicate
|
|
28
|
+
from predicate.set_predicates import (
|
|
29
|
+
InPredicate,
|
|
30
|
+
IsRealSubsetPredicate,
|
|
31
|
+
IsRealSupersetPredicate,
|
|
32
|
+
IsSubsetPredicate,
|
|
33
|
+
IsSupersetPredicate,
|
|
34
|
+
NotInPredicate,
|
|
35
|
+
)
|
|
28
36
|
from predicate.standard_predicates import (
|
|
29
37
|
EqPredicate,
|
|
30
38
|
FnPredicate,
|
|
31
39
|
GePredicate,
|
|
32
40
|
GtPredicate,
|
|
33
|
-
InPredicate,
|
|
34
41
|
IsNonePredicate,
|
|
35
42
|
LePredicate,
|
|
36
43
|
LtPredicate,
|
|
37
44
|
NePredicate,
|
|
38
|
-
NotInPredicate,
|
|
39
45
|
)
|
|
40
46
|
from predicate.tee_predicate import TeePredicate
|
|
41
47
|
from predicate.this_predicate import ThisPredicate, find_this_predicate
|
|
@@ -61,46 +67,52 @@ def to_dot(predicate: Predicate, predicate_string: str = "", show_optimized: boo
|
|
|
61
67
|
return dot
|
|
62
68
|
|
|
63
69
|
|
|
70
|
+
def set_to_str(v: set) -> str:
|
|
71
|
+
# TODO: truncate if too many items.
|
|
72
|
+
items = ", ".join(str(item) for item in v)
|
|
73
|
+
return f"{{{items}}}"
|
|
74
|
+
|
|
75
|
+
|
|
64
76
|
def render(dot, predicate: Predicate, node_nr):
|
|
65
77
|
node_predicate_mapping: dict[str, Predicate] = {}
|
|
66
78
|
|
|
67
|
-
def _add_node(name: str, *, label: str, predicate: Predicate):
|
|
79
|
+
def _add_node(name: str, *, label: str, predicate: Predicate) -> str:
|
|
68
80
|
node = next(node_nr)
|
|
69
81
|
unique_name = f"{name}_{node}"
|
|
70
82
|
dot.node(unique_name, label=label)
|
|
71
83
|
node_predicate_mapping[unique_name] = predicate
|
|
72
84
|
return unique_name
|
|
73
85
|
|
|
86
|
+
def _add_node_left_right(name: str, *, label: str, predicate: Predicate, left: Predicate, right: Predicate) -> str:
|
|
87
|
+
node = _add_node(name, label=label, predicate=predicate)
|
|
88
|
+
dot.edge(node, to_value(left))
|
|
89
|
+
dot.edge(node, to_value(right))
|
|
90
|
+
|
|
91
|
+
return node
|
|
92
|
+
|
|
93
|
+
def _add_node_with_child(name: str, *, label: str, predicate: Predicate, child: Predicate) -> str:
|
|
94
|
+
node = _add_node(name, label=label, predicate=predicate)
|
|
95
|
+
dot.edge(node, to_value(child))
|
|
96
|
+
return node
|
|
97
|
+
|
|
74
98
|
def to_value(predicate: Predicate):
|
|
75
99
|
add_node = partial(_add_node, predicate=predicate)
|
|
100
|
+
add_node_left_right = partial(_add_node_left_right, predicate=predicate)
|
|
101
|
+
add_node_with_child = partial(_add_node_with_child, predicate=predicate)
|
|
76
102
|
|
|
77
103
|
match predicate:
|
|
78
104
|
case AllPredicate(all_predicate):
|
|
79
|
-
|
|
80
|
-
child = to_value(all_predicate)
|
|
81
|
-
dot.edge(node, child)
|
|
82
|
-
return node
|
|
105
|
+
return add_node_with_child("all", label="∀", child=all_predicate)
|
|
83
106
|
case AlwaysFalsePredicate():
|
|
84
107
|
return add_node("F", label="false")
|
|
85
108
|
case AlwaysTruePredicate():
|
|
86
109
|
return add_node("T", label="true")
|
|
87
110
|
case AndPredicate(left, right):
|
|
88
|
-
|
|
89
|
-
left_node = to_value(left)
|
|
90
|
-
right_node = to_value(right)
|
|
91
|
-
dot.edge(node, left_node)
|
|
92
|
-
dot.edge(node, right_node)
|
|
93
|
-
return node
|
|
111
|
+
return add_node_left_right("and", label="∧", left=left, right=right)
|
|
94
112
|
case AnyPredicate(any_predicate):
|
|
95
|
-
|
|
96
|
-
child = to_value(any_predicate)
|
|
97
|
-
dot.edge(node, child)
|
|
98
|
-
return node
|
|
113
|
+
return add_node_with_child("any", label="∃", child=any_predicate)
|
|
99
114
|
case CompPredicate(_fn, comp_predicate):
|
|
100
|
-
|
|
101
|
-
child = to_value(comp_predicate)
|
|
102
|
-
dot.edge(node, child)
|
|
103
|
-
return node
|
|
115
|
+
return add_node_with_child("comp", label="f", child=comp_predicate)
|
|
104
116
|
case EqPredicate(v):
|
|
105
117
|
return add_node("eq", label=f"x = {v}")
|
|
106
118
|
case IsFalsyPredicate():
|
|
@@ -119,17 +131,24 @@ def render(dot, predicate: Predicate, node_nr):
|
|
|
119
131
|
case GtPredicate(v):
|
|
120
132
|
return add_node("gt", label=f"x > {v}")
|
|
121
133
|
case GtLePredicate(upper, lower):
|
|
122
|
-
return add_node("
|
|
134
|
+
return add_node("gtle", label=f"{lower} ≤ x ≤ {upper}")
|
|
123
135
|
case GtLtPredicate(upper, lower):
|
|
124
|
-
return add_node("
|
|
136
|
+
return add_node("gtlt", label=f"{lower} ≤ x < {upper}")
|
|
125
137
|
case InPredicate(v):
|
|
126
|
-
|
|
127
|
-
return add_node("in", label=f"x ∈ {{{items}}}")
|
|
138
|
+
return add_node("in", label=f"x ∈ {set_to_str(v)}")
|
|
128
139
|
case IsInstancePredicate(klass):
|
|
129
140
|
name = klass[0].__name__ # type: ignore
|
|
130
141
|
return add_node("instance", label=f"is_{name}_p")
|
|
131
142
|
case IsNonePredicate():
|
|
132
143
|
return add_node("none", label="x = None")
|
|
144
|
+
case IsRealSubsetPredicate(v):
|
|
145
|
+
return add_node("real_subset", label=f"x ⊂ {set_to_str(v)}")
|
|
146
|
+
case IsSubsetPredicate(v):
|
|
147
|
+
return add_node("subset", label=f"x ⊆ {set_to_str(v)}")
|
|
148
|
+
case IsRealSupersetPredicate(v):
|
|
149
|
+
return add_node("real_superset", label=f"x ⊃ {set_to_str(v)}")
|
|
150
|
+
case IsSupersetPredicate(v):
|
|
151
|
+
return add_node("superset", label=f"x ⊇ {set_to_str(v)}")
|
|
133
152
|
case LazyPredicate(ref):
|
|
134
153
|
return add_node("lazy", label=ref)
|
|
135
154
|
case LePredicate(v):
|
|
@@ -139,22 +158,13 @@ def render(dot, predicate: Predicate, node_nr):
|
|
|
139
158
|
case NamedPredicate(name):
|
|
140
159
|
return add_node("named", label=name)
|
|
141
160
|
case NotInPredicate(v):
|
|
142
|
-
|
|
143
|
-
return add_node("in", label=f"x ∉ {{{items}}}")
|
|
161
|
+
return add_node("in", label=f"x ∉ {set_to_str(v)}")
|
|
144
162
|
case NePredicate(v):
|
|
145
163
|
return add_node("ne", label=f"x ≠ {v}")
|
|
146
164
|
case NotPredicate(not_predicate):
|
|
147
|
-
|
|
148
|
-
node = add_node("not", label="¬")
|
|
149
|
-
dot.edge(node, child)
|
|
150
|
-
return node
|
|
165
|
+
return add_node_with_child("not", label="¬", child=not_predicate)
|
|
151
166
|
case OrPredicate(left, right):
|
|
152
|
-
|
|
153
|
-
left_node = to_value(left)
|
|
154
|
-
right_node = to_value(right)
|
|
155
|
-
dot.edge(node, left_node)
|
|
156
|
-
dot.edge(node, right_node)
|
|
157
|
-
return node
|
|
167
|
+
return add_node_left_right("or", label="∨", left=left, right=right)
|
|
158
168
|
case RootPredicate():
|
|
159
169
|
return add_node("root", label="root")
|
|
160
170
|
case TeePredicate():
|
|
@@ -162,12 +172,7 @@ def render(dot, predicate: Predicate, node_nr):
|
|
|
162
172
|
case ThisPredicate():
|
|
163
173
|
return add_node("this", label="this")
|
|
164
174
|
case XorPredicate(left, right):
|
|
165
|
-
|
|
166
|
-
left_node = to_value(left)
|
|
167
|
-
right_node = to_value(right)
|
|
168
|
-
dot.edge(node, left_node)
|
|
169
|
-
dot.edge(node, right_node)
|
|
170
|
-
return node
|
|
175
|
+
return add_node_left_right("xor", label="⊻", left=left, right=right)
|
|
171
176
|
case _:
|
|
172
177
|
raise ValueError(f"Unknown predicate type {predicate}")
|
|
173
178
|
|
|
@@ -176,7 +181,7 @@ def render(dot, predicate: Predicate, node_nr):
|
|
|
176
181
|
render_lazy_references(dot, node_predicate_mapping)
|
|
177
182
|
|
|
178
183
|
|
|
179
|
-
def render_lazy_references(dot, node_predicate_mapping):
|
|
184
|
+
def render_lazy_references(dot, node_predicate_mapping) -> None:
|
|
180
185
|
def find_in_mapping(lookup: Predicate) -> str:
|
|
181
186
|
return first(node for node, predicate in node_predicate_mapping.items() if predicate == lookup)
|
|
182
187
|
|
|
@@ -199,14 +204,14 @@ def render_lazy_references(dot, node_predicate_mapping):
|
|
|
199
204
|
add_dashed_line(node, this)
|
|
200
205
|
|
|
201
206
|
|
|
202
|
-
def render_original(dot, predicate: Predicate, node_nr):
|
|
207
|
+
def render_original(dot, predicate: Predicate, node_nr) -> None:
|
|
203
208
|
with dot.subgraph(name="cluster_original") as original:
|
|
204
209
|
original.attr(style="filled", color="lightgrey")
|
|
205
210
|
original.attr(label="Original predicate")
|
|
206
211
|
render(original, predicate, node_nr)
|
|
207
212
|
|
|
208
213
|
|
|
209
|
-
def render_optimized(dot, predicate: Predicate, node_nr):
|
|
214
|
+
def render_optimized(dot, predicate: Predicate, node_nr) -> None:
|
|
210
215
|
optimized_predicate = optimize(predicate)
|
|
211
216
|
|
|
212
217
|
with dot.subgraph(name="cluster_optimized") as optimized:
|
|
@@ -10,6 +10,7 @@ from more_itertools import random_combination_with_replacement, take
|
|
|
10
10
|
from predicate.all_predicate import AllPredicate
|
|
11
11
|
from predicate.generator.helpers import (
|
|
12
12
|
generate_anys,
|
|
13
|
+
generate_ints,
|
|
13
14
|
generate_strings,
|
|
14
15
|
generate_uuids,
|
|
15
16
|
random_anys,
|
|
@@ -24,15 +25,20 @@ from predicate.predicate import (
|
|
|
24
25
|
AndPredicate,
|
|
25
26
|
EqPredicate,
|
|
26
27
|
GePredicate,
|
|
28
|
+
GtPredicate,
|
|
29
|
+
IsEmptyPredicate,
|
|
27
30
|
IsFalsyPredicate,
|
|
28
31
|
IsNonePredicate,
|
|
29
32
|
IsNotNonePredicate,
|
|
30
33
|
IsTruthyPredicate,
|
|
34
|
+
NePredicate,
|
|
31
35
|
NotPredicate,
|
|
32
36
|
OrPredicate,
|
|
33
37
|
Predicate,
|
|
34
38
|
always_true_p,
|
|
35
39
|
)
|
|
40
|
+
from predicate.set_of_predicate import SetOfPredicate
|
|
41
|
+
from predicate.set_predicates import InPredicate
|
|
36
42
|
|
|
37
43
|
|
|
38
44
|
@singledispatch
|
|
@@ -58,8 +64,8 @@ def generate_and(predicate: AndPredicate) -> Iterator:
|
|
|
58
64
|
if optimize(predicate) == always_true_p:
|
|
59
65
|
yield from []
|
|
60
66
|
else:
|
|
61
|
-
yield from (item for item in generate_false(predicate.left)
|
|
62
|
-
yield from (item for item in generate_false(predicate.right)
|
|
67
|
+
yield from (item for item in generate_false(predicate.left))
|
|
68
|
+
yield from (item for item in generate_false(predicate.right))
|
|
63
69
|
|
|
64
70
|
|
|
65
71
|
@generate_false.register
|
|
@@ -92,14 +98,51 @@ def generate_ge(predicate: GePredicate) -> Iterator:
|
|
|
92
98
|
yield from generate_uuids(NotPredicate(predicate=predicate))
|
|
93
99
|
|
|
94
100
|
|
|
101
|
+
@generate_false.register
|
|
102
|
+
def generate_gt(predicate: GtPredicate) -> Iterator:
|
|
103
|
+
match predicate.v:
|
|
104
|
+
case datetime() as dt:
|
|
105
|
+
yield from (dt - timedelta(days=days) for days in range(0, 5))
|
|
106
|
+
case float():
|
|
107
|
+
yield from random_floats(upper=predicate.v)
|
|
108
|
+
case int():
|
|
109
|
+
yield from random_ints(upper=predicate.v)
|
|
110
|
+
case str():
|
|
111
|
+
yield from generate_strings(NotPredicate(predicate=predicate))
|
|
112
|
+
case uuid.UUID():
|
|
113
|
+
yield from generate_uuids(NotPredicate(predicate=predicate))
|
|
114
|
+
|
|
115
|
+
|
|
95
116
|
@generate_false.register
|
|
96
117
|
def generate_falsy(_predicate: IsFalsyPredicate) -> Iterator:
|
|
97
118
|
yield from generate_anys(IsTruthyPredicate())
|
|
98
119
|
|
|
99
120
|
|
|
121
|
+
@generate_false.register
|
|
122
|
+
def generate_in(predicate: InPredicate) -> Iterator:
|
|
123
|
+
# TODO: combine with generate_not_in true
|
|
124
|
+
for item in predicate.v:
|
|
125
|
+
match item:
|
|
126
|
+
case int():
|
|
127
|
+
yield from generate_ints(NotPredicate(predicate=predicate))
|
|
128
|
+
case str():
|
|
129
|
+
yield from generate_strings(NotPredicate(predicate=predicate))
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
@generate_false.register
|
|
133
|
+
def generate_is_empty(_predicate: IsEmptyPredicate) -> Iterator:
|
|
134
|
+
# TODO: add generic helper function
|
|
135
|
+
yield from ([1], {1, 2, 3}, (1,), "aap")
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
@generate_false.register
|
|
139
|
+
def generate_ne(predicate: NePredicate) -> Iterator:
|
|
140
|
+
yield from predicate.v
|
|
141
|
+
|
|
142
|
+
|
|
100
143
|
@generate_false.register
|
|
101
144
|
def generate_none(_predicate: IsNonePredicate) -> Iterator:
|
|
102
|
-
yield generate_anys(IsNotNonePredicate())
|
|
145
|
+
yield from generate_anys(IsNotNonePredicate())
|
|
103
146
|
|
|
104
147
|
|
|
105
148
|
@generate_false.register
|
|
@@ -122,3 +165,12 @@ def generate_is_instance_p(predicate: IsInstancePredicate) -> Iterator:
|
|
|
122
165
|
def generate_or(predicate: OrPredicate) -> Iterator:
|
|
123
166
|
yield from (item for item in generate_false(predicate.left) if not predicate.right(item))
|
|
124
167
|
yield from (item for item in generate_false(predicate.right) if not predicate.left(item))
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
@generate_false.register
|
|
171
|
+
def generate_set_of_p(set_of_predicate: SetOfPredicate) -> Iterator:
|
|
172
|
+
predicate = set_of_predicate.predicate
|
|
173
|
+
|
|
174
|
+
values = take(10, generate_false(predicate))
|
|
175
|
+
|
|
176
|
+
yield set(random_combination_with_replacement(values, 5))
|
|
@@ -4,15 +4,18 @@ import uuid
|
|
|
4
4
|
from collections.abc import Iterator
|
|
5
5
|
from datetime import datetime, timedelta
|
|
6
6
|
from functools import singledispatch
|
|
7
|
+
from itertools import cycle
|
|
7
8
|
|
|
8
9
|
import exrex # type: ignore
|
|
9
|
-
from more_itertools import interleave, random_combination_with_replacement, take
|
|
10
|
+
from more_itertools import interleave, powerset_of_sets, random_combination_with_replacement, take
|
|
10
11
|
|
|
11
12
|
from predicate.any_predicate import AnyPredicate
|
|
12
13
|
from predicate.generator.helpers import (
|
|
14
|
+
generate_anys,
|
|
13
15
|
generate_ints,
|
|
14
16
|
generate_strings,
|
|
15
17
|
generate_uuids,
|
|
18
|
+
random_anys,
|
|
16
19
|
random_complex_numbers,
|
|
17
20
|
random_datetimes,
|
|
18
21
|
random_dicts,
|
|
@@ -21,6 +24,7 @@ from predicate.generator.helpers import (
|
|
|
21
24
|
random_strings,
|
|
22
25
|
random_uuids,
|
|
23
26
|
)
|
|
27
|
+
from predicate.has_key_predicate import HasKeyPredicate
|
|
24
28
|
from predicate.is_instance_predicate import IsInstancePredicate
|
|
25
29
|
from predicate.optimizer.predicate_optimizer import optimize
|
|
26
30
|
from predicate.predicate import (
|
|
@@ -30,7 +34,7 @@ from predicate.predicate import (
|
|
|
30
34
|
EqPredicate,
|
|
31
35
|
GePredicate,
|
|
32
36
|
GtPredicate,
|
|
33
|
-
|
|
37
|
+
IsEmptyPredicate,
|
|
34
38
|
IsFalsyPredicate,
|
|
35
39
|
IsNonePredicate,
|
|
36
40
|
IsNotNonePredicate,
|
|
@@ -38,13 +42,15 @@ from predicate.predicate import (
|
|
|
38
42
|
LePredicate,
|
|
39
43
|
LtPredicate,
|
|
40
44
|
NePredicate,
|
|
41
|
-
NotInPredicate,
|
|
42
45
|
OrPredicate,
|
|
43
46
|
Predicate,
|
|
44
47
|
always_false_p,
|
|
45
48
|
)
|
|
46
49
|
from predicate.regex_predicate import RegexPredicate
|
|
50
|
+
from predicate.set_of_predicate import SetOfPredicate
|
|
51
|
+
from predicate.set_predicates import InPredicate, IsRealSubsetPredicate, IsSubsetPredicate, NotInPredicate
|
|
47
52
|
from predicate.standard_predicates import AllPredicate
|
|
53
|
+
from predicate.tuple_of_predicate import TupleOfPredicate
|
|
48
54
|
|
|
49
55
|
|
|
50
56
|
@singledispatch
|
|
@@ -126,6 +132,13 @@ def generate_gt(predicate: GtPredicate) -> Iterator:
|
|
|
126
132
|
yield from generate_uuids(predicate)
|
|
127
133
|
|
|
128
134
|
|
|
135
|
+
@generate_true.register
|
|
136
|
+
def generate_has_key(predicate: HasKeyPredicate) -> Iterator:
|
|
137
|
+
key = predicate.key
|
|
138
|
+
for random_dict, value in zip(random_dicts(), random_anys(), strict=False):
|
|
139
|
+
yield random_dict | {key: value}
|
|
140
|
+
|
|
141
|
+
|
|
129
142
|
@generate_true.register
|
|
130
143
|
def generate_le(predicate: LePredicate) -> Iterator:
|
|
131
144
|
match predicate.v:
|
|
@@ -141,11 +154,26 @@ def generate_le(predicate: LePredicate) -> Iterator:
|
|
|
141
154
|
yield from generate_uuids(predicate)
|
|
142
155
|
|
|
143
156
|
|
|
157
|
+
@generate_true.register
|
|
158
|
+
def generate_subset(predicate: IsSubsetPredicate) -> Iterator:
|
|
159
|
+
yield from powerset_of_sets(predicate.v)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
@generate_true.register
|
|
163
|
+
def generate_real_subset(predicate: IsRealSubsetPredicate) -> Iterator:
|
|
164
|
+
yield from (v for v in powerset_of_sets(predicate.v) if v != predicate.v)
|
|
165
|
+
|
|
166
|
+
|
|
144
167
|
@generate_true.register
|
|
145
168
|
def generate_in(predicate: InPredicate) -> Iterator:
|
|
146
169
|
yield from predicate.v
|
|
147
170
|
|
|
148
171
|
|
|
172
|
+
@generate_true.register
|
|
173
|
+
def generate_is_empty(_predicate: IsEmptyPredicate) -> Iterator:
|
|
174
|
+
yield from ([], {}, (), "", set())
|
|
175
|
+
|
|
176
|
+
|
|
149
177
|
@generate_true.register
|
|
150
178
|
def generate_lt(predicate: LtPredicate) -> Iterator:
|
|
151
179
|
match predicate.v:
|
|
@@ -182,8 +210,8 @@ def generate_not_in(predicate: NotInPredicate) -> Iterator:
|
|
|
182
210
|
|
|
183
211
|
|
|
184
212
|
@generate_true.register
|
|
185
|
-
def generate_not_none(
|
|
186
|
-
yield from (
|
|
213
|
+
def generate_not_none(predicate: IsNotNonePredicate) -> Iterator:
|
|
214
|
+
yield from generate_anys(predicate)
|
|
187
215
|
|
|
188
216
|
|
|
189
217
|
@generate_true.register
|
|
@@ -212,7 +240,7 @@ def generate_is_instance_p(predicate: IsInstancePredicate) -> Iterator:
|
|
|
212
240
|
if klass is str:
|
|
213
241
|
yield from random_strings()
|
|
214
242
|
elif klass is bool:
|
|
215
|
-
yield from (False, True)
|
|
243
|
+
yield from cycle((False, True))
|
|
216
244
|
elif klass is complex:
|
|
217
245
|
yield from random_complex_numbers()
|
|
218
246
|
elif klass == datetime:
|
|
@@ -239,3 +267,19 @@ def generate_any_p(any_predicate: AnyPredicate) -> Iterator:
|
|
|
239
267
|
yield random_combination_with_replacement(values, 5)
|
|
240
268
|
|
|
241
269
|
yield set(random_combination_with_replacement(values, 5))
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
@generate_true.register
|
|
273
|
+
def generate_tuple_of_p(tuple_of_predicate: TupleOfPredicate) -> Iterator:
|
|
274
|
+
predicates = tuple_of_predicate.predicates
|
|
275
|
+
|
|
276
|
+
yield from zip(*(generate_true(predicate) for predicate in predicates), strict=False)
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
@generate_true.register
|
|
280
|
+
def generate_set_of_p(set_of_predicate: SetOfPredicate) -> Iterator:
|
|
281
|
+
predicate = set_of_predicate.predicate
|
|
282
|
+
|
|
283
|
+
values = take(10, generate_true(predicate))
|
|
284
|
+
|
|
285
|
+
yield set(random_combination_with_replacement(values, 5))
|
|
@@ -47,18 +47,17 @@ def random_ints(lower: int = -sys.maxsize, upper: int = sys.maxsize) -> Iterator
|
|
|
47
47
|
# yield lower
|
|
48
48
|
# yield upper
|
|
49
49
|
# TODO: maybe first generate_true some smaller ints
|
|
50
|
-
while True:
|
|
51
|
-
low = max(-1, lower)
|
|
52
|
-
high = min(1, upper)
|
|
53
|
-
if high >= low:
|
|
54
|
-
yield from (random.randint(low, high) for _ in range(0, 1))
|
|
55
50
|
|
|
56
|
-
|
|
57
|
-
|
|
51
|
+
def between(limit: int) -> Iterator[int]:
|
|
52
|
+
low = max(-limit, lower)
|
|
53
|
+
high = min(limit, upper)
|
|
58
54
|
if high >= low:
|
|
59
|
-
yield from (random.randint(low, high) for _ in range(0,
|
|
55
|
+
yield from (random.randint(low, high) for _ in range(0, limit))
|
|
60
56
|
|
|
61
|
-
|
|
57
|
+
while True:
|
|
58
|
+
yield from between(1)
|
|
59
|
+
yield from between(10)
|
|
60
|
+
yield from between(100)
|
|
62
61
|
|
|
63
62
|
|
|
64
63
|
def random_uuids() -> Iterator[UUID]:
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
from dataclasses import dataclass
|
|
2
|
-
from typing import Any
|
|
3
2
|
|
|
4
3
|
from predicate.predicate import Predicate
|
|
5
4
|
|
|
6
5
|
|
|
7
6
|
@dataclass
|
|
8
|
-
class HasKeyPredicate[T](Predicate[
|
|
7
|
+
class HasKeyPredicate[T](Predicate[T]):
|
|
9
8
|
"""A predicate class that models the has key."""
|
|
10
9
|
|
|
11
10
|
key: T
|
|
@@ -13,8 +12,5 @@ class HasKeyPredicate[T](Predicate[dict[T, Any]]):
|
|
|
13
12
|
def __call__(self, v: dict) -> bool:
|
|
14
13
|
return self.key in v.keys()
|
|
15
14
|
|
|
16
|
-
def __eq__(self, other: object) -> bool:
|
|
17
|
-
return isinstance(other, HasKeyPredicate) and self.key == other.key
|
|
18
|
-
|
|
19
15
|
def __repr__(self) -> str:
|
|
20
16
|
return f'has_key_p("{self.key}")'
|