ipython.py :  » Development » Leo » Leo-4.7.1-final » leo » plugins » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Development » Leo 
Leo » Leo 4.7.1 final » leo » plugins » ipython.py
# -*- coding: utf-8 -*-
#@+leo-ver=4-thin
#@+node:ekr.20080201143145:@thin ipython.py
#@@first

#@<< docstring >>
#@+node:ekr.20080201151802:<< docstring >>
''' The ipython plugin provides two-way communication (a bridge) between Leo
scripts and IPython running in the console from whichLeowaslaunched. import 

Using this bridge, scripts running in Leo can affect IPython, and vice versa.
In particular, scripts running in IPython can alter Leo outlines!

There are too many details to cover in this docstring.  For full details,
see: LeoDocs.leo or http://webpages.charter.net/edreamleo/IPythonBridge.html
'''
#@-node:ekr.20080201151802:<< docstring >>
#@nl

__version__ = '0.9'
#@<< version history >>
#@+node:ekr.20080201143145.2:<< version history >>
#@@killcolor
#@+at
# 
# v 0.1: Ideas by Ville M. Vainio, code by EKR.
# 
# v 0.2 EKR: Use g.getScript to synthesize scripts.
# 
# v 0.3 EKR:
# - Moved all code from scripts to this plugin.
# - Added leoInterface and leoInterfaceResults classes.
# - Added createNode function for use by the interface classes.
# - Created minibuffer commands.
# - c.ipythonController is now an official ivar.
# - Docstring now references Chapter 21 of Leo's Users Guide.
# 
# v 0.4 EKR:
# - Disable the command lockout logic for the start-ipython command.
# - (In leoSettings.leo): add shortcuts for ipython commands.
# - The init top-level function now requires the tkinter gui.
# 
# v 0.5 VMV & EKR:  Added leoInterfaceResults.__getattr__.
# 
# v 0.6 EKR:
# - Inject leox into the user_ns in start-ipython.
#   As a result, there is no need for init_ipython and it has been removed.
# 
# v 0.7 EKR:
# - changed execute-ipython-script to push-to-ipython.
# - Disabled trace of script in push-to-ipython.
# 
# v 0.8 VMV and EKR:
# - This version is based on mods made by VMV.
# - EKR: set sys.argv = [] in startIPython before calling any IPython api.
#   This prevents IPython from trying to load the .leo file.
# 
# v 0.9 EKR: tell where the commands are coming from.
#@-at
#@nonl
#@-node:ekr.20080201143145.2:<< version history >>
#@nl
#@<< to do >>
#@+node:ekr.20080203092534:<< to do >>
#@@nocolor
#@+at
# 
# - Read the docs re saving and restoring the IPython namespace.
# 
# - Is it possible to start IPShellEmbed automatically?
# 
#     Calling IPShellEmbed.ipshell() blocks, so it can't be done
#     outside the event loop.  It might be possible to do this in
#     an idle-time handler.
# 
#     If it is possible several more settings would be possible.
#@-at
#@nonl
#@-node:ekr.20080203092534:<< to do >>
#@nl
#@<< imports >>
#@+node:ekr.20080201143145.3:<< imports >>
import leo.core.leoGlobals as g
import leo.core.leoPlugins as leoPlugins

import sys

import_ok = True

try:
    import IPython.ipapi
except ImportError:
    g.es_print('ipython plugin: can not import IPython.ipapi',color='red')
    import_ok = False
#@-node:ekr.20080201143145.3:<< imports >>
#@nl

# Globals

# IPython IPApi instance. Global, because only one can exist through the whole leo session
gIP = None

#@+others
#@+node:ekr.20080201144219:Module-level functions
#@+node:ekr.20080201143145.4:init
def init ():

    if not import_ok: return

    # This plugin depends on the properties of the Tk event loop.
    # It may work for other gui's, but this is not guaranteed.
    #if g.app.gui is None:
    #    g.app.createTkGui(__file__)

    if g.app.gui and g.app.gui.guiName() == 'qt' and not g.app.useIpython:
        g.pr('ipython.py plugin disabled ("leo --ipython" enables it)')
        return False

    # since tk and qt are the only ones used currently, we are not too picky
    ok = True
    #ok = g.app.gui.guiName() in ("tkinter","qt")
    if ok:

        # Call onCreate after the commander and the key handler exist.
        leoPlugins.registerHandler('after-create-leo-frame',onCreate)
        g.plugin_signon(__name__)

    return ok
#@-node:ekr.20080201143145.4:init
#@+node:ekr.20080201143145.5:onCreate
def onCreate (tag, keys):

    c = keys.get('c')

    if not c:
        return

    # Inject the controller into the commander.
    c.ipythonController = ipythonController(c)

    try:
        from leo.external import ipy_leo
    except ImportError:
        return
    try:
        st = ipy_leo._request_immediate_connect
    except AttributeError:
        return
    if st:
        c.ipythonController.startIPython()

