Giter Site home page Giter Site logo

jupyter-server / kernel_gateway Goto Github PK

View Code? Open in Web Editor NEW
491.0 39.0 129.0 894 KB

Jupyter Kernel Gateway

Home Page: http://jupyter-kernel-gateway.readthedocs.org/en/latest/

License: Other

Python 82.85% Jupyter Notebook 17.10% HTML 0.05%
jupyter jupyter-kernels

kernel_gateway's Introduction

Jupyter Kernel Gateway

Google Group PyPI version Build Status Documentation Status

Overview

Jupyter Kernel Gateway is a web server that provides headless access to Jupyter kernels. Your application communicates with the kernels remotely, through REST calls and Websockets rather than ZeroMQ messages. There are no provisions for editing notebooks through the Kernel Gateway. The following operation modes, called personalities, are supported out of the box:

  • Send code snippets for execution using the Jupyter kernel protocol over Websockets. Start and stop kernels through REST calls. This HTTP API is compatible with the respective API sections of the Jupyter Notebook server.

  • Serve HTTP requests from annotated notebook cells. The code snippets are cells of a static notebook configured in the Kernel Gateway. Annotations define which HTTP verbs and resources it supports. Incoming requests are served by executing one of the cells in a kernel.

Jupyter Kernel Gateway uses the same code as Jupyter Notebook to launch kernels in its local process/filesystem space. It can be containerized and scaled out using common technologies like tmpnb, Cloud Foundry, and Kubernetes.

Example Uses of Kernel Gateway

  • Attach a local Jupyter Notebook server to a compute cluster in the cloud running near big data (e.g., interactive gateway to Spark)
  • Enable a new breed of non-notebook web clients to provision and use kernels (e.g., web dashboards using jupyter-js-services)
  • Create microservices from notebooks using the Kernel Gateway notebook-http mode

Features

See the Features page in the documentation for a list of the Jupyter Kernel Gateway features.

Installation

Detailed installation instructions are located in the Getting Started page of the project docs. Here's a quick start using pip:

# install from pypi
pip install jupyter_kernel_gateway

# show all config options
jupyter kernelgateway --help-all

# run it with default options
jupyter kernelgateway

Contributing

The Development page includes information about setting up a development environment and typical developer tasks.

kernel_gateway's People

Contributors

akchinstc avatar applecool avatar bgerrity avatar blink1073 avatar carreau avatar cottrell avatar dleen avatar dolfinus avatar ellisonbg avatar gzuidhof avatar jtyberg avatar juliusvonkohout avatar kevin-bates avatar lresende avatar lull3rskat3r avatar minrk avatar mwouts avatar parente avatar poplav avatar pre-commit-ci[bot] avatar rgbkrk avatar ricklamers avatar rolweber avatar shiti-saxena avatar toddrme2178 avatar tschaume avatar tverbeke avatar vlaurenzano avatar willingc avatar zsailer avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

kernel_gateway's Issues

Installation does not complete in Windows / missing exe and script

I think something is broken with the jupyter gateway installation using Windows (if it is not and I am simply to clumsy to do it properly, please excuse this post and delete it...)

I am using Windows 10 with Anaconda& Python 2.7.
Following the "Try It" section on the website, I installed jupyter gateway via "pip install jupyter_kernel_gateway".
When using "jupyter kernelgateway --help-all" to test the installation, I get the error message "'kernelgateway' is not a jupyter command".
It looks like that in Windows, each legit jupyter command has its own .exe file and matching Python script - which kernelgateway has not. For me, pip install only installed the script, but with the wrong name ("jupyter-kernelgateway").

For solving this problem, I just copied the already existing "jupyter-notebook.exe" file (these files same to be identical for each command) and renamed it "jupyter-kernelgateway.exe", and renamed the existing script file "jupyter-kernelgateway" to "jupyter-kernelgateway-script.py".
Now, jupyter gateway works perfectly fine under Windows.
I am not really sure if there is indeed something wrong with the current installation script, or if it is just my computer or my too limited python skills, but I hoped that this report is to any use for you guys...

Code executed on jupyter kernel from h (hypothes.is)

Hi there,

I am a user of both jupyter notebooks and h and I think about the way the h sidebar + jupyter kernel could do a similar job to jupyter kernel + notebook.

Basically, code is written in the h sidebar, a ipynb file is sent to the kernel and executed, results and errors are sent to a temporary file that is watched by the h sidebar and displayed. Finally, if the user wants to store the code, it is stored in the h server as JSON.

A second step would be to enable the code to run remotely and to be sent to the h sidebar without a local temporary file.

This would enhance annotation/fact-checking with code and results, which is particularly useful in discussion of scientific publications.

I have not yet looked at the kernel_gateway code. Do you think it enables what I try to do? Are there limitations somewhere?

Put some client samples in the README

  1. jupyter-js-services should be mature enough now to give an example using it from NodeJS
  2. Include a Python client example too based on what we do in the tests

Support dev/test on Python 2.7

