ripple-down-rules 0.5.93__py3-none-any.whl → 0.5.95__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.5.93"
1
+ __version__ = "0.5.95"
2
2
 
3
3
  import logging
4
4
  logger = logging.Logger("rdr")
@@ -36,7 +36,7 @@ def general_rdr_classify(classifiers_dict: Dict[str, Union[ModuleType, RippleDow
36
36
  new_conclusions = {}
37
37
  for attribute_name, rdr in classifiers_dict.items():
38
38
  pred_atts = rdr.classify(case_cp, case_query=case_query)
39
- if pred_atts is None:
39
+ if pred_atts is None and type(None) not in rdr.conclusion_type:
40
40
  continue
41
41
  if rdr.mutually_exclusive:
42
42
  if attribute_name not in conclusions or \
ripple_down_rules/rdr.py CHANGED
@@ -139,13 +139,15 @@ class RippleDownRules(SubclassJSONSerializer, ABC):
139
139
  model_dir = os.path.join(load_dir, model_name)
140
140
  json_file = os.path.join(model_dir, cls.metadata_folder, model_name)
141
141
  rdr = cls.from_json_file(json_file)
142
+ rdr.save_dir = load_dir
143
+ rdr.model_name = model_name
142
144
  try:
143
145
  rdr.update_from_python(model_dir, package_name=package_name)
146
+ rdr.to_json_file(json_file)
144
147
  except (FileNotFoundError, ValueError) as e:
145
148
  logger.warning(f"Could not load the python file for the model {model_name} from {model_dir}. "
146
149
  f"Make sure the file exists and is valid.")
147
- rdr.save_dir = load_dir
148
- rdr.model_name = model_name
150
+ rdr.save(save_dir=load_dir, model_name=model_name, package_name=package_name)
149
151
  return rdr
150
152
 
151
153
  @abstractmethod
@@ -296,7 +298,7 @@ class RippleDownRules(SubclassJSONSerializer, ABC):
296
298
  :param update_existing: Whether to update rules that gave the required type of conclusions.
297
299
  :return: True if the rdr should ask the expert, False otherwise.
298
300
  """
299
- if conclusions is None:
301
+ if conclusions is None and type(None) not in case_query.core_attribute_type:
300
302
  return True
301
303
  elif is_iterable(conclusions) and len(conclusions) == 0:
302
304
  return True
@@ -571,8 +573,9 @@ class RDRWithCodeWriter(RippleDownRules, ABC):
571
573
  :return: The type of the conclusion of the RDR classifier.
572
574
  """
573
575
  all_types = []
574
- for rule in [self.start_rule] + list(self.start_rule.descendants):
575
- all_types.extend(list(rule.conclusion.conclusion_type))
576
+ if self.start_rule is not None:
577
+ for rule in [self.start_rule] + list(self.start_rule.descendants):
578
+ all_types.extend(list(rule.conclusion.conclusion_type))
576
579
  return tuple(set(all_types))
577
580
 
578
581
  @property
@@ -120,7 +120,7 @@ class RDRDecorator:
120
120
  func_args_type_hints = get_type_hints(func)
121
121
  output_name = list(func_output.keys())[0]
122
122
  func_args_type_hints.update({output_name: Union[tuple(output_type)]})
123
- return CaseQuery(case, output_name, Union[tuple(output_type)],
123
+ return CaseQuery(case, output_name, tuple(output_type),
124
124
  mutual_exclusive, scope=scope,
125
125
  is_function=True, function_args_type_hints=func_args_type_hints)
126
126
 
@@ -128,7 +128,7 @@ class IPythonShell:
128
128
  break
129
129
  except Exception as e:
130
130
  logging.error(e)
131
- print(f"{Fore.RED}ERROR::{e}{Style.RESET_ALL}")
131
+ print(f"{Fore.RED}ERROR:: {e}{Style.RESET_ALL}")
132
132
 
133
133
  def update_user_input_from_code_lines(self):
134
134
  """
@@ -85,30 +85,6 @@ def are_results_subclass_of_types(result_types: List[Any], types_: List[Type]) -
85
85
  return True
86
86
 
87
87
 
88
- def _get_imports_from_types(types: List[Type]) -> List[str]:
89
- """
90
- Get the import statements for a list of types.
91
-
92
- :param types: The types to get the import statements for.
93
- :return: The import statements as a string.
94
- """
95
- imports = map(get_import_from_type, types)
96
- return list({i for i in imports if i is not None})
97
-
98
-
99
- def get_import_from_type(type_: Type) -> Optional[str]:
100
- """
101
- Get the import statement for a given type.
102
-
103
- :param type_: The type to get the import statement for.
104
- :return: The import statement as a string.
105
- """
106
- if hasattr(type_, "__module__") and hasattr(type_, "__name__"):
107
- if type_.__module__ == "builtins":
108
- return
109
- return f"from {type_.__module__} import {type_.__name__}"
110
-
111
-
112
88
  def get_imports_from_scope(scope: Dict[str, Any]) -> List[str]:
113
89
  """
114
90
  Get the imports from the given scope.
@@ -116,12 +92,7 @@ def get_imports_from_scope(scope: Dict[str, Any]) -> List[str]:
116
92
  :param scope: The scope to get the imports from.
117
93
  :return: The imports as a string.
118
94
  """
119
- imports = []
120
- for k, v in scope.items():
121
- if not hasattr(v, "__module__") or not hasattr(v, "__name__") or v.__module__ is None:
122
- continue
123
- imports.append(f"from {v.__module__} import {v.__name__}")
124
- return imports
95
+ return get_imports_from_types(list(scope.values()))
125
96
 
126
97
 
127
98
  def extract_imports(file_path: Optional[str] = None, tree: Optional[ast.AST] = None,
@@ -861,16 +832,18 @@ def get_relative_import(target_file_path, imported_module_path: Optional[str] =
861
832
  :return: A relative import path as a string.
862
833
  """
863
834
  # Convert to absolute paths
864
- target_path = Path(target_file_path).resolve()
865
- if package_name is not None:
866
- target_path = Path(get_path_starting_from_latest_encounter_of(str(target_path), package_name))
867
835
  if module is not None:
868
836
  imported_module_path = sys.modules[module].__file__
869
837
  if imported_module_path is None:
870
838
  raise ValueError("Either imported_module_path or module must be provided")
839
+ target_path = Path(target_file_path).resolve()
840
+ imported_file_name = Path(imported_module_path).name
841
+ target_file_name = Path(target_file_path).name
842
+ if package_name is not None:
843
+ target_path = Path(get_path_starting_from_latest_encounter_of(str(target_path), package_name, [target_file_name]))
871
844
  imported_path = Path(imported_module_path).resolve()
872
845
  if package_name is not None:
873
- imported_path = Path(get_path_starting_from_latest_encounter_of(str(imported_path), package_name))
846
+ imported_path = Path(get_path_starting_from_latest_encounter_of(str(imported_path), package_name, [imported_file_name]))
874
847
 
875
848
  # Compute relative path from target to imported module
876
849
  rel_path = os.path.relpath(imported_path.parent, target_path.parent)
@@ -879,28 +852,40 @@ def get_relative_import(target_file_path, imported_module_path: Optional[str] =
879
852
  rel_parts = [part.replace('..', '.') for part in Path(rel_path).parts]
880
853
  rel_parts = rel_parts if rel_parts else ['']
881
854
  dot_parts = [part for part in rel_parts if part == '.']
882
- non_dot_parts = [part for part in rel_parts if part != '.']
883
-
855
+ non_dot_parts = [part for part in rel_parts if part != '.'] + [imported_path.stem]
884
856
 
885
- # Join the parts and add the module name
886
- joined_parts = "".join(dot_parts) + ".".join(non_dot_parts) + f".{imported_path.stem}"
887
- joined_parts = f".{joined_parts}" if not joined_parts.startswith(".") else joined_parts
857
+ # Join the parts
858
+ joined_parts = "." + "".join(dot_parts) + ".".join(non_dot_parts)
888
859
 
889
860
  return joined_parts
890
861
 
891
862
 
892
- def get_path_starting_from_latest_encounter_of(path: str, package_name: str) -> Optional[str]:
863
+ def get_path_starting_from_latest_encounter_of(path: str, package_name: str, should_contain: List[str]) -> str:
893
864
  """
894
865
  Get the path starting from the package name.
895
866
 
896
867
  :param path: The full path to the file.
897
868
  :param package_name: The name of the package to start from.
898
- :return: The path starting from the package name or None if not found.
899
- """
900
- if package_name in path:
901
- idx = path.rfind(package_name)
902
- return path[idx:]
903
- return None
869
+ :param should_contain: The names of the files or directorys to look for.
870
+ :return: The path starting from the package name that contains all the names in should_contain, otherwise raise an error.
871
+ :raise ValueError: If the path does not contain all the names in should_contain.
872
+ """
873
+ path_parts = path.split(os.path.sep)
874
+ if package_name not in path_parts:
875
+ raise ValueError(f"Could not find {package_name} in {path}")
876
+ idx = path_parts.index(package_name)
877
+ prev_idx = idx
878
+ while all(sc in path_parts[idx:] for sc in should_contain):
879
+ prev_idx = idx
880
+ try:
881
+ idx = path_parts.index(package_name, idx + 1)
882
+ except ValueError:
883
+ break
884
+ if all(sc in path_parts[idx:] for sc in should_contain):
885
+ path_parts = path_parts[prev_idx:]
886
+ return os.path.join(*path_parts)
887
+ else:
888
+ raise ValueError(f"Could not find {should_contain} in {path}")
904
889
 
905
890
 
906
891
  def get_imports_from_types(type_objs: Iterable[Type],
@@ -937,6 +922,8 @@ def get_imports_from_types(type_objs: Iterable[Type],
937
922
  or module in sys.builtin_module_names or module in excluded_modules or "<" in module \
938
923
  or name in exclueded_names:
939
924
  continue
925
+ if module == "typing":
926
+ module = "typing_extensions"
940
927
  module_to_types[module].append(name)
941
928
  except AttributeError:
942
929
  continue
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ripple_down_rules
3
- Version: 0.5.93
3
+ Version: 0.5.95
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,11 @@
1
- ripple_down_rules/__init__.py,sha256=EtqjIUaQCKbMnjx_7lOMLEVv28R1aj1oXfdOI0j_TNY,100
1
+ ripple_down_rules/__init__.py,sha256=2YbCMVId4Rq_iPakA2uby2d6kRHClQ90FEJIWdgjG3c,100
2
2
  ripple_down_rules/experts.py,sha256=4-dMIVeMzFXCLYl_XBG_P7_Xs4sZih9-vZxCIPri6dA,12958
3
- ripple_down_rules/helpers.py,sha256=v4oE7C5PfQUVJfSUs1FfLHEwrJXEHJLn4vJhJMvyCR8,4453
4
- ripple_down_rules/rdr.py,sha256=C6bvlq6MsKa2Mym1wW6JUMj705aCaoihTP279TM6eT0,55218
5
- ripple_down_rules/rdr_decorators.py,sha256=pj7SwswB9UVdv4-c8pzcOsGTG0Elt7JEG6k65fsnOdk,9202
3
+ ripple_down_rules/helpers.py,sha256=sY8nFbYdLOO6EG5UQugCCxjSjcCQsDUCPgawfQA4Ui8,4495
4
+ ripple_down_rules/rdr.py,sha256=weOkaB2Z8PdudKJfSSdkCPYjk2o4Woduupg-_gHh2vU,55449
5
+ ripple_down_rules/rdr_decorators.py,sha256=riAFmL8jc1rw9dFkNbT023CfB5FbmOWHNiVKO2bAXsE,9195
6
6
  ripple_down_rules/rules.py,sha256=iVevv6iZ-6L2IPI0ZYbBjxBymXEQMmJGRFhiKUS-NmA,20352
7
7
  ripple_down_rules/start-code-server.sh,sha256=otClk7VmDgBOX2TS_cjws6K0UwvgAUJhoA0ugkPCLqQ,949
8
- ripple_down_rules/utils.py,sha256=3O6EZllEv3ixVsehIM0qHqGBCyI_Aju2h02XKNzGuYc,61970
8
+ ripple_down_rules/utils.py,sha256=IDVcKd4YGGvFzO1KaGIEk9u8xh13MrpsFM97VmvTfyw,61881
9
9
  ripple_down_rules/datastructures/__init__.py,sha256=V2aNgf5C96Y5-IGghra3n9uiefpoIm_QdT7cc_C8cxQ,111
10
10
  ripple_down_rules/datastructures/callable_expression.py,sha256=f3wUPTrLa1INO-1qfgVz87ryrCABronfyq0_JKWoZCs,12800
11
11
  ripple_down_rules/datastructures/case.py,sha256=PJ7_-AdxYic6BO5z816piFODj6nU5J6Jt1YzTFH-dds,15510
@@ -13,12 +13,12 @@ ripple_down_rules/datastructures/dataclasses.py,sha256=qoTFHV8Hi-X8VtfC9VdvH4tif
13
13
  ripple_down_rules/datastructures/enums.py,sha256=ce7tqS0otfSTNAOwsnXlhsvIn4iW_Y_N3TNebF3YoZs,5700
14
14
  ripple_down_rules/user_interface/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
15
  ripple_down_rules/user_interface/gui.py,sha256=_lgZAUXxxaBUFQJAHjA5TBPp6XEvJ62t-kSN8sPsocE,27379
16
- ripple_down_rules/user_interface/ipython_custom_shell.py,sha256=6v99tlNcfRyZpnPxq3FfqgFgxbJ5zkA2jVAXamTH1C0,6575
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
18
  ripple_down_rules/user_interface/prompt.py,sha256=JceEUGYsd0lIvd-v2y3D3swoo96_C0lxfp3CxM7Vfts,8900
19
19
  ripple_down_rules/user_interface/template_file_creator.py,sha256=kwBbFLyN6Yx2NTIHPSwOoytWgbJDYhgrUOVFw_jkDQ4,13522
20
- ripple_down_rules-0.5.93.dist-info/licenses/LICENSE,sha256=ixuiBLtpoK3iv89l7ylKkg9rs2GzF9ukPH7ynZYzK5s,35148
21
- ripple_down_rules-0.5.93.dist-info/METADATA,sha256=Dw4u_tSLdXa_okdhdVhFmbU26uCWEzg3z3WVAIFAShM,48214
22
- ripple_down_rules-0.5.93.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
23
- ripple_down_rules-0.5.93.dist-info/top_level.txt,sha256=VeoLhEhyK46M1OHwoPbCQLI1EifLjChqGzhQ6WEUqeM,18
24
- ripple_down_rules-0.5.93.dist-info/RECORD,,
20
+ ripple_down_rules-0.5.95.dist-info/licenses/LICENSE,sha256=ixuiBLtpoK3iv89l7ylKkg9rs2GzF9ukPH7ynZYzK5s,35148
21
+ ripple_down_rules-0.5.95.dist-info/METADATA,sha256=5sPvCDBc_3yV4wBp5f6YRDtQkmNrd1-d_Ce7ijm6NZ0,48214
22
+ ripple_down_rules-0.5.95.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
23
+ ripple_down_rules-0.5.95.dist-info/top_level.txt,sha256=VeoLhEhyK46M1OHwoPbCQLI1EifLjChqGzhQ6WEUqeM,18
24
+ ripple_down_rules-0.5.95.dist-info/RECORD,,