diff --git a/src/sage/repl/ipython_extension.py b/src/sage/repl/ipython_extension.py index b6fc42bbb37..e47eba38179 100644 --- a/src/sage/repl/ipython_extension.py +++ b/src/sage/repl/ipython_extension.py @@ -342,7 +342,18 @@ def cython(self, line, cell): INPUT: - - ``line`` -- ignored + - ``line`` -- parsed as keyword arguments. The allowed arguments are: + + - ``--verbose N`` / ``-v N`` + - ``--compile-message`` + - ``--use-cache`` + - ``--create-local-c-file`` + - ``--annotate`` + - ``--sage-namespace`` + - ``--create-local-so-file`` + - ``--no-compile-message``, ``--no-use-cache``, etc. + + See :func:`~sage.misc.cython.cython` for details. - ``cell`` -- string; the Cython source code to process @@ -350,19 +361,76 @@ def cython(self, line, cell): EXAMPLES:: + sage: # needs sage.misc.cython sage: from sage.repl.interpreter import get_test_shell sage: shell = get_test_shell() - sage: shell.run_cell( # needs sage.misc.cython + sage: shell.run_cell( ....: ''' - ....: %%cython + ....: %%cython -v1 --annotate --no-sage-namespace ....: def f(): ....: print('test') ....: ''') - sage: f() # needs sage.misc.cython + Compiling ....pyx because it changed. + [1/1] Cythonizing ....pyx + sage: f() test + + TESTS: + + Test unrecognized arguments:: + + sage: # needs sage.misc.cython + sage: shell.run_cell(''' + ....: %%cython --some-unrecognized-argument + ....: print(1) + ....: ''') + UsageError: unrecognized arguments: --some-unrecognized-argument + + Test ``--help`` is disabled:: + + sage: # needs sage.misc.cython + sage: shell.run_cell(''' + ....: %%cython --help + ....: print(1) + ....: ''') + UsageError: unrecognized arguments: --help + + Test invalid quotes (see :mod:`sage.repl.interpreter` for explanation of the dummy line):: + + sage: # needs sage.misc.cython + sage: print("dummy line"); shell.run_cell(''' + ....: %%cython --a=' + ....: print(1) + ....: ''') + dummy line + ... + ValueError...Traceback (most recent call last) + ... + ValueError: No closing quotation """ from sage.misc.cython import cython_compile - return cython_compile(cell) + import shlex + import argparse + + class ExitCatchingArgumentParser(argparse.ArgumentParser): + def error(self, message): + # exit_on_error=False does not work completely in some Python versions + # see https://stackoverflow.com/q/67890157 + # we raise UsageError to make the interface similar to what happens when e.g. + # IPython's ``%run`` gets unrecognized arguments + from IPython.core.error import UsageError + raise UsageError(message) + + parser = ExitCatchingArgumentParser(prog="%%cython", add_help=False) + parser.add_argument("--verbose", "-v", type=int) + parser.add_argument("--compile-message", action=argparse.BooleanOptionalAction) + parser.add_argument("--use-cache", action=argparse.BooleanOptionalAction) + parser.add_argument("--create-local-c-file", action=argparse.BooleanOptionalAction) + parser.add_argument("--annotate", action=argparse.BooleanOptionalAction) + parser.add_argument("--sage-namespace", action=argparse.BooleanOptionalAction) + parser.add_argument("--create-local-so-file", action=argparse.BooleanOptionalAction) + args = parser.parse_args(shlex.split(line)) + return cython_compile(cell, **{k: v for k, v in args.__dict__.items() if v is not None}) @cell_magic def fortran(self, line, cell):