hooks.py
173 lines
| 5.5 KiB
| text/x-python
|
PythonLexer
Thomas Kluyver
|
r9244 | """Hooks for IPython. | ||
Ville M. Vainio
|
r1032 | |||
In Python, it is possible to overwrite any method of any object if you really | ||||
Thomas Kluyver
|
r9244 | want to. But IPython exposes a few 'hooks', methods which are *designed* to | ||
Ville M. Vainio
|
r1032 | be overwritten by users for customization purposes. This module defines the | ||
default versions of all such hooks, which get used by IPython if not | ||||
overridden by the user. | ||||
Thomas Kluyver
|
r9244 | Hooks are simple functions, but they should be declared with ``self`` as their | ||
Ville M. Vainio
|
r1032 | first argument, because when activated they are registered into IPython as | ||
Thomas Kluyver
|
r9244 | instance methods. The self argument will be the IPython running instance | ||
Ville M. Vainio
|
r1032 | itself, so hooks have full access to the entire IPython object. | ||
Thomas Kluyver
|
r9244 | If you wish to define a new hook and activate it, you can make an :doc:`extension | ||
</config/extensions/index>` or a :ref:`startup script <startup_files>`. For | ||||
example, you could use a startup file like this:: | ||||
Ville M. Vainio
|
r1032 | |||
Thomas Kluyver
|
r9244 | import os | ||
Ville M. Vainio
|
r1032 | |||
Thomas Kluyver
|
r9244 | def calljed(self,filename, linenum): | ||
"My editor hook calls the jed editor directly." | ||||
print "Calling my own editor, jed ..." | ||||
if os.system('jed +%d %s' % (linenum,filename)) != 0: | ||||
raise TryNext() | ||||
Ville M. Vainio
|
r1032 | |||
Thomas Kluyver
|
r9244 | def load_ipython_extension(ip): | ||
ip.set_hook('editor', calljed) | ||||
Ville M. Vainio
|
r1032 | |||
Fernando Perez
|
r1853 | """ | ||
Ville M. Vainio
|
r1032 | |||
#***************************************************************************** | ||||
# Copyright (C) 2005 Fernando Perez. <fperez@colorado.edu> | ||||
# | ||||
# Distributed under the terms of the BSD License. The full license is in | ||||
# the file COPYING, distributed as part of this software. | ||||
#***************************************************************************** | ||||
Thomas Kluyver
|
r7515 | import os | ||
Takafumi Arakaki
|
r6634 | import subprocess | ||
Robert Kern
|
r1841 | import sys | ||
Brian Granger
|
r2498 | |||
Srinivas Reddy Thatiparthy
|
r25227 | from .error import TryNext | ||
Brian Granger
|
r2498 | |||
Ville M. Vainio
|
r1032 | # List here all the default hooks. For now it's just the editor functions | ||
# but over time we'll move here all the public API for user-accessible things. | ||||
Brian Granger
|
r2226 | |||
Matthias Bussonnier
|
r27301 | __all__ = [ | ||
"editor", | ||||
"synchronize_with_editor", | ||||
"show_in_pager", | ||||
"pre_prompt_hook", | ||||
"clipboard_get", | ||||
] | ||||
Ville M. Vainio
|
r1032 | |||
Thomas Kluyver
|
r15607 | deprecated = {'pre_run_code_hook': "a callback for the 'pre_execute' or 'pre_run_cell' event", | ||
Thomas Kluyver
|
r15612 | 'late_startup_hook': "a callback for the 'shell_initialized' event", | ||
Thomas Kluyver
|
r15602 | 'shutdown_hook': "the atexit module", | ||
} | ||||
Takafumi Arakaki
|
r6634 | def editor(self, filename, linenum=None, wait=True): | ||
Ville M. Vainio
|
r1032 | """Open the default editor at the given filename and linenumber. | ||
This is IPython's default editor hook, you can use it as an example to | ||||
write your own modified one. To set your own editor function as the | ||||
new editor hook, call ip.set_hook('editor',yourfunc).""" | ||||
# IPython configures a default editor at startup by reading $EDITOR from | ||||
# the environment, and falling back on vi (unix) or notepad (win32). | ||||
Brian Granger
|
r2202 | editor = self.editor | ||
Bernardo B. Marques
|
r4872 | |||
Ville M. Vainio
|
r1032 | # marker for at which line to open the file (for existing objects) | ||
if linenum is None or editor=='notepad': | ||||
linemark = '' | ||||
else: | ||||
linemark = '+%d' % int(linenum) | ||||
Bernardo B. Marques
|
r4872 | |||
Ville M. Vainio
|
r1032 | # Enclose in quotes if necessary and legal | ||
if ' ' in editor and os.path.isfile(editor) and editor[0] != '"': | ||||
editor = '"%s"' % editor | ||||
Bernardo B. Marques
|
r4872 | |||
Ville M. Vainio
|
r1032 | # Call the actual editor | ||
Takafumi Arakaki
|
r6634 | proc = subprocess.Popen('%s %s %s' % (editor, linemark, filename), | ||
shell=True) | ||||
if wait and proc.wait() != 0: | ||||
Brian Granger
|
r2205 | raise TryNext() | ||
Ville M. Vainio
|
r1032 | |||
Brian Granger
|
r2226 | |||
vds
|
r1241 | def synchronize_with_editor(self, filename, linenum, column): | ||
Fernando Perez
|
r2116 | pass | ||
Brian Granger
|
r2226 | |||
Ville M. Vainio
|
r1032 | |||
class CommandChainDispatcher: | ||||
""" Dispatch calls to a chain of commands until some func can handle it | ||||
Bernardo B. Marques
|
r4872 | |||
Ville M. Vainio
|
r1032 | Usage: instantiate, execute "add" to add commands (with optional | ||
priority), execute normally via f() calling mechanism. | ||||
Bernardo B. Marques
|
r4872 | |||
Ville M. Vainio
|
r1032 | """ | ||
def __init__(self,commands=None): | ||||
if commands is None: | ||||
self.chain = [] | ||||
else: | ||||
self.chain = commands | ||||
Bernardo B. Marques
|
r4872 | |||
Ville M. Vainio
|
r1032 | def __call__(self,*args, **kw): | ||
Bernardo B. Marques
|
r4872 | """ Command chain is called just like normal func. | ||
Fernando Perez
|
r6951 | This will call all funcs in chain with the same args as were given to | ||
this function, and return the result of first func that didn't raise | ||||
TryNext""" | ||||
Bradley M. Froehle
|
r7334 | last_exc = TryNext() | ||
Ville M. Vainio
|
r1032 | for prio,cmd in self.chain: | ||
#print "prio",prio,"cmd",cmd #dbg | ||||
try: | ||||
Fernando Perez
|
r2370 | return cmd(*args, **kw) | ||
Bradley M. Froehle
|
r7334 | except TryNext as exc: | ||
last_exc = exc | ||||
Ville M. Vainio
|
r1032 | # if no function will accept it, raise TryNext up to the caller | ||
Bradley M. Froehle
|
r7334 | raise last_exc | ||
Bernardo B. Marques
|
r4872 | |||
Ville M. Vainio
|
r1032 | def __str__(self): | ||
return str(self.chain) | ||||
Bernardo B. Marques
|
r4872 | |||
Ville M. Vainio
|
r1032 | def add(self, func, priority=0): | ||
""" Add a func to the cmd chain with given priority """ | ||||
Thomas Kluyver
|
r7515 | self.chain.append((priority, func)) | ||
Thomas Kluyver
|
r7519 | self.chain.sort(key=lambda x: x[0]) | ||
Ville M. Vainio
|
r1032 | |||
def __iter__(self): | ||||
""" Return all objects in chain. | ||||
Bernardo B. Marques
|
r4872 | |||
Ville M. Vainio
|
r1032 | Handy if the objects are not callable. | ||
""" | ||||
return iter(self.chain) | ||||
Brian Granger
|
r2226 | |||
Scott Sanderson
|
r19432 | def show_in_pager(self, data, start, screen_lines): | ||
Ville M. Vainio
|
r1032 | """ Run a string through pager """ | ||
# raising TryNext here will use the default paging functionality | ||||
Brian Granger
|
r2205 | raise TryNext | ||
Ville M. Vainio
|
r1032 | |||
Brian Granger
|
r2226 | |||
Ville M. Vainio
|
r1032 | def pre_prompt_hook(self): | ||
""" Run before displaying the next prompt | ||||
Bernardo B. Marques
|
r4872 | |||
Use this e.g. to display output from asynchronous operations (in order | ||||
to not mess up text entry) | ||||
Ville M. Vainio
|
r1032 | """ | ||
Bernardo B. Marques
|
r4872 | |||
Ville M. Vainio
|
r1032 | return None | ||
Brian Granger
|
r2226 | |||
Robert Kern
|
r1841 | def clipboard_get(self): | ||
""" Get text from the clipboard. | ||||
""" | ||||
Srinivas Reddy Thatiparthy
|
r25227 | from ..lib.clipboard import ( | ||
Artur Svistunov
|
r27662 | osx_clipboard_get, | ||
tkinter_clipboard_get, | ||||
win32_clipboard_get, | ||||
wayland_clipboard_get, | ||||
Brian Granger
|
r2128 | ) | ||
Robert Kern
|
r1841 | if sys.platform == 'win32': | ||
chain = [win32_clipboard_get, tkinter_clipboard_get] | ||||
elif sys.platform == 'darwin': | ||||
chain = [osx_clipboard_get, tkinter_clipboard_get] | ||||
else: | ||||
Artur Svistunov
|
r27519 | chain = [wayland_clipboard_get, tkinter_clipboard_get] | ||
Robert Kern
|
r1841 | dispatcher = CommandChainDispatcher() | ||
for func in chain: | ||||
dispatcher.add(func) | ||||
text = dispatcher() | ||||
return text | ||||