A class used to parse strings containing doctest examples. Note: This is a version modified to properly recognize IPython input and convert any IPython examples into valid Python ones.
| 334 | |
| 335 | |
| 336 | class IPDocTestParser(doctest.DocTestParser): |
| 337 | """ |
| 338 | A class used to parse strings containing doctest examples. |
| 339 | |
| 340 | Note: This is a version modified to properly recognize IPython input and |
| 341 | convert any IPython examples into valid Python ones. |
| 342 | """ |
| 343 | # This regular expression is used to find doctest examples in a |
| 344 | # string. It defines three groups: `source` is the source code |
| 345 | # (including leading indentation and prompts); `indent` is the |
| 346 | # indentation of the first (PS1) line of the source code; and |
| 347 | # `want` is the expected output (including leading indentation). |
| 348 | |
| 349 | # Classic Python prompts or default IPython ones |
| 350 | _PS1_PY = r'>>>' |
| 351 | _PS2_PY = r'\.\.\.' |
| 352 | |
| 353 | _PS1_IP = r'In\ \[\d+\]:' |
| 354 | _PS2_IP = r'\ \ \ \.\.\.+:' |
| 355 | |
| 356 | _RE_TPL = r''' |
| 357 | # Source consists of a PS1 line followed by zero or more PS2 lines. |
| 358 | (?P<source> |
| 359 | (?:^(?P<indent> [ ]*) (?P<ps1> %s) .*) # PS1 line |
| 360 | (?:\n [ ]* (?P<ps2> %s) .*)*) # PS2 lines |
| 361 | \n? # a newline |
| 362 | # Want consists of any non-blank lines that do not start with PS1. |
| 363 | (?P<want> (?:(?![ ]*$) # Not a blank line |
| 364 | (?![ ]*%s) # Not a line starting with PS1 |
| 365 | (?![ ]*%s) # Not a line starting with PS2 |
| 366 | .*$\n? # But any other line |
| 367 | )*) |
| 368 | ''' |
| 369 | |
| 370 | _EXAMPLE_RE_PY = re.compile( _RE_TPL % (_PS1_PY,_PS2_PY,_PS1_PY,_PS2_PY), |
| 371 | re.MULTILINE | re.VERBOSE) |
| 372 | |
| 373 | _EXAMPLE_RE_IP = re.compile( _RE_TPL % (_PS1_IP,_PS2_IP,_PS1_IP,_PS2_IP), |
| 374 | re.MULTILINE | re.VERBOSE) |
| 375 | |
| 376 | # Mark a test as being fully random. In this case, we simply append the |
| 377 | # random marker ('#random') to each individual example's output. This way |
| 378 | # we don't need to modify any other code. |
| 379 | _RANDOM_TEST = re.compile(r'#\s*all-random\s+') |
| 380 | |
| 381 | # Mark tests to be executed in an external process - currently unsupported. |
| 382 | _EXTERNAL_IP = re.compile(r'#\s*ipdoctest:\s*EXTERNAL') |
| 383 | |
| 384 | def ip2py(self,source): |
| 385 | """Convert input IPython source into valid Python.""" |
| 386 | block = _ip.input_transformer_manager.transform_cell(source) |
| 387 | if len(block.splitlines()) == 1: |
| 388 | return _ip.prefilter(block) |
| 389 | else: |
| 390 | return block |
| 391 | |
| 392 | def parse(self, string, name='<string>'): |
| 393 | """ |