ripple-down-rules 0.6.49__py3-none-any.whl → 0.6.50__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ripple_down_rules/__init__.py +1 -1
- ripple_down_rules/rdr_decorators.py +98 -81
- {ripple_down_rules-0.6.49.dist-info → ripple_down_rules-0.6.50.dist-info}/METADATA +1 -1
- {ripple_down_rules-0.6.49.dist-info → ripple_down_rules-0.6.50.dist-info}/RECORD +7 -7
- {ripple_down_rules-0.6.49.dist-info → ripple_down_rules-0.6.50.dist-info}/WHEEL +0 -0
- {ripple_down_rules-0.6.49.dist-info → ripple_down_rules-0.6.50.dist-info}/licenses/LICENSE +0 -0
- {ripple_down_rules-0.6.49.dist-info → ripple_down_rules-0.6.50.dist-info}/top_level.txt +0 -0
ripple_down_rules/__init__.py
CHANGED
@@ -4,17 +4,18 @@ that can be used with any python function such that this function can benefit fr
|
|
4
4
|
of the RDRs.
|
5
5
|
"""
|
6
6
|
import os.path
|
7
|
+
from dataclasses import dataclass, field
|
7
8
|
from functools import wraps
|
8
9
|
from typing import get_origin
|
9
10
|
|
10
11
|
from typing_extensions import Callable, Optional, Type, Tuple, Dict, Any, Self, get_type_hints, List, Union, Sequence
|
11
12
|
|
12
|
-
from .utils import get_type_from_type_hint
|
13
13
|
from .datastructures.case import Case
|
14
14
|
from .datastructures.dataclasses import CaseQuery
|
15
15
|
from .experts import Expert, Human
|
16
16
|
from .rdr import GeneralRDR
|
17
|
-
from . import
|
17
|
+
from .utils import get_type_from_type_hint
|
18
|
+
|
18
19
|
try:
|
19
20
|
from .user_interface.gui import RDRCaseViewer
|
20
21
|
except ImportError:
|
@@ -23,63 +24,92 @@ from .utils import get_method_args_as_dict, get_func_rdr_model_name, make_set, \
|
|
23
24
|
get_method_class_if_exists, str_to_snake_case, make_list
|
24
25
|
|
25
26
|
|
27
|
+
@dataclass(unsafe_hash=True)
|
26
28
|
class RDRDecorator:
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
29
|
+
models_dir: str
|
30
|
+
"""
|
31
|
+
The directory to save the RDR models in.
|
32
|
+
"""
|
33
|
+
output_type: Tuple[Type, ...]
|
34
|
+
"""
|
35
|
+
The type(s) of the output produced by the RDR model (The type(s) of the queried attribute).
|
36
|
+
"""
|
37
|
+
mutual_exclusive: bool
|
38
|
+
"""
|
39
|
+
Whether the queried attribute is mutually exclusive (i.e. allows for only one possible value) or not.
|
40
|
+
"""
|
41
|
+
fit: bool = field(default=True)
|
42
|
+
"""
|
43
|
+
Whether to run in fitting mode and prompt the expert or just classify using existing rules.
|
44
|
+
"""
|
45
|
+
expert: Optional[Expert] = field(default=None)
|
46
|
+
"""
|
47
|
+
The expert instance, this is used by the rdr to prompt for answers.
|
48
|
+
"""
|
49
|
+
update_existing_rules: bool = field(default=True)
|
50
|
+
"""
|
51
|
+
When in fitting mode, whether to ask for answers for existing rules as well or not.
|
52
|
+
"""
|
53
|
+
package_name: Optional[str] = field(default=None)
|
54
|
+
"""
|
55
|
+
The name of the user python package where the RDR model will be saved, this is useful for generating relative
|
56
|
+
imports in the generated rdr model files.
|
57
|
+
"""
|
58
|
+
use_generated_classifier: bool = field(default=False)
|
59
|
+
"""
|
60
|
+
Whether to use the generated classifier files of the rdr model instead of the RDR instance itself, this is useful
|
61
|
+
when you want to debug inside the rules.
|
62
|
+
"""
|
63
|
+
ask_now: Callable[Dict[str, Any], bool] = field(default=lambda _: True)
|
64
|
+
"""
|
65
|
+
A user provided callable function that outputs a boolean indicating when to ask the expert for an answer. The input
|
66
|
+
to the `ask_now` function is a dictionary with the original function arguments, while arguments like `self` and
|
67
|
+
`cls` are passed as a special key `self_` or `cls_` respectively.
|
68
|
+
"""
|
69
|
+
fitting_decorator: Optional[Callable] = field(default=lambda f: f)
|
70
|
+
"""
|
71
|
+
A user provided decorator that wraps the `py:meth:ripple_down_rules.rdr.RippleDownRules.fit_case` method which is
|
72
|
+
used when in fitting mode, this is useful when you want special logic pre and post the fitting operation, you can
|
73
|
+
for example freeze your system during fitting such that you have a stable state that you can query and use while
|
74
|
+
writing and testing your answer/rule.
|
75
|
+
"""
|
76
|
+
generate_dot_file: bool = field(default=False)
|
77
|
+
"""
|
78
|
+
Whether to generate a dynamic dot file representing the state of the rule tree each time the rdr is queried, showing
|
79
|
+
which rules fired and which rules didn't get evaluated, ...etc.
|
80
|
+
"""
|
81
|
+
model_name: Optional[str] = field(default=None)
|
82
|
+
"""
|
83
|
+
The name of the rdr model, this gets auto generated from the function signature and the class/file it is contained
|
84
|
+
in.
|
85
|
+
"""
|
86
|
+
rdr: GeneralRDR = field(init=False)
|
87
|
+
"""
|
88
|
+
The ripple down rules instance of the decorator class.
|
89
|
+
"""
|
90
|
+
parsed_output_type: List[Type] = field(init=False, default_factory=list)
|
91
|
+
"""
|
92
|
+
The output of a post processing done on the output types, for example converting typing module types
|
93
|
+
(i.e. type hints) to python types.
|
94
|
+
"""
|
95
|
+
origin_type: Optional[Type] = field(init=False, default=None)
|
96
|
+
"""
|
97
|
+
The origin of the type hint of the attribute, useful in the case of not mutually exclusive attributes to map the
|
98
|
+
result to the specified container type (e.g. a list instead of a set which is the default container type for rdr
|
99
|
+
output).
|
100
|
+
"""
|
101
|
+
output_name: str = field(init=False, default='output_')
|
102
|
+
"""
|
103
|
+
This is used to refer to the output value of the decorated function, this is used as part of the case as input to
|
104
|
+
the rdr model, but is never used in the rule logic to prevent cycles from happening. The correct way to use the
|
105
|
+
output of an rdr in the rules logic is in the case when mutually exclusive is False, or through refinements of
|
106
|
+
existing rules when mutually exclusive is True, which happens automatically by the rdr prompting for refinements.
|
107
|
+
"""
|
108
|
+
_not_none_output_found: bool = field(init=False, default=False)
|
109
|
+
"""
|
110
|
+
This is a flag that indicates that a not None output for the rdr has been inferred, this is used to update the
|
111
|
+
generated dot file if it is set to `True`.
|
112
|
+
"""
|
83
113
|
|
84
114
|
def decorator(self, func: Callable) -> Callable:
|
85
115
|
|
@@ -102,33 +132,33 @@ class RDRDecorator:
|
|
102
132
|
if len(self.parsed_output_type) == 0:
|
103
133
|
self.parsed_output_type = self.parse_output_type(func, self.output_type, *args)
|
104
134
|
if self.expert is None:
|
105
|
-
self.expert = Human(answers_save_path=self.
|
135
|
+
self.expert = Human(answers_save_path=self.models_dir + f'/{self.model_name}/expert_answers')
|
106
136
|
case_query = self.create_case_query_from_method(func, func_output,
|
107
137
|
self.parsed_output_type,
|
108
138
|
self.mutual_exclusive,
|
109
139
|
case, case_dict,
|
110
140
|
*args, **kwargs)
|
111
141
|
output = self.rdr.fit_case(case_query, expert=self.expert,
|
112
|
-
update_existing_rules=self.update_existing_rules
|
113
|
-
viewer=self.viewer)
|
142
|
+
update_existing_rules=self.update_existing_rules)
|
114
143
|
return output
|
115
|
-
|
144
|
+
|
116
145
|
if self.fit and not self.use_generated_classifier and self.ask_now(case_dict):
|
117
146
|
output = fit()
|
118
147
|
else:
|
119
148
|
if self.use_generated_classifier:
|
120
149
|
if self.generated_classifier is None:
|
121
|
-
model_path = os.path.join(self.
|
150
|
+
model_path = os.path.join(self.models_dir, self.model_name)
|
122
151
|
self.generated_classifier = self.rdr.get_rdr_classifier_from_python_file(model_path)
|
123
152
|
output = self.generated_classifier(case)
|
124
153
|
else:
|
125
154
|
output = self.rdr.classify(case)
|
126
155
|
if self.generate_dot_file:
|
127
156
|
eval_rule_tree = self.rdr.get_evaluated_rule_tree()
|
128
|
-
if not self.
|
129
|
-
self.rdr.render_evaluated_rule_tree(self.
|
157
|
+
if not self._not_none_output_found or (eval_rule_tree and len(eval_rule_tree) > 1):
|
158
|
+
self.rdr.render_evaluated_rule_tree(self.models_dir + f'/{self.model_name}',
|
159
|
+
show_full_tree=True)
|
130
160
|
if eval_rule_tree and len(eval_rule_tree) > 1:
|
131
|
-
self.
|
161
|
+
self._not_none_output_found = True
|
132
162
|
|
133
163
|
if self.output_name in output:
|
134
164
|
if self.origin_type == list:
|
@@ -189,7 +219,6 @@ class RDRDecorator:
|
|
189
219
|
return Case(dict, id(case_dict), case_name, case_dict, **case_dict), case_dict
|
190
220
|
|
191
221
|
def initialize_rdr_model_name_and_load(self, func: Callable) -> None:
|
192
|
-
self.viewer = RDRCaseViewer.instances[0] if RDRCaseViewer is not None and len(RDRCaseViewer.instances) > 0 else self.viewer
|
193
222
|
model_file_name = get_func_rdr_model_name(func, include_file_name=True)
|
194
223
|
self.model_name = str_to_snake_case(model_file_name)
|
195
224
|
self.load()
|
@@ -209,20 +238,8 @@ class RDRDecorator:
|
|
209
238
|
parsed_output_type.append(ot)
|
210
239
|
return parsed_output_type
|
211
240
|
|
212
|
-
def save(self):
|
213
|
-
"""
|
214
|
-
Save the RDR model to the specified directory.
|
215
|
-
"""
|
216
|
-
self.rdr.save(self.rdr_models_dir, self.model_name, package_name=self.package_name)
|
217
|
-
|
218
241
|
def load(self):
|
219
242
|
"""
|
220
|
-
Load the RDR model from the specified directory.
|
221
|
-
"""
|
222
|
-
self.rdr = GeneralRDR(save_dir=self.rdr_models_dir, model_name=self.model_name)
|
223
|
-
|
224
|
-
def update_from_python(self):
|
225
|
-
"""
|
226
|
-
Update the RDR model from a python file.
|
243
|
+
Load the RDR model from the specified directory, otherwise create a new one.
|
227
244
|
"""
|
228
|
-
self.rdr
|
245
|
+
self.rdr = GeneralRDR(save_dir=self.models_dir, model_name=self.model_name)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: ripple_down_rules
|
3
|
-
Version: 0.6.
|
3
|
+
Version: 0.6.50
|
4
4
|
Summary: Implements the various versions of Ripple Down Rules (RDR) for knowledge representation and reasoning.
|
5
5
|
Author-email: Abdelrhman Bassiouny <abassiou@uni-bremen.de>
|
6
6
|
License: GNU GENERAL PUBLIC LICENSE
|
@@ -1,9 +1,9 @@
|
|
1
|
-
ripple_down_rules/__init__.py,sha256=
|
1
|
+
ripple_down_rules/__init__.py,sha256=6EQLRCLTgXJBkkqQ-9rcFfDRgNFPMVqlW-ofOWDjfAY,375
|
2
2
|
ripple_down_rules/experts.py,sha256=KXwWCmDrCffu9HW3yNewqWc1e5rnPI5Rnc981w_5M7U,17896
|
3
3
|
ripple_down_rules/failures.py,sha256=ZPypPwKjyVcJkY9YG6p538ld8ZzpdW6CrC1RmJi44Ek,42
|
4
4
|
ripple_down_rules/helpers.py,sha256=sVU1Q7HPbMh57X8zDYP6vj1maDoaVAvnXHpUYIbr_As,5715
|
5
5
|
ripple_down_rules/rdr.py,sha256=M7CEjHIegJWiDZtn-B8Qf9CpMvplAkrFX3HiiyGQC7M,84292
|
6
|
-
ripple_down_rules/rdr_decorators.py,sha256=
|
6
|
+
ripple_down_rules/rdr_decorators.py,sha256=H3ONvgTSgL5LS_Nv_hKAYY2nkqvn7KZ1zmIzIDi07dA,11870
|
7
7
|
ripple_down_rules/rules.py,sha256=L4Ws-x3g5ljE0GrDt4LAib2qtR1C1_Ra4cRcIB-IQDI,28702
|
8
8
|
ripple_down_rules/start-code-server.sh,sha256=otClk7VmDgBOX2TS_cjws6K0UwvgAUJhoA0ugkPCLqQ,949
|
9
9
|
ripple_down_rules/utils.py,sha256=5UL4h-m5Q4l7RyCYqmUmDDxUAkFqPYpFa3QldDYoJUE,80752
|
@@ -18,8 +18,8 @@ ripple_down_rules/user_interface/ipython_custom_shell.py,sha256=GQf5Je5szkPH17g4
|
|
18
18
|
ripple_down_rules/user_interface/object_diagram.py,sha256=FEa2HaYR9QmTE6NsOwBvZ0jqmu3DKyg6mig2VE5ZP4Y,4956
|
19
19
|
ripple_down_rules/user_interface/prompt.py,sha256=WPbw_8_-8SpF2ISyRZRuFwPKBEuGC4HaX3lbCPFHhh8,10314
|
20
20
|
ripple_down_rules/user_interface/template_file_creator.py,sha256=uSbosZS15MOR3Nv7M3MrFuoiKXyP4cBId-EK3I6stHM,13660
|
21
|
-
ripple_down_rules-0.6.
|
22
|
-
ripple_down_rules-0.6.
|
23
|
-
ripple_down_rules-0.6.
|
24
|
-
ripple_down_rules-0.6.
|
25
|
-
ripple_down_rules-0.6.
|
21
|
+
ripple_down_rules-0.6.50.dist-info/licenses/LICENSE,sha256=ixuiBLtpoK3iv89l7ylKkg9rs2GzF9ukPH7ynZYzK5s,35148
|
22
|
+
ripple_down_rules-0.6.50.dist-info/METADATA,sha256=LVOjG94lFcXLJD80mILahLyK1sYrsHEsDogeKg-PBSU,48294
|
23
|
+
ripple_down_rules-0.6.50.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
24
|
+
ripple_down_rules-0.6.50.dist-info/top_level.txt,sha256=VeoLhEhyK46M1OHwoPbCQLI1EifLjChqGzhQ6WEUqeM,18
|
25
|
+
ripple_down_rules-0.6.50.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|