globalipapp.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. """Global IPython app to support test running.
  2. We must start our own ipython object and heavily muck with it so that all the
  3. modifications IPython makes to system behavior don't send the doctest machinery
  4. into a fit. This code should be considered a gross hack, but it gets the job
  5. done.
  6. """
  7. from __future__ import absolute_import
  8. from __future__ import print_function
  9. # Copyright (c) IPython Development Team.
  10. # Distributed under the terms of the Modified BSD License.
  11. import sys
  12. import warnings
  13. from . import tools
  14. from IPython.core import page
  15. from IPython.utils import io
  16. from IPython.utils import py3compat
  17. from IPython.utils.py3compat import builtin_mod
  18. from IPython.terminal.interactiveshell import TerminalInteractiveShell
  19. class StreamProxy(io.IOStream):
  20. """Proxy for sys.stdout/err. This will request the stream *at call time*
  21. allowing for nose's Capture plugin's redirection of sys.stdout/err.
  22. Parameters
  23. ----------
  24. name : str
  25. The name of the stream. This will be requested anew at every call
  26. """
  27. def __init__(self, name):
  28. warnings.warn("StreamProxy is deprecated and unused as of IPython 5", DeprecationWarning,
  29. stacklevel=2,
  30. )
  31. self.name=name
  32. @property
  33. def stream(self):
  34. return getattr(sys, self.name)
  35. def flush(self):
  36. self.stream.flush()
  37. def get_ipython():
  38. # This will get replaced by the real thing once we start IPython below
  39. return start_ipython()
  40. # A couple of methods to override those in the running IPython to interact
  41. # better with doctest (doctest captures on raw stdout, so we need to direct
  42. # various types of output there otherwise it will miss them).
  43. def xsys(self, cmd):
  44. """Replace the default system call with a capturing one for doctest.
  45. """
  46. # We use getoutput, but we need to strip it because pexpect captures
  47. # the trailing newline differently from commands.getoutput
  48. print(self.getoutput(cmd, split=False, depth=1).rstrip(), end='', file=sys.stdout)
  49. sys.stdout.flush()
  50. def _showtraceback(self, etype, evalue, stb):
  51. """Print the traceback purely on stdout for doctest to capture it.
  52. """
  53. print(self.InteractiveTB.stb2text(stb), file=sys.stdout)
  54. def start_ipython():
  55. """Start a global IPython shell, which we need for IPython-specific syntax.
  56. """
  57. global get_ipython
  58. # This function should only ever run once!
  59. if hasattr(start_ipython, 'already_called'):
  60. return
  61. start_ipython.already_called = True
  62. # Store certain global objects that IPython modifies
  63. _displayhook = sys.displayhook
  64. _excepthook = sys.excepthook
  65. _main = sys.modules.get('__main__')
  66. # Create custom argv and namespaces for our IPython to be test-friendly
  67. config = tools.default_config()
  68. config.TerminalInteractiveShell.simple_prompt = True
  69. # Create and initialize our test-friendly IPython instance.
  70. shell = TerminalInteractiveShell.instance(config=config,
  71. )
  72. # A few more tweaks needed for playing nicely with doctests...
  73. # remove history file
  74. shell.tempfiles.append(config.HistoryManager.hist_file)
  75. # These traps are normally only active for interactive use, set them
  76. # permanently since we'll be mocking interactive sessions.
  77. shell.builtin_trap.activate()
  78. # Modify the IPython system call with one that uses getoutput, so that we
  79. # can capture subcommands and print them to Python's stdout, otherwise the
  80. # doctest machinery would miss them.
  81. shell.system = py3compat.MethodType(xsys, shell)
  82. shell._showtraceback = py3compat.MethodType(_showtraceback, shell)
  83. # IPython is ready, now clean up some global state...
  84. # Deactivate the various python system hooks added by ipython for
  85. # interactive convenience so we don't confuse the doctest system
  86. sys.modules['__main__'] = _main
  87. sys.displayhook = _displayhook
  88. sys.excepthook = _excepthook
  89. # So that ipython magics and aliases can be doctested (they work by making
  90. # a call into a global _ip object). Also make the top-level get_ipython
  91. # now return this without recursively calling here again.
  92. _ip = shell
  93. get_ipython = _ip.get_ipython
  94. builtin_mod._ip = _ip
  95. builtin_mod.get_ipython = get_ipython
  96. # Override paging, so we don't require user interaction during the tests.
  97. def nopage(strng, start=0, screen_lines=0, pager_cmd=None):
  98. if isinstance(strng, dict):
  99. strng = strng.get('text/plain', '')
  100. print(strng)
  101. page.orig_page = page.pager_page
  102. page.pager_page = nopage
  103. return _ip