Copyright | (c) Andrew Gibiansky, 2016 |
---|---|
License | MIT |
Maintainer | andrew.gibiansky@gmail.com |
Stability | stable |
Portability | POSIX |
Safe Haskell | None |
Language | Haskell2010 |
This module provides an easy API for writing Jupyter clients. Jupyter clients (also commonly called frontends) are programs which communicate with Jupyter kernels, possibly starting them and then sending them requests over the ZeroMQ-based messaging protocol. Examples of Jupyter clients include the Jupyter console, the QtConsole, and the http://jupyter.org/.
Communication with clients is done in the Client
monad, which is a thin wrapper over IO
which
maintains a small bit of required state to identify a running kernel and the sockets on which to
communicate with it. The initial state and connection information is supplied when you use runClient
,
which requires connection information and the Client
action to run.
The runClient
function also requires a set of ClientHandlers
, which are callbacks that get called
when the kernel sends any sort of message to the client (KernelRequest
s, KernelOutput
s, and Comm
s).
These functions can be used quite succinctly to communicate with external clients. For example, the
following code connects to an installed Python kernel (the ipykernel
package must be installed):
import Control.Monad.IO.Class (MonadIO(liftIO)) import System.Process (spawnProcess) import Jupyter.Client import Jupyter.Messages main :: IO () main =runClient
Nothing Nothing handlers $ profile -> do -- Theprofile
provided is a generatedKernelProfile
-- that the client will connect to. Start an IPython kernel -- that listens on that profile. liftIO $ dowriteProfile
profile "profile.json"spawnProcess
"python" ["-m", "ipykernel", "-f", "profile.json"] -- Find out info about the kernel by sending it a kernel info request. connection <-connectKernel
reply <-sendClientRequest
connectionKernelInfoRequest
liftIO $ print reply handlers :: ClientHandlers handlers = ClientHandlers { -- Do nothing on comm messagescommHandler
=defaultClientCommHandler
, -- Return a fake stdin string if asked for stdinkernelRequestHandler
= _ req -> case req ofInputRequest
{} -> return $InputReply
"Fake Stdin", -- Do nothing on kernel outputskernelOutputHandler
= _ _ -> return () }
A more detailed example is provided in the
examples/client-kernel-info
directory, and more information about the client and kernel interfaces can be found on the jupyter
README.
- data Client a
- runClient :: Maybe KernelProfile -> Maybe Username -> ClientHandlers -> (KernelProfile -> Client a) -> IO a
- connectKernel :: Client KernelConnection
- sendClientRequest :: KernelConnection -> ClientRequest -> Client KernelReply
- sendClientComm :: KernelConnection -> Comm -> Client ()
- data ClientHandlers = ClientHandlers {
- kernelRequestHandler :: (Comm -> IO ()) -> KernelRequest -> IO ClientReply
- commHandler :: (Comm -> IO ()) -> Comm -> IO ()
- kernelOutputHandler :: (Comm -> IO ()) -> KernelOutput -> IO ()
- defaultClientCommHandler :: (Comm -> IO ()) -> Comm -> IO ()
- data KernelConnection
- writeProfile :: KernelProfile -> FilePath -> IO ()
- data Kernelspec = Kernelspec {}
- findKernel :: Text -> IO (Maybe Kernelspec)
- findKernels :: IO [Kernelspec]
Communicating with Clients
A client action, representing a computation in which communication happens with a Jupyter client.
Use sendClientRequest
and sendClientComm
to construct Client
values, the Monad
interface to
manipulate them, and runClient
to supply all needed connection info and run the action.
:: Maybe KernelProfile | Optionally, a |
-> Maybe Username | Optionally, a username to use when sending messages to the client. If no username is provided, a default one is used. |
-> ClientHandlers | A record containing handlers for messages the kernel sends to the client. |
-> (KernelProfile -> Client a) | Provided with the |
-> IO a |
This function sets up ZeroMQ sockets on which it can connect to a kernel; if no KernelProfile
is provided, it generates a fresh KernelProfile
which contains information about the ports and
transport protocols which it expects the kernel to connect with. It guarantees that the ports it
chooses are open – that is, that no kernel is currently connected to those ports.
The generated KernelProfile
is passed to the user-provided
callback, which may use functions such as KernelProfile
-> Client
asendClientRequest
to communicate with the kernel. If
the kernel sends messages to the client, they are handled with the callbacks provided in the
ClientHandlers
record.
Most clients follow a simple pattern:
- Invoke
runClient
, passingNothing
for theKernelProfile
. This allowsrunClient
to set up and choose its own ports. - Write the connection file containing the chosen ports to a JSON file using
writeProfile
. Make sure to write it to a temporary directory, to avoid clobbering user directories with connection files. - If you do not know the command used to invoke the target kernel, use
findKernel
to find theKernelspec
for the kernel you wish to launch. Then, use thekernelspecCommand
field to generate the kernel command invocation. - Launch the kernel using
spawnProcess
or a similar function, providing the connection file you wrote out as a command-line parameter. - Wait for the kernel to connect to the client using
connectKernel
. - Use the output
KernelConnection
fromconnectClient
to communicate with the kernel usingsendClientRequest
(and maybesendClientComm
).
A full example is provided in the examples/client-kernel-info directory.
If any of the client handlers in the provided ClientHandlers
throw an exception, the client is
gracefully shutdown and the exception is reraised on the main runClient
thread.
connectKernel :: Client KernelConnection Source
Wait for a kernel to connect to this client, and return a KernelConnection
once the kernel
has connected.
This KernelConnection
must be passed to sendClientRequest
and sendClientComm
to communicate
with the connected kernel.
:: KernelConnection | A kernel connection, produced by |
-> ClientRequest | The request to send to the connected kernel. |
-> Client KernelReply |
Send a ClientRequest
to the kernel. Wait for the kernel to reply with a KernelReply
,
blocking until it does so.
:: KernelConnection | A kernel connection, produced by |
-> Comm | The |
-> Client () |
Send a Comm
message to the kernel. The kernel is not obligated to respond in any way, so do
not block, but return immediately upon sending the message.
data ClientHandlers Source
A set of callbacks for the client. These callbacks get called when the client receives any message from the kernel.
One callback exists per message type that the clients can receive. Each callbacks can also send
Comm
messages to kernel, and receive a function of type
that sends a single
Comm
-> IO ()Comm
message to the kernel.
ClientHandlers | |
|
defaultClientCommHandler :: (Comm -> IO ()) -> Comm -> IO () Source
A default client Comm
handlers, which, upon receiving a Comm
message, does nothing.
For use with the ClientHandlers
commHandler
field.
data KernelConnection Source
A connection to a kernel from a client.
A connection can be obtained with connectKernel
, and must be provided to
sendClientRequest
and sendClientComm
to communicate with a kernel.
Writing Connection Files
writeProfile :: KernelProfile -> FilePath -> IO () Source
Write a KernelProfile
to a JSON file, which can be passed as the connection file to a
starting kernel.
Locating kernels
data Kernelspec Source
A kernelspec is a description of a kernel which tells the Jupyter command-line application how to install the kernel and tells the frontends how to invoke the kernel (command line flags, environment, etc).
More documentation about kernelspecs is located in the official documentation.
Kernelspec | |
|
findKernel :: Text -> IO (Maybe Kernelspec) Source
Find the kernelspec for a kernel with a given language name.
If no such kernel exists, then Nothing
is returned. If an error occurs
while searching for Jupyter kernels, a JupyterKernelspecException
is thrown.
findKernels :: IO [Kernelspec] Source
Find all kernelspecs that the Jupyter installation is aware of,
using the jupyter kernelspec list
command.
If an error occurs while searching for Jupyter kernels, a JupyterKernelspecException
is thrown.