Show More
@@ -86,11 +86,14 b' documentation.' | |||||
86 | Pseudo-Decorators |
|
86 | Pseudo-Decorators | |
87 | ================= |
|
87 | ================= | |
88 |
|
88 | |||
|
89 | Note: Only one decorator is supported per input. If more than one decorator | |||
|
90 | is specified, then only the last one is used. | |||
|
91 | ||||
89 | In addition to the Pseudo-Decorators/options described at the above link, |
|
92 | In addition to the Pseudo-Decorators/options described at the above link, | |
90 | several enhancements have been made. |
|
93 | several enhancements have been made. The directive will emit a message to the | |
91 | The directive will emit a message to the console at build-time if |
|
94 | console at build-time if code-execution resulted in an exception or warning. | |
92 | code-execution resulted in an exception or warning. You can suppress these on |
|
95 | You can suppress these on a per-block basis by specifying the :okexcept: | |
93 | a per-block basis by specifying the :okexcept: or :okwarning: options: |
|
96 | or :okwarning: options: | |
94 |
|
97 | |||
95 | .. code-block:: rst |
|
98 | .. code-block:: rst | |
96 |
|
99 | |||
@@ -203,8 +206,8 b' def block_parser(part, rgxin, rgxout, fmtin, fmtout):' | |||||
203 | continue |
|
206 | continue | |
204 |
|
207 | |||
205 | if line_stripped.startswith('@'): |
|
208 | if line_stripped.startswith('@'): | |
206 |
# |
|
209 | # Here is where we assume there is, at most, one decorator. | |
207 | # rethink |
|
210 | # Might need to rethink this. | |
208 | decorator = line_stripped |
|
211 | decorator = line_stripped | |
209 | continue |
|
212 | continue | |
210 |
|
213 | |||
@@ -442,16 +445,57 b' class EmbeddedSphinxShell(object):' | |||||
442 | ret.append(formatted_line) |
|
445 | ret.append(formatted_line) | |
443 |
|
446 | |||
444 | if not is_suppress and len(rest.strip()) and is_verbatim: |
|
447 | if not is_suppress and len(rest.strip()) and is_verbatim: | |
445 |
# |
|
448 | # The "rest" is the standard output of the input. | |
446 |
# |
|
449 | # This needs to be added, even in verbatim mode. | |
447 | # verbatim mode |
|
|||
448 | ret.append(rest) |
|
450 | ret.append(rest) | |
449 |
|
451 | |||
|
452 | # Fetch the processed output. (This is not the submitted output.) | |||
450 | self.cout.seek(0) |
|
453 | self.cout.seek(0) | |
451 | output = self.cout.read() |
|
454 | processed_output = self.cout.read() | |
452 | if not is_suppress and not is_semicolon: |
|
455 | if not is_suppress and not is_semicolon: | |
453 | ret.append(output) |
|
456 | # | |
454 | elif is_semicolon: # get spacing right |
|
457 | # In IPythonDirective.run, the elements of `ret` are eventually | |
|
458 | # combined such that '' entries correspond to newlines. So if | |||
|
459 | # `processed_output` is equal to '', then the adding it to `ret` | |||
|
460 | # ensures that there is a blank line between consecutive inputs | |||
|
461 | # that have no outputs, as in: | |||
|
462 | # | |||
|
463 | # In [1]: x = 4 | |||
|
464 | # | |||
|
465 | # In [2]: x = 5 | |||
|
466 | # | |||
|
467 | # When there is processed output, it has a '\n' at the tail end. So | |||
|
468 | # adding the output to `ret` will provide the necessary spacing | |||
|
469 | # between consecutive input/output blocks, as in: | |||
|
470 | # | |||
|
471 | # In [1]: x | |||
|
472 | # Out[1]: 5 | |||
|
473 | # | |||
|
474 | # In [2]: x | |||
|
475 | # Out[2]: 5 | |||
|
476 | # | |||
|
477 | # When there is stdout from the input, it also has a '\n' at the | |||
|
478 | # tail end, and so this ensures proper spacing as well. E.g.: | |||
|
479 | # | |||
|
480 | # In [1]: print x | |||
|
481 | # 5 | |||
|
482 | # | |||
|
483 | # In [2]: x = 5 | |||
|
484 | # | |||
|
485 | # When in verbatim mode, `processed_output` is empty (because | |||
|
486 | # nothing was passed to IP. Sometimes the submitted code block has | |||
|
487 | # an Out[] portion and sometimes it does not. When it does not, we | |||
|
488 | # need to ensure proper spacing, so we have to add '' to `ret`. | |||
|
489 | # However, if there is an Out[] in the submitted code, then we do | |||
|
490 | # not want to add a newline as `process_output` has stuff to add. | |||
|
491 | # The difficulty is that `process_input` doesn't know if | |||
|
492 | # `process_output` will be called---so it doesn't know if there is | |||
|
493 | # Out[] in the code block. The requires that we include a hack in | |||
|
494 | # `process_block`. See the comments there. | |||
|
495 | # | |||
|
496 | ret.append(processed_output) | |||
|
497 | elif is_semicolon: | |||
|
498 | # Make sure there is a newline after the semicolon. | |||
455 | ret.append('') |
|
499 | ret.append('') | |
456 |
|
500 | |||
457 | # context information |
|
501 | # context information | |
@@ -463,12 +507,12 b' class EmbeddedSphinxShell(object):' | |||||
463 |
|
507 | |||
464 | # output any exceptions raised during execution to stdout |
|
508 | # output any exceptions raised during execution to stdout | |
465 | # unless :okexcept: has been specified. |
|
509 | # unless :okexcept: has been specified. | |
466 | if not is_okexcept and "Traceback" in output: |
|
510 | if not is_okexcept and "Traceback" in processed_output: | |
467 | s = "\nException in %s at block ending on line %s\n" % (filename, lineno) |
|
511 | s = "\nException in %s at block ending on line %s\n" % (filename, lineno) | |
468 | s += "Specify :okexcept: as an option in the ipython:: block to suppress this message\n" |
|
512 | s += "Specify :okexcept: as an option in the ipython:: block to suppress this message\n" | |
469 | sys.stdout.write('\n\n>>>' + ('-' * 73)) |
|
513 | sys.stdout.write('\n\n>>>' + ('-' * 73)) | |
470 | sys.stdout.write(s) |
|
514 | sys.stdout.write(s) | |
471 | sys.stdout.write(output) |
|
515 | sys.stdout.write(processed_output) | |
472 | sys.stdout.write('<<<' + ('-' * 73) + '\n\n') |
|
516 | sys.stdout.write('<<<' + ('-' * 73) + '\n\n') | |
473 |
|
517 | |||
474 | # output any warning raised during execution to stdout |
|
518 | # output any warning raised during execution to stdout | |
@@ -486,21 +530,25 b' class EmbeddedSphinxShell(object):' | |||||
486 | sys.stdout.write('<<<' + ('-' * 73) + '\n') |
|
530 | sys.stdout.write('<<<' + ('-' * 73) + '\n') | |
487 |
|
531 | |||
488 | self.cout.truncate(0) |
|
532 | self.cout.truncate(0) | |
489 | return (ret, input_lines, output, is_doctest, decorator, image_file, |
|
533 | ||
490 | image_directive) |
|
534 | return (ret, input_lines, processed_output, | |
|
535 | is_doctest, decorator, image_file, image_directive) | |||
491 |
|
536 | |||
492 |
|
537 | |||
493 | def process_output(self, data, output_prompt, |
|
538 | def process_output(self, data, output_prompt, input_lines, output, | |
494 |
|
|
539 | is_doctest, decorator, image_file): | |
495 | """ |
|
540 | """ | |
496 | Process data block for OUTPUT token. |
|
541 | Process data block for OUTPUT token. | |
497 |
|
542 | |||
498 | """ |
|
543 | """ | |
|
544 | # Recall: `data` is the submitted output, and `output` is the processed | |||
|
545 | # output from `input_lines`. | |||
|
546 | ||||
499 | TAB = ' ' * 4 |
|
547 | TAB = ' ' * 4 | |
500 |
|
548 | |||
501 | if is_doctest and output is not None: |
|
549 | if is_doctest and output is not None: | |
502 |
|
550 | |||
503 | found = output |
|
551 | found = output # This is the processed output | |
504 | found = found.strip() |
|
552 | found = found.strip() | |
505 | submitted = data.strip() |
|
553 | submitted = data.strip() | |
506 |
|
554 | |||
@@ -542,13 +590,28 b' class EmbeddedSphinxShell(object):' | |||||
542 | else: |
|
590 | else: | |
543 | self.custom_doctest(decorator, input_lines, found, submitted) |
|
591 | self.custom_doctest(decorator, input_lines, found, submitted) | |
544 |
|
592 | |||
545 | # Make sure output is processed when in verbatim mode. |
|
593 | # When in verbatim mode, this holds additional submitted output | |
|
594 | # to be written in the final Sphinx output. | |||
546 | # https://github.com/ipython/ipython/issues/5776 |
|
595 | # https://github.com/ipython/ipython/issues/5776 | |
|
596 | out_data = [] | |||
|
597 | ||||
547 | is_verbatim = decorator=='@verbatim' or self.is_verbatim |
|
598 | is_verbatim = decorator=='@verbatim' or self.is_verbatim | |
548 | if is_verbatim: |
|
599 | if is_verbatim and data.strip(): | |
549 | out_data = data |
|
600 | # Note that `ret` in `process_block` has '' as its last element if | |
550 | else: |
|
601 | # the code block was in verbatim mode. So if there is no submitted | |
551 | out_data = None |
|
602 | # output, then we will have proper spacing only if we do not add | |
|
603 | # an additional '' to `out_data`. This is why we condition on | |||
|
604 | # `and data.strip()`. | |||
|
605 | ||||
|
606 | # The submitted output has no output prompt. If we want the | |||
|
607 | # prompt and the code to appear, we need to join them now | |||
|
608 | # instead of adding them separately---as this would create an | |||
|
609 | # undesired newline. How we do this ultimately depends on the | |||
|
610 | # format of the output regex. I'll do what works for the default | |||
|
611 | # prompt for now, and we might have to adjust if it doesn't work | |||
|
612 | # in other cases. Finally, the submitted output does not have | |||
|
613 | # a trailing newline, so we must add it manually. | |||
|
614 | out_data.append("{0} {1}\n".format(output_prompt, data)) | |||
552 |
|
615 | |||
553 | return out_data |
|
616 | return out_data | |
554 |
|
617 | |||
@@ -589,14 +652,22 b' class EmbeddedSphinxShell(object):' | |||||
589 | if token == COMMENT: |
|
652 | if token == COMMENT: | |
590 | out_data = self.process_comment(data) |
|
653 | out_data = self.process_comment(data) | |
591 | elif token == INPUT: |
|
654 | elif token == INPUT: | |
592 |
(out_data, input_lines, output, is_doctest, |
|
655 | (out_data, input_lines, output, is_doctest, | |
593 |
|
|
656 | decorator, image_file, image_directive) = \ | |
594 | self.process_input(data, input_prompt, lineno) |
|
657 | self.process_input(data, input_prompt, lineno) | |
595 | elif token == OUTPUT: |
|
658 | elif token == OUTPUT: | |
596 | out_data = \ |
|
659 | out_data = \ | |
597 | self.process_output(data, output_prompt, |
|
660 | self.process_output(data, output_prompt, input_lines, | |
598 |
|
|
661 | output, is_doctest, decorator, | |
599 |
|
|
662 | image_file) | |
|
663 | if out_data: | |||
|
664 | # Then there was user submitted output in verbatim mode. | |||
|
665 | # We need to remove the last element of `ret` that was | |||
|
666 | # added in `process_input`, as it is '' and would introduce | |||
|
667 | # an undesirable newline. | |||
|
668 | assert(ret[-1] == '') | |||
|
669 | del ret[-1] | |||
|
670 | ||||
600 | if out_data: |
|
671 | if out_data: | |
601 | ret.extend(out_data) |
|
672 | ret.extend(out_data) | |
602 |
|
673 | |||
@@ -853,7 +924,8 b' class IPythonDirective(Directive):' | |||||
853 | if len(block): |
|
924 | if len(block): | |
854 | rows, figure = self.shell.process_block(block) |
|
925 | rows, figure = self.shell.process_block(block) | |
855 | for row in rows: |
|
926 | for row in rows: | |
856 |
lines.extend([' |
|
927 | lines.extend([' {0}'.format(line) | |
|
928 | for line in row.split('\n')]) | |||
857 |
|
929 | |||
858 | if figure is not None: |
|
930 | if figure is not None: | |
859 | figures.append(figure) |
|
931 | figures.append(figure) | |
@@ -863,7 +935,7 b' class IPythonDirective(Directive):' | |||||
863 | lines.extend(figure.split('\n')) |
|
935 | lines.extend(figure.split('\n')) | |
864 | lines.append('') |
|
936 | lines.append('') | |
865 |
|
937 | |||
866 | if len(lines)>2: |
|
938 | if len(lines) > 2: | |
867 | if debug: |
|
939 | if debug: | |
868 | print('\n'.join(lines)) |
|
940 | print('\n'.join(lines)) | |
869 | else: |
|
941 | else: |
General Comments 0
You need to be logged in to leave comments.
Login now