hooks.py
216 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 | ||
vivainio
|
r394 | $Id: hooks.py 1854 2006-10-30 19:54:25Z vivainio $""" | |
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) | |||