summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES3
-rw-r--r--sphinx/domains/javascript.py26
-rw-r--r--sphinx/domains/python.py68
3 files changed, 54 insertions, 43 deletions
diff --git a/CHANGES b/CHANGES
index 736359ce6..ea938f6a2 100644
--- a/CHANGES
+++ b/CHANGES
@@ -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.
diff --git a/sphinx/domains/javascript.py b/sphinx/domains/javascript.py
index 582e2adc6..98c7948c2 100644
--- a/sphinx/domains/javascript.py
+++ b/sphinx/domains/javascript.py
@@ -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
+ if not arglist:
+ 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):
diff --git a/sphinx/domains/python.py b/sphinx/domains/python.py
index cd87bfbda..cb34492f9 100644
--- a/sphinx/domains/python.py
+++ b/sphinx/domains/python.py
@@ -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