py-predicate 1.0__tar.gz → 1.2__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.
Files changed (91) hide show
  1. {py_predicate-1.0 → py_predicate-1.2}/PKG-INFO +10 -2
  2. {py_predicate-1.0 → py_predicate-1.2}/README.md +9 -1
  3. {py_predicate-1.0 → py_predicate-1.2}/predicate/__init__.py +54 -55
  4. {py_predicate-1.0 → py_predicate-1.2}/predicate/all_predicate.py +6 -1
  5. {py_predicate-1.0 → py_predicate-1.2}/predicate/always_false_predicate.py +1 -1
  6. {py_predicate-1.0 → py_predicate-1.2}/predicate/always_true_predicate.py +1 -1
  7. {py_predicate-1.0 → py_predicate-1.2}/predicate/any_predicate.py +6 -1
  8. {py_predicate-1.0 → py_predicate-1.2}/predicate/comp_predicate.py +6 -1
  9. {py_predicate-1.0 → py_predicate-1.2}/predicate/constructor/construct.py +8 -12
  10. {py_predicate-1.0 → py_predicate-1.2}/predicate/dict_of_predicate.py +7 -1
  11. {py_predicate-1.0 → py_predicate-1.2}/predicate/eq_predicate.py +16 -1
  12. py_predicate-1.2/predicate/fn_predicate.py +67 -0
  13. {py_predicate-1.0 → py_predicate-1.2}/predicate/formatter/format_dot.py +2 -2
  14. {py_predicate-1.0 → py_predicate-1.2}/predicate/formatter/format_latex.py +1 -1
  15. {py_predicate-1.0 → py_predicate-1.2}/predicate/ge_predicate.py +5 -0
  16. {py_predicate-1.0 → py_predicate-1.2}/predicate/generator/generate_false.py +112 -24
  17. {py_predicate-1.0 → py_predicate-1.2}/predicate/generator/generate_predicate.py +6 -3
  18. {py_predicate-1.0 → py_predicate-1.2}/predicate/generator/generate_true.py +204 -43
  19. py_predicate-1.2/predicate/generator/helpers.py +364 -0
  20. {py_predicate-1.0 → py_predicate-1.2}/predicate/gt_predicate.py +10 -1
  21. {py_predicate-1.0 → py_predicate-1.2}/predicate/has_key_predicate.py +5 -0
  22. py_predicate-1.2/predicate/has_length_predicate.py +37 -0
  23. {py_predicate-1.0 → py_predicate-1.2}/predicate/has_path_predicate.py +5 -0
  24. {py_predicate-1.0 → py_predicate-1.2}/predicate/helpers.py +8 -0
  25. {py_predicate-1.0 → py_predicate-1.2}/predicate/implies.py +22 -2
  26. py_predicate-1.2/predicate/in_predicate.py +38 -0
  27. {py_predicate-1.0 → py_predicate-1.2}/predicate/is_falsy_predicate.py +5 -1
  28. py_predicate-1.2/predicate/is_instance_predicate.py +105 -0
  29. {py_predicate-1.0 → py_predicate-1.2}/predicate/is_none_predicate.py +5 -1
  30. {py_predicate-1.0 → py_predicate-1.2}/predicate/is_not_none_predicate.py +5 -1
  31. {py_predicate-1.0 → py_predicate-1.2}/predicate/is_predicate_of_p.py +4 -0
  32. py_predicate-1.2/predicate/is_subclass_predicate.py +48 -0
  33. {py_predicate-1.0 → py_predicate-1.2}/predicate/is_truthy_predicate.py +5 -1
  34. {py_predicate-1.0 → py_predicate-1.2}/predicate/lazy_predicate.py +5 -0
  35. {py_predicate-1.0 → py_predicate-1.2}/predicate/le_predicate.py +5 -0
  36. {py_predicate-1.0 → py_predicate-1.2}/predicate/list_of_predicate.py +10 -0
  37. {py_predicate-1.0 → py_predicate-1.2}/predicate/lt_predicate.py +10 -1
  38. py_predicate-1.2/predicate/match_predicate.py +230 -0
  39. {py_predicate-1.0 → py_predicate-1.2}/predicate/ne_predicate.py +5 -0
  40. {py_predicate-1.0 → py_predicate-1.2}/predicate/negate.py +5 -3
  41. py_predicate-1.2/predicate/not_in_predicate.py +31 -0
  42. {py_predicate-1.0 → py_predicate-1.2}/predicate/optimizer/all_optimizer.py +1 -1
  43. {py_predicate-1.0 → py_predicate-1.2}/predicate/optimizer/and_optimizer.py +3 -1
  44. {py_predicate-1.0 → py_predicate-1.2}/predicate/optimizer/in_optimizer.py +2 -1
  45. {py_predicate-1.0 → py_predicate-1.2}/predicate/optimizer/or_optimizer.py +3 -2
  46. {py_predicate-1.0 → py_predicate-1.2}/predicate/optimizer/predicate_optimizer.py +2 -1
  47. {py_predicate-1.0 → py_predicate-1.2}/predicate/optimizer/xor_optimizer.py +1 -1
  48. {py_predicate-1.0 → py_predicate-1.2}/predicate/predicate.py +5 -5
  49. {py_predicate-1.0 → py_predicate-1.2}/predicate/property_predicate.py +11 -1
  50. {py_predicate-1.0 → py_predicate-1.2}/predicate/range_predicate.py +20 -0
  51. {py_predicate-1.0 → py_predicate-1.2}/predicate/regex_predicate.py +5 -0
  52. {py_predicate-1.0 → py_predicate-1.2}/predicate/set_of_predicate.py +15 -3
  53. {py_predicate-1.0 → py_predicate-1.2}/predicate/set_predicates.py +0 -61
  54. py_predicate-1.2/predicate/spec/__init__.py +0 -0
  55. py_predicate-1.2/predicate/spec/exercise.py +189 -0
  56. py_predicate-1.2/predicate/spec/instrument.py +48 -0
  57. py_predicate-1.2/predicate/spec/spec.py +13 -0
  58. py_predicate-1.2/predicate/standard_predicates.py +95 -0
  59. {py_predicate-1.0 → py_predicate-1.2}/predicate/str_predicates.py +1 -1
  60. {py_predicate-1.0 → py_predicate-1.2}/predicate/tee_predicate.py +6 -1
  61. {py_predicate-1.0 → py_predicate-1.2}/predicate/tuple_of_predicate.py +5 -0
  62. {py_predicate-1.0 → py_predicate-1.2}/pyproject.toml +1 -1
  63. py_predicate-1.0/predicate/fn_predicate.py +0 -27
  64. py_predicate-1.0/predicate/generator/helpers.py +0 -216
  65. py_predicate-1.0/predicate/has_length_predicate.py +0 -23
  66. py_predicate-1.0/predicate/is_instance_predicate.py +0 -29
  67. py_predicate-1.0/predicate/match_predicate.py +0 -144
  68. py_predicate-1.0/predicate/standard_predicates.py +0 -354
  69. {py_predicate-1.0 → py_predicate-1.2}/LICENSE +0 -0
  70. {py_predicate-1.0 → py_predicate-1.2}/predicate/constructor/__init__.py +0 -0
  71. {py_predicate-1.0 → py_predicate-1.2}/predicate/constructor/helpers.py +0 -0
  72. {py_predicate-1.0 → py_predicate-1.2}/predicate/constructor/mutate.py +0 -0
  73. {py_predicate-1.0 → py_predicate-1.2}/predicate/explain.py +0 -0
  74. {py_predicate-1.0 → py_predicate-1.2}/predicate/formatter/__init__.py +0 -0
  75. {py_predicate-1.0 → py_predicate-1.2}/predicate/formatter/format_json.py +0 -0
  76. {py_predicate-1.0 → py_predicate-1.2}/predicate/formatter/helpers.py +0 -0
  77. {py_predicate-1.0 → py_predicate-1.2}/predicate/generator/__init__.py +0 -0
  78. {py_predicate-1.0 → py_predicate-1.2}/predicate/implies_predicate.py +0 -0
  79. {py_predicate-1.0 → py_predicate-1.2}/predicate/in_predicate_predicate.py +0 -0
  80. {py_predicate-1.0 → py_predicate-1.2}/predicate/ip_address_predicates.py +0 -0
  81. {py_predicate-1.0 → py_predicate-1.2}/predicate/is_callable_predicate.py +0 -0
  82. {py_predicate-1.0 → py_predicate-1.2}/predicate/is_lambda_predicate.py +0 -0
  83. {py_predicate-1.0 → py_predicate-1.2}/predicate/named_predicate.py +0 -0
  84. {py_predicate-1.0 → py_predicate-1.2}/predicate/optimizer/__init__.py +0 -0
  85. {py_predicate-1.0 → py_predicate-1.2}/predicate/optimizer/any_optimizer.py +0 -0
  86. {py_predicate-1.0 → py_predicate-1.2}/predicate/optimizer/helpers.py +0 -0
  87. {py_predicate-1.0 → py_predicate-1.2}/predicate/optimizer/not_optimizer.py +0 -0
  88. {py_predicate-1.0 → py_predicate-1.2}/predicate/parser.py +0 -0
  89. {py_predicate-1.0 → py_predicate-1.2}/predicate/root_predicate.py +0 -0
  90. {py_predicate-1.0 → py_predicate-1.2}/predicate/this_predicate.py +0 -0
  91. {py_predicate-1.0 → py_predicate-1.2}/predicate/truth_table.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: py_predicate
