PageRenderTime 43ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/IPython/deathrow/oldfrontend/prefilterfrontend.py

https://github.com/tinyclues/ipython
Python | 256 lines | 150 code | 29 blank | 77 comment | 5 complexity | ac22e75ec329d9befa6ad74409dacee7 MD5 | raw file
  1. """
  2. Frontend class that uses IPython0 to prefilter the inputs.
  3. Using the IPython0 mechanism gives us access to the magics.
  4. This is a transitory class, used here to do the transition between
  5. ipython0 and ipython1. This class is meant to be short-lived as more
  6. functionnality is abstracted out of ipython0 in reusable functions and
  7. is added on the interpreter. This class can be a used to guide this
  8. refactoring.
  9. """
  10. #-------------------------------------------------------------------------------
  11. # Copyright (C) 2008 The IPython Development Team
  12. #
  13. # Distributed under the terms of the BSD License. The full license is in
  14. # the file COPYING, distributed as part of this software.
  15. #-------------------------------------------------------------------------------
  16. #-------------------------------------------------------------------------------
  17. # Imports
  18. #-------------------------------------------------------------------------------
  19. import sys
  20. import pydoc
  21. import os
  22. import re
  23. import __builtin__
  24. from IPython.core.iplib import InteractiveShell
  25. from IPython.kernel.core.redirector_output_trap import RedirectorOutputTrap
  26. from IPython.kernel.core.sync_traceback_trap import SyncTracebackTrap
  27. import IPython.utils.io
  28. from linefrontendbase import LineFrontEndBase, common_prefix
  29. #-----------------------------------------------------------------------------
  30. # Utility functions
  31. #-----------------------------------------------------------------------------
  32. def mk_system_call(system_call_function, command):
  33. """ given a os.system replacement, and a leading string command,
  34. returns a function that will execute the command with the given
  35. argument string.
  36. """
  37. def my_system_call(args):
  38. system_call_function("%s %s" % (command, args))
  39. my_system_call.__doc__ = "Calls %s" % command
  40. return my_system_call
  41. #-----------------------------------------------------------------------------
  42. # Frontend class using ipython0 to do the prefiltering.
  43. #-----------------------------------------------------------------------------
  44. class PrefilterFrontEnd(LineFrontEndBase):
  45. """ Class that uses ipython0 to do prefilter the input, do the
  46. completion and the magics.
  47. The core trick is to use an ipython0 instance to prefilter the
  48. input, and share the namespace between the interpreter instance used
  49. to execute the statements and the ipython0 used for code
  50. completion...
  51. """
  52. debug = False
  53. def __init__(self, ipython0=None, *args, **kwargs):
  54. """ Parameters
  55. ----------
  56. ipython0: an optional ipython0 instance to use for command
  57. prefiltering and completion.
  58. """
  59. LineFrontEndBase.__init__(self, *args, **kwargs)
  60. self.shell.output_trap = RedirectorOutputTrap(
  61. out_callback=self.write,
  62. err_callback=self.write,
  63. )
  64. self.shell.traceback_trap = SyncTracebackTrap(
  65. formatters=self.shell.traceback_trap.formatters,
  66. )
  67. # Start the ipython0 instance:
  68. self.save_output_hooks()
  69. if ipython0 is None:
  70. # Instanciate an IPython0 InteractiveShell to be able to use the
  71. # prefiltering.
  72. # Suppress all key input, to avoid waiting
  73. def my_rawinput(x=None):
  74. return '\n'
  75. old_rawinput = __builtin__.raw_input
  76. __builtin__.raw_input = my_rawinput
  77. ipython0 = InteractiveShell(
  78. parent=None, user_ns=self.shell.user_ns,
  79. user_global_ns=self.shell.user_global_ns
  80. )
  81. __builtin__.raw_input = old_rawinput
  82. self.ipython0 = ipython0
  83. # Set the pager:
  84. self.ipython0.set_hook('show_in_pager',
  85. lambda s, string: self.write("\n" + string))
  86. self.ipython0.write = self.write
  87. self._ip = _ip = self.ipython0
  88. # Make sure the raw system call doesn't get called, as we don't
  89. # have a stdin accessible.
  90. self._ip.system = self.system_call
  91. # XXX: Muck around with magics so that they work better
  92. # in our environment
  93. if not sys.platform.startswith('win'):
  94. self.ipython0.magic_ls = mk_system_call(self.system_call,
  95. 'ls -CF')
  96. # And now clean up the mess created by ipython0
  97. self.release_output()
  98. if not 'banner' in kwargs and self.banner is None:
  99. self.banner = self.ipython0.banner
  100. # FIXME: __init__ and start should be two different steps
  101. self.start()
  102. #--------------------------------------------------------------------------
  103. # FrontEndBase interface
  104. #--------------------------------------------------------------------------
  105. def show_traceback(self):
  106. """ Use ipython0 to capture the last traceback and display it.
  107. """
  108. # Don't do the capture; the except_hook has already done some
  109. # modifications to the IO streams, if we store them, we'll be
  110. # storing the wrong ones.
  111. #self.capture_output()
  112. self.ipython0.showtraceback(tb_offset=-1)
  113. self.release_output()
  114. def execute(self, python_string, raw_string=None):
  115. if self.debug:
  116. print 'Executing Python code:', repr(python_string)
  117. self.capture_output()
  118. LineFrontEndBase.execute(self, python_string,
  119. raw_string=raw_string)
  120. self.release_output()
  121. def save_output_hooks(self):
  122. """ Store all the output hooks we can think of, to be able to
  123. restore them.
  124. We need to do this early, as starting the ipython0 instance will
  125. screw ouput hooks.
  126. """
  127. self.__old_cout_write = Term.cout.write
  128. self.__old_cerr_write = Term.cerr.write
  129. self.__old_stdout = sys.stdout
  130. self.__old_stderr= sys.stderr
  131. self.__old_help_output = pydoc.help.output
  132. self.__old_display_hook = sys.displayhook
  133. def capture_output(self):
  134. """ Capture all the output mechanisms we can think of.
  135. """
  136. self.save_output_hooks()
  137. Term.cout.write = self.write
  138. Term.cerr.write = self.write
  139. sys.stdout = Term.cout
  140. sys.stderr = Term.cerr
  141. pydoc.help.output = self.shell.output_trap.out
  142. def release_output(self):
  143. """ Release all the different captures we have made.
  144. """
  145. Term.cout.write = self.__old_cout_write
  146. Term.cerr.write = self.__old_cerr_write
  147. sys.stdout = self.__old_stdout
  148. sys.stderr = self.__old_stderr
  149. pydoc.help.output = self.__old_help_output
  150. sys.displayhook = self.__old_display_hook
  151. def complete(self, line):
  152. # FIXME: This should be factored out in the linefrontendbase
  153. # method.
  154. word = self._get_completion_text(line)
  155. completions = self.ipython0.complete(word)
  156. # FIXME: The proper sort should be done in the complete method.
  157. key = lambda x: x.replace('_', '')
  158. completions.sort(key=key)
  159. if completions:
  160. prefix = common_prefix(completions)
  161. line = line[:-len(word)] + prefix
  162. return line, completions
  163. #--------------------------------------------------------------------------
  164. # LineFrontEndBase interface
  165. #--------------------------------------------------------------------------
  166. def prefilter_input(self, input_string):
  167. """ Using IPython0 to prefilter the commands to turn them
  168. in executable statements that are valid Python strings.
  169. """
  170. input_string = LineFrontEndBase.prefilter_input(self, input_string)
  171. filtered_lines = []
  172. # The IPython0 prefilters sometime produce output. We need to
  173. # capture it.
  174. self.capture_output()
  175. self.last_result = dict(number=self.prompt_number)
  176. try:
  177. try:
  178. for line in input_string.split('\n'):
  179. pf = self.ipython0.prefilter_manager.prefilter_lines
  180. filtered_lines.append(pf(line, False).rstrip())
  181. except:
  182. # XXX: probably not the right thing to do.
  183. self.ipython0.showsyntaxerror()
  184. self.after_execute()
  185. finally:
  186. self.release_output()
  187. # Clean up the trailing whitespace, to avoid indentation errors
  188. filtered_string = '\n'.join(filtered_lines)
  189. return filtered_string
  190. #--------------------------------------------------------------------------
  191. # PrefilterFrontEnd interface
  192. #--------------------------------------------------------------------------
  193. def system_call(self, command_string):
  194. """ Allows for frontend to define their own system call, to be
  195. able capture output and redirect input.
  196. """
  197. return os.system(command_string)
  198. def do_exit(self):
  199. """ Exit the shell, cleanup and save the history.
  200. """
  201. self.ipython0.atexit_operations()
  202. def _get_completion_text(self, line):
  203. """ Returns the text to be completed by breaking the line at specified
  204. delimiters.
  205. """
  206. # Break at: spaces, '=', all parentheses (except if balanced).
  207. # FIXME2: In the future, we need to make the implementation similar to
  208. # that in the 'pyreadline' module (modes/basemode.py) where we break at
  209. # each delimiter and try to complete the residual line, until we get a
  210. # successful list of completions.
  211. expression = '\s|=|,|:|\((?!.*\))|\[(?!.*\])|\{(?!.*\})'
  212. complete_sep = re.compile(expression)
  213. text = complete_sep.split(line)[-1]
  214. return text