ripple-down-rules 0.6.44__py3-none-any.whl → 0.6.46__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,4 +1,4 @@
1
- __version__ = "0.6.44"
1
+ __version__ = "0.6.46"
2
2
 
3
3
  import logging
4
4
  logger = logging.Logger("rdr")
@@ -0,0 +1,4 @@
1
+
2
+
3
+ class RDRLoadError(Exception):
4
+ pass
ripple_down_rules/rdr.py CHANGED
@@ -15,6 +15,7 @@ from types import NoneType, ModuleType
15
15
 
16
16
  from ripple_down_rules.datastructures.dataclasses import CaseFactoryMetaData
17
17
  from . import logger
18
+ from .failures import RDRLoadError
18
19
 
19
20
  try:
20
21
  from matplotlib import pyplot as plt
@@ -45,7 +46,7 @@ from .utils import draw_tree, make_set, SubclassJSONSerializer, make_list, get_t
45
46
  is_value_conflicting, extract_function_source, extract_imports, get_full_class_name, \
46
47
  is_iterable, str_to_snake_case, get_import_path_from_path, get_imports_from_types, render_tree, \
47
48
  get_types_to_import_from_func_type_hints, get_function_return_type, get_file_that_ends_with, \
48
- get_and_import_python_module, get_and_import_python_modules_in_a_package
49
+ get_and_import_python_module, get_and_import_python_modules_in_a_package, get_type_from_type_hint
49
50
 
50
51
 
51
52
  class RippleDownRules(SubclassJSONSerializer, ABC):
@@ -217,10 +218,10 @@ class RippleDownRules(SubclassJSONSerializer, ABC):
217
218
  if os.path.exists(json_file + ".json"):
218
219
  rdr = cls.from_json_file(json_file)
219
220
  try:
221
+ acronym = cls.get_acronym().lower()
222
+ python_file_name = get_file_that_ends_with(model_dir, f"_{acronym}.py")
223
+ python_file_path = os.path.join(model_dir, python_file_name)
220
224
  if rdr is None:
221
- acronym = cls.get_acronym().lower()
222
- python_file_name = get_file_that_ends_with(model_dir, f"_{acronym}.py")
223
- python_file_path = os.path.join(model_dir, python_file_name)
224
225
  rdr = cls.from_python(model_dir, parent_package_name=package_name, python_file_path=python_file_path)
225
226
  else:
226
227
  rdr.update_from_python(model_dir, package_name=package_name)
@@ -228,6 +229,8 @@ class RippleDownRules(SubclassJSONSerializer, ABC):
228
229
  except (FileNotFoundError, ValueError, SyntaxError, ModuleNotFoundError) as e:
229
230
  logger.warning(f"Could not load the python file for the model {model_name} from {model_dir}. "
230
231
  f"Make sure the file exists and is valid.")
232
+ if rdr is None:
233
+ raise RDRLoadError(f"Could not load the rdr model {model_name} from {model_dir}, error is {e}")
231
234
  rdr.save(save_dir=load_dir, model_name=model_name, package_name=package_name)
232
235
  rdr.save_dir = load_dir
233
236
  rdr.model_name = model_name
@@ -886,22 +889,52 @@ class RDRWithCodeWriter(RippleDownRules, ABC):
886
889
  self.update_rdr_metadata_from_python(main_module)
887
890
 
888
891
  functions_source = extract_function_source(defs_module.__file__,
889
- all_func_names, include_signature=False)
892
+ all_func_names, include_signature=True)
890
893
  scope = extract_imports(defs_module.__file__, package_name=package_name)
891
894
 
895
+ cases_source, cases_scope = None, None
896
+ if cases_module:
897
+ with open(cases_module.__file__, "r") as f:
898
+ cases_source = f.read()
899
+ cases_scope = extract_imports(cases_module.__file__, package_name=package_name)
900
+
901
+ with open(main_module.__file__, "r") as f:
902
+ main_source = f.read()
903
+ main_scope = extract_imports(main_module.__file__, package_name=package_name)
904
+ attribute_name_line = [l for l in main_source.split('\n') if "attribute_name = " in l]
905
+ conclusion_name = None
906
+ if len(attribute_name_line) > 0:
907
+ conclusion_name = eval(attribute_name_line[0].split('=')[-1].strip(), main_scope)
908
+
892
909
  for rule in all_rules:
893
910
  if rule.conditions is not None:
894
911
  conditions_wrapper_func_name = rule.generated_conditions_function_name
895
912
  user_input = functions_source[conditions_wrapper_func_name]
913
+ user_input = '\n'.join(user_input.split("\n")[1:]) # Remove the function signature line
896
914
  rule.conditions = CallableExpression(user_input, (bool,), scope=scope)
897
915
  if cases_module:
