hooks.py
215 lines
| 7.4 KiB
| text/x-python
|
PythonLexer
/ IPython / hooks.py
fperez
|
r0 | """hooks for IPython. | ||
In Python, it is possible to overwrite any method of any object if you really | ||||
want to. But IPython exposes a few 'hooks', methods which are _designed_ to | ||||
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. | ||||
hooks are simple functions, but they should be declared with 'self' as their | ||||
first argument, because when activated they are registered into IPython as | ||||
instance methods. The self argument will be the IPython running instance | ||||
itself, so hooks have full access to the entire IPython object. | ||||
If you wish to define a new hook and activate it, you need to put the | ||||
necessary code into a python file which can be either imported or execfile()'d | ||||
from within your ipythonrc configuration. | ||||
For example, suppose that you have a module called 'myiphooks' in your | ||||
PYTHONPATH, which contains the following definition: | ||||
import os | ||||
vivainio
|
r157 | import IPython.ipapi | ||
ip = IPython.ipapi.get() | ||||
fperez
|
r0 | def calljed(self,filename, linenum): | ||
"My editor hook calls the jed editor directly." | ||||
print "Calling my own editor, jed ..." | ||||
os.system('jed +%d %s' % (linenum,filename)) | ||||
vivainio
|
r157 | ip.set_hook('editor', calljed) | ||
fperez
|
r0 | |||
vivainio
|
r157 | You can then enable the functionality by doing 'import myiphooks' | ||
somewhere in your configuration files or ipython command line. | ||||
fperez
|
r0 | |||
fperez
|
r909 | $Id: hooks.py 2899 2007-12-28 08:32:59Z fperez $""" | ||
fperez
|
r0 | |||
#***************************************************************************** | ||||
# 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. | ||||
#***************************************************************************** | ||||
from IPython import Release | ||||
vivainio
|
r144 | from IPython import ipapi | ||
fperez
|
r0 | __author__ = '%s <%s>' % Release.authors['Fernando'] | ||
__license__ = Release.license | ||||
__version__ = Release.version | ||||
vivainio
|
r112 | import os,bisect | ||
vivainio
|
r113 | from genutils import Term | ||
fperez
|
r273 | from pprint import PrettyPrinter | ||
fperez
|
r0 | |||
fperez
|
r54 | # 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. | ||||
vivainio
|
r149 | __all__ = ['editor', 'fix_error_editor', 'result_display', | ||
vivainio
|
r330 | 'input_prefilter', 'shutdown_hook', 'late_startup_hook', | ||
vivainio
|
r331 | 'generate_prompt', 'generate_output_prompt' ] | ||
fperez
|
r0 | |||
fperez
|
r273 | pformat = PrettyPrinter().pformat | ||
fperez
|
r82 | def editor(self,filename, linenum=None): | ||
fperez
|
r0 | """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 | ||||
vivainio
|
r157 | new editor hook, call ip.set_hook('editor',yourfunc).""" | ||
fperez
|
r0 | |||
# IPython configures a default editor at startup by reading $EDITOR from | ||||
# the environment, and falling back on vi (unix) or notepad (win32). | ||||
editor = self.rc.editor | ||||
# marker for at which line to open the file (for existing objects) | ||||
if linenum is None or editor=='notepad': | ||||
linemark = '' | ||||
else: | ||||
fperez
|
r292 | linemark = '+%d' % int(linenum) | ||
vivainio
|
r227 | |||
# Enclose in quotes if necessary and legal | ||||
if ' ' in editor and os.path.isfile(editor) and editor[0] != '"': | ||||
editor = '"%s"' % editor | ||||
fperez
|
r0 | # Call the actual editor | ||
vivainio
|
r227 | os.system('%s %s %s' % (editor,linemark,filename)) | ||
fperez
|
r54 | |||
import tempfile | ||||
def fix_error_editor(self,filename,linenum,column,msg): | ||||
"""Open the editor at the given filename, linenumber, column and | ||||
show an error message. This is used for correcting syntax errors. | ||||
The current implementation only has special support for the VIM editor, | ||||
and falls back on the 'editor' hook if VIM is not used. | ||||
vivainio
|
r157 | Call ip.set_hook('fix_error_editor',youfunc) to use your own function, | ||
fperez
|
r54 | """ | ||
def vim_quickfix_file(): | ||||
t = tempfile.NamedTemporaryFile() | ||||
t.write('%s:%d:%d:%s\n' % (filename,linenum,column,msg)) | ||||
t.flush() | ||||
return t | ||||
if os.path.basename(self.rc.editor) != 'vim': | ||||
self.hooks.editor(filename,linenum) | ||||
return | ||||
t = vim_quickfix_file() | ||||
try: | ||||
os.system('vim --cmd "set errorformat=%f:%l:%c:%m" -q ' + t.name) | ||||
finally: | ||||
t.close() | ||||
vivainio
|
r112 | |||
class CommandChainDispatcher: | ||||
""" Dispatch calls to a chain of commands until some func can handle it | ||||
Usage: instantiate, execute "add" to add commands (with optional | ||||
priority), execute normally via f() calling mechanism. | ||||
""" | ||||
def __init__(self,commands=None): | ||||
if commands is None: | ||||
self.chain = [] | ||||
else: | ||||
self.chain = commands | ||||
def __call__(self,*args, **kw): | ||||
""" Command chain is called just like normal func. | ||||
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 """ | ||||
for prio,cmd in self.chain: | ||||
#print "prio",prio,"cmd",cmd #dbg | ||||
try: | ||||
ret = cmd(*args, **kw) | ||||
return ret | ||||
vivainio
|
r251 | except ipapi.TryNext, exc: | ||
if exc.args or exc.kwargs: | ||||
args = exc.args | ||||
kw = exc.kwargs | ||||
vivainio
|
r112 | |||
def __str__(self): | ||||
return str(self.chain) | ||||
def add(self, func, priority=0): | ||||
""" Add a func to the cmd chain with given priority """ | ||||
bisect.insort(self.chain,(priority,func)) | ||||
vivainio
|
r394 | def __iter__(self): | ||
""" Return all objects in chain. | ||||
Handy if the objects are not callable. | ||||
""" | ||||
return iter(self.chain) | ||||
vivainio
|
r113 | def result_display(self,arg): | ||
vivainio
|
r149 | """ Default display hook. | ||
Called for displaying the result to the user. | ||||
""" | ||||
vivainio
|
r113 | if self.rc.pprint: | ||
out = pformat(arg) | ||||
if '\n' in out: | ||||
# So that multi-line strings line up with the left column of | ||||
# the screen, instead of having the output prompt mess up | ||||
# their first line. | ||||
Term.cout.write('\n') | ||||
print >>Term.cout, out | ||||
else: | ||||
fperez
|
r273 | # By default, the interactive prompt uses repr() to display results, | ||
# so we should honor this. Users who'd rather use a different | ||||
# mechanism can easily override this hook. | ||||
print >>Term.cout, repr(arg) | ||||
# the default display hook doesn't manipulate the value to put in history | ||||
vivainio
|
r144 | return None | ||
vivainio
|
r149 | |||
def input_prefilter(self,line): | ||||
""" Default input prefilter | ||||
This returns the line as unchanged, so that the interpreter | ||||
knows that nothing was done and proceeds with "classic" prefiltering | ||||
(%magics, !shell commands etc.). | ||||
Note that leading whitespace is not passed to this hook. Prefilter | ||||
can't alter indentation. | ||||
""" | ||||
#print "attempt to rewrite",line #dbg | ||||
vivainio
|
r165 | return line | ||
def shutdown_hook(self): | ||||
""" default shutdown hook | ||||
Typically, shotdown hooks should raise TryNext so all shutdown ops are done | ||||
""" | ||||
#print "default shutdown hook ok" # dbg | ||||
return | ||||
def late_startup_hook(self): | ||||
""" Executed after ipython has been constructed and configured | ||||
""" | ||||
fperez
|
r192 | #print "default startup hook ok" # dbg | ||
vivainio
|
r330 | |||
def generate_prompt(self, is_continuation): | ||||
""" calculate and return a string with the prompt to display """ | ||||
ip = self.api | ||||
if is_continuation: | ||||
return str(ip.IP.outputcache.prompt2) | ||||
return str(ip.IP.outputcache.prompt1) | ||||
vivainio
|
r331 | def generate_output_prompt(self): | ||
ip = self.api | ||||
return str(ip.IP.outputcache.prompt_out) | ||||