From 4265be6e4386a2d8b00436aacbef1e37d2ebe2d9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 7 May 2026 21:56:30 +1000 Subject: [PATCH 01/11] Update pre-commit hook pre-commit/mirrors-mypy to v2 (#4525) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 7ee79056..6cf16130 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -31,7 +31,7 @@ repos: args: [--config=.flake8] fail_fast: true - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.20.2 + rev: v2.0.0 hooks: - id: mypy args: [ From af106eb23838fdee05e1025ff259533f7a965be5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 7 May 2026 21:57:10 +1000 Subject: [PATCH 02/11] Update dependency mypy to v2 (#4523) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 28e91c2a..9fee23fa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,7 +34,7 @@ Source = "https://github.com/archlinux/archinstall" [project.optional-dependencies] log = ["systemd_python==235"] dev = [ - "mypy==1.20.2", + "mypy==2.0.0", "flake8==7.3.0", "pre-commit==4.6.0", "ruff==0.15.12", From 2de7254b21ddd4d554b9933c8131133658fed9cf Mon Sep 17 00:00:00 2001 From: Lena Pastwa Date: Fri, 8 May 2026 03:28:36 +0200 Subject: [PATCH 03/11] Update Polish translation (#4529) --- archinstall/locales/base.pot | 11 + archinstall/locales/pl/LC_MESSAGES/base.mo | Bin 62517 -> 67521 bytes archinstall/locales/pl/LC_MESSAGES/base.po | 237 ++++++++++++++++++++- 3 files changed, 247 insertions(+), 1 deletion(-) diff --git a/archinstall/locales/base.pot b/archinstall/locales/base.pot index 31f5e196..0b08df29 100644 --- a/archinstall/locales/base.pot +++ b/archinstall/locales/base.pot @@ -2293,3 +2293,14 @@ msgstr "" #, python-brace-format msgid "Default: {}ms, Recommended range: 1000-60000" msgstr "" + +#, python-brace-format +msgid "{} needs access to your seat" +msgstr "" + +msgid "collection of hardware devices i.e. keyboard, mouse" +msgstr "" + +#, python-brace-format +msgid "Choose an option how to give {} access to your hardware" +msgstr "" diff --git a/archinstall/locales/pl/LC_MESSAGES/base.mo b/archinstall/locales/pl/LC_MESSAGES/base.mo index 4a57d37caea35cb2f39e0904bfcdd33b192b6be0..0ab34f9eca17057f5f6a378cba00b090d27ae98a 100644 GIT binary patch delta 18125 zcma*u2Y6If9{2H^2BG)fh8`p&^d=A>2_T__-V_{?Aq+`o!pwx201l#v0%93N5EQVB zpvYLTi-H1TMJcX|imtA%3bH@SM@(1DX5n&7$4{^U*5=?G zY=`a9hcoduY>3}sb&Mb6I9|sIJGBUOKpD=$_fR)T8|*mqa4}B9&v6nC9O5|jaIJMK z)*;`G)$kRZfQK;&TW2^9&*OAJH82I6;GkF@cAUusYSDb;;hiAX#~ZO0ZpIq8-R4iB zF1!!*M2E00o6Xq9yY_B*act54q<{b1U$6Uc$nj4<0Pz!8&Ma2 z0Cl6Mk^eb|`6Cr;4>$Rx*p7TDs%N&M8n_#4;~vzFU&loJ4AoPA$FQFKG(i>o9o6#q zOvg#a=BTc1kJ{f0)sTVM6vx|qKI+CxQODnm9dHY(NA_W3JdXYF2V@#KowFGKJ_PP8 z$LWiApz^n{B_`4x?XWE}Z=5V_kISt0p)Pm;HRkH)7BCT$(1#k*5Naq_*?a@4L6450 z|Mf)ssn8RBh*j}NRM-D*tvS*RNh?&(T!M+%3)8SaYR(j(&Z|Im@oLnKZpU7@1Jy&H zVh21Own3v&%uFf`bts0KKrO;5DPDx_Ue4d{t_(jlmxn}BNQJe!A6J+RJtKkCL$ z*?d2$;YX3{g`HCbovHW%b)zOZ=80OP#x4buaR}3MOd%zh`$G#UA9}pe9R8uBMjf;&@z%SK=}3kNv6C zP%Xq*m!o>x;2DgSy_liS$430%sc)oa20n-LT&zGgcnd zEWHyi$K$9c=`-2%)Hr0?ILojTzJYD=tj!xvF%7#Eb;I#E99N;P`{oq-e<(qXsitLP zP?O7zsaTHP@d0dr$52o9Eou(@Ve=}}%#E91W9kQBbcl580}r4YkUTqfg3|z-koQEUgEJaO;N3VFzr>o@ zehxRo?x-FOVQah=JK{aqS?m7*K`kmyqt^3zR11@?G(%Gh)wK;!PtqPWBq^u{_r}qf zgQ{O|y$4&6KZ@$nL#XqQU^6_94YZma}TNq_h1ivFHA6t6)c78k(%Bs2&WL+29&f7q3QL zc)hK^+vX3UmgO#6|0=3S-bD4#$Ecn-i#(H4V}Ti}0P4D7Y>ul?4ZI&YKI}Y7pssrz z)itM3UH2#IhK&l%tWH6V;D*mTK*ks`BdR(bzO5**QTO+WT168s;ft%o@542!MUjO_aM{5IgGrEoSr`B1Kx^y zfFDt-5gmX|0z7P9i_yB>P^e?Mr)OSEV$w=&ug{TH>w);8!9q4*_cRn*6ZTK`Q5v@B9l zT{{rf^6AJs#3{1-k7GUZzhh7Q1zTd*rKWxqs%K_mLtKKo@vW#EZ^gQ}3w52n*p&M_ zM{LDEQ7?$|sAZIJH7^&ei;ZvrX5cbZgI`AV%v-1-Oy**#m}1qBTdjiSsN>$jepr1O z|Ehw+F+7goMS_`F>l!l@^HE*94%2WCPQ$OT2WBicAESlHgmykh?Von7`I-J0PA0E; zotb2AEGOT9OdqHI3iCo*y@LLqO~pDY^rH9?^<=+c0w!N?x~wLu%UYqjG#%AbL+t)c ztWQ1})zt;4Au2=l$aYi@978=&y_M$uGIS+fqOSE)p?7>3b;3%F$0tw?c^W(8bEq4f zLXG8*sD>rpV8*^Nb|mj_^Vz7LSccQ_1Dt?qH=5g&k?nkS!tDdgL6C?3H~t^bBMo5?pF zHMyeL9>2s?tagk2`#O##Uyd4*chHCL<6g|X)f|^}n`zJlyn^~=sD^)nYCxxmndIX! z_WfT>;9|$Es2k9G=AbIR0+)hMaph<6n!4GAe4|3Y>+vqMqbCOu}=hW%UPYNZM^N zlPn8$!7EYqLDVbxcC3TDQ4M|t>*Cv})$%De!mqc4%>~X=QICpxTg{I4ID>ouPQwVc z!*6jk*4}3F890}G31;9))R?!q$9zM&U_Nlf{WqW{)h^Txo<=?SUexjLqn_wPtc|C!E&hc%ukC$ixu#${^6{vi3I_;u;?1a` zxF5AlqSzci!lw8$4#2wio0gBpOUYN^Abic{2@jZ|$-wT^&%&v=2D{=Z)GDa+VC)4I zb_Nj4q~a=6%Z^|YoTSXQK=Aum)a- zRq+53D z#=5B4+!QsoeNYV^gtc%i>V~sW4K2oGEPsstA4Ra73U%ols5#JJm$_g!tWG`}^#oI} z4$ep2=ql9lVN^pmqUOe%sBcNqlEyUj;#VVFQ&ayx45cVJz79qZ$9 zY=z%q2dow~c^VdwkHKO11m@s5)N&jCgt@^+976sA_QXF>%RT)`^KVGuYyvePh(mD| zHo`Zs6Mkk*e#-PnIu56P3{J(HaU%X5H8caBHcz+=CzHR7A#AkAJm4zqL4H4Se%Lui zkWNL~GsfAdE?SFC@h!~6uTVGc`mAZF5B21aVFNsajWOvt^NMYWeaLfA4|I+74%D33 zi7mALpCiy@JBI4wb66W&Ja2w*T!I?&t8g*ifO@jT7tAD@fz`<8T8mI~V-aeSE=8TU z0xK}?Me}uBg0;B6^A~|ySnDNoLVMH`b+vg0CXkOrH6#ab!&x{MzehD-(933ak3hQC znTVR@4`UwgM%6do%P?axhD!*3At*-gE2gWDVSVxzubOq9hI(Q2Lal}w*ah>kJ+4J{ z{chBQ9KcoB8MPf;!V1+`3S z9W?(DIRkZr8*wH^Z~%UfT`}d5d67*ia0Wp~D$21t zZb9An9qfhiht1coFE%4D#Fn@Mb%T3QUHmfYM(?4HJBvwJ^G)+YtB)G0_BQW}^hnql zX)C6oE;Jt#umW{~t5HvWoz2&xF0>9c*&ak4{{rgGxff#%K{fC!YI4?n%Ur)RYVHic z*!nMu1*~gS*WHKeq8Ct4@)7C+=TNh^*4yT9HYs>Dxf^Tarx=evpc-%%%d!4D=2!3< z)ODP9%^YchvG0Ft0<}C1t73-DN8)_)>8MGy7jy9d>W0nUGpi#7mG{Lum~HbZHqXaS z)Q2z`H`)68Fs#Y;1c9FHAkM}w>;aia%n6fFJ#jgzA&XGQFSYd>P*1iSHHizQaQ8!+X>d}W$4SyWfLwjuffumvbZ@2GIp;_JOnCbFNbd&GEBCLJfTwpP#k}pTi zmB&yGJ%F|FQ_RNiQC;2pg!!fnM%{QWs$l`t{uN;Yb;VlLg`U8gco@~<6Q~nEwVuX? ziA~= zF#pn#ifZ_J)GE3MH8i_X$DjEJ{jUo(`o>gr$Cl)iQ9ZB_b-`;b%t1Y=+ZsYWz)Eb5Z=kOK z4c5^5uk))J%ND37@nRMRa6CSZ{jutA=3_Jz)ulVJJMPC^Jcn9tBY!t@={l@J{vzr+ z`*A8Z`ok>qA`I(EZX;-qd$B2giR$|E=*6CYn$PTJ)be==HG9wFl{o6WX~@Iaj{HOH zfq&v`O#jRLykCnNlJ7ByXaA!AKOmUr#Kr!GGAJ%CHtDvahx+3<1c$`O#l~cWp; z3;Y;cK>Y$Zx0oKnYQ|jk=$ScMz**NMqag)V)rr+!(RgUqYu+ zw}BFl*duq@Bi^I(Bg$s#eYWmda&4=unb?dnm$K08a*~PH+G~AET|VU?m5sm!48!HR8L?1=+W6SXRaDeE}q3UVJ-Zu^PXuutw^I1Me{YJ_jing0LZxcR7J`=AcABlQxhnw+7U3+1|*p^5>i-Sku_0;Sm)^gJ3 zB_3msUqbvgWghj*@OO%~YSuAU)jh&FH&ROMxh>c?AwJd~^M2Mr+ODH~NcoEc9L zOuWEetO|A4Q~p7ojbrg4ybkrUs@#r5dZaZ8ucY>QTlFvE%I!_!NtF3iTt#Wf6)wk4 zl-H;qbL;Pf{hI2XYW6A`|eeBa#hgdHOwy-nUR^EwI*zq~FCu94} zANN!LD)k>y1`zB0%cs{FN<5M}ZBvK?CUjD4oznTlIq0X95^q$Dy(xnzAx-a0Dz7EE zn~Th+RBj^(9-@Aat@x2xTj-)=lU#fIqzm?A*G!9%I#+IRPsx4h^=41&MA}>@?45O1dmd> zam>?{H;G;L*g3@7!hQMUdUjTBZxHve2aTaJpST}&K}r6KJac9apN^kPr_8NNFSBQ6` zwj1^Q_3X~ZRJd(CjX0OMhzndwyp5tQN?i#hjry*p%9%mlh5QHdw!|}t9m>nZw@}7W zj#Jg2x=SdviJMTj8QW|9e?p>dhgH7>za(zU!Sg5;#ObjkShLp7_Sig|kG8o@WBijp z`*QwQ>?@<3BmeHA1MVXJwsQQtkZk4P&+rrn_a=Uf@|r#27rcU8KWo2X|3~;Bc@FVx z>_}NgNwdeV#RBrhcpJxP^O3(qd?lrZsdB>036`*95tX+Q-#~mnhV4m{?SWg#_Y?25 z^-1^zOywQ_9(QCuP0He=0Y8NPF#eGj3w%dCElg9me+5 zB@t`;iEV8htSq@iz&M{f_vC6J5PC+cskb9`nyB5Y>n*! zTTJTgC2vWYWOK2BGMTzITu@s(>p|+aQLdqGkgcn){gn3PIh65~Lh^r6PEnduM(X`v zx%DSl!9^xhx9Fn!U#Wk!@*wLf>*XAmM4U_+&$&TLI;G5>|0l6F7aqb~N}Y?Y9h-l7 z_Mn&9xs&n>c}LWCA0^H1?}WwVcW{B5(2b|5YecC+(KeBNFX6kC*0xUd z-Svl7cOeI8%VK9sd?J?dO~9o#eu87VQ)*L|+KX(6kGOj_h?Mk9)HC$4SJ4R#?OB!l zjo>$%)aSUG_6m1W*T}}#;Bb4)K#sYYyeEEbubaib71aHcJeBf}t@lzFp1{uA2()d- zM{QhoY#J!5dTVhelTU$(Bg^;YUz6Zhx5X_OAc{iwT_5+BbT zzL(19D0x)urrd5%e3ZIbHolBl+glVr$JE6asjEV1MXs%s(uMp4C5uu-d6M!T^{-Qw zP=2O#<@kowM~Uy&JG6}8H!3<%E}>{!kAIlZ`G+;p?o+y)i@ad-pKySUAEy2q;(W?y zwob<%rnDwMqQq`1Wol)HLn&jqz}5D|v*b02AE%6_zJVr9w+3XHWZJHz1jw%>Urp?x zG$sCnx}I1P9ows0m85xoUnm&$4Hz3gG~jg?rBC)2dxGhi{?dTg6L1AQB}MK$PqD`r zN_AzH2fRf^-aJ>Zw4}rz2)X9@1FlISkGnX%z|C2aXD(fqZK521z~lD0^5(k(?!1sE5RAM(XmIWM{xVm{?<(*v^0*c+jkF!yGg8#6ZKPyy zv&cieT186+pNLB+@&_U#GFC?RXLPC-^cQ)!vo93+DkHO2&{O2$TKTS!=c-Vo!_a*l z-O5b0*Y9)r=ecsSvR%1F?qIRoRpQPobQjRnFNV%Y4FqX_zQ4@pWR}L_BG0@~WgPGp z%)gM7mP7^)yQZ1Dv?w&twKyw##IPx2CeOKSa`wbIlP?>ay)?3ZSjS|$cWHF}uuI|^ zmw0^n9$%i<6LhjX!MuRCBt&x}FARS+(HkrbMoKe}C2;G==&XM>%k%SqwAx=9Dk(MH zN<)j?zDQd3=tL*mmmk?WvRUNS>@Lw~von*br1a>vcxjhN^_)J@>N!^@w9URM13d;_&K&+YU1L$0|Vm#4TSR305Wc}YToI~a<*KCMsm zr)h7;H+L8PzuFXiab|H`1NS0tL9B_+I8Ug|A1HLj-8QsgG~@Dm3H_a1Gg_{KfWNfl zKeK_AY4Aee^7_n?k!f>gL>`_qu5W?Im8Id$WyoD)G`O*7Vr*z*;S^n#ov~REi%LtP z|C*DPlsKW(8;bPvv=6)U%QZi3cRCY2bNxJWusj&@6qDuoi&-7{p8SjBf%I_fX_|FCM z?nAOpG{0i^D{z&TxTf?R;VSYMczrCE z(w_6?Csq}3|&#Vi&sl%zNd0p z=#>+j5z+W%&66YbCiZIU#8x#6!@s~AYs}n$zl`Ayy4=2em%F4S+Wdz2xGrTppKFTG z8+(Gv#;3Xp{Qi8`Jnl4?HNfeWfJn`xTub`|=4yv)6kz^2i4E8JWvufp$Rv3Ux4gG4u- zPMub+aVgAO;P?5<-0Z6G@J=gZKGLYrtI@KH-Yt=PHqX2?$GpeOT={wk=R#WKDf9n3 zD+#zSP77X*2KH@?{J#0gHd+4S^8K5Nd|uE0{WZVxt}eCz zpMU?RJg+mp#LHCM@_tfQIh_|dw&l$_(`$ib~&)~5^TnR1sNN$-2F zC-T6yiP1CLeydW|W#95cA8r#p^w5CBR^#UeD?9<8+s-+6-U9c(pFbM6(-YSr8XSx?!3t_WY609_<(1{OJ6+s^jT^BA+Lku&aJt zwOoH*#l95`LA2rH-^bU@_2=^fbCtORAs%ku%E;cQ8pgS!aZhwjtU8{t2>HB`u6std zo}zJK`gz^_WGG-(y1Ak&rO2O0&vc0{+_O5NgV*ORb{Bbrq4GS&`v3YA?nu|?)1zIU ze>$$tIIdTqXLKfcJ^NNhPrh(n!tmVKz&j%Yr6u~7+gb46xxNkB#lsuv-vUnYdYr6? z`=9M28}{ZzKH58R=A=-7ma^AOmkVjEpDtu(x?D)jba5`^|8=g}9qsl?a+NC6$`|DC ze>T$lKw8t0{*b>+-x*hh+k8qiqrL8k`#`fv6Fr5z!hL*%+&+B)F3SG*OQL0Kza*@H zR2OrX{`7KfcJO{F^8~1mmLJ$37tUqq%UHx09`Qm24Jl+r=eeDWt4hr17nWYAePwHz znKl;=W3I;5&qWoLT~bk6=w9Gt@zQ1P@vM`uP0Vd&&8)oDWdmf_)pEk+jeq z-SydmxUSQJC463KVCBnP<5A|_x3Mr-5qmMXIH97vkim&GJ2g3Zn#)d=qEkhQ;VEVA z0ym!{&MzyU8*uwHKKg2w@>`h?NYLxa^QO6CYr$1q8uYp<=w|o6m9Ajrae6$KU*&Wt z`;VDcUTi;5UQZhT|3ZF*=Xrt^u7H28muuulzxnFEQ#v zZ9$r=u!zOz4$+iUS8;i;qR{QcUR;{d=KH2+En%`16mh0I;3;%@`NS1@3)T4OO{Z(e z4baQW&$4ut{Z~h&GE;bB&43Dh&)hUTHiPmi+)l_{7&&<+EqeIO?09`&TAt}t)A{`R NTU^ul{gqeY{2#^#3aElidnW{hRBek+kk$wee2g+!&V z5LpVTM5&N0A+lvlRJQ)F_nhPR?>_z?&+|Fw+gzZ$*dfYsYWq3PlqA(UPI`*tG{i1g7w2LJ+=qQJvXL9%mD3fLpORev_Yj9Opa*jp%PIihlKZDlCCvSOr6|fz4Z^F5DgUM14>f&PH8$ zI<~{5*cvZj39QnHS@8|Pp&&anA%)D69;{`*i* zeguo*W#nNUr!jj78X&9a$}80vv9p=Rb*Q;*|Rqj1-DNK7?TRR?v!R7}BM zs3)F-TDzsz-KZzIfVyEY>!hhKgIbD)s2OT+^8u*6G|J`^Jrt@_G0VCYb-_y*grUvN zl0>0SEQ#8jNvJ2SkGgRun-4=h@f7P^)IgTod;^vz--%jk&uqLy$wYJfMeGbZtF4&?sM z1Pb-2IEH00yp5T{6x39=w0SR^4@b?wWYm){uYdfD~B@AwB2A+bcHY{Ww zPR9v&AG0tw-JE|C3zJ{8{)Iv0K}?Sy7Vg6Q>qb#j%*9yLhi5(NhUc+AUPJXu>uNSn zPt*Wb;}ATD>esfLHWl?)4THLyrLBYhSlt2kOQT zQ6~iVFjHF|xrfsf*|(01T8f{sAVxDy+6#$T2(wV*GljvZCy2&SERDsmBDTj=TR+G88tRk13N@3vP`m$2)E+p8ERDyxYYI+aZ*${f z7)OU#)RQ#9s+eZ$C!#LA1a+a0u?T*JmGLz4@pKAgnDaYeeew*fi7qDK7g$U0|5XZ_ z^7uYxYE!IfSc3XYjK-;00T-cev*iN zJ9{W-s!yWU`W))Xuc6+Kdscs5UbPoOU8n?V7neaTO(GV>O4d~LCGUwENCxW0!%#E! z40`l>ETj;Q@1UM+Gpge`EQR+m0*kZ7i(^I9+BZYpus3R^Mq>?}g}reb>bg+_%s>*b z9C>-1fN2Am{~QXRQ=to`JYlA)9rDIGy-}NM9cqd0pk^d^pxKm>s3$3l8gN}4is`5s z+=801y;u^zMQz3_sQ$MHddw3R9AuuL0_q8yqi)y-waG@IrubRZ6V1f@*9e=D??BDe zzsQT@lp1XM<>Dyv>8KgHW$QyT%>&1HC}<=#Q8!9MP4yF~H5-FkYxR>apf=Mhs3%#D zyz8HDU_j*gL<<0s6DX?1JH}H_z7yN ze?nd08fr%FqXwdRSA7U-=8B`PR|z$v4N-4NH`G#3$8viAmr&5u>_ELX$52o5D<W}+_m3~J^Up{}PQHGr9@0WU+{Xgen252%6tgPMtur_5Va4jYh<#+LXl zdNkte6zX8)D6>i0p=KZp%i|nui(V{?4^RV+8*Tb^M)ezmYF~mH_@}6W{f1hCM_2$O zv(4*WI-B`Vq9U7$%D4y%;peEeJ&d~Gb!!A43k|pyCSz~Zjb23c^I`}d#lm<7wMlQH zHt!t_!vbT>%teo3{xz~XR4`jkdsK(b7=e4SCLTo%C?wa^C!uDj9_qqg#SFZT+H7sdn!o=Cpa!%Y>*IRVd;A+#!N76G6zoVo z5Y_K})MmSclQDk0`Stt;^7oZ<6*c3Y))UN>=3+G}7GW>khc&Qt9^VG+j9kmvjcTv` zwD~bP7rT>R!8+JH)f=mNdgU6g2~5Q8P3JHBc|c>iz$ULJ(d; zy=FIUUZ2J$oP2ChV3ypKWnXcki$NFne=^Wg|XfAZp}k;b5=G9EQk-K@`Hb@Gjxp2G23S8-Djt(8#O3WY*>>)JTtFT}+;9)_OROAfJWB@HURY0xz3< z3To52I2zwX{?94=3ZHLWjvcVlJjY@6oIK+$fhv*Rr9)?#vWhcpw=WCwYGT} zfpcxX0yQ%qqdq`|7npDUFl)Dvz%4bW@b_oDX9?-+u&QBV31i(>d|=7W}mnvvS5{=F~>2Vhy8fic|Q zSxZ4D?n6!a3Df{CV>J3NHcwI-8*g)#j2?|-9R)qXLDVKXgBs8^)KvK`HF-3~l2=1bWk=K!4MNStSk#kF#p?JxmcUII ziifZ`{*1NokEP7NHbeP0%x&B9zdOV9^>%=mc-J_OkNLlgACMC4Z-?2 z0k!KtL=EU6>H(`RH%r@KIrFb4Po+Ww>4w_PnW(jU5li8Fwtc_#80tb7Q8)Y(<1t`` z8AuXpGuOmqY+&n0qVAW6#c;NVf~IgK>IuE53m?E({0TK9e_;)*{HFQ$et*;r-o_YQ zkDB_gPy_l7wU^GKu73kHLq03b>l=n`$vwp=w4v|>>OyO<0PaPN^jp--oI|bUAE*Hp ze9J6ZDmEs68b{-1oQ8?3%%*)C%aNZ)J#p~cX6fRPfqI+<6m+9BER6#&0jJn}B@QFs zh0U=1JLd0-EYvRl7iHT0sMxk_%OfS!%1t*d)eJO88s7c zVRPJtx{>c%e(PffHpTVW9e>Ah*z8^NWSdb-br^M?-#WAT`dDY9&fkXl|Ng&6p#>FD z@0lC+!c_9tQBQmV^}3Z_Z=RqA>Vwr5YhxbjNjF&cpw|94YV%%1&8Xi7^I@uh9m(rr z{=ffcP?$``LevvQyl?WMIEnlmK8O83Fc&_9y5V)y!2CZnn=u;w$m3CaCIRPTEz}M7 zV<;BgXlAC&M%F)=il?c_#Aj{81)NRZ=p*yvb3cwEuje&0wHhPIub@9Z!~*EM$$aU; zPba#w8adt0S1zHw06fJ^1c{>nH~yyg7K)SnS@1fCU(W8w*ER6B)^AxOM+V&}^@5pqlfN!Ce<^a|~&j|{;K;$Q8CQ?xs8jKpqB&>n2U_1N_ zb%W4t<}Z<=Sf4xxE8{wBi$^gUr{+U5 z0Be!Y#}c?7WAH3$CLW=tGG>RlK{ZsrP8fj0F&syu_Ke5o^RY1ZcUIX7FX}>jQM>pk z>Ho*=>H!HpDpcCO8oX;8^?#b)62MnSo~FaPo1Oj;GL*M4{T} z<}ZaFsLe3|wf3V?1DK8jaJg-NhO#kH5#GYGIBTDI-`_*+@^4Y~f1~z7sV~gH zYNKwPj(QC1ARM}1KOXt7*;oZ@e`((u3?`q1 z2{;{f-L+yS*5Tzo2gP2z8;z1EybP)P>rhmTVAq z#<8}24{An!!46pP8}rL3!#WA|z)O+qcpNVUO~pY|;oL^;?y!SqATijKydmm|Cu2M= z!xY?!srUyr!jwa159FZgmtbrB8QWl)Z_Rfm3!CWuf1N^M8jho8;xcNg1HLo6w_=^$ zW2nvdE9%Mqu@?Nz3^)#Bsn5g&d=7Qq8q^YbF&KR=n%{s0u(RI(&J^m=umUx8KVdT7 z#B?lk$$VIHu|D|+7>Jj#v-+WyF7>i`Enh=D@eVA9zhg9pUokUW5wpnqV_EL+?5CjD z;R?3HidW5tWh`nSKVn%7_}%<6s(=H?``{D!3Ho7)Yv%9$(#RX^yo#AP?7G=Q2XF|v z-wkuWEc8^RVl9Olcoa)v@J%z73D};z1$M%hQB!&f^@NvEn>6~C8Nf&kC(p(JdMQ-px*`vp zzsZt(`6f{2Lzn;S`X-H|)PZ9jq1miYpG#W*w`dq_8z*63;z=Tln4mK_+E8v|iq3xg zjeHVruysOf{3`Wxh)*fMj62j|k1xq}yn{awttprFFp3nC6-49wX7dM|HGk^LQa_8} z`{dNX--(IDV9tAd1W{N=)UXwUtq(SAc@+PJ!>gwYIUsP1m42@qY`Bu zTF1inX8Jzp7(-h;bzO;ql<(WVYSV@sPyQ9rgK{7G=(T;5d?xW6WgS|!WFO}L5S8YS<)J!(!%KdPC~s0{Ds~~)Q2=`o*9gxmRJ=jFK-?jU+fMr^4r9H|CPh`UyQM~>~H%uw0(M!2NPf0JcV*4)5nwlVdz29*q*Ez8A177+xb_@<%ovF zd(?eI#1XTJTGZ)y11l3XxX!1xt}ad{dQvym)-|B-4@67qZtFy?|7xg6g^t2>{E^t5 zpD_c}mmqdiSCYDQ7(#5K{5r9U@*q5dQwbfR^gmDeBO;G{WPYvr;W3}ONb=8dHnBuc z8&3=)ic*n_yNC!b(w$sKBjTVf*T)vL<>a@RKdL}C>iG!fe@*}TPg@Lq-=*yfdwwEq zZxdnUo+VzQ{Ylz% zyhhxmZfSnTw*ZF_-{}30_q6GuBgA+UZ?ygafWhJ zT!`n0Aj&#M5JmD!{Bw=EuWh{#1Di(qGp)al4-NT$Hl*=BrG<28LbN8=U(3fRug7Yr zqdE2Zh4c6rVC$71B<_(nq0bHcmMCG{Ph0cP)BT^#Fa7@?!|1S$^m(Ga?Hs^`bfgpA zh(DBYEHnJ?&#Lq*N&L%s5!CVn*l9)iguTuJ+p`OOa;Wn(wHK~KQl02chb^}AOIU^I zNS|~ZOIvr!9?Iv4$45n5h@wrukj@h0iAMD4OjMx0uI-aX{u0Oz4d|amRInjbX!||{G^xa3f=YR57Y5$k_gwU~- zNTR(A*Gnc+eeIUuH&yg=tsu5iHV0cGiPH7|Rq)e-vJa6-{QbC}bu@LwC@-@4KRB1@VDn}e zKp!22i93`(u=(EnT7Kpz*XTITXm!UCO-cU2Z!nF<{=`Yjp+sBCUtuTOvoV&uHRYa^ zb?l&Akh%vZb+(aTq1*t66Wu9~A_h`!M8D_oD51j>PN5lEh{HrNd-FCJNrVx%?RESpuccg-m`>lv$I8bATteG3TK^0>U$hOK z@f7h3v4OV7$5mTsW$jPf09&qwfm~ztfBL^nT>^DFx)8y%y+SOe97O&5l=l!NittB! zDxRT1#~xxL;kwQ07I)L@`g;;-t)M23BgEgFq2s2(=|jGm_|oRRC|9H0m-9l1(&SUf z{jo852IcjXAKLz65xI_O#5+V^VhhpEhxfe>C+TQq&871YTi$M(oa*G$?M0HQD@{C4 zo=EJs^&i{5PuSe??x-T!#p6{LDo!2|v$Gwzs-Fu?X2w!jC{uBM&;{#K?QG>qpb<01Q;Ej8- zg^!y&w3v6!kivdJ@xyYn$LBO~zaO6A*34?-{V1zhfcy98vY~^sv&Y4coj7*fkWt=g z*<*d&CSwxa5o3CLuZ}t5<2^I>N`U+0#7A!8DKV4kLmS6JE&f7b~+h_F~KJJ4xv)xzM#<)AzwsYg(z3A3j zm*IZ3Zj<-Hdp&&I%nd)djo$yp8~#B7AGg+r?Y%QTydCJ>wI$l$dv|-LkL$Cuj(7Wx z;XdBVyCQtNt#@DZ^=9m; Date: Mon, 11 May 2026 06:35:53 +1000 Subject: [PATCH 04/11] Enhance config types and summary (#4532) * Enhance config types and summary * Update --- archinstall/lib/args.py | 165 ++++++++++++++++++----- archinstall/lib/configuration.py | 76 +++-------- archinstall/lib/models/application.py | 52 ++++++- archinstall/lib/models/authentication.py | 21 ++- archinstall/lib/models/bootloader.py | 17 ++- archinstall/lib/models/config.py | 12 ++ archinstall/lib/models/device.py | 37 ++++- archinstall/lib/models/locale.py | 15 ++- archinstall/lib/models/mirrors.py | 23 +++- archinstall/lib/models/network.py | 8 +- archinstall/lib/models/pacman.py | 12 +- archinstall/lib/models/profile.py | 24 +++- archinstall/lib/output.py | 32 ++++- archinstall/tui/components.py | 7 - archinstall/tui/rich.py | 25 ++++ 15 files changed, 411 insertions(+), 115 deletions(-) create mode 100644 archinstall/lib/models/config.py create mode 100644 archinstall/tui/rich.py diff --git a/archinstall/lib/args.py b/archinstall/lib/args.py index d8aaaa83..efe9baa2 100644 --- a/archinstall/lib/args.py +++ b/archinstall/lib/args.py @@ -6,6 +6,7 @@ import urllib.error import urllib.parse from argparse import ArgumentParser, Namespace from dataclasses import dataclass, field +from enum import StrEnum from pathlib import Path from typing import Any, Self from urllib.request import Request, urlopen @@ -17,6 +18,7 @@ from archinstall.lib.menu.util import get_password from archinstall.lib.models.application import ApplicationConfiguration, ZramConfiguration from archinstall.lib.models.authentication import AuthenticationConfiguration from archinstall.lib.models.bootloader import Bootloader, BootloaderConfiguration +from archinstall.lib.models.config import SubConfig from archinstall.lib.models.device import DiskEncryption, DiskLayoutConfiguration from archinstall.lib.models.locale import LocaleConfiguration from archinstall.lib.models.mirrors import MirrorConfiguration @@ -57,6 +59,81 @@ class Arguments: verbose: bool = False +class ArchConfigType(StrEnum): + VERSION = 'version' + SCRIPT = 'script' + LOCALE_CONFIG = 'locale_config' + ARCHINSTALL_LANGUAGE = 'archinstall_language' + DISK_CONFIG = 'disk_config' + PROFILE_CONFIG = 'profile_config' + MIRROR_CONFIG = 'mirror_config' + NETWORK_CONFIG = 'network_config' + BOOTLOADER_CONFIG = 'bootloader_config' + APP_CONFIG = 'app_config' + AUTH_CONFIG = 'auth_config' + SWAP = 'swap' + USERS = 'users' + ROOT_ENC_PASSWORD = 'root_enc_password' + ENCRYPTION_PASSWORD = 'encryption_password' + HOSTNAME = 'hostname' + KERNELS = 'kernels' + NTP = 'ntp' + TIMEZONE = 'timezone' + SERVICES = 'services' + PACKAGES = 'packages' + PACMAN_CONFIG = 'pacman_config' + CUSTOM_COMMANDS = 'custom_commands' + + def text(self) -> str: + match self: + case ArchConfigType.ARCHINSTALL_LANGUAGE: + return tr('ArchInstall Language') + case ArchConfigType.VERSION: + return tr('Version') + case ArchConfigType.SCRIPT: + return tr('Installation Script') + case ArchConfigType.LOCALE_CONFIG: + return tr('Locales') + case ArchConfigType.DISK_CONFIG: + return tr('Disk configuration') + case ArchConfigType.PROFILE_CONFIG: + return tr('Profile') + case ArchConfigType.MIRROR_CONFIG: + return tr('Mirrors and repositories') + case ArchConfigType.NETWORK_CONFIG: + return tr('Network') + case ArchConfigType.BOOTLOADER_CONFIG: + return tr('Bootloader') + case ArchConfigType.APP_CONFIG: + return tr('Application') + case ArchConfigType.AUTH_CONFIG: + return tr('Authentication') + case ArchConfigType.SWAP: + return tr('Swap') + case ArchConfigType.HOSTNAME: + return tr('Hostname') + case ArchConfigType.KERNELS: + return tr('Kernels') + case ArchConfigType.NTP: + return tr('Automatic time sync (NTP)') + case ArchConfigType.TIMEZONE: + return tr('Timezone') + case ArchConfigType.SERVICES: + return tr('Services') + case ArchConfigType.PACKAGES: + return tr('Additional packages') + case ArchConfigType.PACMAN_CONFIG: + return tr('Pacman') + case ArchConfigType.CUSTOM_COMMANDS: + return tr('Custom commands') + case ArchConfigType.USERS: + return tr('Users') + case ArchConfigType.ROOT_ENC_PASSWORD: + return tr('Root encrypted password') + case ArchConfigType.ENCRYPTION_PASSWORD: + return tr('Disk encryption password') + + @dataclass class ArchConfig: version: str | None = None @@ -80,58 +157,84 @@ class ArchConfig: services: list[str] = field(default_factory=list) custom_commands: list[str] = field(default_factory=list) - def unsafe_config(self) -> dict[str, Any]: - config: dict[str, list[UserSerialization] | str | None] = {} + def unsafe_config(self) -> dict[ArchConfigType, Any]: + config: dict[ArchConfigType, list[UserSerialization] | str | None] = {} if self.auth_config: if self.auth_config.users: - config['users'] = [user.json() for user in self.auth_config.users] + config[ArchConfigType.USERS] = [user.json() for user in self.auth_config.users] if self.auth_config.root_enc_password: - config['root_enc_password'] = self.auth_config.root_enc_password.enc_password + config[ArchConfigType.ROOT_ENC_PASSWORD] = self.auth_config.root_enc_password.enc_password if self.disk_config: disk_encryption = self.disk_config.disk_encryption if disk_encryption and disk_encryption.encryption_password: - config['encryption_password'] = disk_encryption.encryption_password.plaintext + config[ArchConfigType.ENCRYPTION_PASSWORD] = disk_encryption.encryption_password.plaintext return config - def safe_config(self) -> dict[str, Any]: - config: Any = { - 'version': self.version, - 'script': self.script, - 'archinstall-language': self.archinstall_language.json(), - 'hostname': self.hostname, - 'kernels': self.kernels, - 'ntp': self.ntp, - 'packages': self.packages, - 'pacman_config': self.pacman_config.json(), - 'swap': self.swap, - 'timezone': self.timezone, - 'services': self.services, - 'custom_commands': self.custom_commands, - 'bootloader_config': self.bootloader_config.json() if self.bootloader_config else None, - 'app_config': self.app_config.json() if self.app_config else None, - 'auth_config': self.auth_config.json() if self.auth_config else None, + def safe_config(self) -> dict[ArchConfigType, Any]: + base_config: dict[ArchConfigType, Any] = { + ArchConfigType.VERSION: self.version, + ArchConfigType.SCRIPT: self.script, + ArchConfigType.ARCHINSTALL_LANGUAGE: self.archinstall_language.json(), } - if self.locale_config: - config['locale_config'] = self.locale_config.json() + base_config.update(self.plain_cfg()) + sub_config = self.sub_cfg() - if self.disk_config: - config['disk_config'] = self.disk_config.json() + for config_type, value in sub_config.items(): + if not hasattr(value, 'json'): + raise ValueError(f'Config value for {config_type} must implement json() method') + base_config[config_type] = value.json() - if self.profile_config: - config['profile_config'] = self.profile_config.json() + return base_config + + def plain_cfg(self) -> dict[ArchConfigType, str | list[str] | bool]: + return { + ArchConfigType.HOSTNAME: self.hostname, + ArchConfigType.KERNELS: self.kernels, + ArchConfigType.NTP: self.ntp, + ArchConfigType.TIMEZONE: self.timezone, + ArchConfigType.SERVICES: self.services, + ArchConfigType.PACKAGES: self.packages, + ArchConfigType.CUSTOM_COMMANDS: self.custom_commands, + } + + def sub_cfg(self) -> dict[ArchConfigType, SubConfig]: + cfg: dict[ArchConfigType, SubConfig] = { + ArchConfigType.PACMAN_CONFIG: self.pacman_config, + } if self.mirror_config: - config['mirror_config'] = self.mirror_config.json() + cfg[ArchConfigType.MIRROR_CONFIG] = self.mirror_config + + if self.bootloader_config: + cfg[ArchConfigType.BOOTLOADER_CONFIG] = self.bootloader_config + + if self.disk_config: + cfg[ArchConfigType.DISK_CONFIG] = self.disk_config + + if self.swap: + cfg[ArchConfigType.SWAP] = self.swap + + if self.auth_config: + cfg[ArchConfigType.AUTH_CONFIG] = self.auth_config + + if self.locale_config: + cfg[ArchConfigType.LOCALE_CONFIG] = self.locale_config + + if self.profile_config: + cfg[ArchConfigType.PROFILE_CONFIG] = self.profile_config if self.network_config: - config['network_config'] = self.network_config.json() + cfg[ArchConfigType.NETWORK_CONFIG] = self.network_config - return config + if self.app_config: + cfg[ArchConfigType.APP_CONFIG] = self.app_config + + return cfg @classmethod def from_config(cls, args_config: dict[str, Any], args: Arguments) -> Self: diff --git a/archinstall/lib/configuration.py b/archinstall/lib/configuration.py index aba835d9..c40ef161 100644 --- a/archinstall/lib/configuration.py +++ b/archinstall/lib/configuration.py @@ -6,13 +6,12 @@ from typing import Any from pydantic import TypeAdapter -from archinstall.lib.args import ArchConfig +from archinstall.lib.args import ArchConfig, ArchConfigType from archinstall.lib.crypt import encrypt from archinstall.lib.menu.helpers import Confirmation, Selection from archinstall.lib.menu.util import get_password, prompt_dir -from archinstall.lib.models.bootloader import Bootloader from archinstall.lib.models.network import NetworkConfiguration -from archinstall.lib.output import debug, logger, warn +from archinstall.lib.output import as_key_value_pair, debug, logger, warn from archinstall.lib.translationhandler import tr from archinstall.tui.menu_item import MenuItem, MenuItemGroup from archinstall.tui.result import ResultType @@ -45,15 +44,15 @@ class ConfigurationOutput: def user_config_to_json(self) -> str: config = self._config.safe_config() - adapter = TypeAdapter(dict[str, Any]) + adapter = TypeAdapter(dict[ArchConfigType, Any]) python_dict = adapter.dump_python(config) return json.dumps(python_dict, indent=4, sort_keys=True) def user_credentials_to_json(self) -> str: - config = self._config.unsafe_config() + cfg = self._config.unsafe_config() - adapter = TypeAdapter(dict[str, Any]) - python_dict = adapter.dump_python(config) + adapter = TypeAdapter(dict[ArchConfigType, Any]) + python_dict = adapter.dump_python(cfg) return json.dumps(python_dict, indent=4, sort_keys=True) def write_debug(self) -> None: @@ -64,65 +63,24 @@ class ConfigurationOutput: """ Render a concise two-column summary of the current configuration. - The left column holds section labels, the right column holds values. - Column width adapts to the longest translated label so translations - do not break the alignment. Rows whose underlying config is not set - are skipped. - Returns an empty string if nothing meaningful to show. """ - rows: list[tuple[str, str]] = [] + cfg: dict[str, str | list[str] | bool] = {} - disk_config = self._config.disk_config - if disk_config and disk_config.device_modifications: - disk_parts: list[str] = [] - for mod in disk_config.device_modifications: - path = str(mod.device_path) - root_part = mod.get_root_partition() - flags: list[str] = [] - if root_part and root_part.fs_type: - flags.append(root_part.fs_type.value) - if disk_config.disk_encryption: - flags.append(tr('LUKS')) - disk_parts.append(f'{path} ({" + ".join(flags)})' if flags else path) - rows.append((tr('Disks'), ', '.join(disk_parts))) + for key, value in self._config.plain_cfg().items(): + cfg[key.text()] = value - bl_config = self._config.bootloader_config - if bl_config and bl_config.bootloader != Bootloader.NO_BOOTLOADER: - rows.append((tr('Bootloader'), bl_config.bootloader.value)) + for config_type, obj in self._config.sub_cfg().items(): + if not hasattr(obj, 'summary'): + continue - kernels = self._config.kernels - if kernels: - rows.append((tr('Kernel'), ', '.join(kernels))) + summary = obj.summary() + if summary: + cfg[config_type.text()] = summary - profile_config = self._config.profile_config - if profile_config and profile_config.profile: - names = profile_config.profile.current_selection_names() - rows.append((tr('Profile'), ', '.join(names) if names else profile_config.profile.name)) - if profile_config.greeter: - rows.append((tr('Greeter'), profile_config.greeter.value)) + simple_summary = as_key_value_pair(cfg, ignore_empty=True) - packages = self._config.packages - if packages: - rows.append((tr('Packages'), str(len(packages)))) - - net_config = self._config.network_config - if isinstance(net_config, NetworkConfiguration): - rows.append((tr('Network'), net_config.type.display_msg())) - - locale_config = self._config.locale_config - if locale_config: - rows.append((tr('Locale'), locale_config.sys_lang)) - - tz = self._config.timezone - if tz: - rows.append((tr('Timezone'), tz)) - - if not rows: - return '' - - label_width = max(len(label) for label, _ in rows) + 2 - return '\n'.join(f'{label:<{label_width}}{value}' for label, value in rows) + return simple_summary async def confirm_config(self, show_install_warnings: bool = False) -> bool: header = f'{tr("The specified configuration will be applied")}. ' diff --git a/archinstall/lib/models/application.py b/archinstall/lib/models/application.py index 04d1a342..1e97a784 100644 --- a/archinstall/lib/models/application.py +++ b/archinstall/lib/models/application.py @@ -1,7 +1,8 @@ from dataclasses import dataclass from enum import StrEnum, auto -from typing import Any, NotRequired, Self, TypedDict +from typing import Any, NotRequired, Self, TypedDict, override +from archinstall.lib.models.config import SubConfig from archinstall.lib.translationhandler import tr @@ -168,7 +169,7 @@ class FontsConfiguration: @dataclass(frozen=True) -class ZramConfiguration: +class ZramConfiguration(SubConfig): enabled: bool algorithm: ZramAlgorithm = ZramAlgorithm.ZSTD @@ -181,9 +182,28 @@ class ZramConfiguration: algo = arg.get('algorithm', arg.get('algo', ZramAlgorithm.ZSTD.value)) return cls(enabled=enabled, algorithm=ZramAlgorithm(algo)) + @override + def json(self) -> dict[str, bool | str]: + return { + 'enabled': self.enabled, + 'algorithm': self.algorithm.value, + } + + @override + def summary(self) -> list[str] | None: + out: list[str] = [] + + if self.enabled: + out.append(tr('Zram enabled')) + + out.append(tr('Zram algorithm {}').format(self.algorithm)) + return out + + return None + @dataclass -class ApplicationConfiguration: +class ApplicationConfiguration(SubConfig): bluetooth_config: BluetoothConfiguration | None = None audio_config: AudioConfiguration | None = None power_management_config: PowerManagementConfiguration | None = None @@ -223,6 +243,7 @@ class ApplicationConfiguration: return app_config + @override def json(self) -> ApplicationSerialization: config: ApplicationSerialization = {} @@ -245,3 +266,28 @@ class ApplicationConfiguration: config['fonts_config'] = self.fonts_config.json() return config + + @override + def summary(self) -> list[str]: + out: list[str] = [] + + if self.bluetooth_config and self.bluetooth_config.enabled: + out.append(tr('Bluetooth enabled')) + + if self.audio_config: + out.append(tr('Audio server "{}"').format(self.audio_config.audio)) + + if self.power_management_config: + out.append(tr('Power management "{}"').format(self.power_management_config.power_management)) + + if self.print_service_config and self.print_service_config.enabled: + out.append(tr('Print service enabled')) + + if self.firewall_config: + out.append(tr('Firewall "{}"').format(self.firewall_config.firewall)) + + if self.fonts_config and self.fonts_config.fonts: + fonts = ', '.join(f.value for f in self.fonts_config.fonts) + out.append(tr('Extra fonts "{}"').format(fonts)) + + return out diff --git a/archinstall/lib/models/authentication.py b/archinstall/lib/models/authentication.py index 51120479..37261e7c 100644 --- a/archinstall/lib/models/authentication.py +++ b/archinstall/lib/models/authentication.py @@ -1,7 +1,8 @@ from dataclasses import dataclass, field from enum import Enum -from typing import Any, NotRequired, Self, TypedDict +from typing import Any, NotRequired, Self, TypedDict, override +from archinstall.lib.models.config import SubConfig from archinstall.lib.models.users import Password, User from archinstall.lib.translationhandler import tr @@ -58,7 +59,7 @@ class U2FLoginConfiguration: @dataclass -class AuthenticationConfiguration: +class AuthenticationConfiguration(SubConfig): root_enc_password: Password | None = None users: list[User] = field(default_factory=list) u2f_config: U2FLoginConfiguration | None = None @@ -75,6 +76,7 @@ class AuthenticationConfiguration: return auth_config + @override def json(self) -> AuthenticationSerialization: config: AuthenticationSerialization = {} @@ -83,6 +85,21 @@ class AuthenticationConfiguration: return config + @override + def summary(self) -> list[str]: + out: list[str] = [] + + if self.root_enc_password: + out.append(tr('Root password set')) + + if self.users: + out.append(tr('Configured {} user(s)').format(len(self.users))) + + if self.u2f_config: + out.append(tr('U2F set up')) + + return out + def has_superuser(self) -> bool: return any(u.sudo for u in self.users) diff --git a/archinstall/lib/models/bootloader.py b/archinstall/lib/models/bootloader.py index 5d8d0d80..0dbd4268 100644 --- a/archinstall/lib/models/bootloader.py +++ b/archinstall/lib/models/bootloader.py @@ -1,8 +1,9 @@ import sys from dataclasses import dataclass from enum import Enum -from typing import Any, Self +from typing import Any, Self, override +from archinstall.lib.models.config import SubConfig from archinstall.lib.output import warn from archinstall.lib.translationhandler import tr @@ -60,14 +61,26 @@ class Bootloader(Enum): @dataclass -class BootloaderConfiguration: +class BootloaderConfiguration(SubConfig): bootloader: Bootloader uki: bool = False removable: bool = True + @override def json(self) -> dict[str, Any]: return {'bootloader': self.bootloader.json(), 'uki': self.uki, 'removable': self.removable} + @override + def summary(self) -> list[str]: + out = [tr('Bootloader "{}"').format(self.bootloader.value)] + + if self.uki: + out.append(tr('UKI enabled')) + if self.removable: + out.append(tr('Removable')) + + return out + @classmethod def parse_arg(cls, config: dict[str, Any], skip_boot: bool) -> Self: bootloader = Bootloader.from_arg(config.get('bootloader', ''), skip_boot) diff --git a/archinstall/lib/models/config.py b/archinstall/lib/models/config.py new file mode 100644 index 00000000..45835bc0 --- /dev/null +++ b/archinstall/lib/models/config.py @@ -0,0 +1,12 @@ +from abc import ABC, abstractmethod +from typing import Any + + +class SubConfig(ABC): + @abstractmethod + def json(self) -> Any: + pass + + @abstractmethod + def summary(self) -> str | list[str] | None: + pass diff --git a/archinstall/lib/models/device.py b/archinstall/lib/models/device.py index 7fa05407..a21f3c6f 100644 --- a/archinstall/lib/models/device.py +++ b/archinstall/lib/models/device.py @@ -12,6 +12,7 @@ from parted import Disk, Geometry, Partition from pydantic import BaseModel, Field, ValidationInfo, field_serializer, field_validator from archinstall.lib.hardware import SysInfo +from archinstall.lib.models.config import SubConfig from archinstall.lib.models.users import Password from archinstall.lib.output import debug from archinstall.lib.translationhandler import tr @@ -34,6 +35,15 @@ class DiskLayoutType(Enum): case DiskLayoutType.Pre_mount: return tr('Pre-mounted configuration') + def short_msg(self) -> str: + match self: + case DiskLayoutType.Default: + return tr('Default') + case DiskLayoutType.Manual: + return tr('Manual') + case DiskLayoutType.Pre_mount: + return tr('Pre-mount') + class _DiskLayoutConfigurationSerialization(TypedDict): config_type: str @@ -45,7 +55,7 @@ class _DiskLayoutConfigurationSerialization(TypedDict): @dataclass -class DiskLayoutConfiguration: +class DiskLayoutConfiguration(SubConfig): config_type: DiskLayoutType device_modifications: list[DeviceModification] = field(default_factory=list) lvm_config: LvmConfiguration | None = None @@ -55,6 +65,7 @@ class DiskLayoutConfiguration: # used for pre-mounted config mountpoint: Path | None = None + @override def json(self) -> _DiskLayoutConfigurationSerialization: if self.config_type == DiskLayoutType.Pre_mount: return { @@ -78,6 +89,28 @@ class DiskLayoutConfiguration: return config + @override + def summary(self) -> list[str]: + out = [tr('{} layout').format(self.config_type.short_msg())] + + devices = set(mod.device_path for mod in self.device_modifications) + + if devices: + dev_str = ', '.join(str(d) for d in devices) + out.append(tr('Devices {}').format(dev_str)) + + if self.lvm_config is not None: + out.append(tr('LVM set up')) + + if self.disk_encryption is not None: + out.append(tr('{} encryption').format(self.disk_encryption.encryption_type.type_to_text())) + + if self.btrfs_options is not None: + if self.btrfs_options.snapshot_config: + out.append(tr('Btrfs snapshot "{}"').format(self.btrfs_options.snapshot_config.snapshot_type)) + + return out + @classmethod def parse_arg( cls, @@ -1321,7 +1354,7 @@ class _SnapshotConfigSerialization(TypedDict): type: str -class SnapshotType(Enum): +class SnapshotType(StrEnum): Snapper = 'Snapper' Timeshift = 'Timeshift' diff --git a/archinstall/lib/models/locale.py b/archinstall/lib/models/locale.py index 8f580989..26ab3cc0 100644 --- a/archinstall/lib/models/locale.py +++ b/archinstall/lib/models/locale.py @@ -1,12 +1,13 @@ from dataclasses import dataclass -from typing import Any, Self +from typing import Any, Self, override from archinstall.lib.locale.utils import get_kb_layout +from archinstall.lib.models.config import SubConfig from archinstall.lib.translationhandler import tr @dataclass -class LocaleConfiguration: +class LocaleConfiguration(SubConfig): kb_layout: str sys_lang: str sys_enc: str @@ -23,6 +24,7 @@ class LocaleConfiguration: layout = 'us' return cls(layout, 'en_US.UTF-8', 'UTF-8') + @override def json(self) -> dict[str, str]: return { 'kb_layout': self.kb_layout, @@ -31,6 +33,15 @@ class LocaleConfiguration: 'console_font': self.console_font, } + @override + def summary(self) -> list[str]: + return [ + tr('Keyboard layout "{}"').format(self.kb_layout), + tr('Locale language "{}"').format(self.sys_lang), + tr('Locale encoding "{}"').format(self.sys_enc), + tr('Console font "{}"').format(self.console_font), + ] + def preview(self) -> str: output = '{}: {}\n'.format(tr('Keyboard layout'), self.kb_layout) output += '{}: {}\n'.format(tr('Locale language'), self.sys_lang) diff --git a/archinstall/lib/models/mirrors.py b/archinstall/lib/models/mirrors.py index 0a596c13..3ded2a9a 100644 --- a/archinstall/lib/models/mirrors.py +++ b/archinstall/lib/models/mirrors.py @@ -9,9 +9,11 @@ from typing import TYPE_CHECKING, Any, Self, TypedDict, override from pydantic import BaseModel, ValidationInfo, field_validator, model_validator +from archinstall.lib.models.config import SubConfig from archinstall.lib.models.packages import Repository from archinstall.lib.networking import DownloadTimer, ping from archinstall.lib.output import debug +from archinstall.lib.translationhandler import tr if TYPE_CHECKING: from archinstall.lib.mirror.mirror_handler import MirrorListHandler @@ -236,7 +238,7 @@ class _MirrorConfigurationSerialization(TypedDict): @dataclass -class MirrorConfiguration: +class MirrorConfiguration(SubConfig): mirror_regions: list[MirrorRegion] = field(default_factory=list) custom_servers: list[CustomServer] = field(default_factory=list) optional_repositories: list[Repository] = field(default_factory=list) @@ -250,6 +252,7 @@ class MirrorConfiguration: def custom_server_urls(self) -> str: return '\n'.join(s.url for s in self.custom_servers) + @override def json(self) -> _MirrorConfigurationSerialization: regions = {} for m in self.mirror_regions: @@ -262,6 +265,24 @@ class MirrorConfiguration: 'custom_repositories': [c.json() for c in self.custom_repositories], } + @override + def summary(self) -> list[str]: + out: list[str] = [] + + if self.mirror_regions: + out.append(tr('Mirror regions "{}"').format(', '.join(m.name for m in self.mirror_regions))) + + if self.optional_repositories: + out.append(tr('Optional repositories "{}"').format(', '.join(r.value for r in self.optional_repositories))) + + if self.custom_servers: + out.append(tr('Custom servers set up')) + + if self.custom_repositories: + out.append(tr('Custom repositories set up')) + + return out + def custom_servers_config(self) -> str: config = '' diff --git a/archinstall/lib/models/network.py b/archinstall/lib/models/network.py index 71f3dca2..9e61cb56 100644 --- a/archinstall/lib/models/network.py +++ b/archinstall/lib/models/network.py @@ -3,6 +3,7 @@ from dataclasses import dataclass, field from enum import Enum from typing import NotRequired, Self, TypedDict, override +from archinstall.lib.models.config import SubConfig from archinstall.lib.output import debug from archinstall.lib.translationhandler import tr @@ -103,10 +104,11 @@ class _NetworkConfigurationSerialization(TypedDict): @dataclass -class NetworkConfiguration: +class NetworkConfiguration(SubConfig): type: NicType nics: list[Nic] = field(default_factory=list) + @override def json(self) -> _NetworkConfigurationSerialization: config: _NetworkConfigurationSerialization = {'type': self.type.value} if self.nics: @@ -114,6 +116,10 @@ class NetworkConfiguration: return config + @override + def summary(self) -> str: + return self.type.display_msg() + @classmethod def parse_arg(cls, config: _NetworkConfigurationSerialization) -> Self | None: nic_type = config.get('type', None) diff --git a/archinstall/lib/models/pacman.py b/archinstall/lib/models/pacman.py index 5d271ea9..004dfbc3 100644 --- a/archinstall/lib/models/pacman.py +++ b/archinstall/lib/models/pacman.py @@ -1,6 +1,7 @@ from dataclasses import dataclass -from typing import Self, TypedDict +from typing import Self, TypedDict, override +from archinstall.lib.models.config import SubConfig from archinstall.lib.translationhandler import tr @@ -10,7 +11,7 @@ class PacmanConfigSerialization(TypedDict): @dataclass -class PacmanConfiguration: +class PacmanConfiguration(SubConfig): parallel_downloads: int = 5 color: bool = True @@ -18,12 +19,19 @@ class PacmanConfiguration: def default(cls) -> Self: return cls() + @override def json(self) -> PacmanConfigSerialization: return { 'parallel_downloads': self.parallel_downloads, 'color': self.color, } + @override + def summary(self) -> str | None: + if self.color: + return tr('Color enabled') + return None + def preview(self) -> str: color_str = str(self.color) output = '{}: {}\n'.format(tr('Parallel Downloads'), self.parallel_downloads) diff --git a/archinstall/lib/models/profile.py b/archinstall/lib/models/profile.py index e7ae8c8c..fa890a1e 100644 --- a/archinstall/lib/models/profile.py +++ b/archinstall/lib/models/profile.py @@ -1,8 +1,10 @@ from dataclasses import dataclass -from typing import TYPE_CHECKING, Self, TypedDict +from typing import TYPE_CHECKING, Self, TypedDict, override from archinstall.default_profiles.profile import GreeterType, Profile from archinstall.lib.hardware import GfxDriver +from archinstall.lib.models.config import SubConfig +from archinstall.lib.translationhandler import tr if TYPE_CHECKING: from archinstall.lib.profile.profiles_handler import ProfileSerialization @@ -15,11 +17,12 @@ class _ProfileConfigurationSerialization(TypedDict): @dataclass -class ProfileConfiguration: +class ProfileConfiguration(SubConfig): profile: Profile | None = None gfx_driver: GfxDriver | None = None greeter: GreeterType | None = None + @override def json(self) -> _ProfileConfigurationSerialization: from archinstall.lib.profile.profiles_handler import profile_handler @@ -29,6 +32,23 @@ class ProfileConfiguration: 'greeter': self.greeter.value if self.greeter else None, } + @override + def summary(self) -> list[str] | None: + out: list[str] = [] + + if self.profile: + out.append(self.profile.name) + + if self.gfx_driver: + out.append(tr('{} grphics driver').format(self.gfx_driver.value)) + + if self.greeter: + out.append(tr('{} greeter').format(self.greeter.value)) + + return out + + return None + @classmethod def parse_arg(cls, arg: _ProfileConfigurationSerialization) -> Self: from archinstall.lib.profile.profiles_handler import profile_handler diff --git a/archinstall/lib/output.py b/archinstall/lib/output.py index 3a972dfb..86a47ed1 100644 --- a/archinstall/lib/output.py +++ b/archinstall/lib/output.py @@ -11,6 +11,7 @@ from pathlib import Path from typing import TYPE_CHECKING, Any from archinstall.lib.utils.encoding import unicode_ljust, unicode_rjust +from archinstall.tui.rich import BaseRichTable if TYPE_CHECKING: from _typeshed import DataclassInstance @@ -20,7 +21,7 @@ class FormattedOutput: @staticmethod def _get_values( o: DataclassInstance, - class_formatter: str | Callable | None = None, # type: ignore[type-arg] + class_formatter: str | Callable | None = None, # type: ignore[type-arg] # pyright: ignore[reportMissingTypeArgument] filter_list: list[str] = [], ) -> dict[str, Any]: """ @@ -129,6 +130,35 @@ class FormattedOutput: return output +def as_key_value_pair( + entries: dict[str, str | list[str] | bool], + ignore_empty: bool = True, +) -> str: + """ + Formats key-values as a Rich Table: + key1 : value1 + key2 : value2 + ... + """ + table = BaseRichTable() + table.add_column('key', style='bold', no_wrap=True) + table.add_column('value', style='white', max_width=70) + + for label, value in entries.items(): + if ignore_empty and not value: + continue + + if isinstance(value, bool): + value = 'Yes' if value else 'No' + + if isinstance(value, list): + value = '\n '.join(str(val) for val in value) + + table.add_row(label.title(), f': {value}') + + return table.stringify() + + class Journald: @staticmethod def log(message: str, level: int = logging.DEBUG) -> None: diff --git a/archinstall/tui/components.py b/archinstall/tui/components.py index f732c21f..9fecf3c6 100644 --- a/archinstall/tui/components.py +++ b/archinstall/tui/components.py @@ -350,11 +350,6 @@ class OptionListScreen(BaseScreen[ValueT]): ] ) - # debug(f'Index: {index}') - # debug(f'Region: {option_list.region}') - # debug(f'Scroll offset: {option_list.scroll_offset}') - # debug(f'Target_Y: {target_y}') - self.app.cursor_position = Offset(option_list.region.x, target_y) self.app.refresh() @@ -1163,8 +1158,6 @@ class TableSelectionScreen(BaseScreen[ValueT]): ] ) - debug(f'Setting cursor to target_y: {target_y}') - self.app.cursor_position = Offset(data_table.region.x, target_y) self.app.refresh() diff --git a/archinstall/tui/rich.py b/archinstall/tui/rich.py new file mode 100644 index 00000000..055ec22c --- /dev/null +++ b/archinstall/tui/rich.py @@ -0,0 +1,25 @@ +from io import StringIO + +from rich import box +from rich.console import Console +from rich.table import Table as RichTable + + +class BaseRichTable(RichTable): + def __init__(self) -> None: + super().__init__( + box=box.SIMPLE, + show_header=False, + pad_edge=False, + show_edge=False, + ) + + def stringify(self) -> str: + string_io = StringIO() + buf = Console(file=string_io, highlight=False) + buf.print(self) + + _ = string_io.seek(0) + output = string_io.read() + + return output From f7a6f70fc858280888fce47c01839e0a407b2c20 Mon Sep 17 00:00:00 2001 From: stinga11 Date: Tue, 12 May 2026 18:21:15 -0400 Subject: [PATCH 05/11] Replace terminal and file manager in Budgie profile (#4533) I think it was a mistake to have made the previous changes to KDE Apps. In retrospect, it seemed like a good idea since the Budgie developer had done it that way in Fedora, which is the distro the developer uses as a reference for Budgie. When you start using it, you realize there's no bridge between the desktop and the KDE Apps, and things like Dolphin recognizes icons and themes, requiring some rather annoying manual configurations. Then, if you want to change them again, you have to change those configurations again. Files don't open by default with the apps either; you have to configure them for that to work. At first, I thought the Budgie packager for Arch had forgotten some stray dependency, but with some free time, I tested it with Fedora 44, and to my surprise, it has exactly the same problems, which is completely unacceptable for a final stable release. I suppose he'll make the necessary changes in the near future, but right now, it's a disaster. --- archinstall/default_profiles/desktops/budgie.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/archinstall/default_profiles/desktops/budgie.py b/archinstall/default_profiles/desktops/budgie.py index f156a53b..da147851 100644 --- a/archinstall/default_profiles/desktops/budgie.py +++ b/archinstall/default_profiles/desktops/budgie.py @@ -18,12 +18,13 @@ class BudgieProfile(Profile): return [ 'materia-gtk-theme', 'budgie', - 'konsole', - 'dolphin', + 'mate-terminal', + 'nemo', + 'nemo-fileroller', 'papirus-icon-theme', ] @property @override def default_greeter_type(self) -> GreeterType: - return GreeterType.Sddm + return GreeterType.LightdmSlick From 3dec5025c303d73c2258872bbba3fd4cbfb5b2d6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 13 May 2026 08:21:44 +1000 Subject: [PATCH 06/11] Update dependency arch/python-pydantic to v2.13.4 (#4534) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 9fee23fa..3bbc7acb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,7 +19,7 @@ classifiers = [ ] dependencies = [ "pyparted==3.13.0", - "pydantic==2.12.5", + "pydantic==2.13.4", "cryptography==48.0.0", "textual==8.2.5", "markdown-it-py==4.0.0", From b95321d38ca7db8f3e0432279bfbd76ba143bb89 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 13 May 2026 08:33:42 +1000 Subject: [PATCH 07/11] Update dependency mypy to v2.1.0 (#4535) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 3bbc7acb..13e0933f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,7 +34,7 @@ Source = "https://github.com/archlinux/archinstall" [project.optional-dependencies] log = ["systemd_python==235"] dev = [ - "mypy==2.0.0", + "mypy==2.1.0", "flake8==7.3.0", "pre-commit==4.6.0", "ruff==0.15.12", From 13944f3ccad8ad6ec7de26791a65eab9aed872d1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 13 May 2026 08:54:05 +1000 Subject: [PATCH 08/11] Update pre-commit hook pre-commit/mirrors-mypy to v2.1.0 (#4538) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6cf16130..c573ae04 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -31,7 +31,7 @@ repos: args: [--config=.flake8] fail_fast: true - repo: https://github.com/pre-commit/mirrors-mypy - rev: v2.0.0 + rev: v2.1.0 hooks: - id: mypy args: [ From b81fe955f0c789e371b96ed03c79642d4c607f82 Mon Sep 17 00:00:00 2001 From: HADEON <52324046+h8d13@users.noreply.github.com> Date: Fri, 15 May 2026 03:57:31 +0000 Subject: [PATCH 09/11] Add IWD standalone option to network configuration + fix NM_IWD (#4528) * Add iwd standalone option to network configuration Adds NicType.IWD as a third option alongside NM and NM_IWD: install iwd, write /etc/iwd/main.conf with EnableNetworkConfiguration=true and NameResolvingService=systemd, enable iwd.service + systemd-resolved.service. iwd handles DHCP itself and resolved picks up its DNS via the symlink, so no NetworkManager pulled in. Also fills in parse_arg cases for NM_IWD and IWD so config files round-trip both nic types. Assisted-By: Flint * wire up resolv stub and networkd service * exclude virtual devices, dont harcode iface name instead match 'ether' similar pattern to .network files shipped in /etc/systemd/network * use dedent and rename menu option --- archinstall/lib/models/network.py | 7 ++++ archinstall/lib/network/network_handler.py | 42 ++++++++++++++++++++++ archinstall/lib/network/network_menu.py | 2 ++ 3 files changed, 51 insertions(+) diff --git a/archinstall/lib/models/network.py b/archinstall/lib/models/network.py index 9e61cb56..57a579c3 100644 --- a/archinstall/lib/models/network.py +++ b/archinstall/lib/models/network.py @@ -12,6 +12,7 @@ class NicType(Enum): ISO = 'iso' NM = 'nm' NM_IWD = 'nm_iwd' + IWD = 'iwd' MANUAL = 'manual' def display_msg(self) -> str: @@ -22,6 +23,8 @@ class NicType(Enum): return tr('Use Network Manager (default backend)') case NicType.NM_IWD: return tr('Use Network Manager (iwd backend)') + case NicType.IWD: + return tr('Use standalone iwd') case NicType.MANUAL: return tr('Manual configuration') @@ -131,6 +134,10 @@ class NetworkConfiguration(SubConfig): return cls(NicType.ISO) case NicType.NM: return cls(NicType.NM) + case NicType.NM_IWD: + return cls(NicType.NM_IWD) + case NicType.IWD: + return cls(NicType.IWD) case NicType.MANUAL: nics_arg = config.get('nics', []) if nics_arg: diff --git a/archinstall/lib/network/network_handler.py b/archinstall/lib/network/network_handler.py index 13548584..09d2750c 100644 --- a/archinstall/lib/network/network_handler.py +++ b/archinstall/lib/network/network_handler.py @@ -1,3 +1,5 @@ +import textwrap + from archinstall.lib.installer import Installer from archinstall.lib.models.network import NetworkConfiguration, NicType from archinstall.lib.models.profile import ProfileConfiguration @@ -32,6 +34,13 @@ def install_network_config( _configure_nm_iwd(installation) installation.disable_service('iwd.service') + case NicType.IWD: + installation.add_additional_packages(['iwd']) + _configure_iwd_standalone(installation) + installation.enable_service('iwd.service') + installation.enable_service('systemd-networkd.service') + installation.enable_service('systemd-resolved.service') + case NicType.MANUAL: for nic in network_config.nics: installation.configure_nic(nic) @@ -45,3 +54,36 @@ def _configure_nm_iwd(installation: Installer) -> None: iwd_backend_conf = nm_conf_dir / 'wifi_backend.conf' _ = iwd_backend_conf.write_text('[device]\nwifi.backend=iwd\n') + + +def _configure_iwd_standalone(installation: Installer) -> None: + # iwd manages wireless only; systemd-networkd handles wired DHCP. + iwd_conf_dir = installation.target / 'etc/iwd' + iwd_conf_dir.mkdir(parents=True, exist_ok=True) + + main_conf = iwd_conf_dir / 'main.conf' + main_conf_content = textwrap.dedent("""\ + [General] + EnableNetworkConfiguration=true + + [Network] + NameResolvingService=systemd + """) + _ = main_conf.write_text(main_conf_content) + + networkd_dir = installation.target / 'etc/systemd/network' + networkd_dir.mkdir(parents=True, exist_ok=True) + wired_conf = networkd_dir / '20-wired.network' + wired_conf_content = textwrap.dedent("""\ + [Match] + Type=ether + Kind=!* + + [Network] + DHCP=yes + """) + _ = wired_conf.write_text(wired_conf_content) + + resolv = installation.target / 'etc/resolv.conf' + resolv.unlink(missing_ok=True) + resolv.symlink_to('/run/systemd/resolve/stub-resolv.conf') diff --git a/archinstall/lib/network/network_menu.py b/archinstall/lib/network/network_menu.py index 120af19e..88c26dba 100644 --- a/archinstall/lib/network/network_menu.py +++ b/archinstall/lib/network/network_menu.py @@ -202,6 +202,8 @@ async def select_network(preset: NetworkConfiguration | None) -> NetworkConfigur return NetworkConfiguration(NicType.NM) case NicType.NM_IWD: return NetworkConfiguration(NicType.NM_IWD) + case NicType.IWD: + return NetworkConfiguration(NicType.IWD) case NicType.MANUAL: preset_nics = preset.nics if preset else [] nics = await ManualNetworkConfig(tr('Configure interfaces'), preset_nics).show() From 74a1066661f928690c39437598292719f192c16c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 15 May 2026 13:58:00 +1000 Subject: [PATCH 10/11] Update dependency ruff to v0.15.13 (#4540) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 13e0933f..636c8017 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,7 +37,7 @@ dev = [ "mypy==2.1.0", "flake8==7.3.0", "pre-commit==4.6.0", - "ruff==0.15.12", + "ruff==0.15.13", "pylint==4.0.5", "pytest==9.0.3", ] From e48ca45b0bc8be6a093bf624b951455c031d3de0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 15 May 2026 16:30:33 +1000 Subject: [PATCH 11/11] Update pre-commit hook astral-sh/ruff-pre-commit to v0.15.13 (#4541) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c573ae04..91fd6f33 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,7 +1,7 @@ default_stages: ['pre-commit'] repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.15.12 + rev: v0.15.13 hooks: # fix unused imports and sort them - id: ruff