Skip to content

Commit 6ba08e9

Browse files
committed
fix breakage if no docstring present
make argspec introspection supersmart by being aware of e.g. "kw=os.environ", as per cgi.parse
1 parent a68a2b6 commit 6ba08e9

File tree

1 file changed

+69
-4
lines changed

1 file changed

+69
-4
lines changed

bpython/cli.py

Lines changed: 69 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,65 @@ def log(x):
7878
orig_stdout = sys.__stdout__
7979
stdscr = None
8080

81+
def parsekeywordpairs(signature):
82+
tokens = PythonLexer().get_tokens(signature)
83+
stack = []
84+
substack = []
85+
parendepth = 0
86+
begin = False
87+
for token, value in tokens:
88+
if not begin:
89+
if token is Token.Punctuation and value == u'(':
90+
begin = True
91+
continue
92+
93+
if token is Token.Punctuation:
94+
if value == u'(':
95+
parendepth += 1
96+
elif value == u')' and parendepth:
97+
parendepth -= 1
98+
99+
if parendepth:
100+
substack.append(value)
101+
continue
102+
103+
if ((token is Token.Punctuation and value == ')')
104+
or (token is Token.Punctuation and value == u',')
105+
and not parendepth):
106+
stack.append(substack[:])
107+
del substack[:]
108+
continue
109+
110+
if value and value.strip():
111+
substack.append(value)
112+
113+
d = {}
114+
for item in stack:
115+
if len(item) >= 3:
116+
d[item[0]] = ''.join(item[2:])
117+
return d
118+
119+
def fixlongargs(f, argspec):
120+
"""Functions taking default arguments that are references to other objects
121+
whose str() is too big will cause breakage, so we swap out the object
122+
itself with the name it was referenced with in the source by parsing the
123+
source itself !"""
124+
values = list(argspec[3])
125+
if not values:
126+
return
127+
keys = argspec[0][-len(values):]
128+
try:
129+
src = inspect.getsourcelines(f)
130+
except IOError:
131+
return
132+
signature = src[0][0]
133+
kwparsed = parsekeywordpairs(signature)
134+
135+
for i, (key, value) in enumerate(zip(keys, values)):
136+
if len(str(value)) != len(kwparsed[key]):
137+
values[i] = kwparsed[key]
138+
139+
argspec[3] = values
81140

82141
class FakeStdin(object):
83142
"""Provide a fake stdin type for things like raw_input() etc."""
@@ -183,6 +242,10 @@ def next_token_inside_string(s, inside_string):
183242
inside_string = False
184243
return inside_string
185244

245+
def clean_argspec(spec, f):
246+
"""Argspecs can contain eg.. "foo=os.environ", so display that as it is in
247+
the source as opposed to str(os.environ)"""
248+
186249

187250
class Interpreter(code.InteractiveInterpreter):
188251

@@ -509,6 +572,8 @@ def getargspec(func):
509572
else:
510573
argspec = inspect.getargspec(f)
511574
self.current_func = f
575+
argspec = list(argspec)
576+
fixlongargs(f, argspec)
512577
self.argspec = [func, argspec, is_bound_method]
513578
return True
514579

@@ -737,13 +802,13 @@ def lsize():
737802
else:
738803
docstring = self.format_docstring(self.docstring, max_w - 2)
739804
docstring_string = ''.join(docstring)
740-
rows = len(docstring) - 3
741-
self.list_win.resize(rows + 2, max_w)
805+
rows = len(docstring) - 1
806+
self.list_win.resize(rows + 3, max_w)
742807

743808
if down:
744-
self.list_win.mvwin(y+1, 0)
809+
self.list_win.mvwin(y + 1, 0)
745810
else:
746-
self.list_win.mvwin(y-rows-2, 0)
811+
self.list_win.mvwin(y - rows - 2, 0)
747812

748813
if v_items:
749814
self.list_win.addstr('\n ')

0 commit comments

Comments
 (0)