running a tornado server within a jupyter notebook

  • Last Update :
  • Techknowledgy :

Based on my recent PR to streamz, here is something that works, similar to your idea:

class InNotebookServer(object):
   def __init__(self, port):
   self.port = port
self.loop = get_ioloop()
self.start()

def _start_server(self):
   from tornado.web
import Application, RequestHandler
from tornado.httpserver
import HTTPServer
from tornado
import gen

class Handler(RequestHandler):
   source = self

@gen.coroutine
def get(self):
   self.write('Hello World')

application = Application([
   ('/', Handler),
])
self.server = HTTPServer(application)
self.server.listen(self.port)

def start(self):
   ""
"Start HTTP server and listen"
""
self.loop.add_callback(self._start_server)

_io_loops = []

def get_ioloop():
   from tornado.ioloop
import IOLoop
import threading
if not _io_loops:
   loop = IOLoop()
thread = threading.Thread(target = loop.start)
thread.daemon = True
thread.start()
_io_loops.append(loop)
return _io_loops[0]

To call in the notebook

In [2]: server = InNotebookServer(9005)
In [3]: import requests
requests.get('http://localhost:9005')
Out[3]: <Response [200]>

There are unfortunately no ways to make it totally transparent to users – well unless you control the deployment like on a jupyterhub, and can add these lines to the IPython startups scripts that are automatically loaded. But I think the following is simple enough.

import nest_asyncio
nest_asyncio.apply()

# rest of your tornado setup and start code.

Here is how to use aiohttp in a similar way as requests.

import aiohttp
session = aiohttp.ClientSession()
await session.get('http://localhost:8889')

Example:

% % script python--bg

import tornado.ioloop
import tornado.web

class MainHandler(tornado.web.RequestHandler):
   def get(self):
   self.write("Hello, world")

def make_app():
   return tornado.web.Application([
      (r "/", MainHandler),
   ])

loop = tornado.ioloop.IOLoop.current()

app = make_app()
app.listen(8000) # 8888 was being used by jupyter in my
case

loop.start()

And then you can use requests in a separate cell to connect to the server:

import requests

print(requests.get("http://localhost:8000"))

# prints <Response [200]>

Suggestion : 2

The Jupyter notebook web application is based on a server-client structure. The notebook server uses a two-process kernel architecture based on ZeroMQ, as well as Tornado for serving HTTP requests.,By default, a notebook server runs locally at 127.0.0.1:8888 and is accessible only from localhost. You may access the notebook server from the browser using http://127.0.0.1:8888.,If you want to access your notebook server remotely via a web browser, you can do so by running a public notebook server. For optimal security when running a public notebook server, you should first secure the server with a password and SSL/HTTPS as described in Securing a notebook server.,When behind a proxy, especially if your system or browser is set to autodetect the proxy, the notebook web application might fail to connect to the server’s websockets, and present you with a warning at startup. In this case, you need to configure your system not to use the proxy for the server’s address.

$ jupyter notebook--generate - config
$ jupyter notebook password
Enter password: ** **
   Verify password: ** ** [NotebookPasswordApp] Wrote hashed password to / Users / you / .jupyter / jupyter_notebook_config.json
In[1]: from notebook.auth
import passwd
In[2]: passwd()
Enter password:
   Verify password:
   Out[2]: 'sha1:67c9e60bb8b6:9ffede0825894254b2e042ea597d771089e11aed'
c.NotebookApp.password = u 'sha1:67c9e60bb8b6:9ffede0825894254b2e042ea597d771089e11aed'
$ jupyter notebook--certfile = mycert.pem--keyfile mykey.key
$ openssl req - x509 - nodes - days 365 - newkey rsa: 2048 - keyout mykey.key - out mycert.pem

Suggestion : 3

If we are in love with Flask syntax, but miss the cool, non-blocking ability of Tornado, we can run the Flask application in a Tornado WSGIContainer like so.,Finally, we run the Flask web server. Flask supports the generation of an ad-hoc HTTP certificate and key so we don't need to explicitly put one on disk like we did in the case of Tornado.,Unlike in the Tornado case, the run command above blocks the notebook kernel from returning for as long as the web server is running. To stop the server, we need to interrupt the kernel (Kernel → Interrupt).,In this notebook, we show how to run a Tornado or Flask web server within a notebook, and access it from the public Internet. It sounds hacky, but the technique can prove useful:

1._
In[1]:

   import matplotlib.pyplot as plt
import pandas as pd
import numpy
import io
pd.options.display.mpl_style = 'default'
2._
import matplotlib.pyplot as plt
import pandas as pd
import numpy
import io
pd.options.display.mpl_style = 'default'
import matplotlib.pyplot as plt
import pandas as pd
import numpy
import io
pd.options.display.mpl_style = 'default'
1._
In[2]:

   def plot_random_numbers(n = 50):
   ''
'
Plot random numbers as a line graph.
''
'
fig, ax = plt.subplots()
# generate some random numbers
arr = numpy.random.randn(n)
ax.plot(arr)
ax.set_title('Random numbers!')
# fetch the plot bytes
output = io.BytesIO()
plt.savefig(output, format = 'png')
png = output.getvalue()
plt.close()
return png
2._
def plot_random_numbers(n = 50):
   ''
