From 704627daa22aa4ff18c23cc2a4e40c80bc36985a Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 14 May 2026 06:26:40 -0400 Subject: [PATCH 1/3] Make dependabot less unhappy --- Makefile | 3 ++ README.md | 8 +++- img/logo-32x32.png | Bin 0 -> 1862 bytes img/logo-64x64.png | Bin 0 -> 4679 bytes install-kernel.py | 104 +++++++++++++++++++++++++++++++++++++++++++++ requirements.txt | 2 +- 6 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 img/logo-32x32.png create mode 100644 img/logo-64x64.png create mode 100755 install-kernel.py diff --git a/Makefile b/Makefile index aeb5bb3..b024802 100644 --- a/Makefile +++ b/Makefile @@ -12,6 +12,9 @@ all: $(NOTEBOOK_WHEEL) jupyter lite build --contents content --output-dir dist cp -f index.html dist/index.html +register-kernel: + $(PYTHON3) ./install-kernel.py + #: Remove Jupyter Cache file clean-cache: rm .jupyterlite.doit.db || true; diff --git a/README.md b/README.md index 4b9b28f..ba4e41e 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,13 @@ source .venv/bin/activate pip install -r requirements.txt ``` -The above also needs to be done only once. +Alternatively, you can use pyenv: +```console +pyenv local 3.14 # or whatever Python you use +pip install -r requirements.txt +``` + +Like initializing Git submodules, setting up the Python environment needs to be done only once. Once the virtual environment has been set up with the packages installed, to run the server: diff --git a/img/logo-32x32.png b/img/logo-32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..e981c4d50504a4a2ae21afa08db3e6fa75d402c4 GIT binary patch literal 1862 zcmV-M2f6r(P)kdg00004XF*Lt006O% z3;baP0000WV@Og>004R>004l5008;`004mK004C`008P>0026e000+ooVrmw00002 zVoOIv0RM-N%)bBt010qNS#tmY0lNSI0lNV@?Bn79000McNliru;0Xv92sM>A0Ac_D z1+hs)K~zY`eN}sK)YTb1=l(X?&0{yO-DEe}%>xUzc0e46o!VAm&=eXSD`*u)tYJo> z(?YSdGOaWN4i#GkskU0s4pOnUO(&($p=#@>m|`W;U?*`vGLS4J&}8!<4@fq@-#z^U z#7AiFf8WeG-~GPt-tQa=mpf(QjBCAWRC6|`fXwLtspt9C` zS`oRh>aZtx7!|5UkozFcM4Wjr^s$#KlY1_kpkk?gMn@G;9yZuqg!L6wasrMF-(eGa zIl(8{&a<3@6(@I1Y9X=GZqq?6vH5mG_p|m5`E6Kz+F}2s5nCz0`{wBe`%_zq71)FA ziSJyxR}h4FeSEBJIJzLVDf(9NjN%u=$BN!4e7~Sp5DM=re81@J@R7))MP((;v30T8 zWyA5Yc>M(?1)$;%yUX?~pb0y!9);9vf1tUXHLyq)h~}jC@kJ#0u*t$%lVBzTW|R?g zcV`1YVXA+;&4%$iuU2QhTy@D+q0YfY!@$-HRp!;3Im$A*W{7@-ok13xH+ie+_J97^ zxB=1+D2~%3Ebi?M9vTQmHPWXT)oStH{V-yUb;^OGMjh7^^6b2eqph|+`+e^ep4P9tZmqPQsxLm<4f5<(S^fc@a=bc&3Rq?7 zct#y&svir2#SDb*RTT#Glk>|*cb{tFfqyH8xw!dMf=`({SYJSf(saesb=I6$bzZ=9Q_4B5Z za%I8QxMnEHxAES`>A-N0+VL{~qv;yA0|-XTbrX6e#0|@ESiiKjm=2*HN$le^U7@y5 zZ=G$^m3FEc*@uTAU5D#Yk5eo&7{#dbJhJs806Pc2JM<`eRfy!IE$=`Aox__4zGeOh z=pprHH!6)$gBHy4N=%1J`D))5S*7_5iHb?W5h1xno@{CpUQ^JtkIdi{v>3E7%QWdK z4r1scHV+Q(4ov$vJ#eMD3yzcZVKxq7u6cz-i(v~0Arl3-BXU=y6u=cG$yPqdybtNQ zC8i!t97Yw8Ulm!w8Ww;U1=+$xsXBC8i@j~uFWR)1gwKxQh@Ghq)MQ6RCx004ceF&QS?H;)7W<}lklVcv>;+uY6| zGq^?GMNysVA8%Jg6LwtZ(PlrV9iV?E%LP<2k@j*$;aR~?U+H=6wt8W|CwXs zmsC0N1-`0GJY^4QroB@RAS(;O1>t}+G!RG4Z`sW0+{m z6Cgx@G{a;ABePT>%h=S&#LUDT#0SfONT5nC0O}VJbn-$ql>h($07*qoM6N<$f^M=? A$p8QV literal 0 HcmV?d00001 diff --git a/img/logo-64x64.png b/img/logo-64x64.png new file mode 100644 index 0000000000000000000000000000000000000000..aee6e70e7d79750baa18848f989a66e8d8466ab2 GIT binary patch literal 4679 zcmV-N61eS&P)004R> z004l5008;`004mK004C`008P>0026e000+ooVrmw00002VoOIv0063uBQgL0010qN zS#tmY4#NNd4#NS*Z>VGd000McNliru>IDrA6AQm&&Y%DQ5r;`cK~!kot(kk6UR8C* zfA2ouZSJ?sB$LccZX^N1C4_`<69@sKAQFY5Tr3u`=pz=9Qj}V>La~6gQm`meK`Lm= zrHT&5CI`-AJ@Os{hc zu!+Q|jLFR57!Ie62Fidud)US+EaxR{j`JzD{s}(y$G+GKDJHYPXE2L#WC3FY7$IPo z4p!<3p7Lf&+y8t7zRbNS=VSO73uz<57?ao}tfGO5Sb=~55wnda^dr6Kq4qxqffmSc zJfC7A^~Bf-yVyy_tyB`TlL~4vZ)h_xg%(AKh&?RkE}p0Ghj!wC1X>A-XL1D}p@EVU z^Gz0z zamg{Tp3n0GI(FpC2BJ+#RtpfO!#8@3i*d2k9agf7xs;QTsEoNR#9CiH+`!&HZ3o(D zQTvg;o)3_6$q6PgbnvQo@H*?gkqW-e!3+~f>rvlKt7dYDCep|R$|M3(P>K>i*9~5U zxBu}3S|H7Ne1(Ht!j4I70yaS6m^^!2pau9DlbA(8-PBS}qyShTkO)d6MZC_f`XTxD zKaM~Ps`gb}NwpLAvB!-B2K+dA*D{7NuB8ka5=Lv(8=+toprCUFU6^l1eL zX|gg5>08`P|L;>sz4PQ_G}brrae@c@3-0xCTw(JF*EA08$|&b*TD_3-sl-4N2{B-= z=HIl6o@7W#AgNRnA6DA`qo;i_pH-u;rim}N>=th)@wOmrBS9^`jSIlT{wCKZdA>-K zU*k)33{i@0Px3=fO8h7$Ge(`{_&28PMPJ}Q_8tkN#( zsnby`$TWJjVvbbzZQU+X=K0B46pNkYg7Oc&^W5o+IbU@Cgoc zpvyn!RxjZ!YP_5uP#gkah#d5CGBs@A@7X{lb<}DOClS#`N=I=nXQ>8JBvRl=?F-AQ z-S;~JZ6xpk-$JEJhKSgSvs5@ZCb*T1i;h|0AA1$^c|S$&Wu+M&T}2N1n9RY{c!^(N zFVkqis%N?akW)RCASr`DY0dU4yjDZsn*^!}ZG4+)lz?5{KsA9iE;&bHQ*vx!H~SP$ z^wHF?o$u1uyZ;jbQ39&F6+=mb%62g~`DR}*vu3piR$M4&*sp4E$NP`6@InxiXpJZU1OwOE&iVW#SP zI*~}7d|1yXMAeYtt3H9m8~Fmeob^XpM2;A|&eyWNharYMG??DTO6ItQUUyPP71MnJ zM{pYF=@2R?(WNvgJ$CMGYqs?c4mnRQ3ERDrQ&fkAV%CRty4lNFN~xMizaS34EY2hW zUi9Xqmg~6DV{L4+bkFX$W=fCuBqx53EB#GxbdfBxIg+%CUh7-O2iJf?ho4A$FP{vL+V~Sqa;63}(l;JSflJ`qV zaD%gsow(?d6PKKIeKO!xl-$N7@24yj`&CMqUG&q;jeH>~`VB)&qZgT|W-MR!1Y#0i z=N!(q{3>5#qT6f_@awWT4?r3s&h<0~95|n2T|tp8{ERhJQ%Q}E@#*B2b6$iMmW_Nh!Xe-)goRbtKIrm4hm^ zB&xZPg(QwK5%3gW@CN4dA=`;Fl=&GIGgK%U&w0$Tu?t?q1Kb~0d2pDR^uA~0Hr6pu^@{XcRj7uZsOCD49ob=qxSr)P=_-GU3B2q(m`62@hRc1XYl*RU z@K0eyGF%)5f740~67s3_ba0%~lA4&OLrCi)jngjuvu0{ML;S+UXq(3HKA{?wQ>H?o z5feGG$#9S`Zl=`<8??kfafySuhFOSC7l18EN3#D8c)JxzNVd=k-sfGUIgT$eg`ywg zc{Vy>5@R9Bcp6~WQb9sfpn9~^i4mtJRe~whQuOMijF^&fU@!m0JrtdIqlz5BwAWiL z_VP`B#y&^J1@cK?H6`jbNidl?qcLYpRUnHUSi@rAaApb3Aj<$1x`j`WLdb9U0cXfD z#6}o85Q7pMiK+7-Kk#mZ$a00g>Jo$GJOh}|I12ojP79MA>FBISxQl+*aJJG+1u}e^ z`J~yx%Oo76bC^!>UJlr44FSB)5IJV}L$ngJiVkut;?qP(Q>o`HQr^b5c#Z%lP(%!{ z%rAHa@&eDM6_cWxVIJdZ-@q2qK3B(JI^4q_vK{UPKET;Ttmk^JWhn`bq%m#0--p{Q zj@IjWVxSlpK;-EP13btuy_abfuiQp3OibGk_<&3TPri>hmM8f@gDdTQnA0Fn1 ztRnzrf!qP%MZZ)60x$W$;!;1*LnwtOxp&leo+nkL$_t5rj=&}mT&%NngwE86mx6YP z&fod%)EfjM7R56~`aR*Z2+j4WfOuK^<7E$^trQR_r;F6eWz1IsY)Y|~7&FHIqHa&4 zAX^O4`_@%a=J5#B>`Q%fwEMkNLEIMpO7%d{__RuX%cCJmNHGx$_#p?80bC5MTIH^T~QX#y26hjEe1vhNC>L)E&3saT0bYq9K2{4qGi2ULYv$4*il zMYTqbi!>CPUquJ1|Do5>N7qA}!F_ihe&5vN*%}I$nX7SVg2U zsv2p%8v)+Oxd@oT7{C-6Ah3(|f$gj#AVi{J)lmnS>0IkGG^4JeCMz_KGOU%{#ZKjP zzD`WNBN%faouRXpW)pX69imosqBd986d&%7a22%xRH=xD^IGP!B&T?e zf9Fh{LC%&rgOl7tr*^R26O^JrL)hvkeSvCyY23rc9M~SM{0X!8xGKo&31umlRmop! zm=>C8q(&KuprAe;WCb@cNdjJQUafG7e?qzKulnn*^N)R$yRge$a$=FVo2f6)}C`NFU^c}^)(-l_*w%27~JYU4T%MXdGrmE{UeBe2Z3M4c&u3sA@D z8n2)peU6h9X)*VZD5Id5BC|Of=;pDAb^-wZtEB|Z$#O4)pE5?q)b7B zg&20xn5 z_vt~T393}kkoIeO0~ATWpgUDiMj7qZziKVKsd)%u4J)Wlb>#IeJp)2js>7P4GZaYa zw^}@c8~_6D3z@YwBzamnkpyYQ1>PV4P=wM})Qlv^v52^5$yF*r@ zNP$Fm^B`7WoX(~JkphB>d_UIrBn7pYO!kGNgc;ka-qU(_OU3X&qyTEYz))lEki zHIW1sai7Z>a^m0wx#%u7dIgdHg0xFKz^(Kr0OPsZ3khuUO*H5l#xTqebr=0Yc#3Y~ zScx7URm+ zW@QOV^NP;%h7_CMNdQ_1_+0LG4JGh;&QGl!uBFw7@Oh?rfPJnRZ6{>C?P~+pNXZq5 zwTC9<_zkz~b?pjy#_)jVV^ZqXCwatg(Tm?AR&S>je##-b-Vw28`0J%Bqpk7Y@TyPb zQ1Yzd1mpy>RIgG&mWTkvl*m)$R1U%l?9;QHqljnu6$B{fYP}DLRMIzil()&%Z&SUC=ajCwhqm|Y=UFZJ{izQB0N-3(*#5Ji%$No z1OWP|8R8lBXcpBH(x86C(;TfzWwb;+eo^Z+P2)64r)#GEQWvUT!+Ml!!wbP`*5@>x zKHV20jYkTK)S-XmmUo+%yvNk6kGf)5o-AW5lawaS1m)C7nWpJbb*evX;uU7lLK%nA zMxSFC;NWsR8RB})=RCiUW`ZH!KQB&3 zQ`3l-pwUJjhy)2c^c)ZIG~MPvgUdfSx}87-8BgJOPGS}3@CL83R;zi9E|rGq_@g}k zA6d%#womVwp8x;=8FWQhbW?9;ba!ELWdL_~cP?peYja~^aAhuUa%Y?FJQ@H1002ov JPDHLkV1h;`sSyAG literal 0 HcmV?d00001 diff --git a/install-kernel.py b/install-kernel.py new file mode 100755 index 0000000..9345795 --- /dev/null +++ b/install-kernel.py @@ -0,0 +1,104 @@ +#!/bin/env python3 +import argparse +import json +import os +import os.path as osp +import shutil +import sys +from tempfile import TemporaryDirectory + +from jupyter_client.kernelspec import KernelSpecManager + +KERNEL_NAME = "Mathics3-Live" +DISPLAY_NAME = "Mathics3 (using Jupyterlite)" +# The source directory for icons relative to the project root +ICON_SOURCE_DIR = osp.normpath(osp.join(osp.dirname(__file__), "img")) + +kernel_json = { + "argv": [ + sys.executable, + "-m", + "mathics3_kernel.frontend.jupyter", # The module that handles the kernel loop + "-f", + "{connection_file}", + ], + "display_name": DISPLAY_NAME, + "language": "mathematica", +} + + +def install_my_kernel_spec(user=True, prefix=None): + """ + Creates a JSON 'kernel.json' file custom for the Mathics3 Jupyter kernel of + this project. + """ + with TemporaryDirectory(prefix="kernel-", suffix=".json") as td: + os.chmod(td, 0o755) # Ensure Jupyter can read the directory + + # Write the kernel.json file + with open(os.path.join(td, "kernel.json"), "w") as f: + json.dump(kernel_json, f, sort_keys=True, indent=4) + + # Jupyter specifically looks for logo-32x32.png and logo-64x64.png + icon_found = False + if osp.isdir(ICON_SOURCE_DIR): + for icon_name in ["logo-32x32.png", "logo-64x64.png"]: + src_path = osp.normpath(osp.join(ICON_SOURCE_DIR, icon_name)) + if osp.exists(src_path): + print(f"Found icon: {icon_name}, adding to kernelspec...") + shutil.copy(src_path, td) + icon_found = True + + if not icon_found: + print( + f"Warning: No icons found in {ICON_SOURCE_DIR}/. Kernel will install without a logo." + ) + + print(f"Installing Jupyter kernel spec for {DISPLAY_NAME}...") + try: + KernelSpecManager().install_kernel_spec( + td, KERNEL_NAME, user=user, prefix=prefix + ) + print( + "Successfully installed Mathics3 kernel in mathics3-jupyter/kernel.json" + ) + except Exception as e: + print(f"Failed to install kernel: {e}") + + +def _is_root(): + try: + return os.getuid() == 0 + except AttributeError: + return False # Windows + + +def main(argv=None): + parser = argparse.ArgumentParser( + description=f"Install the {DISPLAY_NAME} kernel spec for Jupyter." + ) + parser.add_argument( + "--user", + action="store_true", + help="Install to the per-user kernelspec directory", + ) + parser.add_argument( + "--sys-prefix", + action="store_true", + help="Install to Python's sys.prefix (e.g. venv)", + ) + parser.add_argument("--prefix", help="Install to the given prefix") + + args = parser.parse_args(argv) + + if args.sys_prefix: + args.prefix = sys.prefix + if not args.prefix and not args.user and _is_root(): + args.user = False + + install_my_kernel_spec(user=args.user or True, prefix=args.prefix) + print("Installation complete.") + + +if __name__ == "__main__": + main() diff --git a/requirements.txt b/requirements.txt index 56e5bca..8c4b7b5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ # Core modules (mandatory) jupyterlite-core==0.4.1 jupyterlab~=4.2.5 -notebook~=7.2.2 +notebook~=7.5.6 # Python kernel (optional) From 79dae0db51a7ad961108d0efe7325b4dcc5eedcf Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 14 May 2026 06:28:58 -0400 Subject: [PATCH 2/3] Add dependabot file --- .github/dependabot.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..4f43e94 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,6 @@ +--- +updates: + - package-ecosystem: "pip" + directory: "/" + schedule: + interval: "monthly" From 2f623c52ec5409e7fdbe06a130da246cb664333f Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 14 May 2026 06:31:49 -0400 Subject: [PATCH 3/3] Dependency hell Update the minimum version of jupyterlab. This is all done to GitHub's dependabot security warnings --- .github/dependabot.yml | 6 ------ install-kernel.py | 5 ++++- requirements.txt | 2 +- 3 files changed, 5 insertions(+), 8 deletions(-) delete mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index 4f43e94..0000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -updates: - - package-ecosystem: "pip" - directory: "/" - schedule: - interval: "monthly" diff --git a/install-kernel.py b/install-kernel.py index 9345795..862e96e 100755 --- a/install-kernel.py +++ b/install-kernel.py @@ -1,4 +1,7 @@ #!/bin/env python3 +""" +A Command-line program to create a JSON kernel.json for Mathics3 JupyLite kernel. +""" import argparse import json import os @@ -29,7 +32,7 @@ def install_my_kernel_spec(user=True, prefix=None): """ - Creates a JSON 'kernel.json' file custom for the Mathics3 Jupyter kernel of + Creates a JSON 'kernel.json' file custom for the Mathics3 JupyterLite kernel of this project. """ with TemporaryDirectory(prefix="kernel-", suffix=".json") as td: diff --git a/requirements.txt b/requirements.txt index 8c4b7b5..3a93343 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ # Core modules (mandatory) jupyterlite-core==0.4.1 -jupyterlab~=4.2.5 +jupyterlab>=4.5.7 notebook~=7.5.6