ripple-down-rules 0.1.3__py3-none-any.whl → 0.1.5__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 +2 -1
- ripple_down_rules/datastructures/__init__.py +4 -4
- ripple_down_rules/datastructures/callable_expression.py +68 -128
- ripple_down_rules/datastructures/case.py +1 -1
- ripple_down_rules/datastructures/dataclasses.py +102 -48
- ripple_down_rules/experts.py +24 -22
- ripple_down_rules/prompt.py +44 -50
- ripple_down_rules/rdr.py +290 -153
- ripple_down_rules/rules.py +64 -32
- ripple_down_rules/utils.py +91 -2
- {ripple_down_rules-0.1.3.dist-info → ripple_down_rules-0.1.5.dist-info}/METADATA +1 -1
- ripple_down_rules-0.1.5.dist-info/RECORD +20 -0
- {ripple_down_rules-0.1.3.dist-info → ripple_down_rules-0.1.5.dist-info}/WHEEL +1 -1
- ripple_down_rules-0.1.3.dist-info/RECORD +0 -20
- {ripple_down_rules-0.1.3.dist-info → ripple_down_rules-0.1.5.dist-info}/licenses/LICENSE +0 -0
- {ripple_down_rules-0.1.3.dist-info → ripple_down_rules-0.1.5.dist-info}/top_level.txt +0 -0
ripple_down_rules/prompt.py
CHANGED
@@ -2,16 +2,14 @@ import ast
|
|
2
2
|
import logging
|
3
3
|
from _ast import AST
|
4
4
|
|
5
|
-
from IPython.core.interactiveshell import ExecutionInfo
|
6
5
|
from IPython.terminal.embed import InteractiveShellEmbed
|
7
6
|
from traitlets.config import Config
|
8
|
-
from
|
9
|
-
from prompt_toolkit.completion import WordCompleter
|
10
|
-
from sqlalchemy.orm import DeclarativeBase as SQLTable, Session
|
11
|
-
from typing_extensions import Any, List, Optional, Tuple, Dict, Union, Type
|
7
|
+
from typing_extensions import List, Optional, Tuple, Dict
|
12
8
|
|
13
|
-
from .datastructures import
|
14
|
-
from .
|
9
|
+
from .datastructures.enums import PromptFor
|
10
|
+
from .datastructures.callable_expression import CallableExpression, parse_string_to_expression
|
11
|
+
from .datastructures.dataclasses import CaseQuery
|
12
|
+
from .utils import extract_dependencies, contains_return_statement
|
15
13
|
|
16
14
|
|
17
15
|
class CustomInteractiveShell(InteractiveShellEmbed):
|
@@ -29,7 +27,7 @@ class CustomInteractiveShell(InteractiveShellEmbed):
|
|
29
27
|
self.history_manager.store_inputs(line_num=self.execution_count, source=raw_cell)
|
30
28
|
self.ask_exit()
|
31
29
|
return None
|
32
|
-
result = super().run_cell(raw_cell,
|
30
|
+
result = super().run_cell(raw_cell, **kwargs)
|
33
31
|
if not result.error_in_exec:
|
34
32
|
self.all_lines.append(raw_cell)
|
35
33
|
return result
|
@@ -39,14 +37,14 @@ class IpythonShell:
|
|
39
37
|
"""
|
40
38
|
Create an embedded Ipython shell that can be used to prompt the user for input.
|
41
39
|
"""
|
42
|
-
|
40
|
+
|
41
|
+
def __init__(self, scope: Optional[Dict] = None, header: Optional[str] = None):
|
43
42
|
"""
|
44
43
|
Initialize the Ipython shell with the given scope and header.
|
45
44
|
|
46
45
|
:param scope: The scope to use for the shell.
|
47
46
|
:param header: The header to display when the shell is started.
|
48
47
|
"""
|
49
|
-
self.prompt_for: PromptFor = prompt_for
|
50
48
|
self.scope: Dict = scope or {}
|
51
49
|
self.header: str = header or ">>> Embedded Ipython Shell"
|
52
50
|
self.user_input: Optional[str] = None
|
@@ -66,26 +64,47 @@ class IpythonShell:
|
|
66
64
|
Run the embedded shell.
|
67
65
|
"""
|
68
66
|
self.shell()
|
69
|
-
self.
|
70
|
-
self.user_input = f"def _get_value(case):\n "
|
71
|
-
self.user_input += '\n '.join(self.all_code_lines)
|
72
|
-
|
67
|
+
self.update_user_input_from_code_lines()
|
73
68
|
|
74
|
-
def
|
75
|
-
|
69
|
+
def update_user_input_from_code_lines(self):
|
70
|
+
"""
|
71
|
+
Update the user input from the code lines captured in the shell.
|
72
|
+
"""
|
73
|
+
if len(self.shell.all_lines) == 1 and self.shell.all_lines[0].replace('return', '').strip() == '':
|
74
|
+
self.user_input = None
|
75
|
+
else:
|
76
|
+
self.all_code_lines = extract_dependencies(self.shell.all_lines)
|
77
|
+
if len(self.all_code_lines) == 1:
|
78
|
+
if self.all_code_lines[0].strip() == '':
|
79
|
+
self.user_input = None
|
80
|
+
else:
|
81
|
+
self.user_input = self.all_code_lines[0].replace('return', '').strip()
|
82
|
+
else:
|
83
|
+
self.user_input = f"def _get_value(case):\n "
|
84
|
+
self.user_input += '\n '.join(self.all_code_lines)
|
85
|
+
|
86
|
+
|
87
|
+
def prompt_user_for_expression(case_query: CaseQuery, prompt_for: PromptFor)\
|
88
|
+
-> Tuple[Optional[str], Optional[CallableExpression]]:
|
76
89
|
"""
|
77
90
|
Prompt the user for an executable python expression to the given case query.
|
78
91
|
|
79
92
|
:param case_query: The case query to prompt the user for.
|
80
93
|
:param prompt_for: The type of information ask user about.
|
81
|
-
:param session: The sqlalchemy orm session.
|
82
94
|
:return: A callable expression that takes a case and executes user expression on it.
|
83
95
|
"""
|
84
96
|
while True:
|
85
97
|
user_input, expression_tree = prompt_user_about_case(case_query, prompt_for)
|
98
|
+
if user_input is None:
|
99
|
+
if prompt_for == PromptFor.Conclusion:
|
100
|
+
print("No conclusion provided. Exiting.")
|
101
|
+
return None, None
|
102
|
+
else:
|
103
|
+
print("Conditions must be provided. Please try again.")
|
104
|
+
continue
|
86
105
|
conclusion_type = bool if prompt_for == PromptFor.Conditions else case_query.attribute_type
|
87
106
|
callable_expression = CallableExpression(user_input, conclusion_type, expression_tree=expression_tree,
|
88
|
-
scope=case_query.scope
|
107
|
+
scope=case_query.scope)
|
89
108
|
try:
|
90
109
|
callable_expression(case_query.case)
|
91
110
|
break
|
@@ -95,7 +114,7 @@ def prompt_user_for_expression(case_query: CaseQuery, prompt_for: PromptFor,
|
|
95
114
|
return user_input, callable_expression
|
96
115
|
|
97
116
|
|
98
|
-
def prompt_user_about_case(case_query: CaseQuery, prompt_for: PromptFor) -> Tuple[str, AST]:
|
117
|
+
def prompt_user_about_case(case_query: CaseQuery, prompt_for: PromptFor) -> Tuple[Optional[str], Optional[AST]]:
|
99
118
|
"""
|
100
119
|
Prompt the user for input.
|
101
120
|
|
@@ -105,27 +124,13 @@ def prompt_user_about_case(case_query: CaseQuery, prompt_for: PromptFor) -> Tupl
|
|
105
124
|
"""
|
106
125
|
prompt_str = f"Give {prompt_for} for {case_query.name}"
|
107
126
|
scope = {'case': case_query.case, **case_query.scope}
|
108
|
-
shell = IpythonShell(
|
109
|
-
|
110
|
-
return user_input, expression_tree
|
111
|
-
|
112
|
-
|
113
|
-
def get_completions(obj: Any) -> List[str]:
|
114
|
-
"""
|
115
|
-
Get all completions for the object. This is used in the python prompt shell to provide completions for the user.
|
116
|
-
|
117
|
-
:param obj: The object to get completions for.
|
118
|
-
:return: A list of completions.
|
119
|
-
"""
|
120
|
-
# Define completer with all object attributes and comparison operators
|
121
|
-
completions = ['==', '!=', '>', '<', '>=', '<=', 'in', 'not', 'and', 'or', 'is']
|
122
|
-
completions += ["isinstance(", "issubclass(", "type(", "len(", "hasattr(", "getattr(", "setattr(", "delattr("]
|
123
|
-
completions += list(create_case(obj).keys())
|
124
|
-
return completions
|
127
|
+
shell = IpythonShell(scope=scope, header=prompt_str)
|
128
|
+
return prompt_user_input_and_parse_to_expression(shell=shell)
|
125
129
|
|
126
130
|
|
127
131
|
def prompt_user_input_and_parse_to_expression(shell: Optional[IpythonShell] = None,
|
128
|
-
user_input: Optional[str] = None)
|
132
|
+
user_input: Optional[str] = None)\
|
133
|
+
-> Tuple[Optional[str], Optional[ast.AST]]:
|
129
134
|
"""
|
130
135
|
Prompt the user for input.
|
131
136
|
|
@@ -138,6 +143,8 @@ def prompt_user_input_and_parse_to_expression(shell: Optional[IpythonShell] = No
|
|
138
143
|
shell = IpythonShell() if shell is None else shell
|
139
144
|
shell.run()
|
140
145
|
user_input = shell.user_input
|
146
|
+
if user_input is None:
|
147
|
+
return None, None
|
141
148
|
print(user_input)
|
142
149
|
try:
|
143
150
|
return user_input, parse_string_to_expression(user_input)
|
@@ -145,16 +152,3 @@ def prompt_user_input_and_parse_to_expression(shell: Optional[IpythonShell] = No
|
|
145
152
|
msg = f"Error parsing expression: {e}"
|
146
153
|
logging.error(msg)
|
147
154
|
user_input = None
|
148
|
-
|
149
|
-
|
150
|
-
def get_prompt_session_for_obj(obj: Any) -> PromptSession:
|
151
|
-
"""
|
152
|
-
Get a prompt session for an object.
|
153
|
-
|
154
|
-
:param obj: The object to get the prompt session for.
|
155
|
-
:return: The prompt session.
|
156
|
-
"""
|
157
|
-
completions = get_completions(obj)
|
158
|
-
completer = WordCompleter(completions)
|
159
|
-
session = PromptSession(completer=completer)
|
160
|
-
return session
|