mirror of
https://github.com/WolframResearch/WolframLanguageForJupyter.git
synced 2025-04-16 11:46:05 +00:00
Add support for ending a jupyter-console session when Quit[___] or Exit[___] are evaluated, or when the code strings "Quit", "Exit", "quit", or "exit" exactly are sent over by the console
This commit is contained in:
parent
7bc5ee8ae6
commit
e006c4f7e1
@ -77,21 +77,55 @@ If[
|
||||
Print[ourArgs___, opts:OptionsPattern[]] :=
|
||||
Block[
|
||||
{
|
||||
$inPrint=True,
|
||||
$Output={OpenWrite[FormatType->OutputForm]}
|
||||
$inPrint = True,
|
||||
$Output
|
||||
},
|
||||
If[
|
||||
!FailureQ[First[$Output]],
|
||||
loopState["printFunction"] =!= False,
|
||||
$Output = {OpenWrite[FormatType -> OutputForm]};
|
||||
If[
|
||||
!FailureQ[First[$Output]],
|
||||
Print[ourArgs, opts];
|
||||
loopState["printFunction"][
|
||||
Import[$Output[[1,1]], "String"]
|
||||
];
|
||||
Close[First[$Output]];
|
||||
];
|
||||
];
|
||||
Close[First[$Output]];
|
||||
Null
|
||||
] /; !TrueQ[$inPrint];
|
||||
Protect[Print];
|
||||
|
||||
(************************************
|
||||
versions of Quit and Exit that
|
||||
ask the Jupyter console
|
||||
to quit, if running under
|
||||
a Jupyter console
|
||||
*************************************)
|
||||
|
||||
Unprotect[Quit];
|
||||
Quit[ourArgs___, opts:OptionsPattern[]] :=
|
||||
Block[
|
||||
{$inQuit = True},
|
||||
If[
|
||||
loopState["isCompleteRequestSent"],
|
||||
loopState["askExit"] = True;,
|
||||
Quit[ourArgs, opts];
|
||||
];
|
||||
] /; !TrueQ[$inQuit];
|
||||
Protect[Quit];
|
||||
|
||||
Unprotect[Exit];
|
||||
Exit[ourArgs___, opts:OptionsPattern[]] :=
|
||||
Block[
|
||||
{$inExit = True},
|
||||
If[
|
||||
loopState["isCompleteRequestSent"],
|
||||
loopState["askExit"] = True;,
|
||||
Exit[ourArgs, opts];
|
||||
];
|
||||
] /; !TrueQ[$inExit];
|
||||
Protect[Exit];
|
||||
|
||||
(************************************
|
||||
versions of Throw and
|
||||
Catch that we can
|
||||
@ -119,7 +153,7 @@ If[
|
||||
*************************************)
|
||||
|
||||
(* redirect Print to Jupyter *)
|
||||
redirectPrint[sourceFrame_, printText_] :=
|
||||
redirectPrint[currentSourceFrame_, printText_] :=
|
||||
(* send a frame *)
|
||||
sendFrame[
|
||||
(* on the IO Publish socket *)
|
||||
|
@ -201,8 +201,11 @@ If[
|
||||
"replyContent" -> Null,
|
||||
(* message relpy frame to send on the IO Publish socket, if it is not Null *)
|
||||
"ioPubReplyFrame" -> Null,
|
||||
(* the function Print should use *)
|
||||
"printFunction" -> Function[#;]
|
||||
(* the redirect function Print should use *)
|
||||
"printFunction" -> False,
|
||||
(* flag for if the Jupyter console (if running under a Jupyter console)
|
||||
should ask the user if it should exit *)
|
||||
"askExit" -> False
|
||||
];
|
||||
|
||||
(* helper utility for applying hooks if they are set *)
|
||||
@ -232,7 +235,7 @@ If[
|
||||
bannerWarning =
|
||||
If[
|
||||
Length[$CommandLine] > 4,
|
||||
"\\n\\nThis Jupyter kernel was installed through the WolframLanguageForJupyter WolframScript script install option. Accordingly, updates to a WolframLanguageForJupyter paclet installed to a Wolfram Engine will not propagate to this installation.",
|
||||
"\\n\\nNote: This Jupyter kernel was installed through the WolframScript install method. Accordingly, updates to a WolframLanguageForJupyter paclet will not affect this kernel.",
|
||||
""
|
||||
];
|
||||
|
||||
|
@ -31,7 +31,7 @@ Needs["ZeroMQLink`"]; (* SocketReadMessage *)
|
||||
files
|
||||
*************************************)
|
||||
|
||||
Get[FileNameJoin[{DirectoryName[$InputFileName], "Initialization.wl"}]]; (* initialize WolframLanguageForJupyter; loopState, bannerWarning, shellSocket, ioPubSocket *)
|
||||
Get[FileNameJoin[{DirectoryName[$InputFileName], "Initialization.wl"}]]; (* initialize WolframLanguageForJupyter; loopState, bannerWarning, shellSocket, controlSocket, ioPubSocket *)
|
||||
|
||||
Get[FileNameJoin[{DirectoryName[$InputFileName], "SocketUtilities.wl"}]]; (* sendFrame *)
|
||||
Get[FileNameJoin[{DirectoryName[$InputFileName], "MessagingUtilities.wl"}]]; (* getFrameAssoc, createReplyFrame *)
|
||||
@ -49,24 +49,27 @@ Begin["`Private`"];
|
||||
loop[] :=
|
||||
Module[
|
||||
{
|
||||
(* the socket that has become ready *)
|
||||
readySocket,
|
||||
|
||||
(* the raw byte array frame received through SocketReadMessage *)
|
||||
rawFrame,
|
||||
|
||||
(* a frame for sending status updates on the IO Publish socket *)
|
||||
statusReplyFrame,
|
||||
|
||||
(* a frame for sending replies on the shell socket *)
|
||||
shellReplyFrame
|
||||
(* a frame for sending replies on a socket *)
|
||||
replyFrame
|
||||
},
|
||||
While[
|
||||
True,
|
||||
Switch[
|
||||
(* poll sockets until one is ready *)
|
||||
First[SocketWaitNext[{shellSocket}]],
|
||||
(* if the shell socket is ready, ... *)
|
||||
shellSocket,
|
||||
readySocket = First[SocketWaitNext[{shellSocket, controlSocket}]],
|
||||
(* if the shell socket or control socket is ready, ... *)
|
||||
shellSocket | controlSocket,
|
||||
(* receive a frame *)
|
||||
rawFrame = SocketReadMessage[shellSocket, "Multipart" -> True];
|
||||
rawFrame = SocketReadMessage[readySocket, "Multipart" -> True];
|
||||
(* check for any problems *)
|
||||
If[FailureQ[rawFrame],
|
||||
Quit[];
|
||||
@ -123,8 +126,8 @@ loop[] :=
|
||||
(* send the frame *)
|
||||
sendFrame[ioPubSocket, statusReplyFrame];
|
||||
|
||||
(* create a message frame to send a reply on the shell socket *)
|
||||
shellReplyFrame =
|
||||
(* create a message frame to send a reply on the socket that became ready *)
|
||||
replyFrame =
|
||||
createReplyFrame[
|
||||
(* use the current source frame *)
|
||||
loopState["frameAssoc"],
|
||||
@ -136,7 +139,7 @@ loop[] :=
|
||||
False
|
||||
];
|
||||
(* send the frame *)
|
||||
sendFrame[shellSocket, shellReplyFrame];
|
||||
sendFrame[readySocket, replyFrame];
|
||||
|
||||
(* if an ioPubReplyFrame was created, send it on the IO Publish socket *)
|
||||
If[
|
||||
@ -161,10 +164,10 @@ loop[] :=
|
||||
]
|
||||
];
|
||||
|
||||
(* if the doShutdown flag was set as True, shut down*)
|
||||
(* if the doShutdown flag is True, shut down *)
|
||||
If[
|
||||
loopState["doShutdown"],
|
||||
Quit[];
|
||||
Block[{$inQuit = True}, Quit[]];
|
||||
];
|
||||
,
|
||||
_,
|
||||
|
@ -118,31 +118,21 @@ If[
|
||||
unreportedErrorMessages
|
||||
},
|
||||
|
||||
(* set the appropriate reply type *)
|
||||
loopState["replyMsgType"] = "execute_reply";
|
||||
|
||||
(* set the content of the reply to information about WolframLanguageForJupyter's execution of the input *)
|
||||
loopState["replyContent"] =
|
||||
ExportString[
|
||||
Association[
|
||||
"status" -> "ok",
|
||||
"execution_count" -> loopState["executionCount"],
|
||||
"user_expressions" -> {}
|
||||
],
|
||||
"JSON",
|
||||
"Compact" -> True
|
||||
];
|
||||
|
||||
(* redirect Print so that it prints in the Jupyter notebook *)
|
||||
loopState["printFunction"] = (redirectPrint[loopState["frameAssoc"], #1] &);
|
||||
|
||||
(* if an is_complete_request has been sent, assume jupyter-console is running the kernel,
|
||||
and redirect messages *)
|
||||
redirect messages, and handle any "Quit", "Exit", "quit" or "exit" inputs *)
|
||||
If[
|
||||
loopState["isCompleteRequestSent"],
|
||||
loopState["redirectMessages"] = True;
|
||||
loopState["askExit"] =
|
||||
StringMatchQ[
|
||||
loopState["frameAssoc"]["content"]["code"],
|
||||
"Quit" | "Exit" | "quit" | "exit"
|
||||
];
|
||||
];
|
||||
|
||||
(* redirect Print so that it prints in the Jupyter notebook *)
|
||||
loopState["printFunction"] = (redirectPrint[loopState["frameAssoc"], #1] &);
|
||||
|
||||
(* if loopState["redirectMessages"] is True,
|
||||
update Jupyter explicitly with any errors that occur DURING the execution of the input *)
|
||||
If[
|
||||
@ -163,8 +153,29 @@ If[
|
||||
(* evaluate the input, and store the total result in totalResult *)
|
||||
totalResult = simulatedEvaluate[loopState["frameAssoc"]["content"]["code"]];
|
||||
|
||||
(* restore printFunction to empty *)
|
||||
loopState["printFunction"] = Function[#;];
|
||||
(* restore printFunction to False *)
|
||||
loopState["printFunction"] = False;
|
||||
|
||||
(* unset Internal`$MessageFormatter *)
|
||||
Unset[Internal`$MessageFormatter];
|
||||
|
||||
(* set the appropriate reply type *)
|
||||
loopState["replyMsgType"] = "execute_reply";
|
||||
|
||||
(* set the content of the reply to information about WolframLanguageForJupyter's execution of the input *)
|
||||
loopState["replyContent"] =
|
||||
ExportString[
|
||||
Association[
|
||||
"status" -> "ok",
|
||||
"execution_count" -> loopState["executionCount"],
|
||||
"user_expressions" -> {},
|
||||
(* see https://jupyter-client.readthedocs.io/en/stable/messaging.html#payloads-deprecated *)
|
||||
(* if the "askExit" flag is True, add an "ask_exit" payload *)
|
||||
"payload" -> If[loopState["askExit"], {Association["source" -> "ask_exit", "keepkernel" -> False]}, {}]
|
||||
],
|
||||
"JSON",
|
||||
"Compact" -> True
|
||||
];
|
||||
|
||||
(* check if there are any unreported error messages *)
|
||||
unreportedErrorMessages =
|
||||
@ -175,6 +186,30 @@ If[
|
||||
(StringLength[totalResult["GeneratedMessages"]] > 0)
|
||||
);
|
||||
|
||||
(* if there are no results, or if the "askExit" flag is True,
|
||||
do not send anything on the IO Publish socket and return *)
|
||||
If[
|
||||
(Length[totalResult["EvaluationResultOutputLineIndices"]] == 0) ||
|
||||
(loopState["askExit"]),
|
||||
(* set the "askExit" flag to False *)
|
||||
loopState["askExit"] = False;
|
||||
(* send any unreported error messages *)
|
||||
If[unreportedErrorMessages,
|
||||
redirectMessages[
|
||||
loopState["frameAssoc"],
|
||||
"",
|
||||
totalResult["GeneratedMessages"],
|
||||
(* do not add a newline *)
|
||||
False,
|
||||
(* drop message name *)
|
||||
True
|
||||
];
|
||||
];
|
||||
(* increment loopState["executionCount"] as needed *)
|
||||
loopState["executionCount"] += totalResult["ConsumedIndices"];
|
||||
Return[];
|
||||
];
|
||||
|
||||
(* generate an HTML form of the message text *)
|
||||
errorMessage =
|
||||
If[
|
||||
@ -196,26 +231,6 @@ If[
|
||||
}
|
||||
];
|
||||
|
||||
(* if there are no results, do not send anything on the IO Publish socket and return *)
|
||||
If[
|
||||
Length[totalResult["EvaluationResultOutputLineIndices"]] == 0,
|
||||
(* send any unreported error messages *)
|
||||
If[unreportedErrorMessages,
|
||||
redirectMessages[
|
||||
loopState["frameAssoc"],
|
||||
"",
|
||||
totalResult["GeneratedMessages"],
|
||||
(* do not add a newline *)
|
||||
False,
|
||||
(* drop message name *)
|
||||
True
|
||||
];
|
||||
];
|
||||
(* increment loopState["executionCount"] as needed *)
|
||||
loopState["executionCount"] += totalResult["ConsumedIndices"];
|
||||
Return[];
|
||||
];
|
||||
|
||||
(* format output as purely text, image, or cloud interface *)
|
||||
If[
|
||||
(* check if the input was wrapped with Interact,
|
||||
|
Loading…
x
Reference in New Issue
Block a user