#@-node:ekr.20080201143145.5:onCreate
#@-node:ekr.20080201144219:Module-level functions
#@+node:ekr.20080201143145.6:class ipythonController
class ipythonController:

    '''A per-commander controller that manages the
    singleton IPython ipshell instance.'''

    #@    @+others
    #@+node:ekr.20080204110426:Birth
    #@+node:ekr.20080201143145.7:ctor
    def __init__ (self,c):

        self.c = c
        self.createCommands()
    #@-node:ekr.20080201143145.7:ctor
    #@+node:ekr.20080204080848:createCommands
    def createCommands(self):

        '''Create all of the ipython plugin's minibuffer commands.'''

        c = self.c ; k = c.k

        table = (
            ('start-ipython',           self.startIPython),
            ('push-to-ipython',         self.pushToIPythonCommand),
        )

        shortcut = None

        if not g.app.unitTesting:
            g.es('ipython plugin...',color='purple')

        for commandName,func in table:
            k.registerCommand (commandName,shortcut,func,pane='all',verbose=True)
    #@-node:ekr.20080204080848:createCommands
    #@-node:ekr.20080204110426:Birth
    #@+node:ekr.20080201151802.1:Commands
    #@+node:ekr.20080201143319.10:startIPython
    def startIPython(self,event=None):

        '''The start-ipython command'''

        c = self.c
        global gIP
        try:
            from leo.external import ipy_leo
        except ImportError:
            self.error("Error importing ipy_leo")
            return

        if gIP:
            # if we are already running, just inject a new commander for current document

            leox = leoInterface(c,g) # inject leox into the namespace.
            ipy_leo.update_commander(leox)
            return

        try:
            api = IPython.ipapi
            leox = leoInterface(c,g) # inject leox into the namespace.

            existing_ip = api.get()
            if existing_ip is None:
                args = c.config.getString('ipython_argv')
                if args is None:
                    argv = ['leo.py']
                else:
                    # force str instead of unicode
                    argv = [str(s) for s in args.split()] 
                if g.app.gui.guiName() == 'qt':
                    # qt ui takes care of the coloring (using scintilla)
                    if '-colors' not in argv:
                        argv.extend(['-colors','NoColor'])
                sys.argv = argv

                self.message('Creating IPython shell.')
                ses = api.make_session()
                gIP = ses.IP.getapi()

                #if g.app.gui.guiName() == 'qt' and not g.app.useIpython:
                if 0:
                    # disable this code for now - --ipython is the one recommended way of using qt + ipython
                    g.es('IPython launch failed. Start Leo with argument "--ipython" on command line!')
                    return
                    #try:
                    #    import ipy_qt.qtipywidget
                    #except:
                    #    g.es('IPython launch failed. Start Leo with argument "--ipython" on command line!')
                    #    raise


                    import textwrap
                    self.qtwidget = ipy_qt.qtipywidget.IPythonWidget()
                    self.qtwidget.set_ipython_session(gIP)
                    self.qtwidget.show()
                    self.qtwidget.viewport.append(textwrap.dedent("""\
                    Qt IPython widget (for Leo). Commands entered on box below.
                    If you want the classic IPython text console, start leo with 'launchLeo.py --gui=qt --ipython'
                    """))

            else:
                # To reuse an old IPython session, you need to launch Leo from IPython by doing:
                #
                # import IPython.Shell
                # IPython.Shell.hijack_tk()
                # %run leo.py  (in leo/leo/src)              
                #
                # Obviously you still need to run launch-ipython (Alt-Shift-I) to make 
                # the document visible for ILeo

                self.message('Reusing existing IPython shell')
                gIP = existing_ip                

            ipy_leo_m = gIP.load('leo.external.ipy_leo')
            ipy_leo_m.update_commander(leox)
            c.inCommand = False # Disable the command lockout logic, just as for scripts.
            # start mainloop only if it's not running already
            if existing_ip is None and g.app.gui.guiName() != 'qt':
                # Does not return until IPython closes!
                ses.mainloop()

        except Exception:
            self.error('exception creating IPython shell')
            g.es_exception()
    #@-node:ekr.20080201143319.10:startIPython
    #@+node:ekr.20080204111314:pushToIPythonCommand
    def pushToIPythonCommand(self,event=None):

        '''The push-to-ipython command.

        IPython must be started, but need not be inited.'''

        self.pushToIPython(script=None)
    #@-node:ekr.20080204111314:pushToIPythonCommand
    #@-node:ekr.20080201151802.1:Commands
    #@+node:ekr.20080201151802.2:Utils...
    #@+node:ekr.20080204075924:error & message
    def error (self,s):

        g.es_print(s,color='red')

    def message (self,s):

        g.es_print(s,color='blue')
    #@-node:ekr.20080204075924:error & message
    #@+node:ekr.20080201150746.2:pushToIPython
    def pushToIPython (self,script=None):
        ''' Push the node to IPython'''
        if not gIP:
            self.startIPython() # Does not return
        else:
            if script:
                gIP.runlines(script)
                return
            c = self.c ; p = c.p
            push = gIP.user_ns['_leo'].push
            c.inCommand = False # Disable the command lockout logic
            push(p)
            return
    #@-node:ekr.20080201150746.2:pushToIPython
    #@+node:ekr.20080204083034:started
    def started (self):
        return gIP
    #@-node:ekr.20080204083034:started
    #@-node:ekr.20080201151802.2:Utils...
    #@-others
#@-node:ekr.20080201143145.6:class ipythonController
#@+node:ekr.20080204103804.3:class leoInterface
class leoInterface:

    '''A class to allow full access to Leo from Ipython. import 

    An instance of this class called leox is typically injected
    into IPython's user_ns namespace by the init-ipython-command.'''

    def __init__(self,c,g,tag='@ipython-results'):
        self.c, self.g = c,g
#@-node:ekr.20080204103804.3:class leoInterface
#@-others
#@nonl
#@-node:ekr.20080201143145:@thin ipython.py
#@-leo
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.