hooks.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  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 sys
  32. from .error import TryNext
  33. # List here all the default hooks. For now it's just the editor functions
  34. # but over time we'll move here all the public API for user-accessible things.
  35. __all__ = [
  36. "editor",
  37. "synchronize_with_editor",
  38. "show_in_pager",
  39. "pre_prompt_hook",
  40. "clipboard_get",
  41. ]
  42. deprecated = {'pre_run_code_hook': "a callback for the 'pre_execute' or 'pre_run_cell' event",
  43. 'late_startup_hook': "a callback for the 'shell_initialized' event",
  44. 'shutdown_hook': "the atexit module",
  45. }
  46. def editor(self, filename, linenum=None, wait=True):
  47. """Open the default editor at the given filename and linenumber.
  48. This is IPython's default editor hook, you can use it as an example to
  49. write your own modified one. To set your own editor function as the
  50. new editor hook, call ip.set_hook('editor',yourfunc)."""
  51. # IPython configures a default editor at startup by reading $EDITOR from
  52. # the environment, and falling back on vi (unix) or notepad (win32).
  53. editor = self.editor
  54. # marker for at which line to open the file (for existing objects)
  55. if linenum is None or editor=='notepad':
  56. linemark = ''
  57. else:
  58. linemark = '+%d' % int(linenum)
  59. # Enclose in quotes if necessary and legal
  60. if ' ' in editor and os.path.isfile(editor) and editor[0] != '"':
  61. editor = '"%s"' % editor
  62. # Call the actual editor
  63. proc = subprocess.Popen('%s %s %s' % (editor, linemark, filename),
  64. shell=True)
  65. if wait and proc.wait() != 0:
  66. raise TryNext()
  67. def synchronize_with_editor(self, filename, linenum, column):
  68. pass
  69. class CommandChainDispatcher:
  70. """ Dispatch calls to a chain of commands until some func can handle it
  71. Usage: instantiate, execute "add" to add commands (with optional
  72. priority), execute normally via f() calling mechanism.
  73. """
  74. def __init__(self,commands=None):
  75. if commands is None:
  76. self.chain = []
  77. else:
  78. self.chain = commands
  79. def __call__(self,*args, **kw):
  80. """ Command chain is called just like normal func.
  81. This will call all funcs in chain with the same args as were given to
  82. this function, and return the result of first func that didn't raise
  83. TryNext"""
  84. last_exc = TryNext()
  85. for prio,cmd in self.chain:
  86. # print("prio",prio,"cmd",cmd) # dbg
  87. try:
  88. return cmd(*args, **kw)
  89. except TryNext as exc:
  90. last_exc = exc
  91. # if no function will accept it, raise TryNext up to the caller
  92. raise last_exc
  93. def __str__(self):
  94. return str(self.chain)
  95. def add(self, func, priority=0):
  96. """ Add a func to the cmd chain with given priority """
  97. self.chain.append((priority, func))
  98. self.chain.sort(key=lambda x: x[0])
  99. def __iter__(self):
  100. """ Return all objects in chain.
  101. Handy if the objects are not callable.
  102. """
  103. return iter(self.chain)
  104. def show_in_pager(self, data, start, screen_lines):
  105. """ Run a string through pager """
  106. # raising TryNext here will use the default paging functionality
  107. raise TryNext
  108. def pre_prompt_hook(self):
  109. """ Run before displaying the next prompt
  110. Use this e.g. to display output from asynchronous operations (in order
  111. to not mess up text entry)
  112. """
  113. return None
  114. def clipboard_get(self):
  115. """ Get text from the clipboard.
  116. """
  117. from ..lib.clipboard import (
  118. osx_clipboard_get,
  119. tkinter_clipboard_get,
  120. win32_clipboard_get,
  121. wayland_clipboard_get,
  122. )
  123. if sys.platform == 'win32':
  124. chain = [win32_clipboard_get, tkinter_clipboard_get]
  125. elif sys.platform == 'darwin':
  126. chain = [osx_clipboard_get, tkinter_clipboard_get]
  127. else:
  128. chain = [wayland_clipboard_get, tkinter_clipboard_get]
  129. dispatcher = CommandChainDispatcher()
  130. for func in chain:
  131. dispatcher.add(func)
  132. text = dispatcher()
  133. return text