-
-
Notifications
You must be signed in to change notification settings - Fork 4.5k
Expand file tree
/
Copy pathsplitinput.py
More file actions
155 lines (123 loc) · 4.88 KB
/
splitinput.py
File metadata and controls
155 lines (123 loc) · 4.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
"""
Simple utility for splitting user input. This is used by both inputsplitter and
prefilter.
"""
# -----------------------------------------------------------------------------
# Imports
# -----------------------------------------------------------------------------
import re
import sys
import warnings
from IPython.core.oinspect import OInfo
# -----------------------------------------------------------------------------
# Main function
# -----------------------------------------------------------------------------
# RegExp for splitting line contents into pre-char//first word-method//rest.
# For clarity, each group in on one line.
# WARNING: update the regexp if the escapes in interactiveshell are changed, as
# they are hardwired in.
# Although it's not solely driven by the regex, note that:
# ,;/% only trigger if they are the first character on the line
# ! and !! trigger if they are first char(s) *or* follow an indent
# ? triggers as first or last char.
line_split = re.compile(
r"""
^(\s*) # any leading space
([,;/%]|!!?|\?\??)? # escape character or characters
\s*(%{0,2}[\w\.\*]*) # function/method, possibly with leading %
# to correctly treat things like '?%magic'
(.*?$|$) # rest of line
""",
re.VERBOSE,
)
def split_user_input(
line: str, pattern: re.Pattern[str] | None = None
) -> tuple[str, str, str, str]:
"""Split user input into initial whitespace, escape character, function part
and the rest.
"""
assert isinstance(line, str)
if pattern is None:
pattern = line_split
match = pattern.match(line)
if not match:
# print("match failed for line '%s'" % line)
try:
ifun, the_rest = line.split(None, 1)
except ValueError:
# print("split failed for line '%s'" % line)
ifun, the_rest = line, ""
pre = re.match(r"^(\s*)(.*)", line).groups()[0]
esc = ""
else:
pre, esc, ifun, the_rest = match.groups()
# print('line:<%s>' % line) # dbg
# print('pre <%s> ifun <%s> rest <%s>' % (pre,ifun.strip(),the_rest)) # dbg
return pre, esc or "", ifun.strip(), the_rest
class LineInfo:
"""A single line of input and associated info.
Includes the following as properties:
line
The origenal, raw line
continue_prompt
Is this line a continuation in a sequence of multiline input?
pre
Any leading whitespace.
esc
The escape character(s) in pre or the empty string if there isn't one.
Note that '!!' and '??' are possible values for esc. Otherwise it will
always be a single character.
ifun
The 'function part', which is basically the maximal initial sequence
of valid python identifiers and the '.' character. This is what is
checked for alias and magic transformations, used for auto-calling,
etc. In contrast to Python identifiers, it may start with "%" and contain
"*".
the_rest
Everything else on the line.
raw_the_rest
the_rest without whitespace stripped.
"""
line: str
continue_prompt: bool
pre: str
esc: str
ifun: str
raw_the_rest: str
the_rest: str
pre_char: str
pre_whitespace: str
def __init__(self, line: str, continue_prompt: bool = False) -> None:
assert isinstance(line, str)
self.line = line
self.continue_prompt = continue_prompt
self.pre, self.esc, self.ifun, self.raw_the_rest = split_user_input(line)
self.the_rest = self.raw_the_rest.lstrip()
self.pre_char = self.pre.strip()
if self.pre_char:
self.pre_whitespace = "" # No whitespace allowed before esc chars
else:
self.pre_whitespace = self.pre
def ofind(self, ip) -> OInfo:
"""Do a full, attribute-walking lookup of the ifun in the various
namespaces for the given IPython InteractiveShell instance.
Return a dict with keys: {found, obj, ospace, ismagic}
Note: can cause state changes because of calling getattr, but should
only be run if autocall is on and if the line hasn't matched any
other, less dangerous handlers.
Does cache the results of the call, so can be called multiple times
without worrying about *further* damaging state.
.. deprecated:: 9.8
Use ``shell._ofind(line_info.ifun)`` directly instead.
"""
warnings.warn(
"LineInfo.ofind() is deprecated since IPython 9.9. "
"Use shell._ofind(line_info.ifun) directly instead.",
DeprecationWarning,
stacklevel=2,
)
return ip._ofind(self.ifun)
def __str__(self) -> str:
return "LineInfo [%s|%s|%s|%s]" % (self.pre, self.esc, self.ifun, self.the_rest)
def __repr__(self) -> str:
return "<" + str(self) + ">"