File: frontend.py

package info (click to toggle)
ipython 0.13.1-2%2Bdeb7u1
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 15,752 kB
  • sloc: python: 69,537; makefile: 355; lisp: 272; sh: 80; objc: 37
file content (197 lines) | stat: -rwxr-xr-x 6,385 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
#!/usr/bin/env python
"""A simple interactive frontend that talks to a kernel over 0MQ.
"""

#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
# stdlib
import cPickle as pickle
import code
import readline
import sys
import time
import uuid

# our own
import zmq
import session
import completer
from IPython.utils.localinterfaces import LOCALHOST
from IPython.zmq.session import Message

#-----------------------------------------------------------------------------
# Classes and functions
#-----------------------------------------------------------------------------

class Console(code.InteractiveConsole):

    def __init__(self, locals=None, filename="<console>",
                 session = session,
                 request_socket=None,
                 sub_socket=None):
        code.InteractiveConsole.__init__(self, locals, filename)
        self.session = session
        self.request_socket = request_socket
        self.sub_socket = sub_socket
        self.backgrounded = 0
        self.messages = {}

        # Set tab completion
        self.completer = completer.ClientCompleter(self, session, request_socket)
        readline.parse_and_bind('tab: complete')
        readline.parse_and_bind('set show-all-if-ambiguous on')
        readline.set_completer(self.completer.complete)

        # Set system prompts
        sys.ps1 = 'Py>>> '
        sys.ps2 = '  ... '
        sys.ps3 = 'Out : '
        # Build dict of handlers for message types
        self.handlers = {}
        for msg_type in ['pyin', 'pyout', 'pyerr', 'stream']:
            self.handlers[msg_type] = getattr(self, 'handle_%s' % msg_type)

    def handle_pyin(self, omsg):
        if omsg.parent_header.session == self.session.session:
            return
        c = omsg.content.code.rstrip()
        if c:
            print '[IN from %s]' % omsg.parent_header.username
            print c

    def handle_pyout(self, omsg):
        #print omsg # dbg
        if omsg.parent_header.session == self.session.session:
            print "%s%s" % (sys.ps3, omsg.content.data)
        else:
            print '[Out from %s]' % omsg.parent_header.username
            print omsg.content.data

    def print_pyerr(self, err):
        print >> sys.stderr, err.etype,':', err.evalue
        print >> sys.stderr, ''.join(err.traceback)

    def handle_pyerr(self, omsg):
        if omsg.parent_header.session == self.session.session:
            return
        print >> sys.stderr, '[ERR from %s]' % omsg.parent_header.username
        self.print_pyerr(omsg.content)

    def handle_stream(self, omsg):
        if omsg.content.name == 'stdout':
            outstream = sys.stdout
        else:
            outstream = sys.stderr
            print >> outstream, '*ERR*',
        print >> outstream, omsg.content.data,

    def handle_output(self, omsg):
        handler = self.handlers.get(omsg.msg_type, None)
        if handler is not None:
            handler(omsg)

    def recv_output(self):
        while True:
            ident,msg = self.session.recv(self.sub_socket)
            if msg is None:
                break
            self.handle_output(Message(msg))

    def handle_reply(self, rep):
        # Handle any side effects on output channels
        self.recv_output()
        # Now, dispatch on the possible reply types we must handle
        if rep is None:
            return
        if rep.content.status == 'error':
            self.print_pyerr(rep.content)
        elif rep.content.status == 'aborted':
            print >> sys.stderr, "ERROR: ABORTED"
            ab = self.messages[rep.parent_header.msg_id].content
            if 'code' in ab:
                print >> sys.stderr, ab.code
            else:
                print >> sys.stderr, ab

    def recv_reply(self):
        ident,rep = self.session.recv(self.request_socket)
        mrep = Message(rep)
        self.handle_reply(mrep)
        return mrep

    def runcode(self, code):
        # We can't pickle code objects, so fetch the actual source
        src = '\n'.join(self.buffer)

        # for non-background inputs, if we do have previoiusly backgrounded
        # jobs, check to see if they've produced results
        if not src.endswith(';'):
            while self.backgrounded > 0:
                #print 'checking background'
                rep = self.recv_reply()
                if rep:
                    self.backgrounded -= 1
                time.sleep(0.05)

        # Send code execution message to kernel
        omsg = self.session.send(self.request_socket,
                                 'execute_request', dict(code=src))
        self.messages[omsg.header.msg_id] = omsg

        # Fake asynchronicity by letting the user put ';' at the end of the line
        if src.endswith(';'):
            self.backgrounded += 1
            return

        # For foreground jobs, wait for reply
        while True:
            rep = self.recv_reply()
            if rep is not None:
                break
            self.recv_output()
            time.sleep(0.05)
        else:
            # We exited without hearing back from the kernel!
            print >> sys.stderr, 'ERROR!!! kernel never got back to us!!!'


class InteractiveClient(object):
    def __init__(self, session, request_socket, sub_socket):
        self.session = session
        self.request_socket = request_socket
        self.sub_socket = sub_socket
        self.console = Console(None, '<zmq-console>',
                               session, request_socket, sub_socket)

    def interact(self):
        self.console.interact()


def main():
    # Defaults
    #ip = '192.168.2.109'
    ip = LOCALHOST
    #ip = '99.146.222.252'
    port_base = 5575
    connection = ('tcp://%s' % ip) + ':%i'
    req_conn = connection % port_base
    sub_conn = connection % (port_base+1)

    # Create initial sockets
    c = zmq.Context()
    request_socket = c.socket(zmq.DEALER)
    request_socket.connect(req_conn)

    sub_socket = c.socket(zmq.SUB)
    sub_socket.connect(sub_conn)
    sub_socket.setsockopt(zmq.SUBSCRIBE, '')

    # Make session and user-facing client
    sess = session.Session()
    client = InteractiveClient(sess, request_socket, sub_socket)
    client.interact()


if __name__ == '__main__':
    main()