898
- rule.corner_case_metadata = cases_module.__dict__.get(rule.generated_corner_case_object_name, None)
916
+ try:
917
+ rule.corner_case_metadata = cases_module.__dict__[rule.generated_corner_case_object_name]
918
+ except KeyError:
919
+ case_def_lines = [l for l in cases_source.split('\n') if rule.generated_corner_case_object_name in l]
920
+ if len(case_def_lines) > 0:
921
+ case_def_line = case_def_lines[0].split('=')[-1].strip()
922
+ rule.corner_case_metadata = eval(case_def_line, cases_scope)
923
+
899
924
  if not isinstance(rule, MultiClassStopRule):
900
- rule.conclusion_name = main_module.attribute_name
901
- conclusion_wrapper_func_name = rule.generated_conclusion_function_name
902
- user_input = functions_source[conclusion_wrapper_func_name]
925
+ if conclusion_name:
926
+ rule.conclusion_name = conclusion_name
927
+ user_input = functions_source[rule.generated_conclusion_function_name]
928
+ split_user_input = user_input.split("\n")
929
+ user_input = '\n'.join(split_user_input[1:])
903
930
  conclusion_func = defs_module.__dict__.get(rule.generated_conclusion_function_name)
904
- conclusion_type = get_function_return_type(conclusion_func)
931
+ if conclusion_func is None:
932
+ function_signature = split_user_input[0]
933
+ return_type_hint_str = function_signature.split('->')[-1].strip(' :')
934
+ return_type_hint = eval(return_type_hint_str, scope)
935
+ conclusion_type = get_type_from_type_hint(return_type_hint)
936
+ else:
937
+ conclusion_type = get_function_return_type(conclusion_func)
905
938
  rule.conclusion = CallableExpression(user_input, conclusion_type, scope=scope,
906
939
  mutually_exclusive=self.mutually_exclusive)
907
940
 
