##// END OF EJS Templates
Fix submitted output in verbatim mode.
chebee7i -
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 # we're assuming at most one decorator -- may need to
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 # the "rest" is the standard output of the
448 # The "rest" is the standard output of the input.
446 # input, which needs to be added in
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 input_lines, output, is_doctest, decorator, image_file):
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, decorator,
655 (out_data, input_lines, output, is_doctest,
593 image_file, image_directive) = \
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 input_lines, output, is_doctest,
661 output, is_doctest, decorator,
599 decorator, image_file)
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([' %s'%line for line in row.split('\n')])
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