8000 Add no_traceback argument to :okexcept: option of ipython sphinx directive by StefRe · Pull Request #13751 · ipython/ipython · GitHub
[go: up one dir, main page]

Skip to content

Add no_traceback argument to :okexcept: option of ipython sphinx directive #13751

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions IPython/lib/lexers.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#-----------------------------------------------------------------------------

# Standard library
import builtins
import re

# Third party
Expand Down Expand Up @@ -255,8 +256,19 @@ class IPythonConsoleLexer(Lexer):
in2_regex = r' \.\.+\.: '
out_regex = r'Out\[[0-9]+\]: '

#: The regex to determine when a traceback starts.
ipytb_start = re.compile(r'^(\^C)?(-+\n)|^( File)(.*)(, line )(\d+\n)')
#: The regex to determine when a traceback or exception starts.
exceptions = [
name
for name, value in builtins.__dict__.items()
if isinstance(value, type)
and issubclass(value, Exception)
and not issubclass(value, Warning)
]
ipytb_start = re.compile(
r"^(\^C)?(-+\n)|^( File)(.*)(, line )(\d+\n)|^("
+ "|".join(exceptions)
+ r"): \S.*\n"
)

def __init__(self, **options):
"""Initialize the IPython console lexer.
Expand Down
40 changes: 40 additions & 0 deletions IPython/lib/tests/test_lexers.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from pygments import __version__ as pygments_version
from pygments.token import Token
from pygments.lexers import BashLexer
import pytest

from .. import lexers

Expand Down Expand Up @@ -182,3 +183,42 @@ def testIPythonLexer(self):
(Token.Text, '\n'),
]
assert tokens == list(self.lexer.get_tokens(fragment))


@pytest.mark.parametrize(
"fragment,expected",
[
(
"---\nZeroDivisionError: division by zero\n",
[
(Token.Generic.Output, ""),
(Token.Generic.Traceback, "---\n"),
(Token.Name.Exception, "ZeroDivisionError"),
(Token.Text, ": division by zero\n"),
],
),
(
' File "x.py", line 1\nSyntaxError: xxx',
[
(Token.Generic.Output, ""),
(Token.Generic.Traceback, " File"),
(Token.Name.Namespace, ' "x.py"'),
(Token.Generic.Traceback, ", line "),
(Token.Literal.Number.Integer, "1\n"),
(Token.Name.Exception, "SyntaxError"),
(Token.Text, ": xxx\n"),
],
),
(
"ZeroDivisionError: division by zero",
[
(Token.Generic.Output, ""),
(Token.Name.Exception, "ZeroDivisionError"),
(Token.Text, ": division by zero\n"),
],
),
],
ids=["exception traceback", "syntax error traceback", "no traceback"],
)
def test_IPythonConsoleLexer(fragment, expected):
assert expected == list(lexers.IPythonConsoleLexer().get_tokens(fragment))
66 changes: 43 additions & 23 deletions IPython/sphinxext/ipython_directive.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,6 @@

In [3]: print(y)

See http://matplotlib.org/sampledoc/ipython_directive.html for additional
documentation.

Pseudo-Decorators
=================
Expand Down Expand Up @@ -220,7 +218,7 @@
# for tokenizing blocks
COMMENT, INPUT, OUTPUT = range(3)

PSEUDO_DECORATORS = ["suppress", "verbatim", "savefig", "doctest"]
PSEUDO_DECORATORS = ["suppress", "verbatim", "savefig", "doctest", "okexcept"]

#-----------------------------------------------------------------------------
# Functions and class declarations
Expand Down Expand Up @@ -443,6 +441,16 @@ def process_image(self, decorator):
image_directive = '\n'.join(imagerows)
return image_file, image_directive

@staticmethod
def no_traceback_handler(shell, etype, value, tb, tb_offset=None):
"""
Exception handler that shows only the exception without the traceback.
"""
shell.InteractiveTB.color_toggle()
stb = shell.InteractiveTB.get_exception_only(etype, value)
print(shell.InteractiveTB.stb2text(stb))
return stb

# Callbacks for each type of token
def process_input(self, data, input_prompt, lineno):
"""
Expand All @@ -453,14 +461,20 @@ def process_input(self, data, input_prompt, lineno):
image_file = None
image_directive = None

