[Zope3-checkins]
SVN: zope.testing/branches/benji-add-footnote-interpretation-to-doctest/src/zope/testing/doctest.py
- fix remaining bugs
Benji York
benji at zope.com
Sun Jul 9 23:25:56 EDT 2006
Log message for revision 69061:
- fix remaining bugs
- make footnote examples also executed in situ
Changed:
U zope.testing/branches/benji-add-footnote-interpretation-to-doctest/src/zope/testing/doctest.py
-=-
Modified: zope.testing/branches/benji-add-footnote-interpretation-to-doctest/src/zope/testing/doctest.py
===================================================================
--- zope.testing/branches/benji-add-footnote-interpretation-to-doctest/src/zope/testing/doctest.py 2006-07-09 19:20:44 UTC (rev 69060)
+++ zope.testing/branches/benji-add-footnote-interpretation-to-doctest/src/zope/testing/doctest.py 2006-07-10 03:25:54 UTC (rev 69061)
@@ -571,9 +571,11 @@
# Find footnote definitions.
_FOOTNOTE_DEFINITION_RE = re.compile(
- r'^\.\.\s*\[\s*([^\]]+)\s*\].*$',
- re.MULTILINE)
+ r'^\.\.\s*\[\s*([^\]]+)\s*\].*$', re.MULTILINE)
+ # End of footnote regex.
+ _FOOTNOTE_END_RE = re.compile(r'^\S+', re.MULTILINE)
+
def parse(self, string, name='<string>', optionflags=0):
"""
Divide the given string into examples and intervening text,
@@ -581,51 +583,6 @@
Line numbers for the Examples are 0-based. The optional
argument `name` is a name identifying this string, and is only
used for error messages.
-
- If the INTERPRET_FOOTNOTES flag is passed as part of optionflags, then
- footnotes will be looked up and their code injected at each point of
- reference. For example:
-
- >>> counter = 0
-
- Here is some text that references a footnote [1]_
-
- >>> counter
- 1
-
- .. [1] and here we set up the value
- >>> counter += 1
-
- Footnotes can also be referenced after they are defined: [1]_
-
- >>> counter
- 2
-
- Footnotes can also be "citations", which just means that the value in
- the brackets is alphanumeric: [citation]_
-
- >>> print from_citation
- hi
-
- .. [citation] this is a citation.
- >>> from_citation = 'hi'
-
- If a footnote isn't defined, it's just skipped: [not defined]_
-
- Footnotes can contain more than one example: [multi example]_
-
- >>> print one
- 1
- >>> print two
- 2
-
- .. [multi example] Here's a footnote with multiple examples:
-
- >>> one = 1
-
- And now another:
-
- >>> two = 2
"""
string = string.expandtabs()
# If all lines begin with the same indentation, then strip it.
@@ -661,21 +618,42 @@
new_output = []
footnotes = {}
- continue_again = False
+ in_footnote = False
for i, x in enumerate(output):
- if continue_again:
- continue_again = False
- continue
+ if in_footnote:
+ if isinstance(x, Example):
+ footnote.append(x)
+ elif self._FOOTNOTE_END_RE.search(x):
+ in_footnote = False
+ footnotes[name] = footnote
+ del name
+ del footnote
+ else:
+ footnote.append(x)
- if not isinstance(x, Example):
- match = self._FOOTNOTE_DEFINITION_RE.search(x)
- if match:
- name = match.group(1)
- if i+1 < len(output):
- footnotes[name] = output[i+1]
- continue_again = True
- continue
+ if not in_footnote:
+ s = x
+ if not isinstance(s, Example):
+ matches = list(
+ self._FOOTNOTE_DEFINITION_RE.finditer(s))
+ if matches:
+ # all but the last one don't have any associated
+ # code
+ for match in matches:
+ footnotes[match.group(1)] = []
+
+ match = matches[-1]
+ s = s[match.end()+1:]
+
+ if self._FOOTNOTE_END_RE.search(s):
+ # over before it began
+ continue
+
+ in_footnote = True
+ name = match.group(1)
+ footnote = []
+
new_output.append(x)
output = new_output
@@ -687,11 +665,11 @@
for m in self._FOOTNOTE_REFERENCE_RE.finditer(x):
name = m.group(1)
if name not in footnotes:
- # apparently this footnote doesn't have any code
- # in it, so skip
- continue
+ raise KeyError(
+ 'A footnote was referred to, but never'
+ ' defined: %r' % name)
- new_output.append(footnotes[name])
+ new_output.extend(footnotes[name])
new_output.append('') # keep the text/example balance
output = new_output
@@ -2840,6 +2818,94 @@
""",
}
+def _test_footnotes():
+ """
+ If the INTERPRET_FOOTNOTES flag is passed as part of optionflags, then
+ footnotes will be looked up and their code injected at each point of
+ reference. For example:
+
+ >>> counter = 0
+
+ Here is some text that references a footnote [1]_
+
+ >>> counter
+ 1
+
+ .. [1] and here we set up the value
+ >>> counter += 1
+
+ Footnotes can also be referenced after they are defined: [1]_
+
+ >>> counter
+ 3
+
+ Footnotes can also be "citations", which just means that the value in
+ the brackets is alphanumeric: [citation]_
+
+ >>> print from_citation
+ hi
+
+ .. [citation] this is a citation.
+ >>> from_citation = 'hi'
+
+ Footnotes can contain more than one example: [multi example]_
+
+ >>> print one
+ 1
+
+ >>> print two
+ 2
+
+ >>> print three
+ 3
+
+ .. [multi example] Here's a footnote with multiple examples:
+
+ >>> one = 1
+
+ And now another (note indentation to make this part of the
+ footnote):
+
+ >>> two = 2
+
+ even more:
+
+ >>> three = 3
+
+ Footnotes can have code that starts with no prose between. [quick code]_
+
+ .. [quick code] foo
+
+ >>> print 'this is some code'
+ this is some code
+
+ Footnotes can be back-to-back [first]_ [second]_
+ .. [first]
+ .. [second]
+ >>> 1+1
+ 2
+
+ .. [no code] Footnotes can also be defined with no code.
+
+ Footnotes can also refer to other footnotes [other]_
+
+ .. [other] This note refer to another one [1]_
+ >>> 'foo'
+ 'foo'
+
+ Or they can even refer to themselves [recursive]_
+
+ .. [recursive] this one refers to itself [recursive]_
+ >>> 'bar'
+ 'bar'
+
+ The last footnote works too
+
+ .. [last] This is the last one
+ >>> 'baz'
+ 'baz'
+ """
+
def _test():
r = unittest.TextTestRunner()
r.run(DocTestSuite(optionflags=INTERPRET_FOOTNOTES))
More information about the Zope3-Checkins
mailing list