#507: Fix crash parsing Python argument lists containing brackets in string literals.

This commit is contained in:
Georg Brandl 2010-08-23 15:20:22 +00:00
parent d1be56c93f
commit a86d481925
3 changed files with 54 additions and 43 deletions

View File

@ -1,6 +1,9 @@
Release 1.0.3 (in development)
==============================
* #507: Fix crash parsing Python argument lists containing brackets
in string literals.
* #501: Fix regression when building LaTeX docs with figures that
don't have captions.

View File

@ -13,8 +13,8 @@ from sphinx import addnodes
from sphinx.domains import Domain, ObjType
from sphinx.locale import l_, _
from sphinx.directives import ObjectDescription
from sphinx.domains.python import py_paramlist_re as js_paramlist_re
from sphinx.roles import XRefRole
from sphinx.domains.python import _pseudo_parse_arglist
from sphinx.util.nodes import make_refnode
from sphinx.util.docfields import Field, GroupedField, TypedField
@ -68,28 +68,10 @@ class JSObject(ObjectDescription):
signode += addnodes.desc_addname(nameprefix + '.', nameprefix + '.')
signode += addnodes.desc_name(name, name)
if self.has_arguments:
signode += addnodes.desc_parameterlist()
if not arglist:
return fullname, nameprefix
stack = [signode[-1]]
for token in js_paramlist_re.split(arglist):
if token == '[':
opt = addnodes.desc_optional()
stack[-1] += opt
stack.append(opt)
elif token == ']':
try:
stack.pop()
except IndexError:
raise ValueError()
elif not token or token == ',' or token.isspace():
pass
signode += addnodes.desc_parameterlist()
else:
token = token.strip()
stack[-1] += addnodes.desc_parameter(token, token)
if len(stack) != 1:
raise ValueError()
_pseudo_parse_arglist(signode, arglist)
return fullname, nameprefix
def add_target_and_index(self, name_obj, sig, signode):

View File

@ -33,7 +33,52 @@ py_sig_re = re.compile(
)? $ # and nothing more
''', re.VERBOSE)
py_paramlist_re = re.compile(r'([\[\],])') # split at '[', ']' and ','
def _pseudo_parse_arglist(signode, arglist):
""""Parse" a list of arguments separated by commas.
Arguments can have "optional" annotations given by enclosing them in
brackets. Currently, this will split at any comma, even if it's inside a
string literal (e.g. default argument value).
"""
paramlist = addnodes.desc_parameterlist()
stack = [paramlist]
try:
for argument in arglist.split(','):
argument = argument.strip()
ends_open = ends_close = 0
while argument.startswith('['):
stack.append(addnodes.desc_optional())
stack[-2] += stack[-1]
argument = argument[1:].strip()
while argument.startswith(']'):
stack.pop()
argument = argument[1:].strip()
while argument.endswith(']'):
ends_close += 1
argument = argument[:-1].strip()
while argument.endswith('['):
ends_open += 1
argument = argument[:-1].strip()
if argument:
stack[-1] += addnodes.desc_parameter(argument, argument)
while ends_open:
stack.append(addnodes.desc_optional())
stack[-2] += stack[-1]
ends_open -= 1
while ends_close:
stack.pop()
ends_close -= 1
if len(stack) != 1:
raise IndexError
except IndexError:
# if there are too few or too many elements on the stack, just give up
# and treat the whole argument list as one argument, discarding the
# already partially populated paramlist node
signode += addnodes.desc_parameterlist()
signode[-1] += addnodes.desc_parameter(arglist, arglist)
else:
signode += paramlist
class PyObject(ObjectDescription):
@ -142,26 +187,7 @@ class PyObject(ObjectDescription):
if retann:
signode += addnodes.desc_returns(retann, retann)
return fullname, name_prefix
signode += addnodes.desc_parameterlist()
stack = [signode[-1]]
for token in py_paramlist_re.split(arglist):
if token == '[':
opt = addnodes.desc_optional()
stack[-1] += opt
stack.append(opt)
elif token == ']':
try:
stack.pop()
except IndexError:
raise ValueError
elif not token or token == ',' or token.isspace():
pass
else:
token = token.strip()
stack[-1] += addnodes.desc_parameter(token, token)
if len(stack) != 1:
raise ValueError
_pseudo_parse_arglist(signode, arglist)
if retann:
signode += addnodes.desc_returns(retann, retann)
return fullname, name_prefix