ripple-down-rules 0.5.5__py3-none-any.whl → 0.5.8__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.
@@ -8,15 +8,20 @@ import json
8
8
  import logging
9
9
  import os
10
10
  import re
11
+ import sys
11
12
  import threading
12
13
  import uuid
13
- from collections import UserDict
14
+ from collections import UserDict, defaultdict
14
15
  from copy import deepcopy, copy
15
16
  from dataclasses import is_dataclass, fields
16
17
  from enum import Enum
18
+ from os.path import dirname
19
+ from pathlib import Path
17
20
  from textwrap import dedent
18
21
  from types import NoneType
19
- from typing import List
22
+
23
+ from sqlalchemy.exc import NoInspectionAvailable
24
+
20
25
 
21
26
  try:
22
27
  import matplotlib
@@ -41,8 +46,7 @@ from sqlalchemy import MetaData, inspect
41
46
  from sqlalchemy.orm import Mapped, registry, class_mapper, DeclarativeBase as SQLTable, Session
42
47
  from tabulate import tabulate
43
48
  from typing_extensions import Callable, Set, Any, Type, Dict, TYPE_CHECKING, get_type_hints, \
44
- get_origin, get_args, Tuple, Optional, List, Union, Self
45
-
49
+ get_origin, get_args, Tuple, Optional, List, Union, Self, ForwardRef, Sequence, Iterable
46
50
 
47
51
  if TYPE_CHECKING:
48
52
  from .datastructures.case import Case
@@ -81,7 +85,7 @@ def are_results_subclass_of_types(result_types: List[Any], types_: List[Type]) -
81
85
  return True
82
86
 
83
87
 
84
- def get_imports_from_types(types: List[Type]) -> List[str]:
88
+ def _get_imports_from_types(types: List[Type]) -> List[str]:
85
89
  """
86
90
  Get the import statements for a list of types.
87
91
 
@@ -114,13 +118,21 @@ def get_imports_from_scope(scope: Dict[str, Any]) -> List[str]:
114
118
  """
115
119
  imports = []
116
120
  for k, v in scope.items():
117
- if not hasattr(v, "__module__") or not hasattr(v, "__name__"):
121
+ if not hasattr(v, "__module__") or not hasattr(v, "__name__") or v.__module__ is None:
118
122
  continue
119
123
  imports.append(f"from {v.__module__} import {v.__name__}")
120
124
  return imports
121
125
 
122
126
 
123
- def extract_imports(file_path: Optional[str] = None, tree: Optional[ast.AST] = None) -> Dict[str, Any]:
127
+ def extract_imports(file_path: Optional[str] = None, tree: Optional[ast.AST] = None,
128
+ package_name: Optional[str] = None) -> Dict[str, Any]:
129
+ """
130
+ Extract imports from a Python file or an AST tree.
131
+
132
+ :param file_path: The path to the Python file to extract imports from.
133
+ :param tree: An AST tree to extract imports from. If provided, file_path is ignored.
134
+ :param package_name: The name of the package to use for relative imports.
135
+ """
124
136
  if tree is None:
125
137
  if file_path is None:
126
138
  raise ValueError("Either file_path or tree must be provided")
