From 62b1e919500c7de91ce72a19b97d5436ce6aea99 Mon Sep 17 00:00:00 2001 From: Ulysse DURAND Date: Wed, 8 Apr 2026 17:17:32 +0200 Subject: [PATCH 01/13] docs: add image and pre-commit checks --- .commitlintrc.js | 3 +++ .pre-commit-config.yaml | 4 ++-- README.rst | 2 ++ pyproject.toml | 2 +- trame-vtk.jpg | Bin 0 -> 136368 bytes 5 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 .commitlintrc.js create mode 100644 trame-vtk.jpg diff --git a/.commitlintrc.js b/.commitlintrc.js new file mode 100644 index 0000000..69b4242 --- /dev/null +++ b/.commitlintrc.js @@ -0,0 +1,3 @@ +module.exports = { + extends: ["@commitlint/config-conventional"], +}; diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2e9a6de..743daf1 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -36,14 +36,14 @@ repos: args: [--prose-wrap=always] - repo: https://github.com/astral-sh/ruff-pre-commit - rev: "v0.15.0" + rev: "v0.15.9" hooks: - id: ruff args: ["--fix", "--show-fixes"] - id: ruff-format - repo: https://github.com/codespell-project/codespell - rev: "v2.4.1" + rev: "v2.4.2" hooks: - id: codespell diff --git a/README.rst b/README.rst index 9ed0f14..6c62b6a 100644 --- a/README.rst +++ b/README.rst @@ -13,6 +13,8 @@ VTK integration in trame allows you to create rich visualization and data proces Several components are available so you can leverage VTK either for its data processing and/or rendering. trame lets you choose if you want to leverage Remote Rendering or if the client should do the rendering by leveraging vtk.js under the hood. +.. image:: https://raw.githubusercontent.com/Kitware/trame-vtk/master/trame-vtk.jpg + :alt: Example of trame-vtk usage Installing ----------------------------------------------------------- diff --git a/pyproject.toml b/pyproject.toml index 646bd5e..0c276ff 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -53,7 +53,7 @@ upload_to_vcs_release = true [tool.ruff] line-length = 88 indent-width = 4 -target-version = "py39" +target-version = "py310" [tool.ruff.lint] select = ["E", "W", "F"] diff --git a/trame-vtk.jpg b/trame-vtk.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5e18216daa1e8af16ca57a73eac011df0fa5cbc1 GIT binary patch literal 136368 zcmeFZ1z1$;*C@Vem6Gm|l+K|;q+>w3K^g`aU?`;w6r>L*HI&i}Fh~q3pi&|w-6hf? zDkX^A0n`)U`Qmq<@BaVabMM*1%wGF_SG}wD+Iu#0GIlZtT-H!gR{=0E0N^+D3pkkv zGL>(+I066|3~&PgZ~?%QQC%Iq*SCW?I6%FfJ$z2) zFJ5u>@$r-r5P*8~+t_>9I`G?hxC`8}@e~l^7ZdKT zet!{u515mHkffxffS|B|urMDQgU|am)W_x)AJm)mCkG`5Z#$Tar;m#Vl=+mSjje~T zk1Pv|09t~;4-u!}FJ0xB|JnYrz&{rF#{&OY;2#V8V}bwoEbx1`;{ZjsIR5Bf1~}OS zByONvB@cAJ@^HXrZpC zXnjLZM@3yr`K&7>)UxsPbi=$10Pav9n4ao&W)o90X1qn60 zJb&)b`2YIY8#!zKfI+@fUcZL_YXGS|x-CL?j}~ZjTYGOicQpJG{oc0og!upf)^qeY ztG|!uDLjOR$zf;((eTPC>~s!)JB4k}U~KeC&^QKqiU5GkhVE|(Y;0go06-v!9%uHm zb3*eWxPgWRq4q9NG<+8g%h@^G*rVZ>XqeaC-QyJAK*Lwj_?`ejNREajZ2!R1=?}1t zjqNY~Ha1Sb;PZ8%DbY$Oxp;fJ+1x%m`0xC1ck@Nt?rh^ge-b#u)b!AMYP9{vTs<^@ z!BAUmouA__=+*s%oqg2|f5LX&il^=T8LhpIlIBks>ZX0_`?GOJ7nRd~{S0>TQ8)Mr zJ9sPW|Ab*4dcR~j!W0#Lj@!V{&<|Q)SHoZ9&JOCo_y;%}82`lab1~BX346Qh|I#PG zS@G96%vbN1{ti&p>p$@wVJg4Y?(U5q{UO)cMg148kF$Z=&v84O-}QHZD*VpV+vJyS z_6|zQKk*%)hQHS9>2v*;EKj$yJUO$EgPZEFac@8UU$j2x;QYzQ)91!78$xU}PUG^7 z7SIAz0cOAua07e*7+?da04@L&aPV=sg^phUQ1tM;4RdjF_F+~)XPg7GI@FGzmswa) zSO@@4^Y;`70KQP3_Ru0pQIG zJ71XJ8N0Jp^Tx0p@(6LaTCJ{1B&5`5rh$n5rvU}0mpcTQG`*BQHSvg zqZ6YaV;o~1V-@2w#vvvaCIKcnCIco1rU0e{rUIrWrU9lUrW2+YW&q{`%vj76%xugO z%xcV6m|d8|m~)uxn7dd27Csgw))g#1ED0<{EFCN}EJrLDRtQ!kRuWb=780u-s{?Bg zYYuAz>nk=cHW@ZEHXpV$wi>n}wjH(?b_jMfHXOSUyBfO{dk}jbdmH;Z4j~Rb4iAnL zjyjGBjuVbQP8d!SPCgC_rwwNqXAx%)7Z;ZjmlIbUR}I$`7lIpz8;zTRTZa1*w;y)_ zcNY&2j|PtiPZm!H&j!y2FAOgguLQ3dZvbx*@8AOd1*Qwa7gR2oU4UM=eDv&B$qfZ$zC$J1i5tYQpzRdrM62` zm%iZRqU3^r6 zT;hgAw8R@p9LejFcO+j(ew7lF@{y{L`Y6pO?JA9sUXkIHagfQCS&(IswUK=$J1561 zcT?`E+?@Osc^mm``S;gYui0PAzqYKvr2tVVQP{dJcpY{fb$wq^N-^LUTsvJLETQhNPSyFTq9VcRg*wdUlXqR zUW;1`rd1Ed1Z#jFgQv9FwV~QII)IM4&SRbF8=N=1ZZzoP>fX>z(_PXN(hJh-&?nQk z)<@{?8C*ArGnh2IYUpeD+KAZ5!l=k--&n~w!FbL@z$DnD%aqpC#kAH8&&t1&|BTNxo=0@UJg(R$P2^{vhD(QMJ;HwE z@~AgLBqBB9d!&8j+bF@Pq^NJvcF}KRgkn-+PGTKnd*j67GJnJU4f@+iynK9N0!czZ z!op+lb}Bw8nSCW$6xC0|PRO`c29N~uj{OZ_eN8{8Q_oOV5}ES)|*B7Hx@ zK4T#BS|&1!AuB5D@Ttqwv1h8!saLJ=xBZ;`{qTbRA=2=iMKUfVqMkUpl(zT zs0Y<6)?3{t-dFoh@?CwuOn=jW{J^V0rNQ~aAxA9LC zeiKKNcc*ZsBBw7;C(Y2$WY2QVmd%OHHO?!|cfZ$vKe=GHu>QgO!?(o;ON2{F%S_8f zE5a);R#jHtt(mVau6wQ@ZG>%-Y^HBr-KzR{?PK@0$@bzW*r$`v(O+o36zquZyxzUB zJG1A$ceEdQKyy&|RpM*Mq4DAJk^eWmZz;!I$MxSezfYaGpPYEwz--QXfzuntn2zY% z$e#<){jn(kkfD2sOXlbO^%=(5?c^U2x*a`(&i8+S&wKE*IWYi0qJh)aNbw~AJV(Dd z?g9YuH2^qmiwv#-m?9#--sq9j&D&8#_zb`xfB^u`!O6)N1^~dT2Y_SP$;na1$;ojp z`dVQe0A6~X_w}dPjOc3&bM&=M#iOC8ZfE3w{5bFV(IY?C_}4vpOYUjMf?(ecvAg6AK#$mxPq;iVz+- z1&gqPuAaV)*S+|JXBVhgMXnp#!JZ_RSG?*UprmF4DH<4?*!tdooRnQTcu`bL+{pVi zyOO<6&iwn(yloEU2Q8me9Q+>Us-Z>EqjkW*`J*BL?x`p|j8jF_NYJxb7}&TMuyD}U z!@@zw8YUJAHV)|(AzU&AT^lc!d-2c8U-fU}kqe{M(4W_{g(YMUe4;S8FX~-M$yULx zsATv0WC9?-La&$viv*Adj?ovEL_`$V4kfw|jG3fvI&?eQjL^GYCioiNP1{P_iX~?! zg8O{gG9YN$!LR4bMk8l{}b_Y~#k$d%r5pyw1ta)g7XEhP#i*F+pe1YIvLoBW(OlPlFKfu{X(PWuDpTqCJd zjedwbV@7C8Xp500lp1aldZywp`7I?sc=$f@LW@~Kiy=D!(7ODE-%m*qC&16umgAl+ z@(=p`6#k1P=!bCn^~(g~zZ;6^l=N)zr%OAPdHIxdubN=rZOmqb)A;5HN6%BozABMT zYEZ;5ZR^^-EZIphf+H0|Tek`C5^&nJo-Eg!eSSS*47R?0r-Qg|M~ZU&p(bf!F}A+f z`Z71uaD#Jj%f;MjTgR*ZUDlN@z2#D9L4G}f6$)Zm8|$V!Pl*^ zv&B|Ak8m2CAGryxlOg^?bl-?dmv;05ocjD;p;t^G)w&jQZVPkV!0J=ejd_=7BVUR* zHQem0vOycQ;LMhC?|zt01#KWKvEb5B*+~NQ%!cHt?P)5fpF2&Ug*y(O*)q%7sll;@ z2#xv~t*hhoU8g?ObEgKIQ1oiiVZDZ4t(^!_IT6~~LFZxnBP)JH_OHlVKlSoi82pO) zpET&`{BxS%mdhX9b^5zp3O5P=k#0W%@K=`oVTQ=}&yn|sR5=$(X!|23|IG};X{w-= z`M2B{Y_a2k9yt9{7!ChbCga9$gGm;5mjcFa_K#?f zEZ5~%Omj7eZ*k#>BH@r!i_I--OeUN)cNOv;6YbIgqPI;f>9Aae_!*YpZtn5EYMe`7 zRFh_Xp-f+dXYc?V2PnV&(B;1%=-;A{uAZ7J-}=XL6?VmmXFnf2 z5>maLx@G%Eixy0!c-0dP8#kB_3_8BX>G7uDldMx4?lcPo*E>CV(Rbe?k$EHb6Zub{ z6c>fwmOQuGxs1Pa$-SXhFaBM>-AF!jDD%s;n={(yY-7(Hsz*SSPxxW^k8b-T(u4X_ ze{$jC>EnL({bMvCzH zW1#+rR{0st|2h(`Rm%U~^1259Lvs>lKKe-V!=89Ulh1>Gn9FSkopq9W1dsa}lB@KH zn|}CXawWEF0-bGQ0jw2!kqWzFvEN^vhXH!zNB(*%sLAC|htB;Yc1=G4u=zB|aO*r$m^trR~?%X`j=Ch@orL(;A zpGb!7Qq9bX4kLYJ4{q;o9dR7vC zl=$BRXolrKDJbV9;csfi&nox#1;va1?2Pk&rdIsBrRjgO%>L^IMf2>m`=6NZZwq#E z{_pwluM{xhosQE|^4I!Yz=f`xWsh<%qjR$h(~_$}_#o2ll{vxpL}|;Uy+pe$8U})) z0noVphi(3rP813Kg(5H4FT&aJ@48a!=qh;;PKu8g$q#{sXy{Zha)E3gqg3Scb#6pZ z%wf2j7nUXeHJ8>+4$!or|La^M?yzM!##X`cX-?jH-qa#LZNKTlj2BfAwEVt&(p3S? zG+JK;%&hAm{AOw15)sj!%k9!sJ^`tNYkX^5`5ev&?$&l&FCmGPt#mJ6W1Nu<1$CeL zE?s47oN$BEKps19JyTh2wMMxp7mvnQCWps-N__74q>Pp|HU?f6+{W*%Co=Bef+qf?z)0WuaHRtcs)7D-LrRb{fU zrKjTY-^IUEbv^UVhxi_Q&&C1%B~;!(ET@8|D%r76sgl0G{}V+IEvd-k$WK}|W<3rD z)djj>R=XjPIb*S$9YXX=Ph3~ZUbgpF9_zd_1g)hB8+7W!@&_zSU1{5eV$=q0K~1^&^{WULe=j-u@{W(M z9_9{O)xhevj8ihL1^DTOh!A=6VxJ(D#v?N;e7oMN1m5gg#P53obCXQQNyRh9*!&U@ zoRXI(!XFknWyaXOtoY0eM=i)aotCANqdp|4S=FKJKGr-k-P3&baMPPfhqkq0Y{^Y> zxMM8!ebN_(?r&H9W-cSjOs;>4T=m?i2n#ckGlLYF^H*eX$SH$y#`fBmH>?erZiHJ= za<4dK`&uz1JWH&vv$+pfQF`*O*<@*H897=^N7)O{D14I>gLLyOFGnnu+QB4zgydDV zFO0G)gE@S~FT4sj?Q0* zKgC!;-;@G?;)NHw#t+<$*7F$B;)bN2mBT0mcB3*Aq*F1WreZGkn{eKcp&2tGVQmj_ z&+rt*dFdCU8?rYW`apHNAl^YMjlc~0Kx261W?c^?dP4jf5>*ui#0%l8}?Lv`4dm=C9>(iMu-Cm9*WYcUJcy@X{&5QVC*uk2} zfG?UERbo-?_A!~x-6C;^oZ_+Rdf{?ny(Y8{Rm3OnGQnMx6?BAnnp>*DR#KxVmTjcN z*d((nEb=VC?_F<9rxfv(fGbMZh+yb&*BmJfn4|yD2#HQEy&-`oDPWevzHUH-(Tkqw z3>e0`>z%NR5Vk^H`)@%io}&>kYXZ*XG+`v{7SEjt_-FVZo1o+3|C@mL?~CUDlvAix zwHZ7>>g!5rl%Z!#^FYp)XIi%)X4fuA`UC^>P0U|@|Wgk0D=IV8T!Jk15dkli2}BFw16Lbg-6 zoUQTtTYnxj%wk7<&B@K>QEfbQfdwj9>6IuBShmxM(#B;=494y-=5yb}IfWNGV| z-=wuFq^ymyRzTn3nXwmlO8`v z2U)+`oq50B`bA^n$o|orEw9dZ73$u-vgAvFM&1Drmx(91O2o9}9dmMGX=&9=$y}Z# z_PLpIeDJPD`0F?_hfOQ16eyQMVMREWQ6(c2Z(W01C?;Hx6%IM-hBrnUpj%796?)}} z$4+a8L}i(m)-7M}svF+tH~cg-Jlw-cR#Q^as;kwVZI|^FTBy| zI*aYC3DVLXET`yAvWRC@nn47!+mD0vR928%E?UTzebZXudK)J>sc7vZ>6N-K-j0bj zMh>}+ynBv%4zIs)v1_xvufczO#oH>OF(rn!>xJ1$l0?z?_l>=m6Dd1;?ss%#`X32z zg&TFzu>~&M+1NTRH`@vkKY|9?AcJLnNR^@zn($cTi-)Almcwpol^|O@-`%iy`Z^{* zNO*ACONZL8XtPkYLqJ-&t2d|9$D&R=XKAxT^VJD(ff6oVl_XsX22B)IR-2g!mlzZ%tScY1*Tf5u#tk;y-h!vyOf6NkGB78-?m5OUH`xp%c%2zsF(Rj27q1tmE0- z%vaCO+#67O?-GkvNQS_&WFNU=g46!VtYeMsu@6LRxKowM(A0n8d`Ro@_&)K0?)*vKM{KwMT_-QmrjP z>I!T&nf#*#qH=4dH=i3=LN@iMs^LKqM2%*J9mD*Ru0>gwd6bHAt`g zfeX@rJUK0RU}(&h#*nvDmS^WF!VPJB$OI-4>C}A_l?UJH9G}xj;pWOP)FoqwltZ}K z-vvqTOl&1QZKZLD+!%-O6xky04G$gCPWXKc1&cs~huFB*KvSb2QUfVF0-JBwCz~$A z>sun6eKMriy=X1JBz=9hdhy1P6@(|i)bFvf7(=7VuxX|CLo$~Stv4gwMn-kbT_CPd zaauE13-z?Mbw?Fpw#_=fD^!$1uSMEqw(T|~+1a4>P&iKsWNhj<27(M6<%<{;E2}~! zCZ*-^H7UFIY<9-FyB2-6IAS$h^tesF-eFSyLLw`aR-KQ`VBS7s*mo4taD>pCI+)mr zDN#j5^$twb%VT^{;!cJzP`oaH7l$@oDkrQYv`Diw4|>d=#A6T;q+VQSnQUC>AKkxx zGn0=U%u(#Eoz(IvO!WD@7Ts${&LlJY%wzvNTXjN37Pwk}^f0fx>%^im%o)Mrp<0VT z6xG-^95oDTwc1sZO@6i<9A7URbc9StL@X?h9lJgddKgY`>OQ(5?H88cB~7vcr*e#p zIsw|Y$vX5r2}7@XhLN|79O=+$63TL`v=4!E;o1RjK4`zMd*e6mtq)1_-5Q*xm(I6~ z4oKNUbO#29@R{Mq;EbfA{3a7Y;6{r*c4fB0rB%?|Q4W_O1DJmduWm)#?Y*K;zqLFt zHDpNQ7*T*Z7&Yaj`sPJ)36C`MyID+Cbg|DAB_OA|Yl}B=K2C79D>B+x@c8Zfu*W9) ziI$ifKjR%rgEQtXObrS{1v_fH)9&&w5Tr$S)xP4GW98nLD4Ft4f;9H>h%;qmdl+gNOSQnw(YE(eJesyTxuD$?X+>!eerp8D_jvLag$aV>v95k12imjGQnAa2Dh^I>4UQZhR}P^UBPj5wV%joJpt-y zOx;?BcLhpIUKiSGsFoNT&8g=u^4!a2yiAT zjgeLhvy$s;M9AnI!C&qRoXI%j&Emyp?oe)(^5hGrkXT)V6q~qOx8h#H?k3rS==P)Q zlm1nedQcbB>W?mtxl`|UIT;tE&Q4X+FR8rlgWG+lY#w`(_y(pMLCvR35vQlDn%avc zvU>@gn^X%Dk68tOoSqh}sr!sIACwR69W{a&7OV6>1;$tuw(Dz@7}zCtHDqKPDhr8_ zh>$RRc`M`eS~`f_0(mvtHB*;N?v0S)>i}NqD1>_oyhkx8|6Z>{@O1r~!mNQ2Au5@A z%P*xH^dJk@#LnBVo{%S!OFi21t2P#(eme3YCR0pOI04Ub*!3}T?Fl{MgRA^w#$=Y; zJ7ciHXtz(V6aBii+TwRX{aGbzWTaTpRZsw#KCA(_4?PwOV`QI!RWo2`%2C@z&{t zz5LiOBw&gh_BBTe32mfoq-2hzERfN2NaRUbf@!0?{AO1(Eo0vsgBoUrR=;G#cYc+p zG_KeUmzkat8a7?wzXikX2;cN;=uKNK<|<-~;eer#Q0LY3*t>O^K+3SxZp|(29C3eO)%Q9wm=^h%qu%cx=e9cm1QhYQ>%3SK%+?C>z@wxHdw9~wU%R1mJit}`M_7V7e(F|bb)=$Mw&Cq z>$%_``@1jRJ^jMyfAmJZCd*PVQ4}x!3ji)AtL52E=?9i~h4Gn$y#0zaT;=&t7MW(X z?k2RdD*HS;`|XzZ?YaYh3X}3ScX;-su5DY5h2aAxUft0lOK0Dp*j2{po=RtwXjS^G zLcgJhA>r2JoQVwONDp11RYzOt_tMLWk{vk|S{{BN|2`a}Ov0(Pcia znC!KAjBjY%a;w7xQgI~vI%%?PmT;hwJuxN`QC~zsLedL0U2az1?A|fE#_EM#*<#a1 zI`An|Zo{Ca%i(AQ|Gwtza_F3!ilRR<~wVBHuKm~`PE;CzNXejAdtRvXo+&U5wer7an>W|9fp%i~Lq`5}^iAFoS#W>i?{ zdbjR+4h|V>f^np|5UbQXxxGnFwrnt6Wz7am>9=o%LIGX_e@pEWzJbNPybr4*%qdp!0i|IX$C!U z(3RRN)t}ma3ft0ZnIbKApYrU|f^Q4cl{h%JB2f9DR~%Br<@z)ssX8n(fXX3HN1s-* ztkWADmc)3ZZoe1xDP28NOR1e5Y|z@yAt9ynaNO7?d)Q%sITl9YN}thl0Y*t4D|&0)vzyr z@mqYp_4VofY*|BPUg5#ADFlnE_{;oUF-=*}K+{(po2PN421;+(>l84>)EAtt4_m=G z)ezI7U@ERgn$(n(%qbPt;<8xonn&|G1Uf-lEy~`u9L50XYQdFZ zuR2r8?5m)|$0+u_tAolB0-)PH&>pds2KE_0W?m!$^n%XDHB5AFfpJ)OSf0veP2G8w ziT4of1LM#v$Q+d<(`4`4iknTv_m~q2o%F+KwV-QpEb+UDEKaIBG&B>@*WO=6eR?wl zrm)Qsm4Xw__+7&)h1{a3u-INmp*Faw7y87JrU?)2dvX$S4T2VRN2NegbRpUp~ZZT2Oh0y$MZ?Hsj|gRW-Nw%M%I zkuj@0$)B}*a7V$_0^^lK{p8#294--vbSLU8iv=NxJ_14L#=0@TZ=%*gtIoy6URm8P znhq-Ny5htD*VLD|`B&0Q7R=efBVm1}Zeev^%Jt7s@D!iL zS-kg0{N!~5+G`tNOIdgNQk341`YH)`@l)^2&G?=8X|l@YD*~@9`6l2E44u}meEk@z zhuDb1hQ98`I}RDuz1cWq?`aU88mz>)(mWttQ&l56>aGu87BO%X>Pi%f3}mg8<1;Lc zgH9g`=vur_X_wHs<92A-cmQDEt~Mwxk$}@%i?Nnlxq+*P^%cPSinj_9dtL1UlO=|u zk|42`OIqFztz(g+=Jw^&8wS+@W7arY`)ceyC8`e9vN%f0U7ELDfFMO$MMBZ5iHs-+}du#O61ZsjfmhSy(On==&Y2lb- zSv$LjQd?=bQe539W0R`>lfV{OUs9jULqrE#Y`6c0Tm#cCG zd?-|XzP>V9=GWY5I$aAy!E#y_JY0HJq{-yIypIDfz52IU+405v@U24zboM+V(e9YiGX@Bf6+& zQH%?Bx{W+c_6gr@>)x6->kD719e78l$qY&}3Cc$mxbpjq;4hi2v*!$8|1T>e^@VPG;Z-u8s8Mm4aJ%q3bI1o1 z+tj_ztkM7uNcu>bT5j;|8OIZ#h3R{n;kU}76Cf8Fc1Z@~Wp6%ZjdV#P@mJ3Dxq$iI z<=bf|0KuIj3ggcmqZvyc--J$p4MXcLnK&M@1Rrca9rut_R9Zmm3jPNn` zfU)*R7SJA{v!MJ(w4dqM$9lBTgok9Z@=tBvZg2Wzc!&3oxRr0dAAG#G9)6w^XMX-8 z>Sy^T>EF}mZx;NI@YCY+kJ-=4>;Lru_xrixZ&Kl($v>S<|8KX@)CnMFom#gMNEN2s zZ_u^LVEnnStW3Il_Q1~i7NR-nHY2dxvflee{5$pN40qXL-2Vl0sYNnF>9`94krtd` z5;|rtEMeX^^Phc)40D}@^P6egvOq1@Zj<^Yr?wn@niKyLeFy9AE^?x7g%Sep;h}8o zrwjo1U~0>@`%Kxyd8Ia>zhlNui(aq&{rc#~cg%BO^V0GePo?VH4&GerF6;$9(KD?f zkG(%pgQ&WW9tCc2y$ml`iXWeI2VeWBP~bhTCN$ZjBts1}_BCIab#I7LjSXyzY#ul3a5K0*J`7kpYB=YG93gL~$nqE}u{?R$Dfb3=;pVcsCOf!qPt zE6~uHgq7l|MiukUbfH&r;<57&c=&gR-q|#`FD29y$ikY{y%X+VErQqvh#^$OR9Tvw zDWXG??knx~iQAiAm2i#CUIp9MdItMdzmK3&PU`B~)lR*`Zjs96epvB-5}I=Tt2(iR zuUwk>9P7T6VWqpFs1*_+)C4 zxzMymx$NO1pP6zCL#59tDJkfCtCyhWh{*iN1u}-mF9E8dzq^?vPjUjNi|^sxyVF~7 z0$_jf*@-$-Z+~Nfy?c5`DR9}I}#n+ z62xYu!34^g==&CJWzQZ}4nUnry|zU17qA1PH>WU8Z_YZNKJ<-2Wn9AFQ3&9isE1O0^>*Qmtc(ZLsq6QFZS4mTqP{j9giG5T3=sb$(bcNm?RzDkF`9K^Fe zs=w2w(@y&R;hl94^c5FG{s7^(XHHZywOFdR_oa8+KZX^T`gfvI5MBE0P5H)~raMwp0=~@{A(kDc zp03>;axQ9V75usn4`op?-mIf`e!CR`F{*h^Jm)a^K)#^)5F0K}74IK=VX;isMQeg0A zj8=a>62al`$TDkh3>r*#w3D3g2$QJik20=YA0Jdf+Cr7IycUeZI2-0h+iK&erw*>6 zJl*eqH0mbhH zuNxH+S%g%0<>jPJkyPRv$zm?FV}9ybhH&U|1IJQYo=`X*ifVH6G1dGFUu)ZW+Jw{{ ziy}=`1|{F2KA5a+5|@}HNzVWz8)a5+4l}$?m`>2+<{rBoc3{-pznw}&w_sA;1m{k+ zk{C?+TJ;{rO4l2U;~1;fW3JDx^=`9rF1!_l2f4Isi4oMxn+$GX@*`;oVN#%-tCsgno3KiGk(+1JNc2J7K& zkWI}3(c{PTlHVzd@O{jrRMw>}hmEN0#Nyf4@mSKq^gBw| zJqX9HuWAM(@}D->JTh}?7}6ioWwq9N!=6B6V=%BY(n;Ra^=wVz@#`rLbD=QiR!TZK zs#ddxAkoi5R<2wrZ*OJDkm%4m*9U0BDvY+E>Q6UDpY^8dF5S*?Z>$o_B>w~=NBK<@ zTMjfnS7b{bTXP5+XilF(KY-1lr+DR znU-bwp5U=TjClfNIDEgjbo%?K|ARNIsu#UXvvC;B>2?S7zAh71PQ)KO?#}iKeIvpe zDYjN5amt+|M4me6*+w}?rv1^)cZ=Wnezt?{O>ux zZg%Dk=?@Xk@Q#shjuVOdmeDfjGB#$si4!*=(5{d4D%k(Dm-^gRI@3ceY9 zvk_P^{$70od~eS=0U`@L^3jE_d3HwRTO08wqJD6PvH6|m7fxRznckCvlMj96k9>n% zypNqufb#EBA*7o)D;B=VcubSCqGjKX<+q2X=94L>wnOlXODmg=Zx<#$=`QK-i(GX| zYpCOB`MgBmQJY0D%MhI1N)cC@q!g@WsLzw;y_R#>I1^7c>RN~jh~$v;%CfL|I@u7? z{@C1h+NXP~cW0r3gM)SLxT_A+FScZ!aq(8e>;eAEy>3I_O4D*OL_tY|DP#Q5TG6~) z1Obdc02NSIS4XC)!nv6AnQyw9x>>8Y0bI`Pk>WXw zW5a!J@Uh|I?9_nLR@sJdUOVGEt@`>lM-D1X4SF^o%1sd5C}>_$Z3oY&C5y;YS5xi= zJ^^*dNbe`R>pLb=IYir~w@ceb2nd5-?T{Z7@whs>LimQa5~!yMWk4iNyc3b7LEdfU z<2=UdVkv^+_$JBpwgfb8*)J(;-9#p`>qjj)8>BTND!}^qb}?}JeV1!(J%)vkmi_K- z&iNQ$+}H9_kAf5lHeV9Q+kVKRFV*>~oj%(>UXG7#w8zs}$j278PM4S8Lmro!`=wFe z^RJo0gzkWH(~huSHZPmrxqrJpK>3($c8n3{1d!_bM%Huof2Dt=`4^9go&uU9<2HE} z^E@TuhnFJX?rV*j6_0UM_)T$F$l_d!xTz!l(x&6F<%*hF7Kjz}RadGWYRlM$& zhxw4oPW??i4Ex}U7!md7a#!z3t$Y~ldfh76sT>Y})alS_P~oS6;HaaUQC7yp_7x*t z_b8V%ywbLoQJ>}w&s6q|9aPWnP>tHqRx+@>h$>a}OBM@ys^pNYMwPDGflT@);PxSi zP+3Q-Lc5cXqURw*&mE^{qEjjwYEH)c_Vc{!UTnIN3rE4Kj?&(n;bRWO)5~+S2_3hi zL_-*Bvwd$BH`$qKNY&~ZK`w=f7qe+(U7)_!<)q2Kni(0ti!yi;U6>!KPNmFIn!#!( zjkJ7}@lFuaiDXQ!V7cNYYE?9mynKj1+DxjHch3o)^VpV~n}5h)x;6~$7xXV_j6dIy z>Q=rBrPL;J-=+4ekS@j7lUh4+C)efcCsQ`tT`h*g-+Ug=g%cYN^Z@I<+tM}%arYqg zM-N|H5tkX1k7!kNy49$`>(yrBi=V}KkHvUHM6DCJt5sM&6x9^FQYH@jZas@Nnix^# z)$M+s3v}X7G@xeCT*LL}PF9U|rHIjEH4Q|92Ou&wA zCa*n?^U4sXwwrPU|C^_>q|cwqvS>7+O#k~P()#v%4gGvEYOBR9^IcMaq$PcjZK(Q$ zEUG(i`j&0GKY_#DPav)8OsncP8BgaMAEt7Z26{v$YhR6i-^%)=|LH;VGwZ|26X1w8 z?mKr@?V#82$n3|DG~aE*55m=ty=2&ezu4|qo&YQ;otB3WJ1PgoVs^l; zhQ96=#{!x%os``OxSf7#yZbQX;Vov`ddGlhRqlm(f$@}N!ijPR_@eELfx5k-L1^i? z6g#*VvXe+u^89Q1^G)POP0!l*W`{>U0)r0K&a~}~`hM^NrHs;W!=KV?P5{=`@6J}F z@BJPmn3{5$vKO--v?pvO4ZqDstVX1O%z4xc>%fzH*@&V=k^PR5V^Gv{ZN~N;u{EAe z3hjyn$Dx5KcT`+K=D3KiE?cC@FnxzT5*&r1VjnY3d)b8R@NBPL&q{9vRpe!1*d@aE zYS_64eUV*UwNoXT>Xehy)5RBlJ@|($(Ar$tZS#!V9}b_H{T8(uy5pW4N>6w5L$Y}Z z>Y^c7(@-tZ5cFB?>$pCvLq?x>M%v6i3TfPsuA=!e8LvX=jj3Jj^>$s|8|`b-Ro%Wk z&dE}y)P-AakBqkmlj$OsprZ`+}N)qJN115ml*NqSU1<41fKCVV<76iYIJCJAdeg zqI=v%L9;QK>_dF?GWV8GrTc8JJm?Q5zOvi89lt*ugb$EwSDyXuDBjC&-yWqsE^7{;H@EQ7lp@bw29y0P13cs~AL`MSV5mTb}Q4dAFg<79(xv42}1{%eE2Vi-f1 zulVuWZgf4k8A6v9ZAB^iG$sLLv|OT6Y?#VFv@9et6>H2sy%VA-Z2)SMI{ z$)sI~DBPszl)5cRLB%)DC1lrj&^dT>lCR+MT5iGHgqR{a+9!uFN&WPqMkZcFtYuMt z9XBQ2?8Wq}HtWL!)5g(UM(bEJ$jqc!N{xy-_JDjhWiThVo#Mv-8hi_$uGonpCNkjC}crX&+j>_8@D6%8ptkLN3Vklmy7s#}4;xla@<+!Y z>fDrv%FWVXeQcH)B3QarI{|lQt@5)Z<3go%Dt(R7&+0-DFS0GA-w5k3)tF}x(&-B* zWLip6?a;srR_!w?Aqin4JFpw3(0$2%*obU>O4@W6=<~Cg-#q0VRr-s$`1V#wCbSC^ zW>6X%HJmw(G)bFq2EJpK5IKBzlo>(sJm#i8zOHb7PLNNDhYJn4M#PNO*ZjsohD49V z&f>S6%V86JN_&Yxn{9I5OuY3%&g-^SruKQk6!q$q_6aiLYO9O!v_%O#X_;!NTgC;N zPFhh(Q#(d)yBYjSi!FDPzb2Mi_d~J|EC=Ov6<+N|#uA#Bg8B*|WpepQt!jh-;xXUK zOni;{L(f3AfJzLTgvDjMmiaQ3@~R)& z4)e0Or2>lG*);3J?pIKYHWZGsAhsszkgXg{cRiB1wS?&T3l_Tb;UGBsAv-MV3{CCo}Y5Kd3>P$toZG9_*&_AmNU(b5fi{s!cLj117>NVRwQ3+RmJ!ryX<*g3va^L z3N4eTMwP{#Rf>`W6`C)mqUcid>lO!$IqvKdXw=_97C&s175eUSDD1K#7MnF1QgUa3 z$#^Ls5L^k&{7uqhI#>yXI8=F@enJ}rdRo{$zP9seE{bXI<$Ei!z zsSLe2rYk6?u=v&h%l?L-F5Cr^hl0g<;^poqK~~$xdRcnV--JgW8yBrWJ0EpVBkp{T z%Xzkb>tY$wT(9$ib0TX&B)gIEn>J;L!;n>f;RzsuQp`y$pBEE;rk^I7@(kv*^6Ac# zWAb)XXF>;K@&~1;?@#2as8ij#>S#Hvuz80E!F64*loO!i5INY-5EVCS{I%(~6>e*h zg=di&5qzDA&O?Jkw)F6}O^zZ8egB8x{B0cXJ_(`e*A(lVW$|w^cAVb$N3xRYXhT@? z7wzg*XT|eG0^tSU7C}B;P|sHV?`DSj{d`f93&vjyR#s>v$lA;6Y&9EkEU8S*y$xND zN_{Tf^vCdDH8rX<73`yd#y${T>!I3Qb}YhzjW@9F&{dI;ae9yXKdmE?2@|ywR#HI} ze08onxPg$et6`C7lV1#f+%FrIu55S*9un7=IE85>m0$Gk=A;LyF@Gp)Njzd?r(Vfo z3Ud^ss~>vUrgLC%Z6xSc-@w`kO6romPM2*kjv((wpE4!e9$a1l|H;m%yON{(VBB`! zTcfp=u=Y&ysp4<_J0Z>9IAV1Y;_zX&L z!`orj9(~?EL|H8MshVeJxJ6XH{2)}aY02h;Ktev0Kud|*_ZU5DWIZ7t%&VVXs5DK_o@#oc?yHJz+&U3Y4Hm()&G2kG#AWLk)Oo@idSgzYj% zwrh@7^Q-2tqQgOsiOt|{-7tJHX%w@OTqj>zrDz$>Y{H`Gu~?JR=uY}!?g~;x;yyGj zCs4w=+2O9-emI!;7ArqDJg$dy009IFd*|{mfPPofOtW2irO~tz30y}-3-z`@GWQ$q zlD0XxPFa*?$GHEke96jNIhPQchb*W=^MqQy5gLZn6Y2euebv* zjEUHYLmfoFaeP$i|FPaiU2^t~KUKJLWQgFjp`W<^TZ6&WJID5}V3`e-D zH=9#R4d&M$#_J5U0f~WO=Ln~-Xw9313<_@ zw2%Gia*1#*+{6tBh#VMJK6C%jg{El0lU@_VTCIV>!{=_Gyj0KtN1ZyG!BI>()Qlm@ z8Wc5m#oUI!vI6}(!X5j7m12f--d@IMr3m^v`Js$7kkquFmp#=sY-q;2qopQQRzu!&<%2^E$jk#?u4WowQm z?@M}?HH4TN3A_Dt^!2-E!gi3VXE27XhfX|jf74c%y&w6c6Jy@fw$RbFnp zAB_~`TvPT+h8b$DY}FyxlKamY`Yo^GR6{2xlbyA|R2xEYz(GFCo@5LM&*IE@n~aK| zoSxcmS{Hl_z&-5X^e)?0v@;6oG7kX5AvoI>T@k&G^j}_Hekx>aTK}(^AAi&9%71r- zGY0>=JLpQOd3`j0uO7L`aip)=YDH20n$kIH+3&4-YtY8uIDpFi_gr$%9pf#%v^PhJ zJdvK;=#ws3>USouQVrUYt79#5{Kl&k_K}Hd&4wXsR89{ZpB~lYOl2Tb8I$+pFx!{! z5qjVFCQUI4()#)gwC2P06_Ms>V}ZZxI5$0fQd&Ln$w;A;prJ!|LN9i49)jd`l~of4 z9+4y-d|sEn46p5{q-ES&VMX$2a~KyGm=qwq87p4>nom`K_X^vuOZ-yFN)Zv(Z?oY| z`G9I#bPVHItJeLKPiUBM+&Z9v07tFm8erM3x%JJZ$3%HQkn%!NU9Kj(@%Q*Fl&*Eh8t z_Y+{*9E}MsT7bZh++5U`uGRps{DAWI!jOFuI>yT-xZv|EYYLBYNcGlhE6=d~Z>e8j z@M(&Pzp7AtqC-B})$Wz7kyG#vs#P|A8sno-f2+Wp{xWX$h&!P}4D>8{nOtHYC$uOP zI;cy0?)JG>lx8dhHoD%rGop+jU~+RUl)G2`89|9LpLDNnspM?^YU{yMUTNOeWFTNJ z9Ece*>R+y=|E$4_s+!f;`SrLO;hI?O3d&f4A%D0_6OR`ym%igKA4|i^{H9psF_N*=p2)1rX%TTtF zYKcgHmSFD*WpMJbu`Ymr|D@fxXKdbW*p*<$!Cccvyv8392e#r&)V>g|pLS&{v{A4^ zPrjCGmNcXskRy?PfUOH5XJWT>uN_=@a(r?vo+0QIV9n^XdVn)Rx?cK)Gg1|PNAuEQ z-qgtLzm|Tmyp-27_wM%R2$2Iq(_c$}n*ZSTwR+~lmP736`pf?+ar|a=vZ3_L$=%t= zP+PUXmM;DJ|6uT=5$f&Jyw43^eGlI+{l2@22)!|DaGCqhO8c#Z@o0p88zFhp0~~t} z-W7IR{ONDbkbm`Ua01rAJ3ItyVgnKGax9U-7KGx+Of)TU2aCcU3v*3W#S8=?7Megr z=3>^oO5sR#j!>RVLdUq7&?9%OM4CLUVzx6hyah&4)3NjF-_3ARP~1(sW`p!wEebGf zqGi}nWw+hTO67iyqSTJ(zGoHDQ}Llfss2A^@tErG>#|FS^^7L9PSWVJA&Hk9xr(_h zgfK(I?43E1=2PELRGnmdO<%>3Nt=fYuX@wFo0>k!=7a$oN%k^-%(-jF1CkU_p=}g< z3h3ZaNLS_Lt+ajQCD#=%7{+XM*TzO-ThiQzD(l2uuDEV-k5cE71E{aqvrMcvOi)N) zKR&K8TeJ%y8i1wnSF!j5@#BRwN#vXU*6D!|4`~B`HosBx6B&6xNBW&XPLcEy&&$uUSvI>WMtSH4mt3Jk+do0_ZUm=f;q`T1JlyXO&x8BGrw zp8!s!>dXv1++j}jesXI)8ln+#$o&E~4AwQYK!$Hp{O4cQ00HI(F*28>$!7d(1__>~ z!f20DvmG(ckeixO?wrE?+6L_L5E*!MU(7rtpo(U@o@L}<^?bpiE3&E5V6B4{dobCo z?A=)hdK&+NR~IZ2CA%fYVrNdW!Q_q8Gq-Z>+dn44jEnkLy}fw z0=OTu!p#-Ha7*f(+93%lno=;9F&PNaeCP%OFHEqguF-EClJY15MrCi%{Y^sKlbxd# zAv6>74)IBFG|G{W6dB)m-g=A{G;LqSd6;OdK7MaM6zrLkd}L6L?Dehl{F=m@yKwsP z?U$Gq7d|mPFjV*H6Y3>~hz#3|a`^t2c?b~D0z&mXlr2j(tVLUEP@=#b9~V(>!t;4X zIrWzdy8FQ5Df0PEY>f+A`q-?dQOuk&`7p|C?buc3V51R1_?q2zyMg0$LgFacRV&WwIMDQq040extqnf-luH-L*9l6PUwbc!=ztXTR>No-oZp!YTOhhYMPZq{o2KP= z2`QO*&vAkS01n6So^!tOS!Qe!)#zJ_uW_NvTyUEVz_-P0D3)ZsFRQgpDhvG+q^dGq zwmF1VNO-liFKG~r(N1vi3+2L;+k_`V16fSiyY}>;?}aP8j20Kl?Gr*?v4!|NO2nbw z>(K!H9m0{PJ?)-cj4+1v&~;K$@gqC^VW&(Tn&o@!0$R%)yQYw@!(p zh1+aayn7rdW@W~4{n-Yw)IPk~aHw;UT1k6WlSH_|^@8X)RxCO%r|BVUTTdbj0)1 z943D(>q{nEFsOrkGZL&2%d<$ch0ujhnRS+4fo5}{gkAOl-6BYt-pEE3O+_+fKPBW) z@9GBa2JSl(-|HpMb#4`zFtu4IL2FLjK_>b8Y$ggX}EMwlI?g&am{lASay(T zEBJ=Gse=%o)>arZR=Y}zyJQ;>l8AG7!}VT_AVuZ={B``SBt_jMbSyv8SaHn|h(L)n zx@z#KcPUchhGy4gWad~jN2XBrpS=A=DB$r|&R7^E)=qq#u+<^Xw=hir%{;)=ah<-fa?M-f(9@kA58BbUZQ7ypBdG_V0wUr<3=pUni78lLTuUCIu@I;2^ z3agJvn-s^*Vvyg8ZXt-aED(tB{!_tjv#mO#;bu$zZPN~%SG6hCIKXg{0U$jsFj)_% z>PTm;BNwRIM9>5}tHkEzflZGCd;M4-xcB zbji>RKD;ayPPDPRiP-|QJpaMdI__NuV(z9S=m?NX{m!(n6Ro4|@Ejrg;)KIWYO&2g z%`o_NxjL-=$3K`VZP$(8QXQgOuJasQ54==*0Z+a2n^LAh#g=x}^{ z>~zkdO&Q?;{fhcX>*3*5tJEYwmja8$?gT#c&)CYfyrQINp)}gA4>~~ z!2D1I%>7G-fut=Au2c42YXyE=>G7Am8!s)pCF7J5_{5N~XHrVm3wrz70Y~@@MX87k zv!QkIY!4DZTjsb@tLxn&=ics2kyx;S7IL@KCe~jFqO<|zK5@%svcEm! zhhuXJ1vc^&O1AaHTwHh{$H3bWf0B8NdM;KN$ZUIy zTG_fg;F(fYjJDY7jq-y(EFY6N^l5s5|MO0ZeA+&DU5}-mzq#%*%U7p}>=4@}K!^}r zke=!C1tw0{yv)M_a^zMsdj;dRlQ4bWCYOilPbfxM10gHU+4EhFi&?*%r(XNtuM^$> z8RHs|UJ*X~b4&VY*x^gA&u{j(F9;uxR=9jq6@7a5t~o?lWuUgDu*otJzz8=m{4Qd z#-3y{E|Hok1u{-?Ng=}4Mei2%A%)j}^ZHWE?UR$Cns?~~U9w-y03B3n{p#b8VTRff zHp`~&F7%GUQ^4GzIP3WBlK)4Ix`d+xAv&=SuEZ?5#v+%o!NCFFnT|e9I)mZn9xq?Bajzw0%5Jrrt+=9Mk2&sr z?o0&6KNAXdH5$M_!%Qk#aUhHWEL1x34r@DVBH=DXqd|g_7r61ky6c9l^R9)D4^^>)8=O;Q z7{BeOUh#aU6Bd&~)3sb$pnF<7X&2AIH6sk+6^{JMVH%>GbqW6F`aJwYj8fOv5y#p5 z&2fT0u6Mj}>CL*TnwMR#=7&*z(3jfS^R_(%5Ot@5X0nCBk8Fx0^O!5r=OE?#P5Y->KcDjv?PjGeIIW(y;BRTgc9q;6sai7*uc{8@?O{Ymn% zTCe%a!8ojU>S^@2l-W_2);AY1}70=9hkM3q%4Yq2@0%Q)AQ7ZdNFm0{x4C3Sp|I)OmE=HRT?(9AGO7qo5A zyQ|6n(Fq<4=2TO*x|l#$gX_tw1!z5Wa`K)o|5(mGn77f~OLW8>e8R8ASs;aXY37=B zGJNd_r%Blc`&ib=@+U)ROfk;PDa&t)qALdkQ|!MGWuOp$F6iz7XbLi4H%PN(=@)Y;ksb_ zTaI482|Row;e*(&XRLEqErMUam^Z~Lv5h3z^yYE?uDeaClOG4gDh)ajU7!sOs;cNc zYn$}Wa&p9w-8a6m-O_5_+7K2bnLkCrE6hv)irb>I^l>e1@D9Saxaf_|&FaOo(Gj&3 z7ZjBvQm-Q~Za_WjXz5^`zd7>ubop1V$%69}{XF3!5{h-}KBi6x_VywVXY(OC_$9jameUoji zlhX`kFgL%jDL>i|l`5^ygqj(q&*^66Oa~>S4gB?yZXNT3EVFTOj}hp4MAIL2x9`?< za5c0-Pc8?%QD~hIG%gOZddexHE2Y!4vIM;5?8*(Tair+zvgOf3`{COr%vL}3={XtR zWslh;kEd&CpGt}-gKA@5gXMR?T0`f^JA9wBr78JH7_uy_@@(>3TX!lBf!nhC&SX)e zuaai_ohe`d!KDC5z&8!_gEsrZtw|bFFcM(%XK$q_H;<3b8O&wDw0n?; z9DXDXGCR*H*A@7p2nMj2v3)|9r25wf-3wTUltRYJ&Y$mhD&3;cT?7*>#n#V`r?bW> z`L1|F;D**_o)@Ot5Y~Cqo$_v~EZ4j&ymPXa%oivl$D?uEbwgvJOn(203Q)?-lOtH7 z+hx*PgE<(BgW}soI1`LA?`cI!z|SI=Q(`*HW#G@i97%s`4DFmGSvo8qqwg|JPCI~`j*!*^Au zZ-O(hyvDI~Id*ZX+Gg45bLEJsErf5_^z-${Aj5bwJrVz}hG`*wn2{wn$Lf`ppN9ot z>1iJZR^1EqU(vw)S_!>ffC&c0%`z*fhd|92Ge!g|^_( zF}z8lYUi^Wn}$m9B;2c9RVV=j{p0SVPt;y!<5=$l%wdihaUE)4xb8^62tqJayCZ>= z*B2RC%wno0p4bxH+JQ2_Yx_Q_aSnj0uOJc^8J&z+24^%;|{SM|p3i@sir zlsNa7qI5BRp=o2!1b*FMutH5eR!4awG<&J8b8l)%il)S5@M0>k(LGd1ZEdS{R`6qE zJG_4U{)l+i3?%>7`N9Y^R2pFKG@O`pc10)ep_wFAD_zo*%&It6>ChJxxpF~r1_HYE z@+s(&4o)XIA6{(XoIM_^5OlDiTuGtXx!1{}t_i>p=G_d6wJX_S8S0bJh0M7g)>{8l zh{5mG(&ygWn^5!Sgx-9hligXtWv(Ub?QD<1IL%||RaW+3{SdH!sjXuj-j)u0SuLP& zo>vr^%UKro$slgsd~sZ$`pf7F79CZwI_J3namD7`$j&iJ&M~uH-%I0KyG(^>Bn>5_ zIk5?Xj%36n8BbMQ-i-(9M7MlrngV4WRCswxTbUF~&+&3;nkxW&ALx(V)6tC0|q^C`}ui0<7xIQXz0YBZabPYAL z7Gu=xi49;q+>%{mCP$n|VrVY}{IH56*`($=-K8`Z8acGE2r&F+$9e<=P9-pq;a6dG zk>&%#(}RW~Ao=6!&~((u^JgWNGZj52=V)o%)QIXX8MB~>8K7wOoO{A9*j3uRPlJ2b zSS{pja$IT~KFsb>_96Gzse=!07j{jD;3F=|w#C0Zg)Z$q{WY{<(G}$|)lvV{F4P%P zx`mx=K9Vb0SC@=LRi7hb8%GrR64tEOfNa8c2t|aOz|QH-p$?wi<wM_2C z2p{8z_kGEF&s$3=sJfvZ+p6{8_666-qEAV~fFN_fvCNF8!n|J7^^>*H%;vs>J+X;u zCu6DfN(-?9T4Ks;!tpiI4H_YHF>y%nSbYzQ{?N0U!hsm4bbkEF0sIpFtp5yHXaFhw zAfA@GZyk1OgJJv{8hYfMGq)kusrD7!P%gNC(+IQO#bJw8(qFSiMd|~SUyv;T_$s55 zad4jYf4oL6ibe%2<_HC5efq1j=>Kw*1W1*{7yYwd2 zcDPF+<2%zt;&&#k_nn^wf}hJYELr264)K0Er@TqmXJP2KR`Is`8o2?;>r!ix=~Oz(P2K9fEjT{D z!A+0f=vv3nzg{F-puaOw4}=)u=aa@>Pidvop5=XKO2wU7&fSD6D=kKTXG+7KS)vgB zUDIM%tfTU`d=+9%N`~TW&0xc>M$kLLu%a&w_?^k1h=9rX@SC5Bb$q}~2AaJ0D%i*1Eq~c>Z2(^O(oVd`g4>COV|74%u4lIrhSZsDe?2}Bi|mu+rrI(zCLEUzeJ#z)v# z1!A1-!4|Kf0G?H~to!H4lbR|qEJIAK)G+bA#2r-~Ra2txp&B6X&A?rLTuNtlF~S`_ zDOz5Xugi-Lt*T)gdnL{6|^(gF`X)BI8@HUo*e<-7yiU!e>0X zKd2{l#}xhMDx~(sds_r}L_$;i7-}}^BAs@TvId`^%JlIRd?@*R zMItqIcc6?eb@yUUm{~^z+YM7?PRr%;Cwj@}Mr~C;h28$_SuX1jGC^D^k0lRWbjvV= znUU^^=46Jw& z&DUR#!iI;UkMs&ZO+c)h4fpo;jy*E`IPMG}c1rzcOR7z}`0?W^sx~IJb(4sOYa=PM z$HN`jHyh2Y@YXAC;RX}4D`6mS--Aws6{i&2DrBB2;LVJk8U<;a1W*LEJ7j$^iYi92 zj7=~*NG-HLZmS7|S&>2v`5M05JSY2zhieBCGfUG8u0J1qk{3+2<&>s_yV{=&JKCz6 z!DBNFn#+K(%oV~N+@aP+IwEh_X@yNe7oAF{Dx%U!GxAzSWE5Iq$32lG|=(go9rJ8Ignd4W-=y%_g6vFvvv-AC$Ej#lSPH^u$ zPJoJqn9i#zv^8&5BddU<1)7wfyRngBq-0Gq79G}=H~j6~EMPr&P*n|RNRexZJZpX| z8Mrv{$=OanShYzY=EFZWhyGE^zY4``{2x%ffWPIaJ1#J~)X&vK<1%nRzEMP*g}Q|a z7X=0iRlsKa%COD~6nDA=fz>CrbP6>&m1DA=vz6v^rxZZyW`j$bj|OZEg7Emur(@Q| z>wITcKfE1jyhNF?dB4nfx%iNz?cWLf-s_bgb1U##(+?3eV2soBdYXEP}X0L2`qk|}%elf=!t56G{ zQJ<+&HPeH|^!!hwf%iJ`>7wqh68PelqHLCrNl2G0^4R+LAHjnDgPmh}9CoU+u5B8k zCZ-yj&zEfO{&AXgTV2i{NVX~ucX9r&QtsDu1%4xBi$F_;(iSJ60OTlIL>KUR{hF`g9$;sn62t?IC?3l z?PElXwxp|2)l<~+@uryu% zgIlCO6>8`y?`|Xzy+j`y_`qle?8%>B2Gp=@m_;O)%TFzNcm&FIS8O@Lh&+!~HHM9Y z@X2`?oE4O+YE}4~?VtZ^(?>Xb_5RM}q$G7RC%u)}j9xEOnBJFryV)aqo+<4_|9|!W zzf@c#-Z$Kom)Mi`ir*@4*GjJTXzyD8T_d~H_x%gbeH_oev>x=rZ%nL~f#Y}AWY?*4 zGW-YfN$dkyh%Bl+wvVu3ESfwmg`|urT8Z<1F_X1-qS=)&AkZ#PrY$?L$r% z)Fn{5Y_|(?Yvi;)VA4A;AK$t{M;?c?hDB!I4892cqV`i_g6T6nINl8Ev#Sz#Wc2e} zffN=UvO7fz?a{H5<(>rI3ib5Xst_!xc{WVtmZv-t=-^N+d;FbgTVpGy?h)3f)~(+$ z>{)D!;Nq?~5WnI}uf6Uh5C-=Yi0w%VmPw!*11wYI(&jkAD7RnLr9jO_JlQ0Xh{x|9(e*kUA`O=R@_AQ3k`yybMw#;Fw_H zrkz?UosQ4~-cQTap~rhDFGn|Lkp#d{C0*&Ve$JI!1F%O~?8bS6jI=`M)V}5(8L@^C zWIHwrHTYhVgQgHo_fj}caE|X$!MfHs;@69{tXBfRdfHEy&z&wv5=kyE&&iD0z47n; z`qmNvL0Ie_783umTkH6+2>}6&6yrrnw$1yqt{frR7ozcSpNcl)Rt^OSvR~(b1va$9 zwfQA|nhWpvZ7py#YYY zGdbq4-8RT*SPJkjrx>Bya6eMA3z}v*@Ki@o(X~o8} zp0M}HppK?ZbS+cP5~T;oOPI*T6E`rQ>r$mt=i! zXmt%xegX!mOG(wKL(;k{1fRFAJXj|5OTk=dzTQQ%<&1Woq0p+4V5Pyr0n1Iv!Ju&u zm2lz*dhnOC4$`rdF&+^C+|SyUbEoyh?19D5xk4>>UA)uC$GPBAa-p24ewr{<=y0p9pvDVXTk=Tfsp&8+s)r10FLX23->1Bxh z9XuE;AJ9KCZf<28uXAcLgrbcNz9`25ZBicBPzC|z2@BjJGMLovJ@rb?vc^+pHOK1j zOcLQ1D<`_c#>~@u#{IX>Sfp-LCR%A4ZCie4dJ|oe{m@*ofc%2EOWv_iJr&j`30Uam zfPpO$tA=Ad^9cEX5MW4oS9uH&7F?LQ zM)e<)oV%%@Wt#>k4J+HsK)E(%E~l}HOm2P6T2qPuZ+SceZ5*gxBzewbqN-*Cdd-r> zQ+A+k6HkGVt@&D7lj79|vD|t1VK;x(TDYJQ|D;w~ip*#m(V>AK58O}h%ELb@tva96IiFp=J=2H-C0}7g{HLG#f&iYt7 z!G#QY2k@wtEh*^(FI-m|8M*3Y_kiQ*hgoN_b)*Lmsl}jSf-$L3#Rwwr@R?Abgw1RO8llYM8 zu6bR`w#_b*rY)y&bSzKF%?9Z>(#pOXsrNBFCG)sCUJ{4RJM2@FYV>R@tdeW$GG)BJ zEb7|$ac^YMmGdy#LjZ7y6!zd&$8k>e0%~~{uIUol{cPaH;e>Ck=W6a6{kDSe!l0jY z{~5=M*DRzGV0?Q-3GO#`&s}`_KEt-(&Yz)-$Tj)| z#V#;DbKHBR+`@tc!Fp|S7US6@r;^&|3kd?blt7yYvhFqh=YhDdugycVKW1GU7%XQ+ z7zxIyvUwZJs-GIoG^@Cgye)JW@UJHqunr`~Qn+@%NhlRVjeK=t}*E6oA0F?EkqGKs2z`W%Aea1TATQNzh_n z@^3oWWZ##(k^gS1i+mmrx+(r^S(S|#V=bwksDq{0IguwUh9dpaP1d=?Ez1kY%sC>kCw#Z66rI(xV^HYKUWA~yA3X* z)yZIyA)~wBnQm(zkDM%Bd%IP!@#*RD(#e;Au|K-hc`RVKd6i*1;iylBqj}v}PYVRz z*LDiZzjs&QTt4h&!(oW@aKqArzs~(;AaDp{r|qD{pnNRIgeSNmQyy>guTgOWAlP*- z0~d~Z`eR)l1xk>D(h8E!27>ZV?6F0iD~9$*oL@#t$FYs)C+u>A_4ze^3vmT{`q#Do z*JKw^Z_bzWpNmZ_&i?C?{s@--ueHoEL~eX%dXGHyJbS6)&fE3>)oFVFr@AMY*c?5o%C(Wuwd3=@1Fwp<-v;2JtdW>|>5VP|536_Zijv4+p+Jdb0)1+q#< zjU_n~g(hC(lQfn`=eIwOoC}To#>6?HV>CTRon zQridTFGv`NsXcIbk#J=8G!Q-DAFh)vCv1oR-Q)Kkdj;=8-oXv43bf1@5UROUSXOF> zPn_|Et#m5I&%Cc=sx!ZV;eq)b%(}L@Gcu!n;qjirk?lUsIzUL+He zcs88xW;$%?B7$Sn3|7!LO%a-`xm#NVL5ldDC#vC22RbF)Yo-RL^bII*bClB3${%C# z(2@|bC2uEn{a_WyZ`xDdger~^g&~_IxM13HVzPQ130FN{1@fElX2h0hr49Zvzafl} zvS-x^$#@#kFlck%s&G73E;%I4)27$Kbh7q-I_0ieGGdZF}*xG(%4Nr)Vtg` z8o25?jn#DHISG4+84uOZ0dQBHkq;C;wUmG8n=a0W2q+PKBJ6alvS54xGTIM3xO~R= ziEWqG;YcjZ&9u&z;gPgbZZiN4D=fv+f5EhxZp=g1JRum4x-&@ihUx=1ZOsapUzeJ) zj`B-?^$1+(U}i5BkF?{G61JL-=AF;$wP@xGULXgEV@cE#1C1(g%Ihl_{+ZXDpoma4@FelNq z0FNj)%8qUwTEAFVDfbcGIc%(x@XPejr`+i|L*DUq1HcR|@bR~NZHwQj8&v(2A(dFD z9aP%hBT~U_C!{9FTZ~1o3PMGS2(nLM>{OqQ?@Y`h?P17(q2v5emIG&CgHu;c^)G=V z)rMW+j@gb6xeJo>?h6FZzaPwA@IMdZ$9f26JRX5)<&{fx6nz26_d`!Z)1Bm&ShkzQ z5PlDgB=mQet$T*&gi!Zg$>SzT%EYk5&qnBp^$Hy_3(zvxmr5h*p9+NA@t< zi@tLFAc7K1xGTduw0*F1SlUVy%{Jkqfe#}n0bOABu)W=p-9*gK0pME$7z)lRRv312Bzw0Xcv=aOP`3~shqYTy5#mFKt2`F#4_D>OsKWFH(Io$5(gF zEr8+;qGKW-rd%Y2RC$Y$Z*qv`a)RT0zuA-3%l38m4=p7@O_OQvPgv}uCNYr$UK~dB=Xbc&L6O5 z`0o5kuEM(pi^e?GjvCxJ(CmM!nLQr;*((~EsN|B8Jq=7DjSHHa`5XXLu`dGcRNY88 z#ur~CKwUgE+d;^O08``D0Zspq=FeiQgxz9$8Uyt<@Bol0$2x{RU+`dv_4@Y~(x zO$#|0tzJx>TvES&PQgXrPI>^H_^kd4LYB@cA5@Y4=sVNms*_s^z*Kpp&>KHLUu|Qv zye*P1uwWl`s-?Aq2rnW91*+DN6sy}FWv;t<1lbqF`^@!(vFd-F1rNe?_MYRq!nMcR z@T`$Z+z*ZSq*D{IHOJhO>C516NwkW3hbR+f;92SzDwDBp*ajC^mH1}EhxrJ@#q7+M z6Bl%unfJ;{6KxTNG#!f3G9`ABf00rbi+C>Kw_8} z33?}}J6OjKJrqjfhkN7=7}9!7?}ipyQ%IVZ0$!VLhAkk(cNS@p0hJZR* z4}uZ7lPqk&i|1u`7>tAXhXaZEI@A?!?zT-yT=8v!rEi z`YIP=W5|2Y+rq-Zwv+s32Eglma(Y&hs#W775^IKE84HE)A5GK=6To1aT?ZNZ+V6b3 zs_RAcjBzxB*!ydYE03!r_hKc7d9QJdvveNl<>{vSD6WV4wcbbh2VnYl+e_Ao3f{&) z{NQL@;Ui@XGI-vwJ84-ens?1SS_Ff03N!1PSFZcEXNUL1NDv@d0WI=7GM&oA6V^5t z6wZo&8Q&B5wB9k*)~^w3vgOO#3HNum%R=M;5KpqLZ2xjE8aM(oLec}1ntM4F(0_3T zrTI6^YOT73hTX_$*ZyZW=Raus?^;i7<~c=+FV9Y1F`vvm`16Z8gs>~~7dc;X&iZJ+ znRC6of5V>p%-sx)@2LK9z9g0v%RhyYqNQ*FR zdA>L{oz9xussg)badRfy1k#k~&kb&IuguUZZ;-r7FCrP3jWkFFM;SGhmY_%`w&JTI zv&#wjU{z0zt~V;Tf(Y?UP_??*t=GR@A%gX`x{n8*VH9~woDf&V?&ES1 zq7SLOxXetHI~jTSOB@ko=T>Psun>%eALXOvKgbkQj3x?digF#0Zu8@L+koD)ynex7 zSSGVTXTs#~OoPV)DUitK5zXUBtt2L0sJHPUV(B}R@iH8Eo=Su590j#<%BuAPZwEnh z)-&%^6RE6#J^}iFXF~7l-MJVnJais4#7FL)#r!`V`~&sY^Q#?_d*yB7v(2>eeU$fz zPK$52JdnZ_g+r3S5+PFQ3Jp(7sW&T*ZR=V95)BXu&H2hN7q%03QzCzTb@yadddpbR z_*uh$SKa#ue~N!xo&Fc1-g*2q04}QLKHeb8sz05z55#Nj1*EQiNhm#Hf-x}(ZL>vm zlR9%Qrlxl0EF-2r#5}P-Tz~ZQ+qJX8=HBXqKUkQUE~Wpu>&=Uy!&VII*@OGVwdyX= zdEp1*A&;=<)bwk=l#h>Bjw*Sgob?IoE~+`)Hi)hQ)8UnfeJu^nxH!8NbF?1CuRYr? zi)X$Myy+uSJo-Veso5*IfRd}*R+;Z9RuB|U&$@c!Qc(S-ZrjJQVzVTr)e!X(sP}5k zx6of9_UG)ux$w8S!jErJbnpeCM_qLj-Kphz;P+VmSaSRLur#4Z@sv$ypC*w}qQemV zBL}AjfA&X^vDN^1*~0gCS@RZ8YlxjP(%%*8Az^Gt+^sa~CymyKl|~d`;p}bqcYa-G z_VOt8-R~9LO)oCSlMZlfmMc^1ba1aM^ljo}%8Jc0j$HR57oVZO3N22mZGkG6G8Tty zySE7g>hVtgNkP05PHR|6YosWeC8k*!-$$cCDI_#i$PsOQZde%0DP#P4J66KzY+(4t&-O5o_?ww|1$-u8BwQ?9?>=@l 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 z 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 literal 0 HcmV?d00001 From 365b97a9305f6b8831023cf81c34a737bbc8c0c6 Mon Sep 17 00:00:00 2001 From: Ulysse DURAND Date: Fri, 10 Apr 2026 11:02:45 +0200 Subject: [PATCH 02/13] ci(pre-commit): copy from cookiecutter --- .pre-commit-config.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 743daf1..d5294d0 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -21,6 +21,12 @@ repos: - id: requirements-txt-fixer - id: trailing-whitespace + - repo: https://github.com/adamchainz/blacken-docs + rev: "1.19.1" + hooks: + - id: blacken-docs + additional_dependencies: [black==24.*] + - repo: https://github.com/pre-commit/pygrep-hooks rev: "v1.10.0" hooks: From f5a40a69d65405c54f4a14ad4cc0fe25ee317bdb Mon Sep 17 00:00:00 2001 From: Ulysse DURAND Date: Wed, 15 Apr 2026 11:48:31 +0200 Subject: [PATCH 03/13] ci(pre-commit): change pre-commit as in trame-cookiecutter --- .pre-commit-config.yaml | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d5294d0..1ce3f06 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -42,7 +42,7 @@ repos: args: [--prose-wrap=always] - repo: https://github.com/astral-sh/ruff-pre-commit - rev: "v0.15.9" + rev: "v0.15.10" hooks: - id: ruff args: ["--fix", "--show-fixes"] @@ -58,19 +58,13 @@ repos: hooks: - id: shellcheck - - repo: local - hooks: - - id: disallow-caps - name: Disallow improper capitalization - language: pygrep - entry: PyBind|Numpy|Cmake|CCache|Github|PyTest - exclude: .pre-commit-config.yaml - - repo: https://github.com/abravalheri/validate-pyproject rev: "v0.25" hooks: - id: validate-pyproject - additional_dependencies: ["validate-pyproject-schema-store[all]"] + additional_dependencies: + - validate-pyproject[all] + - validate-pyproject-schema-store - repo: https://github.com/python-jsonschema/check-jsonschema rev: "0.36.1" From 0d7fb06dfe637782fa85cf8089dd1ce3bd73935b Mon Sep 17 00:00:00 2001 From: Ulysse DURAND Date: Thu, 16 Apr 2026 18:16:42 +0200 Subject: [PATCH 04/13] ci(pre-commit): correct most of the pre-commit errors --- , | 114 + .externals.sha256 | 4 +- .flake8 | 2 +- CHANGELOG.md | 194 +- examples/pyvista/ambient.py | 62 +- examples/pyvista/export_scene.py | 26 +- examples/pyvista/grid.py | 25 +- examples/pyvista/lighting.py | 60 +- examples/pyvista/picking.py | 38 +- examples/pyvista/pump_bracket.py | 14 +- examples/pyvista/push_camera_many_actors.py | 54 +- examples/pyvista/ratios.py | 18 +- examples/pyvista/scalar_range.py | 24 +- examples/pyvista/silhouette.py | 56 +- examples/pyvista/simple.py | 10 +- examples/pyvista/toggle_edge_lighting.py | 24 +- examples/pyvista/toggle_edges_many_actors.py | 30 +- examples/pyvista/volume.py | 20 +- examples/validation/AddRemoveActors.py | 50 +- examples/validation/Animation.py | 31 +- examples/validation/AnimationPV.py | 25 +- examples/validation/AxesActor.py | 29 +- examples/validation/BigIntCoords.py | 8 +- examples/validation/CaptureImage.py | 41 +- examples/validation/CaptureImageLocal.py | 17 +- examples/validation/CaptureImageRemote.py | 17 +- examples/validation/ColorByComponent.py | 47 +- .../validation/ColorByComponentPyVista.py | 41 +- examples/validation/ExportScene.py | 25 +- examples/validation/ManyViews.py | 48 +- examples/validation/NoSize.py | 30 +- examples/validation/PickingRemoteLocalView.py | 17 +- examples/validation/PickingRemoteView.py | 16 +- examples/validation/PushCamera.py | 62 +- examples/validation/PvConeLocal.py | 16 +- examples/validation/PvConeRemote.py | 16 +- examples/validation/PvConeRemoteLocal.py | 20 +- examples/validation/PyVistaAxesGrid.py | 18 +- examples/validation/PyVistaAxesWidget.py | 37 +- .../validation/PyVistaAxesWidgetSubplot.py | 33 +- .../PyVistaAxesWidgetSubplotLinked.py | 27 +- examples/validation/PyVistaDynaLUT.py | 10 +- examples/validation/PyVistaFirstStillRatio.py | 26 +- examples/validation/PyVistaInt64.py | 33 +- examples/validation/PyVistaLookupTable.py | 62 +- examples/validation/PyVistaVolumeRendering.py | 40 +- examples/validation/SwitchView.py | 42 +- examples/validation/VolumeRendering.py | 28 +- examples/validation/VtkRayCast.py | 27 +- examples/vue2/cone-client.py | 26 +- examples/vue2/cone-local.py | 31 +- examples/vue2/cone-remote.py | 31 +- examples/vue2/cone-toggle.py | 33 +- examples/vue2/pv-cone-toggle.py | 24 +- examples/vue2/vtkjs-mesh.py | 28 +- examples/vue2/vtkjs-pipeline.py | 4 +- examples/vue2/vtkjs-polydata.py | 29 +- examples/vue3/cone-client.py | 28 +- examples/vue3/cone-local.py | 31 +- examples/vue3/cone-remote.py | 31 +- examples/vue3/cone-toggle.py | 33 +- examples/vue3/cone-webxr.py | 47 +- examples/vue3/vtkjs-mesh.py | 5 +- examples/vue3/vtkjs-pipeline.py | 4 +- examples/vue3/vtkjs-polydata.py | 29 +- examples/widgets/clip.py | 38 +- pyproject.toml | 82 +- src/trame/widgets/paraview.py | 2 +- src/trame/widgets/vtk.py | 2 +- src/trame_vtk/__init__.py | 4 +- src/trame_vtk/modules/common/__init__.py | 1 - .../modules/common/serve/trame-vtk.js | 4 +- src/trame_vtk/modules/paraview/LICENSE.md | 16 +- src/trame_vtk/modules/paraview/__init__.py | 23 +- .../modules/paraview/protocols/__init__.py | 1 - .../paraview/protocols/local_rendering.py | 20 +- .../paraview/protocols/mouse_handler.py | 5 +- .../protocols/publish_image_delivery.py | 52 +- .../modules/paraview/protocols/view_port.py | 8 +- .../paraview/protocols/web_protocol.py | 16 +- src/trame_vtk/modules/vtk/LICENSE.md | 49 +- src/trame_vtk/modules/vtk/__init__.py | 21 +- .../modules/vtk/protocols/local_rendering.py | 20 +- .../modules/vtk/protocols/mouse_handler.py | 9 +- .../vtk/protocols/publish_image_delivery.py | 33 +- .../modules/vtk/protocols/view_port.py | 4 +- .../modules/vtk/protocols/web_protocol.py | 3 +- .../modules/vtk/serializers/__init__.py | 13 +- .../modules/vtk/serializers/actors.py | 24 +- src/trame_vtk/modules/vtk/serializers/data.py | 37 +- .../modules/vtk/serializers/export.py | 10 +- .../modules/vtk/serializers/helpers.py | 9 +- .../modules/vtk/serializers/initialize.py | 62 +- .../modules/vtk/serializers/lights.py | 6 +- .../modules/vtk/serializers/lookup_tables.py | 25 +- .../modules/vtk/serializers/mappers.py | 22 +- src/trame_vtk/modules/vtk/serializers/mesh.py | 50 +- .../modules/vtk/serializers/properties.py | 4 +- .../modules/vtk/serializers/render_windows.py | 6 +- .../modules/vtk/serializers/serialize.py | 9 +- .../serializers/synchronization_context.py | 15 +- .../modules/vtk/serializers/textures.py | 2 +- .../modules/vtk/serializers/utils.py | 16 +- .../modules/vtk/serializers/widgets.py | 3 +- src/trame_vtk/modules/vtk/widget.py | 38 +- src/trame_vtk/tools/static_viewer.html | 4526 ++++++++++++++++- src/trame_vtk/tools/vtksz2html.py | 13 +- src/trame_vtk/widgets/vtk/__init__.py | 16 +- src/trame_vtk/widgets/vtk/common.py | 115 +- tests/conftest.py | 3 +- tests/test_big_int.py | 5 +- tests/test_export.py | 3 +- tests/test_gc.py | 2 +- tests/test_import.py | 2 +- tests/test_remote_rendering.py | 5 +- tests/test_volume_rendering.py | 5 +- 116 files changed, 6161 insertions(+), 1426 deletions(-) create mode 100644 , mode change 100644 => 100755 examples/validation/VtkRayCast.py diff --git a/, b/, new file mode 100644 index 0000000..5142593 --- /dev/null +++ b/, @@ -0,0 +1,114 @@ +[project] +name = "trame-app" +version = "1.0.0" +description = "An example Trame application" +authors = [ + {name = "Trame Developer"}, +] +dependencies = [ + "trame_client>=3.10", +] +requires-python = ">=3.9" +readme = "README.rst" +license = {text = "BSD License"} +keywords = ["Python", "Interactive", "Web", "Application", "Framework"] +classifiers = [ + "Development Status :: 4 - Beta", + "Environment :: Web Environment", + "License :: OSI Approved :: BSD License", + "Natural Language :: English", + "Operating System :: OS Independent", + "Programming Language :: Python :: 3 :: Only", + "Topic :: Software Development :: Libraries :: Application Frameworks", + "Topic :: Software Development :: Libraries :: Python Modules", +] + +[project.optional-dependencies] +app = [ + "pywebview", +] +jupyter = [ + "jupyterlab", +] +dev = [ + "pre-commit", + "ruff", + "pytest >=6", + "pytest-cov >=3", + "nox", +] + +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + + +[tool.hatch.build] +include = [ + "/src/trame/**/*.py", + "/src/trame_app/**/*.py", + "/src/trame_app/**/*.js", + "/src/trame_app/**/*.css", +] + +[tool.hatch.build.targets.wheel] +packages = [ + "src/trame", + "src/trame_app", +] + +[tool.ruff] + +[tool.ruff.lint] +extend-select = [ + "ARG", # flake8-unused-arguments + "B", # flake8-bugbear + "C4", # flake8-comprehensions + "EM", # flake8-errmsg + "EXE", # flake8-executable + "G", # flake8-logging-format + "I", # isort + "ICN", # flake8-import-conventions + "NPY", # NumPy specific rules + "PD", # pandas-vet + "PGH", # pygrep-hooks + "PIE", # flake8-pie + "PL", # pylint + "PT", # flake8-pytest-style + "PTH", # flake8-use-pathlib + "RET", # flake8-return + "RUF", # Ruff-specific + "SIM", # flake8-simplify + "T20", # flake8-print + "UP", # pyupgrade + "YTT", # flake8-2020 +] +ignore = [ + "PLR09", # Too many <...> + "PLR2004", # Magic value used in comparison + "ISC001", # Conflicts with formatter +] +isort.required-imports = [] + +[tool.ruff.lint.per-file-ignores] +"tests/**" = ["T20"] +"noxfile.py" = ["T20"] +"src/**" = ["SIM117"] +[tool.semantic_release] +version_toml = [ + "pyproject.toml:project.version", +] +version_variables = [ + "src/trame_app/__init__.py:__version__", +] + +build_command = """ + python -m pip install -e '.[build]' + uv lock --upgrade-package "$PACKAGE_NAME" + git add uv.lock + uv build +""" + +[tool.semantic_release.publish] +dist_glob_patterns = ["dist/*"] +upload_to_vcs_release = true diff --git a/.externals.sha256 b/.externals.sha256 index a0ecdf5..1106637 100644 --- a/.externals.sha256 +++ b/.externals.sha256 @@ -1,2 +1,2 @@ -d6e1d6ca32dd252f4c46d1b5c7ab1225f66990da50215b9de91912bbf7aa97ed ./src/trame_vtk/tools/static_viewer.html -948b0cca167bc2e2315a4d1ef18eb23cbe5979c806fbb7f0b157ed7c0e5ed280 ./src/trame_vtk/modules/common/serve/trame-vtk.js +d40400185f1e260ceb298f7218c010be3c6bf86214c0692944ff37a81e5de51f ./src/trame_vtk/tools/static_viewer.html +6d3e20a67b32c8a10443b2df7a1e7b32a459b944cf6f630695e260b5406b4b57 ./src/trame_vtk/modules/common/serve/trame-vtk.js diff --git a/.flake8 b/.flake8 index 3c13221..9420840 100644 --- a/.flake8 +++ b/.flake8 @@ -7,7 +7,7 @@ ignore = per-file-ignores = # These directories will always contain "from ... import *" trame/*:F401,F403 - examples/*:F401,F403 + examples/*:F401,F403,T20 # Will also contain `print` # Black sometimes conflicts with flake8 here # Ignore white space after binary operator and assigning lambda expressions diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b6d8bc..e61681e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,7 +18,6 @@ fix #111 - **static_viewer**: Include in repo to skip auto fetch on vtk.js ([`9302c6b`](https://github.com/Kitware/trame-vtk/commit/9302c6b0309e3961323aea882621ac8922d59524)) - ## v2.11.6 (2026-03-25) ### Bug Fixes @@ -26,7 +25,6 @@ fix #111 - **array**: Skip hash and eq usage on array ([`12e2d35`](https://github.com/Kitware/trame-vtk/commit/12e2d35b5d06c949994a2224fae897b6cb9c3930)) - ## v2.11.5 (2026-03-25) ### Bug Fixes @@ -34,7 +32,6 @@ fix #111 - **static_viewer**: Update static viewer from vtk.js ([`3bb5f16`](https://github.com/Kitware/trame-vtk/commit/3bb5f16b1f7aa658dc14f6f945fafc3acf5faaf3)) - ## v2.11.4 (2026-03-25) ### Bug Fixes @@ -42,7 +39,6 @@ fix #111 - **array**: Don't rely on hashable arrays ([`e740a95`](https://github.com/Kitware/trame-vtk/commit/e740a9552a4ba285d285b88c63f9571474c82988)) - ## v2.11.3 (2026-03-15) ### Bug Fixes @@ -50,7 +46,6 @@ fix #111 - **tool**: Vtksz2html use new dom container ([`4b7fe32`](https://github.com/Kitware/trame-vtk/commit/4b7fe32052189489f73c95b9c854bf0b72107c79)) - ## v2.11.2 (2026-03-15) ### Bug Fixes @@ -58,7 +53,6 @@ fix #111 - **static_viewer**: Fetch latest static viewer ([`d4d8d18`](https://github.com/Kitware/trame-vtk/commit/d4d8d18e6905bac55b924c0c3af761e5a47f3be5)) - ## v2.11.1 (2026-02-05) ### Bug Fixes @@ -68,7 +62,6 @@ fix #111 Update how camera is get in vtkLocalView with a ParaView RenderView - ## v2.11.0 (2026-02-04) ### Continuous Integration @@ -81,7 +74,6 @@ Update how camera is get in vtkLocalView with a ParaView RenderView - Add served directory versioning ([`c9463ef`](https://github.com/Kitware/trame-vtk/commit/c9463ef898671b1d9e714fd8c288c872e9373403)) - ## v2.10.3 (2026-01-28) ### Bug Fixes @@ -89,9 +81,8 @@ Update how camera is get in vtkLocalView with a ParaView RenderView - **actor**: Prevent serialization of actors without a mapper ([`b116bc9`](https://github.com/Kitware/trame-vtk/commit/b116bc9d56824ffcd21722ffbd312b90be632a1b)) -Fix bug where oglmapper wass undefined in traverseOpaquePass for an actor whose visibility got - toggled twice - +Fix bug where oglmapper wass undefined in traverseOpaquePass for an actor whose +visibility got toggled twice ## v2.10.2 (2026-01-08) @@ -105,7 +96,6 @@ Fix bug where oglmapper wass undefined in traverseOpaquePass for an actor whose - Update baseline for test_rendering_lut and test_big_int ([`b73e575`](https://github.com/Kitware/trame-vtk/commit/b73e57591f8f97ddf260aebfec9f64059d1898bc)) - ## v2.10.1 (2025-12-15) ### Bug Fixes @@ -113,7 +103,6 @@ Fix bug where oglmapper wass undefined in traverseOpaquePass for an actor whose - **camera**: Update vue-vtk-js ([`582cb80`](https://github.com/Kitware/trame-vtk/commit/582cb8048252668e2ac329cb26a20cdc1acf23d9)) - ## v2.10.0 (2025-10-02) ### Bug Fixes @@ -140,7 +129,6 @@ Signed-off-by: Patrick Avery - Add WebXR Helper widget ([`beded63`](https://github.com/Kitware/trame-vtk/commit/beded63f1b6268cc30120646b83770a679a57d0a)) - ## v2.9.1 (2025-07-21) ### Bug Fixes @@ -148,7 +136,6 @@ Signed-off-by: Patrick Avery - **vtk-module**: Fix import for custom vtk module ([`090b504`](https://github.com/Kitware/trame-vtk/commit/090b504e8fd28cbce3705628f72cf2fd6ff12e56)) - ## v2.9.0 (2025-06-23) ### Continuous Integration @@ -161,7 +148,6 @@ Signed-off-by: Patrick Avery - **vtk**: Enable custom VTK build ([`448530a`](https://github.com/Kitware/trame-vtk/commit/448530a6456bdfebedd0b356ea5632a345dbc301)) - ## v2.8.17 (2025-06-03) ### Bug Fixes @@ -169,7 +155,6 @@ Signed-off-by: Patrick Avery - Properly bundle static_viewer.html ([`89df689`](https://github.com/Kitware/trame-vtk/commit/89df689f124f7b08835efdfed4216c347d84c391)) - ## v2.8.16 (2025-06-02) ### Bug Fixes @@ -193,7 +178,6 @@ Signed-off-by: Patrick Avery - Update links in readme ([`f73f046`](https://github.com/Kitware/trame-vtk/commit/f73f0465a9fd9989c07244ae666429e68b97cd53)) - ## v2.8.15 (2025-02-09) ### Bug Fixes @@ -228,7 +212,6 @@ Signed-off-by: Patrick Avery - Cover several vtk version ([`274da78`](https://github.com/Kitware/trame-vtk/commit/274da788bcfa15abf4f453158e14ad5210895e2f)) - ## v2.8.14 (2025-01-08) ### Bug Fixes @@ -244,7 +227,6 @@ Signed-off-by: Patrick Avery - **pre-commit**: Fix codespell ([`df46242`](https://github.com/Kitware/trame-vtk/commit/df46242bc34c9e89b9ed42445f77ddd16bb15720)) - ## v2.8.13 (2025-01-07) ### Bug Fixes @@ -257,7 +239,6 @@ Signed-off-by: Patrick Avery - Update README.rst ([`38ad9b2`](https://github.com/Kitware/trame-vtk/commit/38ad9b220a4674f5d820e0252302fc1688c80731)) - ## v2.8.12 (2024-11-08) ### Performance Improvements @@ -265,7 +246,6 @@ Signed-off-by: Patrick Avery - **vtk**: Do not always force image push ([`d2b075f`](https://github.com/Kitware/trame-vtk/commit/d2b075fa00958d2e8ebcad052db89a7a41d3ce4f)) - ## v2.8.11 (2024-10-17) ### Bug Fixes @@ -273,7 +253,6 @@ Signed-off-by: Patrick Avery - **animation**: Enable animation on remote view ([`660a1d4`](https://github.com/Kitware/trame-vtk/commit/660a1d4a755d43684a82f24efbfdb7bd445651cd)) - ## v2.8.10 (2024-08-07) ### Bug Fixes @@ -281,7 +260,6 @@ Signed-off-by: Patrick Avery - **wheel**: Apply modifiers [alt,shift,ctrl] on wheel event ([`42f2283`](https://github.com/Kitware/trame-vtk/commit/42f22838fe409d8b15ed158240ece25a46d0b7dc)) - ## v2.8.9 (2024-06-07) ### Bug Fixes @@ -289,7 +267,6 @@ Signed-off-by: Patrick Avery - **VtkView**: Add set_camera method ([`bc7e883`](https://github.com/Kitware/trame-vtk/commit/bc7e8833bbdc6b58d316c99586c04407be5a41d5)) - ## v2.8.8 (2024-05-06) ### Bug Fixes @@ -297,22 +274,23 @@ Signed-off-by: Patrick Avery - **js**: Track hash of vue-vtk-js as well ([`c82ffec`](https://github.com/Kitware/trame-vtk/commit/c82ffeca9d6d3bddbd65d630f3c6fc9864352eae)) -Similar to offline_viewer.html we track and report mismatched hash of all external dependencies. see - also https://github.com/Kitware/trame-vtk/pull/70 +Similar to offline_viewer.html we track and report mismatched hash of all +external dependencies. see also https://github.com/Kitware/trame-vtk/pull/70 ### Chores - **js**: Allow triggering release on external artifact static_viewer.html ([`eb8461a`](https://github.com/Kitware/trame-vtk/commit/eb8461af4229588b71a8bd8f34bb72be162d877f)) -Previously, when a new version of static_viewer.html is released on the master of vtk-js we couldn't - trigger a release because we do not commit this file but rather grab it during release. This - commit adds the hash of the latest version in a file and a hash check that runs during release but - does not trigger a failure on a mismatch but rather a warning. So now if static_viewer.html is - updated on vtk-js: - If we do not care `.fetch_externals.sh` will just emit a warning - If we - **do** care we update .static_viewer.sha256 and trigger a new release on trame-vtk even if no - other `trame-vtk` change happened during last release. - +Previously, when a new version of static_viewer.html is released on the master +of vtk-js we couldn't trigger a release because we do not commit this file but +rather grab it during release. This commit adds the hash of the latest version +in a file and a hash check that runs during release but does not trigger a +failure on a mismatch but rather a warning. So now if static_viewer.html is +updated on vtk-js: - If we do not care `.fetch_externals.sh` will just emit a +warning - If we **do** care we update .static_viewer.sha256 and trigger a new +release on trame-vtk even if no other `trame-vtk` change happened during last +release. ## v2.8.7 (2024-05-02) @@ -321,9 +299,9 @@ Previously, when a new version of static_viewer.html is released on the master o - **remote rendering**: Round view size half up ([`e6777b9`](https://github.com/Kitware/trame-vtk/commit/e6777b9161d381c01e9ec04f592093c9225f1adf)) -comply with vue-vtk-js vtkRemoteView implementation which uses Math.round for setting view size. - python builtin round function does not work the same way: it rounds half to even. - +comply with vue-vtk-js vtkRemoteView implementation which uses Math.round for +setting view size. python builtin round function does not work the same way: it +rounds half to even. ## v2.8.6 (2024-04-22) @@ -337,7 +315,6 @@ comply with vue-vtk-js vtkRemoteView implementation which uses Math.round for se - **readme**: Fix the link of tutorial url ([`0a46f97`](https://github.com/Kitware/trame-vtk/commit/0a46f97f951f0709a1547a7f4e169cf16c33324a)) - ## v2.8.5 (2024-02-15) ### Bug Fixes @@ -347,7 +324,6 @@ comply with vue-vtk-js vtkRemoteView implementation which uses Math.round for se * Fix breaks compatability with Python 3.8 - ## v2.8.4 (2024-02-14) ### Bug Fixes @@ -355,7 +331,6 @@ comply with vue-vtk-js vtkRemoteView implementation which uses Math.round for se - **serializer**: Md5 hashing is not allowed for FIPS ([`6e163d6`](https://github.com/Kitware/trame-vtk/commit/6e163d62199092d2e3dc2311e2b75f2572854790)) - ## v2.8.3 (2024-02-13) ### Bug Fixes @@ -363,7 +338,6 @@ comply with vue-vtk-js vtkRemoteView implementation which uses Math.round for se - **serializer**: Add encoding option ([`9c20a89`](https://github.com/Kitware/trame-vtk/commit/9c20a89297c356e8dd421ed5d47fb3ed03c660c7)) - ## v2.8.2 (2024-02-09) ### Bug Fixes @@ -371,7 +345,6 @@ comply with vue-vtk-js vtkRemoteView implementation which uses Math.round for se - **js**: Replace invalid downloaded js content ([`d45ca89`](https://github.com/Kitware/trame-vtk/commit/d45ca89ede99b50090c5dc70b6470abce26c126f)) - ## v2.8.1 (2024-02-09) ### Bug Fixes @@ -384,7 +357,6 @@ comply with vue-vtk-js vtkRemoteView implementation which uses Math.round for se - **picking**: Finish remote example ([`1ebeadb`](https://github.com/Kitware/trame-vtk/commit/1ebeadbaaf0044f637f1aa969074c4a3f49570e0)) - ## v2.8.0 (2024-01-30) ### Bug Fixes @@ -397,7 +369,6 @@ comply with vue-vtk-js vtkRemoteView implementation which uses Math.round for se - **picking**: Add support for picking modes ([`edab22d`](https://github.com/Kitware/trame-vtk/commit/edab22dfd6327be3d721efdfcb58a44de714c6c0)) - ## v2.7.1 (2024-01-26) ### Bug Fixes @@ -405,7 +376,6 @@ comply with vue-vtk-js vtkRemoteView implementation which uses Math.round for se - **local**: Add prop3d.orientation for local rendering ([`812c6d1`](https://github.com/Kitware/trame-vtk/commit/812c6d18a582b504f59c7e4dc1e60e2e4fb99b7f)) - ## v2.7.0 (2024-01-12) ### Continuous Integration @@ -423,7 +393,6 @@ comply with vue-vtk-js vtkRemoteView implementation which uses Math.round for se - **multi-server**: Add support for multi-server ([`5a775ea`](https://github.com/Kitware/trame-vtk/commit/5a775ea8d0f3816f733ce9e9d68e0c798976bc64)) - ## v2.6.3 (2023-12-13) ### Bug Fixes @@ -431,7 +400,6 @@ comply with vue-vtk-js vtkRemoteView implementation which uses Math.round for se - **BigInt**: Convert points with (Big)Int to Float for LocalView ([`80496d5`](https://github.com/Kitware/trame-vtk/commit/80496d5ef38269a76e5f4a51c80e3340ad83d1d7)) - ## v2.6.2 (2023-11-16) ### Bug Fixes @@ -439,7 +407,6 @@ comply with vue-vtk-js vtkRemoteView implementation which uses Math.round for se - **ref**: Automatically assign non conflicting ref ([`3cfdf2a`](https://github.com/Kitware/trame-vtk/commit/3cfdf2ada97b1ccae04211e25e92744835621c2f)) - ## v2.6.1 (2023-11-13) ### Bug Fixes @@ -447,7 +414,6 @@ comply with vue-vtk-js vtkRemoteView implementation which uses Math.round for se - **protocol**: Allow several servers within 1 process ([`0c53288`](https://github.com/Kitware/trame-vtk/commit/0c53288add82f5aeea55d3b0190150580311a03b)) - ## v2.6.0 (2023-11-08) ### Bug Fixes @@ -468,7 +434,6 @@ comply with vue-vtk-js vtkRemoteView implementation which uses Math.round for se - Pass `user_matrix` in `add_on` dictionary as payload to ([`ec6cfba`](https://github.com/Kitware/trame-vtk/commit/ec6cfbaaec1940dfc57fb990306f63cd1f56af0b)) - ## v2.5.10 (2023-11-07) ### Bug Fixes @@ -476,7 +441,6 @@ comply with vue-vtk-js vtkRemoteView implementation which uses Math.round for se - **vtk.js**: Bump vtk.js to 29.1.1 ([`bd93a63`](https://github.com/Kitware/trame-vtk/commit/bd93a63907d2ff86fc67c247e751367f6e4753a0)) - ## v2.5.9 (2023-10-06) ### Bug Fixes @@ -500,7 +464,6 @@ comply with vue-vtk-js vtkRemoteView implementation which uses Math.round for se - **pyvista**: Add wip examples ([`487c4c0`](https://github.com/Kitware/trame-vtk/commit/487c4c03054c5a6dad3a671760d53a2375d3119f)) - ## v2.5.8 (2023-07-20) ### Bug Fixes @@ -513,7 +476,6 @@ comply with vue-vtk-js vtkRemoteView implementation which uses Math.round for se - Add trame-vuetify as dep ([`c7259c0`](https://github.com/Kitware/trame-vtk/commit/c7259c05e502193f88fb19640b0388a465598380)) - ## v2.5.7 (2023-07-20) ### Bug Fixes @@ -534,7 +496,6 @@ comply with vue-vtk-js vtkRemoteView implementation which uses Math.round for se - Ignore changelog for spelling ([`aafb2a4`](https://github.com/Kitware/trame-vtk/commit/aafb2a4681eff562324f724e2cbf5a49efab31b6)) - ## v2.5.6 (2023-07-19) ### Bug Fixes @@ -560,7 +521,6 @@ fix #46 fix #44 fix #45 - ## v2.5.5 (2023-07-19) ### Bug Fixes @@ -569,8 +529,8 @@ fix #45 ([`74ed533`](https://github.com/Kitware/trame-vtk/commit/74ed533a2a29930b2f33d0dd2fb77c30987a51e2)) Not using a RenderView as view for the vtkLocalRemoteView will crash, because - "EnableRenderOnInteraction" might not be defined. "GetPropertyValue" will return None for a - non-existing Property +"EnableRenderOnInteraction" might not be defined. "GetPropertyValue" will return +None for a non-existing Property ### Chores @@ -585,7 +545,6 @@ Not using a RenderView as view for the vtkLocalRemoteView will crash, because - Upate baselines ([`082de9c`](https://github.com/Kitware/trame-vtk/commit/082de9c79f8a7b653bb5c71482e2bea97b050a49)) - ## v2.5.4 (2023-06-29) ### Bug Fixes @@ -604,15 +563,14 @@ Not using a RenderView as view for the vtkLocalRemoteView will crash, because - Use better stage name ([`0bf3f73`](https://github.com/Kitware/trame-vtk/commit/0bf3f73b2257f2e49552d69ed2c5ad8f909e6487)) - ## v2.5.3 (2023-06-28) ### Bug Fixes -- **html**: Improve HTML exporting ([#42](https://github.com/Kitware/trame-vtk/pull/42), +- **html**: Improve HTML exporting + ([#42](https://github.com/Kitware/trame-vtk/pull/42), [`3a0184e`](https://github.com/Kitware/trame-vtk/commit/3a0184e86842f275d920827c3e1a5bb62f627655)) - ## v2.5.2 (2023-06-26) ### Bug Fixes @@ -631,7 +589,6 @@ Not using a RenderView as view for the vtkLocalRemoteView will crash, because - **testing**: Update baselines ([`0d6e494`](https://github.com/Kitware/trame-vtk/commit/0d6e4945f80ee56b7ecc8181d4341331989b7d0e)) - ## v2.5.1 (2023-06-23) ### Bug Fixes @@ -647,7 +604,6 @@ Not using a RenderView as view for the vtkLocalRemoteView will crash, because - Split steps ([`b1fdde6`](https://github.com/Kitware/trame-vtk/commit/b1fdde61d96681a9f052d4c75628367f1fe4069c)) - ## v2.5.0 (2023-06-16) ### Bug Fixes @@ -685,7 +641,6 @@ Not using a RenderView as view for the vtkLocalRemoteView will crash, because - **local**: Enable prop caching ([`be29552`](https://github.com/Kitware/trame-vtk/commit/be29552102b0394ae3e45bcc96a0c6b4f2af73dc)) - ## v2.4.4 (2023-04-16) ### Bug Fixes @@ -701,7 +656,6 @@ Not using a RenderView as view for the vtkLocalRemoteView will crash, because - **pv**: Add paraview validation example ([`9146694`](https://github.com/Kitware/trame-vtk/commit/914669478cb2ba088131d8da81ddc287003afb23)) - ## v2.4.3 (2023-04-07) ### Bug Fixes @@ -709,7 +663,6 @@ Not using a RenderView as view for the vtkLocalRemoteView will crash, because - **export**: Add export for VtkLocalView ([`b58ccf4`](https://github.com/Kitware/trame-vtk/commit/b58ccf4109b25f567cac0f8f1185ab71e00c14dc)) - ## v2.4.2 (2023-03-31) ### Bug Fixes @@ -745,7 +698,6 @@ Signed-off-by: Patrick Avery - **examples**: Update the widget ones ([`cdda471`](https://github.com/Kitware/trame-vtk/commit/cdda471df5c2364e7359c2d6533ffcd4e4b38cf0)) - ## v2.4.1 (2023-03-27) ### Bug Fixes @@ -753,7 +705,6 @@ Signed-off-by: Patrick Avery - **paraview**: Fix protocol ([`b72425c`](https://github.com/Kitware/trame-vtk/commit/b72425cdde30344b15cebf8dd1b11aa62701176f)) - ## v2.4.0 (2023-03-24) ### Bug Fixes @@ -769,8 +720,8 @@ Signed-off-by: Patrick Avery ([`3c1614c`](https://github.com/Kitware/trame-vtk/commit/3c1614c82f47528e71de69916baa22961177c3d9)) Now, only critical messages from serializers are printed by default, unless the - `TRAME_SERIALIZE_DEBUG` environment variable is set, in which case all logger output will be - printed from the serializers. +`TRAME_SERIALIZE_DEBUG` environment variable is set, in which case all logger +output will be printed from the serializers. Signed-off-by: Patrick Avery @@ -782,14 +733,15 @@ Signed-off-by: Patrick Avery - **mouse_handler**: Apply a couple of fixes to mouse wheel event ([`45505ef`](https://github.com/Kitware/trame-vtk/commit/45505ef25bb76a4d04bddd9cecdc375999de9e1b)) -First of all, this updates the interactor with the mouse position on a wheel event so that if there - are multiple renderers, the interactor can figure out which one needs to be updated. +First of all, this updates the interactor with the mouse position on a wheel +event so that if there are multiple renderers, the interactor can figure out +which one needs to be updated. -Second, this forwards the event to the interactor, rather than applying a manual zoom to the camera - ourselves. This makes the behavior more consistent. +Second, this forwards the event to the interactor, rather than applying a manual +zoom to the camera ourselves. This makes the behavior more consistent. -Third, this skips the zoom for the start event, since there appears to always be a wheel event right - after it. +Third, this skips the zoom for the start event, since there appears to always be +a wheel event right after it. Fixes: pyvista/pyvista#4020 @@ -810,7 +762,8 @@ Signed-off-by: Patrick Avery - **vue-vtk-js**: Update vue-vtk-js to the newest version ([`eb7310d`](https://github.com/Kitware/trame-vtk/commit/eb7310dd9e763b069de438ad33db3173965c2e81)) -This includes mouse position information for moving the mouse wheel, which we need. +This includes mouse position information for moving the mouse wheel, which we +need. Signed-off-by: Patrick Avery @@ -845,8 +798,8 @@ Signed-off-by: Patrick Avery - **protocols**: Copy protocols from VTK exactly ([`9fe3c26`](https://github.com/Kitware/trame-vtk/commit/9fe3c261bc78a8814e1f4bab37ac6df3977144d8)) -This copies the protocols and render_window_serializer from VTK exactly as they are. Further commits - will modify the code. +This copies the protocols and render_window_serializer from VTK exactly as they +are. Further commits will modify the code. Signed-off-by: Patrick Avery @@ -855,14 +808,16 @@ Signed-off-by: Patrick Avery - **case**: Convert most variables from camelCase to snake_case ([`ba9beaf`](https://github.com/Kitware/trame-vtk/commit/ba9beaf5060ab2b992a85d7ae701f3f4853deba2)) -I went through the code and automatically converted most of the variables from camelCase to - snake_case using regex in vim. I skipped a couple of cases in particular: +I went through the code and automatically converted most of the variables from +camelCase to snake_case using regex in vim. I skipped a couple of cases in +particular: -1. Anything that started with `vtk` (this might be a VTK object) 2. Anything in quotes (since they - might be strings sent to VTK.js) +1. Anything that started with `vtk` (this might be a VTK object) 2. Anything in + quotes (since they might be strings sent to VTK.js) -There were, however, some things still that were modified that should not have been. I tried to - manually fix these, but I may have not caught everything, so we should do testing to verify. +There were, however, some things still that were modified that should not have +been. I tried to manually fix these, but I may have not caught everything, so we +should do testing to verify. Signed-off-by: Patrick Avery @@ -925,15 +880,17 @@ Signed-off-by: Patrick Avery - **serializers**: Apply patches from addon_serializer ([`a93a540`](https://github.com/Kitware/trame-vtk/commit/a93a5400f542c529024e18941f9323c7623cea12)) -This takes the patches being applied in addon_serializer.py and puts them directly in the render - window serializer. We should verify that there are no issues. But I did notice some discrepancies: +This takes the patches being applied in addon_serializer.py and puts them +directly in the render window serializer. We should verify that there are no +issues. But I did notice some discrepancies: -1. I saw no difference in `extractRequiredFields()` 2. The addon serializer did not call - `registerInstanceSerializer()` on `vtkStructuredPoints` with the modified `imagedataSerializer` - (only difference is that extent is used instead of dimensions). 3. The addon serializer did not - call `registerInstanceSerializer()` on `vtkColorTransferFunction` with the modified - `colorTransferFunctionSerializer`. 4. `genericMapperSerializer()` only had debug message - modifications +1. I saw no difference in `extractRequiredFields()` 2. The addon serializer did + not call `registerInstanceSerializer()` on `vtkStructuredPoints` with the + modified `imagedataSerializer` (only difference is that extent is used + instead of dimensions). 3. The addon serializer did not call + `registerInstanceSerializer()` on `vtkColorTransferFunction` with the + modified `colorTransferFunctionSerializer`. 4. `genericMapperSerializer()` + only had debug message modifications Signed-off-by: Patrick Avery @@ -970,7 +927,6 @@ The functions being used were copied over. Signed-off-by: Patrick Avery - ## v2.3.5 (2023-03-21) ### Bug Fixes @@ -978,7 +934,6 @@ Signed-off-by: Patrick Avery - Axes serializer ([`cc2136d`](https://github.com/Kitware/trame-vtk/commit/cc2136df0d4ff850f25f791ffc76f3ae2ba10a92)) - ## v2.3.4 (2023-03-10) ### Bug Fixes @@ -986,7 +941,6 @@ Signed-off-by: Patrick Avery - **RemoteView**: Support no size at startup ([`29c5587`](https://github.com/Kitware/trame-vtk/commit/29c5587f0ca72c78972d6304a48d469231d523e6)) - ## v2.3.3 (2023-03-10) ### Bug Fixes @@ -996,7 +950,6 @@ Signed-off-by: Patrick Avery fix #25 - ## v2.3.2 (2023-03-09) ### Bug Fixes @@ -1004,7 +957,6 @@ fix #25 - **serializer**: Add support for LUT components ([`3ace3f5`](https://github.com/Kitware/trame-vtk/commit/3ace3f5ffa6e0af6d9db029e0a5ca6fb3f4a7174)) - ## v2.3.1 (2023-03-09) ### Bug Fixes @@ -1014,7 +966,6 @@ fix #25 fix #16 - ## v2.3.0 (2023-03-09) ### Bug Fixes @@ -1035,7 +986,6 @@ fix #16 - **screenshot**: Allow screenshot extract ([`8db1f08`](https://github.com/Kitware/trame-vtk/commit/8db1f0845206fc65ec02f7169aa40ab63bb4d792)) - ## v2.2.3 (2023-03-03) ### Bug Fixes @@ -1051,7 +1001,6 @@ fix #16 - **widget**: Simple plane/clip ([`1365d51`](https://github.com/Kitware/trame-vtk/commit/1365d510ebffe0589e3579cbe6b25e8b349626cc)) - ## v2.2.2 (2023-02-28) ### Bug Fixes @@ -1059,7 +1008,6 @@ fix #16 - **widget**: Add a class to wrap vtkAbstractWidgets and make them easier to use ([`29e39d4`](https://github.com/Kitware/trame-vtk/commit/29e39d42b7115c6c1df82f7be38c7ecc456aedf5)) - ## v2.2.1 (2023-02-26) ### Bug Fixes @@ -1072,7 +1020,6 @@ fix #16 - **example**: Update latest vue3 syntax ([`5b64088`](https://github.com/Kitware/trame-vtk/commit/5b64088d05ad5b596758324204092404b8a33f00)) - ## v2.2.0 (2023-02-25) ### Bug Fixes @@ -1095,7 +1042,6 @@ fix #16 - **LocalRemote**: Allow full camera sync with helper method ([`a750af2`](https://github.com/Kitware/trame-vtk/commit/a750af248c5d7025491bca1a8ff6cd0a9bab441b)) - ## v2.1.0 (2023-02-23) ### Bug Fixes @@ -1108,12 +1054,11 @@ fix #16 - **vue23**: Update client code to work with vue2/3 ([`7a8f546`](https://github.com/Kitware/trame-vtk/commit/7a8f546de013f61f7973118b992fec5889c35690)) - ## v2.0.18 (2023-02-23) ### Bug Fixes -- **version**: Add __version__ +- **version**: Add **version** ([`c9ab451`](https://github.com/Kitware/trame-vtk/commit/c9ab451d9e397f2a9c64b488d957915086a81ddc)) Signed-off-by: Patrick Avery @@ -1127,7 +1072,6 @@ There is an issue in the CI that might be resolved if we switch back to master. Signed-off-by: Patrick Avery - ## v2.0.17 (2023-02-01) ### Bug Fixes @@ -1135,11 +1079,12 @@ Signed-off-by: Patrick Avery - **BigInt**: Add support for LocalView ([`aa34620`](https://github.com/Kitware/trame-vtk/commit/aa34620642c64ceb5fd625c83b22fc7f50e823ff)) -* fix: support BigInt64Array and BigUint64Array * Update trame_vtk/modules/vtk/addon_serializer.py * - Add PyVista Int64 validation example * docs(example): Improve int64 validation example * - fix(BigInt): Update vue-vtk-js +* fix: support BigInt64Array and BigUint64Array _ Update + trame_vtk/modules/vtk/addon_serializer.py _ Add PyVista Int64 validation + example _ docs(example): Improve int64 validation example _ fix(BigInt): + Update vue-vtk-js ---------- +--- Co-authored-by: Bane Sullivan @@ -1148,7 +1093,6 @@ Co-authored-by: Bane Sullivan - **semantic-release**: Fix version to 7.32.2 ([`bfa7c41`](https://github.com/Kitware/trame-vtk/commit/bfa7c41d908ebc2c2acbfee4835eccadfc5fb40b)) - ## v2.0.16 (2023-01-27) ### Bug Fixes @@ -1156,9 +1100,8 @@ Co-authored-by: Bane Sullivan - Imagedata extent and vtkSmartVolumeMapper ([`fc096c0`](https://github.com/Kitware/trame-vtk/commit/fc096c0e0190bfef2127aef2f46e3aa9ccdd8893)) -* fix: extent with ImageData serializer * Remove dimensions * fix: support vtkSmartVolumeMapper * - Linting - +* fix: extent with ImageData serializer _ Remove dimensions _ fix: support + vtkSmartVolumeMapper \* Linting ## v2.0.15 (2023-01-20) @@ -1170,7 +1113,6 @@ Co-authored-by: Bane Sullivan - **vtk**: Handle CubeAxes grid color + light + disable_auto_switch ([`d89c04e`](https://github.com/Kitware/trame-vtk/commit/d89c04e265a28234cd3467866c016247fc5d6e36)) - ## v2.0.14 (2023-01-10) ### Bug Fixes @@ -1178,7 +1120,6 @@ Co-authored-by: Bane Sullivan - Convert RGB colors to hex ([`0be279e`](https://github.com/Kitware/trame-vtk/commit/0be279e6190bcc7c54b9fc725da6df014376656a)) - ## v2.0.13 (2023-01-10) ### Bug Fixes @@ -1191,7 +1132,6 @@ Co-authored-by: Bane Sullivan fix #9 - ## v2.0.12 (2022-12-16) ### Bug Fixes @@ -1202,7 +1142,6 @@ fix #9 - **RemoteView**: Expose still_ratio/quality properties ([`7278d5e`](https://github.com/Kitware/trame-vtk/commit/7278d5ed7b8872167a9e9c653792b1b8543ac5ab)) - ## v2.0.11 (2022-12-09) ### Bug Fixes @@ -1210,7 +1149,6 @@ fix #9 - **vue-vtk-js**: Update to 2.1.2 ([`3cf8913`](https://github.com/Kitware/trame-vtk/commit/3cf8913158e36496e564c4a544f07a2f2cf6c630)) - ## v2.0.10 (2022-12-04) ### Bug Fixes @@ -1226,7 +1164,6 @@ fix #9 - **examples**: Add validation examples ([`209914a`](https://github.com/Kitware/trame-vtk/commit/209914ab142fe6bf2f7459a83c4f533d32157212)) - ## v2.0.9 (2022-11-05) ### Bug Fixes @@ -1234,7 +1171,6 @@ fix #9 - **LocalView**: Properly handle add/remove actor ([`85ee285`](https://github.com/Kitware/trame-vtk/commit/85ee285f67cf08438d37bae0bfd8d84ffe34db35)) - ## v2.0.8 (2022-10-20) ### Bug Fixes @@ -1245,7 +1181,6 @@ fix #9 - Improve VTK mapper and scalar bar serializers ([`fb94e81`](https://github.com/Kitware/trame-vtk/commit/fb94e81ef86c152f207e4fd442747c0d318a8dde)) - ## v2.0.7 (2022-10-05) ### Bug Fixes @@ -1253,7 +1188,6 @@ fix #9 - **VtkLocalView**: Automatically register update on_server_ready ([`5b5d296`](https://github.com/Kitware/trame-vtk/commit/5b5d296cc67518801c5ebff9397d55f99461c822)) - ## v2.0.6 (2022-09-01) ### Bug Fixes @@ -1295,7 +1229,6 @@ Signed-off-by: Patrick Avery Signed-off-by: Patrick Avery - ## v2.0.5 (2022-06-01) ### Bug Fixes @@ -1303,7 +1236,6 @@ Signed-off-by: Patrick Avery - **paraview**: Replace invalid import path ([`bd33f2a`](https://github.com/Kitware/trame-vtk/commit/bd33f2a2c71f80792a3039271d70b32f100aeed0)) - ## v2.0.4 (2022-05-31) ### Bug Fixes @@ -1311,7 +1243,6 @@ Signed-off-by: Patrick Avery - **widgets**: Expose more props ([`2fa0156`](https://github.com/Kitware/trame-vtk/commit/2fa01565461f62f96d3a18b2f649b5484981e5bf)) - ## v2.0.3 (2022-05-29) ### Bug Fixes @@ -1321,7 +1252,6 @@ Signed-off-by: Patrick Avery Signed-off-by: Patrick Avery - ## v2.0.2 (2022-05-27) ### Bug Fixes @@ -1329,12 +1259,12 @@ Signed-off-by: Patrick Avery - **paraview**: Remove unnecessary check for import ([`301b684`](https://github.com/Kitware/trame-vtk/commit/301b684378f30d46e93939da67ebd11f2027bf41)) -It is okay to check the servermanager import at the time of instantiating the Helper class, and we - do not need to check for the servermanager when the module is imported. +It is okay to check the servermanager import at the time of instantiating the +Helper class, and we do not need to check for the servermanager when the module +is imported. Signed-off-by: Patrick Avery - ## v2.0.1 (2022-05-27) ### Bug Fixes diff --git a/examples/pyvista/ambient.py b/examples/pyvista/ambient.py index cc0f90b..5ca550c 100644 --- a/examples/pyvista/ambient.py +++ b/examples/pyvista/ambient.py @@ -1,12 +1,12 @@ """Validate lighting and properties.""" +import pyvista as pv from trame.app import get_server from trame.ui.vuetify import SinglePageLayout + from trame.widgets import vuetify from trame.widgets.vtk import VtkLocalView, VtkRemoteView -import pyvista as pv - server = get_server() state, ctrl = server.state, server.controller @@ -30,7 +30,7 @@ @state.change("color") -def color(color="lightblue", **kwargs): +def color(color="lightblue", **_): actor.prop.color = color ctrl.view_update() @@ -56,36 +56,38 @@ def color(color="lightblue", **kwargs): style="max-width: 250px", ) - with layout.content: - with vuetify.VContainer( + with ( + layout.content, + vuetify.VContainer( fluid=True, classes="pa-0 fill-height", + ), + ): + with vuetify.VContainer( + fluid=True, classes="pa-0 fill-height", style="width: 50%;" ): - with vuetify.VContainer( - fluid=True, classes="pa-0 fill-height", style="width: 50%;" - ): - local = VtkLocalView( - plotter.ren_win, - ) - with vuetify.VContainer( - fluid=True, classes="pa-0 fill-height", style="width: 50%;" - ): - remote = VtkRemoteView( - plotter.ren_win, - ) - - def view_update(**kwargs): - local.update(**kwargs) - remote.update(**kwargs) - - def view_reset_camera(**kwargs): - local.reset_camera(**kwargs) - remote.reset_camera(**kwargs) - - ctrl.view_update = view_update - ctrl.view_reset_camera = view_reset_camera - - ctrl.on_server_ready.add(view_update) + local = VtkLocalView( + plotter.ren_win, + ) + with vuetify.VContainer( + fluid=True, classes="pa-0 fill-height", style="width: 50%;" + ): + remote = VtkRemoteView( + plotter.ren_win, + ) + + def view_update(**kwargs): + local.update(**kwargs) + remote.update(**kwargs) + + def view_reset_camera(**kwargs): + local.reset_camera(**kwargs) + remote.reset_camera(**kwargs) + + ctrl.view_update = view_update + ctrl.view_reset_camera = view_reset_camera + + ctrl.on_server_ready.add(view_update) # hide footer layout.footer.hide() diff --git a/examples/pyvista/export_scene.py b/examples/pyvista/export_scene.py index d4d466d..2faaa65 100644 --- a/examples/pyvista/export_scene.py +++ b/examples/pyvista/export_scene.py @@ -2,13 +2,13 @@ https://kitware.github.io/vtk-js/examples/OfflineLocalView.html """ -from trame.app import get_server -from trame.ui.vuetify import SinglePageLayout -from trame.widgets import vuetify - import pyvista as pv from pyvista import examples from pyvista.trame import PyVistaLocalView +from trame.app import get_server +from trame.ui.vuetify import SinglePageLayout + +from trame.widgets import vuetify server = get_server() state, ctrl = server.state, server.controller @@ -39,16 +39,18 @@ def export_scene(): click="utils.download('scene-extract.vtksz', trigger('export'), 'application/octet-stream')", ) - with layout.content: - with vuetify.VContainer( + with ( + layout.content, + vuetify.VContainer( fluid=True, classes="pa-0 fill-height", - ): - with vuetify.VCol(classes="pa-0 ma-1 fill-height"): - view = PyVistaLocalView(plotter) - ctrl.view_export = view.export - ctrl.view_update = view.update - ctrl.view_reset_camera = view.reset_camera + ), + vuetify.VCol(classes="pa-0 ma-1 fill-height"), + ): + view = PyVistaLocalView(plotter) + ctrl.view_export = view.export + ctrl.view_update = view.update + ctrl.view_reset_camera = view.reset_camera if __name__ == "__main__": server.start() diff --git a/examples/pyvista/grid.py b/examples/pyvista/grid.py index 224b32a..1053020 100644 --- a/examples/pyvista/grid.py +++ b/examples/pyvista/grid.py @@ -1,5 +1,6 @@ from trame.app import get_server from trame.ui.vuetify import SinglePageLayout + from trame.widgets import grid server = get_server() @@ -12,18 +13,20 @@ with SinglePageLayout(server) as layout: layout.title.set_text("Grid layout") - with layout.content: - with grid.GridLayout( + with ( + layout.content, + grid.GridLayout( layout=("layout", LAYOUT), - ): - grid.GridItem( - "{{ item.i }}", - v_for="item in layout", - key="item.i", - v_bind="item", - classes="pa-4", - style="border: solid 1px #333; background: rgba(128, 128, 128, 0.5);", - ) + ), + ): + grid.GridItem( + "{{ item.i }}", + v_for="item in layout", + key="item.i", + v_bind="item", + classes="pa-4", + style="border: solid 1px #333; background: rgba(128, 128, 128, 0.5);", + ) if __name__ == "__main__": server.start() diff --git a/examples/pyvista/lighting.py b/examples/pyvista/lighting.py index c3ce727..cd1dc84 100644 --- a/examples/pyvista/lighting.py +++ b/examples/pyvista/lighting.py @@ -1,12 +1,12 @@ """Validate lighting.""" +import pyvista as pv from trame.app import get_server from trame.ui.vuetify import SinglePageLayout + from trame.widgets import vuetify from trame.widgets.vtk import VtkLocalView, VtkRemoteView -import pyvista as pv - server = get_server() state, ctrl = server.state, server.controller @@ -39,36 +39,38 @@ with layout.toolbar: vuetify.VSpacer() - with layout.content: - with vuetify.VContainer( + with ( + layout.content, + vuetify.VContainer( fluid=True, classes="pa-0 fill-height", + ), + ): + with vuetify.VContainer( + fluid=True, classes="pa-0 fill-height", style="width: 50%;" ): - with vuetify.VContainer( - fluid=True, classes="pa-0 fill-height", style="width: 50%;" - ): - local = VtkLocalView( - plotter.ren_win, - ) - with vuetify.VContainer( - fluid=True, classes="pa-0 fill-height", style="width: 50%;" - ): - remote = VtkRemoteView( - plotter.ren_win, - ) - - def view_update(**kwargs): - local.update(**kwargs) - remote.update(**kwargs) - - def view_reset_camera(**kwargs): - local.reset_camera(**kwargs) - remote.reset_camera(**kwargs) - - ctrl.view_update = view_update - ctrl.view_reset_camera = view_reset_camera - - ctrl.on_server_ready.add(view_update) + local = VtkLocalView( + plotter.ren_win, + ) + with vuetify.VContainer( + fluid=True, classes="pa-0 fill-height", style="width: 50%;" + ): + remote = VtkRemoteView( + plotter.ren_win, + ) + + def view_update(**kwargs): + local.update(**kwargs) + remote.update(**kwargs) + + def view_reset_camera(**kwargs): + local.reset_camera(**kwargs) + remote.reset_camera(**kwargs) + + ctrl.view_update = view_update + ctrl.view_reset_camera = view_reset_camera + + ctrl.on_server_ready.add(view_update) # hide footer layout.footer.hide() diff --git a/examples/pyvista/picking.py b/examples/pyvista/picking.py index bacee74..127391c 100644 --- a/examples/pyvista/picking.py +++ b/examples/pyvista/picking.py @@ -1,10 +1,10 @@ +import pyvista as pv from trame.app import get_server +from trame.assets.local import LocalFileManager from trame.ui.vuetify import SinglePageLayout + from trame.widgets import vuetify from trame.widgets.vtk import VtkRemoteView -from trame.assets.local import LocalFileManager - -import pyvista as pv server = get_server() state, ctrl = server.state, server.controller @@ -46,7 +46,7 @@ def on_box_selection(event): ... @state.change("selection_mode") -def on_mode_change(selection_mode, **kwargs): +def on_mode_change(selection_mode, **_): # Use box for selection state.box_selection = selection_mode in [ "select_surface_point", @@ -100,22 +100,24 @@ def on_mode_change(selection_mode, **kwargs): width=ICON_SIZE, ) - with layout.content: - with vuetify.VContainer( + with ( + layout.content, + vuetify.VContainer( fluid=True, classes="pa-0 fill-height", - ): - # with vuetify.VCol(classes="fill-height"): - # view = VtkLocalView(plotter.ren_win) - # ctrl.view_update = view.update - # ctrl.view_reset_camera = view.reset_camera - # with vuetify.VCol(classes="fill-height"): - VtkRemoteView( - plotter.ren_win, - enable_picking=("send_mouse", False), - box_selection=("box_selection", False), - box_selection_change=(ctrl.on_selection_change, "[$event]"), - ) + ), + ): + # with vuetify.VCol(classes="fill-height"): + # view = VtkLocalView(plotter.ren_win) + # ctrl.view_update = view.update + # ctrl.view_reset_camera = view.reset_camera + # with vuetify.VCol(classes="fill-height"): + VtkRemoteView( + plotter.ren_win, + enable_picking=("send_mouse", False), + box_selection=("box_selection", False), + box_selection_change=(ctrl.on_selection_change, "[$event]"), + ) # hide footer layout.footer.hide() diff --git a/examples/pyvista/pump_bracket.py b/examples/pyvista/pump_bracket.py index 4aa5b8c..5b3d341 100644 --- a/examples/pyvista/pump_bracket.py +++ b/examples/pyvista/pump_bracket.py @@ -2,13 +2,13 @@ import matplotlib.pyplot as plt import numpy as np -from trame.app import asynchronous, get_server -from trame.ui.vuetify import SinglePageLayout -from trame.widgets import vuetify - import pyvista as pv from pyvista import examples from pyvista.trame.ui import plotter_ui +from trame.app import asynchronous, get_server +from trame.ui.vuetify import SinglePageLayout + +from trame.widgets import vuetify pv.OFF_SCREEN = True @@ -45,13 +45,13 @@ @state.change("cmap") -def update_cmap(cmap="viridis", **kwargs): +def update_cmap(cmap="viridis", **_): actor.mapper.lookup_table.cmap = cmap ctrl.view_update() @state.change("phase_index") -def update_phase(phase_index=0, **kwargs): +def update_phase(phase_index=0, **_): phase = phases[phase_index] # feel free to change this to visualize different mode shapes mode_shape = "disp_6" @@ -62,7 +62,7 @@ def update_phase(phase_index=0, **kwargs): @state.change("play") @asynchronous.task -async def update_play(**kwargs): +async def update_play(**_): while state.play: with state: if state.phase_index >= len(phases): diff --git a/examples/pyvista/push_camera_many_actors.py b/examples/pyvista/push_camera_many_actors.py index 2004111..c2b6292 100644 --- a/examples/pyvista/push_camera_many_actors.py +++ b/examples/pyvista/push_camera_many_actors.py @@ -1,9 +1,9 @@ # for remote view +import vtkmodules.vtkRenderingOpenGL2 # noqa: F401 from trame.app import get_server from trame.ui.vuetify import SinglePageLayout -from trame.widgets import html, vtk as vtk_widgets, vuetify from vtkmodules.vtkFiltersSources import vtkConeSource -from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa +from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa: F401 from vtkmodules.vtkRenderingCore import ( vtkActor, vtkPolyDataMapper, @@ -11,7 +11,9 @@ vtkRenderWindow, vtkRenderWindowInteractor, ) -import vtkmodules.vtkRenderingOpenGL2 # noqa + +from trame.widgets import html, vuetify +from trame.widgets import vtk as vtk_widgets # ----------------------------------------------------------------------------- # Trame initialization @@ -82,32 +84,34 @@ def push_position(): vuetify.VBtn("Push camera", click=push_camera) vuetify.VBtn("Push position", click=push_position) - with layout.content: - with vuetify.VContainer( + with ( + layout.content, + vuetify.VContainer( fluid=True, classes="pa-0 fill-height", style="display: grid; grid-template-columns: 1fr 1fr; grid-template-rows: 1fr;", + ), + ): + with html.Div( + style="height: 100%;justify-self: stretch;", + ): + remote_view = vtk_widgets.VtkRemoteView( + renderWindow, + ref="view_remote", + ) + ctrl.view_update.add(remote_view.update) + ctrl.view_reset_camera.add(remote_view.reset_camera) + + with html.Div( + style="height: 100%;justify-self: stretch;", ): - with html.Div( - style="height: 100%;justify-self: stretch;", - ): - remote_view = vtk_widgets.VtkRemoteView( - renderWindow, - ref="view_remote", - ) - ctrl.view_update.add(remote_view.update) - ctrl.view_reset_camera.add(remote_view.reset_camera) - - with html.Div( - style="height: 100%;justify-self: stretch;", - ): - local_view = vtk_widgets.VtkLocalView( - renderWindow, - ref="view_local", - ) - ctrl.view_update.add(local_view.update) - ctrl.view_reset_camera.add(local_view.reset_camera) - ctrl.view_push_camera = local_view.push_camera + local_view = vtk_widgets.VtkLocalView( + renderWindow, + ref="view_local", + ) + ctrl.view_update.add(local_view.update) + ctrl.view_reset_camera.add(local_view.reset_camera) + ctrl.view_push_camera = local_view.push_camera # ----------------------------------------------------------------------------- diff --git a/examples/pyvista/ratios.py b/examples/pyvista/ratios.py index e227efe..a8fd1fe 100644 --- a/examples/pyvista/ratios.py +++ b/examples/pyvista/ratios.py @@ -1,10 +1,10 @@ +import pyvista as pv from trame.app import get_server from trame.ui.vuetify import SinglePageLayout + from trame.widgets import vuetify from trame.widgets.vtk import VtkRemoteView -import pyvista as pv - server = get_server() state, ctrl = server.state, server.controller @@ -32,14 +32,16 @@ with layout.toolbar: vuetify.VSpacer() - with layout.content: - with vuetify.VContainer( + with ( + layout.content, + vuetify.VContainer( fluid=True, classes="pa-0 fill-height", - ): - view = VtkRemoteView(plotter.ren_win, interactive_ratio=2, still_ratio=2) - ctrl.view_update = view.update - ctrl.view_reset_camera = view.reset_camera + ), + ): + view = VtkRemoteView(plotter.ren_win, interactive_ratio=2, still_ratio=2) + ctrl.view_update = view.update + ctrl.view_reset_camera = view.reset_camera # ----------------------------------------------------------------------------- # Main diff --git a/examples/pyvista/scalar_range.py b/examples/pyvista/scalar_range.py index 2e65ef5..f8d7037 100644 --- a/examples/pyvista/scalar_range.py +++ b/examples/pyvista/scalar_range.py @@ -1,10 +1,10 @@ import numpy as np +import pyvista as pv +from pyvista.trame.ui import plotter_ui from trame.app import get_server from trame.ui.vuetify import SinglePageLayout -from trame.widgets import vuetify -import pyvista as pv -from pyvista.trame.ui import plotter_ui +from trame.widgets import vuetify # ----------------------------------------------------------------------------- # Trame initialization @@ -847,7 +847,9 @@ @state.change("scalar_range") -def set_scalar_range(scalar_range=mesh.get_data_range("foo"), **kwargs): +def set_scalar_range(scalar_range=None, **_): + if scalar_range is None: + scalar_range = mesh.get_data_range("foo") actor.mapper.scalar_range = scalar_range ctrl.view_update() @@ -875,13 +877,15 @@ def set_scalar_range(scalar_range=mesh.get_data_range("foo"), **kwargs): style="max-width: 400px", ) - with layout.content: - with vuetify.VContainer( + with ( + layout.content, + vuetify.VContainer( fluid=True, classes="pa-0 fill-height", - ): - # Use PyVista UI template for Plotters - view = plotter_ui(pl, default_server_rendering=True) - ctrl.view_update = view.update + ), + ): + # Use PyVista UI template for Plotters + view = plotter_ui(pl, default_server_rendering=True) + ctrl.view_update = view.update server.start() diff --git a/examples/pyvista/silhouette.py b/examples/pyvista/silhouette.py index cfec3d5..b3e067a 100644 --- a/examples/pyvista/silhouette.py +++ b/examples/pyvista/silhouette.py @@ -1,11 +1,11 @@ +import vtkmodules.vtkRenderingOpenGL2 # noqa: F401 from trame.app import get_server from trame.ui.vuetify import SinglePageLayout -from trame.widgets import vtk as vtk_widgets, vuetify from vtkmodules.vtkFiltersHybrid import vtkPolyDataSilhouette from vtkmodules.vtkFiltersSources import vtkConeSource # VTK factory initialization -from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa +from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa: F401 from vtkmodules.vtkRenderingCore import ( vtkActor, vtkPolyDataMapper, @@ -13,7 +13,9 @@ vtkRenderWindow, vtkRenderWindowInteractor, ) -import vtkmodules.vtkRenderingOpenGL2 # noqa + +from trame.widgets import vtk as vtk_widgets +from trame.widgets import vuetify # ----------------------------------------------------------------------------- # Trame initialization @@ -65,7 +67,7 @@ @state.change("resolution") -def update_cone(resolution=DEFAULT_RESOLUTION, **kwargs): +def update_cone(resolution=DEFAULT_RESOLUTION, **_): cone_source.SetResolution(resolution) ctrl.view2_update() ctrl.view_update() @@ -118,29 +120,31 @@ def on_end_animation(cameraInfo): with vuetify.VBtn(icon=True, click=update_reset_resolution): vuetify.VIcon("mdi-undo-variant") - with layout.content: - with vuetify.VContainer( + with ( + layout.content, + vuetify.VContainer( fluid=True, classes="pa-0 fill-height", - ): - with vuetify.VCol(classes="pa-0 fill-height"): - view = vtk_widgets.VtkLocalView( - renderWindow, - ref="local", - interactor_events=("vtk_events", ["EndAnimation"]), - EndAnimation=( - ctrl.view_on_end_animation, - "[$event.pokedRenderer.getActiveCamera().get()]", - ), - ) - ctrl.view_update = view.update - ctrl.view_reset_camera = view.reset_camera - with vuetify.VCol(classes="pa-0 fill-height"): - vr = vtk_widgets.VtkRemoteView( - renderWindow, - ref="remote", - ) - ctrl.view2_update = vr.update + ), + ): + with vuetify.VCol(classes="pa-0 fill-height"): + view = vtk_widgets.VtkLocalView( + renderWindow, + ref="local", + interactor_events=("vtk_events", ["EndAnimation"]), + EndAnimation=( + ctrl.view_on_end_animation, + "[$event.pokedRenderer.getActiveCamera().get()]", + ), + ) + ctrl.view_update = view.update + ctrl.view_reset_camera = view.reset_camera + with vuetify.VCol(classes="pa-0 fill-height"): + vr = vtk_widgets.VtkRemoteView( + renderWindow, + ref="remote", + ) + ctrl.view2_update = vr.update # ----------------------------------------------------------------------------- @@ -149,7 +153,7 @@ def on_end_animation(cameraInfo): def show(**kwargs): - from trame.app import jupyter + from trame.app import jupyter # noqa: PLC0415 jupyter.show(server, **kwargs) diff --git a/examples/pyvista/simple.py b/examples/pyvista/simple.py index b4f7386..2eed68b 100644 --- a/examples/pyvista/simple.py +++ b/examples/pyvista/simple.py @@ -1,9 +1,8 @@ -from trame.app import get_server -from trame.ui.vuetify import SinglePageLayout - import pyvista as pv from pyvista import examples from pyvista.trame.ui import plotter_ui +from trame.app import get_server +from trame.ui.vuetify import SinglePageLayout pv.OFF_SCREEN = True @@ -15,8 +14,7 @@ pl = pv.Plotter() pl.add_mesh(mesh) -with SinglePageLayout(server) as layout: - with layout.content: - view = plotter_ui(pl) +with SinglePageLayout(server) as layout, layout.content: + view = plotter_ui(pl) server.start() diff --git a/examples/pyvista/toggle_edge_lighting.py b/examples/pyvista/toggle_edge_lighting.py index af8c9d9..d1ee9e0 100644 --- a/examples/pyvista/toggle_edge_lighting.py +++ b/examples/pyvista/toggle_edge_lighting.py @@ -1,12 +1,12 @@ """Validate Int64 usage with VTK.js.""" +import pyvista as pv from trame.app import get_server from trame.ui.vuetify import SinglePageLayout + from trame.widgets import vuetify from trame.widgets.vtk import VtkLocalView, VtkRemoteView -import pyvista as pv - server = get_server() state, ctrl = server.state, server.controller @@ -38,17 +38,19 @@ def toggle_edges(): vuetify.VSpacer() vuetify.VBtn("Toggle edges", click=toggle_edges) - with layout.content: - with vuetify.VContainer( + with ( + layout.content, + vuetify.VContainer( fluid=True, classes="pa-0 fill-height", - ): - with vuetify.VCol(classes="fill-height"): - view = VtkLocalView(plotter.ren_win) - ctrl.view_update = view.update - ctrl.view_reset_camera = view.reset_camera - with vuetify.VCol(classes="fill-height"): - VtkRemoteView(plotter.ren_win) + ), + ): + with vuetify.VCol(classes="fill-height"): + view = VtkLocalView(plotter.ren_win) + ctrl.view_update = view.update + ctrl.view_reset_camera = view.reset_camera + with vuetify.VCol(classes="fill-height"): + VtkRemoteView(plotter.ren_win) # hide footer layout.footer.hide() diff --git a/examples/pyvista/toggle_edges_many_actors.py b/examples/pyvista/toggle_edges_many_actors.py index 4ff45d1..e6d2897 100644 --- a/examples/pyvista/toggle_edges_many_actors.py +++ b/examples/pyvista/toggle_edges_many_actors.py @@ -1,9 +1,9 @@ # for remote view +import vtkmodules.vtkRenderingOpenGL2 # noqa: F401 from trame.app import get_server from trame.ui.vuetify import SinglePageLayout -from trame.widgets import vtk as vtk_widgets, vuetify from vtkmodules.vtkFiltersSources import vtkConeSource -from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa +from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa: F401 from vtkmodules.vtkRenderingCore import ( vtkActor, vtkPolyDataMapper, @@ -11,7 +11,9 @@ vtkRenderWindow, vtkRenderWindowInteractor, ) -import vtkmodules.vtkRenderingOpenGL2 # noqa + +from trame.widgets import vtk as vtk_widgets +from trame.widgets import vuetify # ----------------------------------------------------------------------------- # Trame initialization @@ -79,18 +81,20 @@ def toggle_edges(): vuetify.VSpacer() vuetify.VBtn("Toggle edges", click=toggle_edges) - with layout.content: - with vuetify.VContainer( + with ( + layout.content, + vuetify.VContainer( fluid=True, classes="pa-0 fill-height", - ): - local_view = vtk_widgets.VtkLocalView( - renderWindow, - ref="view_local", - ) - ctrl.view_update = local_view.update - ctrl.view_reset_camera = local_view.reset_camera - ctrl.view_push_camera = local_view.push_camera + ), + ): + local_view = vtk_widgets.VtkLocalView( + renderWindow, + ref="view_local", + ) + ctrl.view_update = local_view.update + ctrl.view_reset_camera = local_view.reset_camera + ctrl.view_push_camera = local_view.push_camera # ----------------------------------------------------------------------------- diff --git a/examples/pyvista/volume.py b/examples/pyvista/volume.py index 3bbe6f0..f6dd6d8 100644 --- a/examples/pyvista/volume.py +++ b/examples/pyvista/volume.py @@ -1,9 +1,9 @@ +import pyvista as pv +from pyvista.trame import PyVistaLocalView from trame.app import get_server from trame.ui.vuetify import SinglePageLayout -from trame.widgets import vuetify -import pyvista as pv -from pyvista.trame import PyVistaLocalView +from trame.widgets import vuetify server = get_server() server.client_type = "vue2" @@ -33,14 +33,16 @@ with layout.toolbar: vuetify.VSpacer() - with layout.content: - with vuetify.VContainer( + with ( + layout.content, + vuetify.VContainer( fluid=True, classes="pa-0 fill-height", - ): - view = PyVistaLocalView(plotter) - ctrl.view_update = view.update - ctrl.view_reset_camera = view.reset_camera + ), + ): + view = PyVistaLocalView(plotter) + ctrl.view_update = view.update + ctrl.view_reset_camera = view.reset_camera # hide footer layout.footer.hide() diff --git a/examples/validation/AddRemoveActors.py b/examples/validation/AddRemoveActors.py index 8ba490f..bf114af 100644 --- a/examples/validation/AddRemoveActors.py +++ b/examples/validation/AddRemoveActors.py @@ -1,20 +1,20 @@ +# for remote view +import vtkmodules.vtkRenderingOpenGL2 # noqa: F401 from trame.app import get_server -from trame.widgets import vuetify, vtk as vtk_widgets from trame.ui.vuetify import SinglePageLayout - from vtkmodules.vtkFiltersModeling import vtkOutlineFilter from vtkmodules.vtkFiltersSources import vtkConeSource, vtkSphereSource +from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa: F401 from vtkmodules.vtkRenderingCore import ( + vtkActor, + vtkPolyDataMapper, vtkRenderer, vtkRenderWindow, vtkRenderWindowInteractor, - vtkPolyDataMapper, - vtkActor, ) -from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa -# for remote view -import vtkmodules.vtkRenderingOpenGL2 # noqa +from trame.widgets import vtk as vtk_widgets +from trame.widgets import vuetify # ----------------------------------------------------------------------------- # Trame initialization @@ -75,7 +75,7 @@ def create_pipeline(source): @state.change("resolution") -def update_resolution(resolution=DEFAULT_RESOLUTION, **kwargs): +def update_resolution(resolution=DEFAULT_RESOLUTION, **_): cone_source.SetResolution(resolution) ctrl.view_update() @@ -85,7 +85,7 @@ def update_reset_resolution(): @state.change("show_cone") -def update_cone(show_cone, **kwargs): +def update_cone(show_cone, **_): if show_cone: renderer.AddActor(cone_actor) else: @@ -94,7 +94,7 @@ def update_cone(show_cone, **kwargs): @state.change("show_sphere") -def update_sphere(show_sphere, **kwargs): +def update_sphere(show_sphere, **_): if show_sphere: renderer.AddActor(sphere_actor) else: @@ -144,22 +144,24 @@ def update_sphere(show_sphere, **kwargs): v_model=("show_sphere", True), label="Sphere", dense=True, hide_details=True ) - with layout.content: - with vuetify.VContainer( + with ( + layout.content, + vuetify.VContainer( fluid=True, classes="pa-0 fill-height", - ): - view = vtk_widgets.VtkLocalView( - renderWindow, ref="view_local", v_if="use_local" - ) - ctrl.view_update = view.update - ctrl.view_reset_camera = view.reset_camera - - view_remote = vtk_widgets.VtkRemoteView( - renderWindow, ref="view_remote", v_if="!use_local" - ) - ctrl.view_reset_camera.add(view_remote.reset_camera) - ctrl.view_update.add(view_remote.update) + ), + ): + view = vtk_widgets.VtkLocalView( + renderWindow, ref="view_local", v_if="use_local" + ) + ctrl.view_update = view.update + ctrl.view_reset_camera = view.reset_camera + + view_remote = vtk_widgets.VtkRemoteView( + renderWindow, ref="view_remote", v_if="!use_local" + ) + ctrl.view_reset_camera.add(view_remote.reset_camera) + ctrl.view_update.add(view_remote.update) # ----------------------------------------------------------------------------- diff --git a/examples/validation/Animation.py b/examples/validation/Animation.py index c193309..7b04bc9 100644 --- a/examples/validation/Animation.py +++ b/examples/validation/Animation.py @@ -1,10 +1,10 @@ import asyncio -from trame.app import get_server, asynchronous +import vtkmodules.vtkRenderingOpenGL2 # noqa: F401 +from trame.app import asynchronous, get_server from trame.ui.vuetify3 import SinglePageLayout -from trame.widgets import vuetify3 as v3, vtk as vtk_widgets - from vtkmodules.vtkFiltersSources import vtkConeSource +from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa: F401 from vtkmodules.vtkRenderingCore import ( vtkActor, vtkPolyDataMapper, @@ -12,8 +12,9 @@ vtkRenderWindow, vtkRenderWindowInteractor, ) -from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa -import vtkmodules.vtkRenderingOpenGL2 # noqa + +from trame.widgets import vtk as vtk_widgets +from trame.widgets import vuetify3 as v3 renderer = vtkRenderer() renderWindow = vtkRenderWindow() @@ -84,17 +85,19 @@ def on_animation_change(mode, **_): style="max-width: 200px;", ) - with layout.content: - with v3.VContainer( + with ( + layout.content, + v3.VContainer( fluid=True, classes="pa-0 fill-height", - ): - view = vtk_widgets.VtkRemoteView( - renderWindow, interactive_quality=80, interactive_ratio=1 - ) - ctrl.view_update = view.update - ctrl.view_start_animation = view.start_animation - ctrl.view_stop_animation = view.stop_animation + ), + ): + view = vtk_widgets.VtkRemoteView( + renderWindow, interactive_quality=80, interactive_ratio=1 + ) + ctrl.view_update = view.update + ctrl.view_start_animation = view.start_animation + ctrl.view_stop_animation = view.stop_animation if __name__ == "__main__": server.start() diff --git a/examples/validation/AnimationPV.py b/examples/validation/AnimationPV.py index 6f361b5..280c1a4 100644 --- a/examples/validation/AnimationPV.py +++ b/examples/validation/AnimationPV.py @@ -1,10 +1,11 @@ import asyncio -from trame.app import get_server, asynchronous +from paraview import simple +from trame.app import asynchronous, get_server from trame.ui.vuetify3 import SinglePageLayout -from trame.widgets import vuetify3 as v3, paraview as pv_widgets -from paraview import simple +from trame.widgets import paraview as pv_widgets +from trame.widgets import vuetify3 as v3 server = get_server(client_type="vue3") state, ctrl = server.state, server.controller @@ -68,17 +69,17 @@ def on_animation_change(mode, **_): style="max-width: 200px;", ) - with layout.content: - with v3.VContainer( + with ( + layout.content, + v3.VContainer( fluid=True, classes="pa-0 fill-height", - ): - view = pv_widgets.VtkRemoteView( - v, interactive_quality=80, interactive_ratio=1 - ) - ctrl.view_update = view.update - ctrl.view_start_animation = view.start_animation - ctrl.view_stop_animation = view.stop_animation + ), + ): + view = pv_widgets.VtkRemoteView(v, interactive_quality=80, interactive_ratio=1) + ctrl.view_update = view.update + ctrl.view_start_animation = view.start_animation + ctrl.view_stop_animation = view.stop_animation if __name__ == "__main__": server.start() diff --git a/examples/validation/AxesActor.py b/examples/validation/AxesActor.py index 50b98ee..3be0a8d 100644 --- a/examples/validation/AxesActor.py +++ b/examples/validation/AxesActor.py @@ -1,8 +1,10 @@ +import vtkmodules.vtkRenderingOpenGL2 # noqa: F401 from trame.app import get_server from trame.ui.vuetify import SinglePageLayout -from trame.widgets import vuetify, vtk as vtk_widgets - +from vtkmodules.vtkCommonTransforms import vtkTransform from vtkmodules.vtkFiltersSources import vtkConeSource +from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa: F401 +from vtkmodules.vtkRenderingAnnotation import vtkAxesActor from vtkmodules.vtkRenderingCore import ( vtkActor, vtkPolyDataMapper, @@ -10,10 +12,9 @@ vtkRenderWindow, vtkRenderWindowInteractor, ) -from vtkmodules.vtkRenderingAnnotation import vtkAxesActor -from vtkmodules.vtkCommonTransforms import vtkTransform -from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa -import vtkmodules.vtkRenderingOpenGL2 # noqa + +from trame.widgets import vtk as vtk_widgets +from trame.widgets import vuetify renderer = vtkRenderer() renderWindow = vtkRenderWindow() @@ -46,15 +47,17 @@ with SinglePageLayout(server) as layout: layout.title.set_text("Hello trame") - with layout.content: - with vuetify.VContainer( + with ( + layout.content, + vuetify.VContainer( fluid=True, classes="pa-0 fill-height", - ): - with vuetify.VCol(classes="pa-0 ma-1 fill-height"): - vtk_widgets.VtkLocalView(renderWindow) - with vuetify.VCol(classes="pa-0 ma-1 fill-height"): - vtk_widgets.VtkRemoteView(renderWindow, interactive_ratio=1) + ), + ): + with vuetify.VCol(classes="pa-0 ma-1 fill-height"): + vtk_widgets.VtkLocalView(renderWindow) + with vuetify.VCol(classes="pa-0 ma-1 fill-height"): + vtk_widgets.VtkRemoteView(renderWindow, interactive_ratio=1) if __name__ == "__main__": diff --git a/examples/validation/BigIntCoords.py b/examples/validation/BigIntCoords.py index ba7e958..9a4dee8 100644 --- a/examples/validation/BigIntCoords.py +++ b/examples/validation/BigIntCoords.py @@ -1,9 +1,9 @@ from pathlib import Path +import vtkmodules.vtkRenderingOpenGL2 # noqa: F401 from trame.app import get_server from trame.ui.html import DivLayout -from trame.widgets import vtk - +from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa: F401 from vtkmodules.vtkIOXML import vtkXMLRectilinearGridReader from vtkmodules.vtkRenderingCore import ( vtkActor, @@ -12,8 +12,8 @@ vtkRenderWindow, vtkRenderWindowInteractor, ) -from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa -import vtkmodules.vtkRenderingOpenGL2 # noqa + +from trame.widgets import vtk DATA_FILE = (Path(__file__).parent.with_name("data") / "big-int-coord.vtr").resolve() diff --git a/examples/validation/CaptureImage.py b/examples/validation/CaptureImage.py index 1152c6b..bd93188 100644 --- a/examples/validation/CaptureImage.py +++ b/examples/validation/CaptureImage.py @@ -1,20 +1,21 @@ +import vtkmodules.vtkRenderingOpenGL2 # noqa: F401 from trame.app import get_server from trame.app.file_upload import ClientFile -from trame.widgets import vuetify, vtk as vtk_widgets from trame.ui.vuetify import SinglePageLayout - from vtkmodules.vtkFiltersSources import vtkConeSource + +# VTK factory initialization +from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa: F401 from vtkmodules.vtkRenderingCore import ( + vtkActor, + vtkPolyDataMapper, vtkRenderer, vtkRenderWindow, vtkRenderWindowInteractor, - vtkPolyDataMapper, - vtkActor, ) -# VTK factory initialization -from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa -import vtkmodules.vtkRenderingOpenGL2 # noqa +from trame.widgets import vtk as vtk_widgets +from trame.widgets import vuetify # ----------------------------------------------------------------------------- # Trame initialization @@ -52,7 +53,7 @@ @state.change("resolution") -def update_cone(resolution=DEFAULT_RESOLUTION, **kwargs): +def update_cone(resolution=DEFAULT_RESOLUTION, **_): cone_source.SetResolution(resolution) ctrl.view_update() @@ -87,18 +88,20 @@ def save_image_on_server(screenshot_file): with vuetify.VBtn(icon=True, click=ctrl.view_capture_image): vuetify.VIcon("mdi-camera-outline") - with layout.content: - with vuetify.VContainer( + with ( + layout.content, + vuetify.VContainer( fluid=True, classes="pa-0 fill-height", - ): - view = vtk_widgets.VtkRemoteLocalView( - renderWindow, - on_remote_image_capture="utils.download('remote.png', $event)", - on_local_image_capture="utils.download('local.png', $event)", - ) - ctrl.view_update = view.update - ctrl.view_reset_camera = view.reset_camera - ctrl.view_capture_image = view.capture_image + ), + ): + view = vtk_widgets.VtkRemoteLocalView( + renderWindow, + on_remote_image_capture="utils.download('remote.png', $event)", + on_local_image_capture="utils.download('local.png', $event)", + ) + ctrl.view_update = view.update + ctrl.view_reset_camera = view.reset_camera + ctrl.view_capture_image = view.capture_image server.start() diff --git a/examples/validation/CaptureImageLocal.py b/examples/validation/CaptureImageLocal.py index ecd9862..b35784f 100644 --- a/examples/validation/CaptureImageLocal.py +++ b/examples/validation/CaptureImageLocal.py @@ -1,20 +1,21 @@ +import vtkmodules.vtkRenderingOpenGL2 # noqa: F401 from trame.app import get_server from trame.app.file_upload import ClientFile -from trame.widgets import vuetify, vtk as vtk_widgets from trame.ui.vuetify import SinglePageLayout - from vtkmodules.vtkFiltersSources import vtkConeSource + +# VTK factory initialization +from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa: F401 from vtkmodules.vtkRenderingCore import ( + vtkActor, + vtkPolyDataMapper, vtkRenderer, vtkRenderWindow, vtkRenderWindowInteractor, - vtkPolyDataMapper, - vtkActor, ) -# VTK factory initialization -from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa -import vtkmodules.vtkRenderingOpenGL2 # noqa +from trame.widgets import vtk as vtk_widgets +from trame.widgets import vuetify # ----------------------------------------------------------------------------- # Trame initialization @@ -52,7 +53,7 @@ @state.change("resolution") -def update_cone(resolution=DEFAULT_RESOLUTION, **kwargs): +def update_cone(resolution=DEFAULT_RESOLUTION, **_): cone_source.SetResolution(resolution) ctrl.view_update() diff --git a/examples/validation/CaptureImageRemote.py b/examples/validation/CaptureImageRemote.py index 49faa80..0786681 100644 --- a/examples/validation/CaptureImageRemote.py +++ b/examples/validation/CaptureImageRemote.py @@ -1,20 +1,21 @@ +import vtkmodules.vtkRenderingOpenGL2 # noqa: F401 from trame.app import get_server from trame.app.file_upload import ClientFile -from trame.widgets import vuetify, vtk as vtk_widgets from trame.ui.vuetify import SinglePageLayout - from vtkmodules.vtkFiltersSources import vtkConeSource + +# VTK factory initialization +from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa: F401 from vtkmodules.vtkRenderingCore import ( + vtkActor, + vtkPolyDataMapper, vtkRenderer, vtkRenderWindow, vtkRenderWindowInteractor, - vtkPolyDataMapper, - vtkActor, ) -# VTK factory initialization -from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa -import vtkmodules.vtkRenderingOpenGL2 # noqa +from trame.widgets import vtk as vtk_widgets +from trame.widgets import vuetify # ----------------------------------------------------------------------------- # Trame initialization @@ -52,7 +53,7 @@ @state.change("resolution") -def update_cone(resolution=DEFAULT_RESOLUTION, **kwargs): +def update_cone(resolution=DEFAULT_RESOLUTION, **_): cone_source.SetResolution(resolution) ctrl.view_update() diff --git a/examples/validation/ColorByComponent.py b/examples/validation/ColorByComponent.py index b2745df..70ca115 100644 --- a/examples/validation/ColorByComponent.py +++ b/examples/validation/ColorByComponent.py @@ -1,19 +1,20 @@ +import vtkmodules.vtkRenderingOpenGL2 # noqa: F401 from trame.app import get_server -from trame.widgets import vuetify, vtk as vtk_widgets from trame.ui.vuetify import SinglePageLayout - from vtkmodules.vtkFiltersSources import vtkSphereSource + +# VTK factory initialization +from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa: F401 from vtkmodules.vtkRenderingCore import ( + vtkActor, + vtkPolyDataMapper, vtkRenderer, vtkRenderWindow, vtkRenderWindowInteractor, - vtkPolyDataMapper, - vtkActor, ) -# VTK factory initialization -from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa -import vtkmodules.vtkRenderingOpenGL2 # noqa +from trame.widgets import vtk as vtk_widgets +from trame.widgets import vuetify # ----------------------------------------------------------------------------- # Trame initialization @@ -60,7 +61,7 @@ @state.change("component_idx") -def color_by_array(component_idx, **kwargs): +def color_by_array(component_idx, **_): lut.SetVectorComponent(component_idx) ctrl.remote_view_update() ctrl.local_view_update() @@ -77,27 +78,29 @@ def color_by_array(component_idx, **kwargs): items=( "components", [ - dict(value=0, text="X"), - dict(value=1, text="Y"), - dict(value=2, text="Z"), + {"value": 0, "text": "X"}, + {"value": 1, "text": "Y"}, + {"value": 2, "text": "Z"}, ], ), dense=True, hide_details=True, ) - with layout.content: - with vuetify.VContainer( + with ( + layout.content, + vuetify.VContainer( fluid=True, classes="pa-0 fill-height", - ): - with vuetify.VCol(classes="pa-0 fill-height"): - view = vtk_widgets.VtkLocalView(renderWindow, ref="local") - ctrl.local_view_update = view.update - ctrl.view_reset_camera.add(view.reset_camera) - with vuetify.VCol(classes="pa-0 fill-height"): - view = vtk_widgets.VtkRemoteView(renderWindow, ref="remote") - ctrl.remote_view_update = view.update - ctrl.view_reset_camera.add(view.reset_camera) + ), + ): + with vuetify.VCol(classes="pa-0 fill-height"): + view = vtk_widgets.VtkLocalView(renderWindow, ref="local") + ctrl.local_view_update = view.update + ctrl.view_reset_camera.add(view.reset_camera) + with vuetify.VCol(classes="pa-0 fill-height"): + view = vtk_widgets.VtkRemoteView(renderWindow, ref="remote") + ctrl.remote_view_update = view.update + ctrl.view_reset_camera.add(view.reset_camera) server.start() diff --git a/examples/validation/ColorByComponentPyVista.py b/examples/validation/ColorByComponentPyVista.py index c011bfc..d361485 100644 --- a/examples/validation/ColorByComponentPyVista.py +++ b/examples/validation/ColorByComponentPyVista.py @@ -1,8 +1,9 @@ +import pyvista as pv from trame.app import get_server -from trame.widgets import vuetify, vtk as vtk_widgets from trame.ui.vuetify import SinglePageLayout -import pyvista as pv +from trame.widgets import vtk as vtk_widgets +from trame.widgets import vuetify from trame_vtk.modules.vtk.serializers import encode_lut pv.OFF_SCREEN = True @@ -44,7 +45,7 @@ @state.change("component_idx") -def color_by_array(component_idx, **kwargs): +def color_by_array(component_idx, **_): lut.SetVectorModeToComponent() lut.SetVectorSize(3) lut.SetVectorComponent(component_idx) @@ -54,7 +55,7 @@ def color_by_array(component_idx, **kwargs): @state.change("cmap") -def color_preset(cmap, **kwargs): +def color_preset(cmap, **_): lut.cmap = cmap ctrl.remote_view_update() ctrl.local_view_update() @@ -71,9 +72,9 @@ def color_preset(cmap, **kwargs): items=( "components", [ - dict(value=0, text="X"), - dict(value=1, text="Y"), - dict(value=2, text="Z"), + {"value": 0, "text": "X"}, + {"value": 1, "text": "Y"}, + {"value": 2, "text": "Z"}, ], ), dense=True, @@ -92,19 +93,21 @@ def color_preset(cmap, **kwargs): hide_details=True, ) - with layout.content: - with vuetify.VContainer( + with ( + layout.content, + vuetify.VContainer( fluid=True, classes="pa-0 fill-height", - ): - with vuetify.VCol(classes="pa-0 fill-height"): - view = vtk_widgets.VtkLocalView(plotter.render_window, ref="local") - ctrl.local_view_update = view.update - ctrl.view_reset_camera.add(view.reset_camera) - ctrl.view_push_camera.add(view.push_camera) - with vuetify.VCol(classes="pa-0 fill-height"): - view = vtk_widgets.VtkRemoteView(plotter.render_window, ref="remote") - ctrl.remote_view_update = view.update - ctrl.view_reset_camera.add(view.reset_camera) + ), + ): + with vuetify.VCol(classes="pa-0 fill-height"): + view = vtk_widgets.VtkLocalView(plotter.render_window, ref="local") + ctrl.local_view_update = view.update + ctrl.view_reset_camera.add(view.reset_camera) + ctrl.view_push_camera.add(view.push_camera) + with vuetify.VCol(classes="pa-0 fill-height"): + view = vtk_widgets.VtkRemoteView(plotter.render_window, ref="remote") + ctrl.remote_view_update = view.update + ctrl.view_reset_camera.add(view.reset_camera) server.start() diff --git a/examples/validation/ExportScene.py b/examples/validation/ExportScene.py index 6b026ad..429dca7 100644 --- a/examples/validation/ExportScene.py +++ b/examples/validation/ExportScene.py @@ -1,7 +1,5 @@ from trame.app import get_server from trame.ui.vuetify import SinglePageLayout -from trame.widgets import vuetify, vtk as vtk_widgets - from vtkmodules.vtkFiltersSources import vtkConeSource from vtkmodules.vtkRenderingCore import ( vtkActor, @@ -11,6 +9,9 @@ vtkRenderWindowInteractor, ) +from trame.widgets import vtk as vtk_widgets +from trame.widgets import vuetify + renderer = vtkRenderer() renderWindow = vtkRenderWindow() renderWindow.AddRenderer(renderer) @@ -40,7 +41,7 @@ def export_scene(): @state.change("resolution") -def update_cone(resolution=DEFAULT_RESOLUTION, **kwargs): +def update_cone(resolution=DEFAULT_RESOLUTION, **_): cone_source.SetResolution(resolution) ctrl.view_update() @@ -71,16 +72,18 @@ def update_reset_resolution(): click="utils.download('scene-extract.vtksz', trigger('export'), 'application/octet-stream')", ) - with layout.content: - with vuetify.VContainer( + with ( + layout.content, + vuetify.VContainer( fluid=True, classes="pa-0 fill-height", - ): - with vuetify.VCol(classes="pa-0 ma-1 fill-height"): - view = vtk_widgets.VtkLocalView(renderWindow) - ctrl.view_export = view.export - ctrl.view_update = view.update - ctrl.view_reset_camera = view.reset_camera + ), + vuetify.VCol(classes="pa-0 ma-1 fill-height"), + ): + view = vtk_widgets.VtkLocalView(renderWindow) + ctrl.view_export = view.export + ctrl.view_update = view.update + ctrl.view_reset_camera = view.reset_camera if __name__ == "__main__": server.start() diff --git a/examples/validation/ManyViews.py b/examples/validation/ManyViews.py index 48ef884..c1690e5 100644 --- a/examples/validation/ManyViews.py +++ b/examples/validation/ManyViews.py @@ -1,20 +1,20 @@ +# for remote view +import vtkmodules.vtkRenderingOpenGL2 # noqa: F401 from trame.app import get_server -from trame.widgets import vuetify, html, vtk as vtk_widgets from trame.ui.vuetify import SinglePageLayout - from vtkmodules.vtkFiltersModeling import vtkOutlineFilter from vtkmodules.vtkFiltersSources import vtkConeSource, vtkSphereSource +from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa: F401 from vtkmodules.vtkRenderingCore import ( + vtkActor, + vtkPolyDataMapper, vtkRenderer, vtkRenderWindow, vtkRenderWindowInteractor, - vtkPolyDataMapper, - vtkActor, ) -from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa -# for remote view -import vtkmodules.vtkRenderingOpenGL2 # noqa +from trame.widgets import html, vuetify +from trame.widgets import vtk as vtk_widgets # ----------------------------------------------------------------------------- # Trame initialization @@ -80,18 +80,18 @@ def create_vtk_view(color): renderer.ResetCamera() renderWindow.Render() - return dict( - render_window=renderWindow, - renderer=renderer, - sphere=sphere_source, - cone=cone_source, - cone_actor=cone_actor, - sphere_actor=sphere_actor, - show_cone=True, - show_sphere=True, - resolution=DEFAULT_RESOLUTION, - widget_on=True, - ) + return { + "render_window": renderWindow, + "renderer": renderer, + "sphere": sphere_source, + "cone": cone_source, + "cone_actor": cone_actor, + "sphere_actor": sphere_actor, + "show_cone": True, + "show_sphere": True, + "resolution": DEFAULT_RESOLUTION, + "widget_on": True, + } # Create 4 views @@ -114,7 +114,7 @@ def reset_active_view(): @state.change("active_view") -def active_view_change(active_view, **kwargs): +def active_view_change(active_view, **_): pipeline = VIEWS[active_view] state.show_cone = pipeline.get("show_cone") state.show_sphere = pipeline.get("show_sphere") @@ -123,12 +123,12 @@ def active_view_change(active_view, **kwargs): @state.change("widget_on") -def toggle_view(widget_on, active_view, **kwargs): +def toggle_view(widget_on, active_view, **_): state[f"widget_on_{active_view}"] = widget_on @state.change("resolution") -def update_resolution(resolution, active_view, **kwargs): +def update_resolution(resolution, active_view, **_): pipeline = VIEWS[active_view] pipeline.get("cone").SetResolution(resolution) pipeline["resolution"] = resolution @@ -140,7 +140,7 @@ def update_reset_resolution(): @state.change("show_cone") -def update_cone(active_view, show_cone, **kwargs): +def update_cone(active_view, show_cone, **_): pipeline = VIEWS[active_view] renderer = pipeline.get("renderer") cone_actor = pipeline.get("cone_actor") @@ -153,7 +153,7 @@ def update_cone(active_view, show_cone, **kwargs): @state.change("show_sphere") -def update_sphere(active_view, show_sphere, **kwargs): +def update_sphere(active_view, show_sphere, **_): pipeline = VIEWS[active_view] renderer = pipeline.get("renderer") sphere_actor = pipeline.get("sphere_actor") diff --git a/examples/validation/NoSize.py b/examples/validation/NoSize.py index b5a2f7a..d26b8e1 100644 --- a/examples/validation/NoSize.py +++ b/examples/validation/NoSize.py @@ -1,19 +1,20 @@ +import vtkmodules.vtkRenderingOpenGL2 # noqa: F401 from trame.app import get_server -from trame.widgets import vuetify, vtk as vtk_widgets from trame.ui.vuetify import SinglePageLayout - from vtkmodules.vtkFiltersSources import vtkConeSource, vtkSphereSource + +# VTK factory initialization +from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa: F401 from vtkmodules.vtkRenderingCore import ( + vtkActor, + vtkPolyDataMapper, vtkRenderer, vtkRenderWindow, vtkRenderWindowInteractor, - vtkPolyDataMapper, - vtkActor, ) -# VTK factory initialization -from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa -import vtkmodules.vtkRenderingOpenGL2 # noqa +from trame.widgets import vtk as vtk_widgets +from trame.widgets import vuetify # ----------------------------------------------------------------------------- # Trame initialization @@ -85,13 +86,12 @@ hide_details=True, ) - with layout.content: - with vuetify.VContainer(fluid=True, classes="pa-0 fill-height"): - with vuetify.VCol(classes="pa-0 fill-height"): - with vtk_widgets.VtkRemoteView(renderWindow, ref="v1") as view: - ctrl.view_reset_camera.add(view.reset_camera) - with vuetify.VCol(classes="pa-0 fill-height", v_show="show"): - with vtk_widgets.VtkRemoteView(renderWindow_v2, ref="v2") as view: - ctrl.view_reset_camera.add(view.reset_camera) + with layout.content, vuetify.VContainer(fluid=True, classes="pa-0 fill-height"): + with vuetify.VCol(classes="pa-0 fill-height"): + with vtk_widgets.VtkRemoteView(renderWindow, ref="v1") as view: + ctrl.view_reset_camera.add(view.reset_camera) + with vuetify.VCol(classes="pa-0 fill-height", v_show="show"): + with vtk_widgets.VtkRemoteView(renderWindow_v2, ref="v2") as view: + ctrl.view_reset_camera.add(view.reset_camera) server.start() diff --git a/examples/validation/PickingRemoteLocalView.py b/examples/validation/PickingRemoteLocalView.py index be15a2d..a246daa 100644 --- a/examples/validation/PickingRemoteLocalView.py +++ b/examples/validation/PickingRemoteLocalView.py @@ -1,22 +1,21 @@ +import vtkmodules.vtkRenderingOpenGL2 # noqa: F401 from trame.app import get_server from trame.ui.html import DivLayout -from trame.widgets import html, client, vtk as vtk_widgets - from vtkmodules.vtkCommonDataModel import vtkDataObject from vtkmodules.vtkFiltersSources import vtkConeSource, vtkSphereSource +from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa: F401 from vtkmodules.vtkRenderingCore import ( + vtkActor, + vtkHardwareSelector, + vtkPolyDataMapper, + vtkPropPicker, vtkRenderer, vtkRenderWindow, vtkRenderWindowInteractor, - vtkPolyDataMapper, - vtkActor, - vtkPropPicker, - vtkHardwareSelector, ) -from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa -import vtkmodules.vtkRenderingOpenGL2 # noqa - +from trame.widgets import client, html +from trame.widgets import vtk as vtk_widgets from trame_vtk.modules.vtk.serializers.utils import reference_id INTERACTOR_SETTINGS_WITH_SELECT = [ diff --git a/examples/validation/PickingRemoteView.py b/examples/validation/PickingRemoteView.py index 80afbd2..25af699 100644 --- a/examples/validation/PickingRemoteView.py +++ b/examples/validation/PickingRemoteView.py @@ -1,21 +1,21 @@ +import vtkmodules.vtkRenderingOpenGL2 # noqa: F401 from trame.app import get_server from trame.ui.html import DivLayout -from trame.widgets import html, client, vtk as vtk_widgets - from vtkmodules.vtkCommonDataModel import vtkDataObject from vtkmodules.vtkFiltersSources import vtkConeSource, vtkSphereSource +from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa: F401 from vtkmodules.vtkRenderingCore import ( + vtkActor, + vtkHardwareSelector, + vtkPolyDataMapper, + vtkPropPicker, vtkRenderer, vtkRenderWindow, vtkRenderWindowInteractor, - vtkPolyDataMapper, - vtkActor, - vtkPropPicker, - vtkHardwareSelector, ) -from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa -import vtkmodules.vtkRenderingOpenGL2 # noqa +from trame.widgets import client, html +from trame.widgets import vtk as vtk_widgets class PickingExample: diff --git a/examples/validation/PushCamera.py b/examples/validation/PushCamera.py index e7dae1e..563cdc1 100644 --- a/examples/validation/PushCamera.py +++ b/examples/validation/PushCamera.py @@ -1,19 +1,19 @@ +# for remote view +import vtkmodules.vtkRenderingOpenGL2 # noqa: F401 from trame.app import get_server -from trame.widgets import vuetify, html, vtk as vtk_widgets from trame.ui.vuetify import SinglePageLayout - from vtkmodules.vtkFiltersSources import vtkConeSource +from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa: F401 from vtkmodules.vtkRenderingCore import ( + vtkActor, + vtkPolyDataMapper, vtkRenderer, vtkRenderWindow, vtkRenderWindowInteractor, - vtkPolyDataMapper, - vtkActor, ) -from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa -# for remote view -import vtkmodules.vtkRenderingOpenGL2 # noqa +from trame.widgets import html, vuetify +from trame.widgets import vtk as vtk_widgets # ----------------------------------------------------------------------------- # Trame initialization @@ -57,7 +57,7 @@ @state.change("resolution") -def update_resolution(resolution, **kwargs): +def update_resolution(resolution, **_): cone_source.SetResolution(resolution) ctrl.view_update() @@ -93,32 +93,34 @@ def push_camera(): style="max-width: 300px", ) - with layout.content: - with vuetify.VContainer( + with ( + layout.content, + vuetify.VContainer( fluid=True, classes="pa-0 fill-height", style="display: grid; grid-template-columns: 1fr 1fr; grid-template-rows: 1fr;", + ), + ): + with html.Div( + style="height: 100%;justify-self: stretch;", + ): + remote_view = vtk_widgets.VtkRemoteView( + renderWindow, + ref="view_remote", + ) + ctrl.view_update.add(remote_view.update) + ctrl.view_reset_camera.add(remote_view.reset_camera) + + with html.Div( + style="height: 100%;justify-self: stretch;", ): - with html.Div( - style="height: 100%;justify-self: stretch;", - ): - remote_view = vtk_widgets.VtkRemoteView( - renderWindow, - ref="view_remote", - ) - ctrl.view_update.add(remote_view.update) - ctrl.view_reset_camera.add(remote_view.reset_camera) - - with html.Div( - style="height: 100%;justify-self: stretch;", - ): - local_view = vtk_widgets.VtkLocalView( - renderWindow, - ref="view_local", - ) - ctrl.view_update.add(local_view.update) - ctrl.view_reset_camera.add(local_view.reset_camera) - ctrl.view_push_camera = local_view.push_camera + local_view = vtk_widgets.VtkLocalView( + renderWindow, + ref="view_local", + ) + ctrl.view_update.add(local_view.update) + ctrl.view_reset_camera.add(local_view.reset_camera) + ctrl.view_push_camera = local_view.push_camera # ----------------------------------------------------------------------------- diff --git a/examples/validation/PvConeLocal.py b/examples/validation/PvConeLocal.py index e892aed..983dc45 100644 --- a/examples/validation/PvConeLocal.py +++ b/examples/validation/PvConeLocal.py @@ -1,11 +1,10 @@ # pvpython ./PvConeLocal.py --venv /path/to/venv import paraview.web.venv - +from paraview import simple from trame.app import get_server -from trame.widgets import vuetify, paraview from trame.ui.vuetify import SinglePageLayout -from paraview import simple +from trame.widgets import paraview, vuetify # ----------------------------------------------------------------------------- # Trame setup @@ -27,7 +26,7 @@ @state.change("resolution") -def update_cone(resolution, **kwargs): +def update_cone(resolution, **_): cone.Resolution = resolution ctrl.view_update() @@ -61,11 +60,10 @@ def update_reset_resolution(): with vuetify.VBtn(icon=True, click=update_reset_resolution): vuetify.VIcon("mdi-undo-variant") - with layout.content: - with vuetify.VContainer(fluid=True, classes="pa-0 fill-height"): - html_view = paraview.VtkLocalView(view, ref="view") - ctrl.view_reset_camera = html_view.reset_camera - ctrl.view_update = html_view.update + with layout.content, vuetify.VContainer(fluid=True, classes="pa-0 fill-height"): + html_view = paraview.VtkLocalView(view, ref="view") + ctrl.view_reset_camera = html_view.reset_camera + ctrl.view_update = html_view.update # ----------------------------------------------------------------------------- # Main diff --git a/examples/validation/PvConeRemote.py b/examples/validation/PvConeRemote.py index f677533..5c9388a 100644 --- a/examples/validation/PvConeRemote.py +++ b/examples/validation/PvConeRemote.py @@ -1,11 +1,10 @@ # pvpython ./PvConeRemote.py --venv /path/to/venv import paraview.web.venv - +from paraview import simple from trame.app import get_server -from trame.widgets import vuetify, paraview from trame.ui.vuetify import SinglePageLayout -from paraview import simple +from trame.widgets import paraview, vuetify # ----------------------------------------------------------------------------- # Trame setup @@ -27,7 +26,7 @@ @state.change("resolution") -def update_cone(resolution, **kwargs): +def update_cone(resolution, **_): cone.Resolution = resolution ctrl.view_update() @@ -61,11 +60,10 @@ def update_reset_resolution(): with vuetify.VBtn(icon=True, click=update_reset_resolution): vuetify.VIcon("mdi-undo-variant") - with layout.content: - with vuetify.VContainer(fluid=True, classes="pa-0 fill-height"): - html_view = paraview.VtkRemoteView(view, ref="view") - ctrl.view_reset_camera = html_view.reset_camera - ctrl.view_update = html_view.update + with layout.content, vuetify.VContainer(fluid=True, classes="pa-0 fill-height"): + html_view = paraview.VtkRemoteView(view, ref="view") + ctrl.view_reset_camera = html_view.reset_camera + ctrl.view_update = html_view.update # ----------------------------------------------------------------------------- # Main diff --git a/examples/validation/PvConeRemoteLocal.py b/examples/validation/PvConeRemoteLocal.py index b73d51c..6937f4e 100644 --- a/examples/validation/PvConeRemoteLocal.py +++ b/examples/validation/PvConeRemoteLocal.py @@ -1,12 +1,11 @@ # pvpython ./PvConeRemoteLocal.py --venv /path/to/venv # pvpython ./PvConeRemote.py --venv /path/to/venv import paraview.web.venv - +from paraview import simple from trame.app import get_server -from trame.widgets import vuetify, paraview, html from trame.ui.vuetify import SinglePageLayout -from paraview import simple +from trame.widgets import html, paraview, vuetify # ----------------------------------------------------------------------------- # Trame setup @@ -28,7 +27,7 @@ @state.change("resolution") -def update_cone(resolution, **kwargs): +def update_cone(resolution, **_): cone.Resolution = resolution ctrl.view_update() @@ -73,13 +72,12 @@ def update_reset_resolution(): with vuetify.VBtn(icon=True, click=update_reset_resolution): vuetify.VIcon("mdi-undo-variant") - with layout.content: - with vuetify.VContainer(fluid=True, classes="pa-0 fill-height"): - html_view = paraview.VtkRemoteLocalView( - view, mode=("rendering_mode", "local"), ref="view" - ) - ctrl.view_reset_camera = html_view.reset_camera - ctrl.view_update = html_view.update + with layout.content, vuetify.VContainer(fluid=True, classes="pa-0 fill-height"): + html_view = paraview.VtkRemoteLocalView( + view, mode=("rendering_mode", "local"), ref="view" + ) + ctrl.view_reset_camera = html_view.reset_camera + ctrl.view_update = html_view.update # ----------------------------------------------------------------------------- # Main diff --git a/examples/validation/PyVistaAxesGrid.py b/examples/validation/PyVistaAxesGrid.py index 12d3a90..9fdc128 100644 --- a/examples/validation/PyVistaAxesGrid.py +++ b/examples/validation/PyVistaAxesGrid.py @@ -4,13 +4,13 @@ is synchroniezed in addition to text colors. """ +import pyvista as pv from trame.app import get_server from trame.ui.vuetify import SinglePageLayout + from trame.widgets import vuetify from trame.widgets.vtk import VtkLocalView -import pyvista as pv - server = get_server() server.client_type = "vue2" state, ctrl = server.state, server.controller @@ -40,14 +40,16 @@ with layout.toolbar: vuetify.VSpacer() - with layout.content: - with vuetify.VContainer( + with ( + layout.content, + vuetify.VContainer( fluid=True, classes="pa-0 fill-height", - ): - view = VtkLocalView(plotter.ren_win) - ctrl.view_update = view.update - ctrl.view_reset_camera = view.reset_camera + ), + ): + view = VtkLocalView(plotter.ren_win) + ctrl.view_update = view.update + ctrl.view_reset_camera = view.reset_camera # hide footer layout.footer.hide() diff --git a/examples/validation/PyVistaAxesWidget.py b/examples/validation/PyVistaAxesWidget.py index e0cb388..98daa50 100644 --- a/examples/validation/PyVistaAxesWidget.py +++ b/examples/validation/PyVistaAxesWidget.py @@ -3,6 +3,7 @@ import pyvista as pv from trame.app import get_server from trame.ui.vuetify import SinglePageLayout + from trame.widgets import vuetify from trame.widgets.vtk import VtkLocalView, VtkRemoteView @@ -25,7 +26,7 @@ @state.change("show_widget") -def toggle_axes_widget(show_widget, **kwargs): +def toggle_axes_widget(show_widget, **_): if show_widget: plotter.renderer.show_axes() else: @@ -53,24 +54,26 @@ def toggle_axes_widget(show_widget, **kwargs): classes="my-0 py-0 ml-1", ) - with layout.content: - with vuetify.VContainer( + with ( + layout.content, + vuetify.VContainer( fluid=True, classes="pa-0 fill-height", - ): - with vuetify.VCol(classes="fill-height"): - view = VtkLocalView( - plotter.ren_win, ref="local" - ) # or widgets=[axes_widget] - ctrl.view_update.add(view.update) - ctrl.view_reset_camera.add(view.reset_camera) - ctrl.view_widgets_set = view.set_widgets - view.set_widgets([axes_widget]) # or at constructor - - with vuetify.VCol(classes="fill-height"): - view = VtkRemoteView(plotter.ren_win, ref="remote") - ctrl.view_update.add(view.update) - ctrl.view_reset_camera.add(view.reset_camera) + ), + ): + with vuetify.VCol(classes="fill-height"): + view = VtkLocalView( + plotter.ren_win, ref="local" + ) # or widgets=[axes_widget] + ctrl.view_update.add(view.update) + ctrl.view_reset_camera.add(view.reset_camera) + ctrl.view_widgets_set = view.set_widgets + view.set_widgets([axes_widget]) # or at constructor + + with vuetify.VCol(classes="fill-height"): + view = VtkRemoteView(plotter.ren_win, ref="remote") + ctrl.view_update.add(view.update) + ctrl.view_reset_camera.add(view.reset_camera) # hide footer layout.footer.hide() diff --git a/examples/validation/PyVistaAxesWidgetSubplot.py b/examples/validation/PyVistaAxesWidgetSubplot.py index a964cc3..a7026e8 100644 --- a/examples/validation/PyVistaAxesWidgetSubplot.py +++ b/examples/validation/PyVistaAxesWidgetSubplot.py @@ -3,6 +3,7 @@ import pyvista as pv from trame.app import get_server from trame.ui.vuetify import SinglePageLayout + from trame.widgets import vuetify from trame.widgets.vtk import VtkLocalView, VtkRemoteView @@ -32,7 +33,7 @@ @state.change("show_widget_a") -def toggle_axes_widget_a(show_widget_a, **kwargs): +def toggle_axes_widget_a(show_widget_a, **_): plotter.subplot(0, 0) if show_widget_a: plotter.renderer.show_axes() @@ -42,7 +43,7 @@ def toggle_axes_widget_a(show_widget_a, **kwargs): @state.change("show_widget_b") -def toggle_axes_widget_b(show_widget_b, **kwargs): +def toggle_axes_widget_b(show_widget_b, **_): plotter.subplot(0, 1) if show_widget_b: plotter.renderer.show_axes() @@ -80,21 +81,23 @@ def toggle_axes_widget_b(show_widget_b, **kwargs): classes="my-0 py-0 ml-1", ) - with layout.content: - with vuetify.VContainer( + with ( + layout.content, + vuetify.VContainer( fluid=True, classes="pa-0 fill-height", - ): - with vuetify.VCol(classes="fill-height"): - view = VtkLocalView(plotter.ren_win, ref="local") - ctrl.view_update.add(view.update) - ctrl.view_reset_camera.add(view.reset_camera) - view.set_widgets([axes_widget_0, axes_widget_1]) # or at constructor - - with vuetify.VCol(classes="fill-height"): - view = VtkRemoteView(plotter.ren_win, ref="remote") - ctrl.view_update.add(view.update) - ctrl.view_reset_camera.add(view.reset_camera) + ), + ): + with vuetify.VCol(classes="fill-height"): + view = VtkLocalView(plotter.ren_win, ref="local") + ctrl.view_update.add(view.update) + ctrl.view_reset_camera.add(view.reset_camera) + view.set_widgets([axes_widget_0, axes_widget_1]) # or at constructor + + with vuetify.VCol(classes="fill-height"): + view = VtkRemoteView(plotter.ren_win, ref="remote") + ctrl.view_update.add(view.update) + ctrl.view_reset_camera.add(view.reset_camera) # hide footer layout.footer.hide() diff --git a/examples/validation/PyVistaAxesWidgetSubplotLinked.py b/examples/validation/PyVistaAxesWidgetSubplotLinked.py index 716ac85..0ae4498 100644 --- a/examples/validation/PyVistaAxesWidgetSubplotLinked.py +++ b/examples/validation/PyVistaAxesWidgetSubplotLinked.py @@ -3,6 +3,7 @@ import pyvista as pv from trame.app import get_server from trame.ui.vuetify import SinglePageLayout + from trame.widgets import vuetify from trame.widgets.vtk import VtkLocalView, VtkRemoteView @@ -43,20 +44,22 @@ with layout.toolbar: vuetify.VSpacer() - with layout.content: - with vuetify.VContainer( + with ( + layout.content, + vuetify.VContainer( fluid=True, classes="pa-0 fill-height", - ): - with vuetify.VCol(classes="fill-height"): - view = VtkLocalView( - plotter.ren_win, widgets=[axes_widget_0, axes_widget_1], ref="local" - ) - ctrl.view_update = view.update - ctrl.view_reset_camera.add(view.reset_camera) - with vuetify.VCol(classes="fill-height"): - view = VtkRemoteView(plotter.ren_win, ref="remote") - ctrl.view_reset_camera.add(view.reset_camera) + ), + ): + with vuetify.VCol(classes="fill-height"): + view = VtkLocalView( + plotter.ren_win, widgets=[axes_widget_0, axes_widget_1], ref="local" + ) + ctrl.view_update = view.update + ctrl.view_reset_camera.add(view.reset_camera) + with vuetify.VCol(classes="fill-height"): + view = VtkRemoteView(plotter.ren_win, ref="remote") + ctrl.view_reset_camera.add(view.reset_camera) # hide footer layout.footer.hide() diff --git a/examples/validation/PyVistaDynaLUT.py b/examples/validation/PyVistaDynaLUT.py index 1b0957b..22fefb1 100644 --- a/examples/validation/PyVistaDynaLUT.py +++ b/examples/validation/PyVistaDynaLUT.py @@ -1,15 +1,15 @@ import matplotlib.pyplot as plt -from trame.app import get_server -from trame.ui.vuetify import SinglePageLayout -from trame.widgets import vuetify - import pyvista as pv from pyvista import examples from pyvista.trame.ui import plotter_ui +from trame.app import get_server +from trame.ui.vuetify import SinglePageLayout # Just for using this script in testing from trame_client.utils.testing import enable_testing +from trame.widgets import vuetify + pv.OFF_SCREEN = True server = enable_testing(get_server()) @@ -27,7 +27,7 @@ @state.change("cmap") -def update_cmap(cmap="viridis", **kwargs): +def update_cmap(cmap="viridis", **_): actor.mapper.lookup_table.cmap = cmap ctrl.view_update() diff --git a/examples/validation/PyVistaFirstStillRatio.py b/examples/validation/PyVistaFirstStillRatio.py index c5b3dd3..2a9e55e 100644 --- a/examples/validation/PyVistaFirstStillRatio.py +++ b/examples/validation/PyVistaFirstStillRatio.py @@ -1,7 +1,9 @@ import pyvista as pv from trame.app import get_server from trame.ui.vuetify import SinglePageLayout -from trame.widgets import vuetify, vtk as vtk_widgets + +from trame.widgets import vtk as vtk_widgets +from trame.widgets import vuetify server = get_server() server.client_type = "vue2" @@ -28,18 +30,20 @@ with layout.toolbar: vuetify.VSpacer() - with layout.content: - with vuetify.VContainer( + with ( + layout.content, + vuetify.VContainer( fluid=True, classes="pa-0 fill-height", - ): - view = vtk_widgets.VtkRemoteView( - plotter.ren_win, - interactive_ratio=2, - still_ratio=2, - ) - ctrl.view_update = view.update - ctrl.view_reset_camera = view.reset_camera + ), + ): + view = vtk_widgets.VtkRemoteView( + plotter.ren_win, + interactive_ratio=2, + still_ratio=2, + ) + ctrl.view_update = view.update + ctrl.view_reset_camera = view.reset_camera if __name__ == "__main__": diff --git a/examples/validation/PyVistaInt64.py b/examples/validation/PyVistaInt64.py index abea10a..5cc2059 100644 --- a/examples/validation/PyVistaInt64.py +++ b/examples/validation/PyVistaInt64.py @@ -1,15 +1,16 @@ """Validate Int64 usage with VTK.js.""" -import pyvista as pv import numpy as np +import pyvista as pv from trame.app import get_server from trame.ui.vuetify import SinglePageLayout -from trame.widgets import vuetify, html -from trame.widgets.vtk import VtkLocalView, VtkRemoteView # Just for using this script in testing from trame_client.utils.testing import enable_testing +from trame.widgets import html, vuetify +from trame.widgets.vtk import VtkLocalView, VtkRemoteView + server = enable_testing(get_server(), "local_rendering_ready") server.client_type = "vue2" state, ctrl = server.state, server.controller @@ -39,20 +40,22 @@ vuetify.VSpacer() html.Div("{{ local_rendering_ready }}", classes="readyCount") - with layout.content: - with vuetify.VContainer( + with ( + layout.content, + vuetify.VContainer( fluid=True, classes="pa-0 fill-height", - ): - with vuetify.VCol(classes="fill-height"): - view = VtkLocalView( - plotter.ren_win, - on_ready="local_rendering_ready++", - ) - ctrl.view_update = view.update - ctrl.view_reset_camera = view.reset_camera - with vuetify.VCol(classes="fill-height"): - VtkRemoteView(plotter.ren_win) + ), + ): + with vuetify.VCol(classes="fill-height"): + view = VtkLocalView( + plotter.ren_win, + on_ready="local_rendering_ready++", + ) + ctrl.view_update = view.update + ctrl.view_reset_camera = view.reset_camera + with vuetify.VCol(classes="fill-height"): + VtkRemoteView(plotter.ren_win) # hide footer layout.footer.hide() diff --git a/examples/validation/PyVistaLookupTable.py b/examples/validation/PyVistaLookupTable.py index d3d5273..6dbd54f 100644 --- a/examples/validation/PyVistaLookupTable.py +++ b/examples/validation/PyVistaLookupTable.py @@ -3,11 +3,13 @@ import pyvista as pv from trame.app import get_server from trame.ui.vuetify import SinglePageLayout -from trame.widgets import vuetify, html, vtk as vtk_widgets # Just for using this script in testing from trame_client.utils.testing import enable_testing +from trame.widgets import html, vuetify +from trame.widgets import vtk as vtk_widgets + server = enable_testing(get_server(), "local_rendering_ready") server.client_type = "vue2" state, ctrl = server.state, server.controller @@ -38,37 +40,39 @@ vuetify.VSpacer() html.Div("{{ local_rendering_ready }}", classes="readyCount") - with layout.content: - with vuetify.VContainer( + with ( + layout.content, + vuetify.VContainer( fluid=True, classes="pa-0 fill-height", + ), + ): + with vuetify.VContainer( + fluid=True, classes="pa-0 fill-height", style="width: 50%;" + ): + local = vtk_widgets.VtkLocalView( + plotter.ren_win, + on_ready="local_rendering_ready++", + ) + with vuetify.VContainer( + fluid=True, classes="pa-0 fill-height", style="width: 50%;" ): - with vuetify.VContainer( - fluid=True, classes="pa-0 fill-height", style="width: 50%;" - ): - local = vtk_widgets.VtkLocalView( - plotter.ren_win, - on_ready="local_rendering_ready++", - ) - with vuetify.VContainer( - fluid=True, classes="pa-0 fill-height", style="width: 50%;" - ): - remote = vtk_widgets.VtkRemoteView( - plotter.ren_win, - ) - - def view_update(**kwargs): - local.update(**kwargs) - remote.update(**kwargs) - - def view_reset_camera(**kwargs): - local.reset_camera(**kwargs) - remote.reset_camera(**kwargs) - - ctrl.view_update = view_update - ctrl.view_reset_camera = view_reset_camera - - ctrl.on_server_ready.add(view_update) + remote = vtk_widgets.VtkRemoteView( + plotter.ren_win, + ) + + def view_update(**kwargs): + local.update(**kwargs) + remote.update(**kwargs) + + def view_reset_camera(**kwargs): + local.reset_camera(**kwargs) + remote.reset_camera(**kwargs) + + ctrl.view_update = view_update + ctrl.view_reset_camera = view_reset_camera + + ctrl.on_server_ready.add(view_update) # hide footer layout.footer.hide() diff --git a/examples/validation/PyVistaVolumeRendering.py b/examples/validation/PyVistaVolumeRendering.py index 6456387..2c618bf 100644 --- a/examples/validation/PyVistaVolumeRendering.py +++ b/examples/validation/PyVistaVolumeRendering.py @@ -2,15 +2,17 @@ import os import sys + import pyvista as pv from trame.app import get_server from trame.ui.vuetify import SinglePageLayout -from trame.widgets import vuetify, html -from trame.widgets.vtk import VtkLocalView, VtkRemoteView # Just for using this script in testing from trame_client.utils.testing import enable_testing +from trame.widgets import html, vuetify +from trame.widgets.vtk import VtkLocalView, VtkRemoteView + if os.environ.get("PYTEST_CURRENT_TEST") or "--test" in sys.argv: server = enable_testing(get_server(), "local_rendering_ready") else: @@ -48,24 +50,26 @@ def update_local_rendering(): html.Div("{{ local_rendering_ready }}", classes="readyCount") vuetify.VBtn("Update", click=update_local_rendering) - with layout.content: - with vuetify.VContainer( + with ( + layout.content, + vuetify.VContainer( fluid=True, classes="pa-0 fill-height", - ): - with vuetify.VCol(classes="fill-height"): - view = VtkLocalView( - plotter.ren_win, - ref="local", - on_ready="local_rendering_ready++", - ) - ctrl.view_update = view.update - ctrl.view_reset_camera = view.reset_camera - with vuetify.VCol(classes="fill-height"): - VtkRemoteView( - plotter.ren_win, - ref="remote", - ) + ), + ): + with vuetify.VCol(classes="fill-height"): + view = VtkLocalView( + plotter.ren_win, + ref="local", + on_ready="local_rendering_ready++", + ) + ctrl.view_update = view.update + ctrl.view_reset_camera = view.reset_camera + with vuetify.VCol(classes="fill-height"): + VtkRemoteView( + plotter.ren_win, + ref="remote", + ) # hide footer layout.footer.hide() diff --git a/examples/validation/SwitchView.py b/examples/validation/SwitchView.py index 103ca6d..dc531f6 100644 --- a/examples/validation/SwitchView.py +++ b/examples/validation/SwitchView.py @@ -2,11 +2,16 @@ import asyncio -from trame.app import get_server, asynchronous - +# Required for interactor initialization +import vtkmodules.vtkRenderingOpenGL2 # noqa: F401 +from trame.app import asynchronous, get_server from trame.ui.vuetify import VAppLayout -from trame.widgets import vtk, vuetify - +from vtkmodules.vtkCommonColor import vtkNamedColors +from vtkmodules.vtkFiltersSources import vtkConeSource, vtkSphereSource +from vtkmodules.vtkInteractionStyle import ( + vtkInteractorStyleSwitch, # noqa: F401 + vtkInteractorStyleTrackballCamera, +) from vtkmodules.vtkRenderingCore import ( vtkActor, vtkPolyDataMapper, @@ -15,15 +20,7 @@ vtkRenderWindowInteractor, ) -from vtkmodules.vtkFiltersSources import vtkConeSource, vtkSphereSource -from vtkmodules.vtkCommonColor import vtkNamedColors -from vtkmodules.vtkInteractionStyle import vtkInteractorStyleTrackballCamera - - -# Required for interactor initialization -import vtkmodules.vtkRenderingOpenGL2 # noqa -from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa - +from trame.widgets import vtk, vuetify # ----------------------------------------------------------------------------- # VTK pipeline @@ -116,15 +113,11 @@ def sphere(): @asynchronous.task -async def refresh_function(**kwargs): +async def refresh_function(**_): counter = 1 while True: with state: - if counter % 2 == 0: - ren_win = sphere_window - else: - ren_win = cone_window - + ren_win = sphere_window if (counter % 2 == 0) else cone_window view.replace_view(ren_win) ctrl.view_update() @@ -138,12 +131,11 @@ async def refresh_function(**kwargs): # ----------------------------------------------------------------------------- -with VAppLayout(server) as layout: - with layout.root: - with vuetify.VContainer(fluid=True, classes="pa-0 fill-height"): - view = vtk.VtkLocalView(cone_window) - ctrl.view_update = view.update - ctrl.on_server_ready.add(refresh_function) +with VAppLayout(server) as layout, layout.root: + with vuetify.VContainer(fluid=True, classes="pa-0 fill-height"): + view = vtk.VtkLocalView(cone_window) + ctrl.view_update = view.update + ctrl.on_server_ready.add(refresh_function) # ----------------------------------------------------------------------------- diff --git a/examples/validation/VolumeRendering.py b/examples/validation/VolumeRendering.py index 0d0a557..9c1b814 100644 --- a/examples/validation/VolumeRendering.py +++ b/examples/validation/VolumeRendering.py @@ -1,13 +1,13 @@ import vtk - from trame.app import get_server from trame.ui.vuetify import SinglePageLayout -from trame.widgets import vuetify, html -from trame.widgets.vtk import VtkLocalView, VtkRemoteView # Just for using this script in testing from trame_client.utils.testing import enable_testing +from trame.widgets import html, vuetify +from trame.widgets.vtk import VtkLocalView, VtkRemoteView + server = enable_testing(get_server(), "local_rendering_ready") server.client_type = "vue2" state, ctrl = server.state, server.controller @@ -85,19 +85,21 @@ vuetify.VSpacer() html.Div("{{ local_rendering_ready }}", classes="readyCount") - with layout.content: - with vuetify.VContainer( + with ( + layout.content, + vuetify.VContainer( fluid=True, classes="pa-0 fill-height", + ), + ): + with vuetify.VContainer( + fluid=True, classes="pa-0 fill-height", style="width: 50%;" + ): + local = VtkLocalView(renWin, on_ready="local_rendering_ready++") + with vuetify.VContainer( + fluid=True, classes="pa-0 fill-height", style="width: 50%;" ): - with vuetify.VContainer( - fluid=True, classes="pa-0 fill-height", style="width: 50%;" - ): - local = VtkLocalView(renWin, on_ready="local_rendering_ready++") - with vuetify.VContainer( - fluid=True, classes="pa-0 fill-height", style="width: 50%;" - ): - VtkRemoteView(renWin, ctx_name="remote") + VtkRemoteView(renWin, ctx_name="remote") # hide footer layout.footer.hide() diff --git a/examples/validation/VtkRayCast.py b/examples/validation/VtkRayCast.py old mode 100644 new mode 100755 index a78038d..6201c7f --- a/examples/validation/VtkRayCast.py +++ b/examples/validation/VtkRayCast.py @@ -1,25 +1,22 @@ #!/usr/bin/env python # Web imports -from trame.app import get_server -from trame.ui.vuetify import SinglePageLayout -from trame.widgets import vtk, vuetify - # ----------------------------------------------------------------------------- # Example: SimpleRayCast # taken from: https://kitware.github.io/vtk-examples/site/Python/ # ----------------------------------------------------------------------------- - # noinspection PyUnresolvedReferences -import vtkmodules.vtkInteractionStyle # noqa +import vtkmodules.vtkInteractionStyle # noqa: F401 +from trame.app import get_server +from trame.ui.vuetify import SinglePageLayout from vtkmodules.vtkCommonColor import vtkNamedColors from vtkmodules.vtkCommonDataModel import vtkPiecewiseFunction from vtkmodules.vtkIOLegacy import vtkStructuredPointsReader from vtkmodules.vtkRenderingCore import ( vtkColorTransferFunction, + vtkRenderer, vtkRenderWindow, vtkRenderWindowInteractor, - vtkRenderer, vtkVolume, vtkVolumeProperty, ) @@ -27,9 +24,11 @@ # noinspection PyUnresolvedReferences from vtkmodules.vtkRenderingVolumeOpenGL2 import ( - vtkOpenGLRayCastImageDisplayHelper, # noqa + vtkOpenGLRayCastImageDisplayHelper, # noqa: F401 ) +from trame.widgets import vtk, vuetify + # FIXME DATA_FILE = "/Users/sebastien.jourdain/Documents/code/web/trame-suite/trame-tutorial/data/ironProt.vtk" @@ -105,13 +104,15 @@ with SinglePageLayout(server) as layout: layout.title.set_text("Hello trame") - with layout.content: - with vuetify.VContainer( + with ( + layout.content, + vuetify.VContainer( fluid=True, classes="pa-0 fill-height", - ): - # view = vtk.VtkRemoteView(renWin) - view = vtk.VtkLocalView(renWin) + ), + ): + # view = vtk.VtkRemoteView(renWin) + view = vtk.VtkLocalView(renWin) # ----------------------------------------------------------------------------- diff --git a/examples/vue2/cone-client.py b/examples/vue2/cone-client.py index a31373a..dce455f 100644 --- a/examples/vue2/cone-client.py +++ b/examples/vue2/cone-client.py @@ -1,7 +1,9 @@ from trame.app import get_server -from trame.widgets import vuetify, vtk as vtk_widgets from trame.ui.vuetify import SinglePageLayout +from trame.widgets import vtk as vtk_widgets +from trame.widgets import vuetify + # ----------------------------------------------------------------------------- # Trame initialization # ----------------------------------------------------------------------------- @@ -38,18 +40,20 @@ def update_reset_resolution(): with vuetify.VBtn(icon=True, click=update_reset_resolution): vuetify.VIcon("mdi-undo-variant") - with layout.content: - with vuetify.VContainer( + with ( + layout.content, + vuetify.VContainer( fluid=True, classes="pa-0 fill-height", - ): - with vtk_widgets.VtkView() as view: - ctrl.view_update = view.update - ctrl.view_reset_camera = view.reset_camera - with vtk_widgets.VtkGeometryRepresentation(): - vtk_widgets.VtkAlgorithm( - vtk_class="vtkConeSource", state=("{ resolution }",) - ) + ), + vtk_widgets.VtkView() as view, + ): + ctrl.view_update = view.update + ctrl.view_reset_camera = view.reset_camera + with vtk_widgets.VtkGeometryRepresentation(): + vtk_widgets.VtkAlgorithm( + vtk_class="vtkConeSource", state=("{ resolution }",) + ) server.start() diff --git a/examples/vue2/cone-local.py b/examples/vue2/cone-local.py index 6897b38..9558381 100644 --- a/examples/vue2/cone-local.py +++ b/examples/vue2/cone-local.py @@ -1,19 +1,20 @@ +import vtkmodules.vtkRenderingOpenGL2 # noqa: F401 from trame.app import get_server -from trame.widgets import vuetify, vtk as vtk_widgets from trame.ui.vuetify import SinglePageLayout - from vtkmodules.vtkFiltersSources import vtkConeSource + +# VTK factory initialization +from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa: F401 from vtkmodules.vtkRenderingCore import ( + vtkActor, + vtkPolyDataMapper, vtkRenderer, vtkRenderWindow, vtkRenderWindowInteractor, - vtkPolyDataMapper, - vtkActor, ) -# VTK factory initialization -from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa -import vtkmodules.vtkRenderingOpenGL2 # noqa +from trame.widgets import vtk as vtk_widgets +from trame.widgets import vuetify # ----------------------------------------------------------------------------- # Trame initialization @@ -51,7 +52,7 @@ @state.change("resolution") -def update_cone(resolution=DEFAULT_RESOLUTION, **kwargs): +def update_cone(resolution=DEFAULT_RESOLUTION, **_): cone_source.SetResolution(resolution) ctrl.view_update() @@ -79,13 +80,15 @@ def update_reset_resolution(): with vuetify.VBtn(icon=True, click=update_reset_resolution): vuetify.VIcon("mdi-undo-variant") - with layout.content: - with vuetify.VContainer( + with ( + layout.content, + vuetify.VContainer( fluid=True, classes="pa-0 fill-height", - ): - view = vtk_widgets.VtkLocalView(renderWindow) - ctrl.view_update = view.update - ctrl.view_reset_camera = view.reset_camera + ), + ): + view = vtk_widgets.VtkLocalView(renderWindow) + ctrl.view_update = view.update + ctrl.view_reset_camera = view.reset_camera server.start() diff --git a/examples/vue2/cone-remote.py b/examples/vue2/cone-remote.py index e156abb..d47a1a0 100644 --- a/examples/vue2/cone-remote.py +++ b/examples/vue2/cone-remote.py @@ -1,19 +1,20 @@ +import vtkmodules.vtkRenderingOpenGL2 # noqa: F401 from trame.app import get_server -from trame.widgets import vuetify, vtk as vtk_widgets from trame.ui.vuetify import SinglePageLayout - from vtkmodules.vtkFiltersSources import vtkConeSource + +# VTK factory initialization +from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa: F401 from vtkmodules.vtkRenderingCore import ( + vtkActor, + vtkPolyDataMapper, vtkRenderer, vtkRenderWindow, vtkRenderWindowInteractor, - vtkPolyDataMapper, - vtkActor, ) -# VTK factory initialization -from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa -import vtkmodules.vtkRenderingOpenGL2 # noqa +from trame.widgets import vtk as vtk_widgets +from trame.widgets import vuetify # ----------------------------------------------------------------------------- # Trame initialization @@ -51,7 +52,7 @@ @state.change("resolution") -def update_cone(resolution=DEFAULT_RESOLUTION, **kwargs): +def update_cone(resolution=DEFAULT_RESOLUTION, **_): cone_source.SetResolution(resolution) ctrl.view_update() @@ -79,13 +80,15 @@ def update_reset_resolution(): with vuetify.VBtn(icon=True, click=update_reset_resolution): vuetify.VIcon("mdi-undo-variant") - with layout.content: - with vuetify.VContainer( + with ( + layout.content, + vuetify.VContainer( fluid=True, classes="pa-0 fill-height", - ): - view = vtk_widgets.VtkRemoteView(renderWindow) - ctrl.view_update = view.update - ctrl.view_reset_camera = view.reset_camera + ), + ): + view = vtk_widgets.VtkRemoteView(renderWindow) + ctrl.view_update = view.update + ctrl.view_reset_camera = view.reset_camera server.start() diff --git a/examples/vue2/cone-toggle.py b/examples/vue2/cone-toggle.py index 0567cb7..37f9250 100644 --- a/examples/vue2/cone-toggle.py +++ b/examples/vue2/cone-toggle.py @@ -1,19 +1,20 @@ +import vtkmodules.vtkRenderingOpenGL2 # noqa: F401 from trame.app import get_server -from trame.widgets import html, vuetify, vtk as vtk_widgets from trame.ui.vuetify import SinglePageLayout - from vtkmodules.vtkFiltersSources import vtkConeSource + +# VTK factory initialization +from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa: F401 from vtkmodules.vtkRenderingCore import ( + vtkActor, + vtkPolyDataMapper, vtkRenderer, vtkRenderWindow, vtkRenderWindowInteractor, - vtkPolyDataMapper, - vtkActor, ) -# VTK factory initialization -from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa -import vtkmodules.vtkRenderingOpenGL2 # noqa +from trame.widgets import html, vuetify +from trame.widgets import vtk as vtk_widgets # ----------------------------------------------------------------------------- # Trame initialization @@ -51,7 +52,7 @@ @state.change("resolution") -def update_cone(resolution=DEFAULT_RESOLUTION, **kwargs): +def update_cone(resolution=DEFAULT_RESOLUTION, **_): cone_source.SetResolution(resolution) ctrl.view_update() @@ -89,15 +90,17 @@ def update_reset_resolution(): with vuetify.VBtn(icon=True, click=update_reset_resolution): vuetify.VIcon("mdi-undo-variant") - with layout.content: - with vuetify.VContainer( + with ( + layout.content, + vuetify.VContainer( fluid=True, classes="pa-0 fill-height", - ): - view = vtk_widgets.VtkRemoteLocalView(renderWindow, mode=("mode",)) - ctrl.view_update = view.update - ctrl.view_reset_camera = view.reset_camera - view.push_remote_camera_on_end_interaction() + ), + ): + view = vtk_widgets.VtkRemoteLocalView(renderWindow, mode=("mode",)) + ctrl.view_update = view.update + ctrl.view_reset_camera = view.reset_camera + view.push_remote_camera_on_end_interaction() server.start() diff --git a/examples/vue2/pv-cone-toggle.py b/examples/vue2/pv-cone-toggle.py index f1a7d91..f77cf42 100644 --- a/examples/vue2/pv-cone-toggle.py +++ b/examples/vue2/pv-cone-toggle.py @@ -1,9 +1,9 @@ -import paraview.web.venv # noqa +from paraview import simple from trame.app import get_server -from trame.widgets import html, vuetify, vtk as vtk_widgets from trame.ui.vuetify import SinglePageLayout -from paraview import simple +from trame.widgets import html, vuetify +from trame.widgets import vtk as vtk_widgets # ----------------------------------------------------------------------------- # Trame initialization @@ -27,7 +27,7 @@ @state.change("resolution") -def update_cone(resolution=DEFAULT_RESOLUTION, **kwargs): +def update_cone(resolution=DEFAULT_RESOLUTION, **_): cone.Resolution = resolution ctrl.view_update() @@ -65,15 +65,17 @@ def update_reset_resolution(): with vuetify.VBtn(icon=True, click=update_reset_resolution): vuetify.VIcon("mdi-undo-variant") - with layout.content: - with vuetify.VContainer( + with ( + layout.content, + vuetify.VContainer( fluid=True, classes="pa-0 fill-height", - ): - html_view = vtk_widgets.VtkRemoteLocalView(view, mode=("mode",)) - ctrl.view_update = html_view.update - ctrl.view_reset_camera = html_view.reset_camera - html_view.push_remote_camera_on_end_interaction() + ), + ): + html_view = vtk_widgets.VtkRemoteLocalView(view, mode=("mode",)) + ctrl.view_update = html_view.update + ctrl.view_reset_camera = html_view.reset_camera + html_view.push_remote_camera_on_end_interaction() server.start() diff --git a/examples/vue2/vtkjs-mesh.py b/examples/vue2/vtkjs-mesh.py index cf3040a..0d23bd4 100644 --- a/examples/vue2/vtkjs-mesh.py +++ b/examples/vue2/vtkjs-mesh.py @@ -1,9 +1,10 @@ from trame.app import get_server -from trame.widgets import vuetify, vtk as vtk_widgets from trame.ui.vuetify import SinglePageLayout - from vtkmodules.vtkImagingCore import vtkRTAnalyticSource +from trame.widgets import vtk as vtk_widgets +from trame.widgets import vuetify + # ----------------------------------------------------------------------------- # Trame initialization # ----------------------------------------------------------------------------- @@ -15,18 +16,17 @@ with SinglePageLayout(server) as layout: layout.icon.click = ctrl.view_reset_camera - with layout.content: - with vuetify.VContainer(fluid=True, classes="pa-0 fill-height"): - with vtk_widgets.VtkView() as view: - ctrl.view_reset_camera = view.reset_camera - with vtk_widgets.VtkGeometryRepresentation( - color_data_range=("[20, 280]",), - ): - vtk_widgets.VtkMesh( - "wavelet", - dataset=vtkRTAnalyticSource(), - field_to_keep="RTData", - ) + with layout.content, vuetify.VContainer(fluid=True, classes="pa-0 fill-height"): + with vtk_widgets.VtkView() as view: + ctrl.view_reset_camera = view.reset_camera + with vtk_widgets.VtkGeometryRepresentation( + color_data_range=("[20, 280]",), + ): + vtk_widgets.VtkMesh( + "wavelet", + dataset=vtkRTAnalyticSource(), + field_to_keep="RTData", + ) server.start() diff --git a/examples/vue2/vtkjs-pipeline.py b/examples/vue2/vtkjs-pipeline.py index 792cd4e..8cd07cf 100644 --- a/examples/vue2/vtkjs-pipeline.py +++ b/examples/vue2/vtkjs-pipeline.py @@ -1,7 +1,9 @@ from trame.app import get_server -from trame.widgets import vuetify, vtk as vtk_widgets from trame.ui.vuetify import SinglePageLayout +from trame.widgets import vtk as vtk_widgets +from trame.widgets import vuetify + # ----------------------------------------------------------------------------- # Trame initialization # ----------------------------------------------------------------------------- diff --git a/examples/vue2/vtkjs-polydata.py b/examples/vue2/vtkjs-polydata.py index 272789b..308e559 100644 --- a/examples/vue2/vtkjs-polydata.py +++ b/examples/vue2/vtkjs-polydata.py @@ -1,9 +1,10 @@ from trame.app import get_server -from trame.widgets import vuetify, vtk as vtk_widgets from trame.ui.vuetify import SinglePageLayout - from vtkmodules.vtkFiltersSources import vtkConeSource +from trame.widgets import vtk as vtk_widgets +from trame.widgets import vuetify + # ----------------------------------------------------------------------------- # Trame initialization # ----------------------------------------------------------------------------- @@ -19,7 +20,7 @@ @state.change("resolution") -def update_cone(resolution, **kwargs): +def update_cone(resolution, **_): cone_generator.SetResolution(resolution) ctrl.mesh_update() @@ -46,19 +47,19 @@ def update_reset_resolution(): with vuetify.VBtn(icon=True, click=update_reset_resolution): vuetify.VIcon("mdi-undo-variant") - with layout.content: - with vuetify.VContainer( + with ( + layout.content, + vuetify.VContainer( fluid=True, classes="pa-0 fill-height", - ): - with vtk_widgets.VtkView() as view: - ctrl.view_update = view.update - ctrl.view_reset_camera = view.reset_camera - with vtk_widgets.VtkGeometryRepresentation(): - html_polydata = vtk_widgets.VtkPolyData( - "cone", dataset=cone_generator - ) - ctrl.mesh_update = html_polydata.update + ), + vtk_widgets.VtkView() as view, + ): + ctrl.view_update = view.update + ctrl.view_reset_camera = view.reset_camera + with vtk_widgets.VtkGeometryRepresentation(): + html_polydata = vtk_widgets.VtkPolyData("cone", dataset=cone_generator) + ctrl.mesh_update = html_polydata.update server.start() diff --git a/examples/vue3/cone-client.py b/examples/vue3/cone-client.py index 4da2256..c281b91 100644 --- a/examples/vue3/cone-client.py +++ b/examples/vue3/cone-client.py @@ -1,7 +1,9 @@ from trame.app import get_server -from trame.widgets import vuetify3, vtk as vtk_widgets from trame.ui.vuetify3 import SinglePageLayout +from trame.widgets import vtk as vtk_widgets +from trame.widgets import vuetify3 + # ----------------------------------------------------------------------------- # Trame initialization # ----------------------------------------------------------------------------- @@ -39,19 +41,21 @@ def update_reset_resolution(): with vuetify3.VBtn(icon=True, click=update_reset_resolution): vuetify3.VIcon("mdi-undo-variant") - with layout.content: - with vuetify3.VContainer( + with ( + layout.content, + vuetify3.VContainer( fluid=True, classes="pa-0 fill-height", - ): - with vtk_widgets.VtkView() as view: - ctrl.view_update = view.update - ctrl.view_reset_camera = view.reset_camera - with vtk_widgets.VtkGeometryRepresentation(): - vtk_widgets.VtkAlgorithm( - vtk_class="vtkConeSource", - state=("{ resolution }",), - ) + ), + vtk_widgets.VtkView() as view, + ): + ctrl.view_update = view.update + ctrl.view_reset_camera = view.reset_camera + with vtk_widgets.VtkGeometryRepresentation(): + vtk_widgets.VtkAlgorithm( + vtk_class="vtkConeSource", + state=("{ resolution }",), + ) server.start() diff --git a/examples/vue3/cone-local.py b/examples/vue3/cone-local.py index 3b1980a..9970049 100644 --- a/examples/vue3/cone-local.py +++ b/examples/vue3/cone-local.py @@ -1,19 +1,20 @@ +import vtkmodules.vtkRenderingOpenGL2 # noqa: F401 from trame.app import get_server -from trame.widgets import vuetify3, vtk as vtk_widgets from trame.ui.vuetify3 import SinglePageLayout - from vtkmodules.vtkFiltersSources import vtkConeSource + +# VTK factory initialization +from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa: F401 from vtkmodules.vtkRenderingCore import ( + vtkActor, + vtkPolyDataMapper, vtkRenderer, vtkRenderWindow, vtkRenderWindowInteractor, - vtkPolyDataMapper, - vtkActor, ) -# VTK factory initialization -from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa -import vtkmodules.vtkRenderingOpenGL2 # noqa +from trame.widgets import vtk as vtk_widgets +from trame.widgets import vuetify3 # ----------------------------------------------------------------------------- # Trame initialization @@ -51,7 +52,7 @@ @state.change("resolution") -def update_cone(resolution=DEFAULT_RESOLUTION, **kwargs): +def update_cone(resolution=DEFAULT_RESOLUTION, **_): cone_source.SetResolution(resolution) ctrl.view_update() @@ -80,13 +81,15 @@ def update_reset_resolution(): with vuetify3.VBtn(icon=True, click=update_reset_resolution): vuetify3.VIcon("mdi-undo-variant") - with layout.content: - with vuetify3.VContainer( + with ( + layout.content, + vuetify3.VContainer( fluid=True, classes="pa-0 fill-height", - ): - view = vtk_widgets.VtkLocalView(renderWindow) - ctrl.view_update = view.update - ctrl.view_reset_camera = view.reset_camera + ), + ): + view = vtk_widgets.VtkLocalView(renderWindow) + ctrl.view_update = view.update + ctrl.view_reset_camera = view.reset_camera server.start() diff --git a/examples/vue3/cone-remote.py b/examples/vue3/cone-remote.py index bc7e8cf..b9d48e7 100644 --- a/examples/vue3/cone-remote.py +++ b/examples/vue3/cone-remote.py @@ -1,19 +1,20 @@ +import vtkmodules.vtkRenderingOpenGL2 # noqa: F401 from trame.app import get_server -from trame.widgets import vuetify3, vtk as vtk_widgets from trame.ui.vuetify3 import SinglePageLayout - from vtkmodules.vtkFiltersSources import vtkConeSource + +# VTK factory initialization +from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa: F401 from vtkmodules.vtkRenderingCore import ( + vtkActor, + vtkPolyDataMapper, vtkRenderer, vtkRenderWindow, vtkRenderWindowInteractor, - vtkPolyDataMapper, - vtkActor, ) -# VTK factory initialization -from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa -import vtkmodules.vtkRenderingOpenGL2 # noqa +from trame.widgets import vtk as vtk_widgets +from trame.widgets import vuetify3 # ----------------------------------------------------------------------------- # Trame initialization @@ -51,7 +52,7 @@ @state.change("resolution") -def update_cone(resolution=DEFAULT_RESOLUTION, **kwargs): +def update_cone(resolution=DEFAULT_RESOLUTION, **_): cone_source.SetResolution(resolution) ctrl.view_update() @@ -81,13 +82,15 @@ def update_reset_resolution(): with vuetify3.VBtn(icon=True, click=update_reset_resolution): vuetify3.VIcon("mdi-undo-variant") - with layout.content: - with vuetify3.VContainer( + with ( + layout.content, + vuetify3.VContainer( fluid=True, classes="pa-0 fill-height", - ): - view = vtk_widgets.VtkRemoteView(renderWindow) - ctrl.view_update = view.update - ctrl.view_reset_camera = view.reset_camera + ), + ): + view = vtk_widgets.VtkRemoteView(renderWindow) + ctrl.view_update = view.update + ctrl.view_reset_camera = view.reset_camera server.start() diff --git a/examples/vue3/cone-toggle.py b/examples/vue3/cone-toggle.py index 5b6b573..b98ceab 100644 --- a/examples/vue3/cone-toggle.py +++ b/examples/vue3/cone-toggle.py @@ -1,19 +1,20 @@ +import vtkmodules.vtkRenderingOpenGL2 # noqa: F401 from trame.app import get_server -from trame.widgets import html, vuetify3, vtk as vtk_widgets from trame.ui.vuetify3 import SinglePageLayout - from vtkmodules.vtkFiltersSources import vtkConeSource + +# VTK factory initialization +from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa: F401 from vtkmodules.vtkRenderingCore import ( + vtkActor, + vtkPolyDataMapper, vtkRenderer, vtkRenderWindow, vtkRenderWindowInteractor, - vtkPolyDataMapper, - vtkActor, ) -# VTK factory initialization -from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa -import vtkmodules.vtkRenderingOpenGL2 # noqa +from trame.widgets import html, vuetify3 +from trame.widgets import vtk as vtk_widgets # ----------------------------------------------------------------------------- # Trame initialization @@ -51,7 +52,7 @@ @state.change("resolution") -def update_cone(resolution=DEFAULT_RESOLUTION, **kwargs): +def update_cone(resolution=DEFAULT_RESOLUTION, **_): cone_source.SetResolution(resolution) ctrl.view_update() @@ -91,14 +92,16 @@ def update_reset_resolution(): with vuetify3.VBtn(icon=True, click=update_reset_resolution): vuetify3.VIcon("mdi-undo-variant") - with layout.content: - with vuetify3.VContainer( + with ( + layout.content, + vuetify3.VContainer( fluid=True, classes="pa-0 fill-height", - ): - view = vtk_widgets.VtkRemoteLocalView(renderWindow, mode=("mode",)) - ctrl.view_update = view.update - ctrl.view_reset_camera = view.reset_camera - view.push_remote_camera_on_end_interaction() + ), + ): + view = vtk_widgets.VtkRemoteLocalView(renderWindow, mode=("mode",)) + ctrl.view_update = view.update + ctrl.view_reset_camera = view.reset_camera + view.push_remote_camera_on_end_interaction() server.start() diff --git a/examples/vue3/cone-webxr.py b/examples/vue3/cone-webxr.py index a9c3334..9e0581d 100644 --- a/examples/vue3/cone-webxr.py +++ b/examples/vue3/cone-webxr.py @@ -1,19 +1,20 @@ +import vtkmodules.vtkRenderingOpenGL2 # noqa: F401 from trame.app import get_server -from trame.widgets import vuetify3, vtk as vtk_widgets from trame.ui.vuetify3 import SinglePageLayout - from vtkmodules.vtkFiltersSources import vtkConeSource + +# VTK factory initialization +from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa: F401 from vtkmodules.vtkRenderingCore import ( + vtkActor, + vtkPolyDataMapper, vtkRenderer, vtkRenderWindow, vtkRenderWindowInteractor, - vtkPolyDataMapper, - vtkActor, ) -# VTK factory initialization -from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa -import vtkmodules.vtkRenderingOpenGL2 # noqa +from trame.widgets import vtk as vtk_widgets +from trame.widgets import vuetify3 # ----------------------------------------------------------------------------- # Trame initialization @@ -53,7 +54,7 @@ @state.change("resolution") -def update_cone(resolution=DEFAULT_RESOLUTION, **kwargs): +def update_cone(resolution=DEFAULT_RESOLUTION, **_): cone_source.SetResolution(resolution) ctrl.view_update() @@ -88,24 +89,26 @@ def toggle_xr(): with vuetify3.VBtn(icon=True, click=toggle_xr): vuetify3.VIcon("mdi-virtual-reality") - with layout.content: - with vuetify3.VContainer( + with ( + layout.content, + vuetify3.VContainer( fluid=True, classes="pa-0 fill-height", - ): - with vtk_widgets.VtkLocalView(renderWindow) as view: - ctrl.view_update = view.update + ), + vtk_widgets.VtkLocalView(renderWindow) as view, + ): + ctrl.view_update = view.update - def on_enter_xr(): - state.xr_active = True + def on_enter_xr(): + state.xr_active = True - def on_exit_xr(): - state.xr_active = False + def on_exit_xr(): + state.xr_active = False - webxr_helper = vtk_widgets.VtkWebXRHelper( - draw_controllers_ray=True, enter_xr=on_enter_xr, exit_xr=on_exit_xr - ) - ctrl.start_xr = webxr_helper.start_xr - ctrl.stop_xr = webxr_helper.stop_xr + webxr_helper = vtk_widgets.VtkWebXRHelper( + draw_controllers_ray=True, enter_xr=on_enter_xr, exit_xr=on_exit_xr + ) + ctrl.start_xr = webxr_helper.start_xr + ctrl.stop_xr = webxr_helper.stop_xr server.start() diff --git a/examples/vue3/vtkjs-mesh.py b/examples/vue3/vtkjs-mesh.py index 3f8577e..2e53f8f 100644 --- a/examples/vue3/vtkjs-mesh.py +++ b/examples/vue3/vtkjs-mesh.py @@ -1,9 +1,10 @@ from trame.app import get_server -from trame.widgets import vuetify3, vtk as vtk_widgets from trame.ui.vuetify3 import SinglePageLayout - from vtkmodules.vtkImagingCore import vtkRTAnalyticSource +from trame.widgets import vtk as vtk_widgets +from trame.widgets import vuetify3 + # ----------------------------------------------------------------------------- # Trame initialization # ----------------------------------------------------------------------------- diff --git a/examples/vue3/vtkjs-pipeline.py b/examples/vue3/vtkjs-pipeline.py index 80ee35e..e538220 100644 --- a/examples/vue3/vtkjs-pipeline.py +++ b/examples/vue3/vtkjs-pipeline.py @@ -1,7 +1,9 @@ from trame.app import get_server -from trame.widgets import vuetify3, vtk as vtk_widgets from trame.ui.vuetify3 import SinglePageLayout +from trame.widgets import vtk as vtk_widgets +from trame.widgets import vuetify3 + # ----------------------------------------------------------------------------- # Trame initialization # ----------------------------------------------------------------------------- diff --git a/examples/vue3/vtkjs-polydata.py b/examples/vue3/vtkjs-polydata.py index 656a807..0624fd6 100644 --- a/examples/vue3/vtkjs-polydata.py +++ b/examples/vue3/vtkjs-polydata.py @@ -1,9 +1,10 @@ from trame.app import get_server -from trame.widgets import vuetify3, vtk as vtk_widgets from trame.ui.vuetify3 import SinglePageLayout - from vtkmodules.vtkFiltersSources import vtkConeSource +from trame.widgets import vtk as vtk_widgets +from trame.widgets import vuetify3 + # ----------------------------------------------------------------------------- # Trame initialization # ----------------------------------------------------------------------------- @@ -19,7 +20,7 @@ @state.change("resolution") -def update_cone(resolution, **kwargs): +def update_cone(resolution, **_): cone_generator.SetResolution(resolution) ctrl.mesh_update() @@ -49,19 +50,19 @@ def update_reset_resolution(): with vuetify3.VBtn(icon=True, click=update_reset_resolution): vuetify3.VIcon("mdi-undo-variant") - with layout.content: - with vuetify3.VContainer( + with ( + layout.content, + vuetify3.VContainer( fluid=True, classes="pa-0 fill-height", - ): - with vtk_widgets.VtkView() as view: - ctrl.view_update = view.update - ctrl.view_reset_camera = view.reset_camera - with vtk_widgets.VtkGeometryRepresentation(): - html_polydata = vtk_widgets.VtkPolyData( - "cone", dataset=cone_generator - ) - ctrl.mesh_update = html_polydata.update + ), + vtk_widgets.VtkView() as view, + ): + ctrl.view_update = view.update + ctrl.view_reset_camera = view.reset_camera + with vtk_widgets.VtkGeometryRepresentation(): + html_polydata = vtk_widgets.VtkPolyData("cone", dataset=cone_generator) + ctrl.mesh_update = html_polydata.update server.start() diff --git a/examples/widgets/clip.py b/examples/widgets/clip.py index 46c2db0..e084857 100644 --- a/examples/widgets/clip.py +++ b/examples/widgets/clip.py @@ -1,25 +1,24 @@ +import vtkmodules.vtkRenderingOpenGL2 # noqa: F401 from trame.app import get_server -from trame.widgets import vuetify, vtk as vtk_widgets from trame.ui.vuetify import SinglePageLayout - -# VTK factory initialization -from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa -import vtkmodules.vtkRenderingOpenGL2 # noqa - +from vtkmodules.vtkCommonDataModel import vtkPlane from vtkmodules.vtkFiltersGeneral import vtkClipDataSet from vtkmodules.vtkFiltersModeling import vtkOutlineFilter from vtkmodules.vtkImagingCore import vtkRTAnalyticSource -from vtkmodules.vtkCommonDataModel import vtkPlane + +# VTK factory initialization +from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa: F401 from vtkmodules.vtkInteractionWidgets import vtkImplicitPlaneWidget2 from vtkmodules.vtkRenderingCore import ( vtkActor, vtkDataSetMapper, + vtkRenderer, vtkRenderWindow, vtkRenderWindowInteractor, - vtkRenderer, ) - +from trame.widgets import vtk as vtk_widgets +from trame.widgets import vuetify from trame_vtk.modules.vtk.widget import WidgetManager # ----------------------------------------------------------------------------- @@ -77,12 +76,12 @@ plane_widget = widget_manager.add_widget(vtkImplicitPlaneWidget2) -def on_widget_interaction(*args): +def on_widget_interaction(*_): if state.live_update: plane_widget.GetPlane(clip_plane) -def on_widget_done(*args): +def on_widget_done(*_): plane_widget.GetPlane(clip_plane) @@ -102,7 +101,7 @@ def on_widget_done(*args): @state.change("show_widget") -def on_widget_show(show_widget, **kwargs): +def on_widget_show(show_widget, **_): if show_widget: plane_widget.enable() else: @@ -134,14 +133,13 @@ def on_widget_show(show_widget, **kwargs): with vuetify.VBtn(icon=True, click=ctrl.view_reset_camera): vuetify.VIcon("mdi-crop-free") - with layout.content: - with vuetify.VContainer(fluid=True, classes="pa-0 fill-height"): - view = vtk_widgets.VtkRemoteView( - render_window, - interactive_ratio=1, - ) - ctrl.view_reset_camera = view.reset_camera - ctrl.view_update = view.update + with layout.content, vuetify.VContainer(fluid=True, classes="pa-0 fill-height"): + view = vtk_widgets.VtkRemoteView( + render_window, + interactive_ratio=1, + ) + ctrl.view_reset_camera = view.reset_camera + ctrl.view_update = view.update if __name__ == "__main__": diff --git a/pyproject.toml b/pyproject.toml index 0c276ff..746f569 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,7 +20,13 @@ classifiers = [ ] [project.optional-dependencies] -dev = ["pre-commit", "ruff", "pytest", "pytest-asyncio", "coverage", "nox"] +dev = [ + "pre-commit", + "ruff", + "pytest >=6", + "pytest-cov >=3", + "nox", +] [build-system] requires = ["hatchling"] @@ -30,6 +36,8 @@ build-backend = "hatchling.build" [tool.hatch.build] include = [ "/src/**/*.py", + "/src/**/*.js", + "/src/**/*.css", "/src/**/*.html", "/src/trame_vtk/modules/common/serve/**", ] @@ -37,41 +45,63 @@ include = [ [tool.hatch.build.targets.wheel] packages = ["src/trame_vtk", "src/trame"] -[tool.semantic_release] -version_toml = ["pyproject.toml:project.version"] -build_command = """ - python -m venv .venv - source .venv/bin/activate - pip install -U pip build - python -m build . -""" - [tool.semantic_release.publish] dist_glob_patterns = ["dist/*"] upload_to_vcs_release = true [tool.ruff] -line-length = 88 -indent-width = 4 -target-version = "py310" [tool.ruff.lint] -select = ["E", "W", "F"] -ignore = ["E402"] -fixable = ["ALL"] -unfixable = [] +extend-select = [ + "ARG", # flake8-unused-arguments + "B", # flake8-bugbear + "C4", # flake8-comprehensions + "EM", # flake8-errmsg + "EXE", # flake8-executable + "G", # flake8-logging-format + "I", # isort + "ICN", # flake8-import-conventions + "NPY", # NumPy specific rules + "PD", # pandas-vet + "PGH", # pygrep-hooks + "PIE", # flake8-pie + "PL", # pylint + "PT", # flake8-pytest-style + "PTH", # flake8-use-pathlib + "RET", # flake8-return + "RUF", # Ruff-specific + "SIM", # flake8-simplify + "T20", # flake8-print + "UP", # pyupgrade + "YTT", # flake8-2020 +] +ignore = [ + "PLR09", # Too many <...> + "PLR2004", # Magic value used in comparison + "ISC001", # Conflicts with formatter +] +isort.required-imports = [] +[tool.ruff.lint.per-file-ignores] +"tests/**" = ["T20"] +"examples/**" = ["T20", "SIM117"] +"noxfile.py" = ["T20"] +"src/**" = ["SIM117"] -[tool.ruff.format] -quote-style = "double" -indent-style = "space" -skip-magic-trailing-comma = false -line-ending = "auto" -docstring-code-format = true +[tool.semantic_release] +version_toml = [ + "pyproject.toml:project.version", +] +version_variables = [ + "src/trame_vtk/__init__.py:__version__", +] -# This only has an effect when the `docstring-code-format` setting is -# enabled. -docstring-code-line-length = "dynamic" +build_command = """ + python -m pip install -e '.[build]' + uv lock --upgrade-package "$PACKAGE_NAME" + git add uv.lock + uv build +""" [tool.ruff.lint.pycodestyle] max-line-length = 120 diff --git a/src/trame/widgets/paraview.py b/src/trame/widgets/paraview.py index 3bd89aa..7967a43 100644 --- a/src/trame/widgets/paraview.py +++ b/src/trame/widgets/paraview.py @@ -2,7 +2,7 @@ def initialize(server): - from trame_vtk.modules import common, paraview + from trame_vtk.modules import common, paraview # noqa: PLC0415 server.enable_module(common) server.enable_module(paraview) diff --git a/src/trame/widgets/vtk.py b/src/trame/widgets/vtk.py index 2e9ff8e..5b0b6bc 100644 --- a/src/trame/widgets/vtk.py +++ b/src/trame/widgets/vtk.py @@ -2,7 +2,7 @@ def initialize(server): - from trame_vtk.modules import common, vtk + from trame_vtk.modules import common, vtk # noqa: PLC0415 server.enable_module(common) server.enable_module(vtk) diff --git a/src/trame_vtk/__init__.py b/src/trame_vtk/__init__.py index 42e3261..c4afd89 100644 --- a/src/trame_vtk/__init__.py +++ b/src/trame_vtk/__init__.py @@ -8,7 +8,5 @@ def reference_id(ref): try: return ref.__this__[1:17] except Exception: - id_str = str(ref)[-12:-1] - # print('====> fallback ID %s for %s' % (id_str, ref)) - return id_str + return str(ref)[-12:-1] return "0x0" diff --git a/src/trame_vtk/modules/common/__init__.py b/src/trame_vtk/modules/common/__init__.py index bf78c7a..5634cd3 100644 --- a/src/trame_vtk/modules/common/__init__.py +++ b/src/trame_vtk/modules/common/__init__.py @@ -2,7 +2,6 @@ from trame_vtk import __version__ - # Compute local path to serve serve_path = str(Path(__file__).with_name("serve").resolve()) serve_directory = f"__trame_vtk_{__version__}" diff --git a/src/trame_vtk/modules/common/serve/trame-vtk.js b/src/trame_vtk/modules/common/serve/trame-vtk.js index ee2878b..890da5d 100644 --- a/src/trame_vtk/modules/common/serve/trame-vtk.js +++ b/src/trame_vtk/modules/common/serve/trame-vtk.js @@ -3848,7 +3848,7 @@ Input: `+this.err.str)},u.prototype[Symbol.iterator]=function(){return this._ind `,offset:0,width:0,allowEmptyTags:!1,indentTextOnlyNodes:!1,spaceBeforeSlash:!1}),x}return o(h,f),h.prototype.serialize=function(v){return this._refs={suppressPretty:!1,emptyNode:!1,markup:""},v.nodeType!==u.NodeType.Document||this._writerOptions.headless||this.declaration(this._builderOptions.version,this._builderOptions.encoding,this._builderOptions.standalone),this.serializeNode(v,this._writerOptions.wellFormed),this._writerOptions.prettyPrint&&this._refs.markup.slice(-this._writerOptions.newline.length)===this._writerOptions.newline&&(this._refs.markup=this._refs.markup.slice(0,-this._writerOptions.newline.length)),this._refs.markup},h.prototype.declaration=function(v,m,x){this._beginLine(),this._refs.markup+='",this._endLine()},h.prototype.docType=function(v,m,x){this._beginLine(),this._refs.markup+=m&&x?"':m?"':x?"':"",this._endLine()},h.prototype.openTagBegin=function(v){this._beginLine(),this._refs.markup+="<"+v},h.prototype.openTagEnd=function(v,m,x){if(this._refs.suppressPretty=!1,this._refs.emptyNode=!1,this._writerOptions.prettyPrint&&!m&&!x){for(var y=!0,d=!0,g=this.currentNode.firstChild,C=0,S=0;g;){if(p.Guard.isExclusiveTextNode(g))S++;else{if(!p.Guard.isCDATASectionNode(g)){y=!1,d=!1;break}C++}g.data!==""&&(d=!1),g=g.nextSibling}this._refs.suppressPretty=!this._writerOptions.indentTextOnlyNodes&&y&&(C<=1&&S===0||C===0),this._refs.emptyNode=d}(x||m||this._refs.emptyNode)&&this._writerOptions.allowEmptyTags?this._refs.markup+=">":this._refs.markup+=x?" />":m||this._refs.emptyNode?this._writerOptions.spaceBeforeSlash?" />":"/>":">",this._endLine()},h.prototype.closeTag=function(v){this._refs.emptyNode||(this._beginLine(),this._refs.markup+=""),this._refs.suppressPretty=!1,this._refs.emptyNode=!1,this._endLine()},h.prototype.attribute=function(v,m){var x=v+'="'+m+'"';this._writerOptions.prettyPrint&&this._writerOptions.width>0&&this._refs.markup.length-this._lengthToLastNewline+1+x.length>this._writerOptions.width?(this._endLine(),this._beginLine(),this._refs.markup+=this._indent(1)+x):this._refs.markup+=" "+x},h.prototype.text=function(v){v!==""&&(this._beginLine(),this._refs.markup+=v,this._endLine())},h.prototype.cdata=function(v){v!==""&&(this._beginLine(),this._refs.markup+="",this._endLine())},h.prototype.comment=function(v){this._beginLine(),this._refs.markup+="",this._endLine()},h.prototype.instruction=function(v,m){this._beginLine(),this._refs.markup+="",this._endLine()},h.prototype._beginLine=function(){this._writerOptions.prettyPrint&&!this._refs.suppressPretty&&(this._refs.markup+=this._indent(this._writerOptions.offset+this.level))},h.prototype._endLine=function(){this._writerOptions.prettyPrint&&!this._refs.suppressPretty&&(this._refs.markup+=this._writerOptions.newline,this._lengthToLastNewline=this._refs.markup.length)},h.prototype._indent=function(v){if(v<=0)return"";if(this._indentation[v]!==void 0)return this._indentation[v];var m=this._writerOptions.indent.repeat(v);return this._indentation[v]=m,m},h}(c.BaseWriter);n.XMLWriter=l},function(a,n,r){var i=r(47),o=r(35);a.exports="".repeat||function(s){var u=String(o(this)),c="",p=i(s);if(p<0||p==1/0)throw RangeError("Wrong number of repetitions");for(;p>0;(p>>>=1)&&(u+=u))1&p&&(c+=u);return c}},function(a,n,r){r(31),r(32),r(33),r(19),r(178),r(20),r(22),r(23);var i,o=this&&this.__extends||(i=function(l,f){return(i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(h,v){h.__proto__=v}||function(h,v){for(var m in v)v.hasOwnProperty(m)&&(h[m]=v[m])})(l,f)},function(l,f){function h(){this.constructor=l}i(l,f),l.prototype=f===null?Object.create(f):(h.prototype=f.prototype,new h)}),s=this&&this.__values||function(l){var f=typeof Symbol=="function"&&Symbol.iterator,h=f&&l[f],v=0;if(h)return h.call(l);if(l&&typeof l.length=="number")return{next:function(){return l&&v>=l.length&&(l=void 0),{value:l&&l[v++],done:!l}}};throw new TypeError(f?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(n,"__esModule",{value:!0});var u=r(67),c=r(2),p=function(l){function f(h,v){var m=l.call(this,h)||this;return m._writerOptions=c.applyDefaults(v,{wellFormed:!1,prettyPrint:!1,indent:" ",newline:` `,offset:0,group:!1,verbose:!1}),m}return o(f,l),f.prototype.serialize=function(h){var v=c.applyDefaults(this._writerOptions,{format:"object",wellFormed:!1}),m=new u.ObjectWriter(this._builderOptions,v).serialize(h);return this._beginLine(this._writerOptions,0)+this._convertObject(m,this._writerOptions)},f.prototype._convertObject=function(h,v,m){var x,y,d=this;m===void 0&&(m=0);var g="",C=this._isLeafNode(h);if(c.isArray(h)){g+="[";var S=h.length,T=0;try{for(var w=s(h),_=w.next();!_.done;_=w.next()){var E=_.value;g+=this._endLine(v,m+1)+this._beginLine(v,m+1)+this._convertObject(E,v,m+1),T0?new Array(m).join(h.indent):""},f.prototype._endLine=function(h,v){return h.prettyPrint?h.newline:""},f.prototype._key=function(h){return'"'+h+'":'},f.prototype._val=function(h){return JSON.stringify(h)},f.prototype._isLeafNode=function(h){return this._descendantCount(h)<=1},f.prototype._descendantCount=function(h,v){var m=this;return v===void 0&&(v=0),c.isArray(h)?c.forEachArray(h,function(x){return v+=m._descendantCount(x,v)},this):c.isObject(h)?c.forEachObject(h,function(x,y){return v+=m._descendantCount(y,v)},this):v++,v},f}(r(50).BaseWriter);n.JSONWriter=p},function(a,n,r){r(31),r(32),r(33),r(19),r(178),r(89),r(20),r(22),r(23);var i,o=this&&this.__extends||(i=function(l,f){return(i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(h,v){h.__proto__=v}||function(h,v){for(var m in v)v.hasOwnProperty(m)&&(h[m]=v[m])})(l,f)},function(l,f){function h(){this.constructor=l}i(l,f),l.prototype=f===null?Object.create(f):(h.prototype=f.prototype,new h)}),s=this&&this.__values||function(l){var f=typeof Symbol=="function"&&Symbol.iterator,h=f&&l[f],v=0;if(h)return h.call(l);if(l&&typeof l.length=="number")return{next:function(){return l&&v>=l.length&&(l=void 0),{value:l&&l[v++],done:!l}}};throw new TypeError(f?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(n,"__esModule",{value:!0});var u=r(67),c=r(2),p=function(l){function f(h,v){var m=l.call(this,h)||this;if(m._writerOptions=c.applyDefaults(v,{wellFormed:!1,indent:" ",newline:` `,offset:0,group:!1,verbose:!1}),m._writerOptions.indent.length<2)throw new Error("YAML indententation string must be at least two characters long.");if(m._writerOptions.offset<0)throw new Error("YAML offset should be zero or a positive number.");return m}return o(f,l),f.prototype.serialize=function(h){var v=c.applyDefaults(this._writerOptions,{format:"object",wellFormed:!1}),m=new u.ObjectWriter(this._builderOptions,v).serialize(h),x=this._beginLine(this._writerOptions,0)+"---"+this._endLine(this._writerOptions)+this._convertObject(m,this._writerOptions,0);return x.slice(-this._writerOptions.newline.length)===this._writerOptions.newline&&(x=x.slice(0,-this._writerOptions.newline.length)),x},f.prototype._convertObject=function(h,v,m,x){var y,d,g=this;x===void 0&&(x=!1);var C="";if(c.isArray(h))try{for(var S=s(h),T=S.next();!T.done;T=S.next()){var w=T.value;C+=this._beginLine(v,m,!0),c.isObject(w)?c.isEmpty(w)?C+='""'+this._endLine(v):C+=this._convertObject(w,v,m,!0):C+=this._val(w)+this._endLine(v)}}catch(_){y={error:_}}finally{try{T&&!T.done&&(d=S.return)&&d.call(S)}finally{if(y)throw y.error}}else c.forEachObject(h,function(_,E){x?(C+=g._key(_),x=!1):C+=g._beginLine(v,m)+g._key(_),c.isObject(E)?c.isEmpty(E)?C+=' ""'+g._endLine(v):C+=g._endLine(v)+g._convertObject(E,v,m+1):C+=" "+g._val(E)+g._endLine(v)},this);return C},f.prototype._beginLine=function(h,v,m){m===void 0&&(m=!1);var x=h.offset+v+1,y=new Array(x).join(h.indent);return m?y.substr(0,y.length-2)+"-"+y.substr(-1,1):y},f.prototype._endLine=function(h){return h.newline},f.prototype._key=function(h){return'"'+h+'":'},f.prototype._val=function(h){return JSON.stringify(h)},f}(r(50).BaseWriter);n.YAMLWriter=p},function(a,n,r){Object.defineProperty(n,"__esModule",{value:!0}),r(110).dom.setFeatures(!0);var i=r(110);n.DOMImplementation=i.DOMImplementation;var o=r(272);n.DOMParser=o.DOMParser;var s=r(275);n.XMLSerializer=s.XMLSerializer},function(a,n,r){Object.defineProperty(n,"__esModule",{value:!0});var i=r(3),o=r(0),s=function(){function u(){}return u.prototype.before=function(){for(var c=[],p=0;p=p.length&&(p=void 0),{value:p&&p[h++],done:!p}}};throw new TypeError(l?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(n,"__esModule",{value:!0});var o=r(6),s=r(3),u=r(7),c=function(){function p(l){this._nodeList=[],this._recordQueue=[],this._callback=l;var f=o.dom.window;u.set.append(f._mutationObservers,this)}return p.prototype.observe=function(l,f){var h,v;if((f=f||{childList:!1,subtree:!1}).attributeOldValue===void 0&&f.attributeFilter===void 0||f.attributes!==void 0||(f.attributes=!0),f.characterDataOldValue!==void 0&&f.characterData===void 0&&(f.characterData=!0),!f.childList&&!f.attributes&&!f.characterData)throw new TypeError;if(f.attributeOldValue&&!f.attributes)throw new TypeError;if(f.attributeFilter!==void 0&&!f.attributes)throw new TypeError;if(f.characterDataOldValue&&!f.characterData)throw new TypeError;var m=!1,x=f,y=function(S){var T,w;if(S.observer===d){m=!0;try{for(var _=(T=void 0,i(d._nodeList)),E=_.next();!E.done;E=_.next()){var D=E.value;u.list.remove(D._registeredObserverList,function(O){return s.Guard.isTransientRegisteredObserver(O)&&O.source===S})}}catch(O){T={error:O}}finally{try{E&&!E.done&&(w=_.return)&&w.call(_)}finally{if(T)throw T.error}}S.options=x}},d=this;try{for(var g=i(l._registeredObserverList),C=g.next();!C.done;C=g.next())y(C.value)}catch(S){h={error:S}}finally{try{C&&!C.done&&(v=g.return)&&v.call(g)}finally{if(h)throw h.error}}m||(l._registeredObserverList.push({observer:this,options:f}),this._nodeList.push(l))},p.prototype.disconnect=function(){var l,f,h=this;try{for(var v=i(this._nodeList),m=v.next();!m.done;m=v.next()){var x=m.value;u.list.remove(x._registeredObserverList,function(y){return y.observer===h})}}catch(y){l={error:y}}finally{try{m&&!m.done&&(f=v.return)&&f.call(v)}finally{if(l)throw l.error}}this._recordQueue=[]},p.prototype.takeRecords=function(){var l=this._recordQueue;return this._recordQueue=[],l},p}();n.MutationObserverImpl=c},function(a,n,r){Object.defineProperty(n,"__esModule",{value:!0});var i=r(3),o=function(){function s(){}return Object.defineProperty(s.prototype,"previousElementSibling",{get:function(){for(var u=i.Cast.asNode(this)._previousSibling;u;){if(i.Guard.isElementNode(u))return u;u=u._previousSibling}return null},enumerable:!0,configurable:!0}),Object.defineProperty(s.prototype,"nextElementSibling",{get:function(){for(var u=i.Cast.asNode(this)._nextSibling;u;){if(i.Guard.isElementNode(u))return u;u=u._nextSibling}return null},enumerable:!0,configurable:!0}),s}();n.NonDocumentTypeChildNodeImpl=o},function(a,n,r){Object.defineProperty(n,"__esModule",{value:!0});var i=r(3),o=r(0),s=function(){function u(){}return u.prototype.getElementById=function(c){for(var p=o.tree_getFirstDescendantNode(i.Cast.asNode(this),!1,!1,function(l){return i.Guard.isElementNode(l)});p!==null;){if(p._uniqueIdentifier===c)return p;p=o.tree_getNextDescendantNode(i.Cast.asNode(this),p,!1,!1,function(l){return i.Guard.isElementNode(l)})}return null},u}();n.NonElementParentNodeImpl=s},function(a,n,r){var i=this&&this.__values||function(c){var p=typeof Symbol=="function"&&Symbol.iterator,l=p&&c[p],f=0;if(l)return l.call(c);if(c&&typeof c.length=="number")return{next:function(){return c&&f>=c.length&&(c=void 0),{value:c&&c[f++],done:!c}}};throw new TypeError(p?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(n,"__esModule",{value:!0});var o=r(3),s=r(0),u=function(){function c(){}return Object.defineProperty(c.prototype,"children",{get:function(){return s.create_htmlCollection(o.Cast.asNode(this))},enumerable:!0,configurable:!0}),Object.defineProperty(c.prototype,"firstElementChild",{get:function(){for(var p=o.Cast.asNode(this)._firstChild;p;){if(o.Guard.isElementNode(p))return p;p=p._nextSibling}return null},enumerable:!0,configurable:!0}),Object.defineProperty(c.prototype,"lastElementChild",{get:function(){for(var p=o.Cast.asNode(this)._lastChild;p;){if(o.Guard.isElementNode(p))return p;p=p._previousSibling}return null},enumerable:!0,configurable:!0}),Object.defineProperty(c.prototype,"childElementCount",{get:function(){var p,l,f=0;try{for(var h=i(o.Cast.asNode(this)._children),v=h.next();!v.done;v=h.next()){var m=v.value;o.Guard.isElementNode(m)&&f++}}catch(x){p={error:x}}finally{try{v&&!v.done&&(l=h.return)&&l.call(h)}finally{if(p)throw p.error}}return f},enumerable:!0,configurable:!0}),c.prototype.prepend=function(){for(var p=[],l=0;l0)&&!(x=d.next()).done;)g.push(x.value)}catch(C){y={error:C}}finally{try{x&&!x.done&&(m=d.return)&&m.call(d)}finally{if(y)throw y.error}}return g},o=this&&this.__values||function(h){var v=typeof Symbol=="function"&&Symbol.iterator,m=v&&h[v],x=0;if(m)return m.call(h);if(h&&typeof h.length=="number")return{next:function(){return h&&x>=h.length&&(h=void 0),{value:h&&h[x++],done:!h}}};throw new TypeError(v?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(n,"__esModule",{value:!0});var s=r(180),u=r(111),c=r(7),p=r(0),l=r(69),f=function(){function h(){}return h.prototype.parse=function(v){for(var m,x,y,d,g=new s.XMLStringLexer(v,{skipWhitespaceOnlyText:!0}),C=p.create_document(),S=C,T=g.nextToken();T.type!==u.TokenType.EOF;){switch(T.type){case u.TokenType.Declaration:var w=T;if(w.version!=="1.0")throw new Error("Invalid xml version: "+w.version);break;case u.TokenType.DocType:var _=T;if(!p.xml_isPubidChar(_.pubId))throw new Error("DocType public identifier does not match PubidChar construct.");if(!p.xml_isLegalChar(_.sysId)||_.sysId.indexOf('"')!==-1&&_.sysId.indexOf("'")!==-1)throw new Error("DocType system identifier contains invalid characters.");S.appendChild(C.implementation.createDocumentType(_.name,_.pubId,_.sysId));break;case u.TokenType.CDATA:var E=T;if(!p.xml_isLegalChar(E.data)||E.data.indexOf("]]>")!==-1)throw new Error("CDATA contains invalid characters.");S.appendChild(C.createCDATASection(E.data));break;case u.TokenType.Comment:var D=T;if(!p.xml_isLegalChar(D.data)||D.data.indexOf("--")!==-1||D.data.endsWith("-"))throw new Error("Comment data contains invalid characters.");S.appendChild(C.createComment(D.data));break;case u.TokenType.PI:var O=T;if(O.target.indexOf(":")!==-1||/^xml$/i.test(O.target))throw new Error("Processing instruction target contains invalid characters.");if(!p.xml_isLegalChar(O.data)||O.data.indexOf("?>")!==-1)throw new Error("Processing instruction data contains invalid characters.");S.appendChild(C.createProcessingInstruction(O.target,O.data));break;case u.TokenType.Text:var b=T;if(!p.xml_isLegalChar(b.data))throw new Error("Text data contains invalid characters.");S.appendChild(C.createTextNode(this._decodeText(b.data)));break;case u.TokenType.Element:var R=T,N=i(p.namespace_extractQName(R.name),2),L=N[0],B=N[1];if(B.indexOf(":")!==-1||!p.xml_isName(B))throw new Error("Node local name contains invalid characters.");if(L==="xmlns")throw new Error("An element cannot have the 'xmlns' prefix.");var P=S.lookupNamespaceURI(L),F={};try{for(var k=(m=void 0,o(R.attributes)),G=k.next();!G.done;G=k.next()){var W=i(G.value,2),H=W[0],X=W[1];if(H==="xmlns")P=X;else{var Y=i(p.namespace_extractQName(H),2),q=Y[0],Q=Y[1];q==="xmlns"&&(Q===L&&(P=X),F[Q]=X)}}}catch(z){m={error:z}}finally{try{G&&!G.done&&(x=k.return)&&x.call(k)}finally{if(m)throw m.error}}var ae=P!==null?C.createElementNS(P,R.name):C.createElement(R.name);S.appendChild(ae);var ne=new l.LocalNameSet;try{for(var ee=(y=void 0,o(R.attributes)),V=ee.next();!V.done;V=ee.next()){var M=i(V.value,2),I=(H=M[0],X=M[1],i(p.namespace_extractQName(H),2)),U=(q=I[0],Q=I[1],null);if(q==="xmlns"||q===null&&Q==="xmlns"?U=c.namespace.XMLNS:(U=ae.lookupNamespaceURI(q))!==null&&ae.isDefaultNamespace(U)?U=null:U===null&&q!==null&&(U=F[q]||null),ne.has(U,Q))throw new Error("Element contains duplicate attributes.");if(ne.set(U,Q),U===c.namespace.XMLNS&&X===c.namespace.XMLNS)throw new Error("XMLNS namespace is reserved.");if(Q.indexOf(":")!==-1||!p.xml_isName(Q))throw new Error("Attribute local name contains invalid characters.");if(q==="xmlns"&&X==="")throw new Error("Empty XML namespace is not allowed.");U!==null?ae.setAttributeNS(U,H,this._decodeAttributeValue(X)):ae.setAttribute(H,this._decodeAttributeValue(X))}}catch(z){y={error:z}}finally{try{V&&!V.done&&(d=ee.return)&&d.call(ee)}finally{if(y)throw y.error}}R.selfClosing||(S=ae);break;case u.TokenType.ClosingTag:if(T.name!==S.nodeName)throw new Error("Closing tag name does not match opening tag name.");S._parent&&(S=S._parent)}T=g.nextToken()}return C},h.prototype._decodeText=function(v){return v==null?v:v.replace(/</g,"<").replace(/>/g,">").replace(/&/g,"&")},h.prototype._decodeAttributeValue=function(v){return v==null?v:v.replace(/</g,"<").replace(/>/g,">").replace(/&/g,"&")},h}();n.XMLParserImpl=f},function(a,n,r){Object.defineProperty(n,"__esModule",{value:!0});var i=r(276);n.XMLSerializer=i.XMLSerializerImpl},function(a,n,r){var i=this&&this.__values||function(h){var v=typeof Symbol=="function"&&Symbol.iterator,m=v&&h[v],x=0;if(m)return m.call(h);if(h&&typeof h.length=="number")return{next:function(){return h&&x>=h.length&&(h=void 0),{value:h&&h[x++],done:!h}}};throw new TypeError(v?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(n,"__esModule",{value:!0});var o=r(1),s=r(69),u=r(95),c=r(9),p=r(7),l=r(0),f=function(){function h(){}return h.prototype.serializeToString=function(v){return this._xmlSerialization(v,!1)},h.prototype._xmlSerialization=function(v,m){if(v._nodeDocument===void 0||v._nodeDocument._hasNamespaces){var x=new u.NamespacePrefixMap;x.set("xml",p.namespace.XML);try{return this._serializeNodeNS(v,null,x,{value:1},m)}catch{throw new c.InvalidStateError}}else try{return this._serializeNode(v,m)}catch{throw new c.InvalidStateError}},h.prototype._serializeNodeNS=function(v,m,x,y,d){switch(v.nodeType){case o.NodeType.Element:return this._serializeElementNS(v,m,x,y,d);case o.NodeType.Document:return this._serializeDocumentNS(v,m,x,y,d);case o.NodeType.Comment:return this._serializeComment(v,d);case o.NodeType.Text:return this._serializeText(v,d);case o.NodeType.DocumentFragment:return this._serializeDocumentFragmentNS(v,m,x,y,d);case o.NodeType.DocumentType:return this._serializeDocumentType(v,d);case o.NodeType.ProcessingInstruction:return this._serializeProcessingInstruction(v,d);case o.NodeType.CData:return this._serializeCData(v,d);default:throw new Error("Unknown node type: "+v.nodeType)}},h.prototype._serializeNode=function(v,m){switch(v.nodeType){case o.NodeType.Element:return this._serializeElement(v,m);case o.NodeType.Document:return this._serializeDocument(v,m);case o.NodeType.Comment:return this._serializeComment(v,m);case o.NodeType.Text:return this._serializeText(v,m);case o.NodeType.DocumentFragment:return this._serializeDocumentFragment(v,m);case o.NodeType.DocumentType:return this._serializeDocumentType(v,m);case o.NodeType.ProcessingInstruction:return this._serializeProcessingInstruction(v,m);case o.NodeType.CData:return this._serializeCData(v,m);default:throw new Error("Unknown node type: "+v.nodeType)}},h.prototype._serializeElementNS=function(v,m,x,y,d){var g,C;if(d&&(v.localName.indexOf(":")!==-1||!l.xml_isName(v.localName)))throw new Error("Node local name contains invalid characters (well-formed required).");var S="<",T="",w=!1,_=!1,E=x.copy(),D={},O=this._recordNamespaceInformation(v,E,D),b=m,R=v.namespaceURI;if(b===R)O!==null&&(_=!0),S+=T=R===p.namespace.XML?"xml:"+v.localName:v.localName;else{var N=v.prefix,L=null;if(N===null&&R===O||(L=E.get(N,R)),N==="xmlns"){if(d)throw new Error("An element cannot have the 'xmlns' prefix (well-formed required).");L=N}L!==null?(T=L+":"+v.localName,O!==null&&O!==p.namespace.XML&&(b=O||null),S+=T):N!==null?(N in D&&(N=this._generatePrefix(R,E,y)),E.set(N,R),S+=T+=N+":"+v.localName,S+=" xmlns:"+N+'="'+this._serializeAttributeValue(R,d)+'"',O!==null&&(b=O||null)):O===null||O!==null&&O!==R?(_=!0,b=R,S+=T+=v.localName,S+=' xmlns="'+this._serializeAttributeValue(R,d)+'"'):(b=R,S+=T+=v.localName)}S+=this._serializeAttributesNS(v,E,y,D,_,d);var B=R===p.namespace.HTML;if(B&&v.childNodes.length===0&&h._VoidElementNames.has(v.localName)?(S+=" /",w=!0):B||v.childNodes.length!==0||(S+="/",w=!0),S+=">",w)return S;if(!(B&&v.localName==="template"))try{for(var P=i(v._children||v.childNodes),F=P.next();!F.done;F=P.next()){var k=F.value;S+=this._serializeNodeNS(k,b,E,y,d)}}catch(G){g={error:G}}finally{try{F&&!F.done&&(C=P.return)&&C.call(P)}finally{if(g)throw g.error}}return S+=""},h.prototype._serializeDocumentNS=function(v,m,x,y,d){var g,C;if(d&&v.documentElement===null)throw new Error("Missing document element (well-formed required).");var S="";try{for(var T=i(v._children||v.childNodes),w=T.next();!w.done;w=T.next()){var _=w.value;S+=this._serializeNodeNS(_,m,x,y,d)}}catch(E){g={error:E}}finally{try{w&&!w.done&&(C=T.return)&&C.call(T)}finally{if(g)throw g.error}}return S},h.prototype._serializeComment=function(v,m){if(m&&(!l.xml_isLegalChar(v.data)||v.data.indexOf("--")!==-1||v.data.endsWith("-")))throw new Error("Comment data contains invalid characters (well-formed required).");return""},h.prototype._serializeText=function(v,m){if(m&&!l.xml_isLegalChar(v.data))throw new Error("Text data contains invalid characters (well-formed required).");for(var x="",y=0;y"?">":d}return x},h.prototype._serializeDocumentFragmentNS=function(v,m,x,y,d){var g,C,S="";try{for(var T=i(v._children||v.childNodes),w=T.next();!w.done;w=T.next()){var _=w.value;S+=this._serializeNodeNS(_,m,x,y,d)}}catch(E){g={error:E}}finally{try{w&&!w.done&&(C=T.return)&&C.call(T)}finally{if(g)throw g.error}}return S},h.prototype._serializeDocumentType=function(v,m){if(m&&!l.xml_isPubidChar(v.publicId))throw new Error("DocType public identifier does not match PubidChar construct (well-formed required).");if(m&&(!l.xml_isLegalChar(v.systemId)||v.systemId.indexOf('"')!==-1&&v.systemId.indexOf("'")!==-1))throw new Error("DocType system identifier contains invalid characters (well-formed required).");return v.publicId&&v.systemId?"':v.publicId?"':v.systemId?"':""},h.prototype._serializeProcessingInstruction=function(v,m){if(m&&(v.target.indexOf(":")!==-1||/^xml$/i.test(v.target)))throw new Error("Processing instruction target contains invalid characters (well-formed required).");if(m&&(!l.xml_isLegalChar(v.data)||v.data.indexOf("?>")!==-1))throw new Error("Processing instruction data contains invalid characters (well-formed required).");return""},h.prototype._serializeCData=function(v,m){if(m&&v.data.indexOf("]]>")!==-1)throw new Error("CDATA contains invalid characters (well-formed required).");return""},h.prototype._serializeAttributesNS=function(v,m,x,y,d,g){var C,S,T="",w=g?new s.LocalNameSet:void 0;try{for(var _=i(v.attributes),E=_.next();!E.done;E=_.next()){var D=E.value;if(d||g||D.namespaceURI!==null){if(g&&w&&w.has(D.namespaceURI,D.localName))throw new Error("Element contains duplicate attributes (well-formed required).");g&&w&&w.set(D.namespaceURI,D.localName);var O=D.namespaceURI,b=null;if(O!==null)if(b=m.get(D.prefix,O),O===p.namespace.XMLNS){if(D.value===p.namespace.XML||D.prefix===null&&d||D.prefix!==null&&(!(D.localName in y)||y[D.localName]!==D.value)&&m.has(D.localName,D.value))continue;if(g&&D.value===p.namespace.XMLNS)throw new Error("XMLNS namespace is reserved (well-formed required).");if(g&&D.value==="")throw new Error("Namespace prefix declarations cannot be used to undeclare a namespace (well-formed required).");D.prefix==="xmlns"&&(b="xmlns")}else b===null&&(T+=" xmlns:"+(b=D.prefix===null||m.hasPrefix(D.prefix)&&!m.has(D.prefix,O)?this._generatePrefix(O,m,x):D.prefix)+'="'+this._serializeAttributeValue(O,g)+'"');if(T+=" ",b!==null&&(T+=b+":"),g&&(D.localName.indexOf(":")!==-1||!l.xml_isName(D.localName)||D.localName==="xmlns"&&O===null))throw new Error("Attribute local name contains invalid characters (well-formed required).");T+=D.localName+'="'+this._serializeAttributeValue(D.value,g)+'"'}else T+=" "+D.localName+'="'+this._serializeAttributeValue(D.value,g)+'"'}}catch(R){C={error:R}}finally{try{E&&!E.done&&(S=_.return)&&S.call(_)}finally{if(C)throw C.error}}return T},h.prototype._recordNamespaceInformation=function(v,m,x){var y,d,g=null;try{for(var C=i(v.attributes),S=C.next();!S.done;S=C.next()){var T=S.value,w=T.namespaceURI,_=T.prefix;if(w===p.namespace.XMLNS){if(_===null){g=T.value;continue}var E=T.localName,D=T.value;if(D===p.namespace.XML||(D===""&&(D=null),m.has(E,D)))continue;m.set(E,D),x[E]=D||""}}}catch(O){y={error:O}}finally{try{S&&!S.done&&(d=C.return)&&d.call(C)}finally{if(y)throw y.error}}return g},h.prototype._generatePrefix=function(v,m,x){var y="ns"+x.value;return x.value++,m.set(y,v),y},h.prototype._serializeAttributeValue=function(v,m){if(m&&v!==null&&!l.xml_isLegalChar(v))throw new Error("Invalid characters in attribute value.");if(v===null)return"";for(var x="",y=0;y"?">":d}return x},h.prototype._serializeElement=function(v,m){var x,y;if(m&&(v.localName.indexOf(":")!==-1||!l.xml_isName(v.localName)))throw new Error("Node local name contains invalid characters (well-formed required).");var d=!1,g=v.localName,C="<"+g;if(C+=this._serializeAttributes(v,m),v._children.size===0&&(C+="/",d=!0),C+=">",d)return C;try{for(var S=i(v._children),T=S.next();!T.done;T=S.next()){var w=T.value;C+=this._serializeNode(w,m)}}catch(_){x={error:_}}finally{try{T&&!T.done&&(y=S.return)&&y.call(S)}finally{if(x)throw x.error}}return C+=""},h.prototype._serializeDocument=function(v,m){var x,y;if(m&&v.documentElement===null)throw new Error("Missing document element (well-formed required).");var d="";try{for(var g=i(v._children),C=g.next();!C.done;C=g.next()){var S=C.value;d+=this._serializeNode(S,m)}}catch(T){x={error:T}}finally{try{C&&!C.done&&(y=g.return)&&y.call(g)}finally{if(x)throw x.error}}return d},h.prototype._serializeDocumentFragment=function(v,m){var x,y,d="";try{for(var g=i(v._children),C=g.next();!C.done;C=g.next()){var S=C.value;d+=this._serializeNode(S,m)}}catch(T){x={error:T}}finally{try{C&&!C.done&&(y=g.return)&&y.call(g)}finally{if(x)throw x.error}}return d},h.prototype._serializeAttributes=function(v,m){var x,y,d="",g=m?{}:void 0;try{for(var C=i(v.attributes),S=C.next();!S.done;S=C.next()){var T=S.value;if(m&&g&&T.localName in g)throw new Error("Element contains duplicate attributes (well-formed required).");if(m&&g&&(g[T.localName]=!0),m&&(T.localName.indexOf(":")!==-1||!l.xml_isName(T.localName)))throw new Error("Attribute local name contains invalid characters (well-formed required).");d+=" "+T.localName+'="'+this._serializeAttributeValue(T.value,m)+'"'}}catch(w){x={error:w}}finally{try{S&&!S.done&&(y=C.return)&&y.call(C)}finally{if(x)throw x.error}}return d},h._VoidElementNames=new Set(["area","base","basefont","bgsound","br","col","embed","frame","hr","img","input","keygen","link","menuitem","meta","param","source","track","wbr"]),h}();n.XMLSerializerImpl=f},function(a,n,r){Object.defineProperty(n,"__esModule",{value:!0});var i=r(278);n.XMLReader=i.XMLReader;var o=r(112);n.ObjectReader=o.ObjectReader;var s=r(281);n.JSONReader=s.JSONReader;var u=r(282);n.YAMLReader=u.YAMLReader},function(a,n,r){r(31),r(32),r(33),r(19),r(65),r(20),r(22),r(23);var i,o=this&&this.__extends||(i=function(m,x){return(i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(y,d){y.__proto__=d}||function(y,d){for(var g in d)d.hasOwnProperty(g)&&(y[g]=d[g])})(m,x)},function(m,x){function y(){this.constructor=m}i(m,x),m.prototype=x===null?Object.create(x):(y.prototype=x.prototype,new y)}),s=this&&this.__read||function(m,x){var y=typeof Symbol=="function"&&m[Symbol.iterator];if(!y)return m;var d,g,C=y.call(m),S=[];try{for(;(x===void 0||x-- >0)&&!(d=C.next()).done;)S.push(d.value)}catch(T){g={error:T}}finally{try{d&&!d.done&&(y=C.return)&&y.call(C)}finally{if(g)throw g.error}}return S},u=this&&this.__values||function(m){var x=typeof Symbol=="function"&&Symbol.iterator,y=x&&m[x],d=0;if(y)return y.call(m);if(m&&typeof m.length=="number")return{next:function(){return m&&d>=m.length&&(m=void 0),{value:m&&m[d++],done:!m}}};throw new TypeError(x?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(n,"__esModule",{value:!0});var c=r(180),p=r(111),l=r(1),f=r(7),h=r(0),v=function(m){function x(){return m!==null&&m.apply(this,arguments)||this}return o(x,m),x.prototype._parse=function(y,d){for(var g,C,S,T,w=new c.XMLStringLexer(d,{skipWhitespaceOnlyText:this._builderOptions.skipWhitespaceOnlyText}),_=y,E=y,D=w.nextToken();D.type!==p.TokenType.EOF;){switch(D.type){case p.TokenType.Declaration:var O=D,b=this.sanitize(O.version);if(b!=="1.0")throw new Error("Invalid xml version: "+b);var R={version:b};O.encoding&&(R.encoding=this.sanitize(O.encoding)),O.standalone&&(R.standalone=this.sanitize(O.standalone)==="yes"),E.set(R);break;case p.TokenType.DocType:var N=D;E=this.docType(E,this.sanitize(N.name),this.sanitize(N.pubId),this.sanitize(N.sysId))||E;break;case p.TokenType.CDATA:var L=D;E=this.cdata(E,this.sanitize(L.data))||E;break;case p.TokenType.Comment:var B=D;E=this.comment(E,this.sanitize(B.data))||E;break;case p.TokenType.PI:var P=D;E=this.instruction(E,this.sanitize(P.target),this.sanitize(P.data))||E;break;case p.TokenType.Text:if(E.node.nodeType===l.NodeType.Document)break;var F=D;E=this.text(E,this._decodeText(this.sanitize(F.data)))||E;break;case p.TokenType.Element:var k=D,G=this.sanitize(k.name),W=s(h.namespace_extractQName(G),1)[0],H=E.node.lookupNamespaceURI(W),X={};try{for(var Y=(g=void 0,u(k.attributes)),q=Y.next();!q.done;q=Y.next()){var Q=s(q.value,2),ae=Q[0],ne=Q[1];if(ae=this.sanitize(ae),ne=this.sanitize(ne),ae==="xmlns")H=ne;else{var ee=s(h.namespace_extractQName(ae),2),V=ee[0],M=ee[1];V==="xmlns"&&(M===W&&(H=ne),X[M]=ne)}}}catch(re){g={error:re}}finally{try{q&&!q.done&&(C=Y.return)&&C.call(Y)}finally{if(g)throw g.error}}var I=H!==null?this.element(E,H,G):this.element(E,void 0,G);if(I===void 0)break;E.node===y.node&&(_=I);try{for(var U=(S=void 0,u(k.attributes)),z=U.next();!z.done;z=U.next()){var j=s(z.value,2);ae=j[0],ne=j[1],ae=this.sanitize(ae),ne=this.sanitize(ne);var $=s(h.namespace_extractQName(ae),2),J=(V=$[0],M=$[1],null);V==="xmlns"||V===null&&M==="xmlns"?J=f.namespace.XMLNS:(J=I.node.lookupNamespaceURI(V))!==null&&I.node.isDefaultNamespace(J)?J=null:J===null&&V!==null&&(J=X[V]||null),J!==null?this.attribute(I,J,ae,this._decodeAttributeValue(ne)):this.attribute(I,void 0,ae,this._decodeAttributeValue(ne))}}catch(re){S={error:re}}finally{try{z&&!z.done&&(T=U.return)&&T.call(U)}finally{if(S)throw S.error}}k.selfClosing||(E=I);break;case p.TokenType.ClosingTag:E.node.parentNode&&(E=E.up())}D=w.nextToken()}return _},x}(r(75).BaseReader);n.XMLReader=v},function(a,n,r){var i=r(4),o=r(280);i({target:"Object",stat:!0,forced:Object.assign!==o},{assign:o})},function(a,n,r){var i=r(16),o=r(8),s=r(61),u=r(85),c=r(79),p=r(27),l=r(41),f=Object.assign,h=Object.defineProperty;a.exports=!f||o(function(){if(i&&f({b:1},f(h({},"a",{enumerable:!0,get:function(){h(this,"b",{value:3,enumerable:!1})}}),{b:2})).b!==1)return!0;var v={},m={},x=Symbol();return v[x]=7,"abcdefghijklmnopqrst".split("").forEach(function(y){m[y]=y}),f({},v)[x]!=7||s(f({},m)).join("")!="abcdefghijklmnopqrst"})?function(v,m){for(var x=p(v),y=arguments.length,d=1,g=u.f,C=c.f;y>d;)for(var S,T=l(arguments[d++]),w=g?s(T).concat(g(T)):s(T),_=w.length,E=0;_>E;)S=w[E++],i&&!C.call(T,S)||(x[S]=T[S]);return x}:f},function(a,n,r){var i,o=this&&this.__extends||(i=function(c,p){return(i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(l,f){l.__proto__=f}||function(l,f){for(var h in f)f.hasOwnProperty(h)&&(l[h]=f[h])})(c,p)},function(c,p){function l(){this.constructor=c}i(c,p),c.prototype=p===null?Object.create(p):(l.prototype=p.prototype,new l)});Object.defineProperty(n,"__esModule",{value:!0});var s=r(112),u=function(c){function p(){return c!==null&&c.apply(this,arguments)||this}return o(p,c),p.prototype._parse=function(l,f){return new s.ObjectReader(this._builderOptions).parse(l,JSON.parse(f))},p}(r(75).BaseReader);n.JSONReader=u},function(a,n,r){var i,o=this&&this.__extends||(i=function(l,f){return(i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(h,v){h.__proto__=v}||function(h,v){for(var m in v)v.hasOwnProperty(m)&&(h[m]=v[m])})(l,f)},function(l,f){function h(){this.constructor=l}i(l,f),l.prototype=f===null?Object.create(f):(h.prototype=f.prototype,new h)});Object.defineProperty(n,"__esModule",{value:!0});var s=r(112),u=r(75),c=r(283),p=function(l){function f(){return l!==null&&l.apply(this,arguments)||this}return o(f,l),f.prototype._parse=function(h,v){var m=c.safeLoad(v);if(m===void 0)throw new Error("Unable to parse YAML document.");return new s.ObjectReader(this._builderOptions).parse(h,m)},f}(u.BaseReader);n.YAMLReader=p},function(a,n,r){var i=r(284);a.exports=i},function(a,n,r){var i=r(285),o=r(304);function s(u){return function(){throw new Error("Function "+u+" is deprecated and cannot be used.")}}a.exports.Type=r(10),a.exports.Schema=r(39),a.exports.FAILSAFE_SCHEMA=r(113),a.exports.JSON_SCHEMA=r(182),a.exports.CORE_SCHEMA=r(181),a.exports.DEFAULT_SAFE_SCHEMA=r(54),a.exports.DEFAULT_FULL_SCHEMA=r(76),a.exports.load=i.load,a.exports.loadAll=i.loadAll,a.exports.safeLoad=i.safeLoad,a.exports.safeLoadAll=i.safeLoadAll,a.exports.dump=o.dump,a.exports.safeDump=o.safeDump,a.exports.YAMLException=r(53),a.exports.MINIMAL_SCHEMA=r(113),a.exports.SAFE_SCHEMA=r(54),a.exports.DEFAULT_SCHEMA=r(76),a.exports.scan=s("scan"),a.exports.parse=s("parse"),a.exports.compose=s("compose"),a.exports.addConstructor=s("addConstructor")},function(a,n,r){var i=r(38),o=r(53),s=r(286),u=r(54),c=r(76),p=Object.prototype.hasOwnProperty,l=/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x84\x86-\x9F\uFFFE\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/,f=/[\x85\u2028\u2029]/,h=/[,\[\]\{\}]/,v=/^(?:!|!!|![a-z\-]+!)$/i,m=/^(?:!|[^,\[\]\{\}])(?:%[0-9a-f]{2}|[0-9a-z\-#;\/\?:@&=\+\$,_\.!~\*'\(\)\[\]])*$/i;function x(M){return Object.prototype.toString.call(M)}function y(M){return M===10||M===13}function d(M){return M===9||M===32}function g(M){return M===9||M===32||M===10||M===13}function C(M){return M===44||M===91||M===93||M===123||M===125}function S(M){var I;return 48<=M&&M<=57?M-48:97<=(I=32|M)&&I<=102?I-97+10:-1}function T(M){return M===48?"\0":M===97?"\x07":M===98?"\b":M===116||M===9?" ":M===110?` -`:M===118?"\v":M===102?"\f":M===114?"\r":M===101?"\x1B":M===32?" ":M===34?'"':M===47?"/":M===92?"\\":M===78?"…":M===95?" ":M===76?"\u2028":M===80?"\u2029":""}function w(M){return M<=65535?String.fromCharCode(M):String.fromCharCode(55296+(M-65536>>10),56320+(M-65536&1023))}for(var _=new Array(256),E=new Array(256),D=0;D<256;D++)_[D]=T(D)?1:0,E[D]=T(D);function O(M,I){this.input=M,this.filename=I.filename||null,this.schema=I.schema||c,this.onWarning=I.onWarning||null,this.legacy=I.legacy||!1,this.json=I.json||!1,this.listener=I.listener||null,this.implicitTypes=this.schema.compiledImplicit,this.typeMap=this.schema.compiledTypeMap,this.length=M.length,this.position=0,this.line=0,this.lineStart=0,this.lineIndent=0,this.documents=[]}function b(M,I){return new o(I,new s(M.filename,M.input,M.position,M.line,M.position-M.lineStart))}function R(M,I){throw b(M,I)}function N(M,I){M.onWarning&&M.onWarning.call(null,b(M,I))}var L={YAML:function(M,I,U){var z,j,$;M.version!==null&&R(M,"duplication of %YAML directive"),U.length!==1&&R(M,"YAML directive accepts exactly one argument"),(z=/^([0-9]+)\.([0-9]+)$/.exec(U[0]))===null&&R(M,"ill-formed argument of the YAML directive"),j=parseInt(z[1],10),$=parseInt(z[2],10),j!==1&&R(M,"unacceptable YAML version of the document"),M.version=U[0],M.checkLineBreaks=$<2,$!==1&&$!==2&&N(M,"unsupported YAML version of the document")},TAG:function(M,I,U){var z,j;U.length!==2&&R(M,"TAG directive accepts exactly two arguments"),z=U[0],j=U[1],v.test(z)||R(M,"ill-formed tag handle (first argument) of the TAG directive"),p.call(M.tagMap,z)&&R(M,'there is a previously declared suffix for "'+z+'" tag handle'),m.test(j)||R(M,"ill-formed tag prefix (second argument) of the TAG directive"),M.tagMap[z]=j}};function B(M,I,U,z){var j,$,J,re;if(I1&&(M.result+=i.repeat(` +`:M===118?"\v":M===102?"\f":M===114?"\r":M===101?"\x1B":M===32?" ":M===34?'"':M===47?"/":M===92?"\\":M===78?"…":M===95?" ":M===76?"\u2028":M===80?"\u2029":""}function w(M){return M<=65535?String.fromCharCode(M):String.fromCharCode(55296+(M-65536>>10),56320+(M-65536&1023))}for(var _=new Array(256),E=new Array(256),D=0;D<256;D++)_[D]=T(D)?1:0,E[D]=T(D);function O(M,I){this.input=M,this.filename=I.filename||null,this.schema=I.schema||c,this.onWarning=I.onWarning||null,this.legacy=I.legacy||!1,this.json=I.json||!1,this.listener=I.listener||null,this.implicitTypes=this.schema.compiledImplicit,this.typeMap=this.schema.compiledTypeMap,this.length=M.length,this.position=0,this.line=0,this.lineStart=0,this.lineIndent=0,this.documents=[]}function b(M,I){return new o(I,new s(M.filename,M.input,M.position,M.line,M.position-M.lineStart))}function R(M,I){throw b(M,I)}function N(M,I){M.onWarning&&M.onWarning.call(null,b(M,I))}var L={YAML:function(M,I,U){var z,j,$;M.version!==null&&R(M,"duplication of %YAML directive"),U.length!==1&&R(M,"YAML directive accepts exactly one argument"),(z=/^([0-9]+)\.([0-9]+)$/.exec(U[0]))===null&&R(M,"ill-formed argument of the YAML directive"),j=parseInt(z[1],10),$=parseInt(z[2],10),j!==1&&R(M,"unacceptable YAML version of the document"),M.version=U[0],M.checkLineBreaks=$<2,$!==1&&$!==2&&N(M,"unsupported YAML version of the document")},TAG:function(M,I,U){var z,j;U.length!==2&&R(M,"TAG directive accepts exactly two arguments"),z=U[0],j=U[1],v.test(z)||R(M,"ill-formed tag handle (first argument) of the TAG directive"),p.call(M.tagMap,z)&&R(M,'there is a previously declared suffix for "'+z+'" tag handle'),m.test(j)||R(M,"ill-formed tag prefix (second argument) of the TAG directive"),M.tagMap[z]=j}};function B(M,I,U,z){var j,$,J,re;if(I1&&(M.result+=i.repeat(` `,I-1))}function X(M,I){var U,z,j=M.tag,$=M.anchor,J=[],re=!1;for(M.anchor!==null&&(M.anchorMap[M.anchor]=J),z=M.input.charCodeAt(M.position);z!==0&&z===45&&g(M.input.charCodeAt(M.position+1));)if(re=!0,M.position++,G(M,!0,-1)&&M.lineIndent<=I)J.push(null),z=M.input.charCodeAt(M.position);else if(U=M.line,Q(M,I,3,!1,!0),J.push(M.result),G(M,!0,-1),z=M.input.charCodeAt(M.position),(M.line===U||M.lineIndent>I)&&z!==0)R(M,"bad indentation of a sequence entry");else if(M.lineIndentI?ke=1:M.lineIndent===I?ke=0:M.lineIndentI?ke=1:M.lineIndent===I?ke=0:M.lineIndentDe)&&(Q(K,De,4,!0,te)&&(it?wt=K.result:Ft=K.result),it||(F(K,Se,Be,Ie,wt,Ft,ce,he),Ie=wt=Ft=null),G(K,!0,-1),fe=K.input.charCodeAt(K.position)),K.lineIndent>De&&fe!==0)R(K,"bad indentation of a mapping entry");else if(K.lineIndent=0))break;te===0?R(K,"bad explicit indentation width of a block scalar; it cannot be less than one"):Ve?R(K,"repeat of an indentation width identifier"):(Se=De+te-1,Ve=!0)}if(d(ce)){do ce=K.input.charCodeAt(++K.position);while(d(ce));if(ce===35)do ce=K.input.charCodeAt(++K.position);while(!y(ce)&&ce!==0)}for(;ce!==0;){for(k(K),K.lineIndent=0,ce=K.input.charCodeAt(K.position);(!Ve||K.lineIndentSe&&(Se=K.lineIndent),y(ce))Be++;else{if(K.lineIndent=0&&(d=d.replace(/\\u\{([0-9a-fA-F]+)\}|\\u([a-fA-F0-9]{4})/g,function(C,S,T){var w=parseInt(S||T,16);return w>1114111&&g.throwUnexpectedToken(l.Messages.InvalidRegExp),w<=65535?String.fromCharCode(w):"￿"}).replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g,"￿"));try{RegExp(d)}catch{this.throwUnexpectedToken(l.Messages.InvalidRegExp)}try{return new RegExp(x,y)}catch{return null}},m.prototype.scanRegExpBody=function(){var x=this.source[this.index];c.assert(x==="/","Regular expression literal must start with a slash");for(var y=this.source[this.index++],d=!1,g=!1;!this.eof();)if(y+=x=this.source[this.index++],x==="\\")x=this.source[this.index++],p.Character.isLineTerminator(x.charCodeAt(0))&&this.throwUnexpectedToken(l.Messages.UnterminatedRegExp),y+=x;else if(p.Character.isLineTerminator(x.charCodeAt(0)))this.throwUnexpectedToken(l.Messages.UnterminatedRegExp);else if(d)x==="]"&&(d=!1);else{if(x==="/"){g=!0;break}x==="["&&(d=!0)}return g||this.throwUnexpectedToken(l.Messages.UnterminatedRegExp),y.substr(1,y.length-2)},m.prototype.scanRegExpFlags=function(){for(var x="";!this.eof();){var y=this.source[this.index];if(!p.Character.isIdentifierPart(y.charCodeAt(0)))break;if(++this.index,y!=="\\"||this.eof())x+=y;else if((y=this.source[this.index])==="u"){++this.index;var d=this.index,g=this.scanHexEscape("u");if(g!==null)for(x+=g;d=55296&&x<57343&&p.Character.isIdentifierStart(this.codePointAt(this.index))?this.scanIdentifier():this.scanPunctuator()},m}();s.Scanner=v},function(o,s){Object.defineProperty(s,"__esModule",{value:!0}),s.TokenName={},s.TokenName[1]="Boolean",s.TokenName[2]="",s.TokenName[3]="Identifier",s.TokenName[4]="Keyword",s.TokenName[5]="Null",s.TokenName[6]="Numeric",s.TokenName[7]="Punctuator",s.TokenName[8]="String",s.TokenName[9]="RegularExpression",s.TokenName[10]="Template"},function(o,s){Object.defineProperty(s,"__esModule",{value:!0}),s.XHTMLEntities={quot:'"',amp:"&",apos:"'",gt:">",nbsp:" ",iexcl:"¡",cent:"¢",pound:"£",curren:"¤",yen:"¥",brvbar:"¦",sect:"§",uml:"¨",copy:"©",ordf:"ª",laquo:"«",not:"¬",shy:"­",reg:"®",macr:"¯",deg:"°",plusmn:"±",sup2:"²",sup3:"³",acute:"´",micro:"µ",para:"¶",middot:"·",cedil:"¸",sup1:"¹",ordm:"º",raquo:"»",frac14:"¼",frac12:"½",frac34:"¾",iquest:"¿",Agrave:"À",Aacute:"Á",Acirc:"Â",Atilde:"Ã",Auml:"Ä",Aring:"Å",AElig:"Æ",Ccedil:"Ç",Egrave:"È",Eacute:"É",Ecirc:"Ê",Euml:"Ë",Igrave:"Ì",Iacute:"Í",Icirc:"Î",Iuml:"Ï",ETH:"Ð",Ntilde:"Ñ",Ograve:"Ò",Oacute:"Ó",Ocirc:"Ô",Otilde:"Õ",Ouml:"Ö",times:"×",Oslash:"Ø",Ugrave:"Ù",Uacute:"Ú",Ucirc:"Û",Uuml:"Ü",Yacute:"Ý",THORN:"Þ",szlig:"ß",agrave:"à",aacute:"á",acirc:"â",atilde:"ã",auml:"ä",aring:"å",aelig:"æ",ccedil:"ç",egrave:"è",eacute:"é",ecirc:"ê",euml:"ë",igrave:"ì",iacute:"í",icirc:"î",iuml:"ï",eth:"ð",ntilde:"ñ",ograve:"ò",oacute:"ó",ocirc:"ô",otilde:"õ",ouml:"ö",divide:"÷",oslash:"ø",ugrave:"ù",uacute:"ú",ucirc:"û",uuml:"ü",yacute:"ý",thorn:"þ",yuml:"ÿ",OElig:"Œ",oelig:"œ",Scaron:"Š",scaron:"š",Yuml:"Ÿ",fnof:"ƒ",circ:"ˆ",tilde:"˜",Alpha:"Α",Beta:"Β",Gamma:"Γ",Delta:"Δ",Epsilon:"Ε",Zeta:"Ζ",Eta:"Η",Theta:"Θ",Iota:"Ι",Kappa:"Κ",Lambda:"Λ",Mu:"Μ",Nu:"Ν",Xi:"Ξ",Omicron:"Ο",Pi:"Π",Rho:"Ρ",Sigma:"Σ",Tau:"Τ",Upsilon:"Υ",Phi:"Φ",Chi:"Χ",Psi:"Ψ",Omega:"Ω",alpha:"α",beta:"β",gamma:"γ",delta:"δ",epsilon:"ε",zeta:"ζ",eta:"η",theta:"θ",iota:"ι",kappa:"κ",lambda:"λ",mu:"μ",nu:"ν",xi:"ξ",omicron:"ο",pi:"π",rho:"ρ",sigmaf:"ς",sigma:"σ",tau:"τ",upsilon:"υ",phi:"φ",chi:"χ",psi:"ψ",omega:"ω",thetasym:"ϑ",upsih:"ϒ",piv:"ϖ",ensp:" ",emsp:" ",thinsp:" ",zwnj:"‌",zwj:"‍",lrm:"‎",rlm:"‏",ndash:"–",mdash:"—",lsquo:"‘",rsquo:"’",sbquo:"‚",ldquo:"“",rdquo:"”",bdquo:"„",dagger:"†",Dagger:"‡",bull:"•",hellip:"…",permil:"‰",prime:"′",Prime:"″",lsaquo:"‹",rsaquo:"›",oline:"‾",frasl:"⁄",euro:"€",image:"ℑ",weierp:"℘",real:"ℜ",trade:"™",alefsym:"ℵ",larr:"←",uarr:"↑",rarr:"→",darr:"↓",harr:"↔",crarr:"↵",lArr:"⇐",uArr:"⇑",rArr:"⇒",dArr:"⇓",hArr:"⇔",forall:"∀",part:"∂",exist:"∃",empty:"∅",nabla:"∇",isin:"∈",notin:"∉",ni:"∋",prod:"∏",sum:"∑",minus:"−",lowast:"∗",radic:"√",prop:"∝",infin:"∞",ang:"∠",and:"∧",or:"∨",cap:"∩",cup:"∪",int:"∫",there4:"∴",sim:"∼",cong:"≅",asymp:"≈",ne:"≠",equiv:"≡",le:"≤",ge:"≥",sub:"⊂",sup:"⊃",nsub:"⊄",sube:"⊆",supe:"⊇",oplus:"⊕",otimes:"⊗",perp:"⊥",sdot:"⋅",lceil:"⌈",rceil:"⌉",lfloor:"⌊",rfloor:"⌋",loz:"◊",spades:"♠",clubs:"♣",hearts:"♥",diams:"♦",lang:"⟨",rang:"⟩"}},function(o,s,u){Object.defineProperty(s,"__esModule",{value:!0});var c=u(10),p=u(12),l=u(13),f=function(){function v(){this.values=[],this.curly=this.paren=-1}return v.prototype.beforeFunctionExpression=function(m){return["(","{","[","in","typeof","instanceof","new","return","case","delete","throw","void","=","+=","-=","*=","**=","/=","%=","<<=",">>=",">>>=","&=","|=","^=",",","+","-","*","**","/","%","++","--","<<",">>",">>>","&","|","^","!","~","&&","||","?",":","===","==",">=","<=","<",">","!=","!=="].indexOf(m)>=0},v.prototype.isRegexStart=function(){var m=this.values[this.values.length-1],x=m!==null;switch(m){case"this":case"]":x=!1;break;case")":var y=this.values[this.paren-1];x=y==="if"||y==="while"||y==="for"||y==="with";break;case"}":if(x=!1,this.values[this.curly-3]==="function")x=!!(d=this.values[this.curly-4])&&!this.beforeFunctionExpression(d);else if(this.values[this.curly-4]==="function"){var d;x=!(d=this.values[this.curly-5])||!this.beforeFunctionExpression(d)}}return x},v.prototype.push=function(m){m.type===7||m.type===4?(m.value==="{"?this.curly=this.values.length:m.value==="("&&(this.paren=this.values.length),this.values.push(m.value)):this.values.push(null)},v}(),h=function(){function v(m,x){this.errorHandler=new c.ErrorHandler,this.errorHandler.tolerant=!!x&&typeof x.tolerant=="boolean"&&x.tolerant,this.scanner=new p.Scanner(m,this.errorHandler),this.scanner.trackComment=!!x&&typeof x.comment=="boolean"&&x.comment,this.trackRange=!!x&&typeof x.range=="boolean"&&x.range,this.trackLoc=!!x&&typeof x.loc=="boolean"&&x.loc,this.buffer=[],this.reader=new f}return v.prototype.errors=function(){return this.errorHandler.errors},v.prototype.getNextToken=function(){if(this.buffer.length===0){var m=this.scanner.scanComments();if(this.scanner.trackComment)for(var x=0;x=0&&(d=d.replace(/\\u\{([0-9a-fA-F]+)\}|\\u([a-fA-F0-9]{4})/g,function(C,S,T){var w=parseInt(S||T,16);return w>1114111&&g.throwUnexpectedToken(l.Messages.InvalidRegExp),w<=65535?String.fromCharCode(w):"￿"}).replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g,"￿"));try{RegExp(d)}catch{this.throwUnexpectedToken(l.Messages.InvalidRegExp)}try{return new RegExp(x,y)}catch{return null}},m.prototype.scanRegExpBody=function(){var x=this.source[this.index];c.assert(x==="/","Regular expression literal must start with a slash");for(var y=this.source[this.index++],d=!1,g=!1;!this.eof();)if(y+=x=this.source[this.index++],x==="\\")x=this.source[this.index++],p.Character.isLineTerminator(x.charCodeAt(0))&&this.throwUnexpectedToken(l.Messages.UnterminatedRegExp),y+=x;else if(p.Character.isLineTerminator(x.charCodeAt(0)))this.throwUnexpectedToken(l.Messages.UnterminatedRegExp);else if(d)x==="]"&&(d=!1);else{if(x==="/"){g=!0;break}x==="["&&(d=!0)}return g||this.throwUnexpectedToken(l.Messages.UnterminatedRegExp),y.substr(1,y.length-2)},m.prototype.scanRegExpFlags=function(){for(var x="";!this.eof();){var y=this.source[this.index];if(!p.Character.isIdentifierPart(y.charCodeAt(0)))break;if(++this.index,y!=="\\"||this.eof())x+=y;else if((y=this.source[this.index])==="u"){++this.index;var d=this.index,g=this.scanHexEscape("u");if(g!==null)for(x+=g;d=55296&&x<57343&&p.Character.isIdentifierStart(this.codePointAt(this.index))?this.scanIdentifier():this.scanPunctuator()},m}();s.Scanner=v},function(o,s){Object.defineProperty(s,"__esModule",{value:!0}),s.TokenName={},s.TokenName[1]="Boolean",s.TokenName[2]="",s.TokenName[3]="Identifier",s.TokenName[4]="Keyword",s.TokenName[5]="Null",s.TokenName[6]="Numeric",s.TokenName[7]="Punctuator",s.TokenName[8]="String",s.TokenName[9]="RegularExpression",s.TokenName[10]="Template"},function(o,s){Object.defineProperty(s,"__esModule",{value:!0}),s.XHTMLEntities={quot:'"',amp:"&",apos:"'",gt:">",nbsp:" ",iexcl:"¡",cent:"¢",pound:"£",curren:"¤",yen:"¥",brvbar:"¦",sect:"§",uml:"¨",copy:"©",ordf:"ª",laquo:"«",not:"¬",shy:"­",reg:"®",macr:"¯",deg:"°",plusmn:"±",sup2:"²",sup3:"³",acute:"´",micro:"µ",para:"¶",middot:"·",cedil:"¸",sup1:"¹",ordm:"º",raquo:"»",frac14:"¼",frac12:"½",frac34:"¾",iquest:"¿",Agrave:"À",Aacute:"Á",Acirc:"Â",Atilde:"Ã",Auml:"Ä",Aring:"Å",AElig:"Æ",Ccedil:"Ç",Egrave:"È",Eacute:"É",Ecirc:"Ê",Euml:"Ë",Igrave:"Ì",Iacute:"Í",Icirc:"Î",Iuml:"Ï",ETH:"Ð",Ntilde:"Ñ",Ograve:"Ò",Oacute:"Ó",Ocirc:"Ô",Otilde:"Õ",Ouml:"Ö",times:"×",Oslash:"Ø",Ugrave:"Ù",Uacute:"Ú",Ucirc:"Û",Uuml:"Ü",Yacute:"Ý",THORN:"Þ",szlig:"ß",agrave:"à",aacute:"á",acirc:"â",atilde:"ã",auml:"ä",aring:"å",aelig:"æ",ccedil:"ç",egrave:"è",eacute:"é",ecirc:"ê",euml:"ë",igrave:"ì",iacute:"í",icirc:"î",iuml:"ï",eth:"ð",ntilde:"ñ",ograve:"ò",oacute:"ó",ocirc:"ô",otilde:"õ",ouml:"ö",divide:"÷",oslash:"ø",ugrave:"ù",uacute:"ú",ucirc:"û",uuml:"ü",yacute:"ý",thorn:"þ",yuml:"ÿ",OElig:"Œ",oelig:"œ",Scaron:"Š",scaron:"š",Yuml:"Ÿ",fnof:"ƒ",circ:"ˆ",tilde:"˜",Alpha:"Α",Beta:"Β",Gamma:"Γ",Delta:"Δ",Epsilon:"Ε",Zeta:"Ζ",Eta:"Η",Theta:"Θ",Iota:"Ι",Kappa:"Κ",Lambda:"Λ",Mu:"Μ",Nu:"Ν",Xi:"Ξ",Omicron:"Ο",Pi:"Π",Rho:"Ρ",Sigma:"Σ",Tau:"Τ",Upsilon:"Υ",Phi:"Φ",Chi:"Χ",Psi:"Ψ",Omega:"Ω",alpha:"α",beta:"β",gamma:"γ",delta:"δ",epsilon:"ε",zeta:"ζ",eta:"η",theta:"θ",iota:"ι",kappa:"κ",lambda:"λ",mu:"μ",nu:"ν",xi:"ξ",omicron:"ο",pi:"π",rho:"ρ",sigmaf:"ς",sigma:"σ",tau:"τ",upsilon:"υ",phi:"φ",chi:"χ",psi:"ψ",omega:"ω",thetasym:"ϑ",upsih:"ϒ",piv:"ϖ",ensp:" ",emsp:" ",thinsp:" ",zwnj:"‌",zwj:"‍",lrm:"‎",rlm:"‏",ndash:"–",mdash:"—",lsquo:"‘",rsquo:"’",sbquo:"‚",ldquo:"“",rdquo:"”",bdquo:"„",dagger:"†",Dagger:"‡",bull:"•",hellip:"…",permil:"‰",prime:"′",Prime:"″",lsaquo:"‹",rsaquo:"›",oline:"‾",frasl:"⁄",euro:"€",image:"ℑ",weierp:"℘",real:"ℜ",trade:"™",alefsym:"ℵ",larr:"←",uarr:"↑",rarr:"→",darr:"↓",harr:"↔",crarr:"↵",lArr:"⇐",uArr:"⇑",rArr:"⇒",dArr:"⇓",hArr:"⇔",forall:"∀",part:"∂",exist:"∃",empty:"∅",nabla:"∇",isin:"∈",notin:"∉",ni:"∋",prod:"∏",sum:"∑",minus:"−",lowast:"∗",radic:"√",prop:"∝",infin:"∞",ang:"∠",and:"∧",or:"∨",cap:"∩",cup:"∪",int:"∫",there4:"∴",sim:"∼",cong:"≅",asymp:"≈",ne:"≠",equiv:"≡",le:"≤",ge:"≥",sub:"⊂",sup:"⊃",nsub:"⊄",sube:"⊆",supe:"⊇",oplus:"⊕",otimes:"⊗",perp:"⊥",sdot:"⋅",lceil:"⌈",rceil:"⌉",lfloor:"⌊",rfloor:"⌋",loz:"◊",spades:"♠",clubs:"♣",hearts:"♥",diams:"♦",lang:"⟨",rang:"⟩"}},function(o,s,u){Object.defineProperty(s,"__esModule",{value:!0});var c=u(10),p=u(12),l=u(13),f=function(){function v(){this.values=[],this.curly=this.paren=-1}return v.prototype.beforeFunctionExpression=function(m){return["(","{","[","in","typeof","instanceof","new","return","case","delete","throw","void","=","+=","-=","*=","**=","/=","%=","<<=",">>=",">>>=","&=","|=","^=",",","+","-","*","**","/","%","++","--","<<",">>",">>>","&","|","^","!","~","&&","||","?",":","===","==",">=","<=","<",">","!=","!=="].indexOf(m)>=0},v.prototype.isRegexStart=function(){var m=this.values[this.values.length-1],x=m!==null;switch(m){case"this":case"]":x=!1;break;case")":var y=this.values[this.paren-1];x=y==="if"||y==="while"||y==="for"||y==="with";break;case"}":if(x=!1,this.values[this.curly-3]==="function")x=!!(d=this.values[this.curly-4])&&!this.beforeFunctionExpression(d);else if(this.values[this.curly-4]==="function"){var d;x=!(d=this.values[this.curly-5])||!this.beforeFunctionExpression(d)}}return x},v.prototype.push=function(m){m.type===7||m.type===4?(m.value==="{"?this.curly=this.values.length:m.value==="("&&(this.paren=this.values.length),this.values.push(m.value)):this.values.push(null)},v}(),h=function(){function v(m,x){this.errorHandler=new c.ErrorHandler,this.errorHandler.tolerant=!!x&&typeof x.tolerant=="boolean"&&x.tolerant,this.scanner=new p.Scanner(m,this.errorHandler),this.scanner.trackComment=!!x&&typeof x.comment=="boolean"&&x.comment,this.trackRange=!!x&&typeof x.range=="boolean"&&x.range,this.trackLoc=!!x&&typeof x.loc=="boolean"&&x.loc,this.buffer=[],this.reader=new f}return v.prototype.errors=function(){return this.errorHandler.errors},v.prototype.getNextToken=function(){if(this.buffer.length===0){var m=this.scanner.scanComments();if(this.scanner.trackComment)for(var x=0;x0?N.charCodeAt(k-1):null,ae=ae&&g(G,W)}else{for(k=0;kP&&N[Q+1]!==" ",Q=k);else if(!d(G))return 5;W=k>0?N.charCodeAt(k-1):null,ae=ae&&g(G,W)}Y=Y||q&&k-Q-1>P&&N[Q+1]!==" "}return X||Y?B>9&&C(N)?5:Y?4:3:ae&&!F(N)?1:2}function T(N,L,B,P){N.dump=function(){if(L.length===0)return"''";if(!N.noCompatMode&&f.indexOf(L)!==-1)return"'"+L+"'";var F=N.indent*Math.max(1,B),k=N.lineWidth===-1?-1:Math.max(Math.min(N.lineWidth,40),N.lineWidth-F),G=P||N.flowLevel>-1&&B>=N.flowLevel;switch(S(L,G,N.indent,k,function(W){return function(H,X){var Y,q;for(Y=0,q=H.implicitTypes.length;Y"+w(L,N.indent)+_(m(function(W,H){for(var X,Y,q=/(\n+)([^\n]*)/g,Q=(ne=W.indexOf(` diff --git a/src/trame_vtk/modules/paraview/LICENSE.md b/src/trame_vtk/modules/paraview/LICENSE.md index 3876673..93a2b49 100644 --- a/src/trame_vtk/modules/paraview/LICENSE.md +++ b/src/trame_vtk/modules/paraview/LICENSE.md @@ -1,6 +1,6 @@ -Copyright (c) 2005-2008 Sandia Corporation, Kitware Inc. -Sandia National Laboratories, New Mexico PO Box 5800 Albuquerque, NM 87185 -Kitware Inc., 28 Corporate Drive, Clifton Park, NY 12065, USA +Copyright (c) 2005-2008 Sandia Corporation, Kitware Inc. Sandia National +Laboratories, New Mexico PO Box 5800 Albuquerque, NM 87185 Kitware Inc., 28 +Corporate Drive, Clifton Park, NY 12065, USA Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive license for use of this work by or on behalf of the U.S. Government. @@ -8,14 +8,14 @@ for use of this work by or on behalf of the U.S. Government. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -* Redistributions of source code must retain the above copyright notice, this list - of conditions and the following disclaimer. +- Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. -* Redistributions in binary form must reproduce the above copyright notice, this +- Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -* Neither the name of Kitware nor the names of any contributors may be used to +- Neither the name of Kitware nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission. @@ -28,4 +28,4 @@ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/src/trame_vtk/modules/paraview/__init__.py b/src/trame_vtk/modules/paraview/__init__.py index 232c996..8d02c71 100644 --- a/src/trame_vtk/modules/paraview/__init__.py +++ b/src/trame_vtk/modules/paraview/__init__.py @@ -18,8 +18,10 @@ def __init__(self, trame_server): self._hybrid_views = {} try: # defer need to paraview to support --www usecase - from paraview import servermanager - from paraview.modules.vtkPVClientWeb import vtkPVWebApplication + from paraview import servermanager # noqa: PLC0415 + from paraview.modules.vtkPVClientWeb import ( # noqa: PLC0415 + vtkPVWebApplication, + ) except ImportError: logger.exception("*** ERROR: ParaView is not available!") else: @@ -68,7 +70,7 @@ def scene( new_state=False, widgets=None, orientation_axis=0, - **kwargs, + **_, ): # flush data without requiring a render/picture tmp = view_proxy.SuppressRendering @@ -89,7 +91,7 @@ def scene( scene_state.setdefault("extra", {})["resetCamera"] = 1 return scene_state - def export(self, render_window, widgets=None, orientation_axis=0, **kwargs): + def export(self, render_window, widgets=None, orientation_axis=0, **_): return self._trame_server.protocol_call( "viewport.geometry.view.get.export", self.id(render_window), @@ -168,7 +170,7 @@ def view(self, view_proxy, name="view", **kwargs): def configure_protocol(self, protocol): self._root_protocol = protocol - from .protocols import ( + from .protocols import ( # noqa: PLC0415 ParaViewWebLocalRendering, ParaViewWebMouseHandler, ParaViewWebPublishImageDelivery, @@ -189,7 +191,7 @@ def configure_protocol(self, protocol): self._root_protocol.registerLinkProtocol(ParaViewWebLocalRendering()) # Mimic client interactor on server side - from .core import apply_default_interaction_settings + from .core import apply_default_interaction_settings # noqa: PLC0415 apply_default_interaction_settings() @@ -203,14 +205,14 @@ def add_hybrid_view( still_ratio=1, still_quality=98, force_replace=False, - **kwargs, + **_, ): if name in self._hybrid_views: if force_replace: self._hybrid_views[name].replace_view(view) else: - print(f"A view with name ({name}) is already registered") - print(" => returning previous one") + print(f"A view with name ({name}) is already registered") # noqa: T201 + print(" => returning previous one") # noqa: T201 return self._hybrid_views[name] view_helper = HybridView( @@ -237,8 +239,7 @@ def remove_hybrid_view(self, name): HELPERS_PER_SERVER = {} -def setup(trame_server, **kwargs): - global HELPERS_PER_SERVER +def setup(trame_server, **_): HELPERS_PER_SERVER[trame_server.name] = Helper(trame_server) diff --git a/src/trame_vtk/modules/paraview/protocols/__init__.py b/src/trame_vtk/modules/paraview/protocols/__init__.py index 8f84bf6..38d8944 100644 --- a/src/trame_vtk/modules/paraview/protocols/__init__.py +++ b/src/trame_vtk/modules/paraview/protocols/__init__.py @@ -3,7 +3,6 @@ from .publish_image_delivery import ParaViewWebPublishImageDelivery from .view_port import ParaViewWebViewPort - __all__ = [ "ParaViewWebLocalRendering", "ParaViewWebMouseHandler", diff --git a/src/trame_vtk/modules/paraview/protocols/local_rendering.py b/src/trame_vtk/modules/paraview/protocols/local_rendering.py index 69d81a9..4895248 100644 --- a/src/trame_vtk/modules/paraview/protocols/local_rendering.py +++ b/src/trame_vtk/modules/paraview/protocols/local_rendering.py @@ -2,19 +2,19 @@ from wslink import register as export_rpc from trame_vtk.modules.vtk.serializers import ( - reference_id, + SynchronizationContext, + extract_array_hash, initialize_serializers, + reference_id, serialize, serialize_widget, - extract_array_hash, - SynchronizationContext, ) from .web_protocol import ParaViewWebProtocol class ParaViewWebLocalRendering(ParaViewWebProtocol): - def __init__(self, **kwargs): + def __init__(self, **_): super().__init__() initialize_serializers() self.context = SynchronizationContext() @@ -35,7 +35,7 @@ def get_array(self, data_hash, binary=False): def add_view_observer(self, view_id): s_view = self.get_view(view_id) if not s_view: - return {"error": "Unable to get view with id %s" % view_id} + return {"error": f"Unable to get view with id {view_id}"} real_view_id = s_view.GetGlobalIDAsString() @@ -68,7 +68,7 @@ def observer_callback(*_, **__): def remove_view_observer(self, view_id): s_view = self.get_view(view_id) if not s_view: - return {"error": "Unable to get view with id %s" % view_id} + return {"error": f"Unable to get view with id {view_id}"} real_view_id = s_view.GetGlobalIDAsString() @@ -77,7 +77,7 @@ def remove_view_observer(self, view_id): observer_info = self.tracking_views[real_view_id] if not observer_info: - return {"error": "Unable to find subscription for view %s" % real_view_id} + return {"error": f"Unable to find subscription for view {real_view_id}"} observer_info["observerCount"] -= 1 @@ -96,11 +96,11 @@ def get_view_state( new_subscription=False, widgets=None, orientation_axis=0, - **kwargs, + **_, ): s_view = self.get_view(view_id) if not s_view: - return {"error": "Unable to get view with id %s" % view_id} + return {"error": f"Unable to get view with id {view_id}"} self.context.set_ignore_last_dependencies(new_subscription) @@ -151,4 +151,4 @@ def get_standalone_state(self, view_id, widgets=None, orientation_axis=0, **kwar **entry, content=self.context.get_cached_data_array(data_hash, False) ) - return dict(hashes=hashes, scene=scene_description) + return {"hashes": hashes, "scene": scene_description} diff --git a/src/trame_vtk/modules/paraview/protocols/mouse_handler.py b/src/trame_vtk/modules/paraview/protocols/mouse_handler.py index e23b082..5af2293 100644 --- a/src/trame_vtk/modules/paraview/protocols/mouse_handler.py +++ b/src/trame_vtk/modules/paraview/protocols/mouse_handler.py @@ -1,12 +1,11 @@ -from wslink import register as export_rpc - from vtkmodules.vtkWebCore import vtkWebInteractionEvent +from wslink import register as export_rpc from .web_protocol import ParaViewWebProtocol class ParaViewWebMouseHandler(ParaViewWebProtocol): - def __init__(self, **kwargs): + def __init__(self, **_): super().__init__() self.last_action = "up" diff --git a/src/trame_vtk/modules/paraview/protocols/publish_image_delivery.py b/src/trame_vtk/modules/paraview/protocols/publish_image_delivery.py index 7cb4d2d..d7fcd1c 100644 --- a/src/trame_vtk/modules/paraview/protocols/publish_image_delivery.py +++ b/src/trame_vtk/modules/paraview/protocols/publish_image_delivery.py @@ -1,13 +1,13 @@ import base64 import math import time +from contextlib import suppress from paraview import simple +from vtkmodules.vtkWebCore import vtkWebInteractionEvent from wslink import register as export_rpc from wslink import schedule_callback -from vtkmodules.vtkWebCore import vtkWebInteractionEvent - from .web_protocol import ParaViewWebProtocol @@ -19,7 +19,7 @@ def apply_modifiers(event, interactor): class ParaViewWebPublishImageDelivery(ParaViewWebProtocol): - def __init__(self, decode=True, **kwargs): + def __init__(self, decode=True, **_): super().__init__() self.tracking_views = {} self.last_stale_time = {} @@ -141,8 +141,7 @@ def animate(self, render_all_views=True): next_animate_time -= time.time() - if self.target_frame_rate > self.max_frame_rate: - self.target_frame_rate = self.max_frame_rate + self.target_frame_rate = min(self.target_frame_rate, self.max_frame_rate) if next_animate_time < 0: if next_animate_time < -1.0: @@ -155,7 +154,7 @@ def animate(self, render_all_views=True): schedule_callback(0.001, lambda: self.animate(not render_all_views)) else: # Keep animating at the best rate we can - schedule_callback(0.001, lambda: self.animate()) + schedule_callback(0.001, self.animate) else: # We have time so let's render all if ( @@ -163,7 +162,7 @@ def animate(self, render_all_views=True): and next_animate_time > 0.005 ): self.target_frame_rate += 1.0 - schedule_callback(next_animate_time, lambda: self.animate()) + schedule_callback(next_animate_time, self.animate) @export_rpc("viewport.image.animation.fps.max") def set_max_frame_rate(self, fps=30): @@ -231,14 +230,14 @@ def still_render(self, options): """ RPC Callback to render a view and obtain the rendered image. """ - begin_time = int(round(time.time() * 1000)) + begin_time = round(time.time() * 1000) view_id = str(options["view"]) view = self.get_view(view_id) # If no view id provided, skip rendering if not view_id: - print("No view") - print(options) + print("No view") # noqa: T201 + print(options) # noqa: T201 return None # Make sure request match our selected view @@ -328,7 +327,7 @@ def still_render(self, options): # Convert the vtkUnsignedCharArray into a bytes object, required by Autobahn websockets reply["image"] = memoryview(reply_image).tobytes() if reply_image else None - end_time = int(round(time.time() * 1000)) + end_time = round(time.time() * 1000) reply["workTime"] = end_time - begin_time return reply @@ -337,7 +336,7 @@ def still_render(self, options): def add_render_observer(self, view_id): s_view = self.get_view(view_id) if not s_view: - return {"error": "Unable to get view with id %s" % view_id} + return {"error": f"Unable to get view with id {view_id}"} real_view_id = s_view.GetGlobalIDAsString() @@ -378,7 +377,7 @@ def remove_render_observer(self, view_id): try: s_view = self.get_view(view_id) except Exception: - print("no view with ID %s available in remove_render_observer" % view_id) + print(f"no view with ID {view_id} available in remove_render_observer") # noqa: T201 real_view_id = s_view.GetGlobalIDAsString() if s_view else view_id @@ -387,7 +386,7 @@ def remove_render_observer(self, view_id): observer_info = self.tracking_views[real_view_id] if not observer_info: - return {"error": "Unable to find subscription for view %s" % real_view_id} + return {"error": f"Unable to find subscription for view {real_view_id}"} observer_info["observerCount"] -= 1 @@ -401,7 +400,7 @@ def remove_render_observer(self, view_id): @export_rpc("viewport.image.push.quality.get") def get_view_quality(self, view_id): - response = dict(quality=1, ratio=1) + response = {"quality": 1, "ratio": 1} s_view = self.get_view(view_id) if s_view: @@ -417,7 +416,7 @@ def get_view_quality(self, view_id): def set_view_quality(self, view_id, quality, ratio=1, update_linked_view=True): s_view = self.get_view(view_id) if not s_view: - return {"error": "Unable to get view with id %s" % view_id} + return {"error": f"Unable to get view with id {view_id}"} real_view_id = s_view.GetGlobalIDAsString() observer_info = None @@ -425,7 +424,7 @@ def set_view_quality(self, view_id, quality, ratio=1, update_linked_view=True): observer_info = self.tracking_views[real_view_id] if not observer_info: - return {"error": "Unable to find subscription for view %s" % real_view_id} + return {"error": f"Unable to find subscription for view {real_view_id}"} observer_info["quality"] = quality observer_info["ratio"] = ratio @@ -455,7 +454,7 @@ def set_view_size(self, view_id, width, height): s_view = self.get_view(view_id) if not s_view: - return {"error": "Unable to get view with id %s" % view_id} + return {"error": f"Unable to get view with id {view_id}"} real_view_id = s_view.GetGlobalIDAsString() observer_info = None @@ -463,7 +462,7 @@ def set_view_size(self, view_id, width, height): observer_info = self.tracking_views[real_view_id] if not observer_info: - return {"error": "Unable to find subscription for view %s" % real_view_id} + return {"error": f"Unable to find subscription for view {real_view_id}"} observer_info["originalSize"] = (int(width + 0.5), int(height + 0.5)) @@ -473,7 +472,7 @@ def set_view_size(self, view_id, width, height): def enable_view(self, view_id, enabled): s_view = self.get_view(view_id) if not s_view: - return {"error": "Unable to get view with id %s" % view_id} + return {"error": f"Unable to get view with id {view_id}"} real_view_id = s_view.GetGlobalIDAsString() observer_info = None @@ -481,7 +480,7 @@ def enable_view(self, view_id, enabled): observer_info = self.tracking_views[real_view_id] if not observer_info: - return {"error": "Unable to find subscription for view %s" % real_view_id} + return {"error": f"Unable to find subscription for view {real_view_id}"} observer_info["enabled"] = enabled @@ -491,7 +490,7 @@ def enable_view(self, view_id, enabled): def invalidate_cache(self, view_id): s_view = self.get_view(view_id) if not s_view: - return {"error": "Unable to get view with id %s" % view_id} + return {"error": f"Unable to get view with id {view_id}"} self.app.InvalidateCache(s_view.SMProxy) self.app.InvokeEvent("UpdateEvent") @@ -510,9 +509,8 @@ def validate_view_links(self): view_list = [self.get_view(vid) for vid in self.linked_views] ref_view = view_list.pop(0) for view in view_list: - link_name = "%s_%s" % ( - ref_view.GetGlobalIDAsString(), - view.GetGlobalIDAsString(), + link_name = ( + f"{ref_view.GetGlobalIDAsString()}_{view.GetGlobalIDAsString()}" ) simple.AddCameraLink(ref_view, view, link_name) self.link_names.append(link_name) @@ -528,10 +526,8 @@ def update_view_link(self, view_id=None, link_state=False): if link_state: self.linked_views.append(view_id) else: - try: + with suppress(Exception): self.linked_views.remove(view_id) - except Exception: - pass # self.validate_view_links() if len(self.linked_views) > 1: diff --git a/src/trame_vtk/modules/paraview/protocols/view_port.py b/src/trame_vtk/modules/paraview/protocols/view_port.py index e91bcf6..5c8bc45 100644 --- a/src/trame_vtk/modules/paraview/protocols/view_port.py +++ b/src/trame_vtk/modules/paraview/protocols/view_port.py @@ -1,3 +1,5 @@ +from contextlib import suppress + from paraview import simple from wslink import register as export_rpc @@ -5,7 +7,7 @@ class ParaViewWebViewPort(ParaViewWebProtocol): - def __init__(self, scale=1.0, max_width=2560, max_height=1440, **kwargs): + def __init__(self, scale=1.0, max_width=2560, max_height=1440, **_): super().__init__() self.scale = scale self.max_width = max_width @@ -20,10 +22,8 @@ def reset_camera(self, view_id): view = self.get_view(view_id) simple.Render(view) simple.ResetCamera(view) - try: + with suppress(AttributeError): view.CenterOfRotation = view.CameraFocalPoint - except AttributeError: - pass self.app.InvalidateCache(view.SMProxy) self.app.InvokeEvent("UpdateEvent") diff --git a/src/trame_vtk/modules/paraview/protocols/web_protocol.py b/src/trame_vtk/modules/paraview/protocols/web_protocol.py index bd882b5..7c8b6f2 100644 --- a/src/trame_vtk/modules/paraview/protocols/web_protocol.py +++ b/src/trame_vtk/modules/paraview/protocols/web_protocol.py @@ -1,4 +1,5 @@ import os +from pathlib import Path from paraview import simple from paraview.servermanager import vtkSMTransferFunctionManager @@ -41,13 +42,14 @@ def get_view(self, vid): view = simple.GetActiveView() if not view: - raise Exception(f"no view provided: {vid}") + error_message = f"no view provided: {vid}" + raise Exception(error_message) return view def debug(self, msg): if self.debug_mode: - print(msg) + print(msg) # noqa: T201 def set_base_directory(self, base_path): self.override_data_dir_key = None @@ -58,7 +60,7 @@ def set_base_directory(self, base_path): if base_path.find("|") < 0: if base_path.find("=") >= 0: base_pair = base_path.split("=") - if os.path.exists(base_pair[1]): + if Path(base_pair[1]).exists(): self.base_directory = base_pair[1] self.override_data_dir_key = base_pair[0] else: @@ -68,7 +70,7 @@ def set_base_directory(self, base_path): base_dirs = base_path.split("|") for base_dir in base_dirs: base_pair = base_dir.split("=") - if os.path.exists(base_pair[1]): + if Path(base_pair[1]).exists(): self.base_directory_map[base_pair[0]] = os.path.normpath( base_pair[1] ) @@ -90,15 +92,15 @@ def get_absolute_path(self, relative_path): if self.multi_root: rel_path_parts = relative_path.replace("\\", "/").split("/") real_base_path = self.base_directory_map[rel_path_parts[0]] - absolute_path = os.path.join(real_base_path, *rel_path_parts[1:]) + absolute_path = Path.joinpath(real_base_path, *rel_path_parts[1:]) else: - absolute_path = os.path.join(self.base_directory, relative_path) + absolute_path = Path(self.base_directory) / relative_path cleaned_path = os.path.normpath(absolute_path) # Make sure the cleaned_path is part of the allowed ones if self.multi_root: - for key, value in self.base_directory_map.items(): + for _, value in self.base_directory_map.items(): if cleaned_path.startswith(value): return cleaned_path elif cleaned_path.startswith(self.base_directory): diff --git a/src/trame_vtk/modules/vtk/LICENSE.md b/src/trame_vtk/modules/vtk/LICENSE.md index 4470a08..54da221 100644 --- a/src/trame_vtk/modules/vtk/LICENSE.md +++ b/src/trame_vtk/modules/vtk/LICENSE.md @@ -1,34 +1,33 @@ -/*========================================================================= +/\*========================================================================= - Program: Visualization Toolkit - Module: Copyright.txt +Program: Visualization Toolkit Module: Copyright.txt -Copyright (c) 1993-2015 Ken Martin, Will Schroeder, Bill Lorensen -All rights reserved. +Copyright (c) 1993-2015 Ken Martin, Will Schroeder, Bill Lorensen All rights +reserved. -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. +- Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. +- Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. - * Neither name of Ken Martin, Will Schroeder, or Bill Lorensen nor the names - of any contributors may be used to endorse or promote products derived - from this software without specific prior written permission. +- Neither name of Ken Martin, Will Schroeder, or Bill Lorensen nor the names of + any contributors may be used to endorse or promote products derived from this + software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=========================================================================*/ \ No newline at end of file +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=========================================================================\*/ diff --git a/src/trame_vtk/modules/vtk/__init__.py b/src/trame_vtk/modules/vtk/__init__.py index 97e7cd6..f21de15 100644 --- a/src/trame_vtk/modules/vtk/__init__.py +++ b/src/trame_vtk/modules/vtk/__init__.py @@ -1,7 +1,7 @@ -import warnings import importlib import os import sys +import warnings from .core import HybridView from .serializers import mesh as vtk_mesh @@ -11,7 +11,7 @@ sys.modules["vtk_module"] = importlib.import_module(vtk_module_name) HAS_VTK = True except ImportError: - warnings.warn("VTK is not installed.") + warnings.warn("VTK is not installed.", stacklevel=2) HAS_VTK = False try: @@ -30,7 +30,7 @@ """ -def has_capabilities(*features): +def has_capabilities(*_): if not HAS_VTK_WEB: raise ImportError(IMPROPER_VTK_MSG) @@ -76,7 +76,7 @@ def scene( new_state=False, widgets=None, orientation_axis=0, - **kwargs, + **_, ): scene_state = self._trame_server.protocol_call( "viewport.geometry.view.get.state", @@ -89,7 +89,7 @@ def scene( scene_state.setdefault("extra", {})["resetCamera"] = 1 return scene_state - def export(self, render_window, widgets=None, orientation_axis=0, **kwargs): + def export(self, render_window, widgets=None, orientation_axis=0, **_): return self._trame_server.protocol_call( "viewport.geometry.view.get.export", self.id(render_window), @@ -166,7 +166,7 @@ def view(self, view, name="view", **kwargs): def configure_protocol(self, protocol): self._root_protocol = protocol - from .protocols import ( + from .protocols import ( # noqa: PLC0415 vtkWebLocalRendering, vtkWebMouseHandler, vtkWebPublishImageDelivery, @@ -196,14 +196,14 @@ def add_hybrid_view( still_ratio=1, still_quality=98, force_replace=False, - **kwargs, + **_, ): if name in self._hybrid_views: if force_replace: self._hybrid_views[name].replace_view(view) else: - print(f"A view with name ({name}) is already registered") - print(" => returning previous one") + print(f"A view with name ({name}) is already registered") # noqa: T201 + print(" => returning previous one") # noqa: T201 return self._hybrid_views[name] view_helper = HybridView( @@ -234,8 +234,7 @@ def reload_app(self): HELPERS_PER_SERVER = {} -def setup(trame_server, **kwargs): - global HELPERS_PER_SERVER +def setup(trame_server, **_): if HAS_VTK_WEB: HELPERS_PER_SERVER[trame_server.name] = Helper(trame_server) diff --git a/src/trame_vtk/modules/vtk/protocols/local_rendering.py b/src/trame_vtk/modules/vtk/protocols/local_rendering.py index 39e8439..436dec6 100644 --- a/src/trame_vtk/modules/vtk/protocols/local_rendering.py +++ b/src/trame_vtk/modules/vtk/protocols/local_rendering.py @@ -1,12 +1,12 @@ from wslink import register as export_rpc from ..serializers import ( - reference_id, + SynchronizationContext, + extract_array_hash, initialize_serializers, + reference_id, serialize, serialize_widget, - extract_array_hash, - SynchronizationContext, ) from .web_protocol import vtkWebProtocol @@ -18,7 +18,7 @@ class vtkWebLocalRendering(vtkWebProtocol): client-side rendering capability we have in vtk.js """ - def __init__(self, **kwargs): + def __init__(self, **_): super().__init__() initialize_serializers() self.context = SynchronizationContext() @@ -39,7 +39,7 @@ def get_array(self, data_hash, binary=False): def add_view_observer(self, view_id): s_view = self.get_view(view_id) if not s_view: - return {"error": "Unable to get view with id %s" % view_id} + return {"error": f"Unable to get view with id {view_id}"} real_view_id = self.app.GetObjectIdMap().GetGlobalId(s_view) @@ -71,7 +71,7 @@ def observer_callback(*_, **__): def remove_view_observer(self, view_id): s_view = self.get_view(view_id) if not s_view: - return {"error": "Unable to get view with id %s" % view_id} + return {"error": f"Unable to get view with id {view_id}"} real_view_id = self.app.GetObjectIdMap().GetGlobalId(s_view) @@ -80,7 +80,7 @@ def remove_view_observer(self, view_id): observer_info = self.tracking_views[real_view_id] if not observer_info: - return {"error": "Unable to find subscription for view %s" % real_view_id} + return {"error": f"Unable to find subscription for view {real_view_id}"} observer_info["observerCount"] -= 1 @@ -99,11 +99,11 @@ def get_view_state( new_subscription=False, widgets=None, orientation_axis=0, - **kwargs, + **_, ): s_view = self.get_view(view_id) if not s_view: - return {"error": "Unable to get view with id %s" % view_id} + return {"error": f"Unable to get view with id {view_id}"} self.context.set_ignore_last_dependencies(new_subscription) @@ -156,4 +156,4 @@ def get_standalone_state(self, view_id, widgets=None, orientation_axis=0, **kwar **entry, content=self.context.get_cached_data_array(data_hash, False) ) - return dict(hashes=hashes, scene=scene_description) + return {"hashes": hashes, "scene": scene_description} diff --git a/src/trame_vtk/modules/vtk/protocols/mouse_handler.py b/src/trame_vtk/modules/vtk/protocols/mouse_handler.py index 86f6d6b..43c843a 100644 --- a/src/trame_vtk/modules/vtk/protocols/mouse_handler.py +++ b/src/trame_vtk/modules/vtk/protocols/mouse_handler.py @@ -1,17 +1,16 @@ +import importlib import math import os -import importlib import sys -vtk_module_name = os.environ.get("VTK_MODULE_NAME", "vtkmodules") -sys.modules["vtk_module"] = importlib.import_module(vtk_module_name) - from vtk_module.vtkWebCore import vtkWebInteractionEvent - from wslink import register as export_rpc from .web_protocol import vtkWebProtocol +vtk_module_name = os.environ.get("VTK_MODULE_NAME", "vtkmodules") +sys.modules["vtk_module"] = importlib.import_module(vtk_module_name) + def apply_modifiers(event, interactor): interactor.SetShiftKey(1 if event.get("shiftKey") else 0) diff --git a/src/trame_vtk/modules/vtk/protocols/publish_image_delivery.py b/src/trame_vtk/modules/vtk/protocols/publish_image_delivery.py index 474f11a..cb2b18a 100644 --- a/src/trame_vtk/modules/vtk/protocols/publish_image_delivery.py +++ b/src/trame_vtk/modules/vtk/protocols/publish_image_delivery.py @@ -105,22 +105,21 @@ def animate(self): next_animate_time -= time.time() - if self.target_frame_rate > self.max_frame_rate: - self.target_frame_rate = self.max_frame_rate + self.target_frame_rate = min(self.target_frame_rate, self.max_frame_rate) if next_animate_time < 0: if next_animate_time < -1.0: self.target_frame_rate = 1 if self.target_frame_rate > self.min_frame_rate: self.target_frame_rate -= 1.0 - schedule_callback(0.001, lambda: self.animate()) + schedule_callback(0.001, self.animate) else: if ( self.target_frame_rate < self.max_frame_rate and next_animate_time > 0.005 ): self.target_frame_rate += 1.0 - schedule_callback(next_animate_time, lambda: self.animate()) + schedule_callback(next_animate_time, self.animate) @export_rpc("viewport.image.animation.fps.max") def set_max_frame_rate(self, fps=30): @@ -161,7 +160,7 @@ def still_render(self, options): """ RPC Callback to render a view and obtain the rendered image. """ - begin_time = int(round(time.time() * 1000)) + begin_time = round(time.time() * 1000) view = self.get_view(options["view"]) if not view: # The view has been deleted, we can not render it... @@ -229,7 +228,7 @@ def still_render(self, options): # Convert the vtkUnsignedCharArray into a bytes object, required by Autobahn websockets reply["image"] = memoryview(reply_image).tobytes() if reply_image else None - end_time = int(round(time.time() * 1000)) + end_time = round(time.time() * 1000) reply["workTime"] = end_time - begin_time return reply @@ -238,7 +237,7 @@ def still_render(self, options): def add_render_observer(self, view_id): s_view = self.get_view(view_id) if not s_view: - return {"error": "Unable to get view with id %s" % view_id} + return {"error": f"Unable to get view with id {view_id}"} real_view_id = str(self.get_global_id(s_view)) @@ -276,7 +275,7 @@ def stop_callback(*_, **__): def remove_render_observer(self, view_id): s_view = self.get_view(view_id) if not s_view: - return {"error": "Unable to get view with id %s" % view_id} + return {"error": f"Unable to get view with id {view_id}"} real_view_id = str(self.get_global_id(s_view)) @@ -285,7 +284,7 @@ def remove_render_observer(self, view_id): observer_info = self.tracking_views[real_view_id] if not observer_info: - return {"error": "Unable to find subscription for view %s" % real_view_id} + return {"error": f"Unable to find subscription for view {real_view_id}"} observer_info["observerCount"] -= 1 @@ -298,7 +297,7 @@ def remove_render_observer(self, view_id): @export_rpc("viewport.image.push.quality.get") def get_view_quality(self, view_id): - response = dict(quality=1, ratio=1) + response = {"quality": 1, "ratio": 1} s_view = self.get_view(view_id) if s_view: @@ -314,7 +313,7 @@ def get_view_quality(self, view_id): def set_view_quality(self, view_id, quality, ratio=1): s_view = self.get_view(view_id) if not s_view: - return {"error": "Unable to get view with id %s" % view_id} + return {"error": f"Unable to get view with id {view_id}"} real_view_id = str(self.get_global_id(s_view)) observer_info = None @@ -322,7 +321,7 @@ def set_view_quality(self, view_id, quality, ratio=1): observer_info = self.tracking_views[real_view_id] if not observer_info: - return {"error": "Unable to find subscription for view %s" % real_view_id} + return {"error": f"Unable to find subscription for view {real_view_id}"} observer_info["quality"] = quality observer_info["ratio"] = ratio @@ -344,7 +343,7 @@ def set_view_quality(self, view_id, quality, ratio=1): def set_view_size(self, view_id, width, height): s_view = self.get_view(view_id) if not s_view: - return {"error": "Unable to get view with id %s" % view_id} + return {"error": f"Unable to get view with id {view_id}"} real_view_id = str(self.get_global_id(s_view)) observer_info = None @@ -352,7 +351,7 @@ def set_view_size(self, view_id, width, height): observer_info = self.tracking_views[real_view_id] if not observer_info: - return {"error": "Unable to find subscription for view %s" % real_view_id} + return {"error": f"Unable to find subscription for view {real_view_id}"} observer_info["originalSize"] = [width, height] @@ -362,7 +361,7 @@ def set_view_size(self, view_id, width, height): def enable_view(self, view_id, enabled): s_view = self.get_view(view_id) if not s_view: - return {"error": "Unable to get view with id %s" % view_id} + return {"error": f"Unable to get view with id {view_id}"} real_view_id = str(self.get_global_id(s_view)) observer_info = None @@ -370,7 +369,7 @@ def enable_view(self, view_id, enabled): observer_info = self.tracking_views[real_view_id] if not observer_info: - return {"error": "Unable to find subscription for view %s" % real_view_id} + return {"error": f"Unable to find subscription for view {real_view_id}"} observer_info["enabled"] = enabled @@ -380,7 +379,7 @@ def enable_view(self, view_id, enabled): def invalidate_cache(self, view_id): s_view = self.get_view(view_id) if not s_view: - return {"error": "Unable to get view with id %s" % view_id} + return {"error": f"Unable to get view with id {view_id}"} self.app.InvalidateCache(s_view) self.app.InvokeEvent("UpdateEvent") diff --git a/src/trame_vtk/modules/vtk/protocols/view_port.py b/src/trame_vtk/modules/vtk/protocols/view_port.py index 6e28e85..7d2599c 100644 --- a/src/trame_vtk/modules/vtk/protocols/view_port.py +++ b/src/trame_vtk/modules/vtk/protocols/view_port.py @@ -21,7 +21,7 @@ def reset_camera(self, view_id): return str(self.get_global_id(view)) @export_rpc("viewport.axes.orientation.visibility.update") - def update_orientation_axes_visibility(self, view_id, show_axis): + def update_orientation_axes_visibility(self, view_id, _depth): """ RPC callback to show/hide OrientationAxis. """ @@ -34,7 +34,7 @@ def update_orientation_axes_visibility(self, view_id, show_axis): return str(self.get_global_id(view)) @export_rpc("viewport.axes.center.visibility.update") - def update_center_axes_visibility(self, view_id, show_axis): + def update_center_axes_visibility(self, view_id, _depth): """ RPC callback to show/hide CenterAxesVisibility. """ diff --git a/src/trame_vtk/modules/vtk/protocols/web_protocol.py b/src/trame_vtk/modules/vtk/protocols/web_protocol.py index d52e5c0..8ba7d0b 100644 --- a/src/trame_vtk/modules/vtk/protocols/web_protocol.py +++ b/src/trame_vtk/modules/vtk/protocols/web_protocol.py @@ -50,7 +50,8 @@ def get_view(self, vid): # Use active view is none provided. v = self.app.GetObjectIdMap().GetActiveObject("VIEW") if not v: - raise Exception("no view provided: %s" % vid) + exception_message = f"no view provided: {vid}" + raise Exception(exception_message) return v diff --git a/src/trame_vtk/modules/vtk/serializers/__init__.py b/src/trame_vtk/modules/vtk/serializers/__init__.py index 63679ef..f1117e2 100644 --- a/src/trame_vtk/modules/vtk/serializers/__init__.py +++ b/src/trame_vtk/modules/vtk/serializers/__init__.py @@ -1,13 +1,12 @@ import logging import os +from .export import extract_array_hash +from .initialize import encode_lut, initialize_serializers, skip_light from .mesh import mesh -from .initialize import initialize_serializers from .serialize import serialize, serialize_widget -from .export import extract_array_hash from .synchronization_context import SynchronizationContext from .utils import reference_id -from .initialize import encode_lut, skip_light logger = logging.getLogger(__name__) # By default, only show critical messages for serializers @@ -24,14 +23,14 @@ def configure_serializer(**options): __all__ = [ + "SynchronizationContext", "configure_serializer", "encode_lut", - "skip_light", - "reference_id", + "extract_array_hash", "initialize_serializers", "mesh", + "reference_id", "serialize", - "SynchronizationContext", "serialize_widget", - "extract_array_hash", + "skip_light", ] diff --git a/src/trame_vtk/modules/vtk/serializers/actors.py b/src/trame_vtk/modules/vtk/serializers/actors.py index b6e70e2..99fa313 100644 --- a/src/trame_vtk/modules/vtk/serializers/actors.py +++ b/src/trame_vtk/modules/vtk/serializers/actors.py @@ -1,9 +1,9 @@ import logging +from .cache import cache_properties, get_cached_property from .registry import class_name from .serialize import serialize from .utils import reference_id, rgb_float_to_hex, wrap_id -from .cache import cache_properties, get_cached_property logger = logging.getLogger(__name__) @@ -229,7 +229,7 @@ def scalar_bar_actor_serializer(parent, actor, actor_id, context, depth): prop = actor.GetProperty() else: if context.debug_all: - print("This scalar_bar_actor does not have a GetProperty method") + print("This scalar_bar_actor does not have a GetProperty method") # noqa: T201 if prop: prop_id = reference_id(prop) @@ -298,7 +298,7 @@ def scalar_bar_actor_serializer(parent, actor, actor_id, context, depth): # ----------------------------------------------------------------------------- -def axes_actor_serializer(parent, actor, actor_id, context, depth): +def axes_actor_serializer(parent, actor, actor_id, context, _depth): actor_visibility = actor.GetVisibility() if not actor_visibility: @@ -373,15 +373,15 @@ def axes_actor_serializer(parent, actor, actor_id, context, depth): "shaftRadius": 0.01 if shaft_type else cylinder_radius, # 0.03, "invert": 0, }, - "xAxisColor": list( - map(lambda x: int(x * 255), actor.GetXAxisTipProperty().GetColor()) - ), - "yAxisColor": list( - map(lambda x: int(x * 255), actor.GetYAxisTipProperty().GetColor()) - ), - "zAxisColor": list( - map(lambda x: int(x * 255), actor.GetZAxisTipProperty().GetColor()) - ), + "xAxisColor": [ + int(x * 255) for x in actor.GetXAxisTipProperty().GetColor() + ], + "yAxisColor": [ + int(x * 255) for x in actor.GetYAxisTipProperty().GetColor() + ], + "zAxisColor": [ + int(x * 255) for x in actor.GetZAxisTipProperty().GetColor() + ], }, ), } diff --git a/src/trame_vtk/modules/vtk/serializers/data.py b/src/trame_vtk/modules/vtk/serializers/data.py index c8019e6..ae527c4 100644 --- a/src/trame_vtk/modules/vtk/serializers/data.py +++ b/src/trame_vtk/modules/vtk/serializers/data.py @@ -1,26 +1,34 @@ +import importlib import logging - import os -import importlib import sys -vtk_module_name = os.environ.get("VTK_MODULE_NAME", "vtkmodules") -sys.modules["vtk_module"] = importlib.import_module(vtk_module_name) - -from vtk_module.vtkFiltersGeometry import vtkCompositeDataGeometryFilter -from vtk_module.vtkFiltersGeometry import vtkDataSetSurfaceFilter +from vtk_module.vtkFiltersGeometry import ( + vtkCompositeDataGeometryFilter, + vtkDataSetSurfaceFilter, +) from .helpers import extract_required_fields, get_array_description from .registry import class_name from .serialize import serialize -from .utils import reference_id, wrap_id, get_js_array_type +from .utils import get_js_array_type, reference_id, wrap_id + +vtk_module_name = os.environ.get("VTK_MODULE_NAME", "vtkmodules") +sys.modules["vtk_module"] = importlib.import_module(vtk_module_name) logger = logging.getLogger(__name__) def polydata_serializer( - parent, dataset, dataset_id, context, depth, requested_fields=["Normals", "TCoords"] + parent, + dataset, + dataset_id, + context, + _depth, + requested_fields=None, ): + if requested_fields is None: + requested_fields = ["Normals", "TCoords"] if dataset and dataset.GetPoints(): properties = {} @@ -92,8 +100,10 @@ def merge_to_polydata_serializer( data_object_id, context, depth, - requested_fields=["Normals", "TCoords"], + requested_fields=None, ): + if requested_fields is None: + requested_fields = ["Normals", "TCoords"] dataset = None if data_object.IsA("vtkCompositeDataSet"): @@ -120,7 +130,12 @@ def merge_to_polydata_serializer( def imagedata_serializer( - parent, dataset, dataset_id, context, depth, requested_fields=["Normals", "TCoords"] + parent, + dataset, + dataset_id, + context, + _depth, + _requested_fields, ): if hasattr(dataset, "GetDirectionMatrix"): direction = [dataset.GetDirectionMatrix().GetElement(0, i) for i in range(9)] diff --git a/src/trame_vtk/modules/vtk/serializers/export.py b/src/trame_vtk/modules/vtk/serializers/export.py index 8eac946..481cfa6 100644 --- a/src/trame_vtk/modules/vtk/serializers/export.py +++ b/src/trame_vtk/modules/vtk/serializers/export.py @@ -9,11 +9,11 @@ def handle_property(hash_list, prop_value): if "vtkClass" in prop_value and "hash" in prop_value: hash_list.append( - dict( - hash=prop_value.get("hash"), - type=prop_value.get("dataType"), - vtk=prop_value.get("vtkClass"), - ) + { + "hash": prop_value.get("hash"), + "type": prop_value.get("dataType"), + "vtk": prop_value.get("vtkClass"), + } ) diff --git a/src/trame_vtk/modules/vtk/serializers/helpers.py b/src/trame_vtk/modules/vtk/serializers/helpers.py index a8a8699..fc8454e 100644 --- a/src/trame_vtk/modules/vtk/serializers/helpers.py +++ b/src/trame_vtk/modules/vtk/serializers/helpers.py @@ -10,10 +10,7 @@ def is_array_in(array, arrays): - for a in arrays: - if a is array: - return True - return False + return any(a is array for a in arrays) def data_table_to_list(data_table): @@ -106,8 +103,10 @@ def get_array_description(array, context, **kwargs): def extract_required_fields( - extracted_fields, parent, dataset, context, requested_fields=["Normals", "TCoords"] + extracted_fields, parent, dataset, context, requested_fields=None ): + if requested_fields is None: + requested_fields = ["Normals", "TCoords"] arrays_to_export = [] export_all = "*" in requested_fields # Identify arrays to export diff --git a/src/trame_vtk/modules/vtk/serializers/initialize.py b/src/trame_vtk/modules/vtk/serializers/initialize.py index 1832777..a1afb03 100644 --- a/src/trame_vtk/modules/vtk/serializers/initialize.py +++ b/src/trame_vtk/modules/vtk/serializers/initialize.py @@ -7,8 +7,8 @@ scalar_bar_actor_serializer, ) from .data import ( - imagedata_serializer, generic_volume_serializer, + imagedata_serializer, merge_to_polydata_serializer, polydata_serializer, ) @@ -25,30 +25,57 @@ from .registry import register_instance_serializer, register_js_class from .render_windows import ( camera_serializer, - renderer_serializer, render_window_serializer, + renderer_serializer, ) from .textures import texture_serializer logger = logging.getLogger(__name__) -CONVERT_LUT = False -SKIP_LIGHT = False + +class LUTConfig: + """Configuration globale pour les sérialiseurs VTK""" + + def __init__(self): + self._convert_lut = False + self._skip_light = False + + @property + def convert_lut(self): + return self._convert_lut + + @convert_lut.setter + def convert_lut(self, value): + self._convert_lut = value + + @property + def skip_light(self): + return self._skip_light + + @skip_light.setter + def skip_light(self, value): + self._skip_light = value + + def encode_lut(self, value=True): + self._convert_lut = value + + def skip_light(self, value=True): + self._skip_light = value + + +vtk_config = LUTConfig() def encode_lut(value=True): - global CONVERT_LUT - CONVERT_LUT = value + vtk_config.convert_lut = value def skip_light(value=True): - global SKIP_LIGHT - SKIP_LIGHT = value + vtk_config.skip_light = value def lookup_table_serializer_selector(*args, **kwargs): - global CONVERT_LUT - if CONVERT_LUT: + if vtk_config.convert_lut: return lookup_table_serializer2(*args, **kwargs) return lookup_table_serializer(*args, **kwargs) @@ -133,7 +160,7 @@ def initialize_serializers(): ], # Lights light_serializer: [] - if SKIP_LIGHT + if vtk_config.skip_light else [ "vtkLight", "vtkPVLight", @@ -167,15 +194,14 @@ def initialize_serializers(): } for serializer, names in serializers.items(): - if not isinstance(names, (list, tuple)): - names = [names] + names_list = [names] if not isinstance(names, (list, tuple)) else names - for name in names: + for name in names_list: register_instance_serializer(name, serializer) for js_class, vtk_classes in js_classes.items(): - if not isinstance(vtk_classes, (list, tuple)): - vtk_classes = [vtk_classes] - - for vtk_class in vtk_classes: + vtk_classes_list = ( + [vtk_classes] if not isinstance(vtk_classes, (list, tuple)) else vtk_classes + ) + for vtk_class in vtk_classes_list: register_js_class(vtk_class, js_class) diff --git a/src/trame_vtk/modules/vtk/serializers/lights.py b/src/trame_vtk/modules/vtk/serializers/lights.py index 671cbf3..47434b9 100644 --- a/src/trame_vtk/modules/vtk/serializers/lights.py +++ b/src/trame_vtk/modules/vtk/serializers/lights.py @@ -1,6 +1,6 @@ +from .cache import cache_properties from .registry import class_name from .utils import reference_id -from .cache import cache_properties def light_type_to_string(value): @@ -15,13 +15,13 @@ def light_type_to_string(value): """ if value == 1: return "HeadLight" - elif value == 2: + if value == 2: return "CameraLight" return "SceneLight" -def light_serializer(parent, instance, obj_id, context, depth): +def light_serializer(parent, instance, obj_id, context, _depth): return { "parent": reference_id(parent), "id": obj_id, diff --git a/src/trame_vtk/modules/vtk/serializers/lookup_tables.py b/src/trame_vtk/modules/vtk/serializers/lookup_tables.py index 8ecdc51..f74672e 100644 --- a/src/trame_vtk/modules/vtk/serializers/lookup_tables.py +++ b/src/trame_vtk/modules/vtk/serializers/lookup_tables.py @@ -1,19 +1,20 @@ -import os import importlib +import os import sys - -vtk_module_name = os.environ.get("VTK_MODULE_NAME", "vtkmodules") -sys.modules["vtk_module"] = importlib.import_module(vtk_module_name) +from contextlib import suppress from vtk_module.vtkRenderingCore import vtkColorTransferFunction +from .cache import cache_properties from .helpers import data_table_to_list, linspace from .registry import class_name from .utils import reference_id -from .cache import cache_properties + +vtk_module_name = os.environ.get("VTK_MODULE_NAME", "vtkmodules") +sys.modules["vtk_module"] = importlib.import_module(vtk_module_name) -def lookup_table_serializer(parent, lookup_table, lookup_table_id, context, depth): +def lookup_table_serializer(parent, lookup_table, lookup_table_id, context, _depth): # No children in this case, so no additions to bindings and return empty list # But we do need to add instance @@ -21,10 +22,8 @@ def lookup_table_serializer(parent, lookup_table, lookup_table_id, context, dept lookup_table_hue_range = [0.5, 0] if hasattr(lookup_table, "GetHueRange"): - try: + with suppress(Exception): lookup_table.GetHueRange(lookup_table_hue_range) - except Exception: - pass lut_sat_range = lookup_table.GetSaturationRange() table = data_table_to_list(lookup_table.GetTable()) @@ -37,8 +36,8 @@ def lookup_table_serializer(parent, lookup_table, lookup_table_id, context, dept "nanColor": lookup_table.GetNanColor(), "belowRangeColor": lookup_table.GetBelowRangeColor(), "aboveRangeColor": lookup_table.GetAboveRangeColor(), - "useAboveRangeColor": True if lookup_table.GetUseAboveRangeColor() else False, - "useBelowRangeColor": True if lookup_table.GetUseBelowRangeColor() else False, + "useAboveRangeColor": bool(lookup_table.GetUseAboveRangeColor()), + "useBelowRangeColor": bool(lookup_table.GetUseBelowRangeColor()), "alpha": lookup_table.GetAlpha(), "vectorSize": lookup_table.GetVectorSize(), "vectorComponent": lookup_table.GetVectorComponent(), @@ -92,7 +91,7 @@ def lookup_table_serializer2(parent, lookup_table, lookup_table_id, context, dep return None -def color_transfer_function_serializer(parent, instance, obj_id, context, depth): +def color_transfer_function_serializer(parent, instance, obj_id, context, _depth): nodes = [] for i in range(instance.GetSize()): # x, r, g, b, midpoint, sharpness @@ -153,7 +152,7 @@ def discretizable_color_transfer_function_serializer( return ctf -def pwf_serializer(parent, instance, obj_id, context, depth): +def pwf_serializer(parent, instance, obj_id, context, _depth): nodes = [] for i in range(instance.GetSize()): diff --git a/src/trame_vtk/modules/vtk/serializers/mappers.py b/src/trame_vtk/modules/vtk/serializers/mappers.py index b3b07e9..3e05e91 100644 --- a/src/trame_vtk/modules/vtk/serializers/mappers.py +++ b/src/trame_vtk/modules/vtk/serializers/mappers.py @@ -1,17 +1,17 @@ +import importlib import logging import os -import importlib import sys -vtk_module_name = os.environ.get("VTK_MODULE_NAME", "vtkmodules") -sys.modules["vtk_module"] = importlib.import_module(vtk_module_name) from vtk_module.vtkFiltersGeometry import vtkDataSetSurfaceFilter +from .cache import cache_properties from .registry import class_name from .serialize import serialize from .utils import reference_id, wrap_id -from .cache import cache_properties +vtk_module_name = os.environ.get("VTK_MODULE_NAME", "vtkmodules") +sys.modules["vtk_module"] = importlib.import_module(vtk_module_name) logger = logging.getLogger(__name__) @@ -27,9 +27,8 @@ def generic_mapper_serializer(parent, mapper, mapper_id, context, depth): if hasattr(mapper, "GetInputDataObject"): mapper.GetInputAlgorithm().Update() data_object = mapper.GetInputDataObject(0, 0) - else: - if context.debug_all: - print("This mapper does not have GetInputDataObject method") + elif context.debug_all: + print("This mapper does not have GetInputDataObject method") # noqa: T201 if data_object: if data_object.IsA("vtkDataSet"): @@ -38,7 +37,7 @@ def generic_mapper_serializer(parent, mapper, mapper_id, context, depth): alg.Update() data_object = alg.GetOutput() - data_object_id = "%s-dataset" % mapper_id + data_object_id = f"{mapper_id}-dataset" data_object_instance = serialize( mapper, data_object, data_object_id, context, depth + 1 ) @@ -51,9 +50,8 @@ def generic_mapper_serializer(parent, mapper, mapper_id, context, depth): if hasattr(mapper, "GetLookupTable"): lookup_table = mapper.GetLookupTable() - else: - if context.debug_all: - print("This mapper does not have GetLookupTable method") + elif context.debug_all: + print("This mapper does not have GetLookupTable method") # noqa: T201 if lookup_table: lookup_table_id = reference_id(lookup_table) @@ -120,7 +118,7 @@ def generic_volume_mapper_serializer(parent, mapper, mapper_id, context, depth): logger.debug("This mapper does not have GetInputDataObject method") if data_object: - data_object_id = "%s-dataset" % mapper_id + data_object_id = f"{mapper_id}-dataset" data_object_instance = serialize( mapper, data_object, data_object_id, context, depth + 1 ) diff --git a/src/trame_vtk/modules/vtk/serializers/mesh.py b/src/trame_vtk/modules/vtk/serializers/mesh.py index dff46d4..e88d64b 100644 --- a/src/trame_vtk/modules/vtk/serializers/mesh.py +++ b/src/trame_vtk/modules/vtk/serializers/mesh.py @@ -1,16 +1,15 @@ import base64 - -import numpy as np -import os import importlib +import os import sys -vtk_module_name = os.environ.get("VTK_MODULE_NAME", "vtkmodules") -sys.modules["vtk_module"] = importlib.import_module(vtk_module_name) - +import numpy as np from vtk_module.util.numpy_support import vtk_to_numpy from vtk_module.vtkFiltersGeometry import vtkDataSetSurfaceFilter +vtk_module_name = os.environ.get("VTK_MODULE_NAME", "vtkmodules") +sys.modules["vtk_module"] = importlib.import_module(vtk_module_name) + def mesh(dataset, field_to_keep=None, point_arrays=None, cell_arrays=None): """Expect any dataset and extract its surface into a dash_vtk.Mesh state property""" @@ -84,24 +83,29 @@ def mesh(dataset, field_to_keep=None, point_arrays=None, cell_arrays=None): def mesh_array(array): - if array: - return b64_encode_numpy(vtk_to_numpy(array.GetData())) + if not array: + msg = "array cannot be None or empty" + raise ValueError(msg) + return b64_encode_numpy(vtk_to_numpy(array.GetData())) def data_array(data_array, location="PointData", name=None): - if data_array: - data_range = data_array.GetRange(-1) - nb_comp = data_array.GetNumberOfComponents() - values = vtk_to_numpy(data_array) - js_types = to_js_type[str(values.dtype)] - return { - "name": name if name else data_array.GetName(), - "values": b64_encode_numpy(values), - "numberOfComponents": nb_comp, - "type": js_types, - "location": location, - "dataRange": data_range, - } + if not data_array: + msg = "data array cannot be None or empty" + raise ValueError(msg) + + data_range = data_array.GetRange(-1) + nb_comp = data_array.GetNumberOfComponents() + values = vtk_to_numpy(data_array) + js_types = to_js_type[str(values.dtype)] + return { + "name": name if name else data_array.GetName(), + "values": b64_encode_numpy(values), + "numberOfComponents": nb_comp, + "type": js_types, + "location": location, + "dataRange": data_range, + } def field_data(field_data, names, location="PointData"): @@ -170,9 +174,9 @@ def b64_encode_numpy(obj): dtype = obj.dtype if dtype.kind == "f": return np_encode(obj) - elif dtype.kind == "b": + if dtype.kind == "b": return np_encode(obj, np.uint8) - elif dtype.kind in ["u", "i"]: + if dtype.kind in ["u", "i"]: # Try to see if we can downsize the array max_value = np.amax(obj) min_value = np.amin(obj) diff --git a/src/trame_vtk/modules/vtk/serializers/properties.py b/src/trame_vtk/modules/vtk/serializers/properties.py index e5e8538..7149fde 100644 --- a/src/trame_vtk/modules/vtk/serializers/properties.py +++ b/src/trame_vtk/modules/vtk/serializers/properties.py @@ -1,10 +1,10 @@ +from .cache import cache_properties from .registry import class_name from .serialize import serialize from .utils import reference_id, wrap_id -from .cache import cache_properties -def property_serializer(parent, prop_obj, prop_obj_id, context, depth): +def property_serializer(parent, prop_obj, prop_obj_id, context, _depth): representation = ( prop_obj.GetRepresentation() if hasattr(prop_obj, "GetRepresentation") else 2 ) diff --git a/src/trame_vtk/modules/vtk/serializers/render_windows.py b/src/trame_vtk/modules/vtk/serializers/render_windows.py index a4eb9c0..a267c7e 100644 --- a/src/trame_vtk/modules/vtk/serializers/render_windows.py +++ b/src/trame_vtk/modules/vtk/serializers/render_windows.py @@ -31,7 +31,7 @@ def renderer_serializer(parent, instance, obj_id, context, depth): view_prop_ids.append(view_prop_id) calls += context.build_dependency_call_list( - "%s-props" % obj_id, view_prop_ids, "addViewProp", "removeViewProp" + f"{obj_id}-props", view_prop_ids, "addViewProp", "removeViewProp" ) # Lights @@ -46,7 +46,7 @@ def renderer_serializer(parent, instance, obj_id, context, depth): lights_ids.append(light_id) calls += context.build_dependency_call_list( - "%s-lights" % obj_id, lights_ids, "addLight", "removeLight" + f"{obj_id}-lights", lights_ids, "addLight", "removeLight" ) if len(dependencies) > 1: @@ -86,7 +86,7 @@ def renderer_serializer(parent, instance, obj_id, context, depth): # ----------------------------------------------------------------------------- -def camera_serializer(parent, instance, obj_id, context, depth): +def camera_serializer(parent, instance, obj_id, _context, _depth): return { "parent": reference_id(parent), "id": obj_id, diff --git a/src/trame_vtk/modules/vtk/serializers/serialize.py b/src/trame_vtk/modules/vtk/serializers/serialize.py index 0b4f3da..e3dcc72 100644 --- a/src/trame_vtk/modules/vtk/serializers/serialize.py +++ b/src/trame_vtk/modules/vtk/serializers/serialize.py @@ -1,8 +1,9 @@ import logging + import vtk from .cache import remove_from_cache -from .registry import class_name, SERIALIZERS +from .registry import SERIALIZERS, class_name from .widgets import handle_widget __all__ = ["serialize", "serialize_widget"] @@ -16,10 +17,10 @@ def serialize(parent, instance, instance_id, context, depth): instance_type = class_name(instance) - serializer = SERIALIZERS[instance_type] if instance_type in SERIALIZERS else None + serializer = SERIALIZERS.get(instance_type, None) if instance_id not in DELETE_CALLBACKS: instance.AddObserver( - vtk.vtkCommand.DeleteEvent, lambda *a, **k: remove(instance_id) + vtk.vtkCommand.DeleteEvent, lambda *_a, **_k: remove(instance_id) ) DELETE_CALLBACKS.append(instance_id) @@ -28,7 +29,7 @@ def serialize(parent, instance, instance_id, context, depth): if instance_type not in NO_SERIALIZER_FOR_INSTANCE: # Only print the warning once for each type of serializer - logger.warning(f"!!!No serializer for {instance_type} with id {instance_id}") + logger.warning("!!!No serializer for %s with id %s", instance_type, instance_id) NO_SERIALIZER_FOR_INSTANCE[instance_type] = instance_id return None diff --git a/src/trame_vtk/modules/vtk/serializers/synchronization_context.py b/src/trame_vtk/modules/vtk/serializers/synchronization_context.py index 35e4c6f..24025f2 100644 --- a/src/trame_vtk/modules/vtk/serializers/synchronization_context.py +++ b/src/trame_vtk/modules/vtk/serializers/synchronization_context.py @@ -1,18 +1,17 @@ +import importlib import io import logging -import time -import zipfile import os -import importlib import sys +import time +import zipfile -vtk_module_name = os.environ.get("VTK_MODULE_NAME", "vtkmodules") -sys.modules["vtk_module"] = importlib.import_module(vtk_module_name) - -from vtk_module.vtkCommonCore import vtkTypeUInt32Array, vtkFloatArray, vtkDoubleArray +from vtk_module.vtkCommonCore import vtkDoubleArray, vtkFloatArray, vtkTypeUInt32Array from .utils import base64_encode, wrap_id +vtk_module_name = os.environ.get("VTK_MODULE_NAME", "vtkmodules") +sys.modules["vtk_module"] = importlib.import_module(vtk_module_name) logger = logging.getLogger(__name__) JS_VTK_ARRAY = { @@ -119,6 +118,6 @@ def build_dependency_call_list(self, idstr, new_list, add_method, remove_method) def zip_compression(name, data): with io.BytesIO() as in_memory: with zipfile.ZipFile(in_memory, mode="w") as zf: - zf.writestr("data/%s" % name, data, zipfile.ZIP_DEFLATED) + zf.writestr(f"data/{name}", data, zipfile.ZIP_DEFLATED) in_memory.seek(0) return in_memory.read() diff --git a/src/trame_vtk/modules/vtk/serializers/textures.py b/src/trame_vtk/modules/vtk/serializers/textures.py index e05d136..d518bda 100644 --- a/src/trame_vtk/modules/vtk/serializers/textures.py +++ b/src/trame_vtk/modules/vtk/serializers/textures.py @@ -20,7 +20,7 @@ def texture_serializer(parent, texture, texture_id, context, depth): logger.debug("This texture does not have GetInput method") if data_object: - data_object_id = "%s-texture" % texture_id + data_object_id = f"{texture_id}-texture" data_object_instance = serialize( texture, data_object, data_object_id, context, depth + 1 ) diff --git a/src/trame_vtk/modules/vtk/serializers/utils.py b/src/trame_vtk/modules/vtk/serializers/utils.py index 06db1b1..10ceeed 100644 --- a/src/trame_vtk/modules/vtk/serializers/utils.py +++ b/src/trame_vtk/modules/vtk/serializers/utils.py @@ -1,6 +1,5 @@ import base64 import hashlib -import sys def rgb_float_to_hex(r, g, b): @@ -49,14 +48,9 @@ def base64_encode(x): def hash_data_array(data_array): - if sys.version_info < (3, 9): - hashed_bit = hashlib.md5(memoryview(data_array)).hexdigest() - else: - hashed_bit = hashlib.md5( - memoryview(data_array), usedforsecurity=False - ).hexdigest() + hashed_bit = hashlib.md5(memoryview(data_array), usedforsecurity=False).hexdigest() type_code = array_types_mapping[data_array.GetDataType()] - return "%s_%d%s" % (hashed_bit, data_array.GetNumberOfValues(), type_code) + return f"{hashed_bit}_{data_array.GetNumberOfValues()}{type_code}" def get_js_array_type(data_array): @@ -64,7 +58,7 @@ def get_js_array_type(data_array): def wrap_id(id_str): - return "instance:${%s}" % id_str + return f"instance:${{{id_str}}}" def reference_id(ref): @@ -72,7 +66,5 @@ def reference_id(ref): try: return ref.__this__[1:17] except Exception: - id_str = str(ref)[-12:-1] - # print('====> fallback ID %s for %s' % (id_str, ref)) - return id_str + return str(ref)[-12:-1] return "0x0" diff --git a/src/trame_vtk/modules/vtk/serializers/widgets.py b/src/trame_vtk/modules/vtk/serializers/widgets.py index 1468d80..40412f8 100644 --- a/src/trame_vtk/modules/vtk/serializers/widgets.py +++ b/src/trame_vtk/modules/vtk/serializers/widgets.py @@ -1,4 +1,5 @@ import logging + from .utils import reference_id logger = logging.getLogger(__name__) @@ -50,4 +51,4 @@ def handle_widget(map_to_update, widget): SERIALIZERS[class_name](map_to_update, widget) elif class_name not in UNKNOWN_CLASSES: UNKNOWN_CLASSES.add(class_name) - logger.warning(f"!!!No widget serializer for {class_name}") + logger.warning("!!!No widget serializer for %s", class_name) diff --git a/src/trame_vtk/modules/vtk/widget.py b/src/trame_vtk/modules/vtk/widget.py index 575c0f4..1c510f2 100644 --- a/src/trame_vtk/modules/vtk/widget.py +++ b/src/trame_vtk/modules/vtk/widget.py @@ -1,18 +1,17 @@ -from typing import Type, Callable, Dict, Optional -from functools import partialmethod -import os import importlib +import os import sys +from functools import partialmethod +from typing import Callable, Optional -vtk_module_name = os.environ.get("VTK_MODULE_NAME", "vtkmodules") -sys.modules["vtk_module"] = importlib.import_module(vtk_module_name) - +from vtk_module.vtkCommonCore import vtkCommand from vtk_module.vtkInteractionWidgets import ( vtkAbstractWidget, vtkWidgetRepresentation, ) -from vtk_module.vtkCommonCore import vtkCommand +vtk_module_name = os.environ.get("VTK_MODULE_NAME", "vtkmodules") +sys.modules["vtk_module"] = importlib.import_module(vtk_module_name) EventCallback = Callable[[vtkCommand.EventIds, Optional["VtkWidget"]], None] @@ -27,7 +26,7 @@ def wrapped_callback(*args, **kwargs): class VtkWidget: def __init__(self, w: vtkAbstractWidget): self._w = w - self._listeners: Dict[vtkCommand.EventIds, Dict[EventCallback, int]] = {} + self._listeners: dict[vtkCommand.EventIds, dict[EventCallback, int]] = {} @property def vtk_widget(self) -> vtkAbstractWidget: @@ -40,10 +39,9 @@ def vtk_representation(self) -> vtkWidgetRepresentation: def __getattr__(self, name: str): if hasattr(self.vtk_widget, name): return getattr(self.vtk_widget, name) - elif hasattr(self.vtk_representation, name): + if hasattr(self.vtk_representation, name): return getattr(self.vtk_representation, name) - else: - return super().__getattribute__(name) + return super().__getattribute__(name) def enable(self): self._w.On() @@ -110,8 +108,8 @@ def _to_snake_case(s: str) -> str: ) -WidgetParam = vtkAbstractWidget | Type[vtkAbstractWidget] -RepresentationParam = vtkWidgetRepresentation | Type[vtkWidgetRepresentation] +WidgetParam = vtkAbstractWidget | type[vtkAbstractWidget] +RepresentationParam = vtkWidgetRepresentation | type[vtkWidgetRepresentation] class WidgetManager: @@ -137,9 +135,8 @@ def add_widget( elif isinstance(r, vtkWidgetRepresentation): raw_representation = r elif r is not None: - raise TypeError( - "The r parameter should be one of: vtkWidgetRepresentation | Type[vtkWidgetRepresentation]" - ) + msg = "The r parameter should be one of: vtkWidgetRepresentation | Type[vtkWidgetRepresentation]" + raise TypeError(msg) if isinstance(w, type) and issubclass(w, vtkAbstractWidget): raw_widget = w() @@ -147,15 +144,12 @@ def add_widget( elif isinstance(w, vtkAbstractWidget): raw_widget = w else: - raise TypeError( - "The w parameter should be one of: vtkAbstractWidget | Type[vtkAbstractWidget]" - ) + msg = "The w parameter should be one of: vtkAbstractWidget | Type[vtkAbstractWidget]" + raise TypeError(msg) if raw_representation is not None: raw_widget.SetRepresentation(raw_representation) raw_widget.SetInteractor(self._interactor) - widget = VtkWidget(raw_widget) - - return widget + return VtkWidget(raw_widget) diff --git a/src/trame_vtk/tools/static_viewer.html b/src/trame_vtk/tools/static_viewer.html index 395d1d6..89af575 100644 --- a/src/trame_vtk/tools/static_viewer.html +++ b/src/trame_vtk/tools/static_viewer.html @@ -14,7 +14,4531 @@ - diff --git a/src/trame_vtk/tools/vtksz2html.py b/src/trame_vtk/tools/vtksz2html.py index 9dd83dc..cfcbc09 100644 --- a/src/trame_vtk/tools/vtksz2html.py +++ b/src/trame_vtk/tools/vtksz2html.py @@ -14,12 +14,12 @@ def data_to_base64(data: bytes): def write_html(data: bytes, output: TextIO): base64Content = data_to_base64(data) - with open(HTML_VIEWER_PATH, mode="r", encoding="utf-8") as srcHtml: + with Path.open(HTML_VIEWER_PATH, encoding="utf-8") as srcHtml: for line in srcHtml: if "" in line: output.write("\n") @@ -27,7 +27,7 @@ def write_html(data: bytes, output: TextIO): def embed_data_to_viewer_file(data: bytes, output_file: Path): - with open(output_file, mode="w", encoding="utf-8") as dstHtml: + with Path.open(output_file, mode="w", encoding="utf-8") as dstHtml: write_html(data, dstHtml) @@ -47,13 +47,14 @@ def main(): input_file = Path(args.input) if not input_file.exists(): - raise FileNotFoundError(f"Input file {input_file.name} not found.") + msg = f"Input file {input_file.name} not found." + raise FileNotFoundError(msg) input = Path(input_file) output = input.with_name(f"{input.name}.html") - with open(input, "rb") as data: - data = data.read() + with Path.open(input, "rb") as f: + data = f.read() embed_data_to_viewer_file(data, output) diff --git a/src/trame_vtk/widgets/vtk/__init__.py b/src/trame_vtk/widgets/vtk/__init__.py index 64ea421..b26dd11 100644 --- a/src/trame_vtk/widgets/vtk/__init__.py +++ b/src/trame_vtk/widgets/vtk/__init__.py @@ -1,37 +1,37 @@ from .common import ( - VtkView, - VtkRemoteView, - VtkLocalView, - VtkRemoteLocalView, VtkAlgorithm, VtkCellData, VtkDataArray, VtkFieldData, VtkGeometryRepresentation, VtkGlyphRepresentation, + VtkLocalView, VtkMesh, VtkPointData, VtkPolyData, VtkReader, + VtkRemoteLocalView, + VtkRemoteView, VtkShareDataset, + VtkView, VtkWebXRHelper, ) __all__ = [ - "VtkView", - "VtkRemoteView", - "VtkLocalView", - "VtkRemoteLocalView", "VtkAlgorithm", "VtkCellData", "VtkDataArray", "VtkFieldData", "VtkGeometryRepresentation", "VtkGlyphRepresentation", + "VtkLocalView", "VtkMesh", "VtkPointData", "VtkPolyData", "VtkReader", + "VtkRemoteLocalView", + "VtkRemoteView", "VtkShareDataset", + "VtkView", "VtkWebXRHelper", ] diff --git a/src/trame_vtk/widgets/vtk/common.py b/src/trame_vtk/widgets/vtk/common.py index a228eca..93a546f 100644 --- a/src/trame_vtk/widgets/vtk/common.py +++ b/src/trame_vtk/widgets/vtk/common.py @@ -5,11 +5,11 @@ from trame_client.widgets.core import AbstractElement -from trame_vtk.modules import common from trame_vtk import reference_id +from trame_vtk.modules import common try: - import zlib # noqa + import zlib # noqa: F401 ZIP_COMPRESSION = zipfile.ZIP_DEFLATED except ImportError: @@ -21,15 +21,14 @@ def activate_module_for(helper, server, vtk_or_paraview_obj): return helper if vtk_or_paraview_obj.IsA("vtkSMRemoteObject"): - from trame_vtk.modules import paraview + from trame_vtk.modules import paraview # noqa: PLC0415 server.enable_module(paraview) return paraview.get_helper(server) - else: - from trame_vtk.modules import vtk + from trame_vtk.modules import vtk # noqa: PLC0415 - server.enable_module(vtk) - return vtk.get_helper(server) + server.enable_module(vtk) + return vtk.get_helper(server) class HtmlElement(AbstractElement): @@ -369,7 +368,9 @@ class VtkRemoteLocalView(HtmlElement): _next_id = 0 - def __init__(self, view, enable_rendering=True, widgets=[], **kwargs): + def __init__(self, view, enable_rendering=True, widgets=None, **kwargs): + if widgets is None: + widgets = [] super().__init__("vtk-remote-local-view", **kwargs) self._helper = None self._helper = activate_module_for(self._helper, self.server, view) @@ -493,7 +494,7 @@ def push_remote_camera_on_end_interaction(self): self.__view.GetInteractor().AddObserver(45, self._push_camera) def update_geometry( - self, reset_camera=False, widgets=None, orientation_axis=0, **kwargs + self, _reset_camera=False, widgets=None, orientation_axis=0, **_ ): """ Force update to geometry @@ -520,7 +521,7 @@ def update_geometry( ) self.server.state[self.__scene_id] = full_state - def export_geometry(self, widgets=None, orientation_axis=0, format="zip", **kwargs): + def export_geometry(self, widgets=None, orientation_axis=0, format="zip", **_): """Export standalone scene for OfflineViewer :param format: Can be either be "zip" or "json". @@ -531,7 +532,7 @@ def export_geometry(self, widgets=None, orientation_axis=0, format="zip", **kwar widgets = self._widgets if not self.server.protocol: - return + return None encoded_data = self._helper.export( self.__view, @@ -550,6 +551,8 @@ def export_geometry(self, widgets=None, orientation_axis=0, format="zip", **kwar return zip_buffer.getvalue() + return None + def update_image(self, reset_camera=False): """ Force update to image @@ -557,13 +560,13 @@ def update_image(self, reset_camera=False): if self.server.protocol: self._helper.push_image(self.__view, reset_camera) - def set_local_rendering(self, local=True, **kwargs): + def set_local_rendering(self, local=True, **_): self.server.state[self.__mode_key] = "local" if local else "remote" - def set_remote_rendering(self, remote=True, **kwargs): + def set_remote_rendering(self, remote=True, **_): self.server.state[self.__mode_key] = "remote" if remote else "local" - def update(self, reset_camera=False, widgets=None, orientation_axis=0, **kwargs): + def update(self, reset_camera=False, widgets=None, orientation_axis=0, **_): # need to do both to keep things in sync if self.__rendering: self.update_image(reset_camera) @@ -580,10 +583,10 @@ def update(self, reset_camera=False, widgets=None, orientation_axis=0, **kwargs) self._helper.camera(self.__view), ) - def _push_camera(self, *args, **kwargs): + def _push_camera(self, *_, **_kwargs): self.push_camera() - def push_camera(self, camera=None, center_of_rotation=None, **kwargs): + def push_camera(self, camera=None, center_of_rotation=None, **_): if camera is None: if hasattr(self.__view, "GetRenderers"): # VTK camera = self.__view.GetRenderers().GetFirstRenderer().GetActiveCamera() @@ -593,14 +596,14 @@ def push_camera(self, camera=None, center_of_rotation=None, **kwargs): if camera is None: return - camera_params = dict( - position=camera.GetPosition(), - focalPoint=camera.GetFocalPoint(), - viewUp=camera.GetViewUp(), - parallelProjection=camera.GetParallelProjection(), - parallelScale=camera.GetParallelScale(), - viewAngle=camera.GetViewAngle(), - ) + camera_params = { + "position": camera.GetPosition(), + "focalPoint": camera.GetFocalPoint(), + "viewUp": camera.GetViewUp(), + "parallelProjection": camera.GetParallelProjection(), + "parallelScale": camera.GetParallelScale(), + "viewAngle": camera.GetViewAngle(), + } if center_of_rotation is not None: camera_params["centerOfRotation"] = center_of_rotation @@ -611,7 +614,7 @@ def push_camera(self, camera=None, center_of_rotation=None, **kwargs): camera_params, ) - def replace_view(self, new_view, **kwargs): + def replace_view(self, new_view, **_): self.server.state[self.__view_key_id] = self._helper.id(new_view) _mode = self.server.state[self.__mode_key] self.__view = new_view @@ -621,10 +624,10 @@ def replace_view(self, new_view, **kwargs): self.update() self.resize() - def reset_camera(self, **kwargs): + def reset_camera(self, **_): self.server.js_call(ref=self.__ref, method="resetCamera") - def resize(self, **kwargs): + def resize(self, **_): self.server.js_call(ref=self.__ref, method="resize") @property @@ -634,7 +637,9 @@ def view(self): """ return self.__wrapped_view - def capture_image(self, format="image/png", opts={}): + def capture_image(self, format="image/png", opts=None): + if opts is None: + opts = {} self.server.js_call( self.__ref, "captureImage", @@ -755,7 +760,7 @@ def __init__(self, view, ref=None, **kwargs): "EndInteraction", ] - def update(self, **kwargs): + def update(self, **_): """ Force image to be pushed to client """ @@ -785,19 +790,21 @@ def stop_animation(self): self._helper.stop_animation(self.__view) self.update() - def reset_camera(self, **kwargs): + def reset_camera(self, **_): self.server.js_call(ref=self.__ref, method="resetCamera") - def replace_view(self, new_view, **kwargs): + def replace_view(self, new_view, **_): self.__view = new_view self.server.state[self.__view_key_id] = self._helper.id(new_view) self.update() self.resize() - def resize(self, **kwargs): + def resize(self, **_): self.server.js_call(ref=self.__ref, method="resize") - def capture_image(self, format="image/png", opts={}): + def capture_image(self, format="image/png", opts=None): + if opts is None: + opts = {} self.server.js_call( self.__ref, "captureImage", @@ -856,7 +863,9 @@ class VtkLocalView(HtmlElement): _next_id = 0 - def __init__(self, view, ref=None, widgets=[], **kwargs): + def __init__(self, view, ref=None, widgets=None, **kwargs): + if widgets is None: + widgets = [] super().__init__("vtk-local-view", **kwargs) self._helper = activate_module_for(None, self.server, view) self._helper.has_capabilities("web") @@ -938,7 +947,7 @@ def set_widgets(self, value): self._widgets = value self.update() - def update(self, widgets=None, orientation_axis=0, **kwargs): + def update(self, widgets=None, orientation_axis=0, **_): """ Force geometry to be pushed """ @@ -964,7 +973,7 @@ def update(self, widgets=None, orientation_axis=0, **kwargs): ) self.server.state[self.__scene_id] = full_state - def export(self, widgets=None, orientation_axis=0, format="zip", **kwargs): + def export(self, widgets=None, orientation_axis=0, format="zip", **_): """Export standalone scene for OfflineViewer :param format: Can be either be "zip" or "json". @@ -975,7 +984,7 @@ def export(self, widgets=None, orientation_axis=0, format="zip", **kwargs): widgets = self._widgets if not self.server.protocol: - return + return None encoded_data = self._helper.export( self.__view, @@ -994,23 +1003,25 @@ def export(self, widgets=None, orientation_axis=0, format="zip", **kwargs): return zip_buffer.getvalue() - def reset_camera(self, **kwargs): + return None + + def reset_camera(self, **_): """ Move camera to center actors within the frame """ self.server.js_call(ref=self.__ref, method="resetCamera") - def replace_view(self, new_view, **kwargs): + def replace_view(self, new_view, **_): self.__view = new_view self.server.js_call( self.__ref, "setSynchronizedViewId", self._helper.id(new_view) ) self.update() - def resize(self, **kwargs): + def resize(self, **_): self.server.js_call(ref=self.__ref, method="resize") - def push_camera(self, camera=None, center_of_rotation=None, **kwargs): + def push_camera(self, camera=None, center_of_rotation=None, **_): if camera is None: if hasattr(self.__view, "GetRenderers"): # VTK camera = self.__view.GetRenderers().GetFirstRenderer().GetActiveCamera() @@ -1020,14 +1031,14 @@ def push_camera(self, camera=None, center_of_rotation=None, **kwargs): if camera is None: return - camera_params = dict( - position=camera.GetPosition(), - focalPoint=camera.GetFocalPoint(), - viewUp=camera.GetViewUp(), - parallelProjection=camera.GetParallelProjection(), - parallelScale=camera.GetParallelScale(), - viewAngle=camera.GetViewAngle(), - ) + camera_params = { + "position": camera.GetPosition(), + "focalPoint": camera.GetFocalPoint(), + "viewUp": camera.GetViewUp(), + "parallelProjection": camera.GetParallelProjection(), + "parallelScale": camera.GetParallelScale(), + "viewAngle": camera.GetViewAngle(), + } if center_of_rotation is not None: camera_params["centerOfRotation"] = center_of_rotation @@ -1038,7 +1049,9 @@ def push_camera(self, camera=None, center_of_rotation=None, **kwargs): camera_params, ) - def capture_image(self, format="image/png", opts={}): + def capture_image(self, format="image/png", opts=None): + if opts is None: + opts = {} self.server.js_call( self.__ref, "captureImage", @@ -1122,7 +1135,7 @@ def __init__(self, children=None, ref=None, **kwargs): "EndInteraction", ] - def reset_camera(self, **kwargs): + def reset_camera(self, **_): """ Move camera to center actors within the frame """ diff --git a/tests/conftest.py b/tests/conftest.py index b74bfa9..61c7b43 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,5 +1,6 @@ -import pytest from pathlib import Path + +import pytest from trame_client.utils.testing import FixtureHelper ROOT_PATH = Path(__file__).parent.parent.absolute() diff --git a/tests/test_big_int.py b/tests/test_big_int.py index f583dfc..e4fdd4b 100644 --- a/tests/test_big_int.py +++ b/tests/test_big_int.py @@ -1,9 +1,8 @@ -from pathlib import Path import time +from pathlib import Path -from playwright.sync_api import expect, sync_playwright import pytest - +from playwright.sync_api import expect, sync_playwright from trame_client.utils.testing import ( assert_screenshot_matches, assert_snapshot_matches, diff --git a/tests/test_export.py b/tests/test_export.py index fbc1f78..7d74ecc 100644 --- a/tests/test_export.py +++ b/tests/test_export.py @@ -1,6 +1,7 @@ +import asyncio from pathlib import Path + import pytest -import asyncio import pyvista as pv from pyvista import examples diff --git a/tests/test_gc.py b/tests/test_gc.py index 4de0567..0ee57c7 100644 --- a/tests/test_gc.py +++ b/tests/test_gc.py @@ -3,8 +3,8 @@ import pytest import pyvista as pv - from trame.app import get_server + from trame.widgets import vtk as vtk_widgets # pytest_plugins = ('pytest_asyncio',) diff --git a/tests/test_import.py b/tests/test_import.py index 73683d9..82959de 100644 --- a/tests/test_import.py +++ b/tests/test_import.py @@ -1,2 +1,2 @@ def test_import(): - from trame.widgets.vtk import VtkAlgorithm # noqa: F401 + pass diff --git a/tests/test_remote_rendering.py b/tests/test_remote_rendering.py index bfc2f04..49a8702 100644 --- a/tests/test_remote_rendering.py +++ b/tests/test_remote_rendering.py @@ -1,9 +1,8 @@ -from pathlib import Path import time +from pathlib import Path -from playwright.sync_api import expect, sync_playwright import pytest - +from playwright.sync_api import expect, sync_playwright from trame_client.utils.testing import ( assert_screenshot_matches, assert_snapshot_matches, diff --git a/tests/test_volume_rendering.py b/tests/test_volume_rendering.py index 05fa10a..1c77568 100644 --- a/tests/test_volume_rendering.py +++ b/tests/test_volume_rendering.py @@ -1,9 +1,8 @@ -from pathlib import Path import time +from pathlib import Path -from playwright.sync_api import expect, sync_playwright import pytest - +from playwright.sync_api import expect, sync_playwright from trame_client.utils.testing import ( assert_screenshot_matches, assert_snapshot_matches, From 75d1536fece770825b972da8396770af5f4531d6 Mon Sep 17 00:00:00 2001 From: Ulysse DURAND Date: Mon, 20 Apr 2026 14:18:01 +0200 Subject: [PATCH 05/13] ci(pre-commit): revert `CHANGELOG.md` and make prettier ignore it Ref: https://github.com/Kitware/trame-vtk/pull/108#discussion_r3108164279 --- , | 114 ----------------------- .pre-commit-config.yaml | 1 + CHANGELOG.md | 197 +++++++++++++++++++++++++++------------- 3 files changed, 136 insertions(+), 176 deletions(-) delete mode 100644 , diff --git a/, b/, deleted file mode 100644 index 5142593..0000000 --- a/, +++ /dev/null @@ -1,114 +0,0 @@ -[project] -name = "trame-app" -version = "1.0.0" -description = "An example Trame application" -authors = [ - {name = "Trame Developer"}, -] -dependencies = [ - "trame_client>=3.10", -] -requires-python = ">=3.9" -readme = "README.rst" -license = {text = "BSD License"} -keywords = ["Python", "Interactive", "Web", "Application", "Framework"] -classifiers = [ - "Development Status :: 4 - Beta", - "Environment :: Web Environment", - "License :: OSI Approved :: BSD License", - "Natural Language :: English", - "Operating System :: OS Independent", - "Programming Language :: Python :: 3 :: Only", - "Topic :: Software Development :: Libraries :: Application Frameworks", - "Topic :: Software Development :: Libraries :: Python Modules", -] - -[project.optional-dependencies] -app = [ - "pywebview", -] -jupyter = [ - "jupyterlab", -] -dev = [ - "pre-commit", - "ruff", - "pytest >=6", - "pytest-cov >=3", - "nox", -] - -[build-system] -requires = ["hatchling"] -build-backend = "hatchling.build" - - -[tool.hatch.build] -include = [ - "/src/trame/**/*.py", - "/src/trame_app/**/*.py", - "/src/trame_app/**/*.js", - "/src/trame_app/**/*.css", -] - -[tool.hatch.build.targets.wheel] -packages = [ - "src/trame", - "src/trame_app", -] - -[tool.ruff] - -[tool.ruff.lint] -extend-select = [ - "ARG", # flake8-unused-arguments - "B", # flake8-bugbear - "C4", # flake8-comprehensions - "EM", # flake8-errmsg - "EXE", # flake8-executable - "G", # flake8-logging-format - "I", # isort - "ICN", # flake8-import-conventions - "NPY", # NumPy specific rules - "PD", # pandas-vet - "PGH", # pygrep-hooks - "PIE", # flake8-pie - "PL", # pylint - "PT", # flake8-pytest-style - "PTH", # flake8-use-pathlib - "RET", # flake8-return - "RUF", # Ruff-specific - "SIM", # flake8-simplify - "T20", # flake8-print - "UP", # pyupgrade - "YTT", # flake8-2020 -] -ignore = [ - "PLR09", # Too many <...> - "PLR2004", # Magic value used in comparison - "ISC001", # Conflicts with formatter -] -isort.required-imports = [] - -[tool.ruff.lint.per-file-ignores] -"tests/**" = ["T20"] -"noxfile.py" = ["T20"] -"src/**" = ["SIM117"] -[tool.semantic_release] -version_toml = [ - "pyproject.toml:project.version", -] -version_variables = [ - "src/trame_app/__init__.py:__version__", -] - -build_command = """ - python -m pip install -e '.[build]' - uv lock --upgrade-package "$PACKAGE_NAME" - git add uv.lock - uv build -""" - -[tool.semantic_release.publish] -dist_glob_patterns = ["dist/*"] -upload_to_vcs_release = true diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1ce3f06..00af8fa 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -40,6 +40,7 @@ repos: - id: prettier types_or: [yaml, markdown, html, css, scss, javascript, json] args: [--prose-wrap=always] + exclude: (CHANGELOG.md) - repo: https://github.com/astral-sh/ruff-pre-commit rev: "v0.15.10" diff --git a/CHANGELOG.md b/CHANGELOG.md index e61681e..b8d9b3b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # CHANGELOG +<<<<<<< HEAD ## v2.11.8 (2026-04-24) ### Bug Fixes @@ -11,6 +12,8 @@ fix #111 +======= +>>>>>>> 86f4a5d (ci(pre-commit): revert `CHANGELOG.md` and make prettier ignore it) ## v2.11.7 (2026-04-13) ### Bug Fixes @@ -18,6 +21,7 @@ fix #111 - **static_viewer**: Include in repo to skip auto fetch on vtk.js ([`9302c6b`](https://github.com/Kitware/trame-vtk/commit/9302c6b0309e3961323aea882621ac8922d59524)) + ## v2.11.6 (2026-03-25) ### Bug Fixes @@ -25,6 +29,7 @@ fix #111 - **array**: Skip hash and eq usage on array ([`12e2d35`](https://github.com/Kitware/trame-vtk/commit/12e2d35b5d06c949994a2224fae897b6cb9c3930)) + ## v2.11.5 (2026-03-25) ### Bug Fixes @@ -32,6 +37,7 @@ fix #111 - **static_viewer**: Update static viewer from vtk.js ([`3bb5f16`](https://github.com/Kitware/trame-vtk/commit/3bb5f16b1f7aa658dc14f6f945fafc3acf5faaf3)) + ## v2.11.4 (2026-03-25) ### Bug Fixes @@ -39,6 +45,7 @@ fix #111 - **array**: Don't rely on hashable arrays ([`e740a95`](https://github.com/Kitware/trame-vtk/commit/e740a9552a4ba285d285b88c63f9571474c82988)) + ## v2.11.3 (2026-03-15) ### Bug Fixes @@ -46,6 +53,7 @@ fix #111 - **tool**: Vtksz2html use new dom container ([`4b7fe32`](https://github.com/Kitware/trame-vtk/commit/4b7fe32052189489f73c95b9c854bf0b72107c79)) + ## v2.11.2 (2026-03-15) ### Bug Fixes @@ -53,6 +61,7 @@ fix #111 - **static_viewer**: Fetch latest static viewer ([`d4d8d18`](https://github.com/Kitware/trame-vtk/commit/d4d8d18e6905bac55b924c0c3af761e5a47f3be5)) + ## v2.11.1 (2026-02-05) ### Bug Fixes @@ -62,6 +71,7 @@ fix #111 Update how camera is get in vtkLocalView with a ParaView RenderView + ## v2.11.0 (2026-02-04) ### Continuous Integration @@ -74,6 +84,7 @@ Update how camera is get in vtkLocalView with a ParaView RenderView - Add served directory versioning ([`c9463ef`](https://github.com/Kitware/trame-vtk/commit/c9463ef898671b1d9e714fd8c288c872e9373403)) + ## v2.10.3 (2026-01-28) ### Bug Fixes @@ -81,8 +92,9 @@ Update how camera is get in vtkLocalView with a ParaView RenderView - **actor**: Prevent serialization of actors without a mapper ([`b116bc9`](https://github.com/Kitware/trame-vtk/commit/b116bc9d56824ffcd21722ffbd312b90be632a1b)) -Fix bug where oglmapper wass undefined in traverseOpaquePass for an actor whose -visibility got toggled twice +Fix bug where oglmapper wass undefined in traverseOpaquePass for an actor whose visibility got + toggled twice + ## v2.10.2 (2026-01-08) @@ -96,6 +108,7 @@ visibility got toggled twice - Update baseline for test_rendering_lut and test_big_int ([`b73e575`](https://github.com/Kitware/trame-vtk/commit/b73e57591f8f97ddf260aebfec9f64059d1898bc)) + ## v2.10.1 (2025-12-15) ### Bug Fixes @@ -103,6 +116,7 @@ visibility got toggled twice - **camera**: Update vue-vtk-js ([`582cb80`](https://github.com/Kitware/trame-vtk/commit/582cb8048252668e2ac329cb26a20cdc1acf23d9)) + ## v2.10.0 (2025-10-02) ### Bug Fixes @@ -129,6 +143,7 @@ Signed-off-by: Patrick Avery - Add WebXR Helper widget ([`beded63`](https://github.com/Kitware/trame-vtk/commit/beded63f1b6268cc30120646b83770a679a57d0a)) + ## v2.9.1 (2025-07-21) ### Bug Fixes @@ -136,6 +151,7 @@ Signed-off-by: Patrick Avery - **vtk-module**: Fix import for custom vtk module ([`090b504`](https://github.com/Kitware/trame-vtk/commit/090b504e8fd28cbce3705628f72cf2fd6ff12e56)) + ## v2.9.0 (2025-06-23) ### Continuous Integration @@ -148,6 +164,7 @@ Signed-off-by: Patrick Avery - **vtk**: Enable custom VTK build ([`448530a`](https://github.com/Kitware/trame-vtk/commit/448530a6456bdfebedd0b356ea5632a345dbc301)) + ## v2.8.17 (2025-06-03) ### Bug Fixes @@ -155,6 +172,7 @@ Signed-off-by: Patrick Avery - Properly bundle static_viewer.html ([`89df689`](https://github.com/Kitware/trame-vtk/commit/89df689f124f7b08835efdfed4216c347d84c391)) + ## v2.8.16 (2025-06-02) ### Bug Fixes @@ -178,6 +196,7 @@ Signed-off-by: Patrick Avery - Update links in readme ([`f73f046`](https://github.com/Kitware/trame-vtk/commit/f73f0465a9fd9989c07244ae666429e68b97cd53)) + ## v2.8.15 (2025-02-09) ### Bug Fixes @@ -212,6 +231,7 @@ Signed-off-by: Patrick Avery - Cover several vtk version ([`274da78`](https://github.com/Kitware/trame-vtk/commit/274da788bcfa15abf4f453158e14ad5210895e2f)) + ## v2.8.14 (2025-01-08) ### Bug Fixes @@ -227,6 +247,7 @@ Signed-off-by: Patrick Avery - **pre-commit**: Fix codespell ([`df46242`](https://github.com/Kitware/trame-vtk/commit/df46242bc34c9e89b9ed42445f77ddd16bb15720)) + ## v2.8.13 (2025-01-07) ### Bug Fixes @@ -239,6 +260,7 @@ Signed-off-by: Patrick Avery - Update README.rst ([`38ad9b2`](https://github.com/Kitware/trame-vtk/commit/38ad9b220a4674f5d820e0252302fc1688c80731)) + ## v2.8.12 (2024-11-08) ### Performance Improvements @@ -246,6 +268,7 @@ Signed-off-by: Patrick Avery - **vtk**: Do not always force image push ([`d2b075f`](https://github.com/Kitware/trame-vtk/commit/d2b075fa00958d2e8ebcad052db89a7a41d3ce4f)) + ## v2.8.11 (2024-10-17) ### Bug Fixes @@ -253,6 +276,7 @@ Signed-off-by: Patrick Avery - **animation**: Enable animation on remote view ([`660a1d4`](https://github.com/Kitware/trame-vtk/commit/660a1d4a755d43684a82f24efbfdb7bd445651cd)) + ## v2.8.10 (2024-08-07) ### Bug Fixes @@ -260,6 +284,7 @@ Signed-off-by: Patrick Avery - **wheel**: Apply modifiers [alt,shift,ctrl] on wheel event ([`42f2283`](https://github.com/Kitware/trame-vtk/commit/42f22838fe409d8b15ed158240ece25a46d0b7dc)) + ## v2.8.9 (2024-06-07) ### Bug Fixes @@ -267,6 +292,7 @@ Signed-off-by: Patrick Avery - **VtkView**: Add set_camera method ([`bc7e883`](https://github.com/Kitware/trame-vtk/commit/bc7e8833bbdc6b58d316c99586c04407be5a41d5)) + ## v2.8.8 (2024-05-06) ### Bug Fixes @@ -274,23 +300,22 @@ Signed-off-by: Patrick Avery - **js**: Track hash of vue-vtk-js as well ([`c82ffec`](https://github.com/Kitware/trame-vtk/commit/c82ffeca9d6d3bddbd65d630f3c6fc9864352eae)) -Similar to offline_viewer.html we track and report mismatched hash of all -external dependencies. see also https://github.com/Kitware/trame-vtk/pull/70 +Similar to offline_viewer.html we track and report mismatched hash of all external dependencies. see + also https://github.com/Kitware/trame-vtk/pull/70 ### Chores - **js**: Allow triggering release on external artifact static_viewer.html ([`eb8461a`](https://github.com/Kitware/trame-vtk/commit/eb8461af4229588b71a8bd8f34bb72be162d877f)) -Previously, when a new version of static_viewer.html is released on the master -of vtk-js we couldn't trigger a release because we do not commit this file but -rather grab it during release. This commit adds the hash of the latest version -in a file and a hash check that runs during release but does not trigger a -failure on a mismatch but rather a warning. So now if static_viewer.html is -updated on vtk-js: - If we do not care `.fetch_externals.sh` will just emit a -warning - If we **do** care we update .static_viewer.sha256 and trigger a new -release on trame-vtk even if no other `trame-vtk` change happened during last -release. +Previously, when a new version of static_viewer.html is released on the master of vtk-js we couldn't + trigger a release because we do not commit this file but rather grab it during release. This + commit adds the hash of the latest version in a file and a hash check that runs during release but + does not trigger a failure on a mismatch but rather a warning. So now if static_viewer.html is + updated on vtk-js: - If we do not care `.fetch_externals.sh` will just emit a warning - If we + **do** care we update .static_viewer.sha256 and trigger a new release on trame-vtk even if no + other `trame-vtk` change happened during last release. + ## v2.8.7 (2024-05-02) @@ -299,9 +324,9 @@ release. - **remote rendering**: Round view size half up ([`e6777b9`](https://github.com/Kitware/trame-vtk/commit/e6777b9161d381c01e9ec04f592093c9225f1adf)) -comply with vue-vtk-js vtkRemoteView implementation which uses Math.round for -setting view size. python builtin round function does not work the same way: it -rounds half to even. +comply with vue-vtk-js vtkRemoteView implementation which uses Math.round for setting view size. + python builtin round function does not work the same way: it rounds half to even. + ## v2.8.6 (2024-04-22) @@ -315,6 +340,7 @@ rounds half to even. - **readme**: Fix the link of tutorial url ([`0a46f97`](https://github.com/Kitware/trame-vtk/commit/0a46f97f951f0709a1547a7f4e169cf16c33324a)) + ## v2.8.5 (2024-02-15) ### Bug Fixes @@ -324,6 +350,7 @@ rounds half to even. * Fix breaks compatability with Python 3.8 + ## v2.8.4 (2024-02-14) ### Bug Fixes @@ -331,6 +358,7 @@ rounds half to even. - **serializer**: Md5 hashing is not allowed for FIPS ([`6e163d6`](https://github.com/Kitware/trame-vtk/commit/6e163d62199092d2e3dc2311e2b75f2572854790)) + ## v2.8.3 (2024-02-13) ### Bug Fixes @@ -338,6 +366,7 @@ rounds half to even. - **serializer**: Add encoding option ([`9c20a89`](https://github.com/Kitware/trame-vtk/commit/9c20a89297c356e8dd421ed5d47fb3ed03c660c7)) + ## v2.8.2 (2024-02-09) ### Bug Fixes @@ -345,6 +374,7 @@ rounds half to even. - **js**: Replace invalid downloaded js content ([`d45ca89`](https://github.com/Kitware/trame-vtk/commit/d45ca89ede99b50090c5dc70b6470abce26c126f)) + ## v2.8.1 (2024-02-09) ### Bug Fixes @@ -357,6 +387,7 @@ rounds half to even. - **picking**: Finish remote example ([`1ebeadb`](https://github.com/Kitware/trame-vtk/commit/1ebeadbaaf0044f637f1aa969074c4a3f49570e0)) + ## v2.8.0 (2024-01-30) ### Bug Fixes @@ -369,6 +400,7 @@ rounds half to even. - **picking**: Add support for picking modes ([`edab22d`](https://github.com/Kitware/trame-vtk/commit/edab22dfd6327be3d721efdfcb58a44de714c6c0)) + ## v2.7.1 (2024-01-26) ### Bug Fixes @@ -376,6 +408,7 @@ rounds half to even. - **local**: Add prop3d.orientation for local rendering ([`812c6d1`](https://github.com/Kitware/trame-vtk/commit/812c6d18a582b504f59c7e4dc1e60e2e4fb99b7f)) + ## v2.7.0 (2024-01-12) ### Continuous Integration @@ -393,6 +426,7 @@ rounds half to even. - **multi-server**: Add support for multi-server ([`5a775ea`](https://github.com/Kitware/trame-vtk/commit/5a775ea8d0f3816f733ce9e9d68e0c798976bc64)) + ## v2.6.3 (2023-12-13) ### Bug Fixes @@ -400,6 +434,7 @@ rounds half to even. - **BigInt**: Convert points with (Big)Int to Float for LocalView ([`80496d5`](https://github.com/Kitware/trame-vtk/commit/80496d5ef38269a76e5f4a51c80e3340ad83d1d7)) + ## v2.6.2 (2023-11-16) ### Bug Fixes @@ -407,6 +442,7 @@ rounds half to even. - **ref**: Automatically assign non conflicting ref ([`3cfdf2a`](https://github.com/Kitware/trame-vtk/commit/3cfdf2ada97b1ccae04211e25e92744835621c2f)) + ## v2.6.1 (2023-11-13) ### Bug Fixes @@ -414,6 +450,7 @@ rounds half to even. - **protocol**: Allow several servers within 1 process ([`0c53288`](https://github.com/Kitware/trame-vtk/commit/0c53288add82f5aeea55d3b0190150580311a03b)) + ## v2.6.0 (2023-11-08) ### Bug Fixes @@ -434,6 +471,7 @@ rounds half to even. - Pass `user_matrix` in `add_on` dictionary as payload to ([`ec6cfba`](https://github.com/Kitware/trame-vtk/commit/ec6cfbaaec1940dfc57fb990306f63cd1f56af0b)) + ## v2.5.10 (2023-11-07) ### Bug Fixes @@ -441,6 +479,7 @@ rounds half to even. - **vtk.js**: Bump vtk.js to 29.1.1 ([`bd93a63`](https://github.com/Kitware/trame-vtk/commit/bd93a63907d2ff86fc67c247e751367f6e4753a0)) + ## v2.5.9 (2023-10-06) ### Bug Fixes @@ -464,6 +503,7 @@ rounds half to even. - **pyvista**: Add wip examples ([`487c4c0`](https://github.com/Kitware/trame-vtk/commit/487c4c03054c5a6dad3a671760d53a2375d3119f)) + ## v2.5.8 (2023-07-20) ### Bug Fixes @@ -476,6 +516,7 @@ rounds half to even. - Add trame-vuetify as dep ([`c7259c0`](https://github.com/Kitware/trame-vtk/commit/c7259c05e502193f88fb19640b0388a465598380)) + ## v2.5.7 (2023-07-20) ### Bug Fixes @@ -496,6 +537,7 @@ rounds half to even. - Ignore changelog for spelling ([`aafb2a4`](https://github.com/Kitware/trame-vtk/commit/aafb2a4681eff562324f724e2cbf5a49efab31b6)) + ## v2.5.6 (2023-07-19) ### Bug Fixes @@ -521,6 +563,7 @@ fix #46 fix #44 fix #45 + ## v2.5.5 (2023-07-19) ### Bug Fixes @@ -529,8 +572,8 @@ fix #45 ([`74ed533`](https://github.com/Kitware/trame-vtk/commit/74ed533a2a29930b2f33d0dd2fb77c30987a51e2)) Not using a RenderView as view for the vtkLocalRemoteView will crash, because -"EnableRenderOnInteraction" might not be defined. "GetPropertyValue" will return -None for a non-existing Property + "EnableRenderOnInteraction" might not be defined. "GetPropertyValue" will return None for a + non-existing Property ### Chores @@ -545,6 +588,7 @@ None for a non-existing Property - Upate baselines ([`082de9c`](https://github.com/Kitware/trame-vtk/commit/082de9c79f8a7b653bb5c71482e2bea97b050a49)) + ## v2.5.4 (2023-06-29) ### Bug Fixes @@ -563,14 +607,15 @@ None for a non-existing Property - Use better stage name ([`0bf3f73`](https://github.com/Kitware/trame-vtk/commit/0bf3f73b2257f2e49552d69ed2c5ad8f909e6487)) + ## v2.5.3 (2023-06-28) ### Bug Fixes -- **html**: Improve HTML exporting - ([#42](https://github.com/Kitware/trame-vtk/pull/42), +- **html**: Improve HTML exporting ([#42](https://github.com/Kitware/trame-vtk/pull/42), [`3a0184e`](https://github.com/Kitware/trame-vtk/commit/3a0184e86842f275d920827c3e1a5bb62f627655)) + ## v2.5.2 (2023-06-26) ### Bug Fixes @@ -589,6 +634,7 @@ None for a non-existing Property - **testing**: Update baselines ([`0d6e494`](https://github.com/Kitware/trame-vtk/commit/0d6e4945f80ee56b7ecc8181d4341331989b7d0e)) + ## v2.5.1 (2023-06-23) ### Bug Fixes @@ -604,6 +650,7 @@ None for a non-existing Property - Split steps ([`b1fdde6`](https://github.com/Kitware/trame-vtk/commit/b1fdde61d96681a9f052d4c75628367f1fe4069c)) + ## v2.5.0 (2023-06-16) ### Bug Fixes @@ -641,6 +688,7 @@ None for a non-existing Property - **local**: Enable prop caching ([`be29552`](https://github.com/Kitware/trame-vtk/commit/be29552102b0394ae3e45bcc96a0c6b4f2af73dc)) + ## v2.4.4 (2023-04-16) ### Bug Fixes @@ -656,6 +704,7 @@ None for a non-existing Property - **pv**: Add paraview validation example ([`9146694`](https://github.com/Kitware/trame-vtk/commit/914669478cb2ba088131d8da81ddc287003afb23)) + ## v2.4.3 (2023-04-07) ### Bug Fixes @@ -663,6 +712,7 @@ None for a non-existing Property - **export**: Add export for VtkLocalView ([`b58ccf4`](https://github.com/Kitware/trame-vtk/commit/b58ccf4109b25f567cac0f8f1185ab71e00c14dc)) + ## v2.4.2 (2023-03-31) ### Bug Fixes @@ -698,6 +748,7 @@ Signed-off-by: Patrick Avery - **examples**: Update the widget ones ([`cdda471`](https://github.com/Kitware/trame-vtk/commit/cdda471df5c2364e7359c2d6533ffcd4e4b38cf0)) + ## v2.4.1 (2023-03-27) ### Bug Fixes @@ -705,6 +756,7 @@ Signed-off-by: Patrick Avery - **paraview**: Fix protocol ([`b72425c`](https://github.com/Kitware/trame-vtk/commit/b72425cdde30344b15cebf8dd1b11aa62701176f)) + ## v2.4.0 (2023-03-24) ### Bug Fixes @@ -720,8 +772,8 @@ Signed-off-by: Patrick Avery ([`3c1614c`](https://github.com/Kitware/trame-vtk/commit/3c1614c82f47528e71de69916baa22961177c3d9)) Now, only critical messages from serializers are printed by default, unless the -`TRAME_SERIALIZE_DEBUG` environment variable is set, in which case all logger -output will be printed from the serializers. + `TRAME_SERIALIZE_DEBUG` environment variable is set, in which case all logger output will be + printed from the serializers. Signed-off-by: Patrick Avery @@ -733,15 +785,14 @@ Signed-off-by: Patrick Avery - **mouse_handler**: Apply a couple of fixes to mouse wheel event ([`45505ef`](https://github.com/Kitware/trame-vtk/commit/45505ef25bb76a4d04bddd9cecdc375999de9e1b)) -First of all, this updates the interactor with the mouse position on a wheel -event so that if there are multiple renderers, the interactor can figure out -which one needs to be updated. +First of all, this updates the interactor with the mouse position on a wheel event so that if there + are multiple renderers, the interactor can figure out which one needs to be updated. -Second, this forwards the event to the interactor, rather than applying a manual -zoom to the camera ourselves. This makes the behavior more consistent. +Second, this forwards the event to the interactor, rather than applying a manual zoom to the camera + ourselves. This makes the behavior more consistent. -Third, this skips the zoom for the start event, since there appears to always be -a wheel event right after it. +Third, this skips the zoom for the start event, since there appears to always be a wheel event right + after it. Fixes: pyvista/pyvista#4020 @@ -762,8 +813,7 @@ Signed-off-by: Patrick Avery - **vue-vtk-js**: Update vue-vtk-js to the newest version ([`eb7310d`](https://github.com/Kitware/trame-vtk/commit/eb7310dd9e763b069de438ad33db3173965c2e81)) -This includes mouse position information for moving the mouse wheel, which we -need. +This includes mouse position information for moving the mouse wheel, which we need. Signed-off-by: Patrick Avery @@ -798,8 +848,8 @@ Signed-off-by: Patrick Avery - **protocols**: Copy protocols from VTK exactly ([`9fe3c26`](https://github.com/Kitware/trame-vtk/commit/9fe3c261bc78a8814e1f4bab37ac6df3977144d8)) -This copies the protocols and render_window_serializer from VTK exactly as they -are. Further commits will modify the code. +This copies the protocols and render_window_serializer from VTK exactly as they are. Further commits + will modify the code. Signed-off-by: Patrick Avery @@ -808,16 +858,14 @@ Signed-off-by: Patrick Avery - **case**: Convert most variables from camelCase to snake_case ([`ba9beaf`](https://github.com/Kitware/trame-vtk/commit/ba9beaf5060ab2b992a85d7ae701f3f4853deba2)) -I went through the code and automatically converted most of the variables from -camelCase to snake_case using regex in vim. I skipped a couple of cases in -particular: +I went through the code and automatically converted most of the variables from camelCase to + snake_case using regex in vim. I skipped a couple of cases in particular: -1. Anything that started with `vtk` (this might be a VTK object) 2. Anything in - quotes (since they might be strings sent to VTK.js) +1. Anything that started with `vtk` (this might be a VTK object) 2. Anything in quotes (since they + might be strings sent to VTK.js) -There were, however, some things still that were modified that should not have -been. I tried to manually fix these, but I may have not caught everything, so we -should do testing to verify. +There were, however, some things still that were modified that should not have been. I tried to + manually fix these, but I may have not caught everything, so we should do testing to verify. Signed-off-by: Patrick Avery @@ -880,17 +928,15 @@ Signed-off-by: Patrick Avery - **serializers**: Apply patches from addon_serializer ([`a93a540`](https://github.com/Kitware/trame-vtk/commit/a93a5400f542c529024e18941f9323c7623cea12)) -This takes the patches being applied in addon_serializer.py and puts them -directly in the render window serializer. We should verify that there are no -issues. But I did notice some discrepancies: +This takes the patches being applied in addon_serializer.py and puts them directly in the render + window serializer. We should verify that there are no issues. But I did notice some discrepancies: -1. I saw no difference in `extractRequiredFields()` 2. The addon serializer did - not call `registerInstanceSerializer()` on `vtkStructuredPoints` with the - modified `imagedataSerializer` (only difference is that extent is used - instead of dimensions). 3. The addon serializer did not call - `registerInstanceSerializer()` on `vtkColorTransferFunction` with the - modified `colorTransferFunctionSerializer`. 4. `genericMapperSerializer()` - only had debug message modifications +1. I saw no difference in `extractRequiredFields()` 2. The addon serializer did not call + `registerInstanceSerializer()` on `vtkStructuredPoints` with the modified `imagedataSerializer` + (only difference is that extent is used instead of dimensions). 3. The addon serializer did not + call `registerInstanceSerializer()` on `vtkColorTransferFunction` with the modified + `colorTransferFunctionSerializer`. 4. `genericMapperSerializer()` only had debug message + modifications Signed-off-by: Patrick Avery @@ -927,6 +973,7 @@ The functions being used were copied over. Signed-off-by: Patrick Avery + ## v2.3.5 (2023-03-21) ### Bug Fixes @@ -934,6 +981,7 @@ Signed-off-by: Patrick Avery - Axes serializer ([`cc2136d`](https://github.com/Kitware/trame-vtk/commit/cc2136df0d4ff850f25f791ffc76f3ae2ba10a92)) + ## v2.3.4 (2023-03-10) ### Bug Fixes @@ -941,6 +989,7 @@ Signed-off-by: Patrick Avery - **RemoteView**: Support no size at startup ([`29c5587`](https://github.com/Kitware/trame-vtk/commit/29c5587f0ca72c78972d6304a48d469231d523e6)) + ## v2.3.3 (2023-03-10) ### Bug Fixes @@ -950,6 +999,7 @@ Signed-off-by: Patrick Avery fix #25 + ## v2.3.2 (2023-03-09) ### Bug Fixes @@ -957,6 +1007,7 @@ fix #25 - **serializer**: Add support for LUT components ([`3ace3f5`](https://github.com/Kitware/trame-vtk/commit/3ace3f5ffa6e0af6d9db029e0a5ca6fb3f4a7174)) + ## v2.3.1 (2023-03-09) ### Bug Fixes @@ -966,6 +1017,7 @@ fix #25 fix #16 + ## v2.3.0 (2023-03-09) ### Bug Fixes @@ -986,6 +1038,7 @@ fix #16 - **screenshot**: Allow screenshot extract ([`8db1f08`](https://github.com/Kitware/trame-vtk/commit/8db1f0845206fc65ec02f7169aa40ab63bb4d792)) + ## v2.2.3 (2023-03-03) ### Bug Fixes @@ -1001,6 +1054,7 @@ fix #16 - **widget**: Simple plane/clip ([`1365d51`](https://github.com/Kitware/trame-vtk/commit/1365d510ebffe0589e3579cbe6b25e8b349626cc)) + ## v2.2.2 (2023-02-28) ### Bug Fixes @@ -1008,6 +1062,7 @@ fix #16 - **widget**: Add a class to wrap vtkAbstractWidgets and make them easier to use ([`29e39d4`](https://github.com/Kitware/trame-vtk/commit/29e39d42b7115c6c1df82f7be38c7ecc456aedf5)) + ## v2.2.1 (2023-02-26) ### Bug Fixes @@ -1020,6 +1075,7 @@ fix #16 - **example**: Update latest vue3 syntax ([`5b64088`](https://github.com/Kitware/trame-vtk/commit/5b64088d05ad5b596758324204092404b8a33f00)) + ## v2.2.0 (2023-02-25) ### Bug Fixes @@ -1042,6 +1098,7 @@ fix #16 - **LocalRemote**: Allow full camera sync with helper method ([`a750af2`](https://github.com/Kitware/trame-vtk/commit/a750af248c5d7025491bca1a8ff6cd0a9bab441b)) + ## v2.1.0 (2023-02-23) ### Bug Fixes @@ -1054,11 +1111,12 @@ fix #16 - **vue23**: Update client code to work with vue2/3 ([`7a8f546`](https://github.com/Kitware/trame-vtk/commit/7a8f546de013f61f7973118b992fec5889c35690)) + ## v2.0.18 (2023-02-23) ### Bug Fixes -- **version**: Add **version** +- **version**: Add __version__ ([`c9ab451`](https://github.com/Kitware/trame-vtk/commit/c9ab451d9e397f2a9c64b488d957915086a81ddc)) Signed-off-by: Patrick Avery @@ -1072,6 +1130,7 @@ There is an issue in the CI that might be resolved if we switch back to master. Signed-off-by: Patrick Avery + ## v2.0.17 (2023-02-01) ### Bug Fixes @@ -1079,12 +1138,11 @@ Signed-off-by: Patrick Avery - **BigInt**: Add support for LocalView ([`aa34620`](https://github.com/Kitware/trame-vtk/commit/aa34620642c64ceb5fd625c83b22fc7f50e823ff)) -* fix: support BigInt64Array and BigUint64Array _ Update - trame_vtk/modules/vtk/addon_serializer.py _ Add PyVista Int64 validation - example _ docs(example): Improve int64 validation example _ fix(BigInt): - Update vue-vtk-js +* fix: support BigInt64Array and BigUint64Array * Update trame_vtk/modules/vtk/addon_serializer.py * + Add PyVista Int64 validation example * docs(example): Improve int64 validation example * + fix(BigInt): Update vue-vtk-js ---- +--------- Co-authored-by: Bane Sullivan @@ -1093,6 +1151,7 @@ Co-authored-by: Bane Sullivan - **semantic-release**: Fix version to 7.32.2 ([`bfa7c41`](https://github.com/Kitware/trame-vtk/commit/bfa7c41d908ebc2c2acbfee4835eccadfc5fb40b)) + ## v2.0.16 (2023-01-27) ### Bug Fixes @@ -1100,8 +1159,9 @@ Co-authored-by: Bane Sullivan - Imagedata extent and vtkSmartVolumeMapper ([`fc096c0`](https://github.com/Kitware/trame-vtk/commit/fc096c0e0190bfef2127aef2f46e3aa9ccdd8893)) -* fix: extent with ImageData serializer _ Remove dimensions _ fix: support - vtkSmartVolumeMapper \* Linting +* fix: extent with ImageData serializer * Remove dimensions * fix: support vtkSmartVolumeMapper * + Linting + ## v2.0.15 (2023-01-20) @@ -1113,6 +1173,7 @@ Co-authored-by: Bane Sullivan - **vtk**: Handle CubeAxes grid color + light + disable_auto_switch ([`d89c04e`](https://github.com/Kitware/trame-vtk/commit/d89c04e265a28234cd3467866c016247fc5d6e36)) + ## v2.0.14 (2023-01-10) ### Bug Fixes @@ -1120,6 +1181,7 @@ Co-authored-by: Bane Sullivan - Convert RGB colors to hex ([`0be279e`](https://github.com/Kitware/trame-vtk/commit/0be279e6190bcc7c54b9fc725da6df014376656a)) + ## v2.0.13 (2023-01-10) ### Bug Fixes @@ -1132,6 +1194,7 @@ Co-authored-by: Bane Sullivan fix #9 + ## v2.0.12 (2022-12-16) ### Bug Fixes @@ -1142,6 +1205,7 @@ fix #9 - **RemoteView**: Expose still_ratio/quality properties ([`7278d5e`](https://github.com/Kitware/trame-vtk/commit/7278d5ed7b8872167a9e9c653792b1b8543ac5ab)) + ## v2.0.11 (2022-12-09) ### Bug Fixes @@ -1149,6 +1213,7 @@ fix #9 - **vue-vtk-js**: Update to 2.1.2 ([`3cf8913`](https://github.com/Kitware/trame-vtk/commit/3cf8913158e36496e564c4a544f07a2f2cf6c630)) + ## v2.0.10 (2022-12-04) ### Bug Fixes @@ -1164,6 +1229,7 @@ fix #9 - **examples**: Add validation examples ([`209914a`](https://github.com/Kitware/trame-vtk/commit/209914ab142fe6bf2f7459a83c4f533d32157212)) + ## v2.0.9 (2022-11-05) ### Bug Fixes @@ -1171,6 +1237,7 @@ fix #9 - **LocalView**: Properly handle add/remove actor ([`85ee285`](https://github.com/Kitware/trame-vtk/commit/85ee285f67cf08438d37bae0bfd8d84ffe34db35)) + ## v2.0.8 (2022-10-20) ### Bug Fixes @@ -1181,6 +1248,7 @@ fix #9 - Improve VTK mapper and scalar bar serializers ([`fb94e81`](https://github.com/Kitware/trame-vtk/commit/fb94e81ef86c152f207e4fd442747c0d318a8dde)) + ## v2.0.7 (2022-10-05) ### Bug Fixes @@ -1188,6 +1256,7 @@ fix #9 - **VtkLocalView**: Automatically register update on_server_ready ([`5b5d296`](https://github.com/Kitware/trame-vtk/commit/5b5d296cc67518801c5ebff9397d55f99461c822)) + ## v2.0.6 (2022-09-01) ### Bug Fixes @@ -1229,6 +1298,7 @@ Signed-off-by: Patrick Avery Signed-off-by: Patrick Avery + ## v2.0.5 (2022-06-01) ### Bug Fixes @@ -1236,6 +1306,7 @@ Signed-off-by: Patrick Avery - **paraview**: Replace invalid import path ([`bd33f2a`](https://github.com/Kitware/trame-vtk/commit/bd33f2a2c71f80792a3039271d70b32f100aeed0)) + ## v2.0.4 (2022-05-31) ### Bug Fixes @@ -1243,6 +1314,7 @@ Signed-off-by: Patrick Avery - **widgets**: Expose more props ([`2fa0156`](https://github.com/Kitware/trame-vtk/commit/2fa01565461f62f96d3a18b2f649b5484981e5bf)) + ## v2.0.3 (2022-05-29) ### Bug Fixes @@ -1252,6 +1324,7 @@ Signed-off-by: Patrick Avery Signed-off-by: Patrick Avery + ## v2.0.2 (2022-05-27) ### Bug Fixes @@ -1259,12 +1332,12 @@ Signed-off-by: Patrick Avery - **paraview**: Remove unnecessary check for import ([`301b684`](https://github.com/Kitware/trame-vtk/commit/301b684378f30d46e93939da67ebd11f2027bf41)) -It is okay to check the servermanager import at the time of instantiating the -Helper class, and we do not need to check for the servermanager when the module -is imported. +It is okay to check the servermanager import at the time of instantiating the Helper class, and we + do not need to check for the servermanager when the module is imported. Signed-off-by: Patrick Avery + ## v2.0.1 (2022-05-27) ### Bug Fixes From 10fa7d641a640531a6cd882b55ac1f411e30a7c3 Mon Sep 17 00:00:00 2001 From: Ulysse DURAND Date: Mon, 20 Apr 2026 14:50:36 +0200 Subject: [PATCH 06/13] ci(pre-commit): correct pre-commit changes - Remove .flake8 file - Right noqa codes for test_import.py - Revert and ignore static_viewer.html from prettier Ref: https://github.com/Kitware/trame-vtk/pull/108#discussion_r3108168796 Ref: https://github.com/Kitware/trame-vtk/pull/108#discussion_r3108176041 Ref: https://github.com/Kitware/trame-vtk/pull/108#discussion_r3108223255 --- .flake8 | 14 -------------- .pre-commit-config.yaml | 6 +++++- CHANGELOG.md | 3 --- tests/test_import.py | 2 +- 4 files changed, 6 insertions(+), 19 deletions(-) delete mode 100644 .flake8 diff --git a/.flake8 b/.flake8 deleted file mode 100644 index 9420840..0000000 --- a/.flake8 +++ /dev/null @@ -1,14 +0,0 @@ -[flake8] - -# Just assume black did a good job with the line lengths -ignore = - E501 - -per-file-ignores = - # These directories will always contain "from ... import *" - trame/*:F401,F403 - examples/*:F401,F403,T20 # Will also contain `print` - -# Black sometimes conflicts with flake8 here -# Ignore white space after binary operator and assigning lambda expressions -extend-ignore = E203, W503, E731 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 00af8fa..c45675e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -40,7 +40,11 @@ repos: - id: prettier types_or: [yaml, markdown, html, css, scss, javascript, json] args: [--prose-wrap=always] - exclude: (CHANGELOG.md) + exclude: | + (?x)^( + CHANGELOG.md| + src/trame_vtk/tools/static_viewer.html + )$ - repo: https://github.com/astral-sh/ruff-pre-commit rev: "v0.15.10" diff --git a/CHANGELOG.md b/CHANGELOG.md index b8d9b3b..9b6d8bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,6 @@ # CHANGELOG -<<<<<<< HEAD ## v2.11.8 (2026-04-24) ### Bug Fixes @@ -12,8 +11,6 @@ fix #111 -======= ->>>>>>> 86f4a5d (ci(pre-commit): revert `CHANGELOG.md` and make prettier ignore it) ## v2.11.7 (2026-04-13) ### Bug Fixes diff --git a/tests/test_import.py b/tests/test_import.py index 82959de..2832b32 100644 --- a/tests/test_import.py +++ b/tests/test_import.py @@ -1,2 +1,2 @@ def test_import(): - pass + from trame.widgets.vtk import VtkAlgorithm # noqa: PLC0415, F401 From 7e5a64e75c7b33095c1d35eb530a794a69499819 Mon Sep 17 00:00:00 2001 From: Ulysse DURAND Date: Mon, 20 Apr 2026 15:39:25 +0200 Subject: [PATCH 07/13] ci(pre-commit): put right import order back Ref: https://github.com/Kitware/trame-vtk/pull/108#discussion_r3108255175 --- .../modules/vtk/protocols/mouse_handler.py | 10 +++++----- src/trame_vtk/modules/vtk/serializers/data.py | 16 ++++++++-------- .../modules/vtk/serializers/lookup_tables.py | 4 ++-- src/trame_vtk/modules/vtk/serializers/mappers.py | 5 +++-- src/trame_vtk/modules/vtk/serializers/mesh.py | 12 +++--------- .../vtk/serializers/synchronization_context.py | 9 +++++++-- src/trame_vtk/modules/vtk/widget.py | 9 +++++---- 7 files changed, 33 insertions(+), 32 deletions(-) diff --git a/src/trame_vtk/modules/vtk/protocols/mouse_handler.py b/src/trame_vtk/modules/vtk/protocols/mouse_handler.py index 43c843a..3178b03 100644 --- a/src/trame_vtk/modules/vtk/protocols/mouse_handler.py +++ b/src/trame_vtk/modules/vtk/protocols/mouse_handler.py @@ -3,14 +3,14 @@ import os import sys -from vtk_module.vtkWebCore import vtkWebInteractionEvent -from wslink import register as export_rpc - -from .web_protocol import vtkWebProtocol - vtk_module_name = os.environ.get("VTK_MODULE_NAME", "vtkmodules") sys.modules["vtk_module"] = importlib.import_module(vtk_module_name) +from vtk_module.vtkWebCore import vtkWebInteractionEvent # noqa: E402 +from wslink import register as export_rpc # noqa: E402 + +from .web_protocol import vtkWebProtocol # noqa: E402 + def apply_modifiers(event, interactor): interactor.SetShiftKey(1 if event.get("shiftKey") else 0) diff --git a/src/trame_vtk/modules/vtk/serializers/data.py b/src/trame_vtk/modules/vtk/serializers/data.py index ae527c4..2a910b8 100644 --- a/src/trame_vtk/modules/vtk/serializers/data.py +++ b/src/trame_vtk/modules/vtk/serializers/data.py @@ -3,18 +3,18 @@ import os import sys -from vtk_module.vtkFiltersGeometry import ( +vtk_module_name = os.environ.get("VTK_MODULE_NAME", "vtkmodules") +sys.modules["vtk_module"] = importlib.import_module(vtk_module_name) + +from vtk_module.vtkFiltersGeometry import ( # noqa: E402 vtkCompositeDataGeometryFilter, vtkDataSetSurfaceFilter, ) -from .helpers import extract_required_fields, get_array_description -from .registry import class_name -from .serialize import serialize -from .utils import get_js_array_type, reference_id, wrap_id - -vtk_module_name = os.environ.get("VTK_MODULE_NAME", "vtkmodules") -sys.modules["vtk_module"] = importlib.import_module(vtk_module_name) +from .helpers import extract_required_fields, get_array_description # noqa: E402 +from .registry import class_name # noqa: E402 +from .serialize import serialize # noqa: E402 +from .utils import get_js_array_type, reference_id, wrap_id # noqa: E402 logger = logging.getLogger(__name__) diff --git a/src/trame_vtk/modules/vtk/serializers/lookup_tables.py b/src/trame_vtk/modules/vtk/serializers/lookup_tables.py index f74672e..905964f 100644 --- a/src/trame_vtk/modules/vtk/serializers/lookup_tables.py +++ b/src/trame_vtk/modules/vtk/serializers/lookup_tables.py @@ -3,8 +3,6 @@ import sys from contextlib import suppress -from vtk_module.vtkRenderingCore import vtkColorTransferFunction - from .cache import cache_properties from .helpers import data_table_to_list, linspace from .registry import class_name @@ -13,6 +11,8 @@ vtk_module_name = os.environ.get("VTK_MODULE_NAME", "vtkmodules") sys.modules["vtk_module"] = importlib.import_module(vtk_module_name) +from vtk_module.vtkRenderingCore import vtkColorTransferFunction # noqa: E402 + def lookup_table_serializer(parent, lookup_table, lookup_table_id, context, _depth): # No children in this case, so no additions to bindings and return empty list diff --git a/src/trame_vtk/modules/vtk/serializers/mappers.py b/src/trame_vtk/modules/vtk/serializers/mappers.py index 3e05e91..05f32fe 100644 --- a/src/trame_vtk/modules/vtk/serializers/mappers.py +++ b/src/trame_vtk/modules/vtk/serializers/mappers.py @@ -3,8 +3,6 @@ import os import sys -from vtk_module.vtkFiltersGeometry import vtkDataSetSurfaceFilter - from .cache import cache_properties from .registry import class_name from .serialize import serialize @@ -12,6 +10,9 @@ vtk_module_name = os.environ.get("VTK_MODULE_NAME", "vtkmodules") sys.modules["vtk_module"] = importlib.import_module(vtk_module_name) + +from vtk_module.vtkFiltersGeometry import vtkDataSetSurfaceFilter # noqa: E402 + logger = logging.getLogger(__name__) diff --git a/src/trame_vtk/modules/vtk/serializers/mesh.py b/src/trame_vtk/modules/vtk/serializers/mesh.py index e88d64b..9082955 100644 --- a/src/trame_vtk/modules/vtk/serializers/mesh.py +++ b/src/trame_vtk/modules/vtk/serializers/mesh.py @@ -4,12 +4,13 @@ import sys import numpy as np -from vtk_module.util.numpy_support import vtk_to_numpy -from vtk_module.vtkFiltersGeometry import vtkDataSetSurfaceFilter vtk_module_name = os.environ.get("VTK_MODULE_NAME", "vtkmodules") sys.modules["vtk_module"] = importlib.import_module(vtk_module_name) +from vtk_module.util.numpy_support import vtk_to_numpy # noqa: E402 +from vtk_module.vtkFiltersGeometry import vtkDataSetSurfaceFilter # noqa: E402 + def mesh(dataset, field_to_keep=None, point_arrays=None, cell_arrays=None): """Expect any dataset and extract its surface into a dash_vtk.Mesh state property""" @@ -83,17 +84,10 @@ def mesh(dataset, field_to_keep=None, point_arrays=None, cell_arrays=None): def mesh_array(array): - if not array: - msg = "array cannot be None or empty" - raise ValueError(msg) return b64_encode_numpy(vtk_to_numpy(array.GetData())) def data_array(data_array, location="PointData", name=None): - if not data_array: - msg = "data array cannot be None or empty" - raise ValueError(msg) - data_range = data_array.GetRange(-1) nb_comp = data_array.GetNumberOfComponents() values = vtk_to_numpy(data_array) diff --git a/src/trame_vtk/modules/vtk/serializers/synchronization_context.py b/src/trame_vtk/modules/vtk/serializers/synchronization_context.py index 24025f2..96a2744 100644 --- a/src/trame_vtk/modules/vtk/serializers/synchronization_context.py +++ b/src/trame_vtk/modules/vtk/serializers/synchronization_context.py @@ -6,12 +6,17 @@ import time import zipfile -from vtk_module.vtkCommonCore import vtkDoubleArray, vtkFloatArray, vtkTypeUInt32Array - from .utils import base64_encode, wrap_id vtk_module_name = os.environ.get("VTK_MODULE_NAME", "vtkmodules") sys.modules["vtk_module"] = importlib.import_module(vtk_module_name) + +from vtk_module.vtkCommonCore import ( # noqa: E402 + vtkDoubleArray, + vtkFloatArray, + vtkTypeUInt32Array, +) + logger = logging.getLogger(__name__) JS_VTK_ARRAY = { diff --git a/src/trame_vtk/modules/vtk/widget.py b/src/trame_vtk/modules/vtk/widget.py index 1c510f2..7898b58 100644 --- a/src/trame_vtk/modules/vtk/widget.py +++ b/src/trame_vtk/modules/vtk/widget.py @@ -5,14 +5,15 @@ from typing import Callable, Optional from vtk_module.vtkCommonCore import vtkCommand -from vtk_module.vtkInteractionWidgets import ( - vtkAbstractWidget, - vtkWidgetRepresentation, -) vtk_module_name = os.environ.get("VTK_MODULE_NAME", "vtkmodules") sys.modules["vtk_module"] = importlib.import_module(vtk_module_name) +from vtk_module.vtkInteractionWidgets import ( # noqa: E402 + vtkAbstractWidget, + vtkWidgetRepresentation, +) + EventCallback = Callable[[vtkCommand.EventIds, Optional["VtkWidget"]], None] From 837df4cb4542bcb8f947aafa11a985e39211dfad Mon Sep 17 00:00:00 2001 From: Ulysse DURAND Date: Mon, 20 Apr 2026 16:15:33 +0200 Subject: [PATCH 08/13] ci(pre-commit): bump vtk and pyvista for tests Ref: https://github.com/Kitware/trame-vtk/pull/108/changes/ BASE..146b233cdc35e942891e409214756eafabdf120d#r3108179503 --- tests/requirements.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/requirements.txt b/tests/requirements.txt index b43f121..b8ae6a2 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -1,8 +1,8 @@ coverage pytest-asyncio pytest-playwright -pyvista[all]==0.45.2 +pyvista[all]==0.47.3 trame trame-client[test] trame-vuetify -vtk==9.4.2 +vtk==9.6.1 From 54ed5bf0657fa14949749c0eea86d47a5c2a5235 Mon Sep 17 00:00:00 2001 From: Ulysse DURAND Date: Thu, 23 Apr 2026 11:39:02 +0200 Subject: [PATCH 09/13] ci(pre-commit): make volume render test work with newer pyvista and vtk Ref: https://github.com/Kitware/trame-vtk/pull/108/commits/76b00f28b13dad8496b569822eccd4d3ef343266 Ref: https://github.com/Kitware/trame-vtk/actions/runs/24671570184/job/72314591774?pr=108 --- tests/refs/test_rendering_volume/ref2.png | Bin 81057 -> 82079 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/tests/refs/test_rendering_volume/ref2.png b/tests/refs/test_rendering_volume/ref2.png index bf526f4862e898323b6da44441be70a467dfb7c0..0311139c19acadec7c381cab4a16a6a4b46d43d6 100644 GIT binary patch literal 82079 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 literal 81057 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 TBgPKkCm_<|@?zB@27&(rZ*n-5 From 1e23908435cf528b02733426d6cbdd615b174d8c Mon Sep 17 00:00:00 2001 From: Ulysse DURAND Date: Mon, 27 Apr 2026 09:56:18 +0200 Subject: [PATCH 10/13] ci(pre-commit): revert the mistake of changing `show_axis` to `_depth` Now it is replaced with `_show_axis` Ref: https://github.com/Kitware/trame-vtk/pull/108#discussion_r3134523421 Ref: https://github.com/Kitware/trame-vtk/pull/108#discussion_r3134524240 --- src/trame_vtk/modules/vtk/protocols/view_port.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/trame_vtk/modules/vtk/protocols/view_port.py b/src/trame_vtk/modules/vtk/protocols/view_port.py index 7d2599c..feec086 100644 --- a/src/trame_vtk/modules/vtk/protocols/view_port.py +++ b/src/trame_vtk/modules/vtk/protocols/view_port.py @@ -21,7 +21,7 @@ def reset_camera(self, view_id): return str(self.get_global_id(view)) @export_rpc("viewport.axes.orientation.visibility.update") - def update_orientation_axes_visibility(self, view_id, _depth): + def update_orientation_axes_visibility(self, view_id, _show_axis): """ RPC callback to show/hide OrientationAxis. """ @@ -34,7 +34,7 @@ def update_orientation_axes_visibility(self, view_id, _depth): return str(self.get_global_id(view)) @export_rpc("viewport.axes.center.visibility.update") - def update_center_axes_visibility(self, view_id, _depth): + def update_center_axes_visibility(self, view_id, _show_axis): """ RPC callback to show/hide CenterAxesVisibility. """ From caf4a7c5418ef5c9886e832f1967458a9a2a5185 Mon Sep 17 00:00:00 2001 From: Ulysse DURAND Date: Mon, 27 Apr 2026 10:18:21 +0200 Subject: [PATCH 11/13] ci(pre-commit): Change variable name, handle None, change import order - Revert variable name for kwarg usage (add noqa ARG001) in imagedata serializer - Handle None data array in mesh serialization - Change import order Ref: https://github.com/Kitware/trame-vtk/pull/108#discussion_r3134540961 Ref: https://github.com/Kitware/trame-vtk/pull/108#discussion_r3134587169 Ref: https://github.com/Kitware/trame-vtk/pull/108#discussion_r3134591209 Ref: https://github.com/Kitware/trame-vtk/pull/108#discussion_r3134598613 --- src/trame_vtk/modules/vtk/serializers/data.py | 2 +- src/trame_vtk/modules/vtk/serializers/mesh.py | 4 +++- src/trame_vtk/modules/vtk/widget.py | 3 +-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/trame_vtk/modules/vtk/serializers/data.py b/src/trame_vtk/modules/vtk/serializers/data.py index 2a910b8..d951f38 100644 --- a/src/trame_vtk/modules/vtk/serializers/data.py +++ b/src/trame_vtk/modules/vtk/serializers/data.py @@ -135,7 +135,7 @@ def imagedata_serializer( dataset_id, context, _depth, - _requested_fields, + requested_fields, # noqa: ARG001 ): if hasattr(dataset, "GetDirectionMatrix"): direction = [dataset.GetDirectionMatrix().GetElement(0, i) for i in range(9)] diff --git a/src/trame_vtk/modules/vtk/serializers/mesh.py b/src/trame_vtk/modules/vtk/serializers/mesh.py index 9082955..3edfd04 100644 --- a/src/trame_vtk/modules/vtk/serializers/mesh.py +++ b/src/trame_vtk/modules/vtk/serializers/mesh.py @@ -84,10 +84,12 @@ def mesh(dataset, field_to_keep=None, point_arrays=None, cell_arrays=None): def mesh_array(array): - return b64_encode_numpy(vtk_to_numpy(array.GetData())) + return b64_encode_numpy(vtk_to_numpy(array.GetData())) if array else None def data_array(data_array, location="PointData", name=None): + if data_array is None: + return None data_range = data_array.GetRange(-1) nb_comp = data_array.GetNumberOfComponents() values = vtk_to_numpy(data_array) diff --git a/src/trame_vtk/modules/vtk/widget.py b/src/trame_vtk/modules/vtk/widget.py index 7898b58..9c2f043 100644 --- a/src/trame_vtk/modules/vtk/widget.py +++ b/src/trame_vtk/modules/vtk/widget.py @@ -4,11 +4,10 @@ from functools import partialmethod from typing import Callable, Optional -from vtk_module.vtkCommonCore import vtkCommand - vtk_module_name = os.environ.get("VTK_MODULE_NAME", "vtkmodules") sys.modules["vtk_module"] = importlib.import_module(vtk_module_name) +from vtk_module.vtkCommonCore import vtkCommand # noqa: E402 from vtk_module.vtkInteractionWidgets import ( # noqa: E402 vtkAbstractWidget, vtkWidgetRepresentation, From f692eb0b7e41f9803842feb050e64da50f3dc656 Mon Sep 17 00:00:00 2001 From: Ulysse DURAND Date: Thu, 30 Apr 2026 16:55:55 +0200 Subject: [PATCH 12/13] ci(pre-commit): change _ to _kwargs when replaced by error --- examples/pyvista/ambient.py | 2 +- examples/pyvista/picking.py | 2 +- examples/pyvista/pump_bracket.py | 6 +-- examples/pyvista/scalar_range.py | 2 +- examples/pyvista/silhouette.py | 2 +- examples/validation/AddRemoveActors.py | 6 +-- examples/validation/CaptureImage.py | 2 +- examples/validation/CaptureImageLocal.py | 2 +- examples/validation/CaptureImageRemote.py | 2 +- examples/validation/ColorByComponent.py | 2 +- .../validation/ColorByComponentPyVista.py | 4 +- examples/validation/ExportScene.py | 2 +- examples/validation/ManyViews.py | 10 ++--- examples/validation/PushCamera.py | 2 +- examples/validation/PvConeLocal.py | 2 +- examples/validation/PvConeRemote.py | 2 +- examples/validation/PvConeRemoteLocal.py | 2 +- examples/validation/PyVistaAxesWidget.py | 2 +- .../validation/PyVistaAxesWidgetSubplot.py | 4 +- examples/validation/PyVistaDynaLUT.py | 2 +- examples/validation/SwitchView.py | 2 +- examples/vue2/cone-local.py | 2 +- examples/vue2/cone-remote.py | 2 +- examples/vue2/cone-toggle.py | 2 +- examples/vue2/pv-cone-toggle.py | 2 +- examples/vue2/vtkjs-polydata.py | 2 +- examples/vue3/cone-local.py | 2 +- examples/vue3/cone-remote.py | 2 +- examples/vue3/cone-toggle.py | 2 +- examples/vue3/cone-webxr.py | 2 +- examples/vue3/vtkjs-polydata.py | 2 +- examples/widgets/clip.py | 6 +-- src/trame_vtk/modules/paraview/__init__.py | 8 ++-- .../paraview/protocols/local_rendering.py | 4 +- .../paraview/protocols/mouse_handler.py | 2 +- .../protocols/publish_image_delivery.py | 2 +- .../modules/paraview/protocols/view_port.py | 2 +- .../paraview/protocols/web_protocol.py | 2 +- src/trame_vtk/modules/vtk/__init__.py | 10 ++--- .../modules/vtk/protocols/local_rendering.py | 4 +- .../modules/vtk/serializers/initialize.py | 6 --- src/trame_vtk/widgets/vtk/common.py | 42 ++++++++++--------- 42 files changed, 83 insertions(+), 87 deletions(-) diff --git a/examples/pyvista/ambient.py b/examples/pyvista/ambient.py index 5ca550c..914a8a0 100644 --- a/examples/pyvista/ambient.py +++ b/examples/pyvista/ambient.py @@ -30,7 +30,7 @@ @state.change("color") -def color(color="lightblue", **_): +def color(color="lightblue", **_kwargs): actor.prop.color = color ctrl.view_update() diff --git a/examples/pyvista/picking.py b/examples/pyvista/picking.py index 127391c..fb65331 100644 --- a/examples/pyvista/picking.py +++ b/examples/pyvista/picking.py @@ -46,7 +46,7 @@ def on_box_selection(event): ... @state.change("selection_mode") -def on_mode_change(selection_mode, **_): +def on_mode_change(selection_mode, **_kwargs): # Use box for selection state.box_selection = selection_mode in [ "select_surface_point", diff --git a/examples/pyvista/pump_bracket.py b/examples/pyvista/pump_bracket.py index 5b3d341..1573618 100644 --- a/examples/pyvista/pump_bracket.py +++ b/examples/pyvista/pump_bracket.py @@ -45,13 +45,13 @@ @state.change("cmap") -def update_cmap(cmap="viridis", **_): +def update_cmap(cmap="viridis", **_kwargs): actor.mapper.lookup_table.cmap = cmap ctrl.view_update() @state.change("phase_index") -def update_phase(phase_index=0, **_): +def update_phase(phase_index=0, **_kwargs): phase = phases[phase_index] # feel free to change this to visualize different mode shapes mode_shape = "disp_6" @@ -62,7 +62,7 @@ def update_phase(phase_index=0, **_): @state.change("play") @asynchronous.task -async def update_play(**_): +async def update_play(**_kwargs): while state.play: with state: if state.phase_index >= len(phases): diff --git a/examples/pyvista/scalar_range.py b/examples/pyvista/scalar_range.py index f8d7037..53379b0 100644 --- a/examples/pyvista/scalar_range.py +++ b/examples/pyvista/scalar_range.py @@ -847,7 +847,7 @@ @state.change("scalar_range") -def set_scalar_range(scalar_range=None, **_): +def set_scalar_range(scalar_range=None, **_kwargs): if scalar_range is None: scalar_range = mesh.get_data_range("foo") actor.mapper.scalar_range = scalar_range diff --git a/examples/pyvista/silhouette.py b/examples/pyvista/silhouette.py index b3e067a..ee46340 100644 --- a/examples/pyvista/silhouette.py +++ b/examples/pyvista/silhouette.py @@ -67,7 +67,7 @@ @state.change("resolution") -def update_cone(resolution=DEFAULT_RESOLUTION, **_): +def update_cone(resolution=DEFAULT_RESOLUTION, **_kwargs): cone_source.SetResolution(resolution) ctrl.view2_update() ctrl.view_update() diff --git a/examples/validation/AddRemoveActors.py b/examples/validation/AddRemoveActors.py index bf114af..2f06390 100644 --- a/examples/validation/AddRemoveActors.py +++ b/examples/validation/AddRemoveActors.py @@ -75,7 +75,7 @@ def create_pipeline(source): @state.change("resolution") -def update_resolution(resolution=DEFAULT_RESOLUTION, **_): +def update_resolution(resolution=DEFAULT_RESOLUTION, **_kwargs): cone_source.SetResolution(resolution) ctrl.view_update() @@ -85,7 +85,7 @@ def update_reset_resolution(): @state.change("show_cone") -def update_cone(show_cone, **_): +def update_cone(show_cone, **_kwargs): if show_cone: renderer.AddActor(cone_actor) else: @@ -94,7 +94,7 @@ def update_cone(show_cone, **_): @state.change("show_sphere") -def update_sphere(show_sphere, **_): +def update_sphere(show_sphere, **_kwargs): if show_sphere: renderer.AddActor(sphere_actor) else: diff --git a/examples/validation/CaptureImage.py b/examples/validation/CaptureImage.py index bd93188..1bdd957 100644 --- a/examples/validation/CaptureImage.py +++ b/examples/validation/CaptureImage.py @@ -53,7 +53,7 @@ @state.change("resolution") -def update_cone(resolution=DEFAULT_RESOLUTION, **_): +def update_cone(resolution=DEFAULT_RESOLUTION, **_kwargs): cone_source.SetResolution(resolution) ctrl.view_update() diff --git a/examples/validation/CaptureImageLocal.py b/examples/validation/CaptureImageLocal.py index b35784f..818fb8a 100644 --- a/examples/validation/CaptureImageLocal.py +++ b/examples/validation/CaptureImageLocal.py @@ -53,7 +53,7 @@ @state.change("resolution") -def update_cone(resolution=DEFAULT_RESOLUTION, **_): +def update_cone(resolution=DEFAULT_RESOLUTION, **_kwargs): cone_source.SetResolution(resolution) ctrl.view_update() diff --git a/examples/validation/CaptureImageRemote.py b/examples/validation/CaptureImageRemote.py index 0786681..f81ab21 100644 --- a/examples/validation/CaptureImageRemote.py +++ b/examples/validation/CaptureImageRemote.py @@ -53,7 +53,7 @@ @state.change("resolution") -def update_cone(resolution=DEFAULT_RESOLUTION, **_): +def update_cone(resolution=DEFAULT_RESOLUTION, **_kwargs): cone_source.SetResolution(resolution) ctrl.view_update() diff --git a/examples/validation/ColorByComponent.py b/examples/validation/ColorByComponent.py index 70ca115..4e2764a 100644 --- a/examples/validation/ColorByComponent.py +++ b/examples/validation/ColorByComponent.py @@ -61,7 +61,7 @@ @state.change("component_idx") -def color_by_array(component_idx, **_): +def color_by_array(component_idx, **_kwargs): lut.SetVectorComponent(component_idx) ctrl.remote_view_update() ctrl.local_view_update() diff --git a/examples/validation/ColorByComponentPyVista.py b/examples/validation/ColorByComponentPyVista.py index d361485..2c4f13d 100644 --- a/examples/validation/ColorByComponentPyVista.py +++ b/examples/validation/ColorByComponentPyVista.py @@ -45,7 +45,7 @@ @state.change("component_idx") -def color_by_array(component_idx, **_): +def color_by_array(component_idx, **_kwargs): lut.SetVectorModeToComponent() lut.SetVectorSize(3) lut.SetVectorComponent(component_idx) @@ -55,7 +55,7 @@ def color_by_array(component_idx, **_): @state.change("cmap") -def color_preset(cmap, **_): +def color_preset(cmap, **_kwargs): lut.cmap = cmap ctrl.remote_view_update() ctrl.local_view_update() diff --git a/examples/validation/ExportScene.py b/examples/validation/ExportScene.py index 429dca7..e7be045 100644 --- a/examples/validation/ExportScene.py +++ b/examples/validation/ExportScene.py @@ -41,7 +41,7 @@ def export_scene(): @state.change("resolution") -def update_cone(resolution=DEFAULT_RESOLUTION, **_): +def update_cone(resolution=DEFAULT_RESOLUTION, **_kwargs): cone_source.SetResolution(resolution) ctrl.view_update() diff --git a/examples/validation/ManyViews.py b/examples/validation/ManyViews.py index c1690e5..9f1d0d3 100644 --- a/examples/validation/ManyViews.py +++ b/examples/validation/ManyViews.py @@ -114,7 +114,7 @@ def reset_active_view(): @state.change("active_view") -def active_view_change(active_view, **_): +def active_view_change(active_view, **_kwargs): pipeline = VIEWS[active_view] state.show_cone = pipeline.get("show_cone") state.show_sphere = pipeline.get("show_sphere") @@ -123,12 +123,12 @@ def active_view_change(active_view, **_): @state.change("widget_on") -def toggle_view(widget_on, active_view, **_): +def toggle_view(widget_on, active_view, **_kwargs): state[f"widget_on_{active_view}"] = widget_on @state.change("resolution") -def update_resolution(resolution, active_view, **_): +def update_resolution(resolution, active_view, **_kwargs): pipeline = VIEWS[active_view] pipeline.get("cone").SetResolution(resolution) pipeline["resolution"] = resolution @@ -140,7 +140,7 @@ def update_reset_resolution(): @state.change("show_cone") -def update_cone(active_view, show_cone, **_): +def update_cone(active_view, show_cone, **_kwargs): pipeline = VIEWS[active_view] renderer = pipeline.get("renderer") cone_actor = pipeline.get("cone_actor") @@ -153,7 +153,7 @@ def update_cone(active_view, show_cone, **_): @state.change("show_sphere") -def update_sphere(active_view, show_sphere, **_): +def update_sphere(active_view, show_sphere, **_kwargs): pipeline = VIEWS[active_view] renderer = pipeline.get("renderer") sphere_actor = pipeline.get("sphere_actor") diff --git a/examples/validation/PushCamera.py b/examples/validation/PushCamera.py index 563cdc1..d879b6d 100644 --- a/examples/validation/PushCamera.py +++ b/examples/validation/PushCamera.py @@ -57,7 +57,7 @@ @state.change("resolution") -def update_resolution(resolution, **_): +def update_resolution(resolution, **_kwargs): cone_source.SetResolution(resolution) ctrl.view_update() diff --git a/examples/validation/PvConeLocal.py b/examples/validation/PvConeLocal.py index 983dc45..de01cfe 100644 --- a/examples/validation/PvConeLocal.py +++ b/examples/validation/PvConeLocal.py @@ -26,7 +26,7 @@ @state.change("resolution") -def update_cone(resolution, **_): +def update_cone(resolution, **_kwargs): cone.Resolution = resolution ctrl.view_update() diff --git a/examples/validation/PvConeRemote.py b/examples/validation/PvConeRemote.py index 5c9388a..1cda7e9 100644 --- a/examples/validation/PvConeRemote.py +++ b/examples/validation/PvConeRemote.py @@ -26,7 +26,7 @@ @state.change("resolution") -def update_cone(resolution, **_): +def update_cone(resolution, **_kwargs): cone.Resolution = resolution ctrl.view_update() diff --git a/examples/validation/PvConeRemoteLocal.py b/examples/validation/PvConeRemoteLocal.py index 6937f4e..411437a 100644 --- a/examples/validation/PvConeRemoteLocal.py +++ b/examples/validation/PvConeRemoteLocal.py @@ -27,7 +27,7 @@ @state.change("resolution") -def update_cone(resolution, **_): +def update_cone(resolution, **_kwargs): cone.Resolution = resolution ctrl.view_update() diff --git a/examples/validation/PyVistaAxesWidget.py b/examples/validation/PyVistaAxesWidget.py index 98daa50..58216f0 100644 --- a/examples/validation/PyVistaAxesWidget.py +++ b/examples/validation/PyVistaAxesWidget.py @@ -26,7 +26,7 @@ @state.change("show_widget") -def toggle_axes_widget(show_widget, **_): +def toggle_axes_widget(show_widget, **_kwargs): if show_widget: plotter.renderer.show_axes() else: diff --git a/examples/validation/PyVistaAxesWidgetSubplot.py b/examples/validation/PyVistaAxesWidgetSubplot.py index a7026e8..219bf0c 100644 --- a/examples/validation/PyVistaAxesWidgetSubplot.py +++ b/examples/validation/PyVistaAxesWidgetSubplot.py @@ -33,7 +33,7 @@ @state.change("show_widget_a") -def toggle_axes_widget_a(show_widget_a, **_): +def toggle_axes_widget_a(show_widget_a, **_kwargs): plotter.subplot(0, 0) if show_widget_a: plotter.renderer.show_axes() @@ -43,7 +43,7 @@ def toggle_axes_widget_a(show_widget_a, **_): @state.change("show_widget_b") -def toggle_axes_widget_b(show_widget_b, **_): +def toggle_axes_widget_b(show_widget_b, **_kwargs): plotter.subplot(0, 1) if show_widget_b: plotter.renderer.show_axes() diff --git a/examples/validation/PyVistaDynaLUT.py b/examples/validation/PyVistaDynaLUT.py index 22fefb1..51e7e1c 100644 --- a/examples/validation/PyVistaDynaLUT.py +++ b/examples/validation/PyVistaDynaLUT.py @@ -27,7 +27,7 @@ @state.change("cmap") -def update_cmap(cmap="viridis", **_): +def update_cmap(cmap="viridis", **_kwargs): actor.mapper.lookup_table.cmap = cmap ctrl.view_update() diff --git a/examples/validation/SwitchView.py b/examples/validation/SwitchView.py index dc531f6..0ffbd86 100644 --- a/examples/validation/SwitchView.py +++ b/examples/validation/SwitchView.py @@ -113,7 +113,7 @@ def sphere(): @asynchronous.task -async def refresh_function(**_): +async def refresh_function(**_kwargs): counter = 1 while True: with state: diff --git a/examples/vue2/cone-local.py b/examples/vue2/cone-local.py index 9558381..25abd25 100644 --- a/examples/vue2/cone-local.py +++ b/examples/vue2/cone-local.py @@ -52,7 +52,7 @@ @state.change("resolution") -def update_cone(resolution=DEFAULT_RESOLUTION, **_): +def update_cone(resolution=DEFAULT_RESOLUTION, **_kwargs): cone_source.SetResolution(resolution) ctrl.view_update() diff --git a/examples/vue2/cone-remote.py b/examples/vue2/cone-remote.py index d47a1a0..fe5097d 100644 --- a/examples/vue2/cone-remote.py +++ b/examples/vue2/cone-remote.py @@ -52,7 +52,7 @@ @state.change("resolution") -def update_cone(resolution=DEFAULT_RESOLUTION, **_): +def update_cone(resolution=DEFAULT_RESOLUTION, **_kwargs): cone_source.SetResolution(resolution) ctrl.view_update() diff --git a/examples/vue2/cone-toggle.py b/examples/vue2/cone-toggle.py index 37f9250..515eafc 100644 --- a/examples/vue2/cone-toggle.py +++ b/examples/vue2/cone-toggle.py @@ -52,7 +52,7 @@ @state.change("resolution") -def update_cone(resolution=DEFAULT_RESOLUTION, **_): +def update_cone(resolution=DEFAULT_RESOLUTION, **_kwargs): cone_source.SetResolution(resolution) ctrl.view_update() diff --git a/examples/vue2/pv-cone-toggle.py b/examples/vue2/pv-cone-toggle.py index f77cf42..9b08707 100644 --- a/examples/vue2/pv-cone-toggle.py +++ b/examples/vue2/pv-cone-toggle.py @@ -27,7 +27,7 @@ @state.change("resolution") -def update_cone(resolution=DEFAULT_RESOLUTION, **_): +def update_cone(resolution=DEFAULT_RESOLUTION, **_kwargs): cone.Resolution = resolution ctrl.view_update() diff --git a/examples/vue2/vtkjs-polydata.py b/examples/vue2/vtkjs-polydata.py index 308e559..b685632 100644 --- a/examples/vue2/vtkjs-polydata.py +++ b/examples/vue2/vtkjs-polydata.py @@ -20,7 +20,7 @@ @state.change("resolution") -def update_cone(resolution, **_): +def update_cone(resolution, **_kwargs): cone_generator.SetResolution(resolution) ctrl.mesh_update() diff --git a/examples/vue3/cone-local.py b/examples/vue3/cone-local.py index 9970049..25724a2 100644 --- a/examples/vue3/cone-local.py +++ b/examples/vue3/cone-local.py @@ -52,7 +52,7 @@ @state.change("resolution") -def update_cone(resolution=DEFAULT_RESOLUTION, **_): +def update_cone(resolution=DEFAULT_RESOLUTION, **_kwargs): cone_source.SetResolution(resolution) ctrl.view_update() diff --git a/examples/vue3/cone-remote.py b/examples/vue3/cone-remote.py index b9d48e7..e8d6c07 100644 --- a/examples/vue3/cone-remote.py +++ b/examples/vue3/cone-remote.py @@ -52,7 +52,7 @@ @state.change("resolution") -def update_cone(resolution=DEFAULT_RESOLUTION, **_): +def update_cone(resolution=DEFAULT_RESOLUTION, **_kwargs): cone_source.SetResolution(resolution) ctrl.view_update() diff --git a/examples/vue3/cone-toggle.py b/examples/vue3/cone-toggle.py index b98ceab..096c757 100644 --- a/examples/vue3/cone-toggle.py +++ b/examples/vue3/cone-toggle.py @@ -52,7 +52,7 @@ @state.change("resolution") -def update_cone(resolution=DEFAULT_RESOLUTION, **_): +def update_cone(resolution=DEFAULT_RESOLUTION, **_kwargs): cone_source.SetResolution(resolution) ctrl.view_update() diff --git a/examples/vue3/cone-webxr.py b/examples/vue3/cone-webxr.py index 9e0581d..1fc50cf 100644 --- a/examples/vue3/cone-webxr.py +++ b/examples/vue3/cone-webxr.py @@ -54,7 +54,7 @@ @state.change("resolution") -def update_cone(resolution=DEFAULT_RESOLUTION, **_): +def update_cone(resolution=DEFAULT_RESOLUTION, **_kwargs): cone_source.SetResolution(resolution) ctrl.view_update() diff --git a/examples/vue3/vtkjs-polydata.py b/examples/vue3/vtkjs-polydata.py index 0624fd6..226c82f 100644 --- a/examples/vue3/vtkjs-polydata.py +++ b/examples/vue3/vtkjs-polydata.py @@ -20,7 +20,7 @@ @state.change("resolution") -def update_cone(resolution, **_): +def update_cone(resolution, **_kwargs): cone_generator.SetResolution(resolution) ctrl.mesh_update() diff --git a/examples/widgets/clip.py b/examples/widgets/clip.py index e084857..64ba6a8 100644 --- a/examples/widgets/clip.py +++ b/examples/widgets/clip.py @@ -76,12 +76,12 @@ plane_widget = widget_manager.add_widget(vtkImplicitPlaneWidget2) -def on_widget_interaction(*_): +def on_widget_interaction(*_args): if state.live_update: plane_widget.GetPlane(clip_plane) -def on_widget_done(*_): +def on_widget_done(*_args): plane_widget.GetPlane(clip_plane) @@ -101,7 +101,7 @@ def on_widget_done(*_): @state.change("show_widget") -def on_widget_show(show_widget, **_): +def on_widget_show(show_widget, **_kwargs): if show_widget: plane_widget.enable() else: diff --git a/src/trame_vtk/modules/paraview/__init__.py b/src/trame_vtk/modules/paraview/__init__.py index 8d02c71..e617baa 100644 --- a/src/trame_vtk/modules/paraview/__init__.py +++ b/src/trame_vtk/modules/paraview/__init__.py @@ -70,7 +70,7 @@ def scene( new_state=False, widgets=None, orientation_axis=0, - **_, + **_kwargs, ): # flush data without requiring a render/picture tmp = view_proxy.SuppressRendering @@ -91,7 +91,7 @@ def scene( scene_state.setdefault("extra", {})["resetCamera"] = 1 return scene_state - def export(self, render_window, widgets=None, orientation_axis=0, **_): + def export(self, render_window, widgets=None, orientation_axis=0, **_kwargs): return self._trame_server.protocol_call( "viewport.geometry.view.get.export", self.id(render_window), @@ -205,7 +205,7 @@ def add_hybrid_view( still_ratio=1, still_quality=98, force_replace=False, - **_, + **_kwargs, ): if name in self._hybrid_views: if force_replace: @@ -239,7 +239,7 @@ def remove_hybrid_view(self, name): HELPERS_PER_SERVER = {} -def setup(trame_server, **_): +def setup(trame_server, **_kwargs): HELPERS_PER_SERVER[trame_server.name] = Helper(trame_server) diff --git a/src/trame_vtk/modules/paraview/protocols/local_rendering.py b/src/trame_vtk/modules/paraview/protocols/local_rendering.py index 4895248..6fd539b 100644 --- a/src/trame_vtk/modules/paraview/protocols/local_rendering.py +++ b/src/trame_vtk/modules/paraview/protocols/local_rendering.py @@ -14,7 +14,7 @@ class ParaViewWebLocalRendering(ParaViewWebProtocol): - def __init__(self, **_): + def __init__(self, **_kwargs): super().__init__() initialize_serializers() self.context = SynchronizationContext() @@ -96,7 +96,7 @@ def get_view_state( new_subscription=False, widgets=None, orientation_axis=0, - **_, + **_kwargs, ): s_view = self.get_view(view_id) if not s_view: diff --git a/src/trame_vtk/modules/paraview/protocols/mouse_handler.py b/src/trame_vtk/modules/paraview/protocols/mouse_handler.py index 5af2293..ed9be3b 100644 --- a/src/trame_vtk/modules/paraview/protocols/mouse_handler.py +++ b/src/trame_vtk/modules/paraview/protocols/mouse_handler.py @@ -5,7 +5,7 @@ class ParaViewWebMouseHandler(ParaViewWebProtocol): - def __init__(self, **_): + def __init__(self, **_kwargs): super().__init__() self.last_action = "up" diff --git a/src/trame_vtk/modules/paraview/protocols/publish_image_delivery.py b/src/trame_vtk/modules/paraview/protocols/publish_image_delivery.py index d7fcd1c..a2ee8bf 100644 --- a/src/trame_vtk/modules/paraview/protocols/publish_image_delivery.py +++ b/src/trame_vtk/modules/paraview/protocols/publish_image_delivery.py @@ -19,7 +19,7 @@ def apply_modifiers(event, interactor): class ParaViewWebPublishImageDelivery(ParaViewWebProtocol): - def __init__(self, decode=True, **_): + def __init__(self, decode=True, **_kwargs): super().__init__() self.tracking_views = {} self.last_stale_time = {} diff --git a/src/trame_vtk/modules/paraview/protocols/view_port.py b/src/trame_vtk/modules/paraview/protocols/view_port.py index 5c8bc45..28b85dd 100644 --- a/src/trame_vtk/modules/paraview/protocols/view_port.py +++ b/src/trame_vtk/modules/paraview/protocols/view_port.py @@ -7,7 +7,7 @@ class ParaViewWebViewPort(ParaViewWebProtocol): - def __init__(self, scale=1.0, max_width=2560, max_height=1440, **_): + def __init__(self, scale=1.0, max_width=2560, max_height=1440, **_kwargs): super().__init__() self.scale = scale self.max_width = max_width diff --git a/src/trame_vtk/modules/paraview/protocols/web_protocol.py b/src/trame_vtk/modules/paraview/protocols/web_protocol.py index 7c8b6f2..581df85 100644 --- a/src/trame_vtk/modules/paraview/protocols/web_protocol.py +++ b/src/trame_vtk/modules/paraview/protocols/web_protocol.py @@ -100,7 +100,7 @@ def get_absolute_path(self, relative_path): # Make sure the cleaned_path is part of the allowed ones if self.multi_root: - for _, value in self.base_directory_map.items(): + for _key, value in self.base_directory_map.items(): if cleaned_path.startswith(value): return cleaned_path elif cleaned_path.startswith(self.base_directory): diff --git a/src/trame_vtk/modules/vtk/__init__.py b/src/trame_vtk/modules/vtk/__init__.py index f21de15..c23a775 100644 --- a/src/trame_vtk/modules/vtk/__init__.py +++ b/src/trame_vtk/modules/vtk/__init__.py @@ -30,7 +30,7 @@ """ -def has_capabilities(*_): +def has_capabilities(*_features): if not HAS_VTK_WEB: raise ImportError(IMPROPER_VTK_MSG) @@ -76,7 +76,7 @@ def scene( new_state=False, widgets=None, orientation_axis=0, - **_, + **_kwargs, ): scene_state = self._trame_server.protocol_call( "viewport.geometry.view.get.state", @@ -89,7 +89,7 @@ def scene( scene_state.setdefault("extra", {})["resetCamera"] = 1 return scene_state - def export(self, render_window, widgets=None, orientation_axis=0, **_): + def export(self, render_window, widgets=None, orientation_axis=0, **_kwargs): return self._trame_server.protocol_call( "viewport.geometry.view.get.export", self.id(render_window), @@ -196,7 +196,7 @@ def add_hybrid_view( still_ratio=1, still_quality=98, force_replace=False, - **_, + **_kwargs, ): if name in self._hybrid_views: if force_replace: @@ -234,7 +234,7 @@ def reload_app(self): HELPERS_PER_SERVER = {} -def setup(trame_server, **_): +def setup(trame_server, **_kwargs): if HAS_VTK_WEB: HELPERS_PER_SERVER[trame_server.name] = Helper(trame_server) diff --git a/src/trame_vtk/modules/vtk/protocols/local_rendering.py b/src/trame_vtk/modules/vtk/protocols/local_rendering.py index 436dec6..5f974df 100644 --- a/src/trame_vtk/modules/vtk/protocols/local_rendering.py +++ b/src/trame_vtk/modules/vtk/protocols/local_rendering.py @@ -18,7 +18,7 @@ class vtkWebLocalRendering(vtkWebProtocol): client-side rendering capability we have in vtk.js """ - def __init__(self, **_): + def __init__(self, **_kwargs): super().__init__() initialize_serializers() self.context = SynchronizationContext() @@ -99,7 +99,7 @@ def get_view_state( new_subscription=False, widgets=None, orientation_axis=0, - **_, + **_kwargs, ): s_view = self.get_view(view_id) if not s_view: diff --git a/src/trame_vtk/modules/vtk/serializers/initialize.py b/src/trame_vtk/modules/vtk/serializers/initialize.py index a1afb03..5b708f3 100644 --- a/src/trame_vtk/modules/vtk/serializers/initialize.py +++ b/src/trame_vtk/modules/vtk/serializers/initialize.py @@ -56,12 +56,6 @@ def skip_light(self): def skip_light(self, value): self._skip_light = value - def encode_lut(self, value=True): - self._convert_lut = value - - def skip_light(self, value=True): - self._skip_light = value - vtk_config = LUTConfig() diff --git a/src/trame_vtk/widgets/vtk/common.py b/src/trame_vtk/widgets/vtk/common.py index 93a546f..2967f97 100644 --- a/src/trame_vtk/widgets/vtk/common.py +++ b/src/trame_vtk/widgets/vtk/common.py @@ -494,7 +494,7 @@ def push_remote_camera_on_end_interaction(self): self.__view.GetInteractor().AddObserver(45, self._push_camera) def update_geometry( - self, _reset_camera=False, widgets=None, orientation_axis=0, **_ + self, _reset_camera=False, widgets=None, orientation_axis=0, **_kwargs ): """ Force update to geometry @@ -521,7 +521,9 @@ def update_geometry( ) self.server.state[self.__scene_id] = full_state - def export_geometry(self, widgets=None, orientation_axis=0, format="zip", **_): + def export_geometry( + self, widgets=None, orientation_axis=0, format="zip", **_kwargs + ): """Export standalone scene for OfflineViewer :param format: Can be either be "zip" or "json". @@ -560,13 +562,13 @@ def update_image(self, reset_camera=False): if self.server.protocol: self._helper.push_image(self.__view, reset_camera) - def set_local_rendering(self, local=True, **_): + def set_local_rendering(self, local=True, **_kwargs): self.server.state[self.__mode_key] = "local" if local else "remote" - def set_remote_rendering(self, remote=True, **_): + def set_remote_rendering(self, remote=True, **_kwargs): self.server.state[self.__mode_key] = "remote" if remote else "local" - def update(self, reset_camera=False, widgets=None, orientation_axis=0, **_): + def update(self, reset_camera=False, widgets=None, orientation_axis=0, **_kwargs): # need to do both to keep things in sync if self.__rendering: self.update_image(reset_camera) @@ -583,10 +585,10 @@ def update(self, reset_camera=False, widgets=None, orientation_axis=0, **_): self._helper.camera(self.__view), ) - def _push_camera(self, *_, **_kwargs): + def _push_camera(self, *_args, **_kwargs): self.push_camera() - def push_camera(self, camera=None, center_of_rotation=None, **_): + def push_camera(self, camera=None, center_of_rotation=None, **_kwargs): if camera is None: if hasattr(self.__view, "GetRenderers"): # VTK camera = self.__view.GetRenderers().GetFirstRenderer().GetActiveCamera() @@ -614,7 +616,7 @@ def push_camera(self, camera=None, center_of_rotation=None, **_): camera_params, ) - def replace_view(self, new_view, **_): + def replace_view(self, new_view, **_kwargs): self.server.state[self.__view_key_id] = self._helper.id(new_view) _mode = self.server.state[self.__mode_key] self.__view = new_view @@ -624,10 +626,10 @@ def replace_view(self, new_view, **_): self.update() self.resize() - def reset_camera(self, **_): + def reset_camera(self, **_kwargs): self.server.js_call(ref=self.__ref, method="resetCamera") - def resize(self, **_): + def resize(self, **_kwargs): self.server.js_call(ref=self.__ref, method="resize") @property @@ -760,7 +762,7 @@ def __init__(self, view, ref=None, **kwargs): "EndInteraction", ] - def update(self, **_): + def update(self, **_kwargs): """ Force image to be pushed to client """ @@ -790,16 +792,16 @@ def stop_animation(self): self._helper.stop_animation(self.__view) self.update() - def reset_camera(self, **_): + def reset_camera(self, **_kwargs): self.server.js_call(ref=self.__ref, method="resetCamera") - def replace_view(self, new_view, **_): + def replace_view(self, new_view, **_kwargs): self.__view = new_view self.server.state[self.__view_key_id] = self._helper.id(new_view) self.update() self.resize() - def resize(self, **_): + def resize(self, **_kwargs): self.server.js_call(ref=self.__ref, method="resize") def capture_image(self, format="image/png", opts=None): @@ -947,7 +949,7 @@ def set_widgets(self, value): self._widgets = value self.update() - def update(self, widgets=None, orientation_axis=0, **_): + def update(self, widgets=None, orientation_axis=0, **_kwargs): """ Force geometry to be pushed """ @@ -973,7 +975,7 @@ def update(self, widgets=None, orientation_axis=0, **_): ) self.server.state[self.__scene_id] = full_state - def export(self, widgets=None, orientation_axis=0, format="zip", **_): + def export(self, widgets=None, orientation_axis=0, format="zip", **_kwargs): """Export standalone scene for OfflineViewer :param format: Can be either be "zip" or "json". @@ -1005,23 +1007,23 @@ def export(self, widgets=None, orientation_axis=0, format="zip", **_): return None - def reset_camera(self, **_): + def reset_camera(self, **_kwargs): """ Move camera to center actors within the frame """ self.server.js_call(ref=self.__ref, method="resetCamera") - def replace_view(self, new_view, **_): + def replace_view(self, new_view, **_kwargs): self.__view = new_view self.server.js_call( self.__ref, "setSynchronizedViewId", self._helper.id(new_view) ) self.update() - def resize(self, **_): + def resize(self, **_kwargs): self.server.js_call(ref=self.__ref, method="resize") - def push_camera(self, camera=None, center_of_rotation=None, **_): + def push_camera(self, camera=None, center_of_rotation=None, **_kwargs): if camera is None: if hasattr(self.__view, "GetRenderers"): # VTK camera = self.__view.GetRenderers().GetFirstRenderer().GetActiveCamera() From e46886e5b2c1f421122b7a83b76f26e7033ace4b Mon Sep 17 00:00:00 2001 From: Ulysse DURAND Date: Mon, 1 Jun 2026 16:04:53 +0200 Subject: [PATCH 13/13] ci(pre-commit): fix new lint problems --- .pre-commit-config.yaml | 6 ------ .../modules/paraview/protocols/publish_image_delivery.py | 7 +++---- .../modules/vtk/protocols/publish_image_delivery.py | 7 +++---- src/trame_vtk/modules/vtk/serializers/cache.py | 3 +-- src/trame_vtk/modules/vtk/serializers/mappers.py | 9 +++++---- 5 files changed, 12 insertions(+), 20 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c45675e..e036dcd 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -21,12 +21,6 @@ repos: - id: requirements-txt-fixer - id: trailing-whitespace - - repo: https://github.com/adamchainz/blacken-docs - rev: "1.19.1" - hooks: - - id: blacken-docs - additional_dependencies: [black==24.*] - - repo: https://github.com/pre-commit/pygrep-hooks rev: "v1.10.0" hooks: diff --git a/src/trame_vtk/modules/paraview/protocols/publish_image_delivery.py b/src/trame_vtk/modules/paraview/protocols/publish_image_delivery.py index a2ee8bf..a5ee1d0 100644 --- a/src/trame_vtk/modules/paraview/protocols/publish_image_delivery.py +++ b/src/trame_vtk/modules/paraview/protocols/publish_image_delivery.py @@ -285,10 +285,9 @@ def still_render(self, options): app = self.app if t == 0: app.InvalidateCache(view.SMProxy) - if self.decode: - still_render = app.StillRenderToString - else: - still_render = app.StillRenderToBuffer + still_render = ( + app.StillRenderToString if self.decode else app.StillRenderToBuffer + ) reply_image = still_render(view.SMProxy, t, quality) # Check that we are getting image size we have set if not wait until we diff --git a/src/trame_vtk/modules/vtk/protocols/publish_image_delivery.py b/src/trame_vtk/modules/vtk/protocols/publish_image_delivery.py index cb2b18a..f158404 100644 --- a/src/trame_vtk/modules/vtk/protocols/publish_image_delivery.py +++ b/src/trame_vtk/modules/vtk/protocols/publish_image_delivery.py @@ -192,10 +192,9 @@ def still_render(self, options): app = self.app if t == 0: app.InvalidateCache(view) - if self.decode: - still_render = app.StillRenderToString - else: - still_render = app.StillRenderToBuffer + still_render = ( + app.StillRenderToString if self.decode else app.StillRenderToBuffer + ) reply_image = still_render(view, t, quality) # Check that we are getting image size we have set if not wait until we diff --git a/src/trame_vtk/modules/vtk/serializers/cache.py b/src/trame_vtk/modules/vtk/serializers/cache.py index da3c635..8a24488 100644 --- a/src/trame_vtk/modules/vtk/serializers/cache.py +++ b/src/trame_vtk/modules/vtk/serializers/cache.py @@ -2,8 +2,7 @@ def remove_from_cache(obj_id): - if obj_id in PROP_CACHE: - del PROP_CACHE[obj_id] + PROP_CACHE.pop(obj_id, None) def get_cached_property(obj_id, prop): diff --git a/src/trame_vtk/modules/vtk/serializers/mappers.py b/src/trame_vtk/modules/vtk/serializers/mappers.py index 05f32fe..ef9783b 100644 --- a/src/trame_vtk/modules/vtk/serializers/mappers.py +++ b/src/trame_vtk/modules/vtk/serializers/mappers.py @@ -129,10 +129,11 @@ def generic_volume_mapper_serializer(parent, mapper, mapper_id, context, depth): calls.append(["setInputData", [wrap_id(data_object_id)]]) if data_object_instance: - if hasattr(mapper, "GetImageSampleDistance"): - image_sample_distance = mapper.GetImageSampleDistance() - else: - image_sample_distance = 1.0 + image_sample_distance = ( + mapper.GetImageSampleDistance() + if hasattr(mapper, "GetImageSampleDistance") + else 1.0 + ) return { "parent": reference_id(parent), "id": mapper_id,