ripple-down-rules 0.6.27__py3-none-any.whl → 0.6.28__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 +2 -2
- ripple_down_rules/datastructures/enums.py +13 -0
- ripple_down_rules/experts.py +2 -4
- ripple_down_rules/rdr.py +8 -14
- ripple_down_rules/rdr_decorators.py +1 -2
- ripple_down_rules/user_interface/gui.py +5 -2
- ripple_down_rules/user_interface/prompt.py +14 -12
- {ripple_down_rules-0.6.27.dist-info → ripple_down_rules-0.6.28.dist-info}/METADATA +1 -1
- {ripple_down_rules-0.6.27.dist-info → ripple_down_rules-0.6.28.dist-info}/RECORD +12 -12
- {ripple_down_rules-0.6.27.dist-info → ripple_down_rules-0.6.28.dist-info}/WHEEL +0 -0
- {ripple_down_rules-0.6.27.dist-info → ripple_down_rules-0.6.28.dist-info}/licenses/LICENSE +0 -0
- {ripple_down_rules-0.6.27.dist-info → ripple_down_rules-0.6.28.dist-info}/top_level.txt +0 -0
ripple_down_rules/__init__.py
CHANGED
@@ -7,6 +7,19 @@ from typing_extensions import List, Dict, Any, Type
|
|
7
7
|
from ripple_down_rules.utils import SubclassJSONSerializer
|
8
8
|
|
9
9
|
|
10
|
+
class ExitStatus(Enum):
|
11
|
+
"""
|
12
|
+
Describes the status at exit of the user interface.
|
13
|
+
"""
|
14
|
+
CLOSE = auto()
|
15
|
+
"""
|
16
|
+
The user wants to stop the program.
|
17
|
+
"""
|
18
|
+
SUCCESS = auto()
|
19
|
+
"""
|
20
|
+
The user completed the task successfully.
|
21
|
+
"""
|
22
|
+
|
10
23
|
class InteractionMode(Enum):
|
11
24
|
"""
|
12
25
|
The interaction mode of the RDR.
|
ripple_down_rules/experts.py
CHANGED
@@ -213,14 +213,12 @@ class Human(Expert):
|
|
213
213
|
The Human Expert class, an expert that asks the human to provide differentiating features and conclusions.
|
214
214
|
"""
|
215
215
|
|
216
|
-
def __init__(self,
|
216
|
+
def __init__(self, **kwargs):
|
217
217
|
"""
|
218
218
|
Initialize the Human expert.
|
219
|
-
|
220
|
-
:param viewer: The RDRCaseViewer instance to use for prompting the user.
|
221
219
|
"""
|
222
220
|
super().__init__(**kwargs)
|
223
|
-
self.user_prompt = UserPrompt(
|
221
|
+
self.user_prompt = UserPrompt()
|
224
222
|
|
225
223
|
def ask_for_conditions(self, case_query: CaseQuery,
|
226
224
|
last_evaluated_rule: Optional[Rule] = None) \
|
ripple_down_rules/rdr.py
CHANGED
@@ -83,23 +83,18 @@ class RippleDownRules(SubclassJSONSerializer, ABC):
|
|
83
83
|
Whether the output of the classification of this rdr allows only one possible conclusion or not.
|
84
84
|
"""
|
85
85
|
|
86
|
-
def __init__(self, start_rule: Optional[Rule] = None,
|
86
|
+
def __init__(self, start_rule: Optional[Rule] = None,
|
87
87
|
save_dir: Optional[str] = None, model_name: Optional[str] = None):
|
88
88
|
"""
|
89
89
|
:param start_rule: The starting rule for the classifier.
|
90
|
-
:param viewer: The viewer gui to use for the classifier. If None, no viewer is used.
|
91
90
|
:param save_dir: The directory to save the classifier to.
|
92
91
|
"""
|
93
92
|
self.model_name: Optional[str] = model_name
|
94
93
|
self.save_dir = save_dir
|
95
94
|
self.start_rule = start_rule
|
96
95
|
self.fig: Optional[Figure] = None
|
97
|
-
self.viewer: Optional[RDRCaseViewer] =
|
98
|
-
|
99
|
-
if len(RDRCaseViewer.instances) > 0:
|
100
|
-
self.viewer = RDRCaseViewer.instances[0]
|
101
|
-
logger.error("No viewer was provided, but there is already an existing viewer. "
|
102
|
-
"Using the existing viewer.")
|
96
|
+
self.viewer: Optional[RDRCaseViewer] = RDRCaseViewer.instances[0]\
|
97
|
+
if RDRCaseViewer and any(RDRCaseViewer.instances) else None
|
103
98
|
self.input_node: Optional[Rule] = None
|
104
99
|
|
105
100
|
@property
|
@@ -107,10 +102,10 @@ class RippleDownRules(SubclassJSONSerializer, ABC):
|
|
107
102
|
return self._viewer
|
108
103
|
|
109
104
|
@viewer.setter
|
110
|
-
def viewer(self,
|
111
|
-
self._viewer =
|
112
|
-
if
|
113
|
-
|
105
|
+
def viewer(self, viewer):
|
106
|
+
self._viewer = viewer
|
107
|
+
if viewer:
|
108
|
+
viewer.set_save_function(self.save)
|
114
109
|
|
115
110
|
def render_evaluated_rule_tree(self, filename: str, show_full_tree: bool = False) -> None:
|
116
111
|
if show_full_tree:
|
@@ -335,8 +330,7 @@ class RippleDownRules(SubclassJSONSerializer, ABC):
|
|
335
330
|
self.case_name = case_query.case_name if self.case_name is None else self.case_name
|
336
331
|
case_query.scenario = scenario if case_query.scenario is None else case_query.scenario
|
337
332
|
|
338
|
-
expert = expert or Human(
|
339
|
-
answers_save_path=self.save_dir + '/expert_answers'
|
333
|
+
expert = expert or Human(answers_save_path=self.save_dir + '/expert_answers'
|
340
334
|
if self.save_dir else None)
|
341
335
|
if case_query.target is None:
|
342
336
|
case_query_cp = copy(case_query)
|
@@ -96,8 +96,7 @@ class RDRDecorator:
|
|
96
96
|
if len(self.parsed_output_type) == 0:
|
97
97
|
self.parsed_output_type = self.parse_output_type(func, self.output_type, *args)
|
98
98
|
if self.expert is None:
|
99
|
-
self.expert = Human(
|
100
|
-
answers_save_path=self.rdr_models_dir + f'/{self.model_name}/expert_answers')
|
99
|
+
self.expert = Human(answers_save_path=self.rdr_models_dir + f'/{self.model_name}/expert_answers')
|
101
100
|
case_query = self.create_case_query_from_method(func, func_output,
|
102
101
|
self.parsed_output_type,
|
103
102
|
self.mutual_exclusive,
|
@@ -21,7 +21,7 @@ except ImportError as e:
|
|
21
21
|
from typing_extensions import Optional, Any, List, Dict, Callable
|
22
22
|
|
23
23
|
from ..datastructures.dataclasses import CaseQuery
|
24
|
-
from ..datastructures.enums import PromptFor
|
24
|
+
from ..datastructures.enums import PromptFor, ExitStatus
|
25
25
|
from .template_file_creator import TemplateFileCreator
|
26
26
|
from ..utils import is_iterable, contains_return_statement, encapsulate_code_lines_into_a_function
|
27
27
|
from .object_diagram import generate_object_graph
|
@@ -283,11 +283,13 @@ class RDRCaseViewer(QMainWindow):
|
|
283
283
|
attributes_widget: Optional[QWidget] = None
|
284
284
|
save_function: Optional[Callable[str, str], None] = None
|
285
285
|
instances: List[RDRCaseViewer] = []
|
286
|
+
exit_status: ExitStatus = ExitStatus.CLOSE
|
286
287
|
|
287
288
|
def __init__(self, parent=None,
|
288
289
|
save_dir: Optional[str] = None,
|
289
290
|
save_model_name: Optional[str] = None):
|
290
291
|
super().__init__(parent)
|
292
|
+
self.exit_status = ExitStatus.CLOSE
|
291
293
|
self.instances.clear()
|
292
294
|
self.instances.append(self)
|
293
295
|
self.save_dir = save_dir
|
@@ -328,7 +330,7 @@ class RDRCaseViewer(QMainWindow):
|
|
328
330
|
|
329
331
|
# Add both to main layout
|
330
332
|
main_layout.addWidget(self.attributes_widget, stretch=1)
|
331
|
-
main_layout.addWidget(middle_widget, stretch=
|
333
|
+
main_layout.addWidget(middle_widget, stretch=2)
|
332
334
|
main_layout.addWidget(self.obj_diagram_viewer, stretch=2)
|
333
335
|
|
334
336
|
def set_save_function(self, save_function: Callable[[str, str], None]) -> None:
|
@@ -474,6 +476,7 @@ class RDRCaseViewer(QMainWindow):
|
|
474
476
|
return button_widget
|
475
477
|
|
476
478
|
def _accept(self):
|
479
|
+
self.exit_status = ExitStatus.SUCCESS
|
477
480
|
# close the window
|
478
481
|
self.close()
|
479
482
|
|
@@ -4,7 +4,7 @@ from _ast import AST
|
|
4
4
|
|
5
5
|
try:
|
6
6
|
from PyQt6.QtWidgets import QApplication
|
7
|
-
from .gui import RDRCaseViewer
|
7
|
+
from .gui import RDRCaseViewer, style
|
8
8
|
except ImportError:
|
9
9
|
QApplication = None
|
10
10
|
RDRCaseViewer = None
|
@@ -17,7 +17,7 @@ from typing_extensions import Optional, Tuple
|
|
17
17
|
|
18
18
|
from ..datastructures.callable_expression import CallableExpression, parse_string_to_expression
|
19
19
|
from ..datastructures.dataclasses import CaseQuery
|
20
|
-
from ..datastructures.enums import PromptFor
|
20
|
+
from ..datastructures.enums import PromptFor, ExitStatus
|
21
21
|
from .ipython_custom_shell import IPythonShell
|
22
22
|
from ..utils import make_list
|
23
23
|
from threading import RLock
|
@@ -29,15 +29,12 @@ class UserPrompt:
|
|
29
29
|
"""
|
30
30
|
shell_lock: RLock = RLock() # To ensure that only one thread can access the shell at a time
|
31
31
|
|
32
|
-
def __init__(self
|
32
|
+
def __init__(self):
|
33
33
|
"""
|
34
34
|
Initialize the UserPrompt class.
|
35
|
-
|
36
|
-
:param viewer: The RDRCaseViewer instance to use for prompting the user.
|
37
35
|
"""
|
38
|
-
self.viewer =
|
39
|
-
self.print_func = print if viewer
|
40
|
-
|
36
|
+
self.viewer = RDRCaseViewer.instances[0] if RDRCaseViewer and any(RDRCaseViewer.instances) else None
|
37
|
+
self.print_func = self.viewer.print if self.viewer else print
|
41
38
|
|
42
39
|
def prompt_user_for_expression(self, case_query: CaseQuery, prompt_for: PromptFor, prompt_str: Optional[str] = None) \
|
43
40
|
-> Tuple[Optional[str], Optional[CallableExpression]]:
|
@@ -99,19 +96,20 @@ class UserPrompt:
|
|
99
96
|
:return: The user input, and the executable expression that was parsed from the user input.
|
100
97
|
"""
|
101
98
|
self.print_func("Entered shell")
|
102
|
-
|
99
|
+
initial_prompt_str = f"{prompt_str}\n" if prompt_str is not None else ''
|
103
100
|
if prompt_for == PromptFor.Conclusion:
|
104
|
-
|
101
|
+
prompt_for_str = f"Give possible value(s) for:"
|
105
102
|
else:
|
106
|
-
|
103
|
+
prompt_for_str = f"Give conditions for:"
|
107
104
|
case_query.scope.update({'case': case_query.case})
|
108
105
|
shell = None
|
109
106
|
if self.viewer is None:
|
107
|
+
prompt_str = f"{Fore.WHITE}{initial_prompt_str}{Fore.MAGENTA}{prompt_for_str}"
|
110
108
|
prompt_str = self.construct_prompt_str_for_shell(case_query, prompt_for, prompt_str)
|
111
109
|
shell = IPythonShell(header=prompt_str, prompt_for=prompt_for, case_query=case_query,
|
112
110
|
code_to_modify=code_to_modify)
|
113
111
|
else:
|
114
|
-
|
112
|
+
prompt_str = initial_prompt_str + prompt_for_str
|
115
113
|
self.viewer.update_for_case_query(case_query, prompt_str,
|
116
114
|
prompt_for=prompt_for, code_to_modify=code_to_modify)
|
117
115
|
user_input, expression_tree = self.prompt_user_input_and_parse_to_expression(shell=shell)
|
@@ -176,6 +174,8 @@ class UserPrompt:
|
|
176
174
|
"""
|
177
175
|
if self.viewer is None:
|
178
176
|
shell = IPythonShell() if shell is None else shell
|
177
|
+
if not hasattr(shell.shell, "auto_match"):
|
178
|
+
shell.shell.auto_match = True # or True, depending on your preference
|
179
179
|
shell.run()
|
180
180
|
user_input = shell.user_input
|
181
181
|
else:
|
@@ -184,5 +184,7 @@ class UserPrompt:
|
|
184
184
|
raise RuntimeError("QApplication instance is None. Please run the application first.")
|
185
185
|
self.viewer.show()
|
186
186
|
app.exec()
|
187
|
+
if self.viewer.exit_status == ExitStatus.CLOSE:
|
188
|
+
exit(0)
|
187
189
|
user_input = self.viewer.user_input
|
188
190
|
return user_input
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: ripple_down_rules
|
3
|
-
Version: 0.6.
|
3
|
+
Version: 0.6.28
|
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,8 +1,8 @@
|
|
1
|
-
ripple_down_rules/__init__.py,sha256=
|
2
|
-
ripple_down_rules/experts.py,sha256=
|
1
|
+
ripple_down_rules/__init__.py,sha256=XvJJjrncdmKjrvKVVILZq7uuTOYiohoP3iLBN_oKp_M,99
|
2
|
+
ripple_down_rules/experts.py,sha256=bQfDB7RZE_CANVkpBMb9bi8ZWFwk5p7hn1AzjpaO5ow,12877
|
3
3
|
ripple_down_rules/helpers.py,sha256=X1psHOqrb4_xYN4ssQNB8S9aRKKsqgihAyWJurN0dqk,5499
|
4
|
-
ripple_down_rules/rdr.py,sha256=
|
5
|
-
ripple_down_rules/rdr_decorators.py,sha256=
|
4
|
+
ripple_down_rules/rdr.py,sha256=hVqfCRrru6TUnqzY7yGMjiNnxUIFjfL2U7txmGNjeGI,61661
|
5
|
+
ripple_down_rules/rdr_decorators.py,sha256=xoBGsIJMkJYUdsrsEaPZqoAsGuXkuVZAKCoP-xD2Iv8,11668
|
6
6
|
ripple_down_rules/rules.py,sha256=N4dEx-xyqxGZpoEYzRd9P5u97_DcDEVLY_UiNhZ4E7g,28726
|
7
7
|
ripple_down_rules/start-code-server.sh,sha256=otClk7VmDgBOX2TS_cjws6K0UwvgAUJhoA0ugkPCLqQ,949
|
8
8
|
ripple_down_rules/utils.py,sha256=9xW0N2cB7X4taVANtLg-kVTPS-6ajWZylKkTqw2PKw4,73825
|
@@ -10,15 +10,15 @@ ripple_down_rules/datastructures/__init__.py,sha256=V2aNgf5C96Y5-IGghra3n9uiefpo
|
|
10
10
|
ripple_down_rules/datastructures/callable_expression.py,sha256=P3o-z54Jt4rtIczeFWiuHFTNqMzYEOm94OyOP535D6Q,13378
|
11
11
|
ripple_down_rules/datastructures/case.py,sha256=PJ7_-AdxYic6BO5z816piFODj6nU5J6Jt1YzTFH-dds,15510
|
12
12
|
ripple_down_rules/datastructures/dataclasses.py,sha256=kI3Kv8GiVR8igMgA_BlKN6djUYxC2mLecvyh19pqQQA,10998
|
13
|
-
ripple_down_rules/datastructures/enums.py,sha256=
|
13
|
+
ripple_down_rules/datastructures/enums.py,sha256=CvcROl8fE7A6uTbMfs2lLpyxwS_ZFtFcQlBDDKFfoHc,6059
|
14
14
|
ripple_down_rules/user_interface/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
15
|
-
ripple_down_rules/user_interface/gui.py,sha256=
|
15
|
+
ripple_down_rules/user_interface/gui.py,sha256=JCz6vA2kWVvRD6CupoUfMbtGz39cvUlmVnGnw_fY6OA,27635
|
16
16
|
ripple_down_rules/user_interface/ipython_custom_shell.py,sha256=yp-F8YRWGhj1PLB33HE6vJkdYWFN5Zn2244S2DUWRTM,6576
|
17
17
|
ripple_down_rules/user_interface/object_diagram.py,sha256=FEa2HaYR9QmTE6NsOwBvZ0jqmu3DKyg6mig2VE5ZP4Y,4956
|
18
|
-
ripple_down_rules/user_interface/prompt.py,sha256=
|
18
|
+
ripple_down_rules/user_interface/prompt.py,sha256=nLIAviClSmVCY80vQgTazDPs4a1AYmNQmT7sksLDJpE,9449
|
19
19
|
ripple_down_rules/user_interface/template_file_creator.py,sha256=kwBbFLyN6Yx2NTIHPSwOoytWgbJDYhgrUOVFw_jkDQ4,13522
|
20
|
-
ripple_down_rules-0.6.
|
21
|
-
ripple_down_rules-0.6.
|
22
|
-
ripple_down_rules-0.6.
|
23
|
-
ripple_down_rules-0.6.
|
24
|
-
ripple_down_rules-0.6.
|
20
|
+
ripple_down_rules-0.6.28.dist-info/licenses/LICENSE,sha256=ixuiBLtpoK3iv89l7ylKkg9rs2GzF9ukPH7ynZYzK5s,35148
|
21
|
+
ripple_down_rules-0.6.28.dist-info/METADATA,sha256=fPfcVvFD7eEuG5FKX26HRRWPJkZatA0mfWdarnTqPa8,48294
|
22
|
+
ripple_down_rules-0.6.28.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
23
|
+
ripple_down_rules-0.6.28.dist-info/top_level.txt,sha256=VeoLhEhyK46M1OHwoPbCQLI1EifLjChqGzhQ6WEUqeM,18
|
24
|
+
ripple_down_rules-0.6.28.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|