Skip to content

Commit 36a2f60

Browse files
committed
allow for csp nodes and graphs to be defined in repl
Signed-off-by: Tim Paine <[email protected]>
1 parent a357200 commit 36a2f60

File tree

1 file changed

+57
-1
lines changed

1 file changed

+57
-1
lines changed

Diff for: csp/impl/wiring/base_parser.py

+57-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import ast
22
import copy
33
import inspect
4+
import re
45
import sys
56
import textwrap
67
import typing
@@ -89,6 +90,55 @@ def wrapper(*args, **kwargs):
8990
return wrapper
9091

9192

93+
def _get_source_from_interpreter_function(raw_func):
94+
try:
95+
import readline
96+
except ImportError as exc:
97+
raise OSError(
98+
"Could not get source code for interpreter-defined function without `pyreadline` installed."
99+
) from exc
100+
101+
current_interpreter_history = readline.get_current_history_length()
102+
103+
try:
104+
search_pattern = re.compile(r"^(\s*def\s)")
105+
decorator_pattern = re.compile(r"^(\s*@)")
106+
func_name = raw_func.__name__
107+
code_object = raw_func.__func__ if inspect.ismethod(raw_func) else raw_func.__code__
108+
except Exception:
109+
raise OSError("Could not get source code for interpreter-defined function.")
110+
111+
if not hasattr(code_object, "co_firstlineno"):
112+
raise OSError("could not find function definition")
113+
114+
reassembled_function = ""
115+
starting_index_of_function = current_interpreter_history
116+
117+
# walk back through history to find the function definition
118+
while starting_index_of_function > 0:
119+
line = readline.get_history_item(starting_index_of_function)
120+
121+
# if its a def name_of_function(...
122+
if search_pattern.match(line):
123+
# reassemble function
124+
for i in range(starting_index_of_function, current_interpreter_history + 1):
125+
reassembled_function += f"{readline.get_history_item(i)}\n"
126+
127+
# go through to get decorators
128+
if func_name in line:
129+
for line_number_with_decorator in range(starting_index_of_function - 1, -1, -1):
130+
if decorator_pattern.match(readline.get_history_item(line_number_with_decorator)):
131+
reassembled_function = (
132+
f"{readline.get_history_item(line_number_with_decorator)}\n" + reassembled_function
133+
)
134+
print(reassembled_function)
135+
else:
136+
break
137+
break
138+
starting_index_of_function -= 1
139+
return reassembled_function
140+
141+
92142
class BaseParser(ast.NodeTransformer, metaclass=ABCMeta):
93143
_DEBUG_PARSE = False
94144

@@ -111,7 +161,13 @@ def __init__(self, name, raw_func, func_frame, debug_print=False, add_cache_cont
111161
self._func_globals_modified["csp"] = csp
112162
self._func_globals_modified.update(self._func_frame.f_globals)
113163

114-
source = textwrap.dedent(inspect.getsource(raw_func))
164+
if raw_func.__code__.co_filename == "<stdin>":
165+
raw_source = _get_source_from_interpreter_function(raw_func)
166+
else:
167+
raw_source = inspect.getsource(raw_func)
168+
169+
source = textwrap.dedent(raw_source)
170+
115171
body = ast.parse(source)
116172
self._funcdef = body.body[0]
117173
self._type_annotation_normalizer.normalize_type_annotations(self._funcdef)

0 commit comments

Comments
 (0)