@@ -135,7 +147,7 @@ def extract_imports(file_path: Optional[str] = None, tree: Optional[ast.AST] = N
135
147
  module_name = alias.name
136
148
  asname = alias.asname or alias.name
137
149
  try:
138
- scope[asname] = importlib.import_module(module_name)
150
+ scope[asname] = importlib.import_module(module_name, package=package_name)
139
151
  except ImportError as e:
140
152
  print(f"Could not import {module_name}: {e}")
141
153
  elif isinstance(node, ast.ImportFrom):
@@ -144,7 +156,12 @@ def extract_imports(file_path: Optional[str] = None, tree: Optional[ast.AST] = N
144
156
  name = alias.name
145
157
  asname = alias.asname or name
146
158
  try:
147
- module = importlib.import_module(module_name)
159
+ if package_name is not None and node.level > 0: # Handle relative imports
160
+ module_rel_path = Path(os.path.join(file_path, *['..'] * node.level, module_name)).resolve()
161
+ idx = str(module_rel_path).rfind(package_name)
162
+ if idx != -1:
163
+ module_name = str(module_rel_path)[idx:].replace(os.path.sep, '.')
164
+ module = importlib.import_module(module_name, package=package_name)
148
165
  scope[asname] = getattr(module, name)
149
166
  except (ImportError, AttributeError) as e:
150
167
  logging.warning(f"Could not import {module_name}: {e} while extracting imports from {file_path}")
@@ -157,7 +174,7 @@ def extract_function_source(file_path: str,
157
174
  return_line_numbers: bool = False,
158
175
  include_signature: bool = True) \
159
176
  -> Union[Dict[str, Union[str, List[str]]],
160
- Tuple[Dict[str, Union[str, List[str]]], List[Tuple[int, int]]]]:
177
+ Tuple[Dict[str, Union[str, List[str]]], Dict[str, Tuple[int, int]]]]:
161
178
  """
162
179
  Extract the source code of a function from a file.
163
180
 
@@ -176,7 +193,7 @@ def extract_function_source(file_path: str,
176
193
  tree = ast.parse(source)
177
194
  function_names = make_list(function_names)
178
195
  functions_source: Dict[str, Union[str, List[str]]] = {}
179
- line_numbers = []
196
+ line_numbers: Dict[str, Tuple[int, int]] = {}
180
197
  for node in tree.body:
181
198
  if isinstance(node, ast.FunctionDef) and (node.name in function_names or len(function_names) == 0):
182
199
  # Get the line numbers of the function
@@ -184,7 +201,7 @@ def extract_function_source(file_path: str,
184
201
  func_lines = lines[node.lineno - 1:node.end_lineno]
185
202
  if not include_signature:
186
203
  func_lines = func_lines[1:]
187
- line_numbers.append((node.lineno, node.end_lineno))
204
+ line_numbers[node.name] = (node.lineno, node.end_lineno)
188
205
  functions_source[node.name] = dedent("\n".join(func_lines)) if join_lines else func_lines
189
206
  if (len(functions_source) >= len(function_names)) and (not len(function_names) == 0):
190
207
  break
@@ -496,16 +513,8 @@ def serialize_dataclass(obj: Any, seen=None) -> Any:
496
513
  value = getattr(obj, f.name)
497
514
  result['fields'][f.name] = serialize_dataclass(value, seen)
498
515
  return result
499
- elif isinstance(obj, list):
500
- return [serialize_dataclass(v, seen) for v in obj]
501
- elif isinstance(obj, dict):
502
- return {k: serialize_dataclass(v, seen) for k, v in obj.items()}
503
516
  else:
504
- try:
505
- json.dumps(obj) # Check if the object is JSON serializable
506
- return obj
507
- except TypeError:
508
- return None
517
+ return SubclassJSONSerializer.to_json_static(obj, seen)
509
518
 
510
519
 
511
520
  def deserialize_dataclass(data: Any, refs: Optional[Dict[str, Any]] = None) -> Any:
@@ -667,56 +676,257 @@ def get_func_rdr_model_name(func: Callable, include_file_name: bool = False) ->
667
676
  return model_name
668
677
 
669
678
 
670
- def extract_bracket_arguments(val: str) -> List[str]:
671
- """
672
- Extract arguments inside brackets into a list.
673
-
674
- :param val: The string containing brackets.
675
- :return: List of arguments inside brackets.
676
- """
677
- if '[' not in val:
678
- return [val]
679
- args_start = val.find('[')
680
- args_end = val.rfind(']')
681
- if args_end == -1:
682
- return [val]
683
- base_type = val[:args_start]
684
- args = val[args_start + 1:args_end].split(',')
685
- args = [arg.strip() for arg in args]
686
- return [base_type] + args
687
-
688
-
689
- def typing_hint_to_str(type_hint: Any) -> Tuple[str, List[str]]:
690
- """
691
- Convert a typing hint to a string.
692
-
693
- :param type_hint: The typing hint to convert.
694
- :return: The string representation of the typing hint.
695
- """
696
- val = (str(type_hint).strip("<>")
697
- .replace("class ", "")
698
- # .replace("typing.", "")
699
- .replace("'", ""))
700
- all_args = []
701
- if '[' in val:
702
- args = extract_bracket_arguments(val)
703
- args_with_brackets = [arg for arg in args if '[' in arg]
704
- all_args.extend([arg for arg in args if '[' not in arg])
705
- while args_with_brackets:
706
- for arg in args:
707
- if '[' in arg:
708
- sub_args = extract_bracket_arguments(arg)
709
- args_with_brackets.remove(arg)
710
- all_args.extend([sarg for sarg in sub_args if '[' not in sarg])
711
- args_with_brackets.extend([sarg for sarg in sub_args if '[' in sarg])
712
- elif arg not in all_args:
713
- all_args.append(arg)
714
- args = args_with_brackets
715
- for arg in all_args:
716
- val = val.replace(arg, arg.split('.')[-1])
679
+ def stringify_hint(tp):
680
+ """Recursively convert a type hint to a string."""
681
+ if isinstance(tp, str):
682
+ return tp
683
+
684
+ # Handle ForwardRef (string annotations not yet evaluated)
685
+ if isinstance(tp, ForwardRef):
686
+ return tp.__forward_arg__
687
+
688
+ # Handle typing generics like List[int], Dict[str, List[int]], etc.
689
+ origin = get_origin(tp)
690
+ args = get_args(tp)
691
+
692
+ if origin is not None:
693
+ origin_str = getattr(origin, '__name__', str(origin)).capitalize()
694
+ args_str = ", ".join(stringify_hint(arg) for arg in args)
695
+ return f"{origin_str}[{args_str}]"
696
+
697
+ # Handle built-in types like int, str, etc.
698
+ if isinstance(tp, type):
699
+ if tp.__module__ == 'builtins':
700
+ return tp.__name__
701
+ return f"{tp.__qualname__}"
702
+
703
+ return str(tp)
704
+
705
+
706
+ def is_builtin_type(tp):
707
+ return isinstance(tp, type) and tp.__module__ == "builtins"
708
+
709
+
710
+ def is_typing_type(tp):
711
+ return tp.__module__ == "typing"
712
+
713
+ origin_type_to_hint = {
714
+ list: List,
715
+ set: Set,
716
+ dict: Dict,
717
+ tuple: Tuple,
718
+ }
719
+
720
+ def extract_types(tp, seen: Set = None) -> Set[type]:
721
+ """Recursively extract all base types from a type hint."""
722
+ if seen is None:
723
+ seen = set()
724
+
725
+ if tp in seen or isinstance(tp, str):
726
+ return seen
727
+
728
+ # seen.add(tp)
729
+
730
+ if isinstance(tp, ForwardRef):
731
+ # Can't resolve until evaluated
732
+ return seen
733
+
734
+ origin = get_origin(tp)
735
+ args = get_args(tp)
736
+
737
+ if origin:
738
+ if origin in origin_type_to_hint:
739
+ seen.add(origin_type_to_hint[origin])
740
+ else:
741
+ seen.add(origin)
742
+ for arg in args:
743
+ extract_types(arg, seen)
744
+
745
+ elif isinstance(tp, type):
746
+ seen.add(tp)
747
+
748
+ return seen
749
+
750
+
751
+ def get_types_to_import_from_func_type_hints(func: Callable) -> Set[Type]:
752
+ """
753
+ Extract importable types from a function's annotations.
754
+
755
+ :param func: The function to extract type hints from.
756
+ """
757
+ hints = get_type_hints(func)
758
+
759
+ sig = inspect.signature(func)
760
+ all_hints = list(hints.values())
761
+ if sig.return_annotation != inspect.Signature.empty:
762
+ all_hints.append(sig.return_annotation)
763
+
764
+ for param in sig.parameters.values():
765
+ if param.annotation != inspect.Parameter.empty:
766
+ all_hints.append(param.annotation)
767
+
768
+ return get_types_to_import_from_type_hints(all_hints)
769
+
770
+
771
+ def get_types_to_import_from_type_hints(hints: List[Type]) -> Set[Type]:
772
+ """
773
+ Extract importable types from a list of type hints.
774
+
775
+ :param hints: A list of type hints to extract types from.
776
+ :return: A set of types that need to be imported.
777
+ """
778
+ seen_types = set()
779
+ for hint in hints:
780
+ extract_types(hint, seen_types)
781
+
782
+ # Filter out built-in and internal types
783
+ to_import = set()
784
+ for tp in seen_types:
785
+ if isinstance(tp, ForwardRef) or isinstance(tp, str):
786
+ continue
787
+ if not is_builtin_type(tp):
788
+ to_import.add(tp)
789
+
790
+ return to_import
791
+
792
+
793
+ def get_import_path_from_path(path: str) -> Optional[str]:
794
+ """
795
+ Convert a file system path to a Python import path.
796
+
797
+ :param path: The file system path to convert.
798
+ :return: The Python import path.
799
+ """
800
+ package_name = os.path.abspath(path)
801
+ formated_package_name = package_name.strip('./').replace('/', '.')
802
+ parent_package_idx = 0
803
+ packages = formated_package_name.split('.')
804
+ for i, possible_pacakge in enumerate(reversed(packages)):
805
+ if i == 0:
806
+ current_path = package_name
807
+ else:
808
+ current_path = '/' + '/'.join(packages[:-i])
809
+ if os.path.exists(os.path.join(current_path, '__init__.py')):
810
+ parent_package_idx -= 1
811
+ else:
812
+ break
813
+ package_name = '.'.join(packages[parent_package_idx:]) if parent_package_idx < 0 else None
814
+ return package_name
815
+
816
+
817
+ def get_function_import_data(func: Callable) -> Tuple[str, str]:
818
+ """
819
+ Get the import path of a function.
820
+
821
+ :param func: The function to get the import path for.
822
+ :return: The import path of the function.
823
+ """
824
+ func_name = get_method_name(func)
825
+ func_class_name = get_method_class_name_if_exists(func)
826
+ func_file_path = get_method_file_name(func)
827
+ func_file_name = func_file_path.split('/')[-1].split('.')[0] # Get the file name without extension
828
+ func_import_path = get_import_path_from_path(dirname(func_file_path))
829
+ func_import_path = f"{func_import_path}.{func_file_name}" if func_import_path else func_file_name
830
+ if func_class_name and func_class_name != func_name:
831
+ func_import_name = func_class_name
717
832
  else:
718
- val = val.split('.')[-1]
719
- return val, all_args
833
+ func_import_name = func_name
834
+ return func_import_path, func_import_name
835
+
836
+
837
+ def get_function_representation(func: Callable) -> str:
838
+ """
839
+ Get a string representation of a function, including its module and class if applicable.
840
+
841
+ :param func: The function to represent.
842
+ :return: A string representation of the function.
843
+ """
844
+ func_name = get_method_name(func)
845
+ func_class_name = get_method_class_name_if_exists(func)
846
+ if func_class_name and func_class_name != func_name:
847
+ return f"{func_class_name}.{func_name}"
848
+ return func_name
849
+
850
+
851
+ def get_relative_import(target_file_path, imported_module_path: Optional[str] = None,
852
+ module: Optional[str] = None) -> str:
853
+ """
854
+ Get a relative import path from the target file to the imported module.
855
+
856
+ :param target_file_path: The file path of the target file.
857
+ :param imported_module_path: The file path of the module being imported.
858
+ :param module: The module name, if available.
859
+ :return: A relative import path as a string.
860
+ """
861
+ # Convert to absolute paths
862
+ if module is not None:
863
+ imported_module_path = sys.modules[module].__file__
864
+ if imported_module_path is None:
865
+ raise ValueError("Either imported_module_path or module must be provided")
866
+ target_path = Path(target_file_path).resolve()
867
+ imported_path = Path(imported_module_path).resolve()
868
+
869
+ # Compute relative path from target to imported module
870
+ rel_path = os.path.relpath(imported_path.parent, target_path.parent)
871
+
872
+ # Convert path to Python import format
873
+ rel_parts = [part.replace('..', '.') for part in Path(rel_path).parts]
874
+ rel_parts = rel_parts if rel_parts else ['']
875
+
876
+ # Join the parts and add the module name
877
+ joined_parts = "".join(rel_parts) + f".{imported_path.stem}"
878
+ joined_parts = f".{joined_parts}" if not joined_parts.startswith(".") else joined_parts
879
+
880
+ return joined_parts
881
+
882
+
883
+ def get_imports_from_types(type_objs: Iterable[Type],
884
+ target_file_path: Optional[str] = None,
885
+ package_name: Optional[str] = None) -> List[str]:
886
+ """
887
+ Format import lines from type objects.
888
+
889
+ :param type_objs: A list of type objects to format.
890
+ :param target_file_path: The file path to which the imports should be relative.
891
+ :param package_name: The name of the package to use for relative imports.
892
+ """
893
+
894
+ module_to_types = defaultdict(list)
895
+ module_to_path = {}
896
+ other_imports = []
897
+ for tp in type_objs:
898
+ try:
899
+ if isinstance(tp, type) or is_typing_type(tp):
900
+ module = tp.__module__
901
+ file = getattr(tp, '__file__', None)
902
+ name = tp.__qualname__
903
+ elif callable(tp):
904
+ module, name = get_function_import_data(tp)
905
+ file = get_method_file_name(tp)
906
+ elif hasattr(type(tp), "__module__"):
907
+ module = type(tp).__module__
908
+ file = getattr(tp, '__file__', None)
909
+ name = type(tp).__qualname__
910
+ else:
911
+ continue
912
+ if module is None or module == 'builtins' or module.startswith('_'):
913
+ continue
914
+ module_to_types[module].append(name)
915
+ if file:
916
+ module_to_path[module] = file
917
+ except AttributeError:
918
+ continue
919
+
920
+ lines = []
921
+ for module, names in module_to_types.items():
922
+ joined = ", ".join(sorted(set(names)))
923
+ import_path = module
924
+ if (target_file_path is not None) and (package_name is not None) and (package_name in module):
925
+ import_path = get_relative_import(target_file_path, module=module)
926
+ lines.append(f"from {import_path} import {joined}")
927
+ if other_imports:
928
+ lines.extend(other_imports)
929
+ return sorted(lines)
720
930
 
721
931
 
722
932
  def get_method_args_as_dict(method: Callable, *args, **kwargs) -> Dict[str, Any]:
@@ -753,7 +963,9 @@ def get_method_class_name_if_exists(method: Callable) -> Optional[str]:
753
963
  :return: The class name of the method.
754
964
  """
755
965
  if hasattr(method, "__self__"):
756
- if hasattr(method.__self__, "__class__"):
966
+ if hasattr(method.__self__, "__name__"):
967
+ return method.__self__.__name__
968
+ elif hasattr(method.__self__, "__class__"):
757
969
  return method.__self__.__class__.__name__
758
970
  return method.__qualname__.split('.')[0] if hasattr(method, "__qualname__") else None
759
971
 
@@ -869,10 +1081,28 @@ class SubclassJSONSerializer:
869
1081
  return data
870
1082
 
871
1083
  @staticmethod
872
- def to_json_static(obj) -> Dict[str, Any]:
873
- if is_dataclass(obj):
874
- return serialize_dataclass(obj)
875
- return {"_type": get_full_class_name(obj.__class__), **obj._to_json()}
1084
+ def to_json_static(obj, seen=None) -> Any:
1085
+ if isinstance(obj, SubclassJSONSerializer):
1086
+ return {"_type": get_full_class_name(obj.__class__), **obj._to_json()}
1087
+ elif isinstance(obj, type):
1088
+ return {"_type": get_full_class_name(obj)}
1089
+ elif is_dataclass(obj):
1090
+ return serialize_dataclass(obj, seen)
1091
+ elif isinstance(obj, list):
1092
+ return [SubclassJSONSerializer.to_json_static(v, seen) for v in obj]
1093
+ elif isinstance(obj, dict):
1094
+ serialized_dict = {}
1095
+ for k, v in obj.items():
1096
+ if not isinstance(k, (str, int, bool, float, type(None))):
1097
+ continue
1098
+ serialized_dict[k] = SubclassJSONSerializer.to_json_static(v, seen)
1099
+ return serialized_dict
1100
+ else:
1101
+ try:
1102
+ json.dumps(obj) # Check if the object is JSON serializable
1103
+ return obj
1104
+ except TypeError:
1105
+ return None
876
1106
 
877
1107
  def to_json(self) -> Dict[str, Any]:
878
1108
  return self.to_json_static(self)
@@ -1008,13 +1238,20 @@ def copy_orm_instance(instance: SQLTable) -> SQLTable:
1008
1238
  :param instance: The instance to copy.
1009
1239
  :return: The copied instance.
1010
1240
  """
1011
- session: Session = inspect(instance).session
1241
+ try:
1242
+ session: Session = inspect(instance).session
1243
+ except NoInspectionAvailable:
1244
+ session = None
1012
1245
  if session is not None:
1013
1246
  session.expunge(instance)
1014
1247
  new_instance = deepcopy(instance)
1015
1248
  session.add(instance)
1016
1249
  else:
1017
- new_instance = instance
1250
+ try:
1251
+ new_instance = deepcopy(instance)
1252
+ except Exception as e:
1253
+ logging.debug(e)
1254
+ new_instance = instance
1018
1255
  return new_instance
1019
1256
 
1020
1257
 
@@ -1028,8 +1265,12 @@ def copy_orm_instance_with_relationships(instance: SQLTable) -> SQLTable:
1028
1265
  instance_cp = copy_orm_instance(instance)
1029
1266
  for rel in class_mapper(instance.__class__).relationships:
1030
1267
  related_obj = getattr(instance, rel.key)
1268
+ related_obj_cp = copy_orm_instance(related_obj)
1031
1269
  if related_obj is not None:
1032
- setattr(instance_cp, rel.key, related_obj)
1270
+ try:
1271
+ setattr(instance_cp, rel.key, related_obj_cp)
1272
+ except Exception as e:
1273
+ logging.debug(e)
1033
1274
  return instance_cp
1034
1275
 
1035
1276
 
@@ -1040,7 +1281,17 @@ def get_value_type_from_type_hint(attr_name: str, obj: Any) -> Type:
1040
1281
  :param attr_name: The name of the attribute.
1041
1282
  :param obj: The object to get the attributes from.
1042
1283
  """
1043
- hint, origin, args = get_hint_for_attribute(attr_name, obj)
1284
+ # check first if obj is a function object
1285
+ if hasattr(obj, '__code__'):
1286
+ func_type_hints = get_type_hints(obj)
1287
+ if attr_name in func_type_hints:
1288
+ hint = func_type_hints[attr_name]
1289
+ origin = get_origin(hint)
1290
+ args = get_args(hint)
1291
+ else:
1292
+ raise ValueError(f"Unknown type hint: {attr_name}")
1293
+ else:
1294
+ hint, origin, args = get_hint_for_attribute(attr_name, obj)
1044
1295
  if not origin and not hint:
1045
1296
  if hasattr(obj, attr_name):
1046
1297
  attr_value = getattr(obj, attr_name)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ripple_down_rules
3
- Version: 0.5.5
3
+ Version: 0.5.8
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
@@ -694,6 +694,7 @@ Requires-Dist: pygments
694
694
  Requires-Dist: sqlalchemy
695
695
  Requires-Dist: pandas
696
696
  Requires-Dist: pyparsing>=3.2.3
697
+ Requires-Dist: omegaconf
697
698
  Provides-Extra: viz
698
699
  Requires-Dist: networkx>=3.1; extra == "viz"
699
700
  Requires-Dist: matplotlib>=3.7.5; extra == "viz"
@@ -0,0 +1,24 @@
1
+ ripple_down_rules/__init__.py,sha256=cwOHhynJm6Y-t455Unt4AXAxXv4yPEGHMxCLjDfdT_o,99
2
+ ripple_down_rules/experts.py,sha256=bwozulI1rv0uyaMZQqEgapDO-s8wvW0D6Jqxmvu5fik,12610
3
+ ripple_down_rules/helpers.py,sha256=v4oE7C5PfQUVJfSUs1FfLHEwrJXEHJLn4vJhJMvyCR8,4453
4
+ ripple_down_rules/rdr.py,sha256=2t04Qj931dh6UypLBy4RxJ5hFIui0ejFgvm7D5P8b-E,55118
5
+ ripple_down_rules/rdr_decorators.py,sha256=0sk7izDB53lTKSB9fm33vQahmY_05FyCOWljyQOMB0U,9072
6
+ ripple_down_rules/rules.py,sha256=iVevv6iZ-6L2IPI0ZYbBjxBymXEQMmJGRFhiKUS-NmA,20352
7
+ ripple_down_rules/start-code-server.sh,sha256=otClk7VmDgBOX2TS_cjws6K0UwvgAUJhoA0ugkPCLqQ,949
8
+ ripple_down_rules/utils.py,sha256=mObBszTruGrRvD4MgD8tS1AnMtoyKrPl4RCciinhzY4,60132
9
+ ripple_down_rules/datastructures/__init__.py,sha256=V2aNgf5C96Y5-IGghra3n9uiefpoIm_QdT7cc_C8cxQ,111
10
+ ripple_down_rules/datastructures/callable_expression.py,sha256=f3wUPTrLa1INO-1qfgVz87ryrCABronfyq0_JKWoZCs,12800
11
+ ripple_down_rules/datastructures/case.py,sha256=1zSaXUljaH6z3SgMGzYPoDyjotNam791KpYgvxuMh90,15463
12
+ ripple_down_rules/datastructures/dataclasses.py,sha256=qoTFHV8Hi-X8VtfC9VdvH4tif73YjF3dUe8dyHXTYts,10993
13
+ ripple_down_rules/datastructures/enums.py,sha256=ce7tqS0otfSTNAOwsnXlhsvIn4iW_Y_N3TNebF3YoZs,5700
14
+ ripple_down_rules/user_interface/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
+ ripple_down_rules/user_interface/gui.py,sha256=_lgZAUXxxaBUFQJAHjA5TBPp6XEvJ62t-kSN8sPsocE,27379
16
+ ripple_down_rules/user_interface/ipython_custom_shell.py,sha256=Jrf7NxOdlrwGXH0Xyz3vzQprY-PNx9etfePOTpm2Gu8,6479
17
+ ripple_down_rules/user_interface/object_diagram.py,sha256=FEa2HaYR9QmTE6NsOwBvZ0jqmu3DKyg6mig2VE5ZP4Y,4956
18
+ ripple_down_rules/user_interface/prompt.py,sha256=AkkltdDIaioN43lkRKDPKSjJcmdSSGZDMYz7AL7X9lE,8082
19
+ ripple_down_rules/user_interface/template_file_creator.py,sha256=xWUt-RHRqrvoMo74o-bMLo8xNxil68wgbOZAMADZp2A,13570
20
+ ripple_down_rules-0.5.8.dist-info/licenses/LICENSE,sha256=ixuiBLtpoK3iv89l7ylKkg9rs2GzF9ukPH7ynZYzK5s,35148
21
+ ripple_down_rules-0.5.8.dist-info/METADATA,sha256=bY7Ex1Qpazl71BzyF1sfOdNB3Tny73pQRGBte2oareU,48213
22
+ ripple_down_rules-0.5.8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
23
+ ripple_down_rules-0.5.8.dist-info/top_level.txt,sha256=VeoLhEhyK46M1OHwoPbCQLI1EifLjChqGzhQ6WEUqeM,18
24
+ ripple_down_rules-0.5.8.dist-info/RECORD,,
@@ -1,24 +0,0 @@
1
- ripple_down_rules/__init__.py,sha256=OV_GxE_svT43w1V5gHpc0YaGCqmA-cm_U7P8UmX4Ox4,99
2
- ripple_down_rules/experts.py,sha256=rPRJU2py5wCopZADVWOP3Vzp077KL6ArDlkxUQ0Mh6w,12130
3
- ripple_down_rules/helpers.py,sha256=TvTJU0BA3dPcAyzvZFvAu7jZqsp8Lu0HAAwvuizlGjg,2018
4
- ripple_down_rules/rdr.py,sha256=FJYuRXgpUYSSK1pYrp2yeXb_ZZ2xjPED31tzxofokL4,48865
5
- ripple_down_rules/rdr_decorators.py,sha256=pYCKLgMKgQ6x_252WQtF2t4ZNjWPBxnaWtJ6TpGdcc0,7820
6
- ripple_down_rules/rules.py,sha256=TPNVMqW9T-_46BS4WemrspLg5uG8kP6tsPvWWBAzJxg,17515
7
- ripple_down_rules/start-code-server.sh,sha256=otClk7VmDgBOX2TS_cjws6K0UwvgAUJhoA0ugkPCLqQ,949
8
- ripple_down_rules/utils.py,sha256=4xQ5gmIeMsY-mA9g-4cedKt2WJq4oZAMs5XEKeplWPM,51127
9
- ripple_down_rules/datastructures/__init__.py,sha256=V2aNgf5C96Y5-IGghra3n9uiefpoIm_QdT7cc_C8cxQ,111
10
- ripple_down_rules/datastructures/callable_expression.py,sha256=D2KD1RdShzxYZPAERgywZ5ZPE4ar8WmMtXINqvYo_Tc,12497
11
- ripple_down_rules/datastructures/case.py,sha256=r8kjL9xP_wk84ThXusspgPMrAoed2bGQmKi54fzhmH8,15258
12
- ripple_down_rules/datastructures/dataclasses.py,sha256=PuD-7zWqWT2p4FnGvnihHvZlZKg9A1ctnFgVYf2cs-8,8554
13
- ripple_down_rules/datastructures/enums.py,sha256=ce7tqS0otfSTNAOwsnXlhsvIn4iW_Y_N3TNebF3YoZs,5700
14
- ripple_down_rules/user_interface/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
- ripple_down_rules/user_interface/gui.py,sha256=SB0gUhgReJ3yx-NEHRPMGVuNRLPRUwW8-qup-Kd4Cfo,27182
16
- ripple_down_rules/user_interface/ipython_custom_shell.py,sha256=24MIFwqnAhC6ofObEO6x5xRWRnyQmPpPmTvxbCKBrzM,6514
17
- ripple_down_rules/user_interface/object_diagram.py,sha256=tsB6iuLNEbHxp5lR2WjyejjWbnAX_nHF9xS8jNPOQVk,4548
18
- ripple_down_rules/user_interface/prompt.py,sha256=AkkltdDIaioN43lkRKDPKSjJcmdSSGZDMYz7AL7X9lE,8082
19
- ripple_down_rules/user_interface/template_file_creator.py,sha256=FGtLfYBfr4310c7Dfa9b2qiOWLNzHk1q3kdhD70Ilg4,13804
20
- ripple_down_rules-0.5.5.dist-info/licenses/LICENSE,sha256=ixuiBLtpoK3iv89l7ylKkg9rs2GzF9ukPH7ynZYzK5s,35148
21
- ripple_down_rules-0.5.5.dist-info/METADATA,sha256=irk6Cn48hjgyNiE9XyuRsSFP1svBynaDMTkN1ijbvRc,48188
22
- ripple_down_rules-0.5.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
23
- ripple_down_rules-0.5.5.dist-info/top_level.txt,sha256=VeoLhEhyK46M1OHwoPbCQLI1EifLjChqGzhQ6WEUqeM,18
24
- ripple_down_rules-0.5.5.dist-info/RECORD,,