3
- Version: 1.0
3
+ Version: 1.2
4
4
  Summary: Module to create composable predicates
5
5
  Author-email: Maurits Rijk <maurits.rijk@gmail.com>
6
6
  Requires-Python: >=3.10
@@ -50,6 +50,9 @@ Provides-Extra: test
50
50
 
51
51
  py-predicate is a typed Python library to create composable predicates.
52
52
 
53
+ These predicates can be used for generating test-cases (property based testing) and
54
+ run-time instrumenting of functions against a specification based on predicates.
55
+
53
56
  # Getting started
54
57
 
55
58
  To get started, install the library with [pip](https://pip.pypa.io/en/stable/)
@@ -87,9 +90,14 @@ series of integers for which the predicate ``between_2_and_3`` is False. The ``g
87
90
  infinite (well, with lots of duplicates obviously) series of integers for which the predicate is True.
88
91
 
89
92
  ```python
90
- from predicate import generate_false, generate_true
93
+ from predicate import generate_false, generate_true, ge_p, le_p
91
94
  from more_itertools import take
92
95
 
96
+ ge_2 = ge_p(2)
97
+ le_3 = le_p(3)
98
+
99
+ between_2_and_3 = ge_2 & le_3
100
+
93
101
  take(5, generate_true(between_2_and_3))
94
102
 
95
103
  take(5, generate_false(between_2_and_3))
@@ -6,6 +6,9 @@
6
6
 
7
7
  py-predicate is a typed Python library to create composable predicates.
8
8
 
9
+ These predicates can be used for generating test-cases (property based testing) and
10
+ run-time instrumenting of functions against a specification based on predicates.
11
+
9
12
  # Getting started
10
13
 
11
14
  To get started, install the library with [pip](https://pip.pypa.io/en/stable/)
@@ -43,9 +46,14 @@ series of integers for which the predicate ``between_2_and_3`` is False. The ``g
43
46
  infinite (well, with lots of duplicates obviously) series of integers for which the predicate is True.
44
47
 
45
48
  ```python
46
- from predicate import generate_false, generate_true
49
+ from predicate import generate_false, generate_true, ge_p, le_p
47
50
  from more_itertools import take
48
51
 
52
+ ge_2 = ge_p(2)
53
+ le_3 = le_p(3)
54
+
55
+ between_2_and_3 = ge_2 & le_3
56
+
49
57
  take(5, generate_true(between_2_and_3))
50
58
 
51
59
  take(5, generate_false(between_2_and_3))
@@ -2,86 +2,79 @@
2
2
 
3
3
  __version__ = "0.0.1"
4
4
 
5
+ from predicate.all_predicate import all_p
5
6
  from predicate.always_false_predicate import always_false_p, never_p
6
7
  from predicate.always_true_predicate import always_p, always_true_p
8
+ from predicate.any_predicate import any_p
9
+ from predicate.comp_predicate import comp_p
10
+ from predicate.dict_of_predicate import is_dict_of_p
11
+ from predicate.eq_predicate import eq_false_p, eq_p, eq_true_p, zero_p
7
12
  from predicate.explain import explain
13
+ from predicate.fn_predicate import fn_p, is_even_p, is_finite_p, is_inf_p, is_nan_p, is_odd_p
8
14
  from predicate.formatter import to_dot, to_json, to_latex
15
+ from predicate.ge_predicate import ge_p
9
16
  from predicate.generator.generate_false import generate_false
10
17
  from predicate.generator.generate_true import generate_true
18
+ from predicate.gt_predicate import gt_p, pos_p
19
+ from predicate.has_key_predicate import has_key_p
20
+ from predicate.has_length_predicate import has_length_p, is_empty_p, is_not_empty_p
21
+ from predicate.has_path_predicate import has_path_p
22
+ from predicate.implies_predicate import implies_p
23
+ from predicate.in_predicate import in_p
24
+ from predicate.is_falsy_predicate import is_falsy_p
25
+ from predicate.is_instance_predicate import (
26
+ is_bool_p,
27
+ is_callable_p,
28
+ is_complex_p,
29
+ is_container_p,
30
+ is_datetime_p,
31
+ is_hashable_p,
32
+ is_instance_p,
33
+ is_iterable_p,
34
+ is_predicate_p,
35
+ is_range_p,
36
+ is_set_p,
37
+ is_tuple_p,
38
+ is_uuid_p,
39
+ )
11
40
  from predicate.is_lambda_predicate import is_lambda_p, is_lambda_with_signature_p
41
+ from predicate.is_none_predicate import is_none_p
42
+ from predicate.is_not_none_predicate import is_not_none_p
43
+ from predicate.is_predicate_of_p import is_predicate_of_p
44
+ from predicate.is_subclass_predicate import is_enum_p
45
+ from predicate.is_truthy_predicate import is_truthy_p
46
+ from predicate.lazy_predicate import lazy_p
47
+ from predicate.le_predicate import le_p
48
+ from predicate.list_of_predicate import is_list_of_p
49
+ from predicate.lt_predicate import lt_p, neg_p
12
50
  from predicate.match_predicate import exactly_n, match_p, optional, plus, repeat, star
51
+ from predicate.ne_predicate import ne_p
52
+ from predicate.not_in_predicate import not_in_p
13
53
  from predicate.optimizer.predicate_optimizer import can_optimize, optimize
54
+ from predicate.range_predicate import ge_le_p, ge_lt_p, gt_le_p, gt_lt_p
55
+ from predicate.regex_predicate import regex_p
56
+ from predicate.set_of_predicate import is_set_of_p
14
57
  from predicate.set_predicates import (
15
- in_p,
16
58
  is_real_subset_p,
17
59
  is_real_superset_p,
18
60
  is_subset_p,
19
61
  is_superset_p,
20
- not_in_p,
21
62
  )
63
+ from predicate.spec.exercise import exercise
64
+ from predicate.spec.instrument import instrument_function
65
+ from predicate.spec.spec import Spec
22
66
  from predicate.standard_predicates import (
23
- all_p,
24
- any_p,
25
- comp_p,
26
- eq_false_p,
27
- eq_p,
28
- eq_true_p,
29
- fn_p,
30
- ge_le_p,
31
- ge_lt_p,
32
- ge_p,
33
- gt_le_p,
34
- gt_lt_p,
35
- gt_p,
36
- has_key_p,
37
- has_length_p,
38
- is_bool_p,
39
- is_callable_p,
40
- is_complex_p,
41
- is_container_p,
42
- is_datetime_p,
43
- is_dict_of_p,
44
67
  is_dict_p,
45
- is_empty_p,
46
- is_even_p,
47
- is_falsy_p,
48
- is_finite_p,
49
68
  is_float_p,
50
- is_hashable_p,
51
- is_inf_p,
52
- is_instance_p,
53
69
  is_int_p,
54
70
  is_iterable_of_p,
55
- is_iterable_p,
56
- is_list_of_p,
57
71
  is_list_p,
58
- is_nan_p,
59
- is_none_p,
60
- is_not_empty_p,
61
- is_not_none_p,
62
- is_odd_p,
63
- is_predicate_of_p,
64
- is_predicate_p,
65
- is_range_p,
66
- is_set_of_p,
67
- is_set_p,
68
72
  is_str_p,
69
- is_truthy_p,
70
- is_tuple_of_p,
71
- is_tuple_p,
72
- is_uuid_p,
73
- lazy_p,
74
- le_p,
75
- lt_p,
76
- ne_p,
77
- neg_p,
78
- pos_p,
79
- regex_p,
80
73
  root_p,
81
- tee_p,
82
74
  this_p,
83
- zero_p,
84
75
  )
76
+ from predicate.tee_predicate import tee_p
77
+ from predicate.tuple_of_predicate import is_tuple_of_p
85
78
 
86
79
  __all__ = [
87
80
  "all_p",
@@ -95,6 +88,7 @@ __all__ = [
95
88
  "eq_p",
96
89
  "eq_true_p",
97
90
  "exactly_n",
91
+ "exercise",
98
92
  "explain",
99
93
  "fn_p",
100
94
  "ge_le_p",
@@ -107,7 +101,10 @@ __all__ = [
107
101
  "gt_p",
108
102
  "has_key_p",
109
103
  "has_length_p",
104
+ "has_path_p",
105
+ "implies_p",
110
106
  "in_p",
107
+ "instrument_function",
111
108
  "is_alnum_p",
112
109
  "is_alpha_p",
113
110
  "is_ascii_p",
@@ -120,6 +117,7 @@ __all__ = [
120
117
  "is_dict_of_p",
121
118
  "is_dict_p",
122
119
  "is_empty_p",
120
+ "is_enum_p",
123
121
  "is_even_p",
124
122
  "is_falsy_p",
125
123
  "is_finite_p",
@@ -179,6 +177,7 @@ __all__ = [
179
177
  "to_json",
180
178
  "to_latex",
181
179
  "zero_p",
180
+ "Spec",
182
181
  ]
183
182
 
184
183
  from predicate.str_predicates import (
@@ -2,7 +2,7 @@ from dataclasses import dataclass
2
2
  from typing import Iterable, override
3
3
 
4
4
  from predicate.helpers import first_false
5
- from predicate.predicate import Predicate
5
+ from predicate.predicate import Predicate, resolve_predicate
6
6
 
7
7
 
8
8
  @dataclass
@@ -34,3 +34,8 @@ class AllPredicate[T](Predicate[T]):
34
34
  fail = first_false(iterable, self.predicate)
35
35
 
36
36
  return {"reason": f"Item '{fail}' didn't match predicate {self.predicate!r}"}
37
+
38
+
39
+ def all_p[T](predicate: Predicate[T]) -> AllPredicate[T]:
40
+ """Return True if the predicate holds for each item in the iterable, otherwise False."""
41
+ return AllPredicate(predicate=resolve_predicate(predicate))
@@ -8,7 +8,7 @@ from predicate.predicate import Predicate
8
8
  class AlwaysFalsePredicate(Predicate):
9
9
  """A predicate class that models the 'False' predicate."""
10
10
 
11
- def __call__(self, *args, **kwargs):
11
+ def __call__(self, *args, **kwargs) -> bool:
12
12
  return False
13
13
 
14
14
  def __repr__(self) -> str:
@@ -8,7 +8,7 @@ from predicate.predicate import Predicate
8
8
  class AlwaysTruePredicate(Predicate):
9
9
  """A predicate class that models the 'True' predicate."""
10
10
 
11
- def __call__(self, *args, **kwargs):
11
+ def __call__(self, *args, **kwargs) -> bool:
12
12
  return True
13
13
 
14
14
  def __repr__(self) -> str:
@@ -1,7 +1,7 @@
1
1
  from dataclasses import dataclass
2
2
  from typing import Iterable, override
3
3
 
4
- from predicate.predicate import Predicate
4
+ from predicate.predicate import Predicate, resolve_predicate
5
5
 
6
6
 
7
7
  @dataclass
@@ -31,3 +31,8 @@ class AnyPredicate[T](Predicate[T]):
31
31
  @override
32
32
  def explain_failure(self, iterable: Iterable[T]) -> dict:
33
33
  return {"reason": f"No item matches predicate {self.predicate!r}"}
34
+
35
+
36
+ def any_p[T](predicate: Predicate[T]) -> AnyPredicate[T]:
37
+ """Return True if the predicate holds for any item in the iterable, otherwise False."""
38
+ return AnyPredicate(predicate=resolve_predicate(predicate))
@@ -1,5 +1,5 @@
1
1
  from dataclasses import dataclass
2
- from typing import Callable, override
2
+ from typing import Any, Callable, override
3
3
 
4
4
  from predicate.predicate import Predicate
5
5
 
@@ -24,3 +24,8 @@ class CompPredicate[S, T](Predicate[T]):
24
24
  @override
25
25
  def explain_failure(self, x: S) -> dict:
26
26
  return {"reason": self.predicate.explain(x)}
27
+
28
+
29
+ def comp_p[T](fn: Callable[[Any], T], predicate: Predicate[T]) -> CompPredicate:
30
+ """Return a predicate, composed of a function and another predicate."""
31
+ return CompPredicate(fn=fn, predicate=predicate)
@@ -5,30 +5,26 @@ from more_itertools import first, gray_product, take
5
5
  from predicate import (
6
6
  always_false_p,
7
7
  always_true_p,
8
+ ge_p,
9
+ gt_p,
8
10
  is_datetime_p,
9
11
  is_falsy_p,
10
12
  is_float_p,
11
13
  is_int_p,
14
+ is_none_p,
12
15
  is_not_none_p,
13
16
  is_set_p,
14
17
  is_str_p,
15
18
  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
19
  le_p,
28
20
  lt_p,
29
21
  ne_p,
30
- zero_p,
31
22
  )
23
+ from predicate.constructor.helpers import perfect_match, sort_by_match
24
+ from predicate.constructor.mutate import mutations
25
+ from predicate.eq_predicate import zero_p
26
+ from predicate.is_instance_predicate import is_bool_p, is_dict_p, is_list_p
27
+ from predicate.predicate import Predicate
32
28
 
33
29
 
34
30
  def construct(false_set: list, true_set: list, attempts: int = 30) -> Predicate | None:
@@ -53,7 +53,7 @@ class DictOfPredicate[T](Predicate[T]):
53
53
 
54
54
 
55
55
  def to_key_p(key_p: Predicate | str) -> Predicate:
56
- from predicate.standard_predicates import eq_p
56
+ from predicate import eq_p
57
57
 
58
58
  match key_p:
59
59
  case str(s):
@@ -68,3 +68,9 @@ def from_key_p(key_p: Predicate) -> Predicate | str:
68
68
  return v
69
69
  case _:
70
70
  return key_p
71
+
72
+
73
+ def is_dict_of_p(*predicates: tuple[Predicate | str, Predicate]) -> Predicate:
74
+ """Return True if value is a set, and for all elements in the set the predicate is True, otherwise False."""
75
+ # return is_set_p & all_p(predicate)
76
+ return DictOfPredicate(list(predicates))
@@ -1,5 +1,5 @@
1
1
  from dataclasses import dataclass
2
- from typing import override
2
+ from typing import Final, override
3
3
 
4
4
  from predicate.predicate import Predicate
5
5
 
@@ -23,3 +23,18 @@ class EqPredicate[T](Predicate[T]):
23
23
  @override
24
24
  def explain_failure(self, x: T) -> dict:
25
25
  return {"reason": f"{x} is not equal to {self.v!r}"}
26
+
27
+
28
+ def eq_p[T](v: T) -> EqPredicate[T]:
29
+ """Return True if the value is equal to the constant, otherwise False."""
30
+ return EqPredicate(v=v)
31
+
32
+
33
+ zero_p: Final[EqPredicate] = eq_p(0)
34
+ """Returns True of the value is zero, otherwise False."""
35
+
36
+ eq_true_p: Final[EqPredicate] = eq_p(True)
37
+ """Returns True if the value is True, otherwise False."""
38
+
39
+ eq_false_p: Final[EqPredicate] = eq_p(False)
40
+ """Returns True if the value is False, otherwise False."""
@@ -0,0 +1,67 @@
1
+ import math
2
+ from dataclasses import dataclass
3
+ from itertools import repeat
4
+ from typing import Callable, Final, Iterator, override
5
+
6
+ from predicate.generator.helpers import generate_even_numbers, generate_odd_numbers, random_floats
7
+ from predicate.predicate import Predicate
8
+
9
+
10
+ def undefined() -> Iterator:
11
+ raise ValueError("Please register generator type")
12
+
13
+
14
+ @dataclass
15
+ class FnPredicate[T](Predicate[T]):
16
+ """A predicate class that can hold a function."""
17
+
18
+ predicate_fn: Callable[[T], bool]
19
+ generate_false_fn: Callable[[], Iterator] = undefined
20
+ generate_true_fn: Callable[[], Iterator] = undefined
21
+
22
+ def __call__(self, x: T) -> bool:
23
+ return self.predicate_fn(x)
24
+
25
+ def __repr__(self) -> str:
26
+ return f"fn_p(predicate_fn={self.predicate_fn.__name__})"
27
+
28
+ @override
29
+ def explain_failure(self, x: T) -> dict:
30
+ return {"reason": f"Function returned False for value {x}"}
31
+
32
+
33
+ def fn_p[T](
34
+ fn: Callable[[T], bool],
35
+ generate_false_fn: Callable[[], Iterator[T]] = undefined,
36
+ generate_true_fn: Callable[[], Iterator[T]] = undefined,
37
+ ) -> Predicate[T]:
38
+ """Return the boolean value of the function call."""
39
+ return FnPredicate(predicate_fn=fn, generate_false_fn=generate_false_fn, generate_true_fn=generate_true_fn)
40
+
41
+
42
+ is_even_p: Final[Predicate[int]] = fn_p(
43
+ fn=lambda x: x % 2 == 0, generate_true_fn=generate_even_numbers, generate_false_fn=generate_odd_numbers
44
+ )
45
+ is_odd_p: Final[Predicate[int]] = fn_p(
46
+ fn=lambda x: x % 2 != 0, generate_true_fn=generate_odd_numbers, generate_false_fn=generate_even_numbers
47
+ )
48
+
49
+
50
+ def generate_nan() -> Iterator:
51
+ yield from repeat(math.nan)
52
+
53
+
54
+ def generate_inf() -> Iterator:
55
+ while True:
56
+ yield -math.inf
57
+ yield math.inf
58
+
59
+
60
+ is_finite_p: Final[Predicate] = fn_p(fn=math.isfinite, generate_true_fn=random_floats, generate_false_fn=generate_inf)
61
+ """Return True if value is finite, otherwise False."""
62
+
63
+ is_inf_p: Final[Predicate] = fn_p(fn=math.isinf, generate_true_fn=generate_inf, generate_false_fn=random_floats)
64
+ """Return True if value is infinite, otherwise False."""
65
+
66
+ is_nan_p: Final[Predicate] = fn_p(fn=math.isnan, generate_true_fn=generate_nan, generate_false_fn=random_floats)
67
+ """Return True if value is not a number, otherwise False."""
@@ -17,6 +17,7 @@ from predicate.formatter.helpers import set_to_str
17
17
  from predicate.ge_predicate import GePredicate
18
18
  from predicate.gt_predicate import GtPredicate
19
19
  from predicate.implies import Implies
20
+ from predicate.in_predicate import InPredicate
20
21
  from predicate.is_falsy_predicate import IsFalsyPredicate
21
22
  from predicate.is_instance_predicate import IsInstancePredicate
22
23
  from predicate.is_none_predicate import IsNonePredicate
@@ -26,6 +27,7 @@ from predicate.le_predicate import LePredicate
26
27
  from predicate.lt_predicate import LtPredicate
27
28
  from predicate.named_predicate import NamedPredicate
28
29
  from predicate.ne_predicate import NePredicate
30
+ from predicate.not_in_predicate import NotInPredicate
29
31
  from predicate.optimizer.predicate_optimizer import optimize
30
32
  from predicate.predicate import (
31
33
  AndPredicate,
@@ -37,12 +39,10 @@ from predicate.predicate import (
37
39
  from predicate.range_predicate import GeLePredicate, GeLtPredicate, GtLePredicate, GtLtPredicate
38
40
  from predicate.root_predicate import RootPredicate, find_root_predicate
39
41
  from predicate.set_predicates import (
40
- InPredicate,
41
42
  IsRealSubsetPredicate,
42
43
  IsRealSupersetPredicate,
43
44
  IsSubsetPredicate,
44
45
  IsSupersetPredicate,
45
- NotInPredicate,
46
46
  )
47
47
  from predicate.tee_predicate import TeePredicate
48
48
  from predicate.this_predicate import ThisPredicate, find_this_predicate
@@ -6,6 +6,7 @@ from predicate.eq_predicate import EqPredicate
6
6
  from predicate.ge_predicate import GePredicate
7
7
  from predicate.gt_predicate import GtPredicate
8
8
  from predicate.implies_predicate import ImpliesPredicate
9
+ from predicate.in_predicate import InPredicate
9
10
  from predicate.le_predicate import LePredicate
10
11
  from predicate.lt_predicate import LtPredicate
11
12
  from predicate.ne_predicate import NePredicate
@@ -18,7 +19,6 @@ from predicate.predicate import (
18
19
  )
19
20
  from predicate.range_predicate import GeLePredicate, GeLtPredicate, GtLePredicate, GtLtPredicate
20
21
  from predicate.set_predicates import (
21
- InPredicate,
22
22
  IsRealSubsetPredicate,
23
23
  IsRealSupersetPredicate,
24
24
  IsSubsetPredicate,
@@ -23,3 +23,8 @@ class GePredicate[T](Predicate[T]):
23
23
  @override
24
24
  def explain_failure(self, x: T) -> dict:
25
25
  return {"reason": f"{x} is not greater or equal to {self.v!r}"}
26
+
27
+
28
+ def ge_p(v: ConstrainedT) -> GePredicate[ConstrainedT]:
29
+ """Return True if the value is greater or equal than the constant, otherwise False."""
30
+ return GePredicate(v=v)