File: ipython.py

package info (click to toggle)
python-executing 2.2.0-0.3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 11,860 kB
  • sloc: python: 10,235; sh: 48; makefile: 10
file content (129 lines) | stat: -rw-r--r-- 3,723 bytes parent folder | download | duplicates (3)
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
import inspect
import socket
import sys
from io import BytesIO, StringIO
from threading import current_thread, Thread
from uuid import uuid4

from IPython.core.display import HTML, display
from IPython.core.magic import Magics, cell_magic, magics_class
from jinja2 import Environment, PackageLoader, select_autoescape
from traitlets import Unicode, Int, Bool
from werkzeug.local import LocalProxy
from werkzeug.serving import ThreadingMixIn

from birdseye.bird import PY2, Database
from birdseye import server, eye

fake_stream = BytesIO if PY2 else StringIO

thread_proxies = {}


def stream_proxy(original):
    def p():
        frame = inspect.currentframe()
        while frame:
            if frame.f_code == ThreadingMixIn.process_request_thread.__code__:
                return fake_stream()
            frame = frame.f_back
        return thread_proxies.get(current_thread().ident,
                                  original)

    return LocalProxy(p)


sys.stderr = stream_proxy(sys.stderr)
sys.stdout = stream_proxy(sys.stdout)


def run_server(port, bind_host, show_server_output):
    if not show_server_output:
        thread_proxies[current_thread().ident] = fake_stream()
    try:
        server.app.run(
            debug=True,
            port=port,
            host=bind_host,
            use_reloader=False,
        )
    except socket.error:
        pass


templates_env = Environment(
    loader=PackageLoader('birdseye', 'templates'),
    autoescape=select_autoescape(['html', 'xml'])
)


@magics_class
class BirdsEyeMagics(Magics):
    server_url = Unicode(
        u'', config=True,
        help='If set, a server will not be automatically started by %%eye. '
             'The iframe containing birdseye output will use this value as the base '
             'of its URL.'
    )

    port = Int(
        7777, config=True,
        help='Port number for the server started by %%eye.'
    )

    bind_host = Unicode(
        '127.0.0.1', config=True,
        help='Host that the server started by %%eye listens on. '
             'Set to 0.0.0.0 to make it accessible anywhere.'
    )

    show_server_output = Bool(
        False, config=True,
        help='Set to True to show stdout and stderr from the server started by %%eye.'
    )

    db_url = Unicode(
        u'', config=True,
        help='The database URL that the server started by %%eye reads from. '
             'Equivalent to the environment variable BIRDSEYE_DB.'
    )

    @cell_magic
    def eye(self, _line, cell):
        if not self.server_url:
            server.db = Database(self.db_url)
            server.Function = server.db.Function
            server.Call = server.db.Call
            server.Session = server.db.Session
            Thread(
                target=run_server,
                args=(
                    self.port,
                    self.bind_host,
                    self.show_server_output,
                ),
            ).start()

        eye.db = Database(self.db_url)

        def callback(call_id):
            """
            Always executes after the cell, whether or not an exception is raised
            in the user code.
            """
            if call_id is None:  # probably means a bug
                return

            html = HTML(templates_env.get_template('ipython_iframe.html').render(
                call_id=call_id,
                url=self.server_url.rstrip('/'),
                port=self.port,
                container_id=uuid4().hex,
            ))

            # noinspection PyTypeChecker
            display(html)

        value = eye.exec_ipython_cell(cell, callback)
        # Display the value as would happen if the %eye magic wasn't there
        return value