'
Plot random numbers as a line graph.
''
'
fig, ax = plt.subplots()
# generate some random numbers
arr = numpy.random.randn(n)
ax.plot(arr)
ax.set_title('Random numbers!')
# fetch the plot bytes
output = io.BytesIO()
plt.savefig(output, format = 'png')
png = output.getvalue()
plt.close()
return png
def plot_random_numbers(n = 50):
   ''
'
Plot random numbers as a line graph.
''
'
fig, ax = plt.subplots()
# generate some random numbers
arr = numpy.random.randn(n)
ax.plot(arr)
ax.set_title('Random numbers!')
# fetch the plot bytes
output = io.BytesIO()
plt.savefig(output, format = 'png')
png = output.getvalue()
plt.close()
return png
1._
In[3]:

   from IPython.display
import Image
Image(plot_random_numbers())
2._
from IPython.display
import Image
Image(plot_random_numbers())
/home/notebook / ka_env / lib / python2 .7 / site - packages / matplotlib / font_manager.py: 1282: UserWarning: findfont: Font family[u 'monospace'] not found.Falling back to Bitstream Vera Sans(prop.get_family(), self.defaultFamily[fontext]))

Out[3]:
from IPython.display
import Image
Image(plot_random_numbers())

Suggestion : 4

It can be useful to embed the Bokeh Server in a larger Tornado application, or a Jupyter notebook, and use the already existing Tornado IOloop. Here is the basis for integration of Bokeh in such a scenario:,You might want to use the Bokeh server for exploratory data analysis, possibly in a Jupyter notebook, or for a small app that you and your colleagues can run locally.,Note that the forking operation happens in the underlying Tornado server. For further information, see the Tornado docs.,The Directory format section mentions that you can override the default Jinja template, which the Bokeh server uses to generate user-facing HTML.

# myapp.py

from random
import random

from bokeh.layouts
import column
from bokeh.models
import Button
from bokeh.palettes
import RdYlBu3
from bokeh.plotting
import figure, curdoc

# create a plot and style its properties
p = figure(x_range = (0, 100), y_range = (0, 100), toolbar_location = None)
p.border_fill_color = 'black'
p.background_fill_color = 'black'
p.outline_line_color = None
p.grid.grid_line_color = None

# add a text renderer to the plot(no data yet)
r = p.text(x = [], y = [], text = [], text_color = [], text_font_size = "26px",
   text_baseline = "middle", text_align = "center")

i = 0

ds = r.data_source

# create a callback that adds a number in a random location
def callback():
   global i

# BEST PRACTICE-- - update.data in one step with a new dict
new_data = dict()
new_data['x'] = ds.data['x'] + [random() * 70 + 15]
new_data['y'] = ds.data['y'] + [random() * 70 + 15]
new_data['text_color'] = ds.data['text_color'] + [RdYlBu3[i % 3]]
new_data['text'] = ds.data['text'] + [str(i)]
ds.data = new_data

i = i + 1

# add a button widget and configure with the call back
button = Button(label = "Press Me")
button.on_click(callback)

# put the button and plot in a layout and add to the document
curdoc().add_root(column(button, p))
bokeh serve--show myapp.py
http: //localhost:5006/myapp
http: //localhost:5006/
bokeh serve--show myapp
myapp
   |
   + -- - main.py

Suggestion : 5

The IPython notebook web-application is based on a server-client structure. This server uses a two-process kernel architecture based on ZeroMQ, as well as Tornado for serving HTTP requests. By default, a notebook server runs on http://127.0.0.1:8888/ and is accessible only from localhost. This document describes how you can secure a notebook server and how to run it on a public interface.,When behind a proxy, especially if your system or browser is set to autodetect the proxy, the notebook web application might fail to connect to the server’s websockets, and present you with a warning at startup. In this case, you need to configure your system not to use the proxy for the server’s address.,Keep in mind that when you enable SSL support, you will need to access the notebook server over https://, not over plain http://. The startup message from the server prints this, but it is easy to overlook and think the server is for some reason non-responsive.,You can protect your notebook server with a simple single password by setting the NotebookApp.password configurable. You can prepare a hashed password using the function IPython.lib.security.passwd():

In[1]: from IPython.lib
import passwd
In[2]: passwd()
Enter password:
   Verify password:
   Out[2]: 'sha1:67c9e60bb8b6:9ffede0825894254b2e042ea597d771089e11aed'
# Password to use
for web authentication
c = get_config()
c.NotebookApp.password =
   u 'sha1:67c9e60bb8b6:9ffede0825894254b2e042ea597d771089e11aed'
$ ipython notebook--certfile = mycert.pem
$ openssl req - x509 - nodes - days 365 - newkey rsa: 1024 - keyout mycert.pem - out mycert.pem
$ ipython profile create nbserver
c = get_config()

# Notebook config
c.NotebookApp.certfile = u '/absolute/path/to/your/certificate/mycert.pem'
c.NotebookApp.ip = '*'
c.NotebookApp.open_browser = False
c.NotebookApp.password = u 'sha1:bcd259ccf...[your hashed password here]'
# It is a good idea to put it on a known, fixed port
c.NotebookApp.port = 9999