py-predicate 0.7__tar.gz → 0.8__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.7 → py_predicate-0.8}/PKG-INFO +1 -1
- {py_predicate-0.7 → py_predicate-0.8}/predicate/__init__.py +2 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/all_predicate.py +6 -2
- {py_predicate-0.7 → py_predicate-0.8}/predicate/always_false_predicate.py +5 -1
- {py_predicate-0.7 → py_predicate-0.8}/predicate/always_true_predicate.py +5 -1
- {py_predicate-0.7 → py_predicate-0.8}/predicate/any_predicate.py +6 -2
- py_predicate-0.8/predicate/constructor/construct.py +84 -0
- py_predicate-0.8/predicate/constructor/helpers.py +48 -0
- py_predicate-0.8/predicate/constructor/mutate.py +78 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/eq_predicate.py +6 -2
- {py_predicate-0.7 → py_predicate-0.8}/predicate/ge_predicate.py +6 -2
- {py_predicate-0.7 → py_predicate-0.8}/predicate/generator/generate_false.py +12 -3
- py_predicate-0.8/predicate/generator/generate_predicate.py +164 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/generator/generate_true.py +16 -9
- {py_predicate-0.7 → py_predicate-0.8}/predicate/generator/helpers.py +72 -25
- {py_predicate-0.7 → py_predicate-0.8}/predicate/gt_predicate.py +6 -2
- {py_predicate-0.7 → py_predicate-0.8}/predicate/is_instance_predicate.py +8 -4
- py_predicate-0.8/predicate/is_predicate_of_p.py +30 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/le_predicate.py +6 -2
- {py_predicate-0.7 → py_predicate-0.8}/predicate/list_of_predicate.py +4 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/lt_predicate.py +6 -2
- {py_predicate-0.7 → py_predicate-0.8}/predicate/ne_predicate.py +6 -2
- {py_predicate-0.7 → py_predicate-0.8}/predicate/optimizer/or_optimizer.py +8 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/parser.py +18 -3
- {py_predicate-0.7 → py_predicate-0.8}/predicate/predicate.py +26 -2
- {py_predicate-0.7 → py_predicate-0.8}/predicate/range_predicate.py +24 -8
- {py_predicate-0.7 → py_predicate-0.8}/predicate/set_predicates.py +17 -1
- {py_predicate-0.7 → py_predicate-0.8}/predicate/standard_predicates.py +7 -6
- {py_predicate-0.7 → py_predicate-0.8}/pyproject.toml +1 -1
- py_predicate-0.7/predicate/constructor/construct.py +0 -60
- {py_predicate-0.7 → py_predicate-0.8}/README.md +0 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/comp_predicate.py +0 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/constructor/__init__.py +0 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/dict_of_predicate.py +0 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/explain.py +0 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/fn_predicate.py +0 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/formatter/__init__.py +0 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/formatter/format_dot.py +0 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/formatter/format_json.py +0 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/formatter/format_latex.py +0 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/formatter/helpers.py +0 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/generator/__init__.py +0 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/has_key_predicate.py +0 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/has_length_predicate.py +0 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/has_path_predicate.py +0 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/helpers.py +0 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/implies.py +0 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/implies_predicate.py +0 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/in_predicate_predicate.py +0 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/ip_address_predicates.py +0 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/is_callable_predicate.py +0 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/is_empty_predicate.py +0 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/is_falsy_predicate.py +0 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/is_lambda_predicate.py +0 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/is_none_predicate.py +0 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/is_not_none_predicate.py +0 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/is_truthy_predicate.py +0 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/lazy_predicate.py +0 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/named_predicate.py +0 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/negate.py +0 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/optimizer/__init__.py +0 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/optimizer/all_optimizer.py +0 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/optimizer/and_optimizer.py +0 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/optimizer/any_optimizer.py +0 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/optimizer/in_optimizer.py +0 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/optimizer/not_optimizer.py +0 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/optimizer/predicate_optimizer.py +0 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/optimizer/xor_optimizer.py +0 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/property_predicate.py +0 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/regex_predicate.py +0 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/root_predicate.py +0 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/set_of_predicate.py +0 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/str_predicates.py +0 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/tee_predicate.py +0 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/this_predicate.py +0 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/truth_table.py +0 -0
- {py_predicate-0.7 → py_predicate-0.8}/predicate/tuple_of_predicate.py +0 -0
|
@@ -56,6 +56,7 @@ from predicate.standard_predicates import (
|
|
|
56
56
|
is_nan_p,
|
|
57
57
|
is_none_p,
|
|
58
58
|
is_not_none_p,
|
|
59
|
+
is_predicate_of_p,
|
|
59
60
|
is_predicate_p,
|
|
60
61
|
is_range_p,
|
|
61
62
|
is_set_of_p,
|
|
@@ -133,6 +134,7 @@ __all__ = [
|
|
|
133
134
|
"is_none_p",
|
|
134
135
|
"is_not_empty_p",
|
|
135
136
|
"is_not_none_p",
|
|
137
|
+
"is_predicate_of_p",
|
|
136
138
|
"is_predicate_p",
|
|
137
139
|
"is_range_p",
|
|
138
140
|
"is_set_of_p",
|
|
@@ -18,10 +18,14 @@ class AllPredicate[T](Predicate[T]):
|
|
|
18
18
|
return predicate in self.predicate
|
|
19
19
|
|
|
20
20
|
def __repr__(self) -> str:
|
|
21
|
-
return f"
|
|
21
|
+
return f"all_p({self.predicate!r})"
|
|
22
|
+
|
|
23
|
+
@override
|
|
24
|
+
def get_klass(self) -> type:
|
|
25
|
+
return Predicate[self.predicate.klass] # type: ignore[name-defined]
|
|
22
26
|
|
|
23
27
|
@override
|
|
24
28
|
def explain_failure(self, iterable: Iterable[T]) -> dict:
|
|
25
29
|
fail = first_false(iterable, self.predicate)
|
|
26
30
|
|
|
27
|
-
return {"reason": f"Item '{fail}' didn't match predicate {
|
|
31
|
+
return {"reason": f"Item '{fail}' didn't match predicate {self.predicate!r}"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from dataclasses import dataclass
|
|
2
|
-
from typing import Final, override
|
|
2
|
+
from typing import Any, Final, override
|
|
3
3
|
|
|
4
4
|
from predicate.predicate import Predicate
|
|
5
5
|
|
|
@@ -18,6 +18,10 @@ class AlwaysFalsePredicate(Predicate):
|
|
|
18
18
|
def explain_failure(self, *args, **kwargs) -> dict:
|
|
19
19
|
return {"reason": "Always returns False"}
|
|
20
20
|
|
|
21
|
+
@override
|
|
22
|
+
def get_klass(self) -> type:
|
|
23
|
+
return type(Any)
|
|
24
|
+
|
|
21
25
|
|
|
22
26
|
always_false_p: Final[AlwaysFalsePredicate] = AlwaysFalsePredicate()
|
|
23
27
|
"""Predicate that always evaluates to False."""
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from dataclasses import dataclass
|
|
2
|
-
from typing import Final
|
|
2
|
+
from typing import Any, Final, override
|
|
3
3
|
|
|
4
4
|
from predicate.predicate import Predicate
|
|
5
5
|
|
|
@@ -14,6 +14,10 @@ class AlwaysTruePredicate(Predicate):
|
|
|
14
14
|
def __repr__(self) -> str:
|
|
15
15
|
return "always_true_p"
|
|
16
16
|
|
|
17
|
+
@override
|
|
18
|
+
def get_klass(self) -> type:
|
|
19
|
+
return type(Any)
|
|
20
|
+
|
|
17
21
|
|
|
18
22
|
always_true_p: Final[AlwaysTruePredicate] = AlwaysTruePredicate()
|
|
19
23
|
"""Predicate that always evaluates to True."""
|
|
@@ -17,8 +17,12 @@ class AnyPredicate[T](Predicate[T]):
|
|
|
17
17
|
return predicate in self.predicate
|
|
18
18
|
|
|
19
19
|
def __repr__(self) -> str:
|
|
20
|
-
return f"
|
|
20
|
+
return f"any_p({self.predicate!r})"
|
|
21
|
+
|
|
22
|
+
@override
|
|
23
|
+
def get_klass(self) -> type:
|
|
24
|
+
return Predicate[self.predicate.klass] # type: ignore[name-defined]
|
|
21
25
|
|
|
22
26
|
@override
|
|
23
27
|
def explain_failure(self, iterable: Iterable[T]) -> dict:
|
|
24
|
-
return {"reason": f"No item matches predicate {
|
|
28
|
+
return {"reason": f"No item matches predicate {self.predicate!r}"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
from typing import Iterator
|
|
2
|
+
|
|
3
|
+
from more_itertools import first, gray_product, take
|
|
4
|
+
|
|
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.constructor.helpers import perfect_match, sort_by_match
|
|
18
|
+
from predicate.constructor.mutate import mutations
|
|
19
|
+
from predicate.predicate import Predicate
|
|
20
|
+
from predicate.standard_predicates import (
|
|
21
|
+
ge_p,
|
|
22
|
+
gt_p,
|
|
23
|
+
is_bool_p,
|
|
24
|
+
is_dict_p,
|
|
25
|
+
is_list_p,
|
|
26
|
+
is_none_p,
|
|
27
|
+
le_p,
|
|
28
|
+
lt_p,
|
|
29
|
+
ne_p,
|
|
30
|
+
zero_p,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def construct(false_set: list, true_set: list, attempts: int = 30) -> Predicate | None:
|
|
35
|
+
predicates = initial_predicates()
|
|
36
|
+
|
|
37
|
+
while attempts:
|
|
38
|
+
sorted_by_match = sort_by_match(list(predicates), false_set=false_set, true_set=true_set)
|
|
39
|
+
|
|
40
|
+
if perfect_match(matched := first(sorted_by_match), false_set=false_set, true_set=true_set):
|
|
41
|
+
return matched
|
|
42
|
+
|
|
43
|
+
predicates = create_mutations(take(20, sorted_by_match), false_set=false_set, true_set=true_set)
|
|
44
|
+
|
|
45
|
+
attempts -= 1
|
|
46
|
+
|
|
47
|
+
return None
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def create_mutations(candidates: list[Predicate], false_set: list, true_set: list) -> Iterator[Predicate]:
|
|
51
|
+
for candidate in candidates:
|
|
52
|
+
yield from mutations(candidate, false_set=false_set, true_set=true_set)
|
|
53
|
+
|
|
54
|
+
pairs = gray_product(candidates, candidates)
|
|
55
|
+
for pair in pairs:
|
|
56
|
+
left, right = pair
|
|
57
|
+
if left != right:
|
|
58
|
+
yield left | right
|
|
59
|
+
yield left & right
|
|
60
|
+
yield left ^ right
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def initial_predicates() -> Iterator[Predicate]:
|
|
64
|
+
# TODO: probably import from __init__
|
|
65
|
+
yield always_false_p
|
|
66
|
+
yield always_true_p
|
|
67
|
+
yield ge_p(0)
|
|
68
|
+
yield gt_p(0)
|
|
69
|
+
yield is_bool_p
|
|
70
|
+
yield is_datetime_p
|
|
71
|
+
yield is_dict_p
|
|
72
|
+
yield is_falsy_p
|
|
73
|
+
yield is_float_p
|
|
74
|
+
yield is_int_p
|
|
75
|
+
yield is_list_p
|
|
76
|
+
yield is_none_p
|
|
77
|
+
yield is_not_none_p
|
|
78
|
+
yield is_set_p
|
|
79
|
+
yield is_str_p
|
|
80
|
+
yield is_truthy_p
|
|
81
|
+
yield le_p(0)
|
|
82
|
+
yield lt_p(0)
|
|
83
|
+
yield ne_p(0)
|
|
84
|
+
yield zero_p
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from predicate.predicate import Predicate
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def safe_call_false(predicate: Predicate, value: Any) -> bool:
|
|
7
|
+
# For performance reasons type checking is not part of the predicate itself
|
|
8
|
+
try:
|
|
9
|
+
return predicate(value)
|
|
10
|
+
except TypeError:
|
|
11
|
+
return True
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def safe_call_true(predicate: Predicate, value: Any) -> bool:
|
|
15
|
+
# For performance reasons type checking is not part of the predicate itself
|
|
16
|
+
try:
|
|
17
|
+
return predicate(value)
|
|
18
|
+
except TypeError:
|
|
19
|
+
return False
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def predicate_match(predicate: Predicate, false_set: list, true_set: list) -> dict[str, int]:
|
|
23
|
+
false_misses = sum(safe_call_false(predicate, value) for value in false_set)
|
|
24
|
+
false_matches = len(false_set) - false_misses
|
|
25
|
+
|
|
26
|
+
true_matches = sum(safe_call_true(predicate, value) for value in true_set)
|
|
27
|
+
true_misses = len(true_set) - true_matches
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
"false_matches": false_matches,
|
|
31
|
+
"false_misses": false_misses,
|
|
32
|
+
"true_matches": true_matches,
|
|
33
|
+
"true_misses": true_misses,
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def sort_by_match(predicates: list[Predicate], false_set: list, true_set: list) -> list[Predicate]:
|
|
38
|
+
def best_match(predicate) -> int:
|
|
39
|
+
match = predicate_match(predicate, false_set=false_set, true_set=true_set)
|
|
40
|
+
|
|
41
|
+
return match["false_matches"] + match["true_matches"]
|
|
42
|
+
|
|
43
|
+
return sorted(predicates, key=best_match, reverse=True)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def perfect_match(predicate: Predicate, false_set: list, true_set: list) -> bool:
|
|
47
|
+
match = predicate_match(predicate, false_set=false_set, true_set=true_set)
|
|
48
|
+
return match["false_misses"] + match["true_misses"] == 0
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
from collections.abc import Iterator
|
|
2
|
+
from functools import singledispatch
|
|
3
|
+
from random import choice, randint
|
|
4
|
+
|
|
5
|
+
from predicate import eq_p, ge_p, gt_p, le_p, lt_p, ne_p
|
|
6
|
+
from predicate.eq_predicate import EqPredicate
|
|
7
|
+
from predicate.ge_predicate import GePredicate
|
|
8
|
+
from predicate.gt_predicate import GtPredicate
|
|
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 Predicate
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@singledispatch
|
|
16
|
+
def mutations(predicate: Predicate, false_set: list, true_set: list, nr: int = 3) -> Iterator[Predicate]:
|
|
17
|
+
"""Return nr of mutations."""
|
|
18
|
+
yield predicate
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def int_value_mutations(n: int, values: list, nr: int) -> Iterator[int]:
|
|
22
|
+
yield choice(values)
|
|
23
|
+
yield n - randint(0, 10)
|
|
24
|
+
yield n + randint(0, 10)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@mutations.register
|
|
28
|
+
def _(predicate: EqPredicate, false_set: list, true_set: list, nr: int = 3) -> Iterator[Predicate]:
|
|
29
|
+
match predicate.v:
|
|
30
|
+
case int(n):
|
|
31
|
+
yield from (eq_p(v) for v in int_value_mutations(n, true_set, nr))
|
|
32
|
+
case _:
|
|
33
|
+
pass
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@mutations.register
|
|
37
|
+
def _(predicate: NePredicate, false_set, true_set: list, nr: int = 3) -> Iterator[Predicate]:
|
|
38
|
+
match predicate.v:
|
|
39
|
+
case int(n):
|
|
40
|
+
yield from (ne_p(v) for v in int_value_mutations(n, false_set, nr))
|
|
41
|
+
case _:
|
|
42
|
+
pass
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@mutations.register
|
|
46
|
+
def _(predicate: GePredicate, false_set, true_set: list, nr: int = 3) -> Iterator[Predicate]:
|
|
47
|
+
match predicate.v:
|
|
48
|
+
case int(n):
|
|
49
|
+
yield from (ge_p(v) for v in int_value_mutations(n, true_set, nr))
|
|
50
|
+
case _:
|
|
51
|
+
pass
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@mutations.register
|
|
55
|
+
def _(predicate: GtPredicate, false_set, true_set: list, nr: int = 3) -> Iterator[Predicate]:
|
|
56
|
+
match predicate.v:
|
|
57
|
+
case int(n):
|
|
58
|
+
yield from (gt_p(v) for v in int_value_mutations(n, true_set, nr))
|
|
59
|
+
case _:
|
|
60
|
+
pass
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@mutations.register
|
|
64
|
+
def _(predicate: LePredicate, false_set, true_set: list, nr: int = 3) -> Iterator[Predicate]:
|
|
65
|
+
match predicate.v:
|
|
66
|
+
case int(n):
|
|
67
|
+
yield from (le_p(v) for v in int_value_mutations(n, true_set, nr))
|
|
68
|
+
case _:
|
|
69
|
+
pass
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
@mutations.register
|
|
73
|
+
def _(predicate: LtPredicate, false_set, true_set: list, nr: int = 3) -> Iterator[Predicate]:
|
|
74
|
+
match predicate.v:
|
|
75
|
+
case int(n):
|
|
76
|
+
yield from (lt_p(v) for v in int_value_mutations(n, true_set, nr))
|
|
77
|
+
case _:
|
|
78
|
+
pass
|
|
@@ -14,8 +14,12 @@ class EqPredicate[T](Predicate[T]):
|
|
|
14
14
|
return x == self.v
|
|
15
15
|
|
|
16
16
|
def __repr__(self) -> str:
|
|
17
|
-
return f"eq_p({self.v})"
|
|
17
|
+
return f"eq_p({self.v!r})"
|
|
18
|
+
|
|
19
|
+
@override
|
|
20
|
+
def get_klass(self) -> type:
|
|
21
|
+
return type(self.v)
|
|
18
22
|
|
|
19
23
|
@override
|
|
20
24
|
def explain_failure(self, x: T) -> dict:
|
|
21
|
-
return {"reason": f"{x} is not equal to {self.v}"}
|
|
25
|
+
return {"reason": f"{x} is not equal to {self.v!r}"}
|
|
@@ -14,8 +14,12 @@ class GePredicate[T](Predicate[T]):
|
|
|
14
14
|
return x >= self.v
|
|
15
15
|
|
|
16
16
|
def __repr__(self) -> str:
|
|
17
|
-
return f"ge_p({self.v})"
|
|
17
|
+
return f"ge_p({self.v!r})"
|
|
18
|
+
|
|
19
|
+
@override
|
|
20
|
+
def get_klass(self) -> type:
|
|
21
|
+
return type(self.v)
|
|
18
22
|
|
|
19
23
|
@override
|
|
20
24
|
def explain_failure(self, x: T) -> dict:
|
|
21
|
-
return {"reason": f"{x} is not greater or equal to {self.v}"}
|
|
25
|
+
return {"reason": f"{x} is not greater or equal to {self.v!r}"}
|
|
@@ -331,9 +331,18 @@ def generate_is_instance_p(predicate: IsInstancePredicate) -> Iterator:
|
|
|
331
331
|
|
|
332
332
|
@generate_false.register
|
|
333
333
|
def generate_or(predicate: OrPredicate) -> Iterator:
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
334
|
+
attempts = 100
|
|
335
|
+
|
|
336
|
+
try_left = (item for item in take(attempts, generate_false(predicate.left)) if not predicate.right(item))
|
|
337
|
+
try_right = (item for item in take(attempts, generate_false(predicate.right)) if not predicate.left(item))
|
|
338
|
+
|
|
339
|
+
range_1 = (item for item in generate_false(predicate.left) if not predicate.right(item)) if try_left else ()
|
|
340
|
+
range_2 = (item for item in generate_false(predicate.right) if not predicate.left(item)) if try_right else ()
|
|
341
|
+
|
|
342
|
+
if range_1 or range_2:
|
|
343
|
+
yield from random_first_from_iterables(range_1, range_2)
|
|
344
|
+
|
|
345
|
+
raise ValueError(f"Couldn't generate values that statisfy {predicate}")
|
|
337
346
|
|
|
338
347
|
|
|
339
348
|
@generate_false.register
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
from typing import Any, Iterator
|
|
2
|
+
|
|
3
|
+
from predicate.all_predicate import AllPredicate
|
|
4
|
+
from predicate.eq_predicate import EqPredicate
|
|
5
|
+
from predicate.ge_predicate import GePredicate
|
|
6
|
+
from predicate.gt_predicate import GtPredicate
|
|
7
|
+
from predicate.le_predicate import LePredicate
|
|
8
|
+
from predicate.lt_predicate import LtPredicate
|
|
9
|
+
from predicate.ne_predicate import NePredicate
|
|
10
|
+
from predicate.predicate import AndPredicate, NotPredicate, OrPredicate, Predicate, XorPredicate
|
|
11
|
+
from predicate.range_predicate import GeLePredicate, GeLtPredicate, GtLePredicate, GtLtPredicate
|
|
12
|
+
from predicate.set_predicates import InPredicate, NotInPredicate
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def generate_predicate(predicate_type: type[Predicate], max_depth: int, klass: type) -> Iterator[Predicate]:
|
|
16
|
+
predicate_type_registry: dict[type, Any] = {
|
|
17
|
+
# TODO: AllPredicate works on iterables
|
|
18
|
+
# AllPredicate: generate_all_predicates,
|
|
19
|
+
AndPredicate: generate_and_predicates,
|
|
20
|
+
EqPredicate: generate_eq_predicates,
|
|
21
|
+
GeLePredicate: generate_ge_le_predicates,
|
|
22
|
+
GeLtPredicate: generate_ge_lt_predicates,
|
|
23
|
+
GePredicate: generate_ge_predicates,
|
|
24
|
+
GtPredicate: generate_gt_predicates,
|
|
25
|
+
GtLePredicate: generate_gt_le_predicates,
|
|
26
|
+
GtLtPredicate: generate_gt_lt_predicates,
|
|
27
|
+
InPredicate: generate_in_predicates,
|
|
28
|
+
LePredicate: generate_le_predicates,
|
|
29
|
+
LtPredicate: generate_lt_predicates,
|
|
30
|
+
NePredicate: generate_ne_predicates,
|
|
31
|
+
NotInPredicate: generate_not_in_predicates,
|
|
32
|
+
NotPredicate: generate_not_predicates,
|
|
33
|
+
OrPredicate: generate_or_predicates,
|
|
34
|
+
XorPredicate: generate_xor_predicates,
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if generator := predicate_type_registry.get(predicate_type):
|
|
38
|
+
yield from generator(max_depth=max_depth, klass=klass)
|
|
39
|
+
else:
|
|
40
|
+
yield from []
|
|
41
|
+
# raise ValueError(f"No generator defined for predicate type {predicate_type}")
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def generate_random_predicate_pairs(max_depth: int, klass: type) -> Iterator:
|
|
45
|
+
from predicate.generator.helpers import random_predicates
|
|
46
|
+
|
|
47
|
+
left_predicates = random_predicates(max_depth=max_depth - 1, klass=klass)
|
|
48
|
+
right_predicates = random_predicates(max_depth=max_depth - 1, klass=klass)
|
|
49
|
+
|
|
50
|
+
return zip(left_predicates, right_predicates, strict=False)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def generate_all_predicates(max_depth: int, klass: type) -> Iterator:
|
|
54
|
+
if not max_depth:
|
|
55
|
+
return
|
|
56
|
+
|
|
57
|
+
from predicate.generator.helpers import random_predicates
|
|
58
|
+
|
|
59
|
+
predicates = random_predicates(max_depth=max_depth - 1, klass=klass)
|
|
60
|
+
|
|
61
|
+
yield from (AllPredicate(predicate) for predicate in predicates)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def generate_and_predicates(max_depth: int, klass: type) -> Iterator:
|
|
65
|
+
if not max_depth:
|
|
66
|
+
return
|
|
67
|
+
|
|
68
|
+
yield from (left & right for left, right in generate_random_predicate_pairs(max_depth=max_depth, klass=klass))
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def generate_eq_predicates(max_depth: int, klass: type) -> Iterator:
|
|
72
|
+
from predicate.generator.helpers import random_values_of_type
|
|
73
|
+
|
|
74
|
+
yield from (EqPredicate(value) for value in random_values_of_type(klass))
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def generate_ge_le_predicates(max_depth: int, klass: type) -> Iterator:
|
|
78
|
+
from predicate.generator.helpers import random_constrained_pairs_of_type
|
|
79
|
+
|
|
80
|
+
yield from (GeLePredicate(lower=lower, upper=upper) for lower, upper in random_constrained_pairs_of_type(klass))
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def generate_ge_lt_predicates(max_depth: int, klass: type) -> Iterator:
|
|
84
|
+
from predicate.generator.helpers import random_constrained_pairs_of_type
|
|
85
|
+
|
|
86
|
+
yield from (GeLtPredicate(lower=lower, upper=upper) for lower, upper in random_constrained_pairs_of_type(klass))
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def generate_gt_le_predicates(max_depth: int, klass: type) -> Iterator:
|
|
90
|
+
from predicate.generator.helpers import random_constrained_pairs_of_type
|
|
91
|
+
|
|
92
|
+
yield from (GtLePredicate(lower=lower, upper=upper) for lower, upper in random_constrained_pairs_of_type(klass))
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def generate_gt_lt_predicates(max_depth: int, klass: type) -> Iterator:
|
|
96
|
+
from predicate.generator.helpers import random_constrained_pairs_of_type
|
|
97
|
+
|
|
98
|
+
yield from (GtLtPredicate(lower=lower, upper=upper) for lower, upper in random_constrained_pairs_of_type(klass))
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def generate_ge_predicates(max_depth: int, klass: type) -> Iterator:
|
|
102
|
+
from predicate.generator.helpers import random_constrained_values_of_type
|
|
103
|
+
|
|
104
|
+
yield from (GePredicate(value) for value in random_constrained_values_of_type(klass))
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def generate_gt_predicates(max_depth: int, klass: type) -> Iterator:
|
|
108
|
+
from predicate.generator.helpers import random_constrained_values_of_type
|
|
109
|
+
|
|
110
|
+
yield from (GtPredicate(value) for value in random_constrained_values_of_type(klass))
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def generate_in_predicates(max_depth: int, klass: type) -> Iterator:
|
|
114
|
+
from predicate.generator.helpers import random_iterables
|
|
115
|
+
|
|
116
|
+
yield from (InPredicate(iterable) for iterable in random_iterables(klass=klass))
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def generate_not_in_predicates(max_depth: int, klass: type) -> Iterator:
|
|
120
|
+
from predicate.generator.helpers import random_iterables
|
|
121
|
+
|
|
122
|
+
yield from (NotInPredicate(iterable) for iterable in random_iterables(klass=klass))
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def generate_le_predicates(max_depth: int, klass: type) -> Iterator:
|
|
126
|
+
from predicate.generator.helpers import random_constrained_values_of_type
|
|
127
|
+
|
|
128
|
+
yield from (LePredicate(value) for value in random_constrained_values_of_type(klass))
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def generate_lt_predicates(max_depth: int, klass: type) -> Iterator:
|
|
132
|
+
from predicate.generator.helpers import random_constrained_values_of_type
|
|
133
|
+
|
|
134
|
+
yield from (LtPredicate(value) for value in random_constrained_values_of_type(klass))
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def generate_ne_predicates(max_depth: int, klass: type) -> Iterator:
|
|
138
|
+
from predicate.generator.helpers import random_values_of_type
|
|
139
|
+
|
|
140
|
+
yield from (NePredicate(value) for value in random_values_of_type(klass))
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def generate_not_predicates(max_depth: int, klass: type) -> Iterator:
|
|
144
|
+
if not max_depth:
|
|
145
|
+
return
|
|
146
|
+
|
|
147
|
+
from predicate.generator.helpers import random_predicates
|
|
148
|
+
|
|
149
|
+
predicates = random_predicates(max_depth=max_depth - 1, klass=klass)
|
|
150
|
+
yield from (~predicate for predicate in predicates)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def generate_or_predicates(max_depth: int, klass: type) -> Iterator:
|
|
154
|
+
if not max_depth:
|
|
155
|
+
return
|
|
156
|
+
|
|
157
|
+
yield from (left | right for left, right in generate_random_predicate_pairs(max_depth=max_depth, klass=klass))
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def generate_xor_predicates(max_depth: int, klass: type) -> Iterator:
|
|
161
|
+
if not max_depth:
|
|
162
|
+
return
|
|
163
|
+
|
|
164
|
+
yield from (left ^ right for left, right in generate_random_predicate_pairs(max_depth=max_depth, klass=klass))
|
|
@@ -56,6 +56,7 @@ from predicate.is_falsy_predicate import IsFalsyPredicate
|
|
|
56
56
|
from predicate.is_instance_predicate import IsInstancePredicate
|
|
57
57
|
from predicate.is_none_predicate import IsNonePredicate
|
|
58
58
|
from predicate.is_not_none_predicate import IsNotNonePredicate
|
|
59
|
+
from predicate.is_predicate_of_p import IsPredicateOfPredicate
|
|
59
60
|
from predicate.is_truthy_predicate import IsTruthyPredicate
|
|
60
61
|
from predicate.le_predicate import LePredicate
|
|
61
62
|
from predicate.list_of_predicate import ListOfPredicate
|
|
@@ -119,9 +120,7 @@ def generate_any_p(any_predicate: AnyPredicate, *, min_size: int = 1, max_size:
|
|
|
119
120
|
combined_values = false_values + true_values
|
|
120
121
|
|
|
121
122
|
yield random_permutation(combined_values)
|
|
122
|
-
yield from set_from_list(
|
|
123
|
-
combined_values,
|
|
124
|
-
)
|
|
123
|
+
yield from set_from_list(combined_values)
|
|
125
124
|
|
|
126
125
|
|
|
127
126
|
@generate_true.register
|
|
@@ -219,6 +218,7 @@ def generate_ge(predicate: GePredicate) -> Iterator:
|
|
|
219
218
|
case int():
|
|
220
219
|
yield from random_ints(lower=predicate.v)
|
|
221
220
|
case str():
|
|
221
|
+
yield v
|
|
222
222
|
yield from generate_strings(predicate)
|
|
223
223
|
case UUID():
|
|
224
224
|
yield from generate_uuids(predicate)
|
|
@@ -318,7 +318,7 @@ def generate_lt(predicate: LtPredicate) -> Iterator:
|
|
|
318
318
|
|
|
319
319
|
@generate_true.register
|
|
320
320
|
def generate_ne(predicate: NePredicate) -> Iterator:
|
|
321
|
-
yield
|
|
321
|
+
yield from generate_anys(predicate)
|
|
322
322
|
|
|
323
323
|
|
|
324
324
|
@generate_true.register
|
|
@@ -374,8 +374,13 @@ def generate_truthy(_predicate: IsTruthyPredicate) -> Iterator:
|
|
|
374
374
|
|
|
375
375
|
|
|
376
376
|
@generate_true.register
|
|
377
|
-
def
|
|
378
|
-
klass
|
|
377
|
+
def generate_predicate_of(predicate: IsPredicateOfPredicate, **kwargs) -> Iterator:
|
|
378
|
+
yield from random_predicates(**kwargs, klass=predicate.predicate_klass)
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
@generate_true.register
|
|
382
|
+
def generate_is_instance_p(predicate: IsInstancePredicate, **kwargs) -> Iterator:
|
|
383
|
+
klass = predicate.instance_klass[0] # type: ignore
|
|
379
384
|
|
|
380
385
|
type_registry: dict[Any, Callable[[], Iterator]] = {
|
|
381
386
|
Callable: random_callables,
|
|
@@ -396,9 +401,11 @@ def generate_is_instance_p(predicate: IsInstancePredicate) -> Iterator:
|
|
|
396
401
|
}
|
|
397
402
|
|
|
398
403
|
if generator := type_registry.get(klass):
|
|
399
|
-
yield from generator()
|
|
400
|
-
|
|
401
|
-
|
|
404
|
+
yield from generator(**kwargs)
|
|
405
|
+
elif klass == Predicate: # TODO
|
|
406
|
+
yield from random_predicates(**kwargs)
|
|
407
|
+
else:
|
|
408
|
+
raise ValueError(f"No generator found for {klass}")
|
|
402
409
|
|
|
403
410
|
|
|
404
411
|
@generate_true.register
|