##// END OF EJS Templates
Added an example of how to create non-blocking widget code
Jonathan Frederic -
Show More
@@ -0,0 +1,217 b''
1 {
2 "metadata": {
3 "name": ""
4 },
5 "nbformat": 3,
6 "nbformat_minor": 0,
7 "worksheets": [
8 {
9 "cells": [
10 {
11 "cell_type": "code",
12 "collapsed": false,
13 "input": [
14 "from subprocess import Popen, PIPE\n",
15 "import fcntl\n",
16 "import os\n",
17 "\n",
18 "from IPython.html import widgets\n",
19 "from IPython.display import display"
20 ],
21 "language": "python",
22 "metadata": {},
23 "outputs": [],
24 "prompt_number": 1
25 },
26 {
27 "cell_type": "markdown",
28 "metadata": {},
29 "source": [
30 "Create the output, input, and console toggle widgets."
31 ]
32 },
33 {
34 "cell_type": "code",
35 "collapsed": false,
36 "input": [
37 "console_container = widgets.ContainerWidget(visible=False)\n",
38 "console_container.set_css('padding', '10px')\n",
39 "\n",
40 "console_style = {\n",
41 " 'font-family': 'monospace',\n",
42 " 'color': '#AAAAAA',\n",
43 " 'background': 'black',\n",
44 " 'width': '800px',\n",
45 "}\n",
46 "\n",
47 "output_box = widgets.StringWidget(parent=console_container, default_view_name='TextAreaView')\n",
48 "output_box.set_css(console_style)\n",
49 "output_box.set_css('height', '400px')\n",
50 "\n",
51 "input_box = widgets.StringWidget(parent=console_container)\n",
52 "input_box.set_css(console_style)\n",
53 "\n",
54 "toggle_button = widgets.ButtonWidget(description=\"Start Console\")\n",
55 "def toggle_console():\n",
56 " console_container.visible = not console_container.visible\n",
57 " if console_container.visible:\n",
58 " toggle_button.description=\"Stop Console\"\n",
59 " input_box.disabled = False\n",
60 " else:\n",
61 " toggle_button.description=\"Start Console\"\n",
62 "toggle_button.on_click(toggle_console)\n"
63 ],
64 "language": "python",
65 "metadata": {},
66 "outputs": [],
67 "prompt_number": 2
68 },
69 {
70 "cell_type": "markdown",
71 "metadata": {},
72 "source": [
73 "Define function to run a process without blocking the input."
74 ]
75 },
76 {
77 "cell_type": "code",
78 "collapsed": false,
79 "input": [
80 "def read_process(process, append_output):\n",
81 " \"\"\" Try to read the stdout and stderr of a process and render it using \n",
82 " the append_output method provided\n",
83 " \n",
84 " Parameters\n",
85 " ----------\n",
86 " process: Popen handle\n",
87 " append_output: method handle\n",
88 " Callback to render output. Signature of\n",
89 " append_output(output, [prefix=])\"\"\"\n",
90 " \n",
91 " try:\n",
92 " stdout = process.stdout.read()\n",
93 " if stdout is not None and len(stdout) > 0:\n",
94 " append_output(stdout)\n",
95 " except:\n",
96 " pass\n",
97 " \n",
98 " try:\n",
99 " stderr = process.stderr.read()\n",
100 " if stderr is not None and len(stderr) > 0:\n",
101 " append_output(stderr, prefix='ERR ')\n",
102 " except:\n",
103 " pass\n",
104 "\n",
105 "\n",
106 "def set_pipe_nonblocking(pipe):\n",
107 " \"\"\"Set a pipe as non-blocking\"\"\"\n",
108 " fl = fcntl.fcntl(pipe, fcntl.F_GETFL)\n",
109 " fcntl.fcntl(pipe, fcntl.F_SETFL, fl | os.O_NONBLOCK)\n",
110 "\n",
111 "\n",
112 "kernel = get_ipython().kernel\n",
113 "def run_command(command, append_output, has_user_exited=None):\n",
114 " \"\"\"Run a command asyncronously\n",
115 " \n",
116 " Parameters\n",
117 " ----------\n",
118 " command: str\n",
119 " Shell command to launch a process with.\n",
120 " append_output: method handle\n",
121 " Callback to render output. Signature of\n",
122 " append_output(output, [prefix=])\n",
123 " has_user_exited: method handle\n",
124 " Check to see if the user wants to stop the command.\n",
125 " Must return a boolean.\"\"\"\n",
126 " \n",
127 " # Echo input.\n",
128 " append_output(command, prefix='>>> ')\n",
129 " \n",
130 " # Create the process. Make sure the pipes are set as non-blocking.\n",
131 " process = Popen(command, shell=True, stdout=PIPE, stderr=PIPE)\n",
132 " set_pipe_nonblocking(process.stdout)\n",
133 " set_pipe_nonblocking(process.stderr)\n",
134 " \n",
135 " # Only continue to read from the command \n",
136 " while (has_user_exited is None or not has_user_exited()) and process.poll() is None:\n",
137 " read_process(process, append_output)\n",
138 " kernel.do_one_iteration() # Run IPython iteration. This is the code that\n",
139 " # makes this operation non-blocking. This will\n",
140 " # allow widget messages and callbacks to be \n",
141 " # processed.\n",
142 " \n",
143 " # If the process is still running, the user must have exited.\n",
144 " if process.poll() is None:\n",
145 " process.kill()\n",
146 " else:\n",
147 " read_process(process, append_output) # Read remainer\n",
148 " \n",
149 " \n",
150 " \n",
151 " "
152 ],
153 "language": "python",
154 "metadata": {},
155 "outputs": [],
156 "prompt_number": 3
157 },
158 {
159 "cell_type": "markdown",
160 "metadata": {},
161 "source": [
162 "Hook the process execution methods up to our console widgets."
163 ]
164 },
165 {
166 "cell_type": "code",
167 "collapsed": false,
168 "input": [
169 "def append_output(output, prefix=' '):\n",
170 " output_lines = output.split('\\n')\n",
171 " formatted_output = '\\n'.join([prefix + line for line in output_lines if len(line) > 0]) + '\\n'\n",
172 " output_box.value += formatted_output\n",
173 " output_box.scroll_to_bottom()\n",
174 " \n",
175 "def has_user_exited():\n",
176 " return not console_container.visible\n",
177 "\n",
178 "def handle_input(sender):\n",
179 " sender.disabled = True\n",
180 " try:\n",
181 " command = sender.value\n",
182 " sender.value = ''\n",
183 " run_command(command, append_output=append_output, has_user_exited=has_user_exited)\n",
184 " finally:\n",
185 " sender.disabled = False\n",
186 " \n",
187 "input_box.on_submit(handle_input)"
188 ],
189 "language": "python",
190 "metadata": {},
191 "outputs": [],
192 "prompt_number": 4
193 },
194 {
195 "cell_type": "markdown",
196 "metadata": {},
197 "source": [
198 "Show the console"
199 ]
200 },
201 {
202 "cell_type": "code",
203 "collapsed": false,
204 "input": [
205 "display(toggle_button)\n",
206 "display(console_container)"
207 ],
208 "language": "python",
209 "metadata": {},
210 "outputs": [],
211 "prompt_number": 5
212 }
213 ],
214 "metadata": {}
215 }
216 ]
217 } No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now