is_verbatim = decorator=='@verbatim' or self.is_verbatim
is_doctest = (decorator is not None and \
decorator.startswith('@doctest')) or self.is_doctest
is_suppress = decorator=='@suppress' or self.is_suppress
is_okexcept = decorator=='@okexcept' or self.is_okexcept
is_okwarning = decorator=='@okwarning' or self.is_okwarning
is_savefig = decorator is not None and \
decorator.startswith('@savefig')
is_verbatim = decorator == "@verbatim" or self.is_verbatim
is_doctest = (
decorator is not None and decorator.startswith("@doctest")
) or self.is_doctest
is_suppress = decorator == "@suppress" or self.is_suppress
is_okexcept = (
decorator is not None and decorator.startswith("@okexcept")
) or self.is_okexcept
no_traceback = (
decorator is not None
and decorator.partition(" ")[2].startswith("no_traceback")
) or self.no_traceback
is_okwarning = decorator == "@okwarning" or self.is_okwarning
is_savefig = decorator is not None and decorator.startswith("@savefig")

input_lines = input.split('\n')
if len(input_lines) > 1:
Expand Down Expand Up @@ -494,7 +508,11 @@ def process_input(self, data, input_prompt, lineno):
self.IP.execution_count += 1 # increment it anyway
else:
# only submit the line in non-verbatim mode
if no_traceback:
self.IP.set_custom_exc((BaseException,), self.no_traceback_handler)
self.process_input_lines(input_lines, store_history=store_history)
if no_traceback:
self.IP.set_custom_exc((), None)

if not is_suppress:
for i, line in enumerate(input_lines):
Expand Down Expand Up @@ -901,13 +919,14 @@ class IPythonDirective(Directive):
required_arguments = 0
optional_arguments = 4 # python, suppress, verbatim, doctest
final_argumuent_whitespace = True
option_spec = { 'python': directives.unchanged,
'suppress' : directives.flag,
'verbatim' : directives.flag,
'doctest' : directives.flag,
'okexcept': directives.flag,
'okwarning': directives.flag
}
option_spec = {
"python": directives.unchanged,
"suppress": directives.flag,
"verbatim": directives.flag,
"doctest": directives.flag,
"okexcept": directives.unchanged,
"okwarning": directives.flag,
}

shell = None

Expand Down Expand Up @@ -1002,11 +1021,12 @@ def run(self):
rgxin, rgxout, promptin, promptout = self.setup()

options = self.options
self.shell.is_suppress = 'suppress' in options
self.shell.is_doctest = 'doctest' in options
self.shell.is_verbatim = 'verbatim' in options
self.shell.is_okexcept = 'okexcept' in options
self.shell.is_okwarning = 'okwarning' in options
self.shell.is_suppress = "suppress" in options
self.shell.is_doctest = "doctest" in options
self.shell.is_verbatim = "verbatim" in options
self.shell.is_okexcept = "okexcept" in options
self.shell.is_okwarning = "okwarning" in options
self.shell.no_traceback = options.get("okexcept") == "no_traceback"

# handle pure python code
if 'python' in self.arguments:
Expand Down
16 changes: 13 additions & 3 deletions docs/source/sphinxext.rst
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,10 @@ The IPython directive takes a number of options detailed here.

Used to indicate that the relevant code block does not have IPython prompts.

.. rst:directive:option:: okexcept
.. rst:directive:option:: okexcept [no_traceback]

Allow the code block to raise an exception.
Allow the code block to raise an exception. When the `no_traceback` argument
is given, only the exception without the traceback will be printed.

.. rst:directive:option:: okwarning

Expand All @@ -82,7 +83,7 @@ The IPython directive takes a number of options detailed here.

Save output from matplotlib to *outfile*.

It's important to note that all of these options can be used for the entire
It's important to note that most of these options can be used for the entire
directive block or they can decorate individual lines of code as explained
in :ref:`pseudo-decorators`.

Expand Down Expand Up @@ -478,6 +479,15 @@ line just below them (eg ``savefig``).
match. Also, can be applied to the entire ``.. ipython`` block as a
directive option with ``:doctest:``.

@okexcept [no_traceback]

Allow the decorated line of code to raise an exception. IPython prints
and formats the traceback unless the ``no_traceback`` argument is given.
In this case, only the exception without the traceback is printed.
Also, can be applied to the entire ``.. ipython`` block as a
directive option with ``:okexcept:``.


Configuration Options
=====================

Expand Down
6 changes: 6 additions & 0 deletions docs/source/whatsnew/pr/no_traceback-argument.rst
483B
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
no_traceback argument to :okexcept: option
==========================================

The ``:okexcept:`` option of the ``.. ipython::`` directive can now have an
optional argument ``no_traceback`` that prevents printing of the (potentially
long) traceback. Only the exception is printed in this case.
0