The project supports Python 2.7, but we haven't setup the automation to run the tests against 2.7. They started failing with strange exceptions on travis in PR #21. So we disabled the 2.7 test env in that PR until we can get a 2.7 test environment running locally to debug.

In jupyter-websocket mode, base handler tries to use jinja to render an error

The handler from notebook is overriding http://tornado.readthedocs.org/en/latest/web.html#tornado.web.RequestHandler.write_error and using jinja to render a pretty HTML page for a user. We should probably point it back to the most base class version (http://tornado.readthedocs.org/en/latest/_modules/tornado/web.html#RequestHandler.write_error) for consistency with notebook-http mode. That or consistently return no body or a JSON body like {"status" : same_int_as_http_status_code, "message": "whatever we can"}

ERROR:tornado.application:Uncaught exception in write_error
Traceback (most recent call last):
  File "/usr/local/lib/python3.4/dist-packages/tornado/web.py", line 1443, in _execute
    result = method(*self.path_args, **self.path_kwargs)
  File "/usr/local/lib/python3.4/dist-packages/kernel_gateway/services/kernels/handlers.py", line 31, in get
    raise tornado.web.HTTPError(404, 'Not Found')
tornado.web.HTTPError: HTTP 404: Not Found (Not Found)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.4/dist-packages/tornado/web.py", line 974, in send_error
    self.write_error(status_code, **kwargs)
  File "/usr/local/lib/python3.4/dist-packages/notebook/base/handlers.py", line 364, in write_error
    html = self.render_template('%s.html' % status_code, **ns)
  File "/usr/local/lib/python3.4/dist-packages/notebook/base/handlers.py", line 302, in render_template
    template = self.get_template(name)
  File "/usr/local/lib/python3.4/dist-packages/notebook/base/handlers.py", line 298, in get_template
    return self.settings['jinja2_env'].get_template(name)
KeyError: 'jinja2_env'

Create Sphinx docs for ReadTheDocs deploy

From jupyter/enhancement-proposals#12 (comment):

I also think it would be better to eventually move the docs to the integrated ReadTheDocs deployment; the reason isn't that it doesn't fit in a single markdown file, but rather that eventually we want users to find a comprehensive and coherent set of docs on that site. If key pieces of the architecture only have standalone READMEs on github, it's harder for the users to get the whole project-wide picture.

Option to expose notebook-http endpoints as swagger doc

