mirror of
https://github.com/jupyter/notebook.git
synced 2025-01-06 11:35:24 +08:00
Added an example of how to create non-blocking widget code
This commit is contained in:
parent
d795654251
commit
b7e1797fd2
217
examples/widgets/Nonblocking Console.ipynb
Normal file
217
examples/widgets/Nonblocking Console.ipynb
Normal file
@ -0,0 +1,217 @@
|
||||
{
|
||||
"metadata": {
|
||||
"name": ""
|
||||
},
|
||||
"nbformat": 3,
|
||||
"nbformat_minor": 0,
|
||||
"worksheets": [
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"collapsed": false,
|
||||
"input": [
|
||||
"from subprocess import Popen, PIPE\n",
|
||||
"import fcntl\n",
|
||||
"import os\n",
|
||||
"\n",
|
||||
"from IPython.html import widgets\n",
|
||||
"from IPython.display import display"
|
||||
],
|
||||
"language": "python",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"prompt_number": 1
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Create the output, input, and console toggle widgets."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"collapsed": false,
|
||||
"input": [
|
||||
"console_container = widgets.ContainerWidget(visible=False)\n",
|
||||
"console_container.set_css('padding', '10px')\n",
|
||||
"\n",
|
||||
"console_style = {\n",
|
||||
" 'font-family': 'monospace',\n",
|
||||
" 'color': '#AAAAAA',\n",
|
||||
" 'background': 'black',\n",
|
||||
" 'width': '800px',\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"output_box = widgets.StringWidget(parent=console_container, default_view_name='TextAreaView')\n",
|
||||
"output_box.set_css(console_style)\n",
|
||||
"output_box.set_css('height', '400px')\n",
|
||||
"\n",
|
||||
"input_box = widgets.StringWidget(parent=console_container)\n",
|
||||
"input_box.set_css(console_style)\n",
|
||||
"\n",
|
||||
"toggle_button = widgets.ButtonWidget(description=\"Start Console\")\n",
|
||||
"def toggle_console():\n",
|
||||
" console_container.visible = not console_container.visible\n",
|
||||
" if console_container.visible:\n",
|
||||
" toggle_button.description=\"Stop Console\"\n",
|
||||
" input_box.disabled = False\n",
|
||||
" else:\n",
|
||||
" toggle_button.description=\"Start Console\"\n",
|
||||
"toggle_button.on_click(toggle_console)\n"
|
||||
],
|
||||
"language": "python",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"prompt_number": 2
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Define function to run a process without blocking the input."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"collapsed": false,
|
||||
"input": [
|
||||
"def read_process(process, append_output):\n",
|
||||
" \"\"\" Try to read the stdout and stderr of a process and render it using \n",
|
||||
" the append_output method provided\n",
|
||||
" \n",
|
||||
" Parameters\n",
|
||||
" ----------\n",
|
||||
" process: Popen handle\n",
|
||||
" append_output: method handle\n",
|
||||
" Callback to render output. Signature of\n",
|
||||
" append_output(output, [prefix=])\"\"\"\n",
|
||||
" \n",
|
||||
" try:\n",
|
||||
" stdout = process.stdout.read()\n",
|
||||
" if stdout is not None and len(stdout) > 0:\n",
|
||||
" append_output(stdout)\n",
|
||||
" except:\n",
|
||||
" pass\n",
|
||||
" \n",
|
||||
" try:\n",
|
||||
" stderr = process.stderr.read()\n",
|
||||
" if stderr is not None and len(stderr) > 0:\n",
|
||||
" append_output(stderr, prefix='ERR ')\n",
|
||||
" except:\n",
|
||||
" pass\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def set_pipe_nonblocking(pipe):\n",
|
||||
" \"\"\"Set a pipe as non-blocking\"\"\"\n",
|
||||
" fl = fcntl.fcntl(pipe, fcntl.F_GETFL)\n",
|
||||
" fcntl.fcntl(pipe, fcntl.F_SETFL, fl | os.O_NONBLOCK)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"kernel = get_ipython().kernel\n",
|
||||
"def run_command(command, append_output, has_user_exited=None):\n",
|
||||
" \"\"\"Run a command asyncronously\n",
|
||||
" \n",
|
||||
" Parameters\n",
|
||||
" ----------\n",
|
||||
" command: str\n",
|
||||
" Shell command to launch a process with.\n",
|
||||
" append_output: method handle\n",
|
||||
" Callback to render output. Signature of\n",
|
||||
" append_output(output, [prefix=])\n",
|
||||
" has_user_exited: method handle\n",
|
||||
" Check to see if the user wants to stop the command.\n",
|
||||
" Must return a boolean.\"\"\"\n",
|
||||
" \n",
|
||||
" # Echo input.\n",
|
||||
" append_output(command, prefix='>>> ')\n",
|
||||
" \n",
|
||||
" # Create the process. Make sure the pipes are set as non-blocking.\n",
|
||||
" process = Popen(command, shell=True, stdout=PIPE, stderr=PIPE)\n",
|
||||
" set_pipe_nonblocking(process.stdout)\n",
|
||||
" set_pipe_nonblocking(process.stderr)\n",
|
||||
" \n",
|
||||
" # Only continue to read from the command \n",
|
||||
" while (has_user_exited is None or not has_user_exited()) and process.poll() is None:\n",
|
||||
" read_process(process, append_output)\n",
|
||||
" kernel.do_one_iteration() # Run IPython iteration. This is the code that\n",
|
||||
" # makes this operation non-blocking. This will\n",
|
||||
" # allow widget messages and callbacks to be \n",
|
||||
" # processed.\n",
|
||||
" \n",
|
||||
" # If the process is still running, the user must have exited.\n",
|
||||
" if process.poll() is None:\n",
|
||||
" process.kill()\n",
|
||||
" else:\n",
|
||||
" read_process(process, append_output) # Read remainer\n",
|
||||
" \n",
|
||||
" \n",
|
||||
" \n",
|
||||
" "
|
||||
],
|
||||
"language": "python",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"prompt_number": 3
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Hook the process execution methods up to our console widgets."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"collapsed": false,
|
||||
"input": [
|
||||
"def append_output(output, prefix=' '):\n",
|
||||
" output_lines = output.split('\\n')\n",
|
||||
" formatted_output = '\\n'.join([prefix + line for line in output_lines if len(line) > 0]) + '\\n'\n",
|
||||
" output_box.value += formatted_output\n",
|
||||
" output_box.scroll_to_bottom()\n",
|
||||
" \n",
|
||||
"def has_user_exited():\n",
|
||||
" return not console_container.visible\n",
|
||||
"\n",
|
||||
"def handle_input(sender):\n",
|
||||
" sender.disabled = True\n",
|
||||
" try:\n",
|
||||
" command = sender.value\n",
|
||||
" sender.value = ''\n",
|
||||
" run_command(command, append_output=append_output, has_user_exited=has_user_exited)\n",
|
||||
" finally:\n",
|
||||
" sender.disabled = False\n",
|
||||
" \n",
|
||||
"input_box.on_submit(handle_input)"
|
||||
],
|
||||
"language": "python",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"prompt_number": 4
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Show the console"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"collapsed": false,
|
||||
"input": [
|
||||
"display(toggle_button)\n",
|
||||
"display(console_container)"
|
||||
],
|
||||
"language": "python",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"prompt_number": 5
|
||||
}
|
||||
],
|
||||
"metadata": {}
|
||||
}
|
||||
]
|
||||
}
|
Loading…
Reference in New Issue
Block a user