Format: text/x-python
⬇ Download File (5.5 KB)
   1  """Hooks for IPython.
   2  
   3  In Python, it is possible to overwrite any method of any object if you really
   4  want to.  But IPython exposes a few 'hooks', methods which are *designed* to
   5  be overwritten by users for customization purposes.  This module defines the
   6  default versions of all such hooks, which get used by IPython if not
   7  overridden by the user.
   8  
   9  Hooks are simple functions, but they should be declared with ``self`` as their
  10  first argument, because when activated they are registered into IPython as
  11  instance methods. The self argument will be the IPython running instance
  12  itself, so hooks have full access to the entire IPython object.
  13  
  14  If you wish to define a new hook and activate it, you can make an :doc:`extension
  15  </config/extensions/index>` or a :ref:`startup script <startup_files>`. For
  16  example, you could use a startup file like this::
  17  
  18      import os
  19  
  20      def calljed(self,filename, linenum):
  21          "My editor hook calls the jed editor directly."
  22          print("Calling my own editor, jed ...")
  23          if os.system('jed +%d %s' % (linenum,filename)) != 0:
  24              raise TryNext()
  25  
  26      def load_ipython_extension(ip):
  27          ip.set_hook('editor', calljed)
  28  
  29  """
  30  
  31  #*****************************************************************************
  32  #       Copyright (C) 2005 Fernando Perez. <fperez@colorado.edu>
  33  #
  34  #  Distributed under the terms of the BSD License.  The full license is in
  35  #  the file COPYING, distributed as part of this software.
  36  #*****************************************************************************
  37  
  38  import os
  39  import subprocess
  40  import sys
  41  
  42  from .error import TryNext
  43  
  44  # List here all the default hooks.  For now it's just the editor functions
  45  # but over time we'll move here all the public API for user-accessible things.
  46  
  47  __all__ = [
  48      "editor",
  49      "synchronize_with_editor",
  50      "show_in_pager",
  51      "pre_prompt_hook",
  52      "clipboard_get",
  53  ]
  54  
  55  deprecated = {'pre_run_code_hook': "a callback for the 'pre_execute' or 'pre_run_cell' event",
  56                'late_startup_hook': "a callback for the 'shell_initialized' event",
  57                'shutdown_hook': "the atexit module",
  58               }
  59  
  60  def editor(self, filename, linenum=None, wait=True):
  61      """Open the default editor at the given filename and linenumber.
  62  
  63      This is IPython's default editor hook, you can use it as an example to
  64      write your own modified one.  To set your own editor function as the
  65      new editor hook, call ip.set_hook('editor',yourfunc)."""
  66  
  67      # IPython configures a default editor at startup by reading $EDITOR from
  68      # the environment, and falling back on vi (unix) or notepad (win32).
  69      editor = self.editor
  70  
  71      # marker for at which line to open the file (for existing objects)
  72      if linenum is None or editor=='notepad':
  73          linemark = ''
  74      else:
  75          linemark = '+%d' % int(linenum)
  76  
  77      # Enclose in quotes if necessary and legal
  78      if ' ' in editor and os.path.isfile(editor) and editor[0] != '"':
  79          editor = '"%s"' % editor
  80  
  81      # Call the actual editor
  82      proc = subprocess.Popen('%s %s %s' % (editor, linemark, filename),
  83                              shell=True)
  84      if wait and proc.wait() != 0:
  85          raise TryNext()
  86  
  87  
  88  def synchronize_with_editor(self, filename, linenum, column):
  89          pass
  90  
  91  
  92  class CommandChainDispatcher:
  93      """ Dispatch calls to a chain of commands until some func can handle it
  94  
  95      Usage: instantiate, execute "add" to add commands (with optional
  96      priority), execute normally via f() calling mechanism.
  97  
  98      """
  99      def __init__(self,commands=None):
 100          if commands is None:
 101              self.chain = []
 102          else:
 103              self.chain = commands
 104  
 105  
 106      def __call__(self,*args, **kw):
 107          """ Command chain is called just like normal func.
 108  
 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  
 122      def __str__(self):
 123          return str(self.chain)
 124  
 125      def add(self, func, priority=0):
 126          """ Add a func to the cmd chain with given priority """
 127          self.chain.append((priority, func))
 128          self.chain.sort(key=lambda x: x[0])
 129  
 130      def __iter__(self):
 131          """ Return all objects in chain.
 132  
 133          Handy if the objects are not callable.
 134          """
 135          return iter(self.chain)
 136  
 137  
 138  def show_in_pager(self, data, start, screen_lines):
 139      """ Run a string through pager """
 140      # raising TryNext here will use the default paging functionality
 141      raise TryNext
 142  
 143  
 144  def pre_prompt_hook(self):
 145      """ Run before displaying the next prompt
 146  
 147      Use this e.g. to display output from asynchronous operations (in order
 148      to not mess up text entry)
 149      """
 150  
 151      return None
 152  
 153  
 154  def clipboard_get(self):
 155      """ Get text from the clipboard.
 156      """
 157      from ..lib.clipboard import (
 158          osx_clipboard_get,
 159          tkinter_clipboard_get,
 160          win32_clipboard_get,
 161          wayland_clipboard_get,
 162      )
 163      if sys.platform == 'win32':
 164          chain = [win32_clipboard_get, tkinter_clipboard_get]
 165      elif sys.platform == 'darwin':
 166          chain = [osx_clipboard_get, tkinter_clipboard_get]
 167      else:
 168          chain = [wayland_clipboard_get, tkinter_clipboard_get]
 169      dispatcher = CommandChainDispatcher()
 170      for func in chain:
 171          dispatcher.add(func)
 172      text = dispatcher()
 173      return text
 174