@@ -213,9 +213,7 @@ class RDRDecorator:
213
213
  """
214
214
  self.rdr = None
215
215
  if self.model_name is not None:
216
- model_path = os.path.join(self.rdr_models_dir, self.model_name + f"/rdr_metadata/{self.model_name}.json")
217
- if os.path.exists(os.path.join(self.rdr_models_dir, model_path)):
218
- self.rdr = GeneralRDR.load(self.rdr_models_dir, self.model_name, package_name=self.package_name)
216
+ self.rdr = GeneralRDR.load(self.rdr_models_dir, self.model_name, package_name=self.package_name)
219
217
  if self.rdr is None:
220
218
  self.rdr = GeneralRDR(save_dir=self.rdr_models_dir, model_name=self.model_name)
221
219
 
@@ -168,20 +168,28 @@ def extract_imports(file_path: Optional[str] = None, tree: Optional[ast.AST] = N
168
168
  try:
169
169
  scope[asname] = importlib.import_module(module_name, package=package_name)
170
170
  except ImportError as e:
171
- print(f"Could not import {module_name}: {e}")
171
+ logger.warning(f"Could not import {module_name}: {e}")
172
172
  elif isinstance(node, ast.ImportFrom):
173
173
  module_name = node.module
174
174
  for alias in node.names:
175
175
  name = alias.name
176
176
  asname = alias.asname or name
177
177
  try:
178
+ if node.level > 0: # Handle relative imports
179
+ package_name = get_import_path_from_path(Path(os.path.join(file_path, *['..'] * node.level)).resolve())
178
180
  if package_name is not None and node.level > 0: # Handle relative imports
179
181
  module_rel_path = Path(os.path.join(file_path, *['..'] * node.level, module_name)).resolve()
180
182
  idx = str(module_rel_path).rfind(package_name)
181
183
  if idx != -1:
182
184
  module_name = str(module_rel_path)[idx:].replace(os.path.sep, '.')
183
- module = importlib.import_module(module_name, package=package_name)
184
- scope[asname] = getattr(module, name)
185
+ try:
186
+ module = importlib.import_module(module_name, package=package_name)
187
+ except ModuleNotFoundError:
188
+ module = importlib.import_module(f"{package_name}.{module_name}")
189
+ if name == "*":
190
+ scope.update(module.__dict__)
191
+ else:
192
+ scope[asname] = getattr(module, name)
185
193
  except (ImportError, AttributeError) as e:
186
194
  logger.warning(f"Could not import {module_name}: {e} while extracting imports from {file_path}")
187
195
 
@@ -782,10 +790,14 @@ def get_function_return_type(func: Callable) -> Union[Type, None, Tuple[Type, ..
782
790
  if sig.return_annotation == inspect.Signature.empty:
783
791
  return None
784
792
  type_hint = sig.return_annotation
793
+ return get_type_from_type_hint(type_hint)
794
+
795
+
796
+ def get_type_from_type_hint(type_hint: Type) -> Union[Type, Tuple[Type, ...]]:
785
797
  origin = get_origin(type_hint)
786
798
  args = get_args(type_hint)
787
799
  if origin not in [list, set, None, Union]:
788
- raise TypeError(f"{origin} is not a handled return type for function {func.__name__}")
800
+ raise TypeError(f"{origin} is not a handled return type for type hint {type_hint}")
789
801
  if origin is None:
790
802
  return typing_to_python_type(type_hint)
791
803
  if args is None or len(args) == 0:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ripple_down_rules
3
- Version: 0.6.44
3
+ Version: 0.6.46
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,11 +1,12 @@
1
- ripple_down_rules/__init__.py,sha256=2FQtTZmjBynmy8BB_EoLpB2rZDzN-dI7bKTktUl2mFw,99
1
+ ripple_down_rules/__init__.py,sha256=BK-q-yssQG0Y05Fkmc-Gm7xHrKf32lFrbtphnAm2XD8,99
2
2
  ripple_down_rules/experts.py,sha256=KXwWCmDrCffu9HW3yNewqWc1e5rnPI5Rnc981w_5M7U,17896
3
+ ripple_down_rules/failures.py,sha256=ZPypPwKjyVcJkY9YG6p538ld8ZzpdW6CrC1RmJi44Ek,42
3
4
  ripple_down_rules/helpers.py,sha256=X1psHOqrb4_xYN4ssQNB8S9aRKKsqgihAyWJurN0dqk,5499
4
- ripple_down_rules/rdr.py,sha256=wK6Altc7YNP9JR_mUrKignTkojq2kUy9L9g0g9_c7nM,81626
5
- ripple_down_rules/rdr_decorators.py,sha256=xoBGsIJMkJYUdsrsEaPZqoAsGuXkuVZAKCoP-xD2Iv8,11668
5
+ ripple_down_rules/rdr.py,sha256=Dq5bEuBuf3vct_I6Y3WmTtoTUzNsvHXNYvF5DFoKO14,83468
6
+ ripple_down_rules/rdr_decorators.py,sha256=ehK9YFYCh21fnbuzOX000yBwVDXL-QqYuEfKoWNYyDU,11468
6
7
  ripple_down_rules/rules.py,sha256=L4Ws-x3g5ljE0GrDt4LAib2qtR1C1_Ra4cRcIB-IQDI,28702
7
8
  ripple_down_rules/start-code-server.sh,sha256=otClk7VmDgBOX2TS_cjws6K0UwvgAUJhoA0ugkPCLqQ,949
8
- ripple_down_rules/utils.py,sha256=rZNjAyyuhqAuA7y9zs7R7u8WeSYifO07eUI8dV2Zg_Q,80138
9
+ ripple_down_rules/utils.py,sha256=5UL4h-m5Q4l7RyCYqmUmDDxUAkFqPYpFa3QldDYoJUE,80752
9
10
  ripple_down_rules/datastructures/__init__.py,sha256=V2aNgf5C96Y5-IGghra3n9uiefpoIm_QdT7cc_C8cxQ,111
10
11
  ripple_down_rules/datastructures/callable_expression.py,sha256=rzMrpD5oztaCRlt3hQ2B_xZ09cSuJNkYOCePndfQJRA,13684
11
12
  ripple_down_rules/datastructures/case.py,sha256=dfLnrjsHIVF2bgbz-4ID7OdQvw68V71btCeTK372P-g,15667
@@ -17,8 +18,8 @@ ripple_down_rules/user_interface/ipython_custom_shell.py,sha256=RLdPqPxx-a0Sh74U
17
18
  ripple_down_rules/user_interface/object_diagram.py,sha256=FEa2HaYR9QmTE6NsOwBvZ0jqmu3DKyg6mig2VE5ZP4Y,4956
18
19
  ripple_down_rules/user_interface/prompt.py,sha256=WPbw_8_-8SpF2ISyRZRuFwPKBEuGC4HaX3lbCPFHhh8,10314
19
20
  ripple_down_rules/user_interface/template_file_creator.py,sha256=uSbosZS15MOR3Nv7M3MrFuoiKXyP4cBId-EK3I6stHM,13660
20
- ripple_down_rules-0.6.44.dist-info/licenses/LICENSE,sha256=ixuiBLtpoK3iv89l7ylKkg9rs2GzF9ukPH7ynZYzK5s,35148
21
- ripple_down_rules-0.6.44.dist-info/METADATA,sha256=n5Vo5mABd5HAyUaX3zsbUmGwzSUDROYXnx9JvafVZl0,48294
22
- ripple_down_rules-0.6.44.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
23
- ripple_down_rules-0.6.44.dist-info/top_level.txt,sha256=VeoLhEhyK46M1OHwoPbCQLI1EifLjChqGzhQ6WEUqeM,18
24
- ripple_down_rules-0.6.44.dist-info/RECORD,,
21
+ ripple_down_rules-0.6.46.dist-info/licenses/LICENSE,sha256=ixuiBLtpoK3iv89l7ylKkg9rs2GzF9ukPH7ynZYzK5s,35148
22
+ ripple_down_rules-0.6.46.dist-info/METADATA,sha256=9BzQNnZOCR9GYOIM3DuKycWbsZzjyhRhFz22IVcUCOU,48294
23
+ ripple_down_rules-0.6.46.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
24
+ ripple_down_rules-0.6.46.dist-info/top_level.txt,sha256=VeoLhEhyK46M1OHwoPbCQLI1EifLjChqGzhQ6WEUqeM,18
25
+ ripple_down_rules-0.6.46.dist-info/RECORD,,