mirror of
https://github.com/WolframResearch/WolframLanguageForJupyter.git
synced 2025-04-16 11:46:05 +00:00
Merge branch 'master' of ssh://stash.wolfram.com:7999/se/wolframlanguageforjupyter
This commit is contained in:
commit
b7d499e3b1
@ -72,11 +72,17 @@ SetAttributes[jupEval, HoldAll];
|
||||
|
||||
sendFrame[socket_, frame_Association] := Module[{},
|
||||
|
||||
ZeroMQLink`ZMQSocketWriteMessage[
|
||||
socket,
|
||||
frame["ident"],
|
||||
"Multipart" -> True
|
||||
];
|
||||
|
||||
ZeroMQLink`ZMQSocketWriteMessage[
|
||||
socket,
|
||||
StringToByteArray[#1],
|
||||
"Multipart" -> True
|
||||
]& /@ Lookup[frame, {"uuid", "idsmsg", "signature", "header", "pheader", "metadata"}];
|
||||
]& /@ Lookup[frame, {"idsmsg", "signature", "header", "pheader", "metadata"}];
|
||||
|
||||
ZeroMQLink`ZMQSocketWriteMessage[
|
||||
socket,
|
||||
@ -141,12 +147,12 @@ getFrameAssoc[frame_Association, replyType_String, replyContent_String, branchOf
|
||||
header = frame["header"];
|
||||
content = frame["content"];
|
||||
|
||||
AssociateTo[res, {"header" -> Association[ImportString[header, "JSON"]], "content" -> Association[ImportString[content, "JSON"]]}];
|
||||
AssociateTo[res, {"header" -> Association[ImportByteArray[StringToByteArray[header], "JSON"]], "content" -> Association[ImportByteArray[StringToByteArray[content], "JSON"]]}];
|
||||
AssociateTo[
|
||||
res,
|
||||
"replyMsg" ->
|
||||
Association[
|
||||
"uuid" -> res["header"]["session"],
|
||||
"ident" -> If[KeyExistsQ[frame, "ident"], frame["ident"], ByteArray[{0, 0, 0, 0, 0}]],
|
||||
"idsmsg" -> "<IDS|MSG>",
|
||||
"header" -> ExportString[Append[res["header"], {"date" -> DateString["ISODateTime"], "msg_type" -> replyType, "msg_id" -> StringInsert[StringReplace[CreateUUID[], "-" -> ""], "-", 9]}], "JSON", "Compact" -> True],
|
||||
"pheader" -> If[branchOff, "{}", header],
|
||||
@ -175,17 +181,17 @@ getFrameAssoc[frame_Association, replyType_String, replyContent_String, branchOf
|
||||
Return[res];
|
||||
];
|
||||
|
||||
getFrameAssoc[baFrame_ByteArray, replyType_String, replyContent_String, branchOff:(True|False)] := Module[{frameStr, res = Association[], header, pheader, metadata, content},
|
||||
getFrameAssoc[baFrame_ByteArray, replyType_String, replyContent_String, branchOff:(True|False)] := Module[{frameStr, res = Association[], identLen, header, pheader, metadata, content},
|
||||
frameStr = Quiet[ByteArrayToString[baFrame]];
|
||||
|
||||
{header, pheader, metadata, content} = First[StringCases[frameStr,
|
||||
"<IDS|MSG>" ~~ ___ ~~ "{" ~~ json1___ ~~ "}" ~~ "{" ~~ json2___ ~~ "}" ~~ "{" ~~ json3___ ~~ "}" ~~ "{" ~~ json4___ ~~ "}" ~~ EndOfString :>
|
||||
(StringJoin["{",#1,"}"] &) /@ {json1,json2,json3,json4}
|
||||
{identLen, header, pheader, metadata, content} = First[StringCases[frameStr,
|
||||
ident1___ ~~ "<IDS|MSG>" ~~ ___ ~~ "{" ~~ json1___ ~~ "}" ~~ "{" ~~ json2___ ~~ "}" ~~ "{" ~~ json3___ ~~ "}" ~~ "{" ~~ json4___ ~~ "}" ~~ EndOfString :>
|
||||
Prepend[(StringJoin["{",#1,"}"] &) /@ {json1,json2,json3,json4}, StringLength[ident1]]
|
||||
]];
|
||||
|
||||
Return[
|
||||
getFrameAssoc[
|
||||
Association["header" -> header, "content" -> content],
|
||||
Association["ident" -> baFrame[[;;identLen]], "header" -> header, "content" -> content],
|
||||
replyType,
|
||||
replyContent,
|
||||
branchOff
|
||||
@ -249,142 +255,162 @@ ioPubReplyFrame = Association[];
|
||||
|
||||
doShutdown = False;
|
||||
|
||||
While[
|
||||
True,
|
||||
Switch[
|
||||
First[SocketWaitNext[{shellSocket}]],
|
||||
shellSocket,
|
||||
srm = SocketReadMessage[shellSocket, "Multipart" -> True];
|
||||
frameAssoc = getFrameAssoc[srm, "", "{}", False];
|
||||
Switch[
|
||||
frameAssoc["header"]["msg_type"],
|
||||
"kernel_info_request",
|
||||
replyMsgType = "kernel_info_reply";
|
||||
replyContent = "{\"protocol_version\":\"5.3.0\",\"implementation\":\"WL\"}";,
|
||||
"is_complete_request",
|
||||
(* Add syntax-Q checking *)
|
||||
replyMsgType = "is_complete_reply";
|
||||
replyContent = "{\"status\":\"unknown\"}";,
|
||||
"execute_request",
|
||||
jupyterEvaluationLoop[] :=
|
||||
Module[
|
||||
{
|
||||
srm,
|
||||
frameAssoc,
|
||||
replyMsgType,
|
||||
replyContent,
|
||||
$jupResEval,
|
||||
$res,
|
||||
$msgs,
|
||||
ioPubReplyContent,
|
||||
statReplyFrame,
|
||||
shellReplyFrame
|
||||
},
|
||||
|
||||
replyMsgType = "execute_reply";
|
||||
replyContent = ExportString[Association["status" -> "ok", "execution_count" -> executionCount, "user_expressions" -> {}], "JSON", "Compact" -> True];
|
||||
While[
|
||||
True,
|
||||
Switch[
|
||||
First[SocketWaitNext[{shellSocket}]],
|
||||
shellSocket,
|
||||
srm = SocketReadMessage[shellSocket, "Multipart" -> True];
|
||||
frameAssoc = getFrameAssoc[srm, "", "{}", False];
|
||||
Switch[
|
||||
frameAssoc["header"]["msg_type"],
|
||||
"kernel_info_request",
|
||||
replyMsgType = "kernel_info_reply";
|
||||
replyContent = "{\"protocol_version\":\"5.3.0\",\"implementation\":\"WL\"}";,
|
||||
"is_complete_request",
|
||||
(* Add syntax-Q checking *)
|
||||
replyMsgType = "is_complete_reply";
|
||||
replyContent = "{\"status\":\"unknown\"}";,
|
||||
"execute_request",
|
||||
|
||||
$jupResEval = ToExpression[frameAssoc["content"]["code"], InputForm, Uninteract];
|
||||
$res = $jupResEval["res"];
|
||||
$msgs = $jupResEval["msgs"];
|
||||
If[FailureQ[$jupResEval],
|
||||
$res=$Failed;
|
||||
$msgs=jupEval[ToExpression[frameAssoc["content"]["code"], InputForm]]["msgs"];
|
||||
];
|
||||
replyMsgType = "execute_reply";
|
||||
replyContent = ExportString[Association["status" -> "ok", "execution_count" -> executionCount, "user_expressions" -> {}], "JSON", "Compact" -> True];
|
||||
|
||||
If[TrueQ[InteractQ[ToExpression[frameAssoc["content"]["code"], InputForm, Hold]]] && $CloudConnected,
|
||||
ioPubReplyContent = ExportString[
|
||||
Association[
|
||||
"execution_count" -> executionCount,
|
||||
"data" -> {"text/html" -> StringJoin[
|
||||
"<div><img alt=\"\" src=\"data:image/png;base64,",
|
||||
BaseEncode[ExportByteArray[Rasterize[Style[$msgs, Darker[Red]]], "PNG"]],
|
||||
"\">",
|
||||
EmbedCode[CloudDeploy[$res], "HTML"][[1]]["CodeSection"]["Content"],
|
||||
"</div>"
|
||||
]
|
||||
},
|
||||
"metadata" -> {"text/html" -> {}}
|
||||
],
|
||||
"JSON",
|
||||
"Compact" -> True
|
||||
];
|
||||
,
|
||||
If[doText[$res],
|
||||
ioPubReplyContent = ExportString[
|
||||
Association[
|
||||
"execution_count" -> executionCount,
|
||||
"data" -> {"text/html" -> StringJoin[
|
||||
"<div>",
|
||||
If[StringLength[$msgs] == 0,
|
||||
{},
|
||||
{
|
||||
"<pre style=\"",
|
||||
StringJoin[{"&#",ToString[#1], ";"} & /@ ToCharacterCode["color:red; font-family: \"Courier New\",Courier,monospace;"]],
|
||||
"\">",
|
||||
StringJoin[{"&#", ToString[#1], ";"} & /@ ToCharacterCode[$msgs]],
|
||||
"</pre>"
|
||||
}
|
||||
],
|
||||
"<pre style=\"",
|
||||
StringJoin[{"&#",ToString[#1], ";"} & /@ ToCharacterCode["font-family: \"Courier New\",Courier,monospace;"]],
|
||||
"\">",
|
||||
StringJoin[{"&#", ToString[#1], ";"} & /@ ToCharacterCode[ToString[$res]]],
|
||||
"</pre></div>"
|
||||
]
|
||||
},
|
||||
"metadata" -> {"text/html" -> {}}
|
||||
],
|
||||
"JSON",
|
||||
"Compact" -> True
|
||||
];,
|
||||
ioPubReplyContent = ExportString[
|
||||
Association[
|
||||
"execution_count" -> executionCount,
|
||||
"data" -> {"text/html" -> StringJoin[
|
||||
"<div>",
|
||||
Sequence @@ If[StringLength[$msgs] == 0,
|
||||
{},
|
||||
{
|
||||
"<pre style=\"",
|
||||
StringJoin[{"&#",ToString[#1], ";"} & /@ ToCharacterCode["color:red; font-family: \"Courier New\",Courier,monospace;"]],
|
||||
"\">",
|
||||
StringJoin[{"&#", ToString[#1], ";"} & /@ ToCharacterCode[$msgs]],
|
||||
"</pre>"
|
||||
}
|
||||
],
|
||||
"<img alt=\"Output\" src=\"data:image/png;base64,",
|
||||
BaseEncode[
|
||||
ExportByteArray[
|
||||
If[Head[$res] === Manipulate, $res, Rasterize[$res]],
|
||||
"PNG"
|
||||
]
|
||||
],
|
||||
"\"></div>"
|
||||
]
|
||||
},
|
||||
"metadata" -> {"text/html" -> {}}
|
||||
],
|
||||
"JSON",
|
||||
"Compact" -> True
|
||||
$jupResEval = ToExpression[frameAssoc["content"]["code"], InputForm, Uninteract];
|
||||
$res = $jupResEval["res"];
|
||||
$msgs = $jupResEval["msgs"];
|
||||
If[FailureQ[$jupResEval],
|
||||
$res=$Failed;
|
||||
$msgs=jupEval[ToExpression[frameAssoc["content"]["code"], InputForm]]["msgs"];
|
||||
];
|
||||
|
||||
If[TrueQ[InteractQ[ToExpression[frameAssoc["content"]["code"], InputForm, Hold]]] && $CloudConnected,
|
||||
ioPubReplyContent = ExportString[
|
||||
Association[
|
||||
"execution_count" -> executionCount,
|
||||
"data" -> {"text/html" -> StringJoin[
|
||||
"<div><img alt=\"\" src=\"data:image/png;base64,",
|
||||
BaseEncode[ExportByteArray[Rasterize[Style[$msgs, Darker[Red]]], "PNG"]],
|
||||
"\">",
|
||||
EmbedCode[CloudDeploy[$res], "HTML"][[1]]["CodeSection"]["Content"],
|
||||
"</div>"
|
||||
]
|
||||
},
|
||||
"metadata" -> {"text/html" -> {}}
|
||||
],
|
||||
"JSON",
|
||||
"Compact" -> True
|
||||
];
|
||||
,
|
||||
If[doText[$res],
|
||||
ioPubReplyContent = ExportString[
|
||||
Association[
|
||||
"execution_count" -> executionCount,
|
||||
"data" -> {"text/html" -> StringJoin[
|
||||
"<div>",
|
||||
If[StringLength[$msgs] == 0,
|
||||
{},
|
||||
{
|
||||
"<pre style=\"",
|
||||
StringJoin[{"&#",ToString[#1], ";"} & /@ ToCharacterCode["color:red; font-family: \"Courier New\",Courier,monospace;"]],
|
||||
"\">",
|
||||
StringJoin[{"&#", ToString[#1], ";"} & /@ ToCharacterCode[$msgs]],
|
||||
"</pre>"
|
||||
}
|
||||
],
|
||||
"<pre style=\"",
|
||||
StringJoin[{"&#",ToString[#1], ";"} & /@ ToCharacterCode["font-family: \"Courier New\",Courier,monospace;"]],
|
||||
"\">",
|
||||
StringJoin[{"&#", ToString[#1], ";"} & /@ ToCharacterCode[ToString[$res]]],
|
||||
"</pre></div>"
|
||||
]
|
||||
},
|
||||
"metadata" -> {"text/html" -> {}}
|
||||
],
|
||||
"JSON",
|
||||
"Compact" -> True
|
||||
];,
|
||||
ioPubReplyContent = ExportString[
|
||||
Association[
|
||||
"execution_count" -> executionCount,
|
||||
"data" -> {"text/html" -> StringJoin[
|
||||
"<div>",
|
||||
Sequence @@ If[StringLength[$msgs] == 0,
|
||||
{},
|
||||
{
|
||||
"<pre style=\"",
|
||||
StringJoin[{"&#",ToString[#1], ";"} & /@ ToCharacterCode["color:red; font-family: \"Courier New\",Courier,monospace;"]],
|
||||
"\">",
|
||||
StringJoin[{"&#", ToString[#1], ";"} & /@ ToCharacterCode[$msgs]],
|
||||
"</pre>"
|
||||
}
|
||||
],
|
||||
"<img alt=\"Output\" src=\"data:image/png;base64,",
|
||||
BaseEncode[
|
||||
ExportByteArray[
|
||||
If[Head[$res] === Manipulate, $res, Rasterize[$res]],
|
||||
"PNG"
|
||||
]
|
||||
],
|
||||
"\"></div>"
|
||||
]
|
||||
},
|
||||
"metadata" -> {"text/html" -> {}}
|
||||
],
|
||||
"JSON",
|
||||
"Compact" -> True
|
||||
];
|
||||
];
|
||||
];
|
||||
|
||||
ioPubReplyFrame = getFrameAssoc[srm, "execute_result", ioPubReplyContent, False];
|
||||
|
||||
executionCount++;,
|
||||
"shutdown_request",
|
||||
replyMsgType = "shutdown_reply";
|
||||
replyContent = "{\"restart\":false}";
|
||||
doShutdown = True;,
|
||||
_,
|
||||
Continue[];
|
||||
];
|
||||
statReplyFrame = getFrameAssoc[srm, "status", "{\"execution_state\":\"busy\"}", True]["replyMsg"];
|
||||
sendFrame[ioPubSocket, statReplyFrame];
|
||||
|
||||
shellReplyFrame = getFrameAssoc[srm, replyMsgType, replyContent, False];
|
||||
sendFrame[shellSocket, shellReplyFrame["replyMsg"]];
|
||||
|
||||
If[!(ioPubReplyFrame === Association[]),
|
||||
sendFrame[ioPubSocket, ioPubReplyFrame["replyMsg"]];
|
||||
ioPubReplyFrame = Association[];
|
||||
];
|
||||
|
||||
sendFrame[ioPubSocket, getFrameAssoc[statReplyFrame, "status", "{\"execution_state\":\"idle\"}", False]["replyMsg"]];
|
||||
|
||||
If[doShutdown, Quit[];];
|
||||
,
|
||||
_,
|
||||
Continue[];
|
||||
];
|
||||
|
||||
ioPubReplyFrame = getFrameAssoc[srm, "execute_result", ioPubReplyContent, False];
|
||||
|
||||
executionCount++;,
|
||||
"shutdown_request",
|
||||
replyMsgType = "shutdown_reply";
|
||||
replyContent = "{\"restart\":false}";
|
||||
doShutdown = True;,
|
||||
_,
|
||||
Continue[];
|
||||
];
|
||||
statReplyFrame = getFrameAssoc[srm, "status", "{\"execution_state\":\"busy\"}", True]["replyMsg"];
|
||||
sendFrame[ioPubSocket, statReplyFrame];
|
||||
|
||||
shellReplyFrame = getFrameAssoc[srm, replyMsgType, replyContent, False];
|
||||
sendFrame[shellSocket, shellReplyFrame["replyMsg"]];
|
||||
|
||||
If[!(ioPubReplyFrame === Association[]),
|
||||
sendFrame[ioPubSocket, ioPubReplyFrame["replyMsg"]];
|
||||
ioPubReplyFrame = Association[];
|
||||
];
|
||||
|
||||
sendFrame[ioPubSocket, getFrameAssoc[statReplyFrame, "status", "{\"execution_state\":\"idle\"}", False]["replyMsg"]];
|
||||
|
||||
If[doShutdown, Quit[];];
|
||||
,
|
||||
_,
|
||||
Continue[];
|
||||
];
|
||||
];
|
||||
|
||||
End[];
|
||||
End[];
|
||||
|
||||
(* This setup does not preclude dynamics or widgets. *)
|
||||
|
||||
WolframLanguageForJupyter`Private`jupyterEvaluationLoop[];
|
@ -1,27 +1,52 @@
|
||||
BeginPackage["WolframLanguageForJupyter`"];
|
||||
|
||||
AddKernelToJupyter::usage = "AddKernelToJupyter[] attempts to add the Wolfram kernel to the Jupyter installation on Environment[\"PATH\"].
|
||||
(* AddKernelToJupyter::usage = "AddKernelToJupyter[] attempts to add the Wolfram Language kernel to the Jupyter installation on Environment[\"PATH\"].
|
||||
AddKernelToJupyter[\"\!\(\*
|
||||
StyleBox[\"path\", \"TI\"]\)\"] adds the Wolfram kernel to the location of the Jupyter binary at \!\(\*
|
||||
StyleBox[\"path\", \"TI\"]\).";
|
||||
StyleBox[\"path\", \"TI\"]\)\"] adds the Wolfram Language kernel to the location of the Jupyter binary at \!\(\*
|
||||
StyleBox[\"path\", \"TI\"]\)."; *)
|
||||
AddKernelToJupyter::usage = "AddKernelToJupyter[] adds a Wolfram Language kernel to a Jupyter binary on Environment[\"PATH\"].
|
||||
AddKernelToJupyter[\"jupyter\"] adds a Wolfram Language kernel to the provided Jupyter binary path.
|
||||
AddKernelToJupyter[\"jupyter\", \"kernel\"] adds the provided absolute Wolfram Language kernel binary path to the provided Jupyter binary path.";
|
||||
AddKernelToJupyter::notfound = "Jupyter installation on Environment[\"PATH\"] not found.";
|
||||
AddKernelToJupyter::isdir = "Provided path is a directory. Please provide the path to the Jupyter binary."
|
||||
AddKernelToJupyter::nobin = "Provided path does not exist.";
|
||||
AddKernelToJupyter::notadded = "An error has occurred. There is still no Wolfram kernel in \"jupyter kernelspec list.\"";
|
||||
AddKernelToJupyter::isdir = "Provided `1` binary path is a directory. Please provide the path to the `1` binary.";
|
||||
AddKernelToJupyter::nobin = "Provided `1` binary path does not exist.";
|
||||
AddKernelToJupyter::notadded = "An error has occurred. There is still no Wolfram Language kernel in \"jupyter kernelspec list.\"";
|
||||
|
||||
RemoveKernelFromJupyter::usage = "RemoveKernelFromJupyter[] attempts to remove any Wolfram kernels from the Jupyter installation on Environment[\"PATH\"].
|
||||
(* RemoveKernelFromJupyter::usage = "RemoveKernelFromJupyter[] attempts to remove any Wolfram Language kernels from the Jupyter installation on Environment[\"PATH\"].
|
||||
RemoveKernelFromJupyter[\"\!\(\*
|
||||
StyleBox[\"path\", \"TI\"]\)\"] removes any Wolfram kernels from the location of the Jupyter binary at \!\(\*
|
||||
StyleBox[\"path\", \"TI\"]\).";
|
||||
StyleBox[\"path\", \"TI\"]\)\"] removes any Wolfram Language kernels from the location of the Jupyter binary at \!\(\*
|
||||
StyleBox[\"path\", \"TI\"]\)."; *)
|
||||
RemoveKernelFromJupyter::usage = "RemoveKernelFromJupyter[] removes any Wolfram Language kernels found on a Jupyter binary on Environment[\"PATH\"].
|
||||
RemoveKernelFromJupyter[\"jupyter\"] removes any Wolfram Language kernels found on the provided Jupyter binary path.";
|
||||
RemoveKernelFromJupyter::notfound = AddKernelToJupyter::notfound;
|
||||
RemoveKernelFromJupyter::isdir = AddKernelToJupyter::isdir;
|
||||
RemoveKernelFromJupyter::nobin = AddKernelToJupyter::nobin;
|
||||
RemoveKernelFromJupyter::notremoved = "An error has occurred. There is a Wolfram kernel still in \"jupyter kernelspec list.\"";
|
||||
RemoveKernelFromJupyter::notremoved = "An error has occurred. There is a Wolfram Language kernel still in \"jupyter kernelspec list.\"";
|
||||
|
||||
Begin["`Private`"];
|
||||
|
||||
(* globalKernelUUID = "11a8cf20-da0e-4976-83e5-27579d6360b3"; *)
|
||||
globalKernelUUID = Hash[$InstallationDirectory, "SHA", "HexString"];
|
||||
hashedKernelUUID = Hash[$InstallationDirectory, "SHA", "HexString"];
|
||||
names = StringCases[$Version, name___ ~~ " for " ~~ ("Mac" | "Microsoft" | "Windows" | "Linux") -> name];
|
||||
If[Length[names] > 0,
|
||||
globalKernelUUID =
|
||||
ToLowerCase[StringJoin[
|
||||
"WolframLanguage-",
|
||||
StringReplace[First[names], Whitespace -> "-"]
|
||||
]];
|
||||
displayName =
|
||||
StringJoin[
|
||||
"Wolfram Language (",
|
||||
Capitalize[
|
||||
First[names],
|
||||
"AllWords"
|
||||
],
|
||||
")"
|
||||
];
|
||||
,
|
||||
globalKernelUUID = hashedKernelUUID;
|
||||
displayName = "Wolfram Language";
|
||||
];
|
||||
|
||||
pacletHome = DirectoryName[$InputFileName];
|
||||
|
||||
@ -73,23 +98,84 @@ RemoveKernelFromJupyter[] :=
|
||||
];
|
||||
|
||||
getKernelspecAssoc[jupyterPath_String] :=
|
||||
Replace[
|
||||
ImportString[RunProcess[{jupyterPath, "kernelspec", "list", "--json"}, "StandardOutput"], "JSON"],
|
||||
part_List /; AllTrue[part, Head[#1] === Rule &] -> Association @ part,
|
||||
{0, Infinity}
|
||||
Module[{json},
|
||||
json = Quiet[ImportString[RunProcess[{jupyterPath, "kernelspec", "list", "--json"}, "StandardOutput"], "JSON"]];
|
||||
If[
|
||||
FailureQ[json],
|
||||
Return[Association[]];
|
||||
];
|
||||
Return[
|
||||
Replace[
|
||||
json,
|
||||
part_List /; AllTrue[part, Head[#1] === Rule &] -> Association @ part,
|
||||
{0, Infinity}
|
||||
]
|
||||
];
|
||||
];
|
||||
|
||||
AddKernelToJupyter[jupyterPath_String] :=
|
||||
Module[{baseDir, tempDir, exitCode, kernelspecAssoc, kernelspecs, kernelUUID},
|
||||
AddKernelToJupyter[jupyterPath_String] := AddKernelToJupyter[jupyterPath, mathBin];
|
||||
|
||||
RemoveKernelFromJupyter[jupyterPath_String (*, kernelUUID_String *)] :=
|
||||
Module[{exitCodeOld, exitCode, kernelspecAssoc, kernelspecs, oldEnv},
|
||||
If[DirectoryQ[jupyterPath],
|
||||
Message[AddKernelToJupyter::isdir];
|
||||
Message[RemoveKernelFromJupyter::isdir, "Jupyter"];
|
||||
Return[$Failed];
|
||||
];
|
||||
If[!FileExistsQ[jupyterPath],
|
||||
Message[AddKernelToJupyter::nobin];
|
||||
Message[RemoveKernelFromJupyter::nobin, "Jupyter"];
|
||||
Return[$Failed];
|
||||
];
|
||||
|
||||
oldEnv = Environment["PATH"];
|
||||
SetEnvironment["PATH" -> StringJoin[Environment["PATH"], pathSeperator, DirectoryName[jupyterPath]]];
|
||||
|
||||
exitCodeOld = RunProcess[{jupyterPath, "kernelspec", "remove", "-f", hashedKernelUUID}, "ExitCode"];
|
||||
exitCode = RunProcess[{jupyterPath, "kernelspec", "remove", "-f", globalKernelUUID}, "ExitCode"];
|
||||
|
||||
kernelspecAssoc = getKernelspecAssoc[jupyterPath];
|
||||
If[
|
||||
KeyExistsQ[kernelspecAssoc, "kernelspecs"],
|
||||
kernelspecs = Keys[kernelspecAssoc["kernelspecs"]];,
|
||||
kernelspecs = {};
|
||||
];
|
||||
|
||||
If[MemberQ[
|
||||
kernelspecs,
|
||||
(* kernelUUID *)
|
||||
globalKernelUUID
|
||||
],
|
||||
Message[RemoveKernelFromJupyter::notremoved];
|
||||
Return[$Failed];
|
||||
];
|
||||
|
||||
SetEnvironment["PATH" -> oldEnv];
|
||||
|
||||
(* Return[kernelUUID]; *)
|
||||
];
|
||||
|
||||
AddKernelToJupyter[jupyterPath_String, mathB_String] :=
|
||||
Module[{baseDir, tempDir, exitCode, kernelspecAssoc, kernelspecs, kernelUUID, oldEnv},
|
||||
If[DirectoryQ[jupyterPath],
|
||||
Message[AddKernelToJupyter::isdir, "Jupyter"];
|
||||
Return[$Failed];
|
||||
];
|
||||
If[!FileExistsQ[jupyterPath],
|
||||
Message[AddKernelToJupyter::nobin, "Jupyter"];
|
||||
Return[$Failed];
|
||||
];
|
||||
|
||||
If[DirectoryQ[mathB],
|
||||
Message[AddKernelToJupyter::isdir, "Wolfram Language kernel"];
|
||||
Return[$Failed];
|
||||
];
|
||||
If[!FileExistsQ[mathB],
|
||||
Message[AddKernelToJupyter::nobin, "Wolfram Language kernel"];
|
||||
Return[$Failed];
|
||||
];
|
||||
|
||||
oldEnv = Environment["PATH"];
|
||||
SetEnvironment["PATH" -> StringJoin[Environment["PATH"], pathSeperator, DirectoryName[jupyterPath]]];
|
||||
|
||||
kernelUUID = CreateUUID[];
|
||||
tempDir = CreateDirectory[
|
||||
FileNameJoin[{
|
||||
@ -102,8 +188,8 @@ AddKernelToJupyter[jupyterPath_String] :=
|
||||
Export[
|
||||
FileNameJoin[{tempDir, "kernel.json"}],
|
||||
Association[
|
||||
"argv" -> {mathBin, "-script", FileNameJoin[{pacletHome, "Resources", "kernel.wl"}], "{connection_file}"},
|
||||
"display_name" -> "Wolfram Language",
|
||||
"argv" -> {mathB, "-script", FileNameJoin[{pacletHome, "Resources", "kernel.wl"}], "{connection_file}"},
|
||||
"display_name" -> displayName,
|
||||
"language" -> "Wolfram Language"
|
||||
]
|
||||
];
|
||||
@ -118,7 +204,11 @@ AddKernelToJupyter[jupyterPath_String] :=
|
||||
DeleteDirectory[DirectoryName[tempDir], DeleteContents -> True];
|
||||
|
||||
kernelspecAssoc = getKernelspecAssoc[jupyterPath];
|
||||
kernelspecs = Keys[kernelspecAssoc["kernelspecs"]];
|
||||
If[
|
||||
KeyExistsQ[kernelspecAssoc, "kernelspecs"],
|
||||
kernelspecs = Keys[kernelspecAssoc["kernelspecs"]];,
|
||||
kernelspecs = {};
|
||||
];
|
||||
|
||||
If[!MemberQ[
|
||||
kernelspecs,
|
||||
@ -129,24 +219,7 @@ AddKernelToJupyter[jupyterPath_String] :=
|
||||
Return[$Failed];
|
||||
];
|
||||
|
||||
(* Return[kernelUUID]; *)
|
||||
];
|
||||
|
||||
RemoveKernelFromJupyter[jupyterPath_String (*, kernelUUID_String *)] :=
|
||||
Module[{exitCode, kernelspecAssoc, kernelspecs},
|
||||
exitCode = RunProcess[{jupyterPath, "kernelspec", "remove", "-f", (* kernelUUID *) globalKernelUUID}, "ExitCode"];
|
||||
|
||||
kernelspecAssoc = getKernelspecAssoc[jupyterPath];
|
||||
kernelspecs = Keys[kernelspecAssoc["kernelspecs"]];
|
||||
|
||||
If[MemberQ[
|
||||
kernelspecs,
|
||||
(* kernelUUID *)
|
||||
globalKernelUUID
|
||||
],
|
||||
Message[RemoveKernelFromJupyter::notremoved];
|
||||
Return[$Failed];
|
||||
];
|
||||
SetEnvironment["PATH" -> oldEnv];
|
||||
|
||||
(* Return[kernelUUID]; *)
|
||||
];
|
||||
|
126
install.wls
126
install.wls
@ -3,15 +3,37 @@ Begin["WolframLanguageForJupyter`Private`"];
|
||||
notfound = "install.wls: Jupyter installation on Environment[\"PATH\"] not found.";
|
||||
isdir = "install.wls: Provided Jupyter binary path is a directory. Please provide the path to the Jupyter binary."
|
||||
nobin = "install.wls: Provided Jupyter binary path does not exist.";
|
||||
notadded = "install.wls: An error has occurred. There is still no Wolfram kernel in \"jupyter kernelspec list.\"";
|
||||
notremoved = "install.wls: An error has occurred. There is a Wolfram kernel still in \"jupyter kernelspec list.\"";
|
||||
isdirMath = "install.wls: Provided Wolfram Language kernel binary path is a directory. Please provide the path to the Wolfram Language kernel binary."
|
||||
nobinMath = "install.wls: Provided Wolfram Language kernel binary path does not exist.";
|
||||
notadded = "install.wls: An error has occurred. There is still no Wolfram Language kernel in \"jupyter kernelspec list.\"";
|
||||
notremoved = "install.wls: An error has occurred. There is a Wolfram Language kernel still in \"jupyter kernelspec list.\"";
|
||||
nopaclet = "install.wls: WolframLanguageForJupyter paclet source not detected. Are you running the script in the root project directory?";
|
||||
|
||||
(* globalKernelUUID = "11a8cf20-da0e-4976-83e5-27579d6360b3"; *)
|
||||
globalKernelUUID = Hash[$InstallationDirectory, "SHA", "HexString"];
|
||||
hashedKernelUUID = Hash[$InstallationDirectory, "SHA", "HexString"];
|
||||
names = StringCases[$Version, name___ ~~ " for " ~~ ("Mac" | "Microsoft" | "Windows" | "Linux") -> name];
|
||||
If[Length[names] > 0,
|
||||
globalKernelUUID =
|
||||
ToLowerCase[StringJoin[
|
||||
"WolframLanguage-",
|
||||
StringReplace[First[names], Whitespace -> "-"]
|
||||
]];
|
||||
displayName =
|
||||
StringJoin[
|
||||
"Wolfram Language (",
|
||||
Capitalize[
|
||||
First[names],
|
||||
"AllWords"
|
||||
],
|
||||
")"
|
||||
];
|
||||
,
|
||||
globalKernelUUID = hashedKernelUUID;
|
||||
displayName = "Wolfram Language";
|
||||
];
|
||||
|
||||
kernelScript = FileNameJoin[{projectHome, "WolframLanguageForJupyter", "Resources", "kernel.wl"}];
|
||||
projectHome = Directory[];
|
||||
kernelScript = FileNameJoin[{projectHome, "WolframLanguageForJupyter", "Resources", "kernel.wl"}];
|
||||
If[
|
||||
!FileExistsQ[kernelScript],
|
||||
Print[nopaclet];
|
||||
@ -120,8 +142,10 @@ getKernelspecAssoc[jupyterPath_String] :=
|
||||
];
|
||||
];
|
||||
|
||||
addKernelToJupyter[jupyterPath_String] :=
|
||||
Module[{baseDir, tempDir, exitCode, kernelspecAssoc, kernelspecs, kernelUUID},
|
||||
addKernelToJupyter[jupyterPath_String] := addKernelToJupyter[jupyterPath, mathBin];
|
||||
|
||||
removeKernelFromJupyter[jupyterPath_String (*, kernelUUID_String *)] :=
|
||||
Module[{exitCodeOld, exitCode, kernelspecAssoc, kernelspecs, oldEnv},
|
||||
If[DirectoryQ[jupyterPath],
|
||||
Print[isdir];
|
||||
Return[$Failed];
|
||||
@ -131,6 +155,56 @@ addKernelToJupyter[jupyterPath_String] :=
|
||||
Return[$Failed];
|
||||
];
|
||||
|
||||
oldEnv = Environment["PATH"];
|
||||
SetEnvironment["PATH" -> StringJoin[Environment["PATH"], pathSeperator, DirectoryName[jupyterPath]]];
|
||||
|
||||
exitCodeOld = RunProcess[{jupyterPath, "kernelspec", "remove", "-f", hashedKernelUUID}, "ExitCode"];
|
||||
exitCode = RunProcess[{jupyterPath, "kernelspec", "remove", "-f", globalKernelUUID}, "ExitCode"];
|
||||
|
||||
kernelspecAssoc = getKernelspecAssoc[jupyterPath];
|
||||
If[
|
||||
KeyExistsQ[kernelspecAssoc, "kernelspecs"],
|
||||
kernelspecs = Keys[kernelspecAssoc["kernelspecs"]];,
|
||||
kernelspecs = {};
|
||||
];
|
||||
|
||||
If[MemberQ[
|
||||
kernelspecs,
|
||||
(* kernelUUID *)
|
||||
globalKernelUUID
|
||||
],
|
||||
Print[notremoved];
|
||||
Return[$Failed];
|
||||
];
|
||||
|
||||
SetEnvironment["PATH" -> oldEnv];
|
||||
|
||||
(* Return[kernelUUID]; *)
|
||||
];
|
||||
|
||||
addKernelToJupyter[jupyterPath_String, mathB_String] :=
|
||||
Module[{baseDir, tempDir, exitCode, kernelspecAssoc, kernelspecs, kernelUUID, oldEnv},
|
||||
If[DirectoryQ[jupyterPath],
|
||||
Print[isdir];
|
||||
Return[$Failed];
|
||||
];
|
||||
If[!FileExistsQ[jupyterPath],
|
||||
Print[nobin];
|
||||
Return[$Failed];
|
||||
];
|
||||
|
||||
If[DirectoryQ[mathB],
|
||||
Print[isdirMath];
|
||||
Return[$Failed];
|
||||
];
|
||||
If[!FileExistsQ[mathB],
|
||||
Print[nobinMath];
|
||||
Return[$Failed];
|
||||
];
|
||||
|
||||
oldEnv = Environment["PATH"];
|
||||
SetEnvironment["PATH" -> StringJoin[Environment["PATH"], pathSeperator, DirectoryName[jupyterPath]]];
|
||||
|
||||
kernelUUID = CreateUUID[];
|
||||
tempDir = CreateDirectory[
|
||||
FileNameJoin[{
|
||||
@ -143,8 +217,8 @@ addKernelToJupyter[jupyterPath_String] :=
|
||||
Export[
|
||||
FileNameJoin[{tempDir, "kernel.json"}],
|
||||
Association[
|
||||
"argv" -> {mathBin, "-script", kernelScript, "{connection_file}"},
|
||||
"display_name" -> "Wolfram Language",
|
||||
"argv" -> {mathB, "-script", kernelScript, "{connection_file}"},
|
||||
"display_name" -> displayName,
|
||||
"language" -> "Wolfram Language"
|
||||
]
|
||||
];
|
||||
@ -174,32 +248,18 @@ addKernelToJupyter[jupyterPath_String] :=
|
||||
Return[$Failed];
|
||||
];
|
||||
|
||||
(* Return[kernelUUID]; *)
|
||||
];
|
||||
|
||||
removeKernelFromJupyter[jupyterPath_String (*, kernelUUID_String *)] :=
|
||||
Module[{exitCode, kernelspecAssoc, kernelspecs},
|
||||
exitCode = RunProcess[{jupyterPath, "kernelspec", "remove", "-f", (* kernelUUID *) globalKernelUUID}, "ExitCode"];
|
||||
|
||||
kernelspecAssoc = getKernelspecAssoc[jupyterPath];
|
||||
kernelspecs = Keys[kernelspecAssoc["kernelspecs"]];
|
||||
|
||||
If[MemberQ[
|
||||
kernelspecs,
|
||||
(* kernelUUID *)
|
||||
globalKernelUUID
|
||||
],
|
||||
Print[notremoved];
|
||||
Return[$Failed];
|
||||
];
|
||||
SetEnvironment["PATH" -> oldEnv];
|
||||
|
||||
(* Return[kernelUUID]; *)
|
||||
];
|
||||
|
||||
templateJupyterPath = FileNameJoin[{"path", "to", "Jupyter", "binary"}];
|
||||
templateWLPath = FileNameJoin[{"", "absolute", "path", "to", "Wolfram", "Language", "kernel", "binary"}];
|
||||
|
||||
helpMessage = StringJoin[
|
||||
"install.wls: Usage: install.wls add [", templateJupyterPath, "]\ninstall.wls: Usage:\tadds a Wolfram kernel to a Jupyter binary on PATH, or optional provided Jupyter binary path\ninstall.wls: Usage: install.wls remove [", templateJupyterPath ,"]\ninstall.wls: Usage:\tremoves any Wolfram kernels found on a Jupyter binary on PATH, or optional provided Jupyter binary path"
|
||||
"install.wls: Usage: install.wls add [", templateJupyterPath, "]\ninstall.wls: Usage:\tadds a Wolfram Language kernel to a Jupyter binary on PATH, or optional provided Jupyter binary path\n",
|
||||
"install.wls: Usage: install.wls add ", templateJupyterPath, " ", templateWLPath, "\ninstall.wls: Usage:\tadds the provided absolute Wolfram Language kernel binary path to the provided Jupyter binary path\n",
|
||||
"install.wls: Usage: install.wls remove [", templateJupyterPath ,"]\ninstall.wls: Usage:\tremoves any Wolfram Language kernels found on a Jupyter binary on PATH, or optional provided Jupyter binary path"
|
||||
];
|
||||
|
||||
If[Length[$ScriptCommandLine] == 1 || $ScriptCommandLine[[2]] === "help",
|
||||
@ -210,10 +270,18 @@ If[Length[$ScriptCommandLine] == 1 || $ScriptCommandLine[[2]] === "help",
|
||||
command = addKernelToJupyter;
|
||||
];
|
||||
|
||||
If[Length[$ScriptCommandLine] > 2,
|
||||
Switch[
|
||||
Length[$ScriptCommandLine],
|
||||
4,
|
||||
command[
|
||||
$ScriptCommandLine[[3]]
|
||||
StringTrim[$ScriptCommandLine[[3]], "*"],
|
||||
StringTrim[$ScriptCommandLine[[4]], "*"]
|
||||
];,
|
||||
3,
|
||||
command[
|
||||
StringTrim[$ScriptCommandLine[[3]], "*"]
|
||||
];,
|
||||
_,
|
||||
command[];
|
||||
];
|
||||
];
|
||||
|
Loading…
x
Reference in New Issue
Block a user