globalipapp.py
137 lines
| 4.5 KiB
| text/x-python
|
PythonLexer
Fernando Perez
|
r2423 | """Global IPython app to support test running. | ||
We must start our own ipython object and heavily muck with it so that all the | ||||
modifications IPython makes to system behavior don't send the doctest machinery | ||||
into a fit. This code should be considered a gross hack, but it gets the job | ||||
done. | ||||
""" | ||||
Min RK
|
r22742 | # Copyright (c) IPython Development Team. | ||
# Distributed under the terms of the Modified BSD License. | ||||
Thomas Kluyver
|
r23129 | import builtins as builtin_mod | ||
Fernando Perez
|
r2423 | import sys | ||
Hugo
|
r24010 | import types | ||
Min RK
|
r22742 | import warnings | ||
Fernando Perez
|
r2423 | |||
from . import tools | ||||
Thomas Kluyver
|
r5263 | from IPython.core import page | ||
MinRK
|
r3801 | from IPython.utils import io | ||
Fernando Perez
|
r11024 | from IPython.terminal.interactiveshell import TerminalInteractiveShell | ||
Fernando Perez
|
r2974 | |||
Fernando Perez
|
r2423 | |||
MinRK
|
r3801 | class StreamProxy(io.IOStream): | ||
"""Proxy for sys.stdout/err. This will request the stream *at call time* | ||||
allowing for nose's Capture plugin's redirection of sys.stdout/err. | ||||
Bernardo B. Marques
|
r4872 | |||
MinRK
|
r3801 | Parameters | ||
---------- | ||||
name : str | ||||
The name of the stream. This will be requested anew at every call | ||||
""" | ||||
Bernardo B. Marques
|
r4872 | |||
MinRK
|
r3801 | def __init__(self, name): | ||
Min RK
|
r22742 | warnings.warn("StreamProxy is deprecated and unused as of IPython 5", DeprecationWarning, | ||
stacklevel=2, | ||||
) | ||||
MinRK
|
r3801 | self.name=name | ||
Bernardo B. Marques
|
r4872 | |||
MinRK
|
r3801 | @property | ||
def stream(self): | ||||
return getattr(sys, self.name) | ||||
Bernardo B. Marques
|
r4872 | |||
MinRK
|
r3801 | def flush(self): | ||
self.stream.flush() | ||||
Fernando Perez
|
r2423 | |||
def get_ipython(): | ||||
# This will get replaced by the real thing once we start IPython below | ||||
Fernando Perez
|
r2440 | return start_ipython() | ||
Fernando Perez
|
r2423 | |||
Brian Granger
|
r2499 | |||
Fernando Perez
|
r2974 | # A couple of methods to override those in the running IPython to interact | ||
# better with doctest (doctest captures on raw stdout, so we need to direct | ||||
# various types of output there otherwise it will miss them). | ||||
def xsys(self, cmd): | ||||
"""Replace the default system call with a capturing one for doctest. | ||||
""" | ||||
# We use getoutput, but we need to strip it because pexpect captures | ||||
# the trailing newline differently from commands.getoutput | ||||
Thomas Kluyver
|
r7400 | print(self.getoutput(cmd, split=False, depth=1).rstrip(), end='', file=sys.stdout) | ||
Fernando Perez
|
r2974 | sys.stdout.flush() | ||
def _showtraceback(self, etype, evalue, stb): | ||||
"""Print the traceback purely on stdout for doctest to capture it. | ||||
""" | ||||
print(self.InteractiveTB.stb2text(stb), file=sys.stdout) | ||||
Fernando Perez
|
r2423 | def start_ipython(): | ||
"""Start a global IPython shell, which we need for IPython-specific syntax. | ||||
""" | ||||
global get_ipython | ||||
# This function should only ever run once! | ||||
Brian Granger
|
r2499 | if hasattr(start_ipython, 'already_called'): | ||
Fernando Perez
|
r2423 | return | ||
start_ipython.already_called = True | ||||
Bernardo B. Marques
|
r4872 | |||
Fernando Perez
|
r2423 | # Store certain global objects that IPython modifies | ||
_displayhook = sys.displayhook | ||||
_excepthook = sys.excepthook | ||||
_main = sys.modules.get('__main__') | ||||
Fernando Perez
|
r2444 | # Create custom argv and namespaces for our IPython to be test-friendly | ||
Brian Granger
|
r2499 | config = tools.default_config() | ||
Matthias Bussonnier
|
r22573 | config.TerminalInteractiveShell.simple_prompt = True | ||
Brian Granger
|
r2499 | |||
Fernando Perez
|
r2444 | # Create and initialize our test-friendly IPython instance. | ||
Bernardo B. Marques
|
r4872 | shell = TerminalInteractiveShell.instance(config=config, | ||
Fernando Perez
|
r2974 | ) | ||
Fernando Perez
|
r2444 | |||
# A few more tweaks needed for playing nicely with doctests... | ||||
Bernardo B. Marques
|
r4872 | |||
MinRK
|
r4602 | # remove history file | ||
shell.tempfiles.append(config.HistoryManager.hist_file) | ||||
Bernardo B. Marques
|
r4872 | |||
Fernando Perez
|
r2444 | # These traps are normally only active for interactive use, set them | ||
# permanently since we'll be mocking interactive sessions. | ||||
Fernando Perez
|
r2957 | shell.builtin_trap.activate() | ||
Fernando Perez
|
r2441 | |||
Fernando Perez
|
r2444 | # Modify the IPython system call with one that uses getoutput, so that we | ||
# can capture subcommands and print them to Python's stdout, otherwise the | ||||
# doctest machinery would miss them. | ||||
Hugo
|
r24010 | shell.system = types.MethodType(xsys, shell) | ||
shell._showtraceback = types.MethodType(_showtraceback, shell) | ||||
Fernando Perez
|
r2444 | |||
# IPython is ready, now clean up some global state... | ||||
Bernardo B. Marques
|
r4872 | |||
Fernando Perez
|
r2423 | # Deactivate the various python system hooks added by ipython for | ||
# interactive convenience so we don't confuse the doctest system | ||||
sys.modules['__main__'] = _main | ||||
sys.displayhook = _displayhook | ||||
sys.excepthook = _excepthook | ||||
# So that ipython magics and aliases can be doctested (they work by making | ||||
Fernando Perez
|
r2440 | # a call into a global _ip object). Also make the top-level get_ipython | ||
Fernando Perez
|
r2444 | # now return this without recursively calling here again. | ||
Brian Granger
|
r2499 | _ip = shell | ||
Fernando Perez
|
r2423 | get_ipython = _ip.get_ipython | ||
Thomas Kluyver
|
r4734 | builtin_mod._ip = _ip | ||
Matthias Bussonnier
|
r25074 | builtin_mod.ip = _ip | ||
Thomas Kluyver
|
r4734 | builtin_mod.get_ipython = get_ipython | ||
Bernardo B. Marques
|
r4872 | |||
Thomas Kluyver
|
r5263 | # Override paging, so we don't require user interaction during the tests. | ||
def nopage(strng, start=0, screen_lines=0, pager_cmd=None): | ||||
Matthias Bussonnier
|
r22464 | if isinstance(strng, dict): | ||
strng = strng.get('text/plain', '') | ||||
Thomas Kluyver
|
r5263 | print(strng) | ||
Thomas Kluyver
|
r19436 | page.orig_page = page.pager_page | ||
page.pager_page = nopage | ||||
Fernando Perez
|
r2423 | |||
Fernando Perez
|
r2440 | return _ip | ||