hooks.py 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. """Hooks for IPython.
  2. In Python, it is possible to overwrite any method of any object if you really
  3. want to. But IPython exposes a few 'hooks', methods which are *designed* to
  4. be overwritten by users for customization purposes. This module defines the
  5. default versions of all such hooks, which get used by IPython if not
  6. overridden by the user.
  7. Hooks are simple functions, but they should be declared with ``self`` as their
  8. first argument, because when activated they are registered into IPython as
  9. instance methods. The self argument will be the IPython running instance
  10. itself, so hooks have full access to the entire IPython object.
  11. If you wish to define a new hook and activate it, you can make an :doc:`extension
  12. </config/extensions/index>` or a :ref:`startup script <startup_files>`. For
  13. example, you could use a startup file like this::
  14. import os
  15. def calljed(self,filename, linenum):
  16. "My editor hook calls the jed editor directly."
  17. print "Calling my own editor, jed ..."
  18. if os.system('jed +%d %s' % (linenum,filename)) != 0:
  19. raise TryNext()
  20. def load_ipython_extension(ip):
  21. ip.set_hook('editor', calljed)
  22. """
  23. #*****************************************************************************
  24. # Copyright (C) 2005 Fernando Perez. <fperez@colorado.edu>
  25. #
  26. # Distributed under the terms of the BSD License. The full license is in
  27. # the file COPYING, distributed as part of this software.
  28. #*****************************************************************************
  29. import os
  30. import subprocess
  31. import warnings
  32. import sys
  33. from IPython.core.error import TryNext
  34. # List here all the default hooks. For now it's just the editor functions
  35. # but over time we'll move here all the public API for user-accessible things.
  36. __all__ = ['editor', 'fix_error_editor', 'synchronize_with_editor',
  37. 'shutdown_hook', 'late_startup_hook',
  38. 'show_in_pager','pre_prompt_hook',
  39. 'pre_run_code_hook', 'clipboard_get']
  40. deprecated = {'pre_run_code_hook': "a callback for the 'pre_execute' or 'pre_run_cell' event",
  41. 'late_startup_hook': "a callback for the 'shell_initialized' event",
  42. 'shutdown_hook': "the atexit module",
  43. }
  44. def editor(self, filename, linenum=None, wait=True):
  45. """Open the default editor at the given filename and linenumber.
  46. This is IPython's default editor hook, you can use it as an example to
  47. write your own modified one. To set your own editor function as the
  48. new editor hook, call ip.set_hook('editor',yourfunc)."""
  49. # IPython configures a default editor at startup by reading $EDITOR from
  50. # the environment, and falling back on vi (unix) or notepad (win32).
  51. editor = self.editor
  52. # marker for at which line to open the file (for existing objects)
  53. if linenum is None or editor=='notepad':
  54. linemark = ''
  55. else:
  56. linemark = '+%d' % int(linenum)
  57. # Enclose in quotes if necessary and legal
  58. if ' ' in editor and os.path.isfile(editor) and editor[0] != '"':
  59. editor = '"%s"' % editor
  60. # Call the actual editor
  61. proc = subprocess.Popen('%s %s %s' % (editor, linemark, filename),
  62. shell=True)
  63. if wait and proc.wait() != 0:
  64. raise TryNext()
  65. import tempfile
  66. def fix_error_editor(self,filename,linenum,column,msg):
  67. """DEPRECATED
  68. Open the editor at the given filename, linenumber, column and
  69. show an error message. This is used for correcting syntax errors.
  70. The current implementation only has special support for the VIM editor,
  71. and falls back on the 'editor' hook if VIM is not used.
  72. Call ip.set_hook('fix_error_editor',yourfunc) to use your own function,
  73. """
  74. warnings.warn("""
  75. `fix_error_editor` is pending deprecation as of IPython 5.0 and will be removed
  76. in future versions. It appears to be used only for automatically fixing syntax
  77. error that has been broken for a few years and has thus been removed. If you
  78. happend to use this function and still need it please make your voice heard on
  79. the mailing list ipython-dev@python.org , or on the GitHub Issue tracker:
  80. https://github.com/ipython/ipython/issues/9649 """, UserWarning)
  81. def vim_quickfix_file():
  82. t = tempfile.NamedTemporaryFile()
  83. t.write('%s:%d:%d:%s\n' % (filename,linenum,column,msg))
  84. t.flush()
  85. return t
  86. if os.path.basename(self.editor) != 'vim':
  87. self.hooks.editor(filename,linenum)
  88. return
  89. t = vim_quickfix_file()
  90. try:
  91. if os.system('vim --cmd "set errorformat=%f:%l:%c:%m" -q ' + t.name):
  92. raise TryNext()
  93. finally:
  94. t.close()
  95. def synchronize_with_editor(self, filename, linenum, column):
  96. pass
  97. class CommandChainDispatcher:
  98. """ Dispatch calls to a chain of commands until some func can handle it
  99. Usage: instantiate, execute "add" to add commands (with optional
  100. priority), execute normally via f() calling mechanism.
  101. """
  102. def __init__(self,commands=None):
  103. if commands is None:
  104. self.chain = []
  105. else:
  106. self.chain = commands
  107. def __call__(self,*args, **kw):
  108. """ Command chain is called just like normal func.
  109. This will call all funcs in chain with the same args as were given to
  110. this function, and return the result of first func that didn't raise
  111. TryNext"""
  112. last_exc = TryNext()
  113. for prio,cmd in self.chain:
  114. #print "prio",prio,"cmd",cmd #dbg
  115. try:
  116. return cmd(*args, **kw)
  117. except TryNext as exc:
  118. last_exc = exc
  119. # if no function will accept it, raise TryNext up to the caller
  120. raise last_exc
  121. def __str__(self):
  122. return str(self.chain)
  123. def add(self, func, priority=0):
  124. """ Add a func to the cmd chain with given priority """
  125. self.chain.append((priority, func))
  126. self.chain.sort(key=lambda x: x[0])
  127. def __iter__(self):
  128. """ Return all objects in chain.
  129. Handy if the objects are not callable.
  130. """
  131. return iter(self.chain)
  132. def shutdown_hook(self):
  133. """ default shutdown hook
  134. Typically, shotdown hooks should raise TryNext so all shutdown ops are done
  135. """
  136. #print "default shutdown hook ok" # dbg
  137. return
  138. def late_startup_hook(self):
  139. """ Executed after ipython has been constructed and configured
  140. """
  141. #print "default startup hook ok" # dbg
  142. def show_in_pager(self, data, start, screen_lines):
  143. """ Run a string through pager """
  144. # raising TryNext here will use the default paging functionality
  145. raise TryNext
  146. def pre_prompt_hook(self):
  147. """ Run before displaying the next prompt
  148. Use this e.g. to display output from asynchronous operations (in order
  149. to not mess up text entry)
  150. """
  151. return None
  152. def pre_run_code_hook(self):
  153. """ Executed before running the (prefiltered) code in IPython """
  154. return None
  155. def clipboard_get(self):
  156. """ Get text from the clipboard.
  157. """
  158. from IPython.lib.clipboard import (
  159. osx_clipboard_get, tkinter_clipboard_get,
  160. win32_clipboard_get
  161. )
  162. if sys.platform == 'win32':
  163. chain = [win32_clipboard_get, tkinter_clipboard_get]
  164. elif sys.platform == 'darwin':
  165. chain = [osx_clipboard_get, tkinter_clipboard_get]
  166. else:
  167. chain = [tkinter_clipboard_get]
  168. dispatcher = CommandChainDispatcher()
  169. for func in chain:
  170. dispatcher.add(func)
  171. text = dispatcher()
  172. return text