So developers know what's available.

  • well-known endpoint like /_api/spec or some such. (The underscore indicates this is a API provided by the kernel gateway itself, not the notebook, and putting it under spec indicates it's the specification for the API and leaves us room to expose other things under /_api in the future.)
  • endpoint just returns the swagger JSON, not a rendering of it (Render should be done by external tools.)

Option to enable kernel list

Getting a list of all running kernel IDs should be considered an admin capability in many scenarios. The server should default to not supporting GET /api/kernels (conservative, more secure). If the user specifies --KernelGatewayApp.list_kernels on gateway start, the server should expose the endpoint.

Switch to traitlets decorator syntax

Avoid all the:

/home/travis/build/jupyter-incubator/kernel_gateway/kernel_gateway/gatewayapp.py:68: DeprecationWarning: KernelGatewayApp._base_url_default is deprecated: use @default decorator instead.
  def _base_url_default(self):

that results from using the old syntax with traitlets 4.1.

Running kernelgateway produces: ImportError: No module named nbformat

Tried to follow installation instructions using pip. Building on Ubuntu 14.04 machine with Python 2.7.6 and pip 1.5.4. I'm wondering if this has to do with zmq as the first try at installing I did not have the header files on my system which I later installed (libzmq-dev).

administrator@etc04:~/kernel_gateway$ sudo pip install jupyter_kernel_gateway
Downloading/unpacking jupyter-kernel-gateway
  Downloading jupyter_kernel_gateway-0.4.0-py2.py3-none-any.whl
Requirement already satisfied (use --upgrade to upgrade): jupyter-core>=4.0,<5.0 in /usr/local/lib/python2.7/dist-packages (from jupyter-kernel-gateway)
Requirement already satisfied (use --upgrade to upgrade): jupyter-client>=4.0,<5.0 in /usr/local/lib/python2.7/dist-packages (from jupyter-kernel-gateway)
Requirement already satisfied (use --upgrade to upgrade): requests>=2.7,<3.0 in /usr/local/lib/python2.7/dist-packages (from jupyter-kernel-gateway)
Requirement already satisfied (use --upgrade to upgrade): notebook>=4.0,<5.0 in /usr/local/lib/python2.7/dist-packages (from jupyter-kernel-gateway)
Installing collected packages: jupyter-kernel-gateway
Successfully installed jupyter-kernel-gateway
Cleaning up...
administrator@etc04:~/kernel_gateway$ jupyter kernelgateway
Traceback (most recent call last):
  File "/usr/local/bin/jupyter-kernelgateway", line 7, in <module>
    from kernel_gateway import launch_instance
  File "/usr/local/lib/python2.7/dist-packages/kernel_gateway/__init__.py", line 4, in <module>
    from .gatewayapp import launch_instance
  File "/usr/local/lib/python2.7/dist-packages/kernel_gateway/gatewayapp.py", line 6, in <module>
    import nbformat
ImportError: No module named nbformat
administrator@etc04:~/kernel_gateway$

Option to pre-seed kernel memory

Given a URI of a notebook, execute its contents on launched kernels, either immediately or when the first websocket connection is established.

Proof point: See if notebook-http mode can be made a "plugin"

Right now, the code for the Jupyter Notebook APIs (jupyter-websocket mode) is mixed in with the code for the notebook-defined REST API (notebook-http mode). This was done for convenience during incubation to prove that KG could support other means (transports, APIs, and protocols) for working with kernels. Interestingly enough, I had a conversation the other day that resulted in my thinking about how kernels might operate if hooked to a message queue (e.g., Rabbit MQ). Immediately, I wondered if such a setup could be made possible via the kernel gateway.

I certainly don't want to keep hacking support for additional kernel comm mechanisms into the KG code base. I wonder instead of an API could be defined to allow such things to be plugged-in easily. My hesitation is that not everything will so easily reuse the APIs and classes from the notebook server like the microservice approach did.

I'd like to take a pass at turning the notebook-http mode, the jupyter-websocket mode, and maybe even the message-queue idea into "plugins" (for lack of a better word) to the kernel gateway. If there's common ground, it'll improve the extensibility and maintainability of the project. If there's very little commonality beyond the boilerplate CLI, it may suggest each of these deserves to be in its own project.

Just writing this down. Not planning to jump on it right away.


From discussion with @nitind:

Clarifying the changes being implemented:

  • changing "API" parameter from a string to a fully qualified module name (PR #173)
  • moving the current jupyter-websocket and notebook-http functionality into their own modules, not buried in services/ (PR #173)
  • relocate functionality specific to either mode into their modules (PR #173)
  • update documentation to call "modes" personalities and describe the steps to implement one (e.g., the factory function, the package, how to pass it to KG)
  • relocate traitlets specific to one mode into its module (e.g. KG_LIST_KERNELS)

/cc @fperez @minrk

Escaping Double Quotes In Code Is Causing Failures

When performing requests with fields containing " I am never seeing a response come back because an exception is happening due to a syntax error. I am seeing this specifically with the If-None-Match header. The problem arises from this function.

The case stated above is subtle because an initial request with no cache will go through because the field is not present. For example the first code is:

REQUEST = "{\"body\": \"\", \"headers\": {\"Upgrade-Insecure-Requests\": \"1\", \"Accept\": \"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8\", \"Host\": \"192.168.99.100:8888\", \"User-Agent\": \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36\", \"Cache-Control\": \"max-age=0\", \"Accept-Language\": \"en-US,en;q=0.8,fr;q=0.6\", \"Connection\": \"keep-alive\", \"Accept-Encoding\": \"gzip, deflate, sdch\"}, \"args\": {}, \"path\": {}}"

Then subsequent code calls are like this:

REQUEST = "{\"body\": \"\", \"headers\": {\"Upgrade-Insecure-Requests\": \"1\", \"Cache-Control\": \"max-age=0\", \"Accept\": \"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8\", \"Host\": \"192.168.99.100:8888\", \"User-Agent\": \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36\", \"If-None-Match\": \"\\"208a0559a08279853d9f3d0c03723dd7b783fe8f\\"\", \"Accept-Language\": \"en-US,en;q=0.8,fr;q=0.6\", \"Connection\": \"keep-alive\", \"Accept-Encoding\": \"gzip, deflate, sdch\"}, \"args\": {}, \"path\": {}}"

Override another use of jinja

See #71 for how we fixed in the past.

kernel_gateway_1 | [KernelGatewayApp] WARNING | Blocking Cross Origin API request.  Origin: http://192.168.99.100:3000, Host: kernel_gateway:8888
kernel_gateway_1 | ERROR:tornado.application:Uncaught exception in write_error
kernel_gateway_1 | Traceback (most recent call last):
kernel_gateway_1 |   File "/opt/conda/lib/python3.4/site-packages/tornado/web.py", line 1422, in _execute
kernel_gateway_1 |     result = self.prepare()
kernel_gateway_1 |   File "/opt/conda/lib/python3.4/site-packages/kernel_gateway/mixins.py", line 48, in prepare
kernel_gateway_1 |     return super(TokenAuthorizationMixin, self).prepare()
kernel_gateway_1 |   File "/opt/conda/lib/python3.4/site-packages/notebook/base/handlers.py", line 377, in prepare
kernel_gateway_1 |     raise web.HTTPError(404)
kernel_gateway_1 | tornado.web.HTTPError: HTTP 404: Not Found
kernel_gateway_1 |
kernel_gateway_1 | During handling of the above exception, another exception occurred:
kernel_gateway_1 |
kernel_gateway_1 | Traceback (most recent call last):
kernel_gateway_1 |   File "/opt/conda/lib/python3.4/site-packages/tornado/web.py", line 974, in send_error
kernel_gateway_1 |     self.write_error(status_code, **kwargs)
kernel_gateway_1 |   File "/opt/conda/lib/python3.4/site-packages/notebook/base/handlers.py", line 364, in write_error
kernel_gateway_1 |     html = self.render_template('%s.html' % status_code, **ns)
kernel_gateway_1 |   File "/opt/conda/lib/python3.4/site-packages/notebook/base/handlers.py", line 302, in render_template
kernel_gateway_1 |     template = self.get_template(name)
kernel_gateway_1 |   File "/opt/conda/lib/python3.4/site-packages/notebook/base/handlers.py", line 298, in get_template
kernel_gateway_1 |     return self.settings['jinja2_env'].get_template(name)
kernel_gateway_1 | KeyError: 'jinja2_env'

Option(s) to control channel access

Option to limit access to one or more Jupyter protocol channels: shell, iopub, control. Maybe to limit to specific comm channel names within shell too.

Use case: Restricting kernel access to listen-only.

Invalid Options Should Terminate App

It would be helpful if the application would terminate when receiving invalid command line args. For example, I sent --KernelGatewatApp.api instead of --KernelGatewayApp.api. This will help user error when deploying kernel gateway.

Filter warnings from output

Latest jupyter/datascience-notebook applied to Python scotch demo. Note the cruft at the end.

{"recommendations": [{"Similarity": 0.9621567374083243, "Smoky": 2, "Sweetness": 2, "Winey": 1, "Body": 3, "Name": "Benrinnes", "Spicy": 1, "Tobacco": 0, "Medicinal": 0, "Honey": 3, "Malty": 3, "Nutty": 2, "Fruity": 2}, {"Similarity": 0.9536876128704646, "Smoky": 2, "Sweetness": 2, "Winey": 1, "Body": 2, "Name": "Benromach", "Spicy": 2, "Tobacco": 0, "Medicinal": 0, "Honey": 2, "Malty": 2, "Nutty": 2, "Fruity": 2}, {"Similarity": 0.946457414634764, "Smoky": 2, "Sweetness": 2, "Winey": 0, "Body": 4, "Name": "BenNevis", "Spicy": 2, "Tobacco": 0, "Medicinal": 0, "Honey": 2, "Malty": 2, "Nutty": 2, "Fruity": 2}, {"Similarity": 0.9411239481143201, "Smoky": 1, "Sweetness": 2, "Winey": 0, "Body": 2, "Name": "Benriach", "Spicy": 2, "Tobacco": 0, "Medicinal": 0, "Honey": 2, "Malty": 2, "Nutty": 0, "Fruity": 3}, {"Similarity": 0.937137026507657, "Smoky": 2, "Sweetness": 3, "Winey": 0, "Body": 1, "Name": "AnCnoc", "Spicy": 0, "Tobacco": 0, "Medicinal": 0, "Honey": 2, "Malty": 2, "Nutty": 2, "Fruity": 3}], "for": "Dalwhinnie"}
/opt/conda/lib/python3.4/site-packages/ipykernel/__main__.py:7: FutureWarning: order is deprecated, use sort_values(...)

We could say it's the notebook developer's job to make sure nothing like this gets emitted. But, as I just found, sometimes you just want to run an existing notebook and are greeted by junk like this.

We should look how we're dealing with error messages and the like.

Proof point: Show Jupyter Notebook launching kernels remotely

To prove out the concept, try the following in a personal fork somewhere and let's see how it goes. The changes are something like so:

  • Notebook frontend JavaScript communicates with its backend Jupyter Notebook server to CRUD notebooks on disk and manage notebook sessions
  • Notebook frontend JS gets the remote kernel gateway URL via a config option that passes through to it somehow. (There must be a related code path already because the frontend is aware of the things like the base_url.)
  • Notebook frrontend JavaScript communicates with a remote kernel gateway server to CRUD kernels and communicate with them via Websockets

It sounds straightforward, but there are unknowns around how tightly coupled sessions are to kernels in the local notebook backend. Can the two be divorced so that the sessions are maintained locally in the notebook server and the kernels remotely in the kernel gateway?

/cc @jtyberg

Option to pre-spawn kernels

Launch a number of kernels on gateway start.

Use case: quick-and-dirty pooling on a single host or two-tiered pooling if the gateway is running within a cluster (e.g., binder) and each gateway container needs to service multiple kernels.

Cell Code Needs To Set HTTP Response Code

When implementing the Pet Store Swagger Spec, jupyter/kernel_gateway_demos#2, I need the ability to set the status code for the HTTP response. This is needed because the Swagger Petstore API requires multiple statuses for requests. And in general this will be needed to provide mature and proper functionality to developers using the kernel gateway.

I have two ideas for how this could be implemented, but there may be more. I have highlighted these ideas in upyter-incubator/kernel_gateway#46 and listed the advantages and disadvantages, but will document the differences for this use case here.

Implementation 1: Display Data

We can utilize display data to set the response status. An example in python would be:

# GET /foo/bar
from IPython import display
display.publish_display_data({
    'http-response/status' : 200
})

The only implementation needed in the kernel gateway would be to do the following:

  1. In the kernel gateway, check if there is an 'http-response/status' in the display data
  2. If there is, set the response status code in the tornado handler, otherwise default to our current strategy

Implementation 2: Comm API

We can provide a comm channel API which will allow for objects to be created which will relay the response information to the kernel gateway. An example implementation could look like this:

from KernelGateway import Response
# GET /foo/bar
Response('foo', status=200)

Ignore Whitespace In API Paths

When there is a space trailing a path or a path parameter at the end the endpoint registration will not register properly. Examples include:

# GET /foo/:bar 
# GET /foo/:bar/quo 

Move most of the examples in etc/ to kernel_gateway_demos

If they're not needed for testing, they probably make more sense over in the demos repo. The README should get updated to point to the demos repo (e.g., the big client example should be removed from the README and links should be put in their place). Each demo in the kernel_gateway repo should be in a new subfolder in the kernel_gateway_demos repo.

Set env vars for kernels

Set KERNEL_GATEWAY=1 in the environment of all kernels launched by the server.

Use case: Want to include code meant for testing a notebook in the notebook server. Later, want to use the --seed-uri to preseed kernels with the content of that notebook but don't want the testing code to execute.

Pass HTTP Headers To Code Cells

The headers from the HTTP request need to be passed along to the REQUEST object for cell execution. Things that need to be done:

  • Pass the headers through to the cell execution via REQUEST
  • Update the example notebooks to show access of headers
  • Update the documentation to document access of headers

Port conflict during test run

Caught this on my local box. Could be the culprit causing repeat failures and timeouts on travis.

~/p/j/kernel_gateway ❯❯❯ make test                                                                       master ✭ ◼
docker run -it --rm --workdir '/srv/kernel_gateway' -e PYTHONPATH='/srv/kernel_gateway' -v `pwd`:/srv/kernel_gateway  jupyter/pyspark-notebook:a388c4a66fd4 bash -c " python -B -m unittest discover"
.........................../opt/conda/lib/python3.4/imp.py:32: PendingDeprecationWarning: the imp module is deprecated in favour of importlib; see the module's documentation for alternative uses
  PendingDeprecationWarning)
.....---------------------------------------------------------------------------
ZMQError                                  Traceback (most recent call last)
/opt/conda/lib/python3.4/runpy.py in _run_module_as_main(mod_name='ipykernel.__main__', alter_argv=1)
    168         sys.argv[0] = mod_spec.origin
    169     return _run_code(code, main_globals, None,
--> 170                      "__main__", mod_spec)
        mod_spec = ModuleSpec(name='ipykernel.__main__', loader=<_frozen_importlib.SourceFileLoader object at 0x7f0be0bc8d30>, origin='/opt/conda/lib/python3.4/site-packages/ipykernel/__main__.py')
    171
    172 def run_module(mod_name, init_globals=None,

/opt/conda/lib/python3.4/runpy.py in _run_code(code=<code object <module> at 0x7f0be0c48f60, file "/...3.4/site-packages/ipykernel/__main__.py", line 1>, run_globals={'__builtins__': <module 'builtins' (built-in)>, '__cached__': '/opt/conda/lib/python3.4/site-packages/ipykernel/__pycache__/__main__.cpython-34.pyc', '__doc__': None, '__file__': '/opt/conda/lib/python3.4/site-packages/ipykernel/__main__.py', '__loader__': <_frozen_importlib.SourceFileLoader object>, '__name__': '__main__', '__package__': 'ipykernel', '__spec__': ModuleSpec(name='ipykernel.__main__', loader=<_f...b/python3.4/site-packages/ipykernel/__main__.py'), 'app': <module 'ipykernel.kernelapp' from '/opt/conda/lib/python3.4/site-packages/ipykernel/kernelapp.py'>}, init_globals=None, mod_name='__main__', mod_spec=ModuleSpec(name='ipykernel.__main__', loader=<_f...b/python3.4/site-packages/ipykernel/__main__.py'), pkg_name='ipykernel', script_name=None)
     83                        __package__ = pkg_name,
     84                        __spec__ = mod_spec)
---> 85     exec(code, run_globals)
        global exec = undefined
        code = <code object <module> at 0x7f0be0c48f60, file "/opt/conda/lib/python3.4/site-packages/ipykernel/__main__.py", line 1>
        run_globals = {'app': <module 'ipykernel.kernelapp' from '/opt/conda/lib/python3.4/site-packages/ipykernel/kernelapp.py'>, '__doc__': None, '__loader__': <_frozen_importlib.SourceFileLoader object at 0x7f0be0bc8d30>, '__package__': 'ipykernel', '__file__': '/opt/conda/lib/python3.4/site-packages/ipykernel/__main__.py', '__builtins__': <module 'builtins' (built-in)>, '__spec__': ModuleSpec(name='ipykernel.__main__', loader=<_frozen_importlib.SourceFileLoader object at 0x7f0be0bc8d30>, origin='/opt/conda/lib/python3.4/site-packages/ipykernel/__main__.py'), '__cached__': '/opt/conda/lib/python3.4/site-packages/ipykernel/__pycache__/__main__.cpython-34.pyc', '__name__': '__main__'}
     86     return run_globals
     87

/opt/conda/lib/python3.4/site-packages/ipykernel/__main__.py in <module>()
      1 if __name__ == '__main__':
      2     from ipykernel import kernelapp as app
----> 3     app.launch_new_instance()
        global app.launch_new_instance = <bound method MetaHasTraits.launch_instance of <class 'ipykernel.kernelapp.IPKernelApp'>>

/opt/conda/lib/python3.4/site-packages/traitlets/config/application.py in launch_instance(cls=<class 'ipykernel.kernelapp.IPKernelApp'>, argv=None, **kwargs={})
    589         """
    590         app = cls.instance(**kwargs)
--> 591         app.initialize(argv)
        app.initialize = <bound method IPKernelApp.initialize of <ipykernel.kernelapp.IPKernelApp object at 0x7f0be0c66fd0>>
        argv = None
    592         app.start()
    593

/opt/conda/lib/python3.4/site-packages/ipykernel/kernelapp.py in initialize(self=<ipykernel.kernelapp.IPKernelApp object>, argv=None)

/opt/conda/lib/python3.4/site-packages/traitlets/config/application.py in catch_config_error(method=<function IPKernelApp.initialize>, app=<ipykernel.kernelapp.IPKernelApp object>, *args=(None,), **kwargs={})
     73     """
     74     try:
---> 75         return method(app, *args, **kwargs)
        method = <function IPKernelApp.initialize at 0x7f0bd7abe048>
        app = <ipykernel.kernelapp.IPKernelApp object at 0x7f0be0c66fd0>
        args = (None,)
        kwargs = {}
     76     except (TraitError, ArgumentError) as e:
     77         app.print_help()

/opt/conda/lib/python3.4/site-packages/ipykernel/kernelapp.py in initialize(self=<ipykernel.kernelapp.IPKernelApp object>, argv=None)
    371         self.init_connection_file()
    372         self.init_poller()
--> 373         self.init_sockets()
        self.init_sockets = <bound method IPKernelApp.init_sockets of <ipykernel.kernelapp.IPKernelApp object at 0x7f0be0c66fd0>>
    374         self.init_heartbeat()
    375         # writing/displaying connection info must be *after* init_sockets/heartbeat

/opt/conda/lib/python3.4/site-packages/ipykernel/kernelapp.py in init_sockets(self=<ipykernel.kernelapp.IPKernelApp object>)
    237         self.stdin_socket = context.socket(zmq.ROUTER)
    238         self.stdin_socket.linger = 1000
--> 239         self.stdin_port = self._bind_socket(self.stdin_socket, self.stdin_port)
        self.stdin_port = 42574
        self._bind_socket = <bound method IPKernelApp._bind_socket of <ipykernel.kernelapp.IPKernelApp object at 0x7f0be0c66fd0>>
        self.stdin_socket = <zmq.sugar.socket.Socket object at 0x7f0bd7a769a8>
    240         self.log.debug("stdin ROUTER Channel on port: %i" % self.stdin_port)
    241

/opt/conda/lib/python3.4/site-packages/ipykernel/kernelapp.py in _bind_socket(self=<ipykernel.kernelapp.IPKernelApp object>, s=<zmq.sugar.socket.Socket object>, port=42574)
    169                 port = s.bind_to_random_port(iface)
    170             else:
--> 171                 s.bind("tcp://%s:%i" % (self.ip, port))
        s.bind = <built-in method bind of Socket object at 0x7f0bd7a769a8>
        self.ip = '127.0.0.1'
        port = 42574
    172         elif self.transport == 'ipc':
    173             if port <= 0:

zmq/backend/cython/socket.pyx in zmq.backend.cython.socket.Socket.bind (zmq/backend/cython/socket.c:4824)()

/opt/conda/lib/python3.4/site-packages/zmq/backend/cython/checkrc.pxd in zmq.backend.cython.checkrc._check_rc (zmq/backend/cython/socket.c:7055)()
     23         else:
     24             from zmq.error import ZMQError
---> 25             raise ZMQError(errno)
        global ZMQError = <class 'zmq.error.ZMQError'>
        global errno = undefined
     26     return 0

ZMQError: Address already in use
^CTraceback (most recent call last):
  File "/opt/conda/lib/python3.4/unittest/case.py", line 573, in run
    self.setUp()
  File "/opt/conda/lib/python3.4/site-packages/tornado/testing.py", line 355, in setUp
    self._app = self.get_app()
  File "/srv/kernel_gateway/kernel_gateway/tests/test_gatewayapp.py", line 84, in get_app
    self.app.init_configurables()
  File "/srv/kernel_gateway/kernel_gateway/gatewayapp.py", line 240, in init_configurables
    self.kernel_pool = KernelPool(self.prespawn_count, self.kernel_manager)
  File "/srv/kernel_gateway/kernel_gateway/services/kernels/pool.py", line 27, in __init__
    kernel_id = kernel_manager.start_kernel(kernel_name=self.kernel_manager.parent.seed_notebook['metadata']['kernelspec']['name'])
  File "/srv/kernel_gateway/kernel_gateway/services/kernels/manager.py", line 59, in start_kernel
    client.wait_for_ready()
  File "/opt/conda/lib/python3.4/site-packages/jupyter_client/blocking/client.py", line 22, in wait_for_ready
    msg = self.shell_channel.get_msg(block=True)
  File "/opt/conda/lib/python3.4/site-packages/jupyter_client/blocking/channels.py", line 50, in get_msg
    ready = self.socket.poll(timeout)
  File "/opt/conda/lib/python3.4/site-packages/zmq/sugar/socket.py", line 501, in poll
    evts = dict(p.poll(timeout))
  File "/opt/conda/lib/python3.4/site-packages/zmq/sugar/poll.py", line 101, in poll
    return zmq_poll(self.sockets, timeout=timeout)
  File "zmq/backend/cython/_poll.pyx", line 115, in zmq.backend.cython._poll.zmq_poll (zmq/backend/cython/_poll.c:1625)
  File "zmq/backend/cython/checkrc.pxd", line 12, in zmq.backend.cython.checkrc._check_rc (zmq/backend/cython/_poll.c:1958)
KeyboardInterrupt

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/opt/conda/lib/python3.4/runpy.py", line 170, in _run_module_as_main
    "__main__", mod_spec)
  File "/opt/conda/lib/python3.4/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "/opt/conda/lib/python3.4/unittest/__main__.py", line 18, in <module>
    main(module=None)
  File "/opt/conda/lib/python3.4/unittest/main.py", line 93, in __init__
    self.runTests()
  File "/opt/conda/lib/python3.4/unittest/main.py", line 244, in runTests
    self.result = testRunner.run(self.test)
  File "/opt/conda/lib/python3.4/unittest/runner.py", line 168, in run
    test(result)
  File "/opt/conda/lib/python3.4/unittest/suite.py", line 84, in __call__
    return self.run(*args, **kwds)
  File "/opt/conda/lib/python3.4/unittest/suite.py", line 122, in run
    test(result)
  File "/opt/conda/lib/python3.4/unittest/suite.py", line 84, in __call__
    return self.run(*args, **kwds)
  File "/opt/conda/lib/python3.4/unittest/suite.py", line 122, in run
    test(result)
  File "/opt/conda/lib/python3.4/unittest/suite.py", line 84, in __call__
    return self.run(*args, **kwds)
  File "/opt/conda/lib/python3.4/unittest/suite.py", line 122, in run
    test(result)
  File "/opt/conda/lib/python3.4/unittest/case.py", line 625, in __call__
    return self.run(*args, **kwds)
  File "/opt/conda/lib/python3.4/site-packages/tornado/testing.py", line 265, in run
    self.__rethrow()
  File "/opt/conda/lib/python3.4/site-packages/tornado/testing.py", line 256, in __rethrow
    raise_exc_info(failure)
  File "<string>", line 3, in raise_exc_info
  File "/opt/conda/lib/python3.4/site-packages/tornado/testing.py", line 260, in run
    super(AsyncTestCase, self).run(result)
  File "/opt/conda/lib/python3.4/site-packages/tornado/testing.py", line 564, in run
    super(LogTrapTestCase, self).run(result)
  File "/opt/conda/lib/python3.4/unittest/case.py", line 573, in run
    self.setUp()
KeyboardInterrupt
sys:1: ResourceWarning: unclosed file <_io.TextIOWrapper name='/dev/null' mode='w' encoding='ANSI_X3.4-1968'>
/opt/conda/lib/python3.4/importlib/_bootstrap.py:2150: ImportWarning: sys.meta_path is empty
sys:1: ResourceWarning: unclosed <socket.socket fd=6, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=6, laddr=('127.0.0.1', 41263)>
^C%

Need ability to identify dormant kernels to quiesce them

In the context of a service that needs to efficiently manage jupyter-kernel-gateways for users, it is necessary to be able to monitor kernels to ascertain a sufficient period of inactivity, thereby triggering kernel shutdown.

In the bigger picture, where a kernel-gateway is provisioned for each user, it is necessary to quiesce that user's kernel-gateway when they've "stepped away" from the API and left their kernels inactive for an extended period of time; gateway can be brought back up when they return.

Since kernels can drive work outside of jupyter/gateway, there's more involved than just monitoring the kernel-gateway. But for the kernel-gateway, must be able to monitor for last real activity in a kernel, say timestamp. So, it would help to have an API that would return, for each kernel provisioned, the last time there was "activity" through the kernel. Not sure about the best way to handle no kernels; if nothing returned, no way to determine how long since kernels were running unless state handled outside of the gateway.

Options to enable HTTP access to kernels

I've got it in my head that the kernel gateway can become a vehicle for providing many different ways of accessing kernels, both in terms of API and protocol. Right now, it supports HTTP to the notebook kernel CRUD API and Websockets carrying Jupyter protocol messages. We've talked about limiting channel access and doing HTTP to the notebook kernel CRUD API and SSE carrying Jupyter protocol iopub messages only.

I've got this (semi-crazy) idea that we could also optionally:

  1. Turn off the websocket / kernel CRUD API
  2. Have the kernel gateway read cell annotations from a notebook file on startup (option already supported)
  3. Use those annotations to define HTTP endpoints referring to code cell to execute when they're invoked (new)
  4. When one of those endpoints receives an HTTP request, have the kernel gateway send the request body/query args to the kernel (e.g., by executing them in an assignment statement, ...)
  5. After sending the args, have the kernel gateway execute the cell code associated with the HTTP endpoint on the kernel and read its output (e.g., iopub stream message, ...)
  6. Respond to the HTTP request with the output and/or error status appropriately

Pack the notebook + kernel gateway up in a container, scale that container image, and you've got a to use notebooks as a place to quickly prototype microservices that run on kernels.

Option to set default kernel

Have a command line option --default-language that sets the default kernel to spawn if a request for a kernel (POST) does not explicitly state a kernel language name.

README section about how to use microservices feature

  • update description at the top, it's not just providing the jupyter API and websockets anymore
  • new bullet in "what it provides" about
  • new section with more info about the notebook-http mode
  • link to github view of the api_intro notebook in that section
  • document the make command structure for running with one of the notebooks in etc like:
make dev ARGS="--KernelGatewayApp.api='notebook-http' \
--KernelGatewayApp.seed_uri=/srv/kernel_gateway/etc/api_examples/scotch_api.ipynb"

Make the test suite prettier, add coverage

I'm not spending many cycles on keeping the test suite beautiful at the moment. Tracking warts here.

  • split into multiple modules, not one giant test_gatewayapp module; tests for the jupyter-websocket mode vs the notebook-http mode are a first order candidate for a split
  • try to fix the hangs on travis (not fixed, but rather opened upstream #94)
  • some test cases are not checking all endpoints when they should be; fix these using loops or by making explicit calls to all endpoints.
  • enable code coverage report

Request Code is not properly interpreted by the Julia REPL

The issue arises when using the kernel gateway in notebook-http mode using a Julia kernel.

In the kernel_gateway/handler, request code is being executed before source code, where the source code is dependent on the execution of the request code. The Julia REPL treats strings differently than the other kernels like R and Python. Due to Julia treating strings differently the request code will not be properly assigned resulting in errors in the source code. Specifically, Julia does not support ' for strings. An example of the issue is apparent in the following files/comparisons of the REPLs.

julia_r_python_repl_json

julia_string

Properly Handle Form Submissions

When receiving bodies from a form submission. We need to, at least on a first pass, handle parsing the values of the form. These values should then be propagated to the code execution cell via the REQUEST object.

Cell Code Needs To Set HTTP Response Metadata

When implementing the Pet Store Swagger Spec, jupyter/kernel_gateway_demos#2, I need the ability to set the metadata for the HTTP response. This is needed because the Swagger Petstore API allows for responses in JSON or xml and has various HTTP status codes..

Specially annotated cell should be able to set the response metadata by printing a well know json structure.

Support lightweight request distribution for notebook-http mode

  • don't hardcode 1 kernel to spawn on start, respect the prespawn_count parameter
  • on every request, round-robin through the list of kernels
  • make communication with a given kernel asynchronous to avoid blocking the tornado handling of other incoming requests but ensure the kernel remains "locked" from use by other requests until the current request is fully handled (hard)

Use case: want to deploy a single container with kernel gateway and have it scale with a process pool for small to medium loads without the cost of scaling at the container level associated with handling much larger loads

Pass Configuration Values To Notebook

I am thinking about how you could configure an application in notebook-http mode. Initially, I think we could add a command line option, say --KernelGatewatApp.custom=foo:bar, which can generate a json string representing the config value.

{
  "foo" : "bar"
}

There could then be a config cell which will parse a variable called CONFIG, which is the json structure we defined. An example, in python, would be:

# Config
configuration = json.loads(CONFIG)
print(configuration['foo'])

Support websocket connections in notebook-http mode

Client connects to HTTP endpoint which has been declared as a websocket endpoint in the notebook. Kernel gateway listens for WS connections at that endpoint. Messages received from client to that endpoint cause execution of the cell code backing that endpoint. Response from the cell is pushed back to the client over the Websocket.

Question: What does push from kernel to client look like? Can we do that too?

ActivityManager tuneup

  • Instantiate singleton in gatewayapp for consistency with all the other managers. Put it in the app settings and ref it from there, not via a module import.
  • No need for dummy_map. Just make the global defaults a dict.
  • ignore grows endlessly
  • Instead of checking kg_list_kernels everywhere that calls ActivityManager methods, just check it in the ActivityManager instance itself. (Easy once it gets instantiated in the gatewayapp and can get the settings.)
  • Calls to the activity manager should probably happen after the action takes place in case it fails.

Properly Handle Form Submissions

When receiving bodies from a form submission. We need to, at least on a first pass, handle parsing the values of the form. These values should then be propagated to the code execution cell via the REQUEST object.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.