mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
#507: Fix crash parsing Python argument lists containing brackets in string literals.
This commit is contained in:
parent
d1be56c93f
commit
a86d481925
3
CHANGES
3
CHANGES
@ -1,6 +1,9 @@
|
|||||||
Release 1.0.3 (in development)
|
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
|
* #501: Fix regression when building LaTeX docs with figures that
|
||||||
don't have captions.
|
don't have captions.
|
||||||
|
|
||||||
|
@ -13,8 +13,8 @@ from sphinx import addnodes
|
|||||||
from sphinx.domains import Domain, ObjType
|
from sphinx.domains import Domain, ObjType
|
||||||
from sphinx.locale import l_, _
|
from sphinx.locale import l_, _
|
||||||
from sphinx.directives import ObjectDescription
|
from sphinx.directives import ObjectDescription
|
||||||
from sphinx.domains.python import py_paramlist_re as js_paramlist_re
|
|
||||||
from sphinx.roles import XRefRole
|
from sphinx.roles import XRefRole
|
||||||
|
from sphinx.domains.python import _pseudo_parse_arglist
|
||||||
from sphinx.util.nodes import make_refnode
|
from sphinx.util.nodes import make_refnode
|
||||||
from sphinx.util.docfields import Field, GroupedField, TypedField
|
from sphinx.util.docfields import Field, GroupedField, TypedField
|
||||||
|
|
||||||
@ -68,28 +68,10 @@ class JSObject(ObjectDescription):
|
|||||||
signode += addnodes.desc_addname(nameprefix + '.', nameprefix + '.')
|
signode += addnodes.desc_addname(nameprefix + '.', nameprefix + '.')
|
||||||
signode += addnodes.desc_name(name, name)
|
signode += addnodes.desc_name(name, name)
|
||||||
if self.has_arguments:
|
if self.has_arguments:
|
||||||
signode += addnodes.desc_parameterlist()
|
|
||||||
if not arglist:
|
if not arglist:
|
||||||
return fullname, nameprefix
|
signode += addnodes.desc_parameterlist()
|
||||||
|
|
||||||
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
|
|
||||||
else:
|
else:
|
||||||
token = token.strip()
|
_pseudo_parse_arglist(signode, arglist)
|
||||||
stack[-1] += addnodes.desc_parameter(token, token)
|
|
||||||
if len(stack) != 1:
|
|
||||||
raise ValueError()
|
|
||||||
return fullname, nameprefix
|
return fullname, nameprefix
|
||||||
|
|
||||||
def add_target_and_index(self, name_obj, sig, signode):
|
def add_target_and_index(self, name_obj, sig, signode):
|
||||||
|
@ -33,7 +33,52 @@ py_sig_re = re.compile(
|
|||||||
)? $ # and nothing more
|
)? $ # and nothing more
|
||||||
''', re.VERBOSE)
|
''', 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):
|
class PyObject(ObjectDescription):
|
||||||
@ -142,26 +187,7 @@ class PyObject(ObjectDescription):
|
|||||||
if retann:
|
if retann:
|
||||||
signode += addnodes.desc_returns(retann, retann)
|
signode += addnodes.desc_returns(retann, retann)
|
||||||
return fullname, name_prefix
|
return fullname, name_prefix
|
||||||
signode += addnodes.desc_parameterlist()
|
_pseudo_parse_arglist(signode, arglist)
|
||||||
|
|
||||||
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
|
|
||||||
if retann:
|
if retann:
|
||||||
signode += addnodes.desc_returns(retann, retann)
|
signode += addnodes.desc_returns(retann, retann)
|
||||||
return fullname, name_prefix
|
return fullname, name_prefix
|
||||||
|
Loading…
Reference in New Issue
Block a user