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.
@@ -1,5 +1,5 @@
1
- __version__ = "0.6.27"
1
+ __version__ = "0.6.28"
2
2
 
3
3
  import logging
4
4
  logger = logging.Logger("rdr")
5
- logger.setLevel(logging.INFO)
5
+ logger.setLevel(logging.INFO)
@@ -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.
@@ -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, viewer: Optional[RDRCaseViewer] = None, **kwargs):
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(viewer)
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, viewer: Optional[RDRCaseViewer] = 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] = viewer
98
- if viewer is None and RDRCaseViewer is not None:
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, value):
111
- self._viewer = value
112
- if value is not None:
113
- value.set_save_function(self.save)
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(viewer=self.viewer,
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(viewer=self.viewer,
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=1)
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, viewer: Optional[RDRCaseViewer] = None):
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 = viewer
39
- self.print_func = print if viewer is None else viewer.print
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
- prompt_str = f"{Fore.WHITE}{prompt_str}" if prompt_str is not None else ''
99
+ initial_prompt_str = f"{prompt_str}\n" if prompt_str is not None else ''
103
100
  if prompt_for == PromptFor.Conclusion:
104
- prompt_str += f"\n{Fore.MAGENTA}Give possible value(s) for:"
101
+ prompt_for_str = f"Give possible value(s) for:"
105
102
  else:
106
- prompt_str += f"\n{Fore.MAGENTA}Give conditions on when can the rule be evaluated for:"
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.27
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=TaxvqRWwXyeD_ETYnf_G3Z5VlbdhClbNpLIff72WwGg,100
2
- ripple_down_rules/experts.py,sha256=MYK1-vuvU1Stp82YZa8TcwOzvriIiYb0WrPFpWUNnXc,13005
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=PaoNwbrwnZBjXXkIVO3_sz_MsNUBjfooxBs9RT3bb64,62081
5
- ripple_down_rules/rdr_decorators.py,sha256=TRhbaB_ZIXN0n8Up19NI43_mMjmTm24qo8axAAOzbxM,11728
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=R9AkhMKTDErOSZ8J6gEdh2lQ0Bjsxs22eMBtCPrXosI,5804
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=druufu9cVeVUajPW-RqGW3ZiEbgdgNBQD2CLhadQo18,27486
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=e5FzVfiIagwKTK3WCKsHvWaWZ4kb8FP8X-SgieTln6E,9156
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.27.dist-info/licenses/LICENSE,sha256=ixuiBLtpoK3iv89l7ylKkg9rs2GzF9ukPH7ynZYzK5s,35148
21
- ripple_down_rules-0.6.27.dist-info/METADATA,sha256=L_eYP6eqnQnZaLw-7FHIV774Yj_Q1IcJ9HAkkwP9um4,48294
22
- ripple_down_rules-0.6.27.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
23
- ripple_down_rules-0.6.27.dist-info/top_level.txt,sha256=VeoLhEhyK46M1OHwoPbCQLI1EifLjChqGzhQ6WEUqeM,18
24
- ripple_down_rules-0.6.27.dist-info/RECORD,,
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,,