mirror of
https://github.com/vale981/emacs-jupyter
synced 2025-03-05 23:41:38 -05:00
Update callback interface
- Introduce `run-handlers-p` for `jupyter-request` objects. When this field is non-nil, a clients `jupyter-handle-message` method will pass the message to the channels `jupyter-handle-message` after running any callbacks. Otherwise the channel handlers will not be run. This gives a way to suppress the channel handlers for a request. - Also remove the use of `jupyter-callback` since `jupyter-handle-message` for a client just removes requests when an idle message is received. The callback object was used to check if a callback actually ran.
This commit is contained in:
parent
3c8cfee3ac
commit
068f09fa9e
1 changed files with 60 additions and 56 deletions
|
@ -666,54 +666,52 @@ for the heartbeat channel."
|
||||||
;; request has been handled by the kernel.
|
;; request has been handled by the kernel.
|
||||||
(cl-defstruct jupyter-request
|
(cl-defstruct jupyter-request
|
||||||
(-id)
|
(-id)
|
||||||
(idle-received-p)
|
(time (current-time))
|
||||||
|
(idle-received-p nil)
|
||||||
|
(run-handlers-p t)
|
||||||
(callbacks))
|
(callbacks))
|
||||||
|
|
||||||
(cl-defstruct jupyter-callback
|
|
||||||
(ran-p nil)
|
|
||||||
(cb nil))
|
|
||||||
|
|
||||||
(defun jupyter-request-id (req)
|
(defun jupyter-request-id (req)
|
||||||
(with-timeout (0.5 (error "Request not processed."))
|
(with-timeout (0.5 (error "Request not processed."))
|
||||||
(while (null (jupyter-request--id req))
|
(while (null (jupyter-request--id req))
|
||||||
(sleep-for 0 10)))
|
(sleep-for 0 10)))
|
||||||
(jupyter-request--id req))
|
(jupyter-request--id req))
|
||||||
|
|
||||||
(defun jupyter--run-callbacks-for-message (req msg)
|
(defun jupyter-request-run-callbacks (req msg)
|
||||||
"Run the MSG callbacks of REQ.
|
"Run the MSG callbacks of REQ."
|
||||||
|
|
||||||
The return value is non-nil if any handler methods for MSG should
|
|
||||||
be run. If this function returns nil, then it indicates that no
|
|
||||||
handler methods should be run for MSG. If there are multiple
|
|
||||||
callbacks for a MSG then if at least one of them returns non-nil,
|
|
||||||
this function will also return non-nil."
|
|
||||||
(when req
|
(when req
|
||||||
(let* ((callbacks (jupyter-request-callbacks req))
|
(let* ((callbacks (jupyter-request-callbacks req))
|
||||||
(cbt (cdr (assoc t callbacks)))
|
(cb-all-types (cdr (assoc t callbacks)))
|
||||||
(cb (cdr (assoc (jupyter-message-type msg) callbacks))))
|
(cb-for-type (cdr (assoc (jupyter-message-type msg) callbacks))))
|
||||||
(if (or cb cbt) (cl-find-if
|
(and cb-all-types (funcall cb-all-types msg))
|
||||||
(lambda (a) (not (null a)))
|
(and cb-for-type (funcall cb-for-type msg)))))
|
||||||
(cl-loop
|
|
||||||
for cb in (list cb cbt)
|
|
||||||
when cb collect
|
|
||||||
(funcall (jupyter-callback-cb cb) msg)
|
|
||||||
and do (setf (jupyter-callback-ran-p cb) t)))
|
|
||||||
t))))
|
|
||||||
|
|
||||||
(defun jupyter-add-callback (msg-type req function)
|
(defun jupyter-add-callback (msg-type req function)
|
||||||
"Add callback FUNCTION for a message REQUEST.
|
"Add a callback FUNCTION to a kernel REQuest.
|
||||||
|
|
||||||
FUNCTION will be run for all received messages that are
|
MSG-TYPE is a symbol representing which message type to run
|
||||||
associated with REQ and have a message type of MSG-TYPE. The
|
FUNCTION on when messages of that type are received for REQ. The
|
||||||
CLIENT handler method for MSG-TYPE is prevented from running if
|
symbol should be the same as one of the message types which are
|
||||||
FUNCTION returns nil. Otherwise if FUNCTION returns a non-nil
|
expected to be received from a kernel where underscore characters
|
||||||
value, the handler method for MSG-TYPE is run. This allows for a
|
are replaced with hyphens, see
|
||||||
mechanism to silently consume messages without passing them to
|
http://jupyter-client.readthedocs.io/en/latest/messaging.html. So
|
||||||
the handler methods which are usually run for updating
|
to add a callback which fires for and \"execute_reply\", MSG-TYPE
|
||||||
user-interface elements of the CLIENT.
|
should be the symbol `execute-reply'. As a special case if
|
||||||
|
MSG-TYPE is t, FUNCTION is run for all received messages of REQ.
|
||||||
|
|
||||||
As a special case if MSG-TYPE is t, the callback function is run
|
If MSG-TYPE is a list, then it should be a list of symbols as
|
||||||
for all received messages associated with REQ.
|
described above. FUNCTION will then run for every type of message
|
||||||
|
in the list.
|
||||||
|
|
||||||
|
REQ is a `jupyter-request' object as returned by the kernel
|
||||||
|
request methods of a `jupyter-kernel-client'.
|
||||||
|
|
||||||
|
FUNCTION is the callback function to be run when a message with
|
||||||
|
MSG-TYPE is received for REQ. It should accept one argument which
|
||||||
|
will be the message that has type, MSG-TYPE, and is a message
|
||||||
|
associated with the request, REQ. Note that if multiple callbacks
|
||||||
|
are added for the same MSG-TYPE, they will be called in the order
|
||||||
|
in which they were added.
|
||||||
|
|
||||||
As an example, suppose you want to register a callback when you
|
As an example, suppose you want to register a callback when you
|
||||||
recieve an `execute-reply' after sending an execute request. This
|
recieve an `execute-reply' after sending an execute request. This
|
||||||
|
@ -721,27 +719,32 @@ can be done like so:
|
||||||
|
|
||||||
(jupyter-add-callback 'execute-reply
|
(jupyter-add-callback 'execute-reply
|
||||||
(jupyter-request-execute client :code \"y = 1 + 2\")
|
(jupyter-request-execute client :code \"y = 1 + 2\")
|
||||||
(lambda (msg)
|
(lambda (msg) ...))"
|
||||||
(cl-assert (equal (jupyter-message-type msg) \"execute_reply\"))))
|
|
||||||
|
|
||||||
Note that the callback is given the raw decoded message received
|
|
||||||
from the kernel without any processing done to it."
|
|
||||||
(declare (indent 2))
|
(declare (indent 2))
|
||||||
(let ((mt (plist-get jupyter--received-message-types msg-type)))
|
(if (listp msg-type)
|
||||||
(if mt (setq msg-type mt)
|
(mapc (lambda (mt) (jupyter-add-callback mt req function)) msg-type)
|
||||||
;; msg-type = t means to run for every message type associated with
|
(setq msg-type (or (plist-get jupyter--received-message-types msg-type)
|
||||||
;; msg-id
|
;; A msg-type of t means that FUNCTION is run for all
|
||||||
(unless (eq msg-type t)
|
;; messages associated with a request.
|
||||||
(error "Not a valid received message type (`%s')" msg-type))))
|
(eq msg-type t)))
|
||||||
(if (jupyter-request-idle-received-p req)
|
(unless msg-type
|
||||||
(error "Request already received idle message.")
|
(error "Not a valid received message type (`%s')" msg-type))
|
||||||
(let ((callbacks (jupyter-request-callbacks req))
|
(if (jupyter-request-idle-received-p req)
|
||||||
(cb (make-jupyter-callback :cb function)))
|
(error "Request already received idle message.")
|
||||||
(if (null callbacks)
|
(let ((callbacks (jupyter-request-callbacks req)))
|
||||||
(setf (jupyter-request-callbacks req) (list (cons msg-type cb)))
|
(if (null callbacks)
|
||||||
(let* ((cb-for-type (assoc msg-type callbacks)))
|
(setf (jupyter-request-callbacks req)
|
||||||
(if cb-for-type (setcdr cb-for-type cb)
|
(list (cons msg-type function)))
|
||||||
(nconc callbacks (list (cons msg-type cb)))))))))
|
(let ((cb-for-type (assoc msg-type callbacks)))
|
||||||
|
(if cb-for-type
|
||||||
|
(setcdr cb-for-type (apply-partially
|
||||||
|
(lambda (cb1 cb2 msg)
|
||||||
|
(funcall cb1 msg)
|
||||||
|
(funcall cb2 msg))
|
||||||
|
(cdr cb-for-type)
|
||||||
|
function))
|
||||||
|
(nconc callbacks
|
||||||
|
(list (cons msg-type function))))))))))
|
||||||
|
|
||||||
(defun jupyter-wait-until (msg-type req timeout cond)
|
(defun jupyter-wait-until (msg-type req timeout cond)
|
||||||
"Wait until COND returns non-nil for a received message.
|
"Wait until COND returns non-nil for a received message.
|
||||||
|
@ -830,9 +833,10 @@ are taken:
|
||||||
(when (eq (oref channel type) :iopub)
|
(when (eq (oref channel type) :iopub)
|
||||||
(jupyter-handle-message channel client nil msg))
|
(jupyter-handle-message channel client nil msg))
|
||||||
(unwind-protect
|
(unwind-protect
|
||||||
(jupyter-handle-message channel client req msg)
|
(jupyter-request-run-callbacks req msg)
|
||||||
(unwind-protect
|
(unwind-protect
|
||||||
(jupyter--run-callbacks-for-message req msg)
|
(when (jupyter-request-run-handlers-p req)
|
||||||
|
(jupyter-handle-message channel client req msg))
|
||||||
(when (jupyter-message-status-idle-p msg)
|
(when (jupyter-message-status-idle-p msg)
|
||||||
(setf (jupyter-request-idle-received-p req) t))
|
(setf (jupyter-request-idle-received-p req) t))
|
||||||
(when (jupyter-request-idle-received-p req)
|
(when (jupyter-request-idle-received-p req)
|
||||||
|
|
Loading…
Add table
Reference in a new issue