ripple-down-rules 0.2.3__py3-none-any.whl → 0.3.0__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/datasets.py +66 -6
- ripple_down_rules/datastructures/callable_expression.py +13 -3
- ripple_down_rules/datastructures/case.py +33 -5
- ripple_down_rules/datastructures/dataclasses.py +53 -9
- ripple_down_rules/datastructures/enums.py +30 -1
- ripple_down_rules/experts.py +2 -1
- ripple_down_rules/prompt.py +274 -118
- ripple_down_rules/rdr.py +7 -5
- ripple_down_rules/rdr_decorators.py +122 -38
- ripple_down_rules/utils.py +162 -18
- {ripple_down_rules-0.2.3.dist-info → ripple_down_rules-0.3.0.dist-info}/METADATA +1 -1
- ripple_down_rules-0.3.0.dist-info/RECORD +20 -0
- {ripple_down_rules-0.2.3.dist-info → ripple_down_rules-0.3.0.dist-info}/WHEEL +1 -1
- ripple_down_rules-0.2.3.dist-info/RECORD +0 -20
- {ripple_down_rules-0.2.3.dist-info → ripple_down_rules-0.3.0.dist-info}/licenses/LICENSE +0 -0
- {ripple_down_rules-0.2.3.dist-info → ripple_down_rules-0.3.0.dist-info}/top_level.txt +0 -0
@@ -5,51 +5,135 @@ of the RDRs.
|
|
5
5
|
"""
|
6
6
|
import os.path
|
7
7
|
from functools import wraps
|
8
|
-
from
|
8
|
+
from typing_extensions import Callable, Optional, Type, Tuple, Dict, Any, Self, get_type_hints, List, Union
|
9
9
|
|
10
|
-
from
|
11
|
-
from
|
12
|
-
|
13
|
-
from ripple_down_rules.datastructures import Case, Category, create_case, CaseQuery
|
10
|
+
from ripple_down_rules.datastructures.case import create_case
|
11
|
+
from ripple_down_rules.datastructures.dataclasses import CaseQuery
|
12
|
+
from ripple_down_rules.datastructures.enums import Category
|
14
13
|
from ripple_down_rules.experts import Expert, Human
|
14
|
+
from ripple_down_rules.rdr import GeneralRDR, RippleDownRules
|
15
|
+
from ripple_down_rules.utils import get_method_args_as_dict, get_func_rdr_model_name, make_set, \
|
16
|
+
get_method_class_if_exists
|
15
17
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
18
|
+
|
19
|
+
class RDRDecorator:
|
20
|
+
rdr: GeneralRDR
|
21
|
+
|
22
|
+
def __init__(self, models_dir: str,
|
23
|
+
output_type: Tuple[Type],
|
24
|
+
mutual_exclusive: bool,
|
25
|
+
python_dir: Optional[str] = None,
|
26
|
+
output_name: str = "output_",
|
27
|
+
fit: bool = True,
|
28
|
+
expert: Optional[Expert] = None):
|
29
|
+
"""
|
30
|
+
:param models_dir: The directory to save/load the RDR models.
|
31
|
+
:param output_type: The type of the output. This is used to create the RDR model.
|
32
|
+
:param mutual_exclusive: If True, the output types are mutually exclusive.
|
33
|
+
:param python_dir: The directory to save the RDR model as a python file.
|
34
|
+
If None, the RDR model will not be saved as a python file.
|
35
|
+
:param output_name: The name of the output. This is used to create the RDR model.
|
36
|
+
:param fit: If True, the function will be in fit mode. This means that the RDR will prompt the user for the
|
37
|
+
correct output if the function's output is not in the RDR model. If False, the function will be in
|
38
|
+
classification mode. This means that the RDR will classify the function's output based on the RDR model.
|
39
|
+
:param expert: The expert that will be used to prompt the user for the correct output. If None, a Human
|
40
|
+
expert will be used.
|
41
|
+
:return: A decorator to use a GeneralRDR as a classifier that monitors and modifies the function's output.
|
42
|
+
"""
|
43
|
+
self.rdr_models_dir = models_dir
|
44
|
+
self.output_type = output_type
|
45
|
+
self.parsed_output_type: List[Type] = []
|
46
|
+
self.mutual_exclusive = mutual_exclusive
|
47
|
+
self.rdr_python_path: Optional[str] = python_dir
|
48
|
+
self.output_name = output_name
|
49
|
+
self.fit: bool = fit
|
50
|
+
self.expert = expert if expert else Human()
|
51
|
+
self.rdr_model_path: Optional[str] = None
|
52
|
+
self.load()
|
53
|
+
|
54
|
+
def decorator(self, func: Callable) -> Callable:
|
39
55
|
|
40
56
|
@wraps(func)
|
41
|
-
def wrapper(*args, **kwargs) ->
|
57
|
+
def wrapper(*args, **kwargs) -> Optional[Any]:
|
58
|
+
if len(self.parsed_output_type) == 0:
|
59
|
+
self.parse_output_type(func, *args)
|
60
|
+
if self.rdr_model_path is None:
|
61
|
+
self.initialize_rdr_model_path_and_load(func)
|
42
62
|
case_dict = get_method_args_as_dict(func, *args, **kwargs)
|
43
63
|
func_output = func(*args, **kwargs)
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
64
|
+
case_dict.update({self.output_name: func_output})
|
65
|
+
case = create_case(case_dict, obj_name=get_func_rdr_model_name(func), max_recursion_idx=3)
|
66
|
+
if self.fit:
|
67
|
+
scope = func.__globals__
|
68
|
+
scope.update(case_dict)
|
69
|
+
func_args_type_hints = get_type_hints(func)
|
70
|
+
func_args_type_hints.update({self.output_name: Union[tuple(self.parsed_output_type)]})
|
71
|
+
case_query = CaseQuery(case, self.output_name, Union[tuple(self.parsed_output_type)],
|
72
|
+
self.mutual_exclusive,
|
73
|
+
scope=scope, is_function=True, function_args_type_hints=func_args_type_hints)
|
74
|
+
output = self.rdr.fit_case(case_query, expert=self.expert)
|
75
|
+
return output[self.output_name]
|
51
76
|
else:
|
52
|
-
return
|
77
|
+
return self.rdr.classify(case)[self.output_name]
|
78
|
+
|
53
79
|
return wrapper
|
54
80
|
|
55
|
-
|
81
|
+
def initialize_rdr_model_path_and_load(self, func: Callable) -> None:
|
82
|
+
model_file_name = get_func_rdr_model_name(func, include_file_name=True)
|
83
|
+
model_file_name = (''.join(['_' + c.lower() if c.isupper() else c for c in model_file_name]).lstrip('_')
|
84
|
+
.replace('__', '_') + ".json")
|
85
|
+
self.rdr_model_path = os.path.join(self.rdr_models_dir, model_file_name)
|
86
|
+
self.load()
|
87
|
+
|
88
|
+
def parse_output_type(self, func: Callable, *args) -> None:
|
89
|
+
for ot in make_set(self.output_type):
|
90
|
+
if ot is Self:
|
91
|
+
func_class = get_method_class_if_exists(func, *args)
|
92
|
+
if func_class is not None:
|
93
|
+
self.parsed_output_type.append(func_class)
|
94
|
+
else:
|
95
|
+
raise ValueError(f"The function {func} is not a method of a class,"
|
96
|
+
f" and the output type is {Self}.")
|
97
|
+
else:
|
98
|
+
self.parsed_output_type.append(ot)
|
99
|
+
|
100
|
+
def save(self):
|
101
|
+
"""
|
102
|
+
Save the RDR model to the specified directory.
|
103
|
+
"""
|
104
|
+
self.rdr.save(self.rdr_model_path)
|
105
|
+
|
106
|
+
if self.rdr_python_path is not None:
|
107
|
+
if not os.path.exists(self.rdr_python_path):
|
108
|
+
os.makedirs(self.rdr_python_path)
|
109
|
+
if not os.path.exists(os.path.join(self.rdr_python_path, "__init__.py")):
|
110
|
+
# add __init__.py file to the directory
|
111
|
+
with open(os.path.join(self.rdr_python_path, "__init__.py"), "w") as f:
|
112
|
+
f.write("# This is an empty __init__.py file to make the directory a package.")
|
113
|
+
# write the RDR model to a python file
|
114
|
+
self.rdr.write_to_python_file(self.rdr_python_path)
|
115
|
+
|
116
|
+
def load(self):
|
117
|
+
"""
|
118
|
+
Load the RDR model from the specified directory.
|
119
|
+
"""
|
120
|
+
if self.rdr_model_path is not None and os.path.exists(self.rdr_model_path):
|
121
|
+
self.rdr = GeneralRDR.load(self.rdr_model_path)
|
122
|
+
else:
|
123
|
+
self.rdr = GeneralRDR()
|
124
|
+
|
125
|
+
def write_to_python_file(self, package_dir: str, file_name_postfix: str = ""):
|
126
|
+
"""
|
127
|
+
Write the RDR model to a python file.
|
128
|
+
|
129
|
+
:param package_dir: The path to the directory to write the python file.
|
130
|
+
"""
|
131
|
+
self.rdr.write_to_python_file(package_dir, postfix=file_name_postfix)
|
132
|
+
|
133
|
+
def update_from_python_file(self, package_dir: str):
|
134
|
+
"""
|
135
|
+
Update the RDR model from a python file.
|
136
|
+
|
137
|
+
:param package_dir: The directory of the package that contains the generated python file.
|
138
|
+
"""
|
139
|
+
self.rdr.update_from_python_file(package_dir)
|
ripple_down_rules/utils.py
CHANGED
@@ -2,14 +2,16 @@ from __future__ import annotations
|
|
2
2
|
|
3
3
|
import ast
|
4
4
|
import builtins
|
5
|
+
import copyreg
|
5
6
|
import importlib
|
6
7
|
import json
|
7
8
|
import logging
|
8
9
|
import os
|
9
10
|
import re
|
11
|
+
import threading
|
10
12
|
import uuid
|
11
13
|
from collections import UserDict
|
12
|
-
from copy import deepcopy
|
14
|
+
from copy import deepcopy, copy
|
13
15
|
from dataclasses import is_dataclass, fields
|
14
16
|
from enum import Enum
|
15
17
|
from types import NoneType
|
@@ -26,14 +28,28 @@ from tabulate import tabulate
|
|
26
28
|
from typing_extensions import Callable, Set, Any, Type, Dict, TYPE_CHECKING, get_type_hints, \
|
27
29
|
get_origin, get_args, Tuple, Optional, List, Union, Self
|
28
30
|
|
31
|
+
|
29
32
|
if TYPE_CHECKING:
|
30
33
|
from .datastructures.case import Case
|
31
34
|
from .datastructures.dataclasses import CaseQuery
|
32
|
-
from .rules import Rule
|
33
35
|
|
34
36
|
import ast
|
35
37
|
|
36
|
-
|
38
|
+
|
39
|
+
def str_to_snake_case(snake_str: str) -> str:
|
40
|
+
"""
|
41
|
+
Convert a string to snake case.
|
42
|
+
|
43
|
+
:param snake_str: The string to convert.
|
44
|
+
:return: The converted string.
|
45
|
+
"""
|
46
|
+
s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', snake_str)
|
47
|
+
s1 = re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower()
|
48
|
+
# remove redundant underscores
|
49
|
+
s1 = re.sub(r'_{2,}', '_', s1)
|
50
|
+
# remove leading and trailing underscores
|
51
|
+
s1 = re.sub(r'^_|_$', '', s1)
|
52
|
+
return s1
|
37
53
|
|
38
54
|
|
39
55
|
def are_results_subclass_of_types(result_types: List[Any], types_: List[Type]) -> bool:
|
@@ -613,13 +629,76 @@ def get_func_rdr_model_path(func: Callable, model_dir: str) -> str:
|
|
613
629
|
:param model_dir: The directory to save the model to.
|
614
630
|
:return: The path to the model file.
|
615
631
|
"""
|
632
|
+
return os.path.join(model_dir, f"{get_func_rdr_model_name(func)}.json")
|
633
|
+
|
634
|
+
|
635
|
+
def get_func_rdr_model_name(func: Callable, include_file_name: bool = False) -> str:
|
636
|
+
"""
|
637
|
+
:param func: The function to get the model name for.
|
638
|
+
:return: The name of the model.
|
639
|
+
"""
|
616
640
|
func_name = get_method_name(func)
|
617
641
|
func_class_name = get_method_class_name_if_exists(func)
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
642
|
+
if include_file_name:
|
643
|
+
func_file_name = get_method_file_name(func).split(os.sep)[-1].split('.')[0]
|
644
|
+
model_name = func_file_name + '_'
|
645
|
+
else:
|
646
|
+
model_name = ''
|
647
|
+
model_name += f"{func_class_name}_" if func_class_name else ""
|
648
|
+
model_name += f"{func_name}"
|
649
|
+
return model_name
|
650
|
+
|
651
|
+
|
652
|
+
def extract_bracket_arguments(val: str) -> List[str]:
|
653
|
+
"""
|
654
|
+
Extract arguments inside brackets into a list.
|
655
|
+
|
656
|
+
:param val: The string containing brackets.
|
657
|
+
:return: List of arguments inside brackets.
|
658
|
+
"""
|
659
|
+
if '[' not in val:
|
660
|
+
return [val]
|
661
|
+
args_start = val.find('[')
|
662
|
+
args_end = val.rfind(']')
|
663
|
+
if args_end == -1:
|
664
|
+
return [val]
|
665
|
+
base_type = val[:args_start]
|
666
|
+
args = val[args_start + 1:args_end].split(',')
|
667
|
+
args = [arg.strip() for arg in args]
|
668
|
+
return [base_type] + args
|
669
|
+
|
670
|
+
|
671
|
+
def typing_hint_to_str(type_hint: Any) -> Tuple[str, List[str]]:
|
672
|
+
"""
|
673
|
+
Convert a typing hint to a string.
|
674
|
+
|
675
|
+
:param type_hint: The typing hint to convert.
|
676
|
+
:return: The string representation of the typing hint.
|
677
|
+
"""
|
678
|
+
val = (str(type_hint).strip("<>")
|
679
|
+
.replace("class ", "")
|
680
|
+
# .replace("typing.", "")
|
681
|
+
.replace("'", ""))
|
682
|
+
all_args = []
|
683
|
+
if '[' in val:
|
684
|
+
args = extract_bracket_arguments(val)
|
685
|
+
args_with_brackets = [arg for arg in args if '[' in arg]
|
686
|
+
all_args.extend([arg for arg in args if '[' not in arg])
|
687
|
+
while args_with_brackets:
|
688
|
+
for arg in args:
|
689
|
+
if '[' in arg:
|
690
|
+
sub_args = extract_bracket_arguments(arg)
|
691
|
+
args_with_brackets.remove(arg)
|
692
|
+
all_args.extend([sarg for sarg in sub_args if '[' not in sarg])
|
693
|
+
args_with_brackets.extend([sarg for sarg in sub_args if '[' in sarg])
|
694
|
+
elif arg not in all_args:
|
695
|
+
all_args.append(arg)
|
696
|
+
args = args_with_brackets
|
697
|
+
for arg in all_args:
|
698
|
+
val = val.replace(arg, arg.split('.')[-1])
|
699
|
+
else:
|
700
|
+
val = val.split('.')[-1]
|
701
|
+
return val, all_args
|
623
702
|
|
624
703
|
|
625
704
|
def get_method_args_as_dict(method: Callable, *args, **kwargs) -> Dict[str, Any]:
|
@@ -632,6 +711,8 @@ def get_method_args_as_dict(method: Callable, *args, **kwargs) -> Dict[str, Any]
|
|
632
711
|
:return: A dictionary of the arguments.
|
633
712
|
"""
|
634
713
|
func_arg_names = method.__code__.co_varnames
|
714
|
+
func_arg_names = list(map(lambda arg_name: f"{arg_name}_" if arg_name in ["self", "cls"] else arg_name,
|
715
|
+
func_arg_names))
|
635
716
|
func_arg_values = args + tuple(kwargs.values())
|
636
717
|
return dict(zip(func_arg_names, func_arg_values))
|
637
718
|
|
@@ -653,8 +734,27 @@ def get_method_class_name_if_exists(method: Callable) -> Optional[str]:
|
|
653
734
|
:param method: The method to get the class name of.
|
654
735
|
:return: The class name of the method.
|
655
736
|
"""
|
656
|
-
if hasattr(method, "__self__")
|
657
|
-
|
737
|
+
if hasattr(method, "__self__"):
|
738
|
+
if hasattr(method.__self__, "__class__"):
|
739
|
+
return method.__self__.__class__.__name__
|
740
|
+
return method.__qualname__.split('.')[0] if hasattr(method, "__qualname__") else None
|
741
|
+
|
742
|
+
|
743
|
+
def get_method_class_if_exists(method: Callable, *args) -> Optional[Type]:
|
744
|
+
"""
|
745
|
+
Get the class of a method if it has one.
|
746
|
+
|
747
|
+
:param method: The method to get the class of.
|
748
|
+
:return: The class of the method, if it exists otherwise None.
|
749
|
+
"""
|
750
|
+
if hasattr(method, "__self__"):
|
751
|
+
if hasattr(method.__self__, "__class__"):
|
752
|
+
return method.__self__.__class__
|
753
|
+
elif method.__code__.co_varnames:
|
754
|
+
if method.__code__.co_varnames[0] == 'self':
|
755
|
+
return args[0].__class__
|
756
|
+
elif method.__code__.co_varnames[0] == 'cls':
|
757
|
+
return args[0]
|
658
758
|
return None
|
659
759
|
|
660
760
|
|
@@ -839,7 +939,25 @@ class SubclassJSONSerializer:
|
|
839
939
|
load = from_json_file
|
840
940
|
|
841
941
|
|
842
|
-
def
|
942
|
+
def _pickle_thread(thread_obj) -> Any:
|
943
|
+
"""Return a plain object with user-defined attributes but no thread behavior."""
|
944
|
+
|
945
|
+
class DummyThread:
|
946
|
+
pass
|
947
|
+
|
948
|
+
dummy = DummyThread()
|
949
|
+
# Copy only non-thread-related attributes
|
950
|
+
for attr, value in thread_obj.__dict__.items():
|
951
|
+
print(attr)
|
952
|
+
if not attr.startswith("_"): # Skip internal Thread attributes
|
953
|
+
setattr(dummy, attr, value)
|
954
|
+
return dummy
|
955
|
+
|
956
|
+
|
957
|
+
copyreg.pickle(threading.Thread, _pickle_thread)
|
958
|
+
|
959
|
+
|
960
|
+
def copy_case(case: Union[Case, SQLTable]) -> Union[Case, SQLTable, Any]:
|
843
961
|
"""
|
844
962
|
Copy a case.
|
845
963
|
|
@@ -849,7 +967,18 @@ def copy_case(case: Union[Case, SQLTable]) -> Union[Case, SQLTable]:
|
|
849
967
|
if isinstance(case, SQLTable):
|
850
968
|
return copy_orm_instance_with_relationships(case)
|
851
969
|
else:
|
852
|
-
|
970
|
+
# copy the case recursively for 1 level
|
971
|
+
# try:
|
972
|
+
# case_copy = deepcopy(case)
|
973
|
+
# except Exception as e:
|
974
|
+
case_copy = copy(case)
|
975
|
+
for attr in dir(case):
|
976
|
+
if attr.startswith("_") or callable(getattr(case, attr)):
|
977
|
+
continue
|
978
|
+
attr_value = getattr(case, attr)
|
979
|
+
if is_iterable(attr_value):
|
980
|
+
setattr(case_copy, attr, copy(attr_value))
|
981
|
+
return case_copy
|
853
982
|
|
854
983
|
|
855
984
|
def copy_orm_instance(instance: SQLTable) -> SQLTable:
|
@@ -908,7 +1037,7 @@ def get_value_type_from_type_hint(attr_name: str, obj: Any) -> Type:
|
|
908
1037
|
return attr_value_type
|
909
1038
|
|
910
1039
|
|
911
|
-
def get_hint_for_attribute(attr_name: str, obj: Any) -> Tuple[Optional[
|
1040
|
+
def get_hint_for_attribute(attr_name: str, obj: Any) -> Tuple[Optional[Type], Optional[Type], Tuple[Type]]:
|
912
1041
|
"""
|
913
1042
|
Get the type hint for an attribute of an object.
|
914
1043
|
|
@@ -928,12 +1057,23 @@ def get_hint_for_attribute(attr_name: str, obj: Any) -> Tuple[Optional[Any], Opt
|
|
928
1057
|
hint = get_type_hints(obj.__class__)[attr_name]
|
929
1058
|
except KeyError:
|
930
1059
|
hint = type(class_attr)
|
931
|
-
origin =
|
932
|
-
|
1060
|
+
origin, args = get_origin_and_args_from_type_hint(hint)
|
1061
|
+
return origin, origin, args
|
1062
|
+
|
1063
|
+
|
1064
|
+
def get_origin_and_args_from_type_hint(type_hint: Type) -> Tuple[Optional[Type], Tuple[Type]]:
|
1065
|
+
"""
|
1066
|
+
Get the origin and arguments from a type hint.W
|
1067
|
+
|
1068
|
+
:param type_hint: The type hint to get the origin and arguments from.
|
1069
|
+
:return: The origin and arguments of the type hint.
|
1070
|
+
"""
|
1071
|
+
origin = get_origin(type_hint)
|
1072
|
+
args = get_args(type_hint)
|
933
1073
|
if origin is Mapped:
|
934
|
-
return
|
1074
|
+
return get_origin(args[0]), get_args(args[0])
|
935
1075
|
else:
|
936
|
-
return
|
1076
|
+
return origin, args
|
937
1077
|
|
938
1078
|
|
939
1079
|
def table_rows_as_str(row_dict: Dict[str, Any], columns_per_row: int = 9):
|
@@ -951,6 +1091,7 @@ def table_rows_as_str(row_dict: Dict[str, Any], columns_per_row: int = 9):
|
|
951
1091
|
all_table_rows = []
|
952
1092
|
for row_keys, row_values in zip(keys, values):
|
953
1093
|
row_values = [str(v) if v is not None else "" for v in row_values]
|
1094
|
+
row_values = [v.lower() if v in ["True", "False"] else v for v in row_values]
|
954
1095
|
table = tabulate([row_values], headers=row_keys, tablefmt='plain', maxcolwidths=[20] * len(row_keys))
|
955
1096
|
all_table_rows.append(table)
|
956
1097
|
return "\n".join(all_table_rows)
|
@@ -1100,7 +1241,7 @@ def get_all_subclasses(cls: Type) -> Dict[str, Type]:
|
|
1100
1241
|
return all_subclasses
|
1101
1242
|
|
1102
1243
|
|
1103
|
-
def make_set(value: Any) -> Set
|
1244
|
+
def make_set(value: Any) -> Set:
|
1104
1245
|
"""
|
1105
1246
|
Make a set from a value.
|
1106
1247
|
|
@@ -1205,6 +1346,9 @@ def draw_tree(root: Node, fig: plt.Figure):
|
|
1205
1346
|
"""
|
1206
1347
|
Draw the tree using matplotlib and networkx.
|
1207
1348
|
"""
|
1349
|
+
if matplotlib.get_backend().lower() not in ['qt5agg', 'qt4agg', 'qt6agg']:
|
1350
|
+
matplotlib.use("Qt5Agg") # or "Qt5Agg", depending on availability
|
1351
|
+
|
1208
1352
|
if root is None:
|
1209
1353
|
return
|
1210
1354
|
fig.clf()
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: ripple_down_rules
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.3.0
|
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
|
@@ -0,0 +1,20 @@
|
|
1
|
+
ripple_down_rules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
+
ripple_down_rules/datasets.py,sha256=zi5LVNA3oYUYL26HVUgOV8lKQ-wSmaJeOKHptdJ8A3E,6667
|
3
|
+
ripple_down_rules/experts.py,sha256=8wTInaKum38mH5r5esw7tXq_iL15-JP2tf5VIHHBmpw,6229
|
4
|
+
ripple_down_rules/failures.py,sha256=E6ajDUsw3Blom8eVLbA7d_Qnov2conhtZ0UmpQ9ZtSE,302
|
5
|
+
ripple_down_rules/helpers.py,sha256=TvTJU0BA3dPcAyzvZFvAu7jZqsp8Lu0HAAwvuizlGjg,2018
|
6
|
+
ripple_down_rules/prompt.py,sha256=KmlMRZRKqoyYIinp9l09LWL7e41DsqsGNcVbHRjebhg,23122
|
7
|
+
ripple_down_rules/rdr.py,sha256=7Ir3jYqAf2qZwi0Quz-ZMc3jreiSADo9xfAfLj2gbLM,43491
|
8
|
+
ripple_down_rules/rdr_decorators.py,sha256=VdmE0JrE8j89b6Af1R1tLZiKfy3h1VCvhAUefN_FLLQ,6753
|
9
|
+
ripple_down_rules/rules.py,sha256=QQy7NBG6mKiowxVG_LjQJBxLTDW2hMyx5zAgwUxdCMM,17183
|
10
|
+
ripple_down_rules/utils.py,sha256=SXNkIA9k75yKbfCAWQzq4XVxh3CpcxqSistnVFY3gBQ,48917
|
11
|
+
ripple_down_rules/datastructures/__init__.py,sha256=V2aNgf5C96Y5-IGghra3n9uiefpoIm_QdT7cc_C8cxQ,111
|
12
|
+
ripple_down_rules/datastructures/callable_expression.py,sha256=jA7424_mWPbOoPICW3eLMX0-ypxnsW6gOqxrJ7JpDbE,11610
|
13
|
+
ripple_down_rules/datastructures/case.py,sha256=oC8OSdhXvHE-Zx1IIQlad-fsKzQQqr6MZBW24c-dbeU,15191
|
14
|
+
ripple_down_rules/datastructures/dataclasses.py,sha256=GWnUF4h4zfNHSsyBIz3L9y8sLkrXRv0FK_OxzzLc8L8,8183
|
15
|
+
ripple_down_rules/datastructures/enums.py,sha256=sOEKvsmcFUnztScFOGmrxgrBNeIYHfV_CeQ5_Sj62so,5368
|
16
|
+
ripple_down_rules-0.3.0.dist-info/licenses/LICENSE,sha256=ixuiBLtpoK3iv89l7ylKkg9rs2GzF9ukPH7ynZYzK5s,35148
|
17
|
+
ripple_down_rules-0.3.0.dist-info/METADATA,sha256=f-xZg62otuqgnzlf4Bwzt0ns25WQLWl2RgIARt9v-tk,42576
|
18
|
+
ripple_down_rules-0.3.0.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
|
19
|
+
ripple_down_rules-0.3.0.dist-info/top_level.txt,sha256=VeoLhEhyK46M1OHwoPbCQLI1EifLjChqGzhQ6WEUqeM,18
|
20
|
+
ripple_down_rules-0.3.0.dist-info/RECORD,,
|
@@ -1,20 +0,0 @@
|
|
1
|
-
ripple_down_rules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
-
ripple_down_rules/datasets.py,sha256=mjJh1GLD_5qMgHaukdDWSGphXS9k_BPEF001ZXPchr8,4687
|
3
|
-
ripple_down_rules/experts.py,sha256=JGVvSNiWhm4FpRpg76f98tl8Ii_C7x_aWD9FxD-JDLQ,6130
|
4
|
-
ripple_down_rules/failures.py,sha256=E6ajDUsw3Blom8eVLbA7d_Qnov2conhtZ0UmpQ9ZtSE,302
|
5
|
-
ripple_down_rules/helpers.py,sha256=TvTJU0BA3dPcAyzvZFvAu7jZqsp8Lu0HAAwvuizlGjg,2018
|
6
|
-
ripple_down_rules/prompt.py,sha256=ReXnZ6OraFPqK5kDfAqH8d4SRPYiQ5d4ESk0js_MM9c,16150
|
7
|
-
ripple_down_rules/rdr.py,sha256=vxNZckp6sLAUD92JQgfCzhBhg9CXfMZ_7W4VgrIUFjU,43366
|
8
|
-
ripple_down_rules/rdr_decorators.py,sha256=8SclpceI3EtrsbuukWJu8HGLh7Q1ZCgYGLX-RPlG-w0,2018
|
9
|
-
ripple_down_rules/rules.py,sha256=QQy7NBG6mKiowxVG_LjQJBxLTDW2hMyx5zAgwUxdCMM,17183
|
10
|
-
ripple_down_rules/utils.py,sha256=EdVdIf93TAqbxRTzbf_1422FjenRSI4MI_Ecp3e10z8,44007
|
11
|
-
ripple_down_rules/datastructures/__init__.py,sha256=V2aNgf5C96Y5-IGghra3n9uiefpoIm_QdT7cc_C8cxQ,111
|
12
|
-
ripple_down_rules/datastructures/callable_expression.py,sha256=qVo8baEI_seeg6V23wmsctYdWj_tJJEOTkHeUc04Wvw,10912
|
13
|
-
ripple_down_rules/datastructures/case.py,sha256=nJDKOjyhGLx4gt0sHxJNxBLdy9X2SLcDn89_SmKzwoc,14035
|
14
|
-
ripple_down_rules/datastructures/dataclasses.py,sha256=BUr0T0CCh98sdsW2CVAXGk2oWqfemM7w1t91QKvg_KU,6171
|
15
|
-
ripple_down_rules/datastructures/enums.py,sha256=hlE6LAa1jUafnG_6UazvaPDfhC1ClI7hKvD89zOyAO8,4661
|
16
|
-
ripple_down_rules-0.2.3.dist-info/licenses/LICENSE,sha256=ixuiBLtpoK3iv89l7ylKkg9rs2GzF9ukPH7ynZYzK5s,35148
|
17
|
-
ripple_down_rules-0.2.3.dist-info/METADATA,sha256=58UZ0WaNhQOguD_oiFOrHkFWS-hydrMeA6nE3KbRT5Q,42576
|
18
|
-
ripple_down_rules-0.2.3.dist-info/WHEEL,sha256=0CuiUZ_p9E4cD6NyLD6UG80LBXYyiSYZOKDm5lp32xk,91
|
19
|
-
ripple_down_rules-0.2.3.dist-info/top_level.txt,sha256=VeoLhEhyK46M1OHwoPbCQLI1EifLjChqGzhQ6WEUqeM,18
|
20
|
-
ripple_down_rules-0.2.3.dist-info/RECORD,,
|
File without changes
|
File without changes
|