From 5d4f7fb6dc36a05b0b02d0d301756b3b5033531d Mon Sep 17 00:00:00 2001 From: ShubhamDesai <42180509+ShubhamDesai@users.noreply.github.com> Date: Mon, 21 Oct 2024 08:32:27 -0400 Subject: [PATCH 01/55] v.hull: fix null pointer dereference issues (#4524) --- vector/v.hull/chull.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/vector/v.hull/chull.c b/vector/v.hull/chull.c index 93dfd15742e..cd8dcf52153 100644 --- a/vector/v.hull/chull.c +++ b/vector/v.hull/chull.c @@ -687,6 +687,8 @@ void CleanEdges(void) e = edges; DELETE(edges, e); } + if (!edges) + return; e = edges->next; do { if (e->delete) { @@ -711,6 +713,8 @@ void CleanFaces(void) f = faces; DELETE(faces, f); } + if (!faces) + return; f = faces->next; do { if (f->visible) { @@ -746,6 +750,8 @@ void CleanVertices(void) v = vertices; DELETE(vertices, v); } + if (!vertices) + return; v = vertices->next; do { if (v->mark && !v->onhull) { From 24b398a38159a88e2b4b41241cd578b3fee15052 Mon Sep 17 00:00:00 2001 From: Anna Petrasova Date: Mon, 21 Oct 2024 09:48:43 -0400 Subject: [PATCH 02/55] r.sim.water: add tests (#4551) --- .../testsuite/data/depth_complex.pack | Bin 0 -> 36093 bytes .../testsuite/data/depth_default.pack | Bin 0 -> 25906 bytes .../testsuite/data/discharge_complex.pack | Bin 0 -> 38375 bytes .../testsuite/data/discharge_default.pack | Bin 0 -> 38180 bytes .../r.sim.water/testsuite/test_r_sim_water.py | 201 ++++++++++++++++++ 5 files changed, 201 insertions(+) create mode 100644 raster/r.sim/r.sim.water/testsuite/data/depth_complex.pack create mode 100644 raster/r.sim/r.sim.water/testsuite/data/depth_default.pack create mode 100644 raster/r.sim/r.sim.water/testsuite/data/discharge_complex.pack create mode 100644 raster/r.sim/r.sim.water/testsuite/data/discharge_default.pack create mode 100644 raster/r.sim/r.sim.water/testsuite/test_r_sim_water.py diff --git a/raster/r.sim/r.sim.water/testsuite/data/depth_complex.pack b/raster/r.sim/r.sim.water/testsuite/data/depth_complex.pack new file mode 100644 index 0000000000000000000000000000000000000000..60f9de2be64c74c7d2c2dc1d40a8b0385bd0810a GIT binary patch literal 36093 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 Z3l=O`uwcQ01q*iw{{njY%!dF#0RWf+Lm~hG literal 0 HcmV?d00001 diff --git a/raster/r.sim/r.sim.water/testsuite/data/depth_default.pack b/raster/r.sim/r.sim.water/testsuite/data/depth_default.pack new file mode 100644 index 0000000000000000000000000000000000000000..579863ecca98c84a9fa757a0de79d72b5b76aafa GIT binary patch literal 25906 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≦u6EvM z7gF_5fOk*7jK1p*j45^KYNt2*>KfFURCVEgJhDMVzDJzxt=7_fsn;KbZX91Czy!rAO9N>*S! zWogp{9+tYj;jy@Rb}3YWau6w5ELeC`jGVMl9=l|N!jJ_N3K@aqBl4mZvMV`Mk#qB= zn%edDPU(GWe28D#{^n1A8}Oi9r#W#q46gTodb;EK)Vd@8dM<%>BBBn(@o)glA3Oj? z3DZ}5FMtYptcpbpji_V<;+1W(yz~R44+$?Yi(G=VB*)N&)}gU@Sg{Bz03LxUDHuGI zCm{!lAm2fm7TQLx1UI4tg_9CFu1Q`%a=`=0tQ6%h)P>OMhTI{4R2z`sqIye`RPMFz zC3ZHq65iqngB-anjBvo|J(v{YylcYp2V6nJAO=*0c|(dSq-6cM1QW}lahhY%W5z7( z<8^#T@#y9m^%AcJ9qwq^u-(pDNvXLP{O!XwE*TkWxT}fRz`_?t)N#mHE|i0SC>0;< zSV7o1=*K-_#o*hLT|h2mz-n0qqJil{@UkkzK^};Tjp8U6H28o~vT&cfNiGC)gFZ}+ituvkx(;J8W_OVlZ z1(Tf7heLg=mmfN7p3l4`MI<^X?pNL=B7Z5za+W0-mN!sBhAVtD!X$*P0y`{3ZN8Hi zz`22`7%^6-)qph!%5Vlai7W{M0K_+8%}$Sa0?m?hAe4Z$V^{=m5AQ{*7syvDYA_13 z1PAhfh}uQvQzt|^NI;|*JRD>Wts_bRmci9g`ULbqtxGx;(bcN#q+6MBPRX=+1k56} z;3P)n>o0Xf3)ROw9Ql$ADv}~D^ziJ}B_k*`=TyS+i!%|b_%eJ9!T=u`Xt+V}ZVcZn$Ul%j3XZzAZ(0mgB)g$YL`!^QSw zrC7aQ1=5G;AZ>Nnj*Jdt2I!!pNrsscoGBqgLId~GrcANXv>l6q6a&MC5M_gdK^-|B zzzl$ZL0(w|0U5zrNN{lyrdo1G|6`ElOsI$c6S^hK03to^UW#XJF=LC7ILxA>^YN)= zF;T+uzOWoUS~Rvx5CQiVh^lQPc}Bl9Wf3wN@+I;ZY>RP);X8Yh8n(_yk)iP7(eqBT~Ft0 zaF*o?AxCWFfHT&e7RBek;GhSCQ%|vDdlWwrCkb|8@G#W~W{I$Kgf>JhoF;;4;aJq? zOs-#p=KyqJhOjDw-3?Hgkq1>di9zlq4}bC)17ay$1vw##S8DPKV?$)e@l65>k_8YO z3h_a_?bp<)+^wW!t4K7#fag`%bvL|3!4p%oNo= z^#G7UHzF`|sOVxiN<;;8MFW)MMVB?b5v@ToW0#M?w5V2Ik5NjqFTU`E+({ds96I>S z-}!w1&I-_*9+YyeHy%>}$pg zb?gsH1|gO`F(!71dEhbX9U~x(qzQr+U@v0ajw3&d{+^w5_S;|Sy3d%1T9mA=sLB#? z(eC2OVkc&$z%VEuVnvG#@Qo0N{2f6RDr(+`9Zt3l7#=9i1p3gU(o+Jj34(-K$%ovS z$5l=k-rt#&!t>ei9^6%MVBl_L)dd3zK;XpyF;YI_2#UsAKSYAh(DNa*)jwt{#t*O& z@2s9HkE$I5ssV);z75e8nb1n@F_+S~Esomp$oyQ)+8wbSAG&+($hpxa{f*V#TH()6 zINBXwW+atJm##)OGML5G=}9=jNx(P#JZQn#>Y=!#_HT3q7^g^*c{MR-=2_D z4-7%H1$E#8;T0^39AESsHdzev^UxKYU?L_}9KqKDq^By-# zkqLpX5UXQ&MDRs<46cYRBIN|sAxH!CK?N37Y{a36d=0h&+6F_zlz-~mtGe3XmkR5U z3NS*1YTz>cHNN&xQ`<6fZR34cQ*3_EzU95DeB$}ofjeGXq`NPfSk-)tn`hM(&bfyT z^3fQ5F@QZE1#nCtUznN8LI!dJZ^*0wD{$0>q3H}q>Qy@WtIqOfl`-vSq|_8oFPbQ) z?3~bR!wpaf)?!lYN}_Jvy{@vlsun^-t6e+A*Jj=vtx?Vc4Z?IR@CT_lD)vAT^m;}H z97KRrLoj>56w8*%x_Xb;2GkqvU>fQjaO89wy5ytzs7PR<3-Zr5ZHmSeppPsKK2KVq z{gG7Z*U>-L7X#{uUACcAxPvVP4)a#c!0L>ahlvgOdwz)tP=>aeR&q9ymi!iw8uj&ZopjmNRVx znoz4+&tF%8p@o#mcNz!ppA&+Z*(gVvzWVJA|N`dBnAn;0pJ$(em z@hadSnTu97_SN}P^};rs0zh9MDuaqh{GbHrv=KaUL<3AB&p_~(7qno2OkUhmQj^v1 zqeJ0U53}nUOz^q4e)fp?@Ct|GY^U^moifobHQ0I6nHKG`cQ!Z5C;aaE798#$0S01{ z?@aDaF?a4z7Armw_zXn=?lc)4VmavAjPy~cOYqlk$8azVI zA?Nk@G2)B{*B+Od;)zp$=$0~9luKJ6nhtm%nt3fnM_U-QO&8Pqj}{Ig@7ey5-9y2^ z_xPmt;%;cBGUN6`KJkM(2#zrz9YEkk;@J1iRvx1U?jw^x2tr(Vll+tqM5CUdj+}uj zf!3hv0SZjd3U?)}2I_+$ef+I8hOJ>ka9o+BaS{1Y(J!1+0JPLA6rc@&7xKciMjar3 z1Oe4~;!J%oFsVoTqUQE{t-DwbE;;jdzlgb3A#pK11Jd3+A74c4=sBi$o8%K+8M8v~unjp$q0ufmM{+ zV=v5OJ}Q?g&*x&zs)(AvL6q5WBMPqQJoeK-<%(b7{!@2wO&TJSUE?(az z*6$f41}2;r({en8Yv~}6c;&ZJ-pbTVW6(Wemh;SiIUlULG~gx2a?CnZTiTohiHgSZ z{#N!jus*U}(KPgkIA{2svnd?=herU#K|!y-uw+j`2B4NV;7MRAFc-|OAYp?(P(FaC zpgoGvpdO1+IkdbuPFc~zURX_g0l_3b+sGqch+rIT&iS$y&TWa~bDygNf^j{Rl3w4H z4~gLxh1)kP3sb9kqFB2Mh*+?Tf0+J}#wgO<(H1E{`X@HPP(R!xTOfqYbE& z;!H#3(*1Bl8tWF-O_cTm)+X^*&}WB8G2;`w@&wNr0UMT`+$ap|q%n&DSMIQ^5rspT zgT-Sf+@-|42y-dwoV$9rB%lL0KXc|cShz^Mxj{6$*q^H>hNw;PAS5c??S2&`)f`|*_z(O!*V&CvpxG9J;hH+$d$V6jQD`%GN=I|qNMz_|@ zuCVaanG!o=4h(lMvu|k1k)D4Zqa&XvtM>^A7jr{Mix1WfguA1>x7SI*K4(^1-`EuA6kvh@**BH?vX)C8VXk^HP`z#~< zED}RM`hh4EL|17o*5%yb(265O@2(XUPNo~!bL9mtTr5Rm!ox^YiXr;IYjI^KHtwfW^tLKScI|A)reJ&-iifw zf}zWsP$-vS3MEgIaU=tfI0+BEOH`d1vOC_zG$1hdX0>}a`zPMIpLJq}`Du@x(Ruet z=9;LX8>-kit|VW-f{;s0hY!QT`cNHDbPZ>Ae$Ziy^4WI@Uz-gJnpWp7SJ2NlTOexH zwoyJjv}Y#qz3@C?6uL!OZI#00lES`d`zi&;G4keb^rRk8PFn)N;#AtCUVn%Sr=of0 z2>d~7w2xM56BR?3i|Nik?`nkQ%M3o2Fh)>_1y14q?TnazR3gE1CZY26=>Y{AizW>L)wt{ zm_m$tMYK3+akuVJXRCdEUsNn}>-wE>9cwhLy#GP)&5C))K1?;<>=IlJ03PGoM`TWS z%6;Y2M?i;zqbDk-z9=}&rX0V%k*DB5Iv!o$syu1ipQn^A6n!m<42a~;93~3B2K$L+ zCp|?a@7p}8v7*duQO((iPvO89)HzH@LZ0`aP0}tz^%iHvjaG47mMK*Fqi|_aOc~lQ zg^?5GQ+b72-pn<5ov6GyQ#racR|!d9%bXY2f*{>M14F%@63l>Pt@2;a?NRYxb1_h@ z3NVYHCj`)Y@P9-OMBD8Y9r;H(P{ zP2grA9C3bC(uiBAm{x_hfZcbx2MN1p*M+8ian4P^LdlSYPwn2qdioKdn^^L;9AwH@ z)2nAB!E7KaG9iQu^;SAuri1Qm)~PHduEz_puxMkHMEH;^>fd1dC> z2yod8#V_h=RGlpEu>!V{eTa(j)5Ny=Y4AHlCHm!hb#$0)QR8Xm`RKm4N1ezVQ2tQV zw4UqAj4$WNft_`X8?H8!t-}P)7+2yl~4#y<)7nt6Z2vKIQ#PmP=I)_cs=o@ z7-v{Sn7DV#o2-DEa6|%I#J~x-1F9g)ea?tRi{f~+4Rv(L5P=6-0&XzEv@t5?INyze z7!Fh-h{#tE04 z2j^7fbYweLAZ!(BFi7}Urx*?@P#Oll5%^K;M}k4N3)0O&8*Tx?BT106#GGV6A@Y6~ zD2lJp_)z8;1O{2*P&MKVOd4pT-s%fnM7EAgc}%DKvHX!c&6_-zF%^|X$Vd*#Gi?VR zqY#3=iR4#s2@*A;5xfE1j1MqU?njt`G#+y-L>K{cq%T;$y#1TY(v>!!7gK7O`RMs$zcWp`c4J?B|@sqfJ4Z>m&JDr%Eg{n%@wS)?yLft+9} z6&wg+gqV@rpf!y*5Uico3b(x|FKh>~D&7u%%_#&zY@kPf#BLN|S^S$kWBJ%5BH`A) zj>`0gPFnROH{u0mP(jLJXMiU)eOHec%3_o_A7LRDHd@MZ#1$Tr1*6skssSN^YT%#_ zZhm|7{T&2`*LiF_vx{rmKp-d_9tZ{sS_agY$Bbpcj1Q{Ft4*N^RN_&A0@Q&B099cF zWb33#bRCcOFC@Y&LfB~NdwN)X`N?^4%u0(Uw*uTwTrJY3eu(|KDShpS`^_$5(=6%z zI%7`7nr!5yJ2+_cfVm6JEuD(gKBmAKWu z%I7uF%4?5wo?HSQ$F+$#G=Z`x6oBbDfEAQQgey-0xS$7ug#80thyZb60>W3j&4>ZW zoVJ`W&}sa4q5z;0V6D6+12}=)29smBEw7N@5FY+PrvSM(#{7wrqZA>PzzqwG7)wZk zXCU*Jx36$8K`IEog^ZEXAo`n>UF6-E16)NO39blD0u!MxN_)keg>O)o0KTELMUJG; zCk`(=yuNthJGa9lYi7<4h^|`8Yt}ip$gf+AC4SquK_4D4?g*)aWB}SB?YlGILh{0B zu9q+$nGO@irSELsZ{zNX(o-uk5sd7rb`sD@wPF|!sO=RZ`fLVddj3k=$VToFbQIzbrX9-o5CiXt`l zC@=2YF#QMVz+ng6WP*GGegpV{l>umglK3Ck5&j&GqV~z*EC?sS8szE-Gnjmq?+al6 z17c4eG8M;n^4=!^RmtHlE=2>>kRSq5aEU&y%^GiWja7;8gD{A)N1L02^M{9Wd0bXr zHo;*6#C+cM0CswG1Dy{=iIyjODTlJ+aFT;hX@N}vo3dhdF!rE6L9T<^8U~Nn^!i;4 zuAPjjxV(_9rgMl2hy>VQW^6xQ*K9}KwljgcpZmn>N?+`QlTjjda#^iRf*Hoi8?aSG zdT>&h$ciEnj6Y!7l*tIgR+;RKh>mapQ~;3b!BbEjfl5(&MO6Tf4Aex#M}HfYJyH#_ zMUW4aa#6b>ONCH?QN)>uzJRbn)QCXv2wAq(ncXtgSs&pttvXx-6`>m-RxLTECr`oE zJHN=8F?(m)mx@nbZE;xhB>t+gZ`3FweL)abfRRWvp@EU$h3E>by;WWL^7#qB{|Gfn z9M(W_4{uh=Xjoeqlp3mJ?DXPESOmqheXHOkyeR+pjHvLWgqSm|C*BH@AD7g&8)FS< zGi^oZSi(iOqwNA+rJEr-aW`7$^S-F4H#|j6rMTV;G0L0V^F{_x9sxih5rT*8G5(#~ zthmaIvS{Y4YQJTMLlYiI(?VYEc*MEwugMMfC5*C^tXh-s3)h zKD-P+!z2jQ2TqK;M-WV}J%0yN;6Fzd04+s10w-2{_Z9ov#pJy{07!w$jKh0R5U#aP z@O#%-Avl!`izky7bw0Nik-Jxm3F}L6!EXO_3oZh}hLArYvqPohil07mU%c{+a}4|r zC}n@Ma{L$_>f~U?P(OTR-D>&}MFz_5WzlqonKY)!Y|@oI?|+)s$p0BVwv}zjU{*VUOOT zqxi(|1zG_pdsy$el3V7zf(s#_n2Z;JN@mbzjz6$4U@p-v%0z^+xB~_R)e3oDmVqEm zscPQ+BYlUht6=Y4lhi@j0K_`Z2ex82S+L#xFpu3oR2&%3cVf2sWyNX&2|ju z5XqHSkEkyjVE5n9E}A*+ky9;ryx8rvPW1G9r!(8WK-cT$Bfy0IS`*GfD3@isfXoqU z;g|?Z$Gc3z?F?c__HN;}L5J3%nEN^b6(52^G4)e*Q7JA#z1P-6)50)gqScD)&h=_! zzl->s+-!nlzonhrFaLHmW0HeGzQCa`M&-S|4I)aⅆOz+Ls8Z=_1PLz6z_KzK9Ad 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 Z95`^`z<~n?4jgV0{0l^7P67Zx0RS0g#c2Ql literal 0 HcmV?d00001 diff --git a/raster/r.sim/r.sim.water/testsuite/data/discharge_complex.pack b/raster/r.sim/r.sim.water/testsuite/data/discharge_complex.pack new file mode 100644 index 0000000000000000000000000000000000000000..01810de0cb695a428f15ec647b919853a8c4d9d1 GIT binary patch literal 38375 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

|DgMIs~v0XA8ey6gz?x@?` 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 636500 && y() > 223500, 0.3, 0.01)", + ) + cls.runModule( + "r.mapcalc", + expression=f"{cls.infil} = if (x() < 636500 && y() > 223500, 0.001, 0)", + ) + cls.runModule( + "r.unpack", + input="data/depth_complex.pack", + output=cls.reference_depth_complex, + ) + cls.runModule( + "r.unpack", + input="data/discharge_complex.pack", + output=cls.reference_discharge_complex, + ) + + @classmethod + def tearDownClass(cls): + """Clean up test environment""" + cls.runModule( + "g.remove", + flags="f", + type="raster", + name=[ + cls.elevation, + cls.dx, + cls.dy, + cls.reference_depth_default, + cls.reference_discharge_default, + cls.rain, + cls.mannings, + cls.infil, + cls.reference_depth_complex, + cls.reference_discharge_complex, + ], + ) + + def tearDown(self): + """Clean up test environment""" + self.runModule( + "g.remove", + flags="f", + type="raster", + pattern=f"{self.depth}*,{self.discharge}*", + ) + + def test_default(self): + """Test r.sim.water execution with defaults""" + # Run the r.sim.water simulation + self.assertModule( + "r.sim.water", + elevation=self.elevation, + dx=self.dx, + dy=self.dy, + depth=self.depth, + discharge=self.discharge, + random_seed=1, + ) + + # Assert that the output rasters exist + self.assertRasterExists(self.depth) + self.assertRasterExists(self.discharge) + # Assert that the output rasters are the same + self.assertRastersEqual( + self.depth, reference=self.reference_depth_default, precision="0.000001" + ) + self.assertRastersEqual( + self.discharge, + reference=self.reference_discharge_default, + precision="0.000001", + ) + + def test_complex(self): + """Test r.sim.water execution with more complex inputs""" + # Run the r.sim.water simulation + self.assertModule( + "r.sim.water", + flags="t", + elevation=self.elevation, + dx=self.dx, + dy=self.dy, + rain=self.rain, + man=self.mannings, + infil=self.infil, + depth=self.depth, + discharge=self.discharge, + niterations=15, + output_step=5, + diffusion_coeff=0.9, + hmax=0.25, + halpha=3.9, + hbeta=0.6, + random_seed=1, + ) + + # Assert that the output rasters exist + self.assertRasterExists(f"{self.depth}.05") + self.assertRasterExists(f"{self.depth}.10") + self.assertRasterExists(f"{self.depth}.15") + # Assert that the output rasters are the same + self.assertRastersEqual( + f"{self.depth}.15", + reference=self.reference_depth_complex, + precision="0.000001", + ) + self.assertRastersEqual( + f"{self.discharge}.15", + reference=self.reference_discharge_complex, + precision="0.000001", + ) + + +@unittest.skip("runs too long") +class TestRSimWaterLarge(TestCase): + """Test r.sim.water with large region""" + + # Set up the necessary raster maps for testing + elevation = "elevation" + dx = "tmp_dx" + dy = "tmp_dy" + depth = "tmp_depth" + + @classmethod + def setUpClass(cls): + """Set up region, create necessary data""" + cls.runModule("g.region", raster=cls.elevation) + cls.runModule("r.slope.aspect", elevation=cls.elevation, dx=cls.dx, dy=cls.dy) + + @classmethod + def tearDownClass(cls): + """Clean up test environment""" + cls.runModule( + "g.remove", + flags="f", + type="raster", + name=[cls.elevation, cls.dx, cls.dy, cls.depth], + ) + + def test_default(self): + """Test r.sim.water execution with defaults""" + # Run the r.sim.water simulation + self.assertModule( + "r.sim.water", + elevation=self.elevation, + dx=self.dx, + dy=self.dy, + depth=self.depth, + random_seed=1, + ) + self.assertRasterFitsUnivar( + self.depth, reference="sum=30364.327529", precision=1e-6 + ) + + +if __name__ == "__main__": + from grass.gunittest.main import test + + test() From 690534d037511a8ad386ef4d67ec83fa82a90d20 Mon Sep 17 00:00:00 2001 From: Arohan Ajit Date: Mon, 21 Oct 2024 11:09:02 -0400 Subject: [PATCH 03/55] wxGUI: Fixed E722 in modules/ (#4546) --- .flake8 | 3 +-- gui/wxpython/modules/colorrules.py | 4 ++-- gui/wxpython/modules/histogram.py | 4 ++-- gui/wxpython/modules/import_export.py | 2 +- gui/wxpython/modules/mcalc_builder.py | 6 +++--- 5 files changed, 9 insertions(+), 10 deletions(-) diff --git a/.flake8 b/.flake8 index 5d2d792b0c3..3a146f34ebd 100644 --- a/.flake8 +++ b/.flake8 @@ -24,8 +24,7 @@ per-file-ignores = doc/python/m.distance.py: E501 gui/scripts/d.wms.py: E501 gui/wxpython/image2target/g.gui.image2target.py: E501 - gui/wxpython/modules/*: F841, E722 - gui/wxpython/nviz/*: E722, F403, F405 + gui/wxpython/nviz/*: E266, E722, F403, F405 gui/wxpython/photo2image/*: F841, E722, E265 gui/wxpython/photo2image/g.gui.photo2image.py: E501, F841 gui/wxpython/psmap/*: F841, E266, E722 diff --git a/gui/wxpython/modules/colorrules.py b/gui/wxpython/modules/colorrules.py index 3dfdde8c42b..6f48006db44 100644 --- a/gui/wxpython/modules/colorrules.py +++ b/gui/wxpython/modules/colorrules.py @@ -325,7 +325,7 @@ def LoadRules(self): else: value = float(self.ruleslines[item][self.attributeType]) self.mainPanel.FindWindowById(item + 2000).SetValue(value) - except: + except Exception: continue if message: @@ -407,7 +407,7 @@ def _initLayer(self): layer = sel else: layer = self.layerTree.FindItemByData(key="type", value=self.mapType) - except: + except (AttributeError, TypeError): layer = None if layer: mapLayer = self.layerTree.GetLayerInfo(layer, key="maplayer") diff --git a/gui/wxpython/modules/histogram.py b/gui/wxpython/modules/histogram.py index c8001858dff..61d41809858 100644 --- a/gui/wxpython/modules/histogram.py +++ b/gui/wxpython/modules/histogram.py @@ -258,7 +258,7 @@ def UpdateHistDone(self): return try: id = self.imagedict[self.img] - except: + except KeyError: return # paint images to PseudoDC @@ -524,7 +524,7 @@ def OnCloseWindow(self, event): """ try: self.propwin.Close(True) - except: + except Exception: pass self.Map.Clean() self.Destroy() diff --git a/gui/wxpython/modules/import_export.py b/gui/wxpython/modules/import_export.py index c3106d0467b..6810484bfdd 100644 --- a/gui/wxpython/modules/import_export.py +++ b/gui/wxpython/modules/import_export.py @@ -527,7 +527,7 @@ def OnRun(self, event): if nBandsStr: try: nBands = int(nBandsStr.rstrip("\n")) - except: + except ValueError: pass if nBands < 0: GWarning(_("Unable to determine number of raster bands"), parent=self) diff --git a/gui/wxpython/modules/mcalc_builder.py b/gui/wxpython/modules/mcalc_builder.py index b0f2f280409..52630e55820 100644 --- a/gui/wxpython/modules/mcalc_builder.py +++ b/gui/wxpython/modules/mcalc_builder.py @@ -608,7 +608,7 @@ def _addSomething(self, what): if newmcalcstr[-1] != " ": newmcalcstr += " " position_offset += 1 - except: + except IndexError: pass newmcalcstr += what @@ -617,7 +617,7 @@ def _addSomething(self, what): try: if newmcalcstr[-1] != " " and mcalcstr[position] != " ": newmcalcstr += " " - except: + except IndexError: newmcalcstr += " " newmcalcstr += mcalcstr[position:] @@ -632,7 +632,7 @@ def _addSomething(self, what): try: if newmcalcstr[position + position_offset] == " ": position_offset += 1 - except: + except IndexError: pass self.text_mcalc.SetInsertionPoint(position + position_offset) From 15134e14f181c9c042a74486132cba52ea8d90e6 Mon Sep 17 00:00:00 2001 From: Arohan Ajit Date: Mon, 21 Oct 2024 11:10:58 -0400 Subject: [PATCH 04/55] temporal: Fixed E265/E266 in t.rast.what/ (#4550) --- .flake8 | 3 +-- temporal/t.rast.what/t.rast.what.py | 16 ---------------- 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/.flake8 b/.flake8 index 3a146f34ebd..90686370f67 100644 --- a/.flake8 +++ b/.flake8 @@ -114,8 +114,7 @@ per-file-ignores = scripts/*/*.py: E501 temporal/t.rast.to.vect/t.rast.to.vect.py: E501 temporal/t.vect.algebra/t.vect.algebra.py: E501 - # ## used (##% key: r etc) - temporal/t.rast.what/t.rast.what.py: E265, E266, E501 + temporal/t.rast.what/t.rast.what.py: E501 # Line too long (esp. module interface definitions) temporal/*/*.py: E501 diff --git a/temporal/t.rast.what/t.rast.what.py b/temporal/t.rast.what/t.rast.what.py index 4d13c6a924c..24190a6a716 100755 --- a/temporal/t.rast.what/t.rast.what.py +++ b/temporal/t.rast.what/t.rast.what.py @@ -98,22 +98,6 @@ # % description: Use stdin as input and ignore coordinates and point option # %end -## Temporary disabled the r.what flags due to test issues -##%flag -##% key: f -##% description: Show the category labels of the grid cell(s) -##%end - -##%flag -##% key: r -##% description: Output color values as RRR:GGG:BBB -##%end - -##%flag -##% key: i -##% description: Output integer category values, not cell values -##%end - # %flag # % key: v # % description: Show the category for vector points map From a4786e1272e741865c2c42371056c718e8388ea3 Mon Sep 17 00:00:00 2001 From: Arohan Ajit Date: Mon, 21 Oct 2024 15:29:22 -0400 Subject: [PATCH 05/55] wxGUI: Fixed F405 in nviz/ (#4567) --- .flake8 | 2 +- gui/wxpython/nviz/wxnviz.py | 197 ++++++++++++++++++++++++++++++++++-- 2 files changed, 188 insertions(+), 11 deletions(-) diff --git a/.flake8 b/.flake8 index 90686370f67..8211d9e03d4 100644 --- a/.flake8 +++ b/.flake8 @@ -24,7 +24,7 @@ per-file-ignores = doc/python/m.distance.py: E501 gui/scripts/d.wms.py: E501 gui/wxpython/image2target/g.gui.image2target.py: E501 - gui/wxpython/nviz/*: E266, E722, F403, F405 + gui/wxpython/nviz/*: E722 gui/wxpython/photo2image/*: F841, E722, E265 gui/wxpython/photo2image/g.gui.photo2image.py: E501, F841 gui/wxpython/psmap/*: F841, E266, E722 diff --git a/gui/wxpython/nviz/wxnviz.py b/gui/wxpython/nviz/wxnviz.py index 47cf99c079d..5a223747277 100644 --- a/gui/wxpython/nviz/wxnviz.py +++ b/gui/wxpython/nviz/wxnviz.py @@ -22,9 +22,9 @@ @author Anna Kratochvilova (Google SoC 2011) """ -import sys import locale import struct +import sys from math import sqrt try: @@ -42,26 +42,203 @@ import wx try: - from ctypes import * + from ctypes import ( + CFUNCTYPE, + UNCHECKED, + byref, + c_char_p, + c_double, + c_float, + c_int, + c_ubyte, + create_string_buffer, + pointer, + ) except KeyError as e: print("wxnviz.py: {}".format(e), file=sys.stderr) try: - from grass.lib.gis import * - from grass.lib.raster3d import * - from grass.lib.vector import * - from grass.lib.ogsf import * - from grass.lib.nviz import * - from grass.lib.raster import * + from grass.lib.gis import ( + G_find_raster2, + G_find_raster3d, + G_find_vector2, + G_free, + G_fully_qualified_name, + G_gisinit, + G_set_error_routine, + G_set_percent_routine, + G_unset_error_routine, + G_unset_percent_routine, + G_unset_window, + G_warning, + ) + from grass.lib.nviz import ( + ATT_COLOR, + ATT_EMIT, + ATT_MASK, + ATT_SHINE, + ATT_TOPO, + ATT_TRANSP, + CONST_ATT, + MAP_ATT, + MAP_OBJ_SITE, + MAP_OBJ_SURF, + MAP_OBJ_UNDEFINED, + MAP_OBJ_VECT, + MAP_OBJ_VOL, + Colors, + Nviz_change_exag, + Nviz_color_from_str, + Nviz_del_texture, + Nviz_delete_arrow, + Nviz_delete_scalebar, + Nviz_draw_all, + Nviz_draw_arrow, + Nviz_draw_cplane, + Nviz_draw_fringe, + Nviz_draw_image, + Nviz_draw_model, + Nviz_draw_quick, + Nviz_draw_scalebar, + Nviz_flythrough, + Nviz_get_bgcolor, + Nviz_get_cplane_rotation, + Nviz_get_cplane_translation, + Nviz_get_current_cplane, + Nviz_get_exag, + Nviz_get_exag_height, + Nviz_get_focus, + Nviz_get_longdim, + Nviz_get_max_texture, + Nviz_get_modelview, + Nviz_get_viewpoint_height, + Nviz_get_viewpoint_position, + Nviz_get_xyrange, + Nviz_get_zrange, + Nviz_has_focus, + Nviz_init_data, + Nviz_init_rotation, + Nviz_init_view, + Nviz_load_image, + Nviz_look_here, + Nviz_new_map_obj, + Nviz_num_cplanes, + Nviz_off_cplane, + Nviz_on_cplane, + Nviz_resize_window, + Nviz_set_2D, + Nviz_set_arrow, + Nviz_set_attr, + Nviz_set_bgcolor, + Nviz_set_cplane_here, + Nviz_set_cplane_rotation, + Nviz_set_cplane_translation, + Nviz_set_fence_color, + Nviz_set_focus, + Nviz_set_focus_map, + Nviz_set_fringe, + Nviz_set_light_ambient, + Nviz_set_light_bright, + Nviz_set_light_color, + Nviz_set_light_position, + Nviz_set_rotation, + Nviz_set_scalebar, + Nviz_set_surface_attr_default, + Nviz_set_viewpoint_height, + Nviz_set_viewpoint_persp, + Nviz_set_viewpoint_position, + Nviz_set_viewpoint_twist, + Nviz_unset_attr, + Nviz_unset_rotation, + nv_data, + ) + from grass.lib.ogsf import ( + GS_clear, + GS_delete_surface, + GS_get_cat_at_xy, + GS_get_distance_alongsurf, + GS_get_rotation_matrix, + GS_get_selected_point_on_surface, + GS_get_surf_list, + GS_get_trans, + GS_get_val_at_xy, + GS_get_viewdir, + GS_libinit, + GS_num_surfs, + GS_set_att_const, + GS_set_drawmode, + GS_set_drawres, + GS_set_rotation_matrix, + GS_set_trans, + GS_set_viewdir, + GS_set_wire_color, + GS_setall_drawmode, + GS_setall_drawres, + GS_surf_exists, + GS_write_ppm, + GS_write_tif, + GVL_delete_vol, + GVL_get_trans, + GVL_init_region, + GVL_isosurf_add, + GVL_isosurf_del, + GVL_isosurf_move_down, + GVL_isosurf_move_up, + GVL_isosurf_num_isosurfs, + GVL_isosurf_set_att_const, + GVL_isosurf_set_att_map, + GVL_isosurf_set_drawmode, + GVL_isosurf_set_drawres, + GVL_isosurf_set_flags, + GVL_isosurf_unset_att, + GVL_libinit, + GVL_set_draw_wire, + GVL_set_trans, + GVL_slice_add, + GVL_slice_del, + GVL_slice_move_down, + GVL_slice_move_up, + GVL_slice_num_slices, + GVL_slice_set_drawmode, + GVL_slice_set_drawres, + GVL_slice_set_pos, + GVL_slice_set_transp, + GVL_vol_exists, + ) + from grass.lib.raster import Rast__init_window, Rast_unset_window, Vect_read_colors + from grass.lib.raster3d import ( + GP_delete_site, + GP_get_sitename, + GP_select_surf, + GP_set_style, + GP_set_style_thematic, + GP_set_trans, + GP_set_zmode, + GP_site_exists, + GP_unselect_surf, + GP_unset_style_thematic, + ) + from grass.lib.vector import ( + GV_delete_vector, + GV_get_vectname, + GV_select_surf, + GV_set_style, + GV_set_style_thematic, + GV_set_trans, + GV_surf_is_selected, + GV_unselect_surf, + GV_unset_style_thematic, + GV_vect_exists, + ) except (ImportError, OSError, TypeError) as e: print("wxnviz.py: {}".format(e), file=sys.stderr) +import grass.script as gs from core.debug import Debug -from core.utils import autoCropImageFromFile from core.gcmd import DecodeString from core.globalvar import wxPythonPhoenix +from core.utils import autoCropImageFromFile from gui_core.wrap import Rect -import grass.script as gs log = None progress = None From 9d699d57ce29f16865e734ca8ee6c0454add9244 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Bartoletti?= Date: Mon, 21 Oct 2024 21:44:58 +0200 Subject: [PATCH 06/55] r3.showdspf: fix a typo: case 3 instead of case3 (#3867) --- raster3d/r3.showdspf/main_ogl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/raster3d/r3.showdspf/main_ogl.c b/raster3d/r3.showdspf/main_ogl.c index 55b3097e2cf..da6e90a3721 100644 --- a/raster3d/r3.showdspf/main_ogl.c +++ b/raster3d/r3.showdspf/main_ogl.c @@ -1159,7 +1159,7 @@ void do__draw(file_info *Headp, struct dspec *D_spec) fdraw_polys(D_spec); break; case 2: - case3: + case 3: gdraw_polys(D_spec); break; } From 67a160931aa01d29a896def827d5dd687e08bfd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Mon, 21 Oct 2024 17:07:17 -0400 Subject: [PATCH 07/55] style: Fix if-else-block-instead-of-if-exp (SIM108) (part 2) (#4562) * style: Fix if-else-block-instead-of-if-exp (SIM108) in scripts/ Ruff rule: https://docs.astral.sh/ruff/rules/if-else-block-instead-of-if-exp * style: Fix if-else-block-instead-of-if-exp (SIM108) in python/ Ruff rule: https://docs.astral.sh/ruff/rules/if-else-block-instead-of-if-exp * checks: Rename inner variable shadowing type to _type in python/grass/temporal/gui_support.py * style: Manual fixes for if-else-block-instead-of-if-exp (SIM108) in python/ Ruff rule: https://docs.astral.sh/ruff/rules/if-else-block-instead-of-if-exp --- python/grass/app/runtime.py | 10 +---- python/grass/benchmark/app.py | 6 +-- python/grass/benchmark/plots.py | 10 +---- python/grass/exceptions/__init__.py | 10 ++--- python/grass/gunittest/case.py | 14 ++----- python/grass/gunittest/invoker.py | 5 +-- python/grass/gunittest/multireport.py | 5 +-- python/grass/gunittest/reporters.py | 22 +++-------- python/grass/jupyter/map3d.py | 5 +-- python/grass/pydispatch/signal.py | 7 +--- .../pygrass/modules/interface/parameter.py | 5 +-- python/grass/pygrass/vector/__init__.py | 5 +-- python/grass/pygrass/vector/geometry.py | 5 +-- python/grass/pygrass/vector/table.py | 5 +-- python/grass/script/core.py | 15 ++------ python/grass/script/raster.py | 5 +-- python/grass/script/task.py | 10 +---- .../data/script_using_temporary_region.py | 10 +---- python/grass/script/utils.py | 20 ++-------- python/grass/script/vector.py | 10 +---- python/grass/temporal/abstract_map_dataset.py | 5 +-- .../temporal/abstract_space_time_dataset.py | 10 +---- .../grass/temporal/c_libraries_interface.py | 11 +----- python/grass/temporal/datetime_math.py | 15 ++------ python/grass/temporal/gui_support.py | 23 ++++++------ python/grass/temporal/list_stds.py | 5 +-- python/grass/temporal/register.py | 10 +---- python/grass/temporal/sampling.py | 17 ++------- python/grass/temporal/temporal_algebra.py | 37 ++++--------------- python/grass/temporal/temporal_granularity.py | 9 ++--- .../temporal/temporal_raster_base_algebra.py | 5 +-- python/grass/temporal/univar_statistics.py | 5 +-- scripts/d.rast.edit/d.rast.edit.py | 5 +-- scripts/d.rast.leg/d.rast.leg.py | 10 +---- scripts/db.droptable/db.droptable.py | 10 +---- scripts/db.out.ogr/db.out.ogr.py | 5 +-- scripts/db.univar/db.univar.py | 5 +-- scripts/g.extension/g.extension.py | 15 ++------ scripts/g.manual/g.manual.py | 5 +-- scripts/i.in.spotvgt/i.in.spotvgt.py | 6 +-- scripts/i.oif/i.oif.py | 10 +---- scripts/i.spectral/i.spectral.py | 5 +-- scripts/m.proj/m.proj.py | 10 +---- scripts/r.buffer.lowmem/r.buffer.lowmem.py | 5 +-- scripts/r.in.aster/r.in.aster.py | 5 +-- scripts/r.in.srtm/r.in.srtm.py | 5 +-- scripts/r.in.wms/wms_cap_parsers.py | 10 +---- scripts/r.in.wms/wms_drv.py | 5 +-- scripts/r.out.xyz/r.out.xyz.py | 5 +-- scripts/r.reclass.area/r.reclass.area.py | 5 +-- scripts/r.unpack/r.unpack.py | 5 +-- scripts/r3.in.xyz/r3.in.xyz.py | 10 +---- scripts/v.build.all/v.build.all.py | 5 +-- .../v.db.reconnect.all/v.db.reconnect.all.py | 5 +-- scripts/v.dissolve/tests/conftest.py | 5 +-- .../tests/v_dissolve_aggregate_test.py | 10 +---- .../tests/v_dissolve_layers_test.py | 5 +-- scripts/v.in.e00/v.in.e00.py | 5 +-- scripts/v.in.lines/v.in.lines.py | 7 +--- scripts/v.in.mapgen/v.in.mapgen.py | 10 +---- scripts/v.pack/v.pack.py | 5 +-- scripts/v.rast.stats/v.rast.stats.py | 15 ++------ scripts/v.report/v.report.py | 5 +-- scripts/v.unpack/v.unpack.py | 15 ++------ 64 files changed, 124 insertions(+), 445 deletions(-) diff --git a/python/grass/app/runtime.py b/python/grass/app/runtime.py index 3f3805c9dfd..27f35760b8f 100644 --- a/python/grass/app/runtime.py +++ b/python/grass/app/runtime.py @@ -79,10 +79,7 @@ def append_left_addon_paths(paths, config_dir, env): # addons (base) addon_base = env.get("GRASS_ADDON_BASE") if not addon_base: - if MACOS: - name = "Addons" - else: - name = "addons" + name = "addons" if not MACOS else "Addons" addon_base = os.path.join(config_dir, name) env["GRASS_ADDON_BASE"] = addon_base @@ -174,10 +171,7 @@ def set_python_path_variable(install_path, env): """Set PYTHONPATH to find GRASS Python package in subprocesses""" path = env.get("PYTHONPATH") etcpy = os.path.join(install_path, "etc", "python") - if path: - path = etcpy + os.pathsep + path - else: - path = etcpy + path = etcpy + os.pathsep + path if path else etcpy env["PYTHONPATH"] = path diff --git a/python/grass/benchmark/app.py b/python/grass/benchmark/app.py index 09cdf3f9481..835fc0d544b 100644 --- a/python/grass/benchmark/app.py +++ b/python/grass/benchmark/app.py @@ -47,11 +47,7 @@ def join_results_cli(args): def select_only(result): return result.label == args.only - if args.only: - select_function = select_only - else: - select_function = None - + select_function = select_only if args.only else None results = join_results_from_files( source_filenames=args.results, prefixes=args.prefixes, diff --git a/python/grass/benchmark/plots.py b/python/grass/benchmark/plots.py index 9483fda9116..24afcbcfbae 100644 --- a/python/grass/benchmark/plots.py +++ b/python/grass/benchmark/plots.py @@ -25,10 +25,7 @@ def get_pyplot(to_file): """ import matplotlib as mpl # pylint: disable=import-outside-toplevel - if to_file: - backend = "agg" - else: - backend = None + backend = "agg" if to_file else None if backend: mpl.use(backend) @@ -124,10 +121,7 @@ def num_cells_plot(results, filename=None, title=None, show_resolution=False): x_ticks = set() for result in results: - if show_resolution: - x = result.resolutions - else: - x = result.cells + x = result.resolutions if show_resolution else result.cells x_ticks.update(x) plt.plot(x, result.times, label=result.label) if hasattr(result, "all_times"): diff --git a/python/grass/exceptions/__init__.py b/python/grass/exceptions/__init__.py index b22d0a45c1d..deec48ffd96 100644 --- a/python/grass/exceptions/__init__.py +++ b/python/grass/exceptions/__init__.py @@ -71,13 +71,9 @@ def __init__(self, module, code, returncode, errors=None): """ # CalledProcessError has undocumented constructor super().__init__(returncode, module) - if not module or module in code: - # No need to include module name if it is directly in code - # of if it is not set. - executed = code - else: - # Make sure module name is there if provided and not in code. - executed = f"{module} {code}" + # No need to include module name if it is directly in code of if it is not set. + # Otherwise, make sure module name is there if provided and not in code. + executed = code if not module or module in code else f"{module} {code}" if errors: # We assume actual errors, e.g., captured stderr. err = _("See the following errors:\n{errors}").format(errors=errors) diff --git a/python/grass/gunittest/case.py b/python/grass/gunittest/case.py index 1277ee542b5..4e0ee3ab24d 100644 --- a/python/grass/gunittest/case.py +++ b/python/grass/gunittest/case.py @@ -691,10 +691,7 @@ def assertFileMd5(self, filename, md5, text=False, msg=None): at the end of file (as for example, Git or PEP8 requires). """ self.assertFileExists(filename, msg=msg) - if text: - actual = text_file_md5(filename) - else: - actual = file_md5(filename) + actual = text_file_md5(filename) if text else file_md5(filename) if actual != md5: standardMsg = ( "File <{name}> does not have the right MD5 sum.\n" @@ -1339,12 +1336,9 @@ def runModule(cls, module, expecting_stdout=False, **kwargs): errors = " The errors are:\n" + module.outputs.stderr else: errors = " There were no error messages." - if module.outputs.stdout: - # this is not appropriate for translation but we don't want - # and don't need testing to be translated - got = "only whitespace." - else: - got = "nothing." + # This is not appropriate for translation but we don't want + # and don't need testing to be translated + got = "only whitespace." if module.outputs.stdout else "nothing." raise RuntimeError( "Module call " + module.get_python() diff --git a/python/grass/gunittest/invoker.py b/python/grass/gunittest/invoker.py index 2fe9c898b8b..29b62830e25 100644 --- a/python/grass/gunittest/invoker.py +++ b/python/grass/gunittest/invoker.py @@ -54,10 +54,7 @@ def update_keyval_file(filename, module, returncode): keyval["name"] = module.name keyval["tested_dir"] = module.tested_dir if "status" not in keyval.keys(): - if returncode is None or returncode: - status = "failed" - else: - status = "passed" + status = "failed" if returncode is None or returncode else "passed" keyval["status"] = status keyval["returncode"] = returncode keyval["test_file_authors"] = test_file_authors diff --git a/python/grass/gunittest/multireport.py b/python/grass/gunittest/multireport.py index c5f36a6e0db..5a0350f1786 100644 --- a/python/grass/gunittest/multireport.py +++ b/python/grass/gunittest/multireport.py @@ -119,10 +119,7 @@ def median(values): smedian = median(successes) smax = max(successes) - if successes[-1] < smedian: - color = "r" - else: - color = "g" + color = "r" if successes[-1] < smedian else "g" # another possibility is to color according to the gradient, ideally # on the whole curve but that's much more complicated diff --git a/python/grass/gunittest/reporters.py b/python/grass/gunittest/reporters.py index 09f371dfffc..57b0a8fc643 100644 --- a/python/grass/gunittest/reporters.py +++ b/python/grass/gunittest/reporters.py @@ -234,11 +234,8 @@ def get_svn_path_authors(path, from_date=None): :returns: a set of authors """ - if from_date is None: - # this is the SVN default for local copies - revision_range = "BASE:1" - else: - revision_range = "BASE:{%s}" % from_date + # "BASE:1" is the SVN default for local copies + revision_range = "BASE:1" if from_date is None else "BASE:{%s}" % from_date try: # TODO: allow also usage of --limit p = subprocess.Popen( @@ -487,10 +484,7 @@ def tail(filename, n): def returncode_to_html_text(returncode, timed_out=None): if returncode: - if timed_out is not None: - extra = f" (timeout >{timed_out}s)" - else: - extra = "" + extra = f" (timeout >{timed_out}s)" if timed_out is not None else "" return f'FAILED{extra}' # alternatives: SUCCEEDED, passed, OK return 'succeeded' @@ -857,10 +851,7 @@ def finish(self): # this shoul be moved to some additional meta passed in constructor svn_info = get_svn_info() - if not svn_info: - svn_revision = "" - else: - svn_revision = svn_info["revision"] + svn_revision = "" if not svn_info else svn_info["revision"] summary = {} summary["files_total"] = self.test_files @@ -1025,10 +1016,7 @@ def end_file_test( num_failed = test_summary.get("failures", 0) num_failed += test_summary.get("errors", 0) if num_failed: - if num_failed > 1: - text = " ({f} tests failed)" - else: - text = " ({f} test failed)" + text = " ({f} tests failed)" if num_failed > 1 else " ({f} test failed)" self._stream.write(text.format(f=num_failed)) self._stream.write("\n") # TODO: here we lost the possibility to include also file name diff --git a/python/grass/jupyter/map3d.py b/python/grass/jupyter/map3d.py index dd373f315a7..99253251406 100644 --- a/python/grass/jupyter/map3d.py +++ b/python/grass/jupyter/map3d.py @@ -210,10 +210,7 @@ def render(self, **kwargs): with Display( size=(self._width, self._height), **additional_kwargs ) as display: - if has_env_copy: - env = display.env() - else: - env = os.environ.copy() + env = display.env() if has_env_copy else os.environ.copy() self._region_manager.set_region_from_command(env=env, **kwargs) self.overlay.region_manager.set_region_from_env(env) gs.run_command(module, env=env, **kwargs) diff --git a/python/grass/pydispatch/signal.py b/python/grass/pydispatch/signal.py index 1e968e99dca..51808e01ee3 100644 --- a/python/grass/pydispatch/signal.py +++ b/python/grass/pydispatch/signal.py @@ -7,7 +7,7 @@ from grass.pydispatch import dispatcher -def _islambda(function): +def _islambda(function) -> bool: """ Tests if object is a lambda function. @@ -146,10 +146,7 @@ class connects to the signal:: will print """ if weak is None: - if _islambda(handler): - weak = False - else: - weak = True + weak = not _islambda(handler) dispatcher.connect(receiver=handler, signal=self, weak=weak) def disconnect(self, handler, weak=True): diff --git a/python/grass/pygrass/modules/interface/parameter.py b/python/grass/pygrass/modules/interface/parameter.py index 3b58ea2b372..1ec5466bc74 100644 --- a/python/grass/pygrass/modules/interface/parameter.py +++ b/python/grass/pygrass/modules/interface/parameter.py @@ -337,10 +337,7 @@ def __doc__(self): .. """ if hasattr(self, "values"): - if self.isrange: - vals = self.isrange - else: - vals = ", ".join([repr(val) for val in self.values]) + vals = self.isrange or ", ".join([repr(val) for val in self.values]) else: vals = False if self.keydescvalues: diff --git a/python/grass/pygrass/vector/__init__.py b/python/grass/pygrass/vector/__init__.py index 461050807b0..6723b2e44b3 100644 --- a/python/grass/pygrass/vector/__init__.py +++ b/python/grass/pygrass/vector/__init__.py @@ -859,10 +859,7 @@ def features_to_wkb_list(self, bbox=None, feature_type="point", field=1): ok = libvect.Vect_cat_get( ctypes.byref(line_c), field, ctypes.byref(cat) ) - if ok < 1: - pcat = None - else: - pcat = cat.value + pcat = None if ok < 1 else cat.value wkb_list.append((f_id, pcat, ctypes.string_at(barray, size.value))) libgis.G_free(barray) diff --git a/python/grass/pygrass/vector/geometry.py b/python/grass/pygrass/vector/geometry.py index 10ecb1d2d13..b734161d1ea 100644 --- a/python/grass/pygrass/vector/geometry.py +++ b/python/grass/pygrass/vector/geometry.py @@ -810,10 +810,7 @@ def extend(self, line, forward=True): """ # set direction - if forward: - direction = libvect.GV_FORWARD - else: - direction = libvect.GV_BACKWARD + direction = libvect.GV_FORWARD if forward else libvect.GV_BACKWARD # check if is a Line object if isinstance(line, Line): c_points = line.c_points diff --git a/python/grass/pygrass/vector/table.py b/python/grass/pygrass/vector/table.py index 9c8d0c3f9a2..5442d2f1e51 100644 --- a/python/grass/pygrass/vector/table.py +++ b/python/grass/pygrass/vector/table.py @@ -1261,10 +1261,7 @@ def create(self, cols, name=None, overwrite=False, cursor=None): """ cur = cursor or self.conn.cursor() coldef = ",\n".join(["%s %s" % col for col in cols]) - if name: - newname = name - else: - newname = self.name + newname = name or self.name try: cur.execute(sql.CREATE_TAB.format(tname=newname, coldef=coldef)) self.conn.commit() diff --git a/python/grass/script/core.py b/python/grass/script/core.py index 4f70f525133..0b51e7fdbe9 100644 --- a/python/grass/script/core.py +++ b/python/grass/script/core.py @@ -334,10 +334,7 @@ def get_module_and_code(args, kwargs): args = make_command(*args, **kwargs) # Since we are in error handler, let's be extra cautious # about an empty command. - if args: - module = args[0] - else: - module = None + module = args[0] if args else None code = " ".join(args) return module, code @@ -1699,10 +1696,7 @@ def mapsets(search_path=False, env=None): :return: list of mapsets """ - if search_path: - flags = "p" - else: - flags = "l" + flags = "p" if search_path else "l" mapsets = read_command("g.mapsets", flags=flags, sep="newline", quiet=True, env=env) if not mapsets: fatal(_("Unable to list mapsets")) @@ -2033,10 +2027,7 @@ def create_environment(gisdbase, location, mapset, env=None): f.write("GISDBASE: {g}\n".format(g=gisdbase)) f.write("LOCATION_NAME: {l}\n".format(l=location)) f.write("GUI: text\n") - if env: - env = env.copy() - else: - env = os.environ.copy() + env = env.copy() if env else os.environ.copy() env["GISRC"] = f.name # remove mapset-specific env vars env = sanitize_mapset_environment(env) diff --git a/python/grass/script/raster.py b/python/grass/script/raster.py index 54c1219dbaf..d82780d7c5c 100644 --- a/python/grass/script/raster.py +++ b/python/grass/script/raster.py @@ -218,10 +218,7 @@ def raster_what(map, coord, env=None, localized=False): query :param env: """ - if isinstance(map, (bytes, str)): - map_list = [map] - else: - map_list = map + map_list = [map] if isinstance(map, (bytes, str)) else map coord_list = [] if isinstance(coord, tuple): diff --git a/python/grass/script/task.py b/python/grass/script/task.py index cf398c59214..9867b3d8c49 100644 --- a/python/grass/script/task.py +++ b/python/grass/script/task.py @@ -345,14 +345,8 @@ def _process_params(self): for ki in node_key_desc.findall("item"): key_desc.append(ki.text) - if p.get("multiple", "no") == "yes": - multiple = True - else: - multiple = False - if p.get("required", "no") == "yes": - required = True - else: - required = False + multiple = p.get("multiple", "no") == "yes" + required = p.get("required", "no") == "yes" if ( self.task.blackList["enabled"] diff --git a/python/grass/script/testsuite/data/script_using_temporary_region.py b/python/grass/script/testsuite/data/script_using_temporary_region.py index 5bb5a4cda26..839bf3d0a72 100755 --- a/python/grass/script/testsuite/data/script_using_temporary_region.py +++ b/python/grass/script/testsuite/data/script_using_temporary_region.py @@ -65,15 +65,9 @@ def main(): argument = sys.argv[1] sizes = argument.split(",", 1) size = sizes[0] - if len(sizes) > 1: - remaining = sizes[1] - else: - remaining = None + remaining = sizes[1] if len(sizes) > 1 else None nesting = int(sys.argv[2]) - if len(sys.argv) == 4: - map_name = sys.argv[3] - else: - map_name = None + map_name = sys.argv[3] if len(sys.argv) == 4 else None call_use_temp_region( script=this_file, size=size, diff --git a/python/grass/script/utils.py b/python/grass/script/utils.py index 448289b57aa..25eb70190c5 100644 --- a/python/grass/script/utils.py +++ b/python/grass/script/utils.py @@ -190,10 +190,7 @@ def decode(bytes_, encoding=None): if isinstance(bytes_, str): return bytes_ if isinstance(bytes_, bytes): - if encoding is None: - enc = _get_encoding() - else: - enc = encoding + enc = _get_encoding() if encoding is None else encoding return bytes_.decode(enc) # only text should be used raise TypeError("can only accept types str and bytes") @@ -221,10 +218,7 @@ def encode(string, encoding=None): if isinstance(string, bytes): return string if isinstance(string, str): - if encoding is None: - enc = _get_encoding() - else: - enc = encoding + enc = _get_encoding() if encoding is None else encoding return string.encode(enc) # if something else than text raise TypeError("can only accept types str and bytes") @@ -276,10 +270,7 @@ def parse_key_val(s, sep="=", dflt=None, val_type=None, vsep=None): for line in lines: kv = line.split(sep, 1) k = decode(kv[0].strip()) - if len(kv) > 1: - v = decode(kv[1].strip()) - else: - v = dflt + v = decode(kv[1].strip()) if len(kv) > 1 else dflt if val_type: result[k] = val_type(v) @@ -353,10 +344,7 @@ def convert(text): return int(text) if text.isdigit() else text.lower() def alphanum_key(actual_key): - if key: - sort_key = key(actual_key) - else: - sort_key = actual_key + sort_key = key(actual_key) if key else actual_key return [convert(c) for c in re.split("([0-9]+)", sort_key)] items.sort(key=alphanum_key) diff --git a/python/grass/script/vector.py b/python/grass/script/vector.py index ca3caf18471..2d484f7d590 100644 --- a/python/grass/script/vector.py +++ b/python/grass/script/vector.py @@ -129,10 +129,7 @@ def vector_columns(map, layer=None, getDict=True, env=None, **kwargs): s = read_command( "v.info", flags="c", map=map, layer=layer, quiet=True, env=env, **kwargs ) - if getDict: - result = {} - else: - result = [] + result = {} if getDict else [] i = 0 for line in s.splitlines(): ctype, cname = line.split("|") @@ -377,10 +374,7 @@ def vector_what( if "LC_ALL" in env: env["LC_ALL"] = "C" - if isinstance(map, (bytes, str)): - map_list = [map] - else: - map_list = map + map_list = [map] if isinstance(map, (bytes, str)) else map if layer: if isinstance(layer, (tuple, list)): diff --git a/python/grass/temporal/abstract_map_dataset.py b/python/grass/temporal/abstract_map_dataset.py index ecbf761d139..f6bec2bfef3 100644 --- a/python/grass/temporal/abstract_map_dataset.py +++ b/python/grass/temporal/abstract_map_dataset.py @@ -820,10 +820,7 @@ def temporal_buffer(self, increment, update=False, dbif=None): else: start, end, unit = self.get_relative_time() new_start = start - increment - if end is None: - new_end = start + increment - else: - new_end = end + increment + new_end = start + increment if end is None else end + increment if update: self.update_relative_time(new_start, new_end, unit, dbif=dbif) diff --git a/python/grass/temporal/abstract_space_time_dataset.py b/python/grass/temporal/abstract_space_time_dataset.py index d17baaab6ae..8140a2da261 100644 --- a/python/grass/temporal/abstract_space_time_dataset.py +++ b/python/grass/temporal/abstract_space_time_dataset.py @@ -779,10 +779,7 @@ def sample_by_dataset(self, stds, method=None, spatial=False, dbif=None): # print(relations) tb = SpatioTemporalTopologyBuilder() - if spatial: - spatial = "2D" - else: - spatial = None + spatial = "2D" if spatial else None mapsA = self.get_registered_maps_as_objects(dbif=dbif) mapsB = stds.get_registered_maps_as_objects_with_gaps(dbif=dbif) @@ -1429,10 +1426,7 @@ def get_registered_maps_as_objects_with_gaps( start1, end1 = maps[i].get_temporal_extent_as_tuple() start2, end2 = maps[i + 1].get_temporal_extent_as_tuple() end = start2 - if end1 is not None: - start = end1 - else: - start = start1 + start = end1 if end1 is not None else start1 map = self.get_new_map_instance(None) diff --git a/python/grass/temporal/c_libraries_interface.py b/python/grass/temporal/c_libraries_interface.py index 85a19a3ec6e..0d24fc0f732 100644 --- a/python/grass/temporal/c_libraries_interface.py +++ b/python/grass/temporal/c_libraries_interface.py @@ -256,11 +256,7 @@ def _get_driver_name(lock, conn, data): :returns: Name of the driver or None if no temporal database present """ mapset = data[1] - if not mapset: - mapset = libgis.G_mapset() - else: - mapset = encode(mapset) - + mapset = libgis.G_mapset() if not mapset else encode(mapset) drstring = libtgis.tgis_get_mapset_driver_name(mapset) conn.send(decode(drstring.data)) @@ -280,10 +276,7 @@ def _get_database_name(lock, conn, data): dbstring = None try: mapset = data[1] - if not mapset: - mapset = libgis.G_mapset() - else: - mapset = encode(mapset) + mapset = libgis.G_mapset() if not mapset else encode(mapset) dbstring = libtgis.tgis_get_mapset_database_name(mapset) dbstring = dbstring.data diff --git a/python/grass/temporal/datetime_math.py b/python/grass/temporal/datetime_math.py index 1031582fe23..b986637162a 100644 --- a/python/grass/temporal/datetime_math.py +++ b/python/grass/temporal/datetime_math.py @@ -694,10 +694,7 @@ def compute_datetime_delta(start, end): else: d += 24 * 60 * day_diff elif d == 0: - if comp["hour"]: - d = 60 * comp["hour"] - else: - d = 24 * 60 * day_diff + d = 60 * comp["hour"] if comp["hour"] else 24 * 60 * day_diff comp["minute"] = d @@ -914,10 +911,7 @@ def datetime_to_grass_datetime_string(dt): # Check for time zone info in the datetime object if dt.tzinfo is not None: tz = dt.tzinfo.utcoffset(0) - if tz.seconds > 86400 / 2: - tz = (tz.seconds - 86400) / 60 - else: - tz = tz.seconds / 60 + tz = (tz.seconds - 86400) / 60 if tz.seconds > 86400 / 2 else tz.seconds / 60 string = "%.2i %s %.2i %.2i:%.2i:%.2i %+.4i" % ( dt.day, @@ -999,10 +993,7 @@ def create_numeric_suffix(base, count, zeros): if len(spli) == 2: suff = spli[1] if suff.isdigit(): - if int(suff[0]) == 0: - zero = suff - else: - zero = "0{nu}".format(nu=suff) + zero = suff if int(suff[0]) == 0 else "0{nu}".format(nu=suff) else: zero = "05" else: diff --git a/python/grass/temporal/gui_support.py b/python/grass/temporal/gui_support.py index 41f22edc6b7..d2cbca13d68 100644 --- a/python/grass/temporal/gui_support.py +++ b/python/grass/temporal/gui_support.py @@ -37,16 +37,14 @@ def tlist_grouped(type, group_type=False, dbif=None): :return: directory of mapsets/elements """ result = {} + _type = type dbif, connection_state_changed = init_dbif(dbif) mapset = None - if type == "stds": - types = ["strds", "str3ds", "stvds"] - else: - types = [type] - for type in types: + types = ["strds", "str3ds", "stvds"] if _type == "stds" else [_type] + for _type in types: try: - tlist_result = tlist(type=type, dbif=dbif) + tlist_result = tlist(type=_type, dbif=dbif) except gs.ScriptError as e: gs.warning(e) continue @@ -65,10 +63,10 @@ def tlist_grouped(type, group_type=False, dbif=None): result[mapset] = [] if group_type: - if type in result[mapset]: - result[mapset][type].append(name) + if _type in result[mapset]: + result[mapset][_type].append(name) else: - result[mapset][type] = [ + result[mapset][_type] = [ name, ] else: @@ -90,19 +88,20 @@ def tlist(type, dbif=None): :return: a list of space time dataset ids """ + _type = type id = None - sp = dataset_factory(type, id) + sp = dataset_factory(_type, id) dbif, connection_state_changed = init_dbif(dbif) mapsets = get_available_temporal_mapsets() output = [] temporal_type = ["absolute", "relative"] - for type in temporal_type: + for _type in temporal_type: # For each available mapset for mapset in mapsets.keys(): # Table name - if type == "absolute": + if _type == "absolute": table = sp.get_type() + "_view_abs_time" else: table = sp.get_type() + "_view_rel_time" diff --git a/python/grass/temporal/list_stds.py b/python/grass/temporal/list_stds.py index 9f6b6867766..22a2708123d 100644 --- a/python/grass/temporal/list_stds.py +++ b/python/grass/temporal/list_stds.py @@ -325,10 +325,7 @@ def _get_get_registered_maps_as_objects_delta_gran( msgr.fatal(_("Empty entry in map list, this should not happen")) start, end = map_object.get_temporal_extent_as_tuple() - if end: - delta = end - start - else: - delta = None + delta = end - start if end else None delta_first = start - first_time if map_object.is_time_absolute(): diff --git a/python/grass/temporal/register.py b/python/grass/temporal/register.py index 92be36a3547..d8705765d02 100644 --- a/python/grass/temporal/register.py +++ b/python/grass/temporal/register.py @@ -158,10 +158,7 @@ def register_maps_in_space_time_dataset( # Read the map list from file if file: - if hasattr(file, "readline"): - fd = file - else: - fd = open(file) + fd = file if hasattr(file, "readline") else open(file) line = True while True: @@ -639,10 +636,7 @@ def register_map_object_list( string = f"{id}|{start}|{end}\n" register_file.write(string) - if output_stds: - output_stds_id = output_stds.get_id() - else: - output_stds_id = None + output_stds_id = output_stds.get_id() if output_stds else None register_maps_in_space_time_dataset( type, output_stds_id, unit=unit, file=filename, dbif=dbif diff --git a/python/grass/temporal/sampling.py b/python/grass/temporal/sampling.py index 425ca484da5..5209ce6a80c 100644 --- a/python/grass/temporal/sampling.py +++ b/python/grass/temporal/sampling.py @@ -82,19 +82,11 @@ def sample_stds_by_stds_topology( sts = [] for input in inputs: - if input.find("@") >= 0: - id = input - else: - id = input + "@" + mapset - + id = input if input.find("@") >= 0 else input + "@" + mapset st = dataset_factory(intype, id) sts.append(st) - if sampler.find("@") >= 0: - sid = sampler - else: - sid = sampler + "@" + mapset - + sid = sampler if sampler.find("@") >= 0 else sampler + "@" + mapset sst = dataset_factory(sampletype, sid) dbif = SQLDatabaseInterfaceConnection() @@ -156,10 +148,7 @@ def sample_stds_by_stds_topology( map = entry["granule"] start, end = map.get_temporal_extent_as_tuple() - if end: - delta = end - start - else: - delta = None + delta = end - start if end else None delta_first = start - first_time if map.is_time_absolute(): diff --git a/python/grass/temporal/temporal_algebra.py b/python/grass/temporal/temporal_algebra.py index e4717eb3326..2429b61e35e 100644 --- a/python/grass/temporal/temporal_algebra.py +++ b/python/grass/temporal/temporal_algebra.py @@ -992,10 +992,7 @@ def generate_map_name(self): same object for map name generation in multiple threads. """ self.count += 1 - if self.pid is not None: - pid = self.pid - else: - pid = os.getpid() + pid = self.pid if self.pid is not None else os.getpid() name = "tmp_map_name_%i_%i" % (pid, self.count) self.names[name] = name return name @@ -1234,10 +1231,7 @@ def check_stds(self, input, clear=False, stds_type=None, check_type=True): """ if isinstance(input, str): # Check for mapset in given stds input. - if input.find("@") >= 0: - id_input = input - else: - id_input = input + "@" + self.mapset + id_input = input if input.find("@") >= 0 else input + "@" + self.mapset # Create empty spacetime dataset. if stds_type: stds = dataset_factory(stds_type, id_input) @@ -1634,7 +1628,7 @@ def build_spatio_temporal_topology_list( def assign_bool_value( self, map_i, temporal_topo_list=["EQUAL"], spatial_topo_list=[] - ): + ) -> bool: """Function to assign boolean map value based on the map_values from the compared map list by topological relationships. @@ -1668,10 +1662,7 @@ def assign_bool_value( str(relationmap.get_temporal_extent_as_tuple()) + str(boolean), ) - if all(condition_value_list): - resultbool = True - else: - resultbool = False + resultbool = bool(all(condition_value_list)) map_i.condition_value = [resultbool] return resultbool @@ -2296,20 +2287,14 @@ def recurse_compare(conditionlist): ele_index = conditionlist.index(ele) right = conditionlist.pop(ele_index) left = conditionlist.pop(ele_index - 2) - if any([left, right]): - result = True - else: - result = False + result = bool(any([left, right])) conditionlist[ele_index - 2] = result recurse_compare(conditionlist) if ele == "&&": ele_index = conditionlist.index(ele) right = conditionlist.pop(ele_index) left = conditionlist.pop(ele_index - 2) - if all([left, right]): - result = True - else: - result = False + result = bool(all([left, right])) conditionlist[ele_index - 2] = result recurse_compare(conditionlist) @@ -2643,10 +2628,7 @@ def p_expr_tmap_function(self, t): input = t[3] if not isinstance(input, list): # Check for mapset in given stds input. - if input.find("@") >= 0: - id_input = input - else: - id_input = input + "@" + self.mapset + id_input = input if input.find("@") >= 0 else input + "@" + self.mapset # Create empty map dataset. map_i = dataset_factory(self.maptype, id_input) # Check for occurrence of space time dataset. @@ -3079,10 +3061,7 @@ def p_expr_t_select_operator(self, t): # Evaluate temporal operator. operators = self.eval_toperator(t[2], optype="select") # Check for negative selection. - if operators[2] == "!:": - negation = True - else: - negation = False + negation = operators[2] == "!:" # Perform selection. selectlist = self.perform_temporal_selection( maplistA, maplistB, topolist=operators[0], inverse=negation diff --git a/python/grass/temporal/temporal_granularity.py b/python/grass/temporal/temporal_granularity.py index b4043054520..173e4e715ea 100644 --- a/python/grass/temporal/temporal_granularity.py +++ b/python/grass/temporal/temporal_granularity.py @@ -494,7 +494,7 @@ def compute_absolute_time_granularity(maps): # Keep the temporal extent to compare to the following/next map previous_start, previous_end = start, end - # Create a list with a single time unit only + # Create a set with a single time unit only dlist = set() assigned_time_unit = None time_unit_multipliers = { @@ -529,11 +529,8 @@ def compute_absolute_time_granularity(maps): if not dlist: return None - if len(dlist) > 1: - # Find greatest common divisor - granularity = gcd_list(dlist) - else: - granularity = dlist.pop() + # Find greatest common divisor to get a single time unit + granularity = gcd_list(dlist) if len(dlist) > 1 else dlist.pop() if granularity is None: return None diff --git a/python/grass/temporal/temporal_raster_base_algebra.py b/python/grass/temporal/temporal_raster_base_algebra.py index 8ff156cbed5..cb2122f4a37 100644 --- a/python/grass/temporal/temporal_raster_base_algebra.py +++ b/python/grass/temporal/temporal_raster_base_algebra.py @@ -960,10 +960,7 @@ def p_expr_spmap_function(self, t): input = t[3] if not isinstance(input, list): # Check for mapset in given stds input. - if input.find("@") >= 0: - id_input = input - else: - id_input = input + "@" + self.mapset + id_input = input if input.find("@") >= 0 else input + "@" + self.mapset # Create empty map dataset. map_i = dataset_factory(self.maptype, id_input) # Check for occurrence of space time dataset. diff --git a/python/grass/temporal/univar_statistics.py b/python/grass/temporal/univar_statistics.py index dd334e7e9f1..b6a9c1ac508 100755 --- a/python/grass/temporal/univar_statistics.py +++ b/python/grass/temporal/univar_statistics.py @@ -304,10 +304,7 @@ def print_vector_dataset_univar_statistics( mapset = get_current_mapset() - if input.find("@") >= 0: - id = input - else: - id = input + "@" + mapset + id = input if input.find("@") >= 0 else input + "@" + mapset sp = dataset_factory("stvds", id) diff --git a/scripts/d.rast.edit/d.rast.edit.py b/scripts/d.rast.edit/d.rast.edit.py index ea6cc1e46bf..3464941e825 100755 --- a/scripts/d.rast.edit/d.rast.edit.py +++ b/scripts/d.rast.edit/d.rast.edit.py @@ -295,10 +295,7 @@ def paint_cell(self, dc, r, c): px, py = -dy, dx r, g, b, a = wx.Colour(fill).Get() - if r + g + b > 384: - line = "black" - else: - line = "white" + line = "black" if r + g + b > 384 else "white" dc.SetPen(wx.Pen(line)) dc.DrawLine(x0, y0, x1, y1) diff --git a/scripts/d.rast.leg/d.rast.leg.py b/scripts/d.rast.leg/d.rast.leg.py index 85cb423f9e9..74576113577 100755 --- a/scripts/d.rast.leg/d.rast.leg.py +++ b/scripts/d.rast.leg/d.rast.leg.py @@ -132,16 +132,10 @@ def main(): if not nlines: nlines = None - if rast: - lmap = rast - else: - lmap = map + lmap = rast or map kv = gs.raster_info(map=lmap) - if kv["datatype"] == "CELL": - leg_at = None - else: - leg_at = "%f,95,5,10" % VSpacing + leg_at = None if kv["datatype"] == "CELL" else "%f,95,5,10" % VSpacing # checking for histogram causes more problems than it solves # histfiledir = grass.find_file(lmap, 'cell_misc')['file'] diff --git a/scripts/db.droptable/db.droptable.py b/scripts/db.droptable/db.droptable.py index 571638748cf..39408221acc 100755 --- a/scripts/db.droptable/db.droptable.py +++ b/scripts/db.droptable/db.droptable.py @@ -56,14 +56,8 @@ def main(): gs.run_command("db.connect", flags="c", quiet=True) kv = gs.db_connection() - if options["database"]: - database = options["database"] - else: - database = kv["database"] - if options["driver"]: - driver = options["driver"] - else: - driver = kv["driver"] + database = options["database"] or kv["database"] + driver = options["driver"] or kv["driver"] # schema needed for PG? if force: diff --git a/scripts/db.out.ogr/db.out.ogr.py b/scripts/db.out.ogr/db.out.ogr.py index 4a840755b20..4fdfed23648 100755 --- a/scripts/db.out.ogr/db.out.ogr.py +++ b/scripts/db.out.ogr/db.out.ogr.py @@ -72,10 +72,7 @@ def main(): if format.lower() == "dbf": format = "ESRI_Shapefile" - if format.lower() == "csv": - olayer = basename(output, "csv") - else: - olayer = None + olayer = basename(output, "csv") if format.lower() == "csv" else None # is there a simpler way of testing for --overwrite? dbffile = input + ".dbf" diff --git a/scripts/db.univar/db.univar.py b/scripts/db.univar/db.univar.py index 97dfbdb7dbe..4654e3011a0 100755 --- a/scripts/db.univar/db.univar.py +++ b/scripts/db.univar/db.univar.py @@ -118,10 +118,7 @@ def main(): perc = [float(p) for p in perc.split(",")] if not output_format: - if shellstyle: - output_format = "shell" - else: - output_format = "plain" + output_format = "shell" if shellstyle else "plain" elif shellstyle: # This can be a message or warning in future versions. # In version 9, -g may be removed. diff --git a/scripts/g.extension/g.extension.py b/scripts/g.extension/g.extension.py index 194f498d49c..f14a742ca06 100644 --- a/scripts/g.extension/g.extension.py +++ b/scripts/g.extension/g.extension.py @@ -1608,10 +1608,7 @@ def install_extension_win(name): source, url = resolve_source_code(url="{0}/{1}.zip".format(base_url, name)) # to hide non-error messages from subprocesses - if gs.verbosity() <= 2: - outdev = open(os.devnull, "w") - else: - outdev = sys.stdout + outdev = open(os.devnull, "w") if gs.verbosity() <= 2 else sys.stdout # download Addons ZIP file os.chdir(TMPDIR) # this is just to not leave something behind @@ -1961,10 +1958,7 @@ def install_extension_std_platforms(name, source, url, branch): path_to_src_code_message = _("Path to the source code:") # to hide non-error messages from subprocesses - if gs.verbosity() <= 2: - outdev = open(os.devnull, "w") - else: - outdev = sys.stdout + outdev = open(os.devnull, "w") if gs.verbosity() <= 2 else sys.stdout os.chdir(TMPDIR) # this is just to not leave something behind srcdir = os.path.join(TMPDIR, name) @@ -2578,10 +2572,7 @@ def resolve_known_host_service(url, name, branch): ) return None, None if match: - if not actual_start: - actual_start = match["url_start"] - else: - actual_start = "" + actual_start = match["url_start"] if not actual_start else "" if "branch" in match["url_end"]: suffix = match["url_end"].format( name=name, diff --git a/scripts/g.manual/g.manual.py b/scripts/g.manual/g.manual.py index f4ecf961076..345a6d1714a 100755 --- a/scripts/g.manual/g.manual.py +++ b/scripts/g.manual/g.manual.py @@ -132,10 +132,7 @@ def main(): elif flags["t"]: special = "topics" - if flags["m"]: - start = start_man - else: - start = start_browser + start = start_man if flags["m"] else start_browser entry = options["entry"] gisbase = os.environ["GISBASE"] diff --git a/scripts/i.in.spotvgt/i.in.spotvgt.py b/scripts/i.in.spotvgt/i.in.spotvgt.py index cd744d4c252..666f3721761 100755 --- a/scripts/i.in.spotvgt/i.in.spotvgt.py +++ b/scripts/i.in.spotvgt/i.in.spotvgt.py @@ -136,11 +136,7 @@ def main(): spotdir = os.path.dirname(infile) spotname = gs.basename(infile, "hdf") - - if rast: - name = rast - else: - name = spotname + name = rast or spotname if not gs.overwrite() and gs.find_file(name)["file"]: gs.fatal(_("<%s> already exists. Aborting.") % name) diff --git a/scripts/i.oif/i.oif.py b/scripts/i.oif/i.oif.py index 0dabbe7cb38..cb156675927 100755 --- a/scripts/i.oif/i.oif.py +++ b/scripts/i.oif/i.oif.py @@ -90,10 +90,7 @@ def main(): stddev[band] = float(kv["stddev"]) else: # run all bands in parallel - if "WORKERS" in os.environ: - workers = int(os.environ["WORKERS"]) - else: - workers = len(bands) + workers = int(os.environ["WORKERS"]) if "WORKERS" in os.environ else len(bands) proc = {} pout = {} @@ -142,10 +139,7 @@ def main(): _("The Optimum Index Factor analysis result (best combination shown first):") ) - if shell: - fmt = "%s,%s,%s:%.4f\n" - else: - fmt = "%s, %s, %s: %.4f\n" + fmt = "%s,%s,%s:%.4f\n" if shell else "%s, %s, %s: %.4f\n" if not output or output == "-": for v, p in oif: diff --git a/scripts/i.spectral/i.spectral.py b/scripts/i.spectral/i.spectral.py index 171eac7359c..07efd8af31f 100755 --- a/scripts/i.spectral/i.spectral.py +++ b/scripts/i.spectral/i.spectral.py @@ -136,10 +136,7 @@ def draw_gnuplot(what, xlabels, output, img_format, coord_legend): cmd = [] for i, row in enumerate(what): - if not coord_legend: - title = "Pick " + str(i + 1) - else: - title = str(tuple(row[0:2])) + title = "Pick " + str(i + 1) if not coord_legend else str(tuple(row[0:2])) x_datafile = os.path.join(tmp_dir, "data_%d" % i) cmd.append(" '%s' title '%s'" % (x_datafile, title)) diff --git a/scripts/m.proj/m.proj.py b/scripts/m.proj/m.proj.py index 4540b3dcd0a..a018606fff9 100755 --- a/scripts/m.proj/m.proj.py +++ b/scripts/m.proj/m.proj.py @@ -236,14 +236,8 @@ def main(): gcore.debug("output file=[%s]" % outfile) # set up output style - if not decimal: - outfmt = ["-w5"] - else: - outfmt = ["-f", "%.8f"] - if not copy_input: - copyinp = [] - else: - copyinp = ["-E"] + outfmt = ["-w5"] if not decimal else ["-f", "%.8f"] + copyinp = [] if not copy_input else ["-E"] # do the conversion # Convert cs2cs DMS format to GRASS DMS format: diff --git a/scripts/r.buffer.lowmem/r.buffer.lowmem.py b/scripts/r.buffer.lowmem/r.buffer.lowmem.py index 2916ad95e7d..8866c21faeb 100755 --- a/scripts/r.buffer.lowmem/r.buffer.lowmem.py +++ b/scripts/r.buffer.lowmem/r.buffer.lowmem.py @@ -92,10 +92,7 @@ def main(): s = gs.read_command("g.proj", flags="j") kv = gs.parse_key_val(s) - if kv["+proj"] == "longlat": - metric = "geodesic" - else: - metric = "squared" + metric = "geodesic" if kv["+proj"] == "longlat" else "squared" gs.run_command( "r.grow.distance", input=input, metric=metric, distance=temp_dist, flags="m" diff --git a/scripts/r.in.aster/r.in.aster.py b/scripts/r.in.aster/r.in.aster.py index 24722293dde..626d27e7976 100755 --- a/scripts/r.in.aster/r.in.aster.py +++ b/scripts/r.in.aster/r.in.aster.py @@ -152,10 +152,7 @@ def main(): # Band 3b is not included ASTER L1T if proctype == "L1T": allbands.remove("3b") - if band == "all": - bandlist = allbands - else: - bandlist = band.split(",") + bandlist = allbands if band == "all" else band.split(",") # initialize datasets for L1A, L1B, L1T if proctype in {"L1A", "L1B", "L1T"}: diff --git a/scripts/r.in.srtm/r.in.srtm.py b/scripts/r.in.srtm/r.in.srtm.py index 1e4c585ac02..b9f51415ca0 100755 --- a/scripts/r.in.srtm/r.in.srtm.py +++ b/scripts/r.in.srtm/r.in.srtm.py @@ -177,10 +177,7 @@ def main(): infile = infile[:-4] (fdir, tile) = os.path.split(infile) - if not output: - tileout = tile - else: - tileout = output + tileout = output or tile if ".hgt" in input: suff = ".hgt" diff --git a/scripts/r.in.wms/wms_cap_parsers.py b/scripts/r.in.wms/wms_cap_parsers.py index 56b1d0ce48c..723a63f0b23 100644 --- a/scripts/r.in.wms/wms_cap_parsers.py +++ b/scripts/r.in.wms/wms_cap_parsers.py @@ -501,10 +501,7 @@ def _find(self, etreeElement, tag, ns=None): """!Find child element. If the element is not found it raises xml.etree.ElementTree.ParseError. """ - if not ns: - res = etreeElement.find(tag) - else: - res = etreeElement.find(ns(tag)) + res = etreeElement.find(tag) if not ns else etreeElement.find(ns(tag)) if res is None: raise ParseError( @@ -521,10 +518,7 @@ def _findall(self, etreeElement, tag, ns=None): """!Find all children element. If no element is found it raises xml.etree.ElementTree.ParseError. """ - if not ns: - res = etreeElement.findall(tag) - else: - res = etreeElement.findall(ns(tag)) + res = etreeElement.findall(tag) if not ns else etreeElement.findall(ns(tag)) if not res: raise ParseError( diff --git a/scripts/r.in.wms/wms_drv.py b/scripts/r.in.wms/wms_drv.py index 531112a1a6c..e1131918c4a 100644 --- a/scripts/r.in.wms/wms_drv.py +++ b/scripts/r.in.wms/wms_drv.py @@ -995,10 +995,7 @@ def _parseTilePattern(self, group_t_patts, bbox, region): res["y"] = (bbox["maxy"] - bbox["miny"]) / region["rows"] res["x"] = (bbox["maxx"] - bbox["minx"]) / region["cols"] - if res["x"] < res["y"]: - comp_res = "x" - else: - comp_res = "y" + comp_res = "x" if res["x"] < res["y"] else "y" t_res = {} best_patt = None diff --git a/scripts/r.out.xyz/r.out.xyz.py b/scripts/r.out.xyz/r.out.xyz.py index ae8e04de4d6..6df97f3c202 100755 --- a/scripts/r.out.xyz/r.out.xyz.py +++ b/scripts/r.out.xyz/r.out.xyz.py @@ -48,10 +48,7 @@ def main(): output = options["output"] donodata = flags["i"] - if donodata: - statsflags = "1g" - else: - statsflags = "1gn" + statsflags = "1g" if donodata else "1gn" parameters = { "flags": statsflags, "input": options["input"], diff --git a/scripts/r.reclass.area/r.reclass.area.py b/scripts/r.reclass.area/r.reclass.area.py index 5d6fc1292bc..01e474659bc 100755 --- a/scripts/r.reclass.area/r.reclass.area.py +++ b/scripts/r.reclass.area/r.reclass.area.py @@ -152,10 +152,7 @@ def reclass(inf, outf, lim, clump, diag, les): if len(f) < 5: continue hectares = float(f[4]) * 0.0001 - if lesser: - test = hectares <= limit - else: - test = hectares >= limit + test = hectares <= limit if lesser else hectares >= limit if test: rules += "%s = %s %s\n" % (f[0], f[2], f[3]) if rules: diff --git a/scripts/r.unpack/r.unpack.py b/scripts/r.unpack/r.unpack.py index 575d465ebb5..dd595b4722b 100644 --- a/scripts/r.unpack/r.unpack.py +++ b/scripts/r.unpack/r.unpack.py @@ -92,10 +92,7 @@ def main(): return 0 - if options["output"]: - map_name = options["output"] - else: - map_name = data_names[0].split("@")[0] + map_name = options["output"] or data_names[0].split("@")[0] gfile = grass.find_file(name=map_name, element="cell", mapset=".") if gfile["file"]: diff --git a/scripts/r3.in.xyz/r3.in.xyz.py b/scripts/r3.in.xyz/r3.in.xyz.py index b17d59506b7..5b2c8be4a65 100755 --- a/scripts/r3.in.xyz/r3.in.xyz.py +++ b/scripts/r3.in.xyz/r3.in.xyz.py @@ -226,10 +226,7 @@ def main(): addl_opts["flags"] = "i" if scan_only or shell_style: - if shell_style: - doShell = "g" - else: - doShell = "" + doShell = "g" if shell_style else "" grass.run_command( "r.in.xyz", flags="s" + doShell, @@ -243,10 +240,7 @@ def main(): ) sys.exit() - if dtype == "float": - data_type = "FCELL" - else: - data_type = "DCELL" + data_type = "FCELL" if dtype == "float" else "DCELL" region = grass.region(region3d=True) diff --git a/scripts/v.build.all/v.build.all.py b/scripts/v.build.all/v.build.all.py index 69b0837209f..8691ecddc32 100755 --- a/scripts/v.build.all/v.build.all.py +++ b/scripts/v.build.all/v.build.all.py @@ -31,10 +31,7 @@ def main(): vectors = grass.list_grouped("vect")[mapset] num_vectors = len(vectors) - if grass.verbosity() < 2: - quiet = True - else: - quiet = False + quiet = grass.verbosity() < 2 i = 1 for vect in vectors: diff --git a/scripts/v.db.reconnect.all/v.db.reconnect.all.py b/scripts/v.db.reconnect.all/v.db.reconnect.all.py index b42b8006673..9a9d46356a9 100755 --- a/scripts/v.db.reconnect.all/v.db.reconnect.all.py +++ b/scripts/v.db.reconnect.all/v.db.reconnect.all.py @@ -255,10 +255,7 @@ def main(): schema = "" table = schema_table - if new_schema: - new_schema_table = "%s.%s" % (new_schema, table) - else: - new_schema_table = table + new_schema_table = "%s.%s" % (new_schema, table) if new_schema else table gs.debug( "DATABASE = '%s' SCHEMA = '%s' TABLE = '%s' ->\n" diff --git a/scripts/v.dissolve/tests/conftest.py b/scripts/v.dissolve/tests/conftest.py index 9b069330488..e5e9a38818d 100644 --- a/scripts/v.dissolve/tests/conftest.py +++ b/scripts/v.dissolve/tests/conftest.py @@ -13,10 +13,7 @@ def updates_as_transaction(table, cat_column, column, column_quote, cats, values): """Create SQL statement for categories and values for a given column""" sql = ["BEGIN TRANSACTION"] - if column_quote: - quote = "'" - else: - quote = "" + quote = "'" if column_quote else "" for cat, value in zip(cats, values): sql.append( f"UPDATE {table} SET {column} = {quote}{value}{quote} " diff --git a/scripts/v.dissolve/tests/v_dissolve_aggregate_test.py b/scripts/v.dissolve/tests/v_dissolve_aggregate_test.py index 68ca178b864..90dc3de075e 100644 --- a/scripts/v.dissolve/tests/v_dissolve_aggregate_test.py +++ b/scripts/v.dissolve/tests/v_dissolve_aggregate_test.py @@ -101,10 +101,7 @@ def test_aggregate_column_result(dataset, backend): for stats_column in stats_columns: assert stats_column in columns column_info = columns[stats_column] - if stats_column.endswith("_n"): - correct_type = "integer" - else: - correct_type = "double precision" + correct_type = "integer" if stats_column.endswith("_n") else "double precision" assert ( columns[stats_column]["type"].lower() == correct_type ), f"{stats_column} has a wrong type" @@ -221,10 +218,7 @@ def test_sqlite_agg_accepted(dataset): for method, stats_column in zip(stats, expected_stats_columns): assert stats_column in columns column_info = columns[stats_column] - if method == "count": - correct_type = "integer" - else: - correct_type = "double precision" + correct_type = "integer" if method == "count" else "double precision" assert ( columns[stats_column]["type"].lower() == correct_type ), f"{stats_column} has a wrong type" diff --git a/scripts/v.dissolve/tests/v_dissolve_layers_test.py b/scripts/v.dissolve/tests/v_dissolve_layers_test.py index 702aa8f8496..f6986d35917 100644 --- a/scripts/v.dissolve/tests/v_dissolve_layers_test.py +++ b/scripts/v.dissolve/tests/v_dissolve_layers_test.py @@ -50,10 +50,7 @@ def test_layer_2(dataset_layer_2): for method, stats_column in zip(stats, expected_stats_columns): assert stats_column in columns column_info = columns[stats_column] - if method == "count": - correct_type = "integer" - else: - correct_type = "double precision" + correct_type = "integer" if method == "count" else "double precision" assert ( columns[stats_column]["type"].lower() == correct_type ), f"{stats_column} has a wrong type" diff --git a/scripts/v.in.e00/v.in.e00.py b/scripts/v.in.e00/v.in.e00.py index 4d63636199f..4258fa3181a 100755 --- a/scripts/v.in.e00/v.in.e00.py +++ b/scripts/v.in.e00/v.in.e00.py @@ -86,10 +86,7 @@ def main(): ) merging = True - if vect: - name = vect - else: - name = e00name + name = vect or e00name # do import diff --git a/scripts/v.in.lines/v.in.lines.py b/scripts/v.in.lines/v.in.lines.py index 44112b297a3..35991988f6b 100755 --- a/scripts/v.in.lines/v.in.lines.py +++ b/scripts/v.in.lines/v.in.lines.py @@ -50,12 +50,7 @@ def main(): fs = separator(options["separator"]) threeD = flags["z"] - - if threeD: - do3D = "z" - else: - do3D = "" - + do3D = "z" if threeD else "" tmp = grass.tempfile() # set up input file diff --git a/scripts/v.in.mapgen/v.in.mapgen.py b/scripts/v.in.mapgen/v.in.mapgen.py index 404fb7ec6b2..efe7af1075d 100755 --- a/scripts/v.in.mapgen/v.in.mapgen.py +++ b/scripts/v.in.mapgen/v.in.mapgen.py @@ -73,18 +73,12 @@ def main(): if not os.path.isfile(infile): grass.fatal(_("Input file <%s> not found") % infile) - if output: - name = output - else: - name = "" + name = output or "" if threeD: matlab = True - if threeD: - do3D = "z" - else: - do3D = "" + do3D = "z" if threeD else "" tmp = grass.tempfile() diff --git a/scripts/v.pack/v.pack.py b/scripts/v.pack/v.pack.py index 4468c888bcb..e39d52dbafe 100755 --- a/scripts/v.pack/v.pack.py +++ b/scripts/v.pack/v.pack.py @@ -73,10 +73,7 @@ def main(): infile = infile.split("@")[0] # output name - if options["output"]: - outfile = options["output"] - else: - outfile = infile + ".pack" + outfile = options["output"] or infile + ".pack" # check if exists the output file if os.path.exists(outfile): diff --git a/scripts/v.rast.stats/v.rast.stats.py b/scripts/v.rast.stats/v.rast.stats.py index 803fc8691ad..4096aa49caf 100644 --- a/scripts/v.rast.stats/v.rast.stats.py +++ b/scripts/v.rast.stats/v.rast.stats.py @@ -116,10 +116,7 @@ def main(): # Get mapset of the vector vs = vector.split("@") - if len(vs) > 1: - vect_mapset = vs[1] - else: - vect_mapset = mapset + vect_mapset = vs[1] if len(vs) > 1 else mapset # does map exist in CURRENT mapset? if vect_mapset != mapset or not gs.find_file(vector, "vector", mapset)["file"]: @@ -373,10 +370,7 @@ def set_up_columns(vector, layer, percentile, colprefix, basecols, dbfdriver, c) perc = b if perc: # namespace is limited in DBF but the % value is important - if dbfdriver: - perccol = "per" + percentile - else: - perccol = "percentile_" + percentile + perccol = "per" + percentile if dbfdriver else "percentile_" + percentile percindex = basecols.index(perc) basecols[percindex] = perccol @@ -424,10 +418,7 @@ def set_up_columns(vector, layer, percentile, colprefix, basecols, dbfdriver, c) + _("Use -c flag to update values in this column.") ) else: - if i == "n": - coltype = "INTEGER" - else: - coltype = "DOUBLE PRECISION" + coltype = "INTEGER" if i == "n" else "DOUBLE PRECISION" addcols.append(currcolumn + " " + coltype) if addcols: diff --git a/scripts/v.report/v.report.py b/scripts/v.report/v.report.py index cec84582155..29d9d3c914e 100755 --- a/scripts/v.report/v.report.py +++ b/scripts/v.report/v.report.py @@ -91,10 +91,7 @@ def main(): isConnection = False colnames = ["cat"] - if option == "coor": - extracolnames = ["x", "y", "z"] - else: - extracolnames = [option] + extracolnames = ["x", "y", "z"] if option == "coor" else [option] if units == "percent": unitsp = "meters" diff --git a/scripts/v.unpack/v.unpack.py b/scripts/v.unpack/v.unpack.py index ea75d443b57..c3a7a55deb7 100644 --- a/scripts/v.unpack/v.unpack.py +++ b/scripts/v.unpack/v.unpack.py @@ -93,10 +93,7 @@ def main(): return 0 # set the output name - if options["output"]: - map_name = options["output"] - else: - map_name = data_name + map_name = options["output"] or data_name # grass env gisenv = grass.gisenv() @@ -233,19 +230,13 @@ def main(): # for each old connection for t in dbnlist: # it split the line of each connection, to found layer number and key - if len(t.split("|")) != 1: - values = t.split("|") - else: - values = t.split(" ") + values = t.split("|") if len(t.split("|")) != 1 else t.split(" ") from_table = values[1] layer = values[0].split("/")[0] # we need to take care about the table name in case of several layer if options["output"]: - if len(dbnlist) > 1: - to_table = "%s_%s" % (map_name, layer) - else: - to_table = map_name + to_table = "%s_%s" % (map_name, layer) if len(dbnlist) > 1 else map_name else: to_table = from_table From af55fa7eaeeaabd3c4db99f4622e9849b71da80a Mon Sep 17 00:00:00 2001 From: Arohan Ajit Date: Tue, 22 Oct 2024 10:20:23 -0400 Subject: [PATCH 08/55] d.rast.edit: Fixed E722 in d.rast.edit/ (#4568) --- .flake8 | 1 - scripts/d.rast.edit/d.rast.edit.py | 21 +-------------------- 2 files changed, 1 insertion(+), 21 deletions(-) diff --git a/.flake8 b/.flake8 index 8211d9e03d4..ffa7d162eda 100644 --- a/.flake8 +++ b/.flake8 @@ -108,7 +108,6 @@ per-file-ignores = scripts/i.pansharpen/i.pansharpen.py: E722, E501 scripts/r.in.srtm/r.in.srtm.py: E722 scripts/r.fillnulls/r.fillnulls.py: E722 - scripts/d.rast.edit/d.rast.edit.py: E722 scripts/v.what.strds/v.what.strds.py: E501 # Line too long (esp. module interface definitions) scripts/*/*.py: E501 diff --git a/scripts/d.rast.edit/d.rast.edit.py b/scripts/d.rast.edit/d.rast.edit.py index 3464941e825..102d7e447d8 100755 --- a/scripts/d.rast.edit/d.rast.edit.py +++ b/scripts/d.rast.edit/d.rast.edit.py @@ -644,28 +644,9 @@ def update_status(self, row, col): if self.angles: self.status["aspect"] = self.angles[row][col] - def force_color(self, val): - run("g.region", rows=1, cols=1) - run("r.mapcalc", expression="%s = %d" % (self.tempmap, val)) - run("r.colors", map=self.tempmap, rast=self.inmap) - run("r.out.ppm", input=self.tempmap, out=self.tempfile) - run("g.remove", flags="f", type="raster", name=self.tempmap) - - tempimg = wx.Image(self.tempfile) - gs.try_remove(self.tempfile) - - rgb = tempimg.get(0, 0) - color = "#%02x%02x%02x" % rgb - self.colors[val] = color - tempimg.delete() - def get_color(self, val): if val not in self.colors: - try: - self.force_color(val) - except: - self.colors[val] = "#ffffff" - + self.colors[val] = "#ffffff" return self.colors[val] def refresh_canvas(self): From c5c42cf440cd037976beb58eb9cd1b9cc23ccb3e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 23 Oct 2024 12:22:19 +0000 Subject: [PATCH 09/55] CI(deps): Update github/codeql-action action to v3.27.0 (#4575) --- .github/workflows/codeql-analysis.yml | 4 ++-- .github/workflows/python-code-quality.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 6672287794c..97f89578306 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -56,7 +56,7 @@ jobs: if: ${{ matrix.language == 'c-cpp' }} - name: Initialize CodeQL - uses: github/codeql-action/init@f779452ac5af1c261dce0346a8f964149f49322b # v3.26.13 + uses: github/codeql-action/init@662472033e021d55d94146f66f6058822b0b39fd # v3.27.0 with: languages: ${{ matrix.language }} config-file: ./.github/codeql/codeql-config.yml @@ -81,6 +81,6 @@ jobs: run: .github/workflows/build_ubuntu-22.04.sh "${HOME}/install" - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@f779452ac5af1c261dce0346a8f964149f49322b # v3.26.13 + uses: github/codeql-action/analyze@662472033e021d55d94146f66f6058822b0b39fd # v3.27.0 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/python-code-quality.yml b/.github/workflows/python-code-quality.yml index 9f71c28e922..15357764d6a 100644 --- a/.github/workflows/python-code-quality.yml +++ b/.github/workflows/python-code-quality.yml @@ -135,7 +135,7 @@ jobs: path: bandit.sarif - name: Upload SARIF File into Security Tab - uses: github/codeql-action/upload-sarif@f779452ac5af1c261dce0346a8f964149f49322b # v3.26.13 + uses: github/codeql-action/upload-sarif@662472033e021d55d94146f66f6058822b0b39fd # v3.27.0 with: sarif_file: bandit.sarif From 25757837f282466a31062335ef2d99d0879fb148 Mon Sep 17 00:00:00 2001 From: Arohan Ajit Date: Wed, 23 Oct 2024 08:31:02 -0400 Subject: [PATCH 10/55] wxGUI: Fixed F841 in photo2image/ (#4573) * fixed 841 * fixed busyInfo --- .flake8 | 4 +- gui/wxpython/photo2image/g.gui.photo2image.py | 2 +- gui/wxpython/photo2image/ip2i_manager.py | 56 ++++++++----------- gui/wxpython/photo2image/ip2i_mapdisplay.py | 2 - 4 files changed, 27 insertions(+), 37 deletions(-) diff --git a/.flake8 b/.flake8 index ffa7d162eda..14224a97843 100644 --- a/.flake8 +++ b/.flake8 @@ -25,8 +25,8 @@ per-file-ignores = gui/scripts/d.wms.py: E501 gui/wxpython/image2target/g.gui.image2target.py: E501 gui/wxpython/nviz/*: E722 - gui/wxpython/photo2image/*: F841, E722, E265 - gui/wxpython/photo2image/g.gui.photo2image.py: E501, F841 + gui/wxpython/photo2image/*: E722 + gui/wxpython/photo2image/g.gui.photo2image.py: E501 gui/wxpython/psmap/*: F841, E266, E722 gui/wxpython/vdigit/*: F841, E722, F405, F403 gui/wxpython/animation/g.gui.animation.py: E501 diff --git a/gui/wxpython/photo2image/g.gui.photo2image.py b/gui/wxpython/photo2image/g.gui.photo2image.py index 65b4141873e..fe153b236cc 100755 --- a/gui/wxpython/photo2image/g.gui.photo2image.py +++ b/gui/wxpython/photo2image/g.gui.photo2image.py @@ -121,7 +121,7 @@ def main(): app = wx.App() - wizard = GCPWizard( + GCPWizard( parent=None, giface=StandaloneGrassInterface(), group=group, diff --git a/gui/wxpython/photo2image/ip2i_manager.py b/gui/wxpython/photo2image/ip2i_manager.py index 5a2a1f14f21..711ec4191af 100644 --- a/gui/wxpython/photo2image/ip2i_manager.py +++ b/gui/wxpython/photo2image/ip2i_manager.py @@ -1107,22 +1107,20 @@ def OnGeorect(self, event): else: flags = "a" - busy = wx.BusyInfo(_("Rectifying images, please wait..."), parent=self) - wx.GetApp().Yield() + with wx.BusyInfo(_("Rectifying images, please wait..."), parent=self): + wx.GetApp().Yield() - ret, msg = RunCommand( - "i.rectify", - parent=self, - getErrorMsg=True, - quiet=True, - group=self.xygroup, - extension=self.extension, - order=self.gr_order, - method=self.gr_method, - flags=flags, - ) - - del busy + ret, msg = RunCommand( + "i.rectify", + parent=self, + getErrorMsg=True, + quiet=True, + group=self.xygroup, + extension=self.extension, + order=self.gr_order, + method=self.gr_method, + flags=flags, + ) # provide feedback on failure if ret != 0: @@ -1130,21 +1128,19 @@ def OnGeorect(self, event): print(self.grwiz.src_map, file=sys.stderr) print(msg, file=sys.stderr) - busy = wx.BusyInfo( + with wx.BusyInfo( _("Writing output image to group, please wait..."), parent=self - ) - wx.GetApp().Yield() - - ret1, msg1 = RunCommand( - "i.group", - parent=self, - getErrorMsg=True, - quiet=False, - group=self.xygroup, - input="".join([self.grwiz.src_map.split("@")[0], self.extension]), - ) + ): + wx.GetApp().Yield() - del busy + ret1, msg1 = RunCommand( + "i.group", + parent=self, + getErrorMsg=True, + quiet=False, + group=self.xygroup, + input="".join([self.grwiz.src_map.split("@")[0], self.extension]), + ) if ret1 != 0: print("ip2i: Error in i.group", file=sys.stderr) @@ -1253,7 +1249,6 @@ def OnGROrder(self, event): elif self.gr_order == 2: minNumOfItems = 6 - diff = 6 - numOfItems # self.SetStatusText(_( # "Insufficient points, 6+ points needed for 2nd order")) @@ -1556,7 +1551,6 @@ def OnZoomToTarget(self, event): def OnZoomMenuGCP(self, event): """Popup Zoom menu""" - point = wx.GetMousePosition() zoommenu = Menu() # Add items to the menu @@ -2467,7 +2461,6 @@ def UpdateSettings(self): srcrender = False tgtrender = False - reload_target = False if self.new_src_map != src_map: # remove old layer layers = self.parent.grwiz.SrcMap.GetListOfLayers() @@ -2499,7 +2492,6 @@ def UpdateSettings(self): del layers[0] layers = self.parent.grwiz.TgtMap.GetListOfLayers() # self.parent.grwiz.TgtMap.DeleteAllLayers() - reload_target = True tgt_map["raster"] = self.new_tgt_map["raster"] if tgt_map["raster"] != "": diff --git a/gui/wxpython/photo2image/ip2i_mapdisplay.py b/gui/wxpython/photo2image/ip2i_mapdisplay.py index aa085f2b43a..732716a1a0c 100644 --- a/gui/wxpython/photo2image/ip2i_mapdisplay.py +++ b/gui/wxpython/photo2image/ip2i_mapdisplay.py @@ -466,7 +466,6 @@ def PrintMenu(self, event): """ Print options and output menu for map display """ - point = wx.GetMousePosition() printmenu = Menu() # Add items to the menu setup = wx.MenuItem(printmenu, wx.ID_ANY, _("Page setup")) @@ -510,7 +509,6 @@ def SaveDisplayRegion(self, event): def OnZoomMenu(self, event): """Popup Zoom menu""" - point = wx.GetMousePosition() zoommenu = Menu() # Add items to the menu From a05ed293ec9af66daa61f493e62611a6f179d2af Mon Sep 17 00:00:00 2001 From: Mohan Yelugoti Date: Wed, 23 Oct 2024 08:48:45 -0400 Subject: [PATCH 11/55] lib/db: Remove deprecated implementation of db_get_login() and replace it with that of db_get_login2() (#4302) `db_get_login()` is deprecated in 7.8.0 release with da399c52637ee5c81228459fa374a114c8fef06c. Change its function signature and implementation to match that of the currently preferred `db_get_login2()`. Technically, this is removing the old function and introducing a new one with the same name, but a different signature. Modify `db_get_login2()` to internally call `db_get_login()` function call. In the next major version, `db_get_login2()` should be removed to have only one method to get login details for simplicity. See also #4308. --------- Signed-off-by: Mohan Yelugoti --- db/drivers/mysql/db.c | 2 +- db/drivers/postgres/db.c | 4 ++-- db/drivers/postgres/listdb.c | 2 +- include/grass/defs/dbmi.h | 3 ++- lib/db/dbmi_base/connect.c | 10 +++++----- lib/db/dbmi_base/login.c | 16 +++++++--------- lib/vector/Vlib/open_pg.c | 4 ++-- vector/v.external/dsn.c | 2 +- vector/v.in.ogr/dsn.c | 2 +- vector/v.out.ogr/dsn.c | 2 +- 10 files changed, 23 insertions(+), 24 deletions(-) diff --git a/db/drivers/mysql/db.c b/db/drivers/mysql/db.c index 5c98c652e95..b83d3d7064d 100644 --- a/db/drivers/mysql/db.c +++ b/db/drivers/mysql/db.c @@ -51,7 +51,7 @@ int db__driver_open_database(dbHandle *handle) connpar.host, connpar.port, connpar.dbname, connpar.user, connpar.password); - db_get_login2("mysql", name, &user, &password, &host, &port); + db_get_login("mysql", name, &user, &password, &host, &port); connection = mysql_init(NULL); res = diff --git a/db/drivers/postgres/db.c b/db/drivers/postgres/db.c index 5343acf03d8..aa27d370419 100644 --- a/db/drivers/postgres/db.c +++ b/db/drivers/postgres/db.c @@ -54,7 +54,7 @@ int db__driver_open_database(dbHandle *handle) return DB_FAILED; } - db_get_login2("pg", name, &user, &password, &host, &port); + db_get_login("pg", name, &user, &password, &host, &port); pg_conn = PQsetdbLogin(host, port, pgconn.options, pgconn.tty, pgconn.dbname, user, password); @@ -241,7 +241,7 @@ int create_delete_db(dbHandle *handle, int create) pgconn.host, pgconn.port, pgconn.options, pgconn.tty, pgconn.dbname, pgconn.user, pgconn.password, pgconn.host, pgconn.port, pgconn.schema); - db_get_login2("pg", template_db, &user, &password, &host, &port); + db_get_login("pg", template_db, &user, &password, &host, &port); pg_conn = PQsetdbLogin(host, port, pgconn.options, pgconn.tty, pgconn.dbname, user, password); diff --git a/db/drivers/postgres/listdb.c b/db/drivers/postgres/listdb.c index 0efa0328c0f..974141f1e36 100644 --- a/db/drivers/postgres/listdb.c +++ b/db/drivers/postgres/listdb.c @@ -48,7 +48,7 @@ int db__driver_list_databases(dbString *dbpath, int npaths, dbHandle **dblist, pgconn.dbname, pgconn.user, pgconn.password, pgconn.host, pgconn.port, pgconn.options, pgconn.tty); - db_get_login2("pg", NULL, &user, &passwd, &host, &port); + db_get_login("pg", NULL, &user, &passwd, &host, &port); G_debug(1, "user = %s, passwd = %s", user, passwd ? "xxx" : ""); if (user || passwd) { diff --git a/include/grass/defs/dbmi.h b/include/grass/defs/dbmi.h index c5bf648414f..0eca1858489 100644 --- a/include/grass/defs/dbmi.h +++ b/include/grass/defs/dbmi.h @@ -389,7 +389,8 @@ unsigned int db_sizeof_string(const dbString *); int db_set_login(const char *, const char *, const char *, const char *); int db_set_login2(const char *, const char *, const char *, const char *, const char *, const char *, int); -int db_get_login(const char *, const char *, const char **, const char **); +int db_get_login(const char *, const char *, const char **, const char **, + const char **, const char **); int db_get_login2(const char *, const char *, const char **, const char **, const char **, const char **); int db_get_login_dump(FILE *); diff --git a/lib/db/dbmi_base/connect.c b/lib/db/dbmi_base/connect.c index 780d929dd3a..ced282405bd 100644 --- a/lib/db/dbmi_base/connect.c +++ b/lib/db/dbmi_base/connect.c @@ -87,11 +87,11 @@ int db_get_connection(dbConnection *connection) connection->group = (char *)G_getenv_nofatal2("DB_GROUP", G_VAR_MAPSET); /* try to get user/password */ - db_get_login2(connection->driverName, connection->databaseName, - (const char **)&(connection->user), - (const char **)&(connection->password), - (const char **)&(connection->hostName), - (const char **)&(connection->port)); + db_get_login(connection->driverName, connection->databaseName, + (const char **)&(connection->user), + (const char **)&(connection->password), + (const char **)&(connection->hostName), + (const char **)&(connection->port)); return DB_OK; } diff --git a/lib/db/dbmi_base/login.c b/lib/db/dbmi_base/login.c index d79fc84e6cf..bc84f78118c 100644 --- a/lib/db/dbmi_base/login.c +++ b/lib/db/dbmi_base/login.c @@ -346,22 +346,20 @@ static int get_login(const char *driver, const char *database, If driver/database is not found, output arguments are set to NULL. - \deprecated Use db_set_login2() instead. - - \todo: GRASS 8: to be replaced by db_set_login2(). - \param driver driver name \param database database name (can be NULL) \param[out] user name \param[out] password string + \param[out] host name + \param[out] port \return DB_OK on success \return DB_FAILED on failure */ -int db_get_login(const char *driver, const char *database, const char **user, - const char **password) +int db_get_login2(const char *driver, const char *database, const char **user, + const char **password, const char **host, const char **port) { - return get_login(driver, database, user, password, NULL, NULL); + return db_get_login(driver, database, user, password, host, port); } /*! @@ -379,8 +377,8 @@ int db_get_login(const char *driver, const char *database, const char **user, \return DB_OK on success \return DB_FAILED on failure */ -int db_get_login2(const char *driver, const char *database, const char **user, - const char **password, const char **host, const char **port) +int db_get_login(const char *driver, const char *database, const char **user, + const char **password, const char **host, const char **port) { return get_login(driver, database, user, password, host, port); } diff --git a/lib/vector/Vlib/open_pg.c b/lib/vector/Vlib/open_pg.c index 7db0113be99..293291066c2 100644 --- a/lib/vector/Vlib/open_pg.c +++ b/lib/vector/Vlib/open_pg.c @@ -535,11 +535,11 @@ void connect_db(struct Format_info_pg *pg_info) /* try connection settings for given database first, then try * any settings defined for pg driver */ - db_get_login2("pg", dbname, &user, &passwd, &host, &port); + db_get_login("pg", dbname, &user, &passwd, &host, &port); /* any settings defined for pg driver disabled - can cause problems when running multiple local/remote db clusters if (strlen(dbname) > 0 && !user && !passwd) - db_get_login2("pg", NULL, &user, &passwd, &host, &port); + db_get_login("pg", NULL, &user, &passwd, &host, &port); */ if (user || passwd || host || port) { char conninfo[DB_SQL_MAX]; diff --git a/vector/v.external/dsn.c b/vector/v.external/dsn.c index 1a0d6bc2a57..c56009a64e2 100644 --- a/vector/v.external/dsn.c +++ b/vector/v.external/dsn.c @@ -31,7 +31,7 @@ char *get_datasource_name(const char *opt_dsn, int use_ogr) /* add db.login settings (user, password, host, port) */ if (DB_OK == - db_get_login2("pg", database, &user, &passwd, &host, &port)) { + db_get_login("pg", database, &user, &passwd, &host, &port)) { if (user) { if (!G_strcasestr(opt_dsn, "user=")) { strcat(connect_str, " user="); diff --git a/vector/v.in.ogr/dsn.c b/vector/v.in.ogr/dsn.c index 2fecff7e9fb..7e483e71050 100644 --- a/vector/v.in.ogr/dsn.c +++ b/vector/v.in.ogr/dsn.c @@ -38,7 +38,7 @@ char *get_datasource_name(const char *opt_dsn, int use_ogr) /* add db.login settings (user, password, host, port) */ if (DB_OK == - db_get_login2("pg", database, &user, &passwd, &host, &port)) { + db_get_login("pg", database, &user, &passwd, &host, &port)) { if (user) { if (!G_strcasestr(opt_dsn, "user=")) { strcat(connect_str, " user="); diff --git a/vector/v.out.ogr/dsn.c b/vector/v.out.ogr/dsn.c index 31d258c05c7..bd7ce101ed2 100644 --- a/vector/v.out.ogr/dsn.c +++ b/vector/v.out.ogr/dsn.c @@ -37,7 +37,7 @@ char *get_datasource_name(const char *opt_dsn, int use_ogr) /* add db.login settings (user, password, host, port) */ if (DB_OK == - db_get_login2("pg", database, &user, &passwd, &host, &port)) { + db_get_login("pg", database, &user, &passwd, &host, &port)) { if (user) { if (!G_strcasestr(opt_dsn, "user=")) { strcat(connect_str, " user="); From 930d59a3c30235f6ac33ba53e10dd1a8e201f732 Mon Sep 17 00:00:00 2001 From: Mohan Yelugoti Date: Wed, 23 Oct 2024 08:50:28 -0400 Subject: [PATCH 12/55] lib/db: Remove deprecated implementation of db_set_login() and replace it with that of db_set_login2() (#4308) `db_set_login()` is deprecated in 7.8.0 release with da399c52637ee5c81228459fa374a114c8fef06c. Change its function signature and implementation to match that of the currently preferred `db_set_login2()`. Technically, this is removing the old function and introducing a new one with the same name, but a different signature. Modify `db_set_login2()` to internally call `db_set_login()` function call. In the next major version, `db_set_login2()` should be removed to have only one method to get login details for simplicity. See also #4308. --------- Signed-off-by: Mohan Yelugoti --- db/db.login/main.c | 6 +++--- include/grass/defs/dbmi.h | 3 ++- lib/db/dbmi_base/login.c | 21 +++++++++++---------- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/db/db.login/main.c b/db/db.login/main.c index 9147c0e7f1f..f073b654665 100644 --- a/db/db.login/main.c +++ b/db/db.login/main.c @@ -98,9 +98,9 @@ int main(int argc, char *argv[]) exit(EXIT_SUCCESS); } - if (db_set_login2(driver->answer, database->answer, user->answer, - password->answer, host->answer, port->answer, - G_get_overwrite()) == DB_FAILED) { + if (db_set_login(driver->answer, database->answer, user->answer, + password->answer, host->answer, port->answer, + G_get_overwrite()) == DB_FAILED) { G_fatal_error(_("Unable to set user/password")); } diff --git a/include/grass/defs/dbmi.h b/include/grass/defs/dbmi.h index 0eca1858489..5af0476849d 100644 --- a/include/grass/defs/dbmi.h +++ b/include/grass/defs/dbmi.h @@ -386,7 +386,8 @@ const char *db_whoami(void); void db_zero(void *, int); void db_zero_string(dbString *); unsigned int db_sizeof_string(const dbString *); -int db_set_login(const char *, const char *, const char *, const char *); +int db_set_login(const char *, const char *, const char *, const char *, + const char *, const char *, int); int db_set_login2(const char *, const char *, const char *, const char *, const char *, const char *, int); int db_get_login(const char *, const char *, const char **, const char **, diff --git a/lib/db/dbmi_base/login.c b/lib/db/dbmi_base/login.c index bc84f78118c..9c865233d2c 100644 --- a/lib/db/dbmi_base/login.c +++ b/lib/db/dbmi_base/login.c @@ -253,22 +253,23 @@ static int set_login(const char *driver, const char *database, const char *user, /*! \brief Set login parameters for driver/database - \deprecated Use db_set_login2() instead. - - \todo: GRASS 8: to be replaced by db_set_login2(). - \param driver driver name \param database database name \param user user name \param password password string + \param host host name + \param port + \param overwrite TRUE to overwrite existing connections \return DB_OK on success \return DB_FAILED on failure */ -int db_set_login(const char *driver, const char *database, const char *user, - const char *password) +int db_set_login2(const char *driver, const char *database, const char *user, + const char *password, const char *host, const char *port, + int overwrite) { - return set_login(driver, database, user, password, NULL, NULL, FALSE); + return db_set_login(driver, database, user, password, host, port, + overwrite); } /*! @@ -285,9 +286,9 @@ int db_set_login(const char *driver, const char *database, const char *user, \return DB_OK on success \return DB_FAILED on failure */ -int db_set_login2(const char *driver, const char *database, const char *user, - const char *password, const char *host, const char *port, - int overwrite) +int db_set_login(const char *driver, const char *database, const char *user, + const char *password, const char *host, const char *port, + int overwrite) { return set_login(driver, database, user, password, host, port, overwrite); } From 5cd687092b6bcdcaed1e52feed8cd7a312ac5e30 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 23 Oct 2024 18:47:36 +0000 Subject: [PATCH 13/55] CI(deps): Update actions/checkout action to v4.2.2 (#4578) --- .github/workflows/additional_checks.yml | 2 +- .github/workflows/clang-format-check.yml | 2 +- .github/workflows/codeql-analysis.yml | 2 +- .github/workflows/coverity.yml | 2 +- .github/workflows/create_release_draft.yml | 2 +- .github/workflows/docker.yml | 2 +- .github/workflows/gcc.yml | 2 +- .github/workflows/macos.yml | 2 +- .github/workflows/osgeo4w.yml | 2 +- .github/workflows/periodic_update.yml | 2 +- .github/workflows/pytest.yml | 2 +- .github/workflows/python-code-quality.yml | 2 +- .github/workflows/super-linter.yml | 2 +- .github/workflows/test-nix.yml | 2 +- .github/workflows/titles.yml | 2 +- .github/workflows/ubuntu.yml | 2 +- 16 files changed, 16 insertions(+), 16 deletions(-) diff --git a/.github/workflows/additional_checks.yml b/.github/workflows/additional_checks.yml index a91d221f1e4..a2fbfadc36f 100644 --- a/.github/workflows/additional_checks.yml +++ b/.github/workflows/additional_checks.yml @@ -24,7 +24,7 @@ jobs: steps: - name: Checkout repository contents - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 31 diff --git a/.github/workflows/clang-format-check.yml b/.github/workflows/clang-format-check.yml index 13ba5bb3cd9..489d8197c09 100644 --- a/.github/workflows/clang-format-check.yml +++ b/.github/workflows/clang-format-check.yml @@ -16,7 +16,7 @@ jobs: name: Formatting Check runs-on: ubuntu-latest steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: persist-credentials: false - uses: DoozyX/clang-format-lint-action@c71d0bf4e21876ebec3e5647491186f8797fde31 # v0.18.2 diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 97f89578306..9c161300170 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -40,7 +40,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Set up Python uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0 with: diff --git a/.github/workflows/coverity.yml b/.github/workflows/coverity.yml index 22a6b7a42a8..51ab83015ca 100644 --- a/.github/workflows/coverity.yml +++ b/.github/workflows/coverity.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-22.04 if: github.repository == 'OSGeo/grass' steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Get dependencies run: | diff --git a/.github/workflows/create_release_draft.yml b/.github/workflows/create_release_draft.yml index 3112fb8b33f..6c3597599fc 100644 --- a/.github/workflows/create_release_draft.yml +++ b/.github/workflows/create_release_draft.yml @@ -30,7 +30,7 @@ jobs: contents: write steps: - name: Checks-out repository - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: ref: ${{ github.ref }} fetch-depth: 0 diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 4de674ee9a2..6b2ad83629e 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -49,7 +49,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 - name: Docker meta diff --git a/.github/workflows/gcc.yml b/.github/workflows/gcc.yml index 651cb272fba..6b6286ef3f0 100644 --- a/.github/workflows/gcc.yml +++ b/.github/workflows/gcc.yml @@ -26,7 +26,7 @@ jobs: fail-fast: false steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Get dependencies run: | sudo apt-get update -y diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 41ac51df8ff..cdc02ad1432 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -44,7 +44,7 @@ jobs: -mindepth 1 -maxdepth 1 -type f -print -delete # Rehash to forget about the deleted files hash -r - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Get current date cache key segment id: date # Year and week of year so cache key changes weekly diff --git a/.github/workflows/osgeo4w.yml b/.github/workflows/osgeo4w.yml index a7694fa9b30..30add8dde09 100644 --- a/.github/workflows/osgeo4w.yml +++ b/.github/workflows/osgeo4w.yml @@ -31,7 +31,7 @@ jobs: run: | git config --global core.autocrlf false git config --global core.eol lf - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: msys2/setup-msys2@ddf331adaebd714795f1042345e6ca57bd66cea8 # v2.24.1 with: path-type: inherit diff --git a/.github/workflows/periodic_update.yml b/.github/workflows/periodic_update.yml index 17855d6149e..d27b8664c55 100644 --- a/.github/workflows/periodic_update.yml +++ b/.github/workflows/periodic_update.yml @@ -21,7 +21,7 @@ jobs: - name: Create URL to the run output id: vars run: echo "run-url=https://github.com/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID" >> $GITHUB_OUTPUT - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: "Check that autoconf scripts are up-to-date:" run: | rm -f config.guess config.sub diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index e1b3b84b54e..b28fb40ad14 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -32,7 +32,7 @@ jobs: PYTHONWARNINGS: always steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Set up Python uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0 diff --git a/.github/workflows/python-code-quality.yml b/.github/workflows/python-code-quality.yml index 15357764d6a..94a8d0be26b 100644 --- a/.github/workflows/python-code-quality.yml +++ b/.github/workflows/python-code-quality.yml @@ -54,7 +54,7 @@ jobs: echo Bandit: ${{ env.BANDIT_VERSION }} echo Ruff: ${{ env.RUFF_VERSION }} - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Set up Python uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0 diff --git a/.github/workflows/super-linter.yml b/.github/workflows/super-linter.yml index 62328723f77..ab2168cd1a3 100644 --- a/.github/workflows/super-linter.yml +++ b/.github/workflows/super-linter.yml @@ -25,7 +25,7 @@ jobs: statuses: write steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: # super-linter needs the full git history to get the # list of files that changed across commits diff --git a/.github/workflows/test-nix.yml b/.github/workflows/test-nix.yml index ba14e0747ab..43a1b5d40ab 100644 --- a/.github/workflows/test-nix.yml +++ b/.github/workflows/test-nix.yml @@ -28,7 +28,7 @@ jobs: contents: read steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Install nix uses: DeterminateSystems/nix-installer-action@da36cb69b1c3247ad7a1f931ebfd954a1105ef14 # v14 diff --git a/.github/workflows/titles.yml b/.github/workflows/titles.yml index f202fdafe02..9821a209a87 100644 --- a/.github/workflows/titles.yml +++ b/.github/workflows/titles.yml @@ -21,7 +21,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout base repository (doesn't include the PR changes) - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Call PR title validation function run: python utils/generate_release_notes.py check "${PR_TITLE}" "" "" env: diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 966dbfe21ab..9023df7d1b3 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -59,7 +59,7 @@ jobs: fail-fast: false steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Invert inclusion list to an exclusion list id: get-exclude From 533070dbc9807657e96ec376f23ab6db64fbdc9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Wed, 23 Oct 2024 17:12:02 -0400 Subject: [PATCH 14/55] style: Fix unused-import (F401) (#4521) * t.rast.accumulate: Remove unused SimpleModule import in test_accumulation * temporal: Fix unused-import (F401) in testsuite * grass.temporal: Fix unused-import (F401) * grass.benchmark: Fix unused-import (F401) by defining __all__ * grass.pygrass.vector: Fix unused-import (F401) for testsuite * grass.pygrass.vector: Sort imports * vector: Fix unused-import (F401) for testsuite * scripts: Fix unused-import (F401) for testsuite * raster: Fix unused-import (F401) for testsuite * v.fill.holes: Fix unused-import (F401) * doc: Fix unused-import (F401) * grass.semantic_label: Fix unused-import (F401) by defining __all__ in __init__ * grass.pygrass.rpc: Fix unused-import (F401) in __init__ * grass.pygrass.modules.interface: Fix unused-import (F401) by defining __all__ in __init__ * grass.pygrass.modules.interface: Apply isort * grass.pygrass.modules.grid: Fix unused-import (F401) by defining __all__ in __init__ * grass.pygrass.modules: Fix unused-import (F401) by defining __all__ in __init__ * grass.pygrass.modules: Apply isort * grass.imaging: Fix unused-import (F401) by defining __all__ in __init__ * grass.imaging: Apply isort * grass.jupyter: Fix unused-import (F401) by defining __all__ in __init__ * grass.jupyter: Apply isort * pygrass: Ignore F401 (unused imports) Ignored inline where the import is justified and isn't to fix later, and ignored in a per-file exclusion where the imports seemed to be for commented-out test case lines * lib/gis: Fix F401 unused platform import in test_gis_lib_getl * grass.script: Ignore F401 in `__init__.py` for setup import * style: Remove exclusion for F401 ruff rule * style: Remove unneeded flake8 exclusions for F401 * Apply suggestions from code review --- .flake8 | 14 +++++--------- doc/notebooks/hydrology.ipynb | 1 - doc/notebooks/jupyter_tutorial.ipynb | 1 - doc/notebooks/parallelization_tutorial.ipynb | 1 - doc/notebooks/solar_potential.ipynb | 1 - doc/notebooks/viewshed_analysis.ipynb | 1 - lib/gis/testsuite/test_gis_lib_getl.py | 1 - pyproject.toml | 3 ++- python/grass/benchmark/__init__.py | 14 ++++++++++++++ python/grass/imaging/__init__.py | 15 +++++++++++++-- python/grass/jupyter/__init__.py | 13 ++++++++++++- python/grass/pygrass/modules/__init__.py | 9 ++++++++- python/grass/pygrass/modules/grid/__init__.py | 2 ++ .../pygrass/modules/interface/__init__.py | 18 ++++++++++++------ .../modules/testsuite/test_import_isolation.py | 9 ++++++--- python/grass/pygrass/rpc/__init__.py | 3 --- .../pygrass/vector/testsuite/test_filters.py | 1 - .../pygrass/vector/testsuite/test_geometry.py | 11 ++++------- .../vector/testsuite/test_geometry_attrs.py | 8 -------- .../testsuite/test_pygrass_vector_doctests.py | 3 --- .../pygrass/vector/testsuite/test_table.py | 5 ++--- .../pygrass/vector/testsuite/test_vector.py | 2 -- .../pygrass/vector/testsuite/test_vector3d.py | 6 +----- python/grass/script/__init__.py | 2 +- python/grass/semantic_label/__init__.py | 2 ++ .../unittests_temporal_algebra_grs.py | 1 - .../unittests_temporal_algebra_mixed_stds.py | 1 - .../unittests_temporal_conditionals.py | 1 - raster/r.in.ascii/testsuite/test_r_in_ascii.py | 1 - .../testsuite/test_r_object_geometry.py | 2 -- raster/r.viewshed/testsuite/test_r_viewshed.py | 1 - scripts/db.in.ogr/testsuite/test_db_in_ogr.py | 1 - .../r.fillnulls/testsuite/test_r_fillnulls.py | 2 -- scripts/r.grow/testsuite/test_r_grow.py | 1 - scripts/v.dissolve/v_dissolve.ipynb | 1 - .../testsuite/test_accumulation.py | 1 - .../testsuite/test_aggregation_absolute.py | 1 - .../test_aggregation_absolute_parallel.py | 1 - .../testsuite/test_aggregation_relative.py | 1 - .../testsuite/test_raster_algebra_operators.py | 1 - .../testsuite/test_t_rast_extract.py | 3 --- .../t.rast.gapfill/testsuite/test_gapfill.py | 2 -- .../testsuite/test_neighbors.py | 1 + .../t.rast.series/testsuite/test_series.py | 1 - .../testsuite/test_strds_to_rast3.py | 4 ---- .../t.rast.to.vect/testsuite/test_to_vect.py | 2 -- .../testsuite/test_t_rast_univar.py | 1 + .../testsuite/test_t_rast3d_extract.py | 3 --- .../testsuite/test_t_rast3d_univar.py | 1 + temporal/t.shift/testsuite/test_shift.py | 2 -- temporal/t.snap/testsuite/test_snap.py | 2 -- .../t.support/testsuite/test_support_str3ds.py | 2 -- .../t.support/testsuite/test_support_strds.py | 2 -- .../t.support/testsuite/test_support_stvds.py | 2 -- .../t.unregister/testsuite/test_unregister.py | 1 - vector/v.extract/testsuite/test_v_extract.py | 1 - vector/v.fill.holes/examples.ipynb | 2 -- vector/v.in.ogr/testsuite/test_v_in_ogr.py | 1 - 58 files changed, 87 insertions(+), 109 deletions(-) diff --git a/.flake8 b/.flake8 index 14224a97843..9985b8e5a42 100644 --- a/.flake8 +++ b/.flake8 @@ -15,11 +15,10 @@ per-file-ignores = # E501 line too long # E722 do not use bare 'except' # W605 invalid escape sequence - # F401 imported but unused # F821 undefined name 'unicode' # F841 local variable assigned to but never used # E741 ambiguous variable name 'l' - __init__.py: F401, F403 + __init__.py: F403 man/build_html.py: E501 doc/python/m.distance.py: E501 gui/scripts/d.wms.py: E501 @@ -66,10 +65,8 @@ per-file-ignores = python/grass/pygrass/vector/__init__.py: E402 python/grass/pygrass/raster/__init__.py: E402 python/grass/pygrass/vector/__init__.py: E402 - python/grass/pygrass/modules/interface/*.py: F401 - python/grass/pygrass/modules/grid/*.py: F401 python/grass/pygrass/raster/category.py: E721 - python/grass/pygrass/rpc/__init__.py: F401, F403 + python/grass/pygrass/rpc/__init__.py: F403 python/grass/pygrass/utils.py: E402 python/grass/temporal/abstract_space_time_dataset.py: E722 python/grass/temporal/c_libraries_interface.py: E722 @@ -82,17 +79,16 @@ per-file-ignores = python/grass/temporal/temporal_topology_dataset_connector.py: E722 # Current benchmarks/tests are changing sys.path before import. # Possibly, a different approach should be taken there anyway. - python/grass/pygrass/tests/benchmark.py: E402, F401, F821 + python/grass/pygrass/tests/benchmark.py: E402, F821 # Configuration file for Sphinx: # Ignoring import/code mix and line length. # Files not managed by Black python/grass/imaging/images2gif.py: E226 # Unused imports in init files - # F401 imported but unused # F403 star import used; unable to detect undefined names python/grass/*/__init__.py: F401, F403 - python/grass/*/*/__init__.py: F401, F403 - python/grass/*/*/*/__init__.py: F401, F403 + python/grass/*/*/__init__.py: F403 + python/grass/*/*/*/__init__.py: F403 # E402 module level import not at top of file scripts/r.in.wms/wms_gdal_drv.py: E722 scripts/r.in.wms/wms_drv.py: E402, E722 diff --git a/doc/notebooks/hydrology.ipynb b/doc/notebooks/hydrology.ipynb index b9e23acf3c1..f5c853de9a2 100644 --- a/doc/notebooks/hydrology.ipynb +++ b/doc/notebooks/hydrology.ipynb @@ -25,7 +25,6 @@ "outputs": [], "source": [ "# Import Python standard library and IPython packages we need.\n", - "import os\n", "import subprocess\n", "import sys\n", "import csv\n", diff --git a/doc/notebooks/jupyter_tutorial.ipynb b/doc/notebooks/jupyter_tutorial.ipynb index 71852c226e6..6dfdfb63625 100644 --- a/doc/notebooks/jupyter_tutorial.ipynb +++ b/doc/notebooks/jupyter_tutorial.ipynb @@ -30,7 +30,6 @@ "source": [ "# Import Python standard library and IPython packages we need.\n", "import subprocess\n", - "import time\n", "import sys\n", "\n", "# Ask GRASS GIS where its Python packages are.\n", diff --git a/doc/notebooks/parallelization_tutorial.ipynb b/doc/notebooks/parallelization_tutorial.ipynb index 2c5d902e9a4..4611f5d1c24 100644 --- a/doc/notebooks/parallelization_tutorial.ipynb +++ b/doc/notebooks/parallelization_tutorial.ipynb @@ -21,7 +21,6 @@ "metadata": {}, "outputs": [], "source": [ - "import os\n", "import subprocess\n", "import sys\n", "\n", diff --git a/doc/notebooks/solar_potential.ipynb b/doc/notebooks/solar_potential.ipynb index 98253ad6450..07da1af77e2 100644 --- a/doc/notebooks/solar_potential.ipynb +++ b/doc/notebooks/solar_potential.ipynb @@ -28,7 +28,6 @@ "outputs": [], "source": [ "# Import Python standard library and IPython packages we need.\n", - "import os\n", "import subprocess\n", "import sys\n", "\n", diff --git a/doc/notebooks/viewshed_analysis.ipynb b/doc/notebooks/viewshed_analysis.ipynb index a4f0b61744a..5cfe69c4dae 100644 --- a/doc/notebooks/viewshed_analysis.ipynb +++ b/doc/notebooks/viewshed_analysis.ipynb @@ -30,7 +30,6 @@ "outputs": [], "source": [ "# Import Python standard library and IPython packages we need.\n", - "import os\n", "import subprocess\n", "import sys\n", "\n", diff --git a/lib/gis/testsuite/test_gis_lib_getl.py b/lib/gis/testsuite/test_gis_lib_getl.py index 98092955ab2..72e8992ad39 100644 --- a/lib/gis/testsuite/test_gis_lib_getl.py +++ b/lib/gis/testsuite/test_gis_lib_getl.py @@ -5,7 +5,6 @@ import ctypes import pathlib -import platform import unittest import grass.lib.gis as libgis diff --git a/pyproject.toml b/pyproject.toml index 4b7856bab3b..a428c79106f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -131,7 +131,6 @@ ignore = [ "E722", # bare-except "E731", # lambda-assignment "E741", # ambiguous-variable-name - "F401", # unused-import "F403", # undefined-local-with-import-star "F405", # undefined-local-with-import-star-usage "F811", # redefined-while-unused @@ -319,7 +318,9 @@ ignore = [ "python/grass/jupyter/testsuite/map_test.py" = ["PGH004"] "python/grass/pydispatch/signal.py" = ["A005"] "python/grass/pygrass/modules/grid/grid.py" = ["SIM115"] +"python/grass/pygrass/modules/grid/testsuite/test_*_modules_grid_doctests.py" = ["F401"] "python/grass/pygrass/modules/interface/env.py" = ["SIM115"] +"python/grass/pygrass/modules/testsuite/test_pygrass_modules_doctests.py" = ["F401"] "python/grass/pygrass/raster/segment.py" = ["SIM115"] "python/grass/pygrass/tests/*.py" = ["SIM115"] "python/grass/pygrass/vector/geometry.py" = ["PYI024"] diff --git a/python/grass/benchmark/__init__.py b/python/grass/benchmark/__init__.py index a4a7bf4e991..62a6a85c3e1 100644 --- a/python/grass/benchmark/__init__.py +++ b/python/grass/benchmark/__init__.py @@ -34,3 +34,17 @@ save_results_to_file, ) from .runners import benchmark_nprocs, benchmark_resolutions, benchmark_single + +__all__ = [ + "benchmark_nprocs", + "benchmark_resolutions", + "benchmark_single", + "join_results", + "join_results_from_files", + "load_results", + "load_results_from_file", + "nprocs_plot", + "num_cells_plot", + "save_results", + "save_results_to_file", +] diff --git a/python/grass/imaging/__init__.py b/python/grass/imaging/__init__.py index 41626697f8e..7434942abe0 100644 --- a/python/grass/imaging/__init__.py +++ b/python/grass/imaging/__init__.py @@ -1,4 +1,15 @@ -from grass.imaging.images2gif import readGif, writeGif -from grass.imaging.images2swf import readSwf, writeSwf from grass.imaging.images2avi import readAvi, writeAvi +from grass.imaging.images2gif import readGif, writeGif from grass.imaging.images2ims import readIms, writeIms +from grass.imaging.images2swf import readSwf, writeSwf + +__all__ = [ + "readAvi", + "readGif", + "readIms", + "readSwf", + "writeAvi", + "writeGif", + "writeIms", + "writeSwf", +] diff --git a/python/grass/jupyter/__init__.py b/python/grass/jupyter/__init__.py index 91457f07ac3..21223c2cd47 100644 --- a/python/grass/jupyter/__init__.py +++ b/python/grass/jupyter/__init__.py @@ -109,6 +109,17 @@ from .interactivemap import InteractiveMap, Raster, Vector from .map import Map from .map3d import Map3D +from .seriesmap import SeriesMap from .setup import init from .timeseriesmap import TimeSeriesMap -from .seriesmap import SeriesMap + +__all__ = [ + "InteractiveMap", + "Map", + "Map3D", + "Raster", + "SeriesMap", + "TimeSeriesMap", + "Vector", + "init", +] diff --git a/python/grass/pygrass/modules/__init__.py b/python/grass/pygrass/modules/__init__.py index 61073791599..ce4d169fedd 100644 --- a/python/grass/pygrass/modules/__init__.py +++ b/python/grass/pygrass/modules/__init__.py @@ -1,2 +1,9 @@ -from grass.pygrass.modules.interface import Module, MultiModule, ParallelModuleQueue from grass.pygrass.modules import shortcuts +from grass.pygrass.modules.interface import Module, MultiModule, ParallelModuleQueue + +__all__ = [ + "Module", + "MultiModule", + "ParallelModuleQueue", + "shortcuts", +] diff --git a/python/grass/pygrass/modules/grid/__init__.py b/python/grass/pygrass/modules/grid/__init__.py index 1c971174998..0d770ed3ad2 100644 --- a/python/grass/pygrass/modules/grid/__init__.py +++ b/python/grass/pygrass/modules/grid/__init__.py @@ -1 +1,3 @@ from grass.pygrass.modules.grid.grid import GridModule + +__all__ = ["GridModule"] diff --git a/python/grass/pygrass/modules/interface/__init__.py b/python/grass/pygrass/modules/interface/__init__.py index a05211e21c3..bde59049c6e 100644 --- a/python/grass/pygrass/modules/interface/__init__.py +++ b/python/grass/pygrass/modules/interface/__init__.py @@ -4,14 +4,20 @@ @author: pietro """ -from grass.pygrass.modules.interface import flag -from grass.pygrass.modules.interface import parameter -from grass.pygrass.modules.interface import module -from grass.pygrass.modules.interface import typedict -from grass.pygrass.modules.interface import read - +from grass.pygrass.modules.interface import flag, module, parameter, read, typedict from grass.pygrass.modules.interface.module import ( Module, MultiModule, ParallelModuleQueue, ) + +__all__ = [ + "Module", + "MultiModule", + "ParallelModuleQueue", + "flag", + "module", + "parameter", + "read", + "typedict", +] diff --git a/python/grass/pygrass/modules/testsuite/test_import_isolation.py b/python/grass/pygrass/modules/testsuite/test_import_isolation.py index d1321a554d0..af643ec2fee 100644 --- a/python/grass/pygrass/modules/testsuite/test_import_isolation.py +++ b/python/grass/pygrass/modules/testsuite/test_import_isolation.py @@ -36,14 +36,17 @@ def test_import_isolation(self): isolate, check(*self.patterns), msg="Test isolation before any import." ) # same import done in __init__ file - from grass.pygrass.modules.interface import Module, ParallelModuleQueue - from grass.pygrass.modules import shortcuts + from grass.pygrass.modules.interface import ( + Module, # noqa: F401 + ParallelModuleQueue, # noqa: F401 + ) + from grass.pygrass.modules import shortcuts # noqa: F401 self.assertEqual( isolate, check(*self.patterns), msg="Test isolation after import Module." ) # test the other way round - from grass.pygrass.vector import VectorTopo + from grass.pygrass.vector import VectorTopo # noqa: F401 self.assertNotEqual( isolate, diff --git a/python/grass/pygrass/rpc/__init__.py b/python/grass/pygrass/rpc/__init__.py index 07cbfe6503a..a6ab19b9369 100644 --- a/python/grass/pygrass/rpc/__init__.py +++ b/python/grass/pygrass/rpc/__init__.py @@ -10,8 +10,6 @@ :authors: Soeren Gebbert """ -import time -import threading import sys from multiprocessing import Process, Lock, Pipe from ctypes import CFUNCTYPE, c_void_p @@ -24,7 +22,6 @@ from .base import RPCServerBase from grass.pygrass.gis.region import Region from grass.pygrass import utils -import logging ############################################################################### ############################################################################### diff --git a/python/grass/pygrass/vector/testsuite/test_filters.py b/python/grass/pygrass/vector/testsuite/test_filters.py index 9252b134c02..9adba4cdefc 100644 --- a/python/grass/pygrass/vector/testsuite/test_filters.py +++ b/python/grass/pygrass/vector/testsuite/test_filters.py @@ -6,7 +6,6 @@ from grass.gunittest.case import TestCase from grass.gunittest.main import test - from grass.pygrass.vector.table import Filters diff --git a/python/grass/pygrass/vector/testsuite/test_geometry.py b/python/grass/pygrass/vector/testsuite/test_geometry.py index b2a7a1e37df..6957a473165 100644 --- a/python/grass/pygrass/vector/testsuite/test_geometry.py +++ b/python/grass/pygrass/vector/testsuite/test_geometry.py @@ -6,18 +6,15 @@ import sys import unittest + import numpy as np +import grass.lib.vector as libvect from grass.gunittest.case import TestCase from grass.gunittest.main import test - -import grass.lib.vector as libvect -from grass.script.core import run_command - -from grass.pygrass.vector import Vector, VectorTopo -from grass.pygrass.vector.geometry import Point, Line, Node -from grass.pygrass.vector.geometry import Area, Boundary, Centroid +from grass.pygrass.vector import VectorTopo from grass.pygrass.vector.basic import Bbox +from grass.pygrass.vector.geometry import Area, Line, Node, Point class PointTestCase(TestCase): diff --git a/python/grass/pygrass/vector/testsuite/test_geometry_attrs.py b/python/grass/pygrass/vector/testsuite/test_geometry_attrs.py index 356a55ec4d7..cba638b1901 100644 --- a/python/grass/pygrass/vector/testsuite/test_geometry_attrs.py +++ b/python/grass/pygrass/vector/testsuite/test_geometry_attrs.py @@ -4,16 +4,8 @@ @author: pietro """ -import sys -import unittest -import numpy as np - from grass.gunittest.case import TestCase from grass.gunittest.main import test - -import grass.lib.vector as libvect -from grass.script.core import run_command - from grass.pygrass.vector import VectorTopo diff --git a/python/grass/pygrass/vector/testsuite/test_pygrass_vector_doctests.py b/python/grass/pygrass/vector/testsuite/test_pygrass_vector_doctests.py index b3d26220ec1..2cf0d0ba0c5 100644 --- a/python/grass/pygrass/vector/testsuite/test_pygrass_vector_doctests.py +++ b/python/grass/pygrass/vector/testsuite/test_pygrass_vector_doctests.py @@ -7,10 +7,7 @@ import grass.gunittest.case import grass.gunittest.main import grass.gunittest.utils - import grass.pygrass.vector as gvector -import grass.pygrass.utils as gutils - # doctest does not allow changing the base classes of test case, skip test case # and test suite, so we need to create a new type which inherits from our class diff --git a/python/grass/pygrass/vector/testsuite/test_table.py b/python/grass/pygrass/vector/testsuite/test_table.py index d87786fb3bd..c77233400b1 100644 --- a/python/grass/pygrass/vector/testsuite/test_table.py +++ b/python/grass/pygrass/vector/testsuite/test_table.py @@ -7,16 +7,15 @@ import os import sqlite3 import tempfile as tmp -from string import ascii_letters, digits from random import choice +from string import ascii_letters, digits + import numpy as np from grass.gunittest.case import TestCase from grass.gunittest.main import test - from grass.pygrass.vector.table import Table, get_path - # dictionary that generate random data RNG = np.random.default_rng() COL2VALS = { diff --git a/python/grass/pygrass/vector/testsuite/test_vector.py b/python/grass/pygrass/vector/testsuite/test_vector.py index 5d16333c31f..b4eebb2ab1e 100644 --- a/python/grass/pygrass/vector/testsuite/test_vector.py +++ b/python/grass/pygrass/vector/testsuite/test_vector.py @@ -6,8 +6,6 @@ from grass.gunittest.case import TestCase from grass.gunittest.main import test - -from grass.script.core import run_command from grass.pygrass.vector import VectorTopo diff --git a/python/grass/pygrass/vector/testsuite/test_vector3d.py b/python/grass/pygrass/vector/testsuite/test_vector3d.py index 796f85ca529..84e688d22e8 100644 --- a/python/grass/pygrass/vector/testsuite/test_vector3d.py +++ b/python/grass/pygrass/vector/testsuite/test_vector3d.py @@ -8,13 +8,9 @@ from grass.gunittest.case import TestCase from grass.gunittest.main import test - -from grass.script.core import run_command - +from grass.pygrass.gis.region import Region from grass.pygrass.vector import VectorTopo from grass.pygrass.vector.geometry import Point -from grass.pygrass.gis.region import Region -from grass.pygrass.utils import get_mapset_vector def generate_coordinates(number, bbox=None, with_z=False): diff --git a/python/grass/script/__init__.py b/python/grass/script/__init__.py index 8589e8a1521..ea82c2fe451 100644 --- a/python/grass/script/__init__.py +++ b/python/grass/script/__init__.py @@ -7,4 +7,4 @@ from .raster3d import * from .vector import * from .utils import * -from . import setup +from . import setup # noqa: F401 diff --git a/python/grass/semantic_label/__init__.py b/python/grass/semantic_label/__init__.py index 9f0b9b6caed..58bfe11a418 100644 --- a/python/grass/semantic_label/__init__.py +++ b/python/grass/semantic_label/__init__.py @@ -1 +1,3 @@ from .reader import SemanticLabelReader, SemanticLabelReaderError + +__all__ = ["SemanticLabelReader", "SemanticLabelReaderError"] diff --git a/python/grass/temporal/testsuite/unittests_temporal_algebra_grs.py b/python/grass/temporal/testsuite/unittests_temporal_algebra_grs.py index 7e0db57a8ce..d7a81bcb34d 100644 --- a/python/grass/temporal/testsuite/unittests_temporal_algebra_grs.py +++ b/python/grass/temporal/testsuite/unittests_temporal_algebra_grs.py @@ -8,7 +8,6 @@ """ import datetime -import os import grass.temporal as tgis from grass.gunittest.case import TestCase diff --git a/python/grass/temporal/testsuite/unittests_temporal_algebra_mixed_stds.py b/python/grass/temporal/testsuite/unittests_temporal_algebra_mixed_stds.py index cf0e9c82bb7..ce911839049 100644 --- a/python/grass/temporal/testsuite/unittests_temporal_algebra_mixed_stds.py +++ b/python/grass/temporal/testsuite/unittests_temporal_algebra_mixed_stds.py @@ -8,7 +8,6 @@ """ import datetime -import os import grass.temporal as tgis from grass.gunittest.case import TestCase diff --git a/python/grass/temporal/testsuite/unittests_temporal_conditionals.py b/python/grass/temporal/testsuite/unittests_temporal_conditionals.py index ff0703aec1d..800c7d30bf6 100644 --- a/python/grass/temporal/testsuite/unittests_temporal_conditionals.py +++ b/python/grass/temporal/testsuite/unittests_temporal_conditionals.py @@ -8,7 +8,6 @@ """ import datetime -import os import grass.temporal as tgis from grass.gunittest.case import TestCase diff --git a/raster/r.in.ascii/testsuite/test_r_in_ascii.py b/raster/r.in.ascii/testsuite/test_r_in_ascii.py index baa892d83a8..8db06f83517 100644 --- a/raster/r.in.ascii/testsuite/test_r_in_ascii.py +++ b/raster/r.in.ascii/testsuite/test_r_in_ascii.py @@ -11,7 +11,6 @@ from grass.gunittest.case import TestCase from grass.gunittest.main import test -from grass.script.core import read_command INPUT_NOQUOTES = """north: 4299000.00 south: 4247000.00 diff --git a/raster/r.object.geometry/testsuite/test_r_object_geometry.py b/raster/r.object.geometry/testsuite/test_r_object_geometry.py index 419df4d780b..279d46ae4f0 100644 --- a/raster/r.object.geometry/testsuite/test_r_object_geometry.py +++ b/raster/r.object.geometry/testsuite/test_r_object_geometry.py @@ -6,11 +6,9 @@ import json import os -from sys import stderr from grass.gunittest.case import TestCase from grass.gunittest.main import test -from grass.gunittest.gmodules import call_module from grass.gunittest.gmodules import SimpleModule diff --git a/raster/r.viewshed/testsuite/test_r_viewshed.py b/raster/r.viewshed/testsuite/test_r_viewshed.py index 2b136abd551..a341d8e97b5 100644 --- a/raster/r.viewshed/testsuite/test_r_viewshed.py +++ b/raster/r.viewshed/testsuite/test_r_viewshed.py @@ -1,6 +1,5 @@ from grass.gunittest.case import TestCase from grass.gunittest.main import test -from grass.gunittest.gmodules import call_module class TestViewshed(TestCase): diff --git a/scripts/db.in.ogr/testsuite/test_db_in_ogr.py b/scripts/db.in.ogr/testsuite/test_db_in_ogr.py index 423917e1b93..b79efa1f096 100644 --- a/scripts/db.in.ogr/testsuite/test_db_in_ogr.py +++ b/scripts/db.in.ogr/testsuite/test_db_in_ogr.py @@ -8,7 +8,6 @@ from grass.gunittest.main import test from grass.gunittest.gmodules import SimpleModule -from grass.script.core import run_command from grass.script.utils import decode import os diff --git a/scripts/r.fillnulls/testsuite/test_r_fillnulls.py b/scripts/r.fillnulls/testsuite/test_r_fillnulls.py index 975fd5330f2..dda6d99ed95 100644 --- a/scripts/r.fillnulls/testsuite/test_r_fillnulls.py +++ b/scripts/r.fillnulls/testsuite/test_r_fillnulls.py @@ -4,8 +4,6 @@ @author: Sanjeet Bhatti """ -import os - from grass.gunittest.case import TestCase from grass.gunittest.main import test from grass.gunittest.gmodules import SimpleModule diff --git a/scripts/r.grow/testsuite/test_r_grow.py b/scripts/r.grow/testsuite/test_r_grow.py index 3d54b9ab993..1c9488b4180 100644 --- a/scripts/r.grow/testsuite/test_r_grow.py +++ b/scripts/r.grow/testsuite/test_r_grow.py @@ -7,7 +7,6 @@ from grass.gunittest.case import TestCase from grass.gunittest.main import test from grass.gunittest.gmodules import SimpleModule -from grass.script.core import run_command class TestRGrow(TestCase): diff --git a/scripts/v.dissolve/v_dissolve.ipynb b/scripts/v.dissolve/v_dissolve.ipynb index f90907a704d..085b23828d8 100644 --- a/scripts/v.dissolve/v_dissolve.ipynb +++ b/scripts/v.dissolve/v_dissolve.ipynb @@ -19,7 +19,6 @@ "metadata": {}, "outputs": [], "source": [ - "import os\n", "import json\n", "import subprocess\n", "import sys\n", diff --git a/temporal/t.rast.accumulate/testsuite/test_accumulation.py b/temporal/t.rast.accumulate/testsuite/test_accumulation.py index 566c1971f99..6c277c320cf 100644 --- a/temporal/t.rast.accumulate/testsuite/test_accumulation.py +++ b/temporal/t.rast.accumulate/testsuite/test_accumulation.py @@ -12,7 +12,6 @@ import grass.temporal as tgis from grass.gunittest.case import TestCase -from grass.gunittest.gmodules import SimpleModule class TestAccumulate(TestCase): diff --git a/temporal/t.rast.aggregate/testsuite/test_aggregation_absolute.py b/temporal/t.rast.aggregate/testsuite/test_aggregation_absolute.py index 924e3950ca8..e7702ba23b5 100644 --- a/temporal/t.rast.aggregate/testsuite/test_aggregation_absolute.py +++ b/temporal/t.rast.aggregate/testsuite/test_aggregation_absolute.py @@ -10,7 +10,6 @@ import os -import grass.pygrass.modules as pymod import grass.temporal as tgis from grass.gunittest.case import TestCase from grass.gunittest.gmodules import SimpleModule diff --git a/temporal/t.rast.aggregate/testsuite/test_aggregation_absolute_parallel.py b/temporal/t.rast.aggregate/testsuite/test_aggregation_absolute_parallel.py index 2b56dd30615..5ad25e2e32c 100644 --- a/temporal/t.rast.aggregate/testsuite/test_aggregation_absolute_parallel.py +++ b/temporal/t.rast.aggregate/testsuite/test_aggregation_absolute_parallel.py @@ -11,7 +11,6 @@ import os from datetime import datetime -import grass.pygrass.modules as pymod import grass.temporal as tgis from grass.gunittest.case import TestCase from grass.gunittest.gmodules import SimpleModule diff --git a/temporal/t.rast.aggregate/testsuite/test_aggregation_relative.py b/temporal/t.rast.aggregate/testsuite/test_aggregation_relative.py index 244b0d519d5..dc1da4c1cc3 100644 --- a/temporal/t.rast.aggregate/testsuite/test_aggregation_relative.py +++ b/temporal/t.rast.aggregate/testsuite/test_aggregation_relative.py @@ -10,7 +10,6 @@ import os -import grass.pygrass.modules as pymod import grass.temporal as tgis from grass.gunittest.case import TestCase from grass.gunittest.gmodules import SimpleModule diff --git a/temporal/t.rast.algebra/testsuite/test_raster_algebra_operators.py b/temporal/t.rast.algebra/testsuite/test_raster_algebra_operators.py index cf3d12a1aae..f07fabc9106 100644 --- a/temporal/t.rast.algebra/testsuite/test_raster_algebra_operators.py +++ b/temporal/t.rast.algebra/testsuite/test_raster_algebra_operators.py @@ -12,7 +12,6 @@ import grass.temporal as tgis from grass.gunittest.case import TestCase -from grass.gunittest.gmodules import SimpleModule from grass.gunittest.main import test diff --git a/temporal/t.rast.extract/testsuite/test_t_rast_extract.py b/temporal/t.rast.extract/testsuite/test_t_rast_extract.py index ca3c1a4c1db..b9fff4753c2 100644 --- a/temporal/t.rast.extract/testsuite/test_t_rast_extract.py +++ b/temporal/t.rast.extract/testsuite/test_t_rast_extract.py @@ -8,9 +8,6 @@ @author Soeren Gebbert """ -import subprocess - -import grass.pygrass.modules as pymod from grass.gunittest.case import TestCase from grass.gunittest.gmodules import SimpleModule diff --git a/temporal/t.rast.gapfill/testsuite/test_gapfill.py b/temporal/t.rast.gapfill/testsuite/test_gapfill.py index 7b083617d08..bfc8f48f581 100644 --- a/temporal/t.rast.gapfill/testsuite/test_gapfill.py +++ b/temporal/t.rast.gapfill/testsuite/test_gapfill.py @@ -8,8 +8,6 @@ @author Soeren Gebbert """ -import subprocess - from grass.gunittest.case import TestCase from grass.gunittest.gmodules import SimpleModule from grass.gunittest.utils import xfail_windows diff --git a/temporal/t.rast.neighbors/testsuite/test_neighbors.py b/temporal/t.rast.neighbors/testsuite/test_neighbors.py index 414b009fb1d..b48df4df169 100644 --- a/temporal/t.rast.neighbors/testsuite/test_neighbors.py +++ b/temporal/t.rast.neighbors/testsuite/test_neighbors.py @@ -5,6 +5,7 @@ """ import os + import grass.temporal as tgis from grass.gunittest.case import TestCase from grass.gunittest.gmodules import SimpleModule diff --git a/temporal/t.rast.series/testsuite/test_series.py b/temporal/t.rast.series/testsuite/test_series.py index e936e10e0e7..97df7c048fc 100644 --- a/temporal/t.rast.series/testsuite/test_series.py +++ b/temporal/t.rast.series/testsuite/test_series.py @@ -10,7 +10,6 @@ import os -import grass.pygrass.modules as pymod import grass.temporal as tgis from grass.gunittest.case import TestCase from grass.gunittest.gmodules import SimpleModule diff --git a/temporal/t.rast.to.rast3/testsuite/test_strds_to_rast3.py b/temporal/t.rast.to.rast3/testsuite/test_strds_to_rast3.py index 3a6eb7d45cc..28853ecbff1 100644 --- a/temporal/t.rast.to.rast3/testsuite/test_strds_to_rast3.py +++ b/temporal/t.rast.to.rast3/testsuite/test_strds_to_rast3.py @@ -8,11 +8,7 @@ @author Soeren Gebbert """ -import subprocess - -import grass.pygrass.modules as pymod from grass.gunittest.case import TestCase -from grass.gunittest.gmodules import SimpleModule class TestSTRDSToRast3(TestCase): diff --git a/temporal/t.rast.to.vect/testsuite/test_to_vect.py b/temporal/t.rast.to.vect/testsuite/test_to_vect.py index 2217b46a909..b429d8bf0dc 100644 --- a/temporal/t.rast.to.vect/testsuite/test_to_vect.py +++ b/temporal/t.rast.to.vect/testsuite/test_to_vect.py @@ -8,8 +8,6 @@ @author Soeren Gebbert """ -import subprocess - from grass.gunittest.case import TestCase from grass.gunittest.gmodules import SimpleModule diff --git a/temporal/t.rast.univar/testsuite/test_t_rast_univar.py b/temporal/t.rast.univar/testsuite/test_t_rast_univar.py index 17831b9b5b9..83e5c2d6229 100644 --- a/temporal/t.rast.univar/testsuite/test_t_rast_univar.py +++ b/temporal/t.rast.univar/testsuite/test_t_rast_univar.py @@ -9,6 +9,7 @@ """ from pathlib import Path + from grass.gunittest.case import TestCase from grass.gunittest.gmodules import SimpleModule from grass.gunittest.utils import xfail_windows diff --git a/temporal/t.rast3d.extract/testsuite/test_t_rast3d_extract.py b/temporal/t.rast3d.extract/testsuite/test_t_rast3d_extract.py index 4f0d476e0e8..3ae010e8423 100644 --- a/temporal/t.rast3d.extract/testsuite/test_t_rast3d_extract.py +++ b/temporal/t.rast3d.extract/testsuite/test_t_rast3d_extract.py @@ -8,9 +8,6 @@ :authors: Soeren Gebbert """ -import subprocess - -import grass.pygrass.modules as pymod from grass.gunittest.case import TestCase from grass.gunittest.gmodules import SimpleModule diff --git a/temporal/t.rast3d.univar/testsuite/test_t_rast3d_univar.py b/temporal/t.rast3d.univar/testsuite/test_t_rast3d_univar.py index 4ca64e88442..21980921168 100644 --- a/temporal/t.rast3d.univar/testsuite/test_t_rast3d_univar.py +++ b/temporal/t.rast3d.univar/testsuite/test_t_rast3d_univar.py @@ -9,6 +9,7 @@ """ from pathlib import Path + from grass.gunittest.case import TestCase from grass.gunittest.gmodules import SimpleModule from grass.gunittest.utils import xfail_windows diff --git a/temporal/t.shift/testsuite/test_shift.py b/temporal/t.shift/testsuite/test_shift.py index ea28e165995..3d55b059b4c 100644 --- a/temporal/t.shift/testsuite/test_shift.py +++ b/temporal/t.shift/testsuite/test_shift.py @@ -10,10 +10,8 @@ import os -import grass.pygrass.modules as pymod import grass.temporal as tgis from grass.gunittest.case import TestCase -from grass.gunittest.gmodules import SimpleModule class TestShiftAbsoluteSTRDS(TestCase): diff --git a/temporal/t.snap/testsuite/test_snap.py b/temporal/t.snap/testsuite/test_snap.py index 36a71c420bf..e46e25c454d 100644 --- a/temporal/t.snap/testsuite/test_snap.py +++ b/temporal/t.snap/testsuite/test_snap.py @@ -10,10 +10,8 @@ import os -import grass.pygrass.modules as pymod import grass.temporal as tgis from grass.gunittest.case import TestCase -from grass.gunittest.gmodules import SimpleModule class TestSnapAbsoluteSTRDS(TestCase): diff --git a/temporal/t.support/testsuite/test_support_str3ds.py b/temporal/t.support/testsuite/test_support_str3ds.py index 928826dbd72..533a9649692 100644 --- a/temporal/t.support/testsuite/test_support_str3ds.py +++ b/temporal/t.support/testsuite/test_support_str3ds.py @@ -10,10 +10,8 @@ import os -import grass.pygrass.modules as pymod import grass.temporal as tgis from grass.gunittest.case import TestCase -from grass.gunittest.gmodules import SimpleModule class TestSupportAbsoluteSTR3DS(TestCase): diff --git a/temporal/t.support/testsuite/test_support_strds.py b/temporal/t.support/testsuite/test_support_strds.py index f5e9ac3aa29..397a4a5e88d 100644 --- a/temporal/t.support/testsuite/test_support_strds.py +++ b/temporal/t.support/testsuite/test_support_strds.py @@ -10,10 +10,8 @@ import os -import grass.pygrass.modules as pymod import grass.temporal as tgis from grass.gunittest.case import TestCase -from grass.gunittest.gmodules import SimpleModule class TestSupportAbsoluteSTRDS(TestCase): diff --git a/temporal/t.support/testsuite/test_support_stvds.py b/temporal/t.support/testsuite/test_support_stvds.py index 2b6e347dead..b7ecc1aee01 100644 --- a/temporal/t.support/testsuite/test_support_stvds.py +++ b/temporal/t.support/testsuite/test_support_stvds.py @@ -10,10 +10,8 @@ import os -import grass.pygrass.modules as pymod import grass.temporal as tgis from grass.gunittest.case import TestCase -from grass.gunittest.gmodules import SimpleModule class TestSupportAbsoluteSTVDS(TestCase): diff --git a/temporal/t.unregister/testsuite/test_unregister.py b/temporal/t.unregister/testsuite/test_unregister.py index a32d33c1f32..b0102095e3d 100644 --- a/temporal/t.unregister/testsuite/test_unregister.py +++ b/temporal/t.unregister/testsuite/test_unregister.py @@ -10,7 +10,6 @@ import os -import grass.pygrass.modules as pymod import grass.temporal as tgis from grass.gunittest.case import TestCase from grass.gunittest.gmodules import SimpleModule diff --git a/vector/v.extract/testsuite/test_v_extract.py b/vector/v.extract/testsuite/test_v_extract.py index 958f153d1a3..c46505a5527 100644 --- a/vector/v.extract/testsuite/test_v_extract.py +++ b/vector/v.extract/testsuite/test_v_extract.py @@ -11,7 +11,6 @@ import os from grass.gunittest.case import TestCase -from grass.gunittest.gmodules import SimpleModule from grass.script.core import read_command TABLE_1 = """cat|MAJORRDS_|ROAD_NAME|MULTILANE|PROPYEAR|OBJECTID|SHAPE_LEN diff --git a/vector/v.fill.holes/examples.ipynb b/vector/v.fill.holes/examples.ipynb index fcc006501e4..a6b3ea746ce 100644 --- a/vector/v.fill.holes/examples.ipynb +++ b/vector/v.fill.holes/examples.ipynb @@ -15,12 +15,10 @@ "metadata": {}, "outputs": [], "source": [ - "import os\n", "import sys\n", "\n", "from IPython.display import Image\n", "\n", - "import grass.script as gs\n", "import grass.jupyter as gj" ] }, diff --git a/vector/v.in.ogr/testsuite/test_v_in_ogr.py b/vector/v.in.ogr/testsuite/test_v_in_ogr.py index 167cd8747e8..31d2ef7ef3b 100644 --- a/vector/v.in.ogr/testsuite/test_v_in_ogr.py +++ b/vector/v.in.ogr/testsuite/test_v_in_ogr.py @@ -4,7 +4,6 @@ """ from grass.gunittest.case import TestCase -from grass.gunittest.gmodules import SimpleModule class TestOgrImport(TestCase): From 058270914eafaf09b4b7e8c49c0590936890d0a2 Mon Sep 17 00:00:00 2001 From: Arohan Ajit Date: Wed, 23 Oct 2024 17:13:03 -0400 Subject: [PATCH 15/55] wxGUI: Fixed F841 in psmap/ (#4574) --- .flake8 | 6 +-- gui/wxpython/psmap/dialogs.py | 24 +--------- gui/wxpython/psmap/frame.py | 74 +++++++++++++++--------------- gui/wxpython/psmap/instructions.py | 2 +- 4 files changed, 41 insertions(+), 65 deletions(-) diff --git a/.flake8 b/.flake8 index 9985b8e5a42..5d951306ad1 100644 --- a/.flake8 +++ b/.flake8 @@ -24,9 +24,9 @@ per-file-ignores = gui/scripts/d.wms.py: E501 gui/wxpython/image2target/g.gui.image2target.py: E501 gui/wxpython/nviz/*: E722 - gui/wxpython/photo2image/*: E722 - gui/wxpython/photo2image/g.gui.photo2image.py: E501 - gui/wxpython/psmap/*: F841, E266, E722 + gui/wxpython/photo2image/*: F841, E722, E265 + gui/wxpython/photo2image/g.gui.photo2image.py: E501, F841 + gui/wxpython/psmap/*: E501, E722 gui/wxpython/vdigit/*: F841, E722, F405, F403 gui/wxpython/animation/g.gui.animation.py: E501 gui/wxpython/tplot/frame.py: F841, E722 diff --git a/gui/wxpython/psmap/dialogs.py b/gui/wxpython/psmap/dialogs.py index c4784525cc9..f086d65dd36 100644 --- a/gui/wxpython/psmap/dialogs.py +++ b/gui/wxpython/psmap/dialogs.py @@ -5731,8 +5731,6 @@ def updateDialog(self): y = self.unitConv.convert(value=y, fromUnit="inch", toUnit=currUnit) self.positionPanel.position["xCtrl"].SetValue("%5.3f" % x) self.positionPanel.position["yCtrl"].SetValue("%5.3f" % y) - # EN coordinates - e, n = self.textDict["east"], self.textDict["north"] self.positionPanel.position["eCtrl"].SetValue(str(self.textDict["east"])) self.positionPanel.position["nCtrl"].SetValue(str(self.textDict["north"])) @@ -6027,7 +6025,7 @@ def OnImageSelectionChanged(self, event): pImg = PILImage.open(file) img = PilImageToWxImage(pImg) except OSError as e: - GError(message=_("Unable to read file %s") % file) + GError(message=_("Unable to read file %s: %s") % (file, str(e))) self.ClearPreview() return self.SetSizeInfoLabel(img) @@ -6140,15 +6138,6 @@ def update(self): else: self.imageDict["XY"] = False - if self.positionPanel.position["eCtrl"].GetValue(): - e = self.positionPanel.position["eCtrl"].GetValue() - else: - self.imageDict["east"] = self.imageDict["east"] - - if self.positionPanel.position["nCtrl"].GetValue(): - n = self.positionPanel.position["nCtrl"].GetValue() - else: - self.imageDict["north"] = self.imageDict["north"] x, y = PaperMapCoordinates( mapInstr=self.instruction[self.mapId], @@ -6211,7 +6200,6 @@ def updateDialog(self): self.positionPanel.position["xCtrl"].SetValue("%5.3f" % x) self.positionPanel.position["yCtrl"].SetValue("%5.3f" % y) # EN coordinates - e, n = self.imageDict["east"], self.imageDict["north"] self.positionPanel.position["eCtrl"].SetValue(str(self.imageDict["east"])) self.positionPanel.position["nCtrl"].SetValue(str(self.imageDict["north"])) @@ -6526,15 +6514,6 @@ def update(self): else: self.pointDict["XY"] = False - if self.positionPanel.position["eCtrl"].GetValue(): - e = self.positionPanel.position["eCtrl"].GetValue() - else: - self.pointDict["east"] = self.pointDict["east"] - - if self.positionPanel.position["nCtrl"].GetValue(): - n = self.positionPanel.position["nCtrl"].GetValue() - else: - self.pointDict["north"] = self.pointDict["north"] x, y = PaperMapCoordinates( mapInstr=self.instruction[self.mapId], @@ -6590,7 +6569,6 @@ def updateDialog(self): self.positionPanel.position["xCtrl"].SetValue("%5.3f" % x) self.positionPanel.position["yCtrl"].SetValue("%5.3f" % y) # EN coordinates - e, n = self.pointDict["east"], self.pointDict["north"] self.positionPanel.position["eCtrl"].SetValue(str(self.pointDict["east"])) self.positionPanel.position["nCtrl"].SetValue(str(self.pointDict["north"])) diff --git a/gui/wxpython/psmap/frame.py b/gui/wxpython/psmap/frame.py index 1d937483123..e86b277252c 100644 --- a/gui/wxpython/psmap/frame.py +++ b/gui/wxpython/psmap/frame.py @@ -195,7 +195,6 @@ def __init__( self.getInitMap() # image path - env = gs.gisenv() self.imgName = gs.tempfile() # canvas for preview @@ -513,45 +512,44 @@ def OnCmdDone(self, event): env=self.env, ) # wx.BusyInfo does not display the message - busy = wx.BusyInfo(_("Generating preview, wait please"), parent=self) - wx.GetApp().Yield() - try: - im = PILImage.open(event.userData["filename"]) - if self.instruction[self.pageId]["Orientation"] == "Landscape": - import numpy as np - - im_array = np.array(im) - im = PILImage.fromarray(np.rot90(im_array, 3)) - im.save(self.imgName, format="PNG") - except OSError: - del busy - program = self._getGhostscriptProgramName() - dlg = HyperlinkDialog( - self, - title=_("Preview not available"), - message=_( - "Preview is not available probably because Ghostscript is not " - "installed or not on PATH." - ), - hyperlink="https://www.ghostscript.com/releases/gsdnld.html", - hyperlinkLabel=_( - "You can download {program} {arch} version here." - ).format( - program=program, - arch="64bit" if "64" in program else "32bit", - ), - ) - dlg.ShowModal() - dlg.Destroy() - return + with wx.BusyInfo(_("Generating preview, wait please"), parent=self): + wx.GetApp().Yield() + try: + im = PILImage.open(event.userData["filename"]) + if self.instruction[self.pageId]["Orientation"] == "Landscape": + import numpy as np + + im_array = np.array(im) + im = PILImage.fromarray(np.rot90(im_array, 3)) + im.save(self.imgName, format="PNG") + except OSError: + del busy + program = self._getGhostscriptProgramName() + dlg = HyperlinkDialog( + self, + title=_("Preview not available"), + message=_( + "Preview is not available probably because Ghostscript is not " + "installed or not on PATH." + ), + hyperlink="https://www.ghostscript.com/releases/gsdnld.html", + hyperlinkLabel=_( + "You can download {program} {arch} version here." + ).format( + program=program, + arch="64bit" if "64" in program else "32bit", + ), + ) + dlg.ShowModal() + dlg.Destroy() + return - self.book.SetSelection(1) - self.currentPage = 1 - rect = self.previewCanvas.ImageRect() - self.previewCanvas.image = wx.Image(self.imgName, wx.BITMAP_TYPE_PNG) - self.previewCanvas.DrawImage(rect=rect) + self.book.SetSelection(1) + self.currentPage = 1 + rect = self.previewCanvas.ImageRect() + self.previewCanvas.image = wx.Image(self.imgName, wx.BITMAP_TYPE_PNG) + self.previewCanvas.DrawImage(rect=rect) - del busy self.SetStatusText(_("Preview generated"), 0) gs.try_remove(event.userData["instrFile"]) diff --git a/gui/wxpython/psmap/instructions.py b/gui/wxpython/psmap/instructions.py index 845e99b2e6a..82560353806 100644 --- a/gui/wxpython/psmap/instructions.py +++ b/gui/wxpython/psmap/instructions.py @@ -1751,7 +1751,7 @@ def EstimateHeight(self, raster, discrete, fontsize, cols=None, height=None): rinfo = gs.raster_info(raster) if rinfo["datatype"] in {"DCELL", "FCELL"}: - minim, maxim = rinfo["min"], rinfo["max"] + maxim = rinfo["max"] rows = ceil(maxim / cols) else: cat = ( From 3d7b331ba8e059217e8f6c7d1a6b2d13e6e4781e Mon Sep 17 00:00:00 2001 From: Arohan Ajit Date: Wed, 23 Oct 2024 17:17:00 -0400 Subject: [PATCH 16/55] r.in.srtm: Fix exception handling and add specific error types (#4571) --- .flake8 | 1 - scripts/r.in.srtm/r.in.srtm.py | 5 +++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.flake8 b/.flake8 index 5d951306ad1..7bc3070d15e 100644 --- a/.flake8 +++ b/.flake8 @@ -102,7 +102,6 @@ per-file-ignores = scripts/db.univar/db.univar.py: E501 scripts/d.frame/d.frame.py: E722 scripts/i.pansharpen/i.pansharpen.py: E722, E501 - scripts/r.in.srtm/r.in.srtm.py: E722 scripts/r.fillnulls/r.fillnulls.py: E722 scripts/v.what.strds/v.what.strds.py: E501 # Line too long (esp. module interface definitions) diff --git a/scripts/r.in.srtm/r.in.srtm.py b/scripts/r.in.srtm/r.in.srtm.py index b9f51415ca0..49c7cef9758 100755 --- a/scripts/r.in.srtm/r.in.srtm.py +++ b/scripts/r.in.srtm/r.in.srtm.py @@ -76,6 +76,7 @@ import atexit import grass.script as gs import zipfile as zfile +from grass.exceptions import CalledModuleError tmpl1sec = """BYTEORDER M @@ -227,7 +228,7 @@ def main(): try: zf = zfile.ZipFile(zipfile) zf.extractall() - except: + except (zfile.BadZipfile, zfile.LargeZipFile, PermissionError): gs.fatal(_("Unable to unzip file.")) gs.message(_("Converting input file to BIL...")) @@ -274,7 +275,7 @@ def main(): try: gs.run_command("r.in.gdal", input=bilfile, out=tileout) - except: + except CalledModuleError: gs.fatal(_("Unable to import data")) # nice color table From cc0fb732328f6f3a0137eddcd937c7c3e2badcab Mon Sep 17 00:00:00 2001 From: Moritz Lennert Date: Thu, 24 Oct 2024 17:39:24 +0200 Subject: [PATCH 17/55] i.segment.html: parameter names and links to other modules (#4483) --- imagery/i.segment/i.segment.html | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/imagery/i.segment/i.segment.html b/imagery/i.segment/i.segment.html index e30f21d3743..43d5e5fde68 100644 --- a/imagery/i.segment/i.segment.html +++ b/imagery/i.segment/i.segment.html @@ -100,11 +100,11 @@

Goodness of Fit

Mean shift

Mean shift image segmentation consists of 2 steps: anisotrophic filtering and 2. clustering. For anisotrophic filtering new cell values -are calculated from all pixels not farther than hs pixels away +are calculated from all pixels not farther than radius pixels away from the current pixel and with a spectral difference not larger than hr. That means that pixels that are too different from the current pixel are not considered in the calculation of new pixel values. -hs and hr are the spatial and spectral (range) bandwidths +radius and hr are the spatial and spectral (range) bandwidths for anisotrophic filtering. Cell values are iteratively recalculated (shifted to the segment's mean) until the maximum number of iterations is reached or until the largest shift is smaller than threshold. @@ -251,8 +251,6 @@

Functionality

Use of Segmentation Results

    -
  • Improve the optional output from this module, or better yet, add a -module for i.segment.metrics.
  • Providing updates to i.maxlik to ensure the segmentation output can be used as input for the existing classification functionality.
  • @@ -277,6 +275,9 @@

    REFERENCES

    SEE ALSO

    +i.segment.stats (addon), +i.segment.uspo (addon), +i.segment.hierarchical (addon) g.gui.iclass, i.group, i.maxlik, From 0860b87ec7b6f69ae48319bbee151857947cc15e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 24 Oct 2024 23:53:58 -0400 Subject: [PATCH 18/55] CI(deps): Update ruff to v0.7.1 (#4587) --- .github/workflows/python-code-quality.yml | 2 +- .pre-commit-config.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/python-code-quality.yml b/.github/workflows/python-code-quality.yml index 94a8d0be26b..9aaa37a7db1 100644 --- a/.github/workflows/python-code-quality.yml +++ b/.github/workflows/python-code-quality.yml @@ -36,7 +36,7 @@ jobs: # renovate: datasource=pypi depName=bandit BANDIT_VERSION: "1.7.10" # renovate: datasource=pypi depName=ruff - RUFF_VERSION: "0.7.0" + RUFF_VERSION: "0.7.1" runs-on: ${{ matrix.os }} permissions: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4c82e138950..2f3216877de 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -37,7 +37,7 @@ repos: ) - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.7.0 + rev: v0.7.1 hooks: # Run the linter. - id: ruff From bbe66e460d19d1e6ca3d51694a1c1aaf350bd8ed Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 24 Oct 2024 23:54:27 -0400 Subject: [PATCH 19/55] CI(deps): Update actions/setup-python action to v5.3.0 (#4583) --- .github/workflows/additional_checks.yml | 2 +- .github/workflows/codeql-analysis.yml | 2 +- .github/workflows/create_release_draft.yml | 2 +- .github/workflows/pytest.yml | 2 +- .github/workflows/python-code-quality.yml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/additional_checks.yml b/.github/workflows/additional_checks.yml index a2fbfadc36f..76554f24db3 100644 --- a/.github/workflows/additional_checks.yml +++ b/.github/workflows/additional_checks.yml @@ -43,7 +43,7 @@ jobs: exclude: mswindows .*\.bat .*/testsuite/data/.* - name: Set up Python - uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0 + uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 with: python-version: '3.10' diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 9c161300170..d98950b0818 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -42,7 +42,7 @@ jobs: - name: Checkout repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Set up Python - uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0 + uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 with: python-version: '3.x' - name: Install non-Python dependencies diff --git a/.github/workflows/create_release_draft.yml b/.github/workflows/create_release_draft.yml index 6c3597599fc..efefb0fd0c7 100644 --- a/.github/workflows/create_release_draft.yml +++ b/.github/workflows/create_release_draft.yml @@ -35,7 +35,7 @@ jobs: ref: ${{ github.ref }} fetch-depth: 0 - name: Set up Python - uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0 + uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 with: python-version: '3.11' - name: Create output directory diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index b28fb40ad14..3fea65773ce 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -35,7 +35,7 @@ jobs: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Set up Python - uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0 + uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 with: python-version: ${{ matrix.python-version }} cache: pip diff --git a/.github/workflows/python-code-quality.yml b/.github/workflows/python-code-quality.yml index 9aaa37a7db1..aa6bd33724f 100644 --- a/.github/workflows/python-code-quality.yml +++ b/.github/workflows/python-code-quality.yml @@ -57,7 +57,7 @@ jobs: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Set up Python - uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0 + uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 with: python-version: ${{ env.PYTHON_VERSION }} cache: pip From b6514ca8afc5b82a080f3b694a49a8684ff4defc Mon Sep 17 00:00:00 2001 From: Makiko Shukunobe Date: Thu, 24 Oct 2024 23:56:18 -0400 Subject: [PATCH 20/55] tests: Add regression test for r.his (#4572) * Add tests to r.his * Add assertRasterFitsUnivar * Update assertRasterFitsUnivar * Add g.region to make r.univar values consistent * Update raster/r.his/testsuite/test_r_his.py Apply the suggestion. Co-authored-by: Anna Petrasova * Update raster/r.his/testsuite/test_r_his.py Apply the suggestion. Co-authored-by: Anna Petrasova * Update raster/r.his/testsuite/test_r_his.py Black styling --------- Co-authored-by: Anna Petrasova --- raster/r.his/testsuite/test_r_his.py | 91 ++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 raster/r.his/testsuite/test_r_his.py diff --git a/raster/r.his/testsuite/test_r_his.py b/raster/r.his/testsuite/test_r_his.py new file mode 100644 index 00000000000..da56d633b6d --- /dev/null +++ b/raster/r.his/testsuite/test_r_his.py @@ -0,0 +1,91 @@ +from grass.gunittest.case import TestCase +from grass.gunittest.main import test + + +class TestRHis(TestCase): + hue = "elevation" + intensity = "elevation_shaded_50" + saturation = "elevation" + red = "shadedmap_r" + green = "shadedmap_g" + blue = "shadedmap_b" + bgcolor = "none" + + @classmethod + def setUpClass(cls): + cls.use_temp_region() + cls.runModule("g.region", raster="elevation") + cls.elev_shade = "elevation_shaded_relief" + cls.runModule("r.relief", input="elevation", output=cls.elev_shade) + cls.runModule( + "r.mapcalc", expression=f"{cls.intensity} = {cls.elev_shade} * 1.5" + ) + cls.runModule("r.colors", map=cls.intensity, color="grey255") + + @classmethod + def tearDownClass(cls): + cls.runModule( + "g.remove", type="raster", flags="f", name=[cls.intensity, cls.elev_shade] + ) + cls.del_temp_region() + + def tearDown(self): + """Remove d.his generated rasters after each test method""" + self.runModule("g.remove", type="raster", flags="f", pattern="shadedmap_*") + + def test_bgcolor_none(self): + """Test r.his with bgcolor 'none'""" + self.runModule( + "r.his", + hue=self.hue, + intensity=self.intensity, + saturation=self.saturation, + red=self.red, + green=self.green, + blue=self.blue, + bgcolor=self.bgcolor, + ) + + red_value = "null_cells=5696\nmin=3\nmax=255\nmean=156.41168\nstddev=34.434612" + blue_value = "null_cells=5696\nmin=0\nmax=127\nmean=36.05560\nstddev=37.61216" + green_value = "null_cells=5696\nmin=1\nmax=255\nmean=129.62880\nstddev=34.48307" + + self.assertRasterFitsUnivar( + raster=self.red, reference=red_value, precision=1e-5 + ) + self.assertRasterFitsUnivar( + raster=self.blue, reference=blue_value, precision=1e-5 + ) + self.assertRasterFitsUnivar( + raster=self.green, reference=green_value, precision=1e-5 + ) + + def test_with_bgcolor_rgb(self): + """Test r.his with bgcolor '0:0:0'""" + self.runModule( + "r.his", + hue=self.hue, + intensity=self.intensity, + saturation=self.saturation, + red=self.red, + green=self.green, + blue=self.blue, + bgcolor="0:0:0", + ) + + red_value = "null_cells=0\nmin=0\nmax=255\nmean=155.97172\nstddev=35.36988" + blue_value = "null_cells=0\nmin=0\nmax=127\nmean=35.95417\nstddev=37.60774" + green_value = "null_cells=0\nmin=0\nmax=255\nmean=129.26418\nstddev=35.11225" + self.assertRasterFitsUnivar( + raster=self.red, reference=red_value, precision=1e-5 + ) + self.assertRasterFitsUnivar( + raster=self.blue, reference=blue_value, precision=1e-5 + ) + self.assertRasterFitsUnivar( + raster=self.green, reference=green_value, precision=1e-5 + ) + + +if __import__("__main__"): + test() From 5b94314a82de7e9c78fd6044659ea9d6c2323edb Mon Sep 17 00:00:00 2001 From: Markus Neteler Date: Fri, 25 Oct 2024 16:16:09 +0200 Subject: [PATCH 21/55] manual: mention raster semantic labels and multiple http/https fixes (#4591) * r.support/i.band.library/r.semantic.label: better mention raster semantic labels * v.db.reconnect.all: add missing keywords * URLs: selectively change http to https; fix a few broken URLs --- AUTHORS | 2 +- REQUIREMENTS.md | 4 ++-- TODO | 4 ++-- binaryInstall.src | 2 +- configure.ac | 2 +- db/drivers/mysql/grass-mesql.html | 2 +- db/drivers/mysql/grass-mysql.html | 2 +- db/drivers/odbc/INSTALL | 2 +- db/drivers/odbc/grass-odbc.html | 6 ++--- db/drivers/postgres/README | 2 +- db/drivers/postgres/grass-pg.html | 10 ++++---- db/drivers/sqlite/README | 2 +- db/drivers/sqlite/fetch.c | 2 +- db/drivers/sqlite/grass-sqlite.html | 12 +++++----- doc/debugging.txt | 2 +- doc/development/rfc/PSC_guidelines.md | 2 +- doc/development/rfc/PSC_voting_procedures.md | 6 ++--- .../legal_aspects_of_code_contributions.md | 2 +- doc/development/style_guide.md | 4 ++-- doc/gui/wxpython/example/g.gui.example.html | 2 +- doc/vector/TODO | 10 ++++---- general/g.list/g.list.html | 2 +- general/g.version/g.version.html | 4 ++-- gui/wxpython/animation/dialogs.py | 2 +- gui/wxpython/animation/g.gui.animation.html | 2 +- gui/wxpython/core/settings.py | 2 +- gui/wxpython/docs/wxGUI.html | 2 +- gui/wxpython/docs/wxgui_sphinx/src/index.rst | 2 +- gui/wxpython/iclass/dialogs.py | 2 +- gui/wxpython/iclass/g.gui.iclass.html | 6 ++--- gui/wxpython/iscatt/iscatt_core.py | 4 ++-- gui/wxpython/iscatt/plots.py | 2 +- gui/wxpython/mapswipe/g.gui.mapswipe.html | 2 +- gui/wxpython/timeline/frame.py | 2 +- gui/wxpython/timeline/g.gui.timeline.html | 4 ++-- gui/wxpython/tplot/frame.py | 2 +- gui/wxpython/tplot/g.gui.tplot.html | 2 +- imagery/i.atcorr/i.atcorr.html | 4 ++-- imagery/i.biomass/i.biomass.html | 2 +- imagery/i.cluster/i.cluster.html | 2 +- imagery/i.eb.eta/i.eb.eta.html | 6 ++--- imagery/i.eb.evapfr/i.eb.evapfr.html | 6 ++--- imagery/i.eb.hsebal01/i.eb.hsebal01.html | 6 ++--- imagery/i.eb.netrad/i.eb.netrad.html | 4 ++-- .../i.eb.soilheatflux/i.eb.soilheatflux.html | 6 ++--- imagery/i.emissivity/i.emissivity.html | 2 +- imagery/i.fft/i.fft.html | 4 ++-- imagery/i.ifft/i.ifft.html | 2 +- imagery/i.landsat.toar/i.landsat.toar.html | 2 +- imagery/i.ortho.photo/README | 2 +- imagery/i.ortho.photo/lib/TODO | 2 +- imagery/i.rectify/i.rectify.html | 4 ++-- imagery/i.vi/evi2.c | 2 +- imagery/i.vi/i.vi.html | 10 ++++---- imagery/imageryintro.html | 2 +- include/Make/Doxyfile_arch_html.in | 12 +++++----- include/Make/Doxyfile_arch_latex.in | 12 +++++----- include/grass/defs/gprojects.h | 2 +- include/grass/gprojects.h | 2 +- lib/cairodriver/cairodriver.dox | 2 +- lib/db/README | 2 +- lib/db/dbmi_base/default_name.c | 2 +- lib/db/dbmilib.dox | 6 ++--- lib/db/sqlp/sql.html | 8 +++---- lib/gmath/gmathlib.dox | 4 ++-- lib/init/variables.html | 2 +- lib/vector/Vlib/buffer2.c | 2 +- lib/vector/Vlib/legal_vname.c | 2 +- lib/vector/vectorlib_pg.dox | 4 ++-- locale/po/grassmods_ar.po | 2 +- locale/po/grassmods_bn.po | 2 +- locale/po/grassmods_cs.po | 2 +- locale/po/grassmods_de.po | 2 +- locale/po/grassmods_el.po | 2 +- locale/po/grassmods_es.po | 2 +- locale/po/grassmods_fi.po | 2 +- locale/po/grassmods_fr.po | 2 +- locale/po/grassmods_hu.po | 2 +- locale/po/grassmods_id_ID.po | 2 +- locale/po/grassmods_it.po | 2 +- locale/po/grassmods_ja.po | 2 +- locale/po/grassmods_ko.po | 2 +- locale/po/grassmods_lv.po | 2 +- locale/po/grassmods_ml.po | 2 +- locale/po/grassmods_pl.po | 2 +- locale/po/grassmods_pt.po | 2 +- locale/po/grassmods_pt_BR.po | 2 +- locale/po/grassmods_ro.po | 2 +- locale/po/grassmods_ru.po | 2 +- locale/po/grassmods_si.po | 2 +- locale/po/grassmods_sl.po | 2 +- locale/po/grassmods_ta.po | 2 +- locale/po/grassmods_th.po | 2 +- locale/po/grassmods_tr.po | 2 +- locale/po/grassmods_uk.po | 2 +- locale/po/grassmods_vi.po | 2 +- locale/po/grassmods_zh.po | 2 +- locale/po/grassmods_zh_CN.po | 2 +- locale/templates/grassmods.pot | 2 +- macosx/ReadMe.md | 2 +- mswindows/README.html | 2 +- mswindows/external/rbatch/R.bat | 4 ++-- mswindows/external/rbatch/README.grass | 2 +- mswindows/external/rbatch/Rpathset.bat | 2 +- mswindows/external/rbatch/batchfiles.md | 2 +- mswindows/external/rbatch/batchfiles.tex | 2 +- mswindows/external/rbatch/copydir.bat | 2 +- mswindows/external/rbatch/movedir.bat | 2 +- python/grass/docs/src/pygrass_index.rst | 4 ++-- python/grass/docs/src/pygrass_modules.rst | 2 +- python/grass/docs/src/temporal_framework.rst | 2 +- python/grass/gunittest/reporters.py | 2 +- python/grass/imaging/images2gif.py | 2 +- .../grass/pygrass/modules/interface/module.py | 2 +- python/grass/script/utils.py | 2 +- .../ctypesgen/parser/yacc.py | 2 +- .../ctypesgen/printer_json/printer.py | 2 +- raster/r.buildvrt/r.buildvrt.html | 4 ++-- raster/r.composite/r.composite.html | 2 +- raster/r.external.out/r.external.out.html | 2 +- raster/r.external/r.external.html | 2 +- raster/r.fill.stats/r.fill.stats.html | 2 +- raster/r.geomorphon/r.geomorphon.html | 2 +- raster/r.grow.distance/r.grow.distance.html | 4 ++-- raster/r.in.gdal/r.in.gdal.html | 6 ++--- raster/r.in.xyz/r.in.xyz.html | 2 +- raster/r.out.gdal/r.out.gdal.html | 10 ++++---- raster/r.out.mpeg/r.out.mpeg.html | 2 +- raster/r.resamp.filter/r.resamp.filter.html | 4 ++-- .../r.sim/r.sim.sediment/r.sim.sediment.html | 2 +- raster/r.sim/r.sim.water/r.sim.water.html | 2 +- raster/r.stream.extract/r.stream.extract.html | 2 +- raster/r.sun/TODO | 4 ++-- raster/r.sun/r.sun.html | 2 +- raster/r.support/r.support.html | 13 ++++++---- raster/r.surf.fractal/r.surf.fractal.html | 2 +- raster/r.watershed/front/r.watershed.html | 8 +++---- raster3d/r3.flow/r3.flow.html | 2 +- raster3d/r3.out.netcdf/main.c | 2 +- raster3d/r3.out.netcdf/r3.out.netcdf.html | 2 +- scripts/d.polar/d.polar.html | 2 +- scripts/db.in.ogr/db.in.ogr.html | 4 ++-- scripts/i.band.library/i.band.library.html | 10 ++++---- scripts/i.in.spotvgt/i.in.spotvgt.py | 6 ++--- scripts/i.pansharpen/i.pansharpen.html | 2 +- scripts/r.grow/r.grow.html | 4 ++-- scripts/r.in.wms/r.in.wms.html | 2 +- .../r.semantic.label/r.semantic.label.html | 8 +++---- scripts/v.db.dropcolumn/v.db.dropcolumn.py | 2 +- scripts/v.db.join/v.db.join.html | 6 ++--- .../v.db.reconnect.all/v.db.reconnect.all.py | 2 ++ scripts/v.import/v.import.html | 8 +++---- scripts/v.in.e00/v.in.e00.html | 2 +- scripts/v.in.geonames/v.in.geonames.html | 2 +- temporal/t.rast.algebra/t.rast.algebra.html | 4 ++-- temporal/temporalintro.html | 4 ++-- vector/v.buffer/v.buffer.html | 2 +- vector/v.cluster/v.cluster.html | 4 ++-- vector/v.external.out/v.external.out.html | 14 +++++------ vector/v.external/v.external.html | 4 ++-- vector/v.in.dxf/v.in.dxf.html | 2 +- vector/v.kernel/v.kernel.html | 6 ++--- vector/v.label.sa/v.label.sa.html | 2 +- vector/v.net.bridge/v.net.bridge.html | 4 ++-- vector/v.net.centrality/v.net.centrality.html | 2 +- vector/v.net.flow/v.net.flow.html | 2 +- vector/v.net/v.net.html | 2 +- vector/v.out.ascii/v.out.ascii.html | 2 +- vector/v.out.dxf/v.out.dxf.html | 2 +- vector/v.out.ogr/v.out.ogr.html | 24 +++++++++---------- vector/v.out.postgis/v.out.postgis.html | 4 ++-- vector/v.surf.rst/v.surf.rst.html | 2 +- vector/v.univar/main.c | 2 +- vector/v.vol.rst/v.vol.rst.html | 2 +- vector/v.voronoi/v.voronoi.html | 2 +- 175 files changed, 296 insertions(+), 293 deletions(-) diff --git a/AUTHORS b/AUTHORS index a81f5a75e39..952b369702f 100644 --- a/AUTHORS +++ b/AUTHORS @@ -206,7 +206,7 @@ MS-Windows/Cygwin: Huidae Cho Source code Quality assessment system - SOCCER Labs at Ecole Polytechnique de Montreal, Canada http://web.soccerlab.polymtl.ca/grass-evolution/grass-browsers/grass-index-en.html - http://lists.osgeo.org/mailman/listinfo/grass-qa + https://lists.osgeo.org/mailman/listinfo/grass-qa GRASS 5.7/6.0: Primary authors of new source code diff --git a/REQUIREMENTS.md b/REQUIREMENTS.md index 7b2757d38f5..5d173133716 100644 --- a/REQUIREMENTS.md +++ b/REQUIREMENTS.md @@ -49,7 +49,7 @@ Note: also the respective development packages (commonly named `xxx-dev` or [https://facebook.github.io/zstd](https://facebook.github.io/zstd) - **FFTW 2.x or 3.x** (library for computing the Discrete Fourier Transform), required for `i.fft` and `i.ifft` and other modules - [http://www.fftw.org](http://www.fftw.org) + [https://fftw.org](https://fftw.org) - **GEOS** (Geometry Engine library), needed for `v.buffer` and adds extended options to the `v.select` module [https://libgeos.org/](https://libgeos.org/) @@ -81,7 +81,7 @@ Note: also the respective development packages (commonly named `xxx-dev` or - **SQLite libraries** (for the SQLite database interface) [https://www.sqlite.org](https://www.sqlite.org) - **unixODBC** (for the ODBC database interface) - [http://www.unixodbc.org](http://www.unixodbc.org) + [https://www.unixodbc.org](https://www.unixodbc.org) - **R Statistics** (for the R statistical language interface) [https://cran.r-project.org](https://cran.r-project.org) - **FreeType2** (for TrueType font support and `d.text.freetype`) diff --git a/TODO b/TODO index 510d38dfa6b..5750175258e 100644 --- a/TODO +++ b/TODO @@ -39,6 +39,6 @@ Imagery ----------------- See also -http://trac.osgeo.org/grass/wiki/Grass7Planning +https://trac.osgeo.org/grass/wiki/Grass7Planning -http://trac.osgeo.org/grass/wiki/Grass8Planning +https://trac.osgeo.org/grass/wiki/Grass8Planning diff --git a/binaryInstall.src b/binaryInstall.src index 5ab008dd796..2bcb3165327 100755 --- a/binaryInstall.src +++ b/binaryInstall.src @@ -109,7 +109,7 @@ if [ $? -eq 0 ] ; then IFS="$IFSSAVE" if [ ! "$GUNZIP" ] ; then echo "No gunzip installed. Please get from:" - echo " http://www.gnu.org/software/gzip/gzip.html" + echo " https://www.gnu.org/software/gzip/gzip.html" exit fi else diff --git a/configure.ac b/configure.ac index 52a985960c3..fc3403163da 100644 --- a/configure.ac +++ b/configure.ac @@ -15,7 +15,7 @@ # Public License (>=v2). Read the file COPYING that # comes with GRASS for details. # -# MANUAL: http://www.gnu.org/software/autoconf/manual/autoconf.html +# MANUAL: https://www.gnu.org/software/autoconf/manual/autoconf.html # http://savannah.gnu.org/projects/autoconf/ # Website for config.guess, config.sub: # wget http://git.savannah.gnu.org/cgit/config.git/plain/config.guess diff --git a/db/drivers/mysql/grass-mesql.html b/db/drivers/mysql/grass-mesql.html index 8e2aca2155c..e04b30a2a8f 100644 --- a/db/drivers/mysql/grass-mesql.html +++ b/db/drivers/mysql/grass-mesql.html @@ -83,7 +83,7 @@

    AUTHOR

    Credits: Development of the driver was sponsored by -Faunalia (Italy) +Faunalia (Italy) as part of a project for ATAC. diff --git a/db/drivers/mysql/grass-mysql.html b/db/drivers/mysql/grass-mysql.html index 60c7fbe4f78..af8c0273d98 100644 --- a/db/drivers/mysql/grass-mysql.html +++ b/db/drivers/mysql/grass-mysql.html @@ -116,7 +116,7 @@

    SEE ALSO

    Credits

    Development of the driver was sponsored by -Faunalia (Italy) +Faunalia (Italy) as part of a project for ATAC.

    AUTHOR

    diff --git a/db/drivers/odbc/INSTALL b/db/drivers/odbc/INSTALL index 74928ff55a6..3f485ee3f20 100644 --- a/db/drivers/odbc/INSTALL +++ b/db/drivers/odbc/INSTALL @@ -1,4 +1,4 @@ -1. Download, compile, install and configure ODBC (http://www.unixodbc.org/) +1. Download, compile, install and configure ODBC (https://www.unixodbc.org/) 2. Copy ODBC include files to /usr/include/odbc 3. Compile src/libes/dbmi/drivers/odbc 4. Add row for ODBC driver to dbmscap file diff --git a/db/drivers/odbc/grass-odbc.html b/db/drivers/odbc/grass-odbc.html index 7692893ca92..75a5ca578d7 100644 --- a/db/drivers/odbc/grass-odbc.html +++ b/db/drivers/odbc/grass-odbc.html @@ -95,10 +95,10 @@

    Linux

     ConnSettings            = Configuration of an DSN without GUI is described on -http://www.unixodbc.org/odbcinst.html, +https://www.unixodbc.org/odbcinst.html, but odbc.ini and .odbc.ini may be created by the 'ODBCConfig' tool. You can easily view your DSN structure by 'DataManager'. Configuration with -GUI is described on http://www.unixodbc.org/doc/UserManual/ +GUI is described on https://www.unixodbc.org/doc/UserManual/

    To find out about your PostgreSQL protocol, run:

    @@ -159,6 +159,6 @@ 

    SEE ALSO

    db.connect, v.db.connect, -unixODBC web site, +unixODBC web site, SQL support in GRASS GIS diff --git a/db/drivers/postgres/README b/db/drivers/postgres/README index 254a0fd28c9..a2959739f6e 100644 --- a/db/drivers/postgres/README +++ b/db/drivers/postgres/README @@ -19,7 +19,7 @@ Check also for PostgreSQL data types for defining them in GRASS: Supported types in ./globals.h: -(See http://www.postgresql.org/docs/9.4/interactive/datatype.html) +(See https://www.postgresql.org/docs/9.4/interactive/datatype.html) DB_C_TYPE_INT: bit, int2, smallint, int4, int, integer, int8, bigint, serial, oid diff --git a/db/drivers/postgres/grass-pg.html b/db/drivers/postgres/grass-pg.html index 72c292aade4..cb707fa9314 100644 --- a/db/drivers/postgres/grass-pg.html +++ b/db/drivers/postgres/grass-pg.html @@ -6,7 +6,7 @@

    Creating a PostgreSQL database

    A new database is created with createdb, see -the PostgreSQL +the PostgreSQL manual for details.

    Connecting GRASS to PostgreSQL

    @@ -120,7 +120,7 @@

    Geometry Converters

  • e00pg: E00 to PostGIS filter, see also v.in.e00.
  • -
  • GDAL/OGR ogrinfo and ogr2ogr: +
  • GDAL/OGR ogrinfo and ogr2ogr: GIS vector format converter and library, e.g. ArcInfo or SHAPE to PostGIS.
    ogr2ogr -f "PostgreSQL" shapefile ??
  • @@ -141,8 +141,8 @@

    SEE ALSO

    REFERENCES

    diff --git a/db/drivers/sqlite/README b/db/drivers/sqlite/README index b0c59be7d64..955cbede58a 100644 --- a/db/drivers/sqlite/README +++ b/db/drivers/sqlite/README @@ -14,7 +14,7 @@ db.connect driver=sqlite \ The database is created automatically when used first time. That is SQLite feature followed also in the driver. -SQLite uses "type affinity", (http://www.sqlite.org/datatype3.html) +SQLite uses "type affinity", (https://www.sqlite.org/datatype3.html) that means column types are recommended, but not required. If the driver in GRASS has to determine column type, it first reads diff --git a/db/drivers/sqlite/fetch.c b/db/drivers/sqlite/fetch.c index 8e020753293..44a62b4bb4d 100644 --- a/db/drivers/sqlite/fetch.c +++ b/db/drivers/sqlite/fetch.c @@ -130,7 +130,7 @@ int db__driver_fetch(dbCursor *cn, int position, int *more) G_debug(3, "col %d, litetype %d, sqltype %d: val = '%s'", col, litetype, sqltype, text); - /* http://www.sqlite.org/capi3ref.html#sqlite3_column_type + /* https://www.sqlite.org/capi3ref.html#sqlite3_column_type SQLITE_INTEGER 1 SQLITE_FLOAT 2 SQLITE_TEXT 3 diff --git a/db/drivers/sqlite/grass-sqlite.html b/db/drivers/sqlite/grass-sqlite.html index e746f5820c0..ae59def1e52 100644 --- a/db/drivers/sqlite/grass-sqlite.html +++ b/db/drivers/sqlite/grass-sqlite.html @@ -25,8 +25,8 @@

    Supported SQL commands

    All SQL commands supported by SQLite (for limitations, see SQLite help page: -SQL As Understood By SQLite and -Unsupported SQL). +SQL As Understood By SQLite and +Unsupported SQL).

    Operators available in conditions

    @@ -46,7 +46,7 @@

    Browsing table data in DB

    The algorithm uses input parameters set by the user on the diff --git a/imagery/i.eb.eta/i.eb.eta.html b/imagery/i.eb.eta/i.eb.eta.html index ff947cb1b43..7915c7eba1a 100644 --- a/imagery/i.eb.eta/i.eb.eta.html +++ b/imagery/i.eb.eta/i.eb.eta.html @@ -24,7 +24,7 @@

    REFERENCES

    [1] Bastiaanssen, W.G.M., 1995. Estimation of Land surface parameters by remote sensing under clear-sky conditions. PhD thesis, Wageningen University, Wageningen, The Netherlands. -(PDF) +(PDF)

    [2] Chemin Y., Alexandridis T.A., 2001. Improving spatial resolution of ET seasonal for irrigated rice in Zhanghe, China. Asian Journal of Geoinformatics. @@ -33,12 +33,12 @@

    REFERENCES

    [3] Alexandridis T.K., Cherif I., Chemin Y., Silleos N.G., Stavrinos E., Zalidis G.C. Integrated methodology for estimating water use in Mediterranean agricultural areas. Remote Sensing. 2009, 1, 445-465. -(PDF) +(PDF)

    [4] Chemin, Y., 2012. A Distributed Benchmarking Framework for Actual ET Models, in: Irmak, A. (Ed.), Evapotranspiration - Remote Sensing and Modeling. InTech. -(PDF) +(PDF)

    SEE ALSO

    diff --git a/imagery/i.eb.evapfr/i.eb.evapfr.html b/imagery/i.eb.evapfr/i.eb.evapfr.html index 8d6354f36f9..9e745534728 100644 --- a/imagery/i.eb.evapfr/i.eb.evapfr.html +++ b/imagery/i.eb.evapfr/i.eb.evapfr.html @@ -18,7 +18,7 @@

    REFERENCES

    Bastiaanssen, W.G.M., 1995. Estimation of Land surface parameters by remote sensing under clear-sky conditions. PhD thesis, Wageningen University, Wageningen, The Netherlands. -(PDF) +(PDF)

    Bastiaanssen, W.G.M., Molden, D.J., Makin, I.W., 2000. Remote sensing for irrigated agriculture: examples from research and @@ -32,12 +32,12 @@

    REFERENCES

    Zalidis G.C., 2009. Integrated methodology for estimating water use in Mediterranean agricultural areas. Remote Sensing. 1, 445-465. -(PDF) +(PDF)

    Chemin, Y., 2012. A Distributed Benchmarking Framework for Actual ET Models, in: Irmak, A. (Ed.), Evapotranspiration - Remote Sensing and Modeling. InTech. -(PDF) +(PDF)

    SEE ALSO

    diff --git a/imagery/i.eb.hsebal01/i.eb.hsebal01.html b/imagery/i.eb.hsebal01/i.eb.hsebal01.html index 4b6d3953e53..4501af13c3c 100644 --- a/imagery/i.eb.hsebal01/i.eb.hsebal01.html +++ b/imagery/i.eb.hsebal01/i.eb.hsebal01.html @@ -37,7 +37,7 @@

    REFERENCES

    [1] Bastiaanssen, W.G.M., 1995. Estimation of Land surface parameters by remote sensing under clear-sky conditions. PhD thesis, Wageningen University, Wageningen, The Netherlands. -(PDF) +(PDF)

    [2] Chemin Y., Alexandridis T.A., 2001. Improving spatial resolution of ET seasonal for irrigated rice in Zhanghe, China. Asian Journal of @@ -46,12 +46,12 @@

    REFERENCES

    [3] Alexandridis T.K., Cherif I., Chemin Y., Silleos N.G., Stavrinos E., Zalidis G.C. Integrated methodology for estimating water use in Mediterranean agricultural areas. Remote Sensing. 2009, 1, 445-465. -(PDF) +(PDF)

    [4] Chemin, Y., 2012. A Distributed Benchmarking Framework for Actual ET Models, in: Irmak, A. (Ed.), Evapotranspiration - Remote Sensing and Modeling. InTech. -(PDF) +(PDF)

    SEE ALSO

    diff --git a/imagery/i.eb.netrad/i.eb.netrad.html b/imagery/i.eb.netrad/i.eb.netrad.html index 306bb39c90d..c6cba3ad484 100644 --- a/imagery/i.eb.netrad/i.eb.netrad.html +++ b/imagery/i.eb.netrad/i.eb.netrad.html @@ -28,12 +28,12 @@

    REFERENCES

    densities and moisture indicators in composite terrain; a remote sensing approach under clear skies in mediterranean climates. PhD thesis, Wageningen Agricultural Univ., The Netherland, 271 pp. -(PDF) +(PDF)
  • Chemin, Y., 2012. A Distributed Benchmarking Framework for Actual ET Models, in: Irmak, A. (Ed.), Evapotranspiration - Remote Sensing and Modeling. InTech. -(PDF)
  • +(PDF)

SEE ALSO

diff --git a/imagery/i.eb.soilheatflux/i.eb.soilheatflux.html b/imagery/i.eb.soilheatflux/i.eb.soilheatflux.html index b948d827da2..ecf62af78e9 100644 --- a/imagery/i.eb.soilheatflux/i.eb.soilheatflux.html +++ b/imagery/i.eb.soilheatflux/i.eb.soilheatflux.html @@ -41,7 +41,7 @@

REFERENCES

Bastiaanssen, W.G.M., 1995. Estimation of Land surface parameters by remote sensing under clear-sky conditions. PhD thesis, Wageningen University, Wageningen, The Netherlands. - (PDF) + (PDF)

Chemin Y., Alexandridis T.A., 2001. Improving spatial resolution of ET seasonal for irrigated rice in Zhanghe, China. Asian Journal of Geoinformatics. 5(1):3-11,2004. @@ -49,12 +49,12 @@

REFERENCES

Alexandridis T.K., Cherif I., Chemin Y., Silleos N.G., Stavrinos E., Zalidis G.C. Integrated methodology for estimating water use in Mediterranean agricultural areas. Remote Sensing. 2009, 1, 445-465. -(PDF) +(PDF)

Chemin, Y., 2012. A Distributed Benchmarking Framework for Actual ET Models, in: Irmak, A. (Ed.), Evapotranspiration - Remote Sensing and Modeling. InTech. -(PDF) +(PDF)

SEE ALSO

diff --git a/imagery/i.emissivity/i.emissivity.html b/imagery/i.emissivity/i.emissivity.html index 872ca4fddae..e6419e8f776 100644 --- a/imagery/i.emissivity/i.emissivity.html +++ b/imagery/i.emissivity/i.emissivity.html @@ -21,7 +21,7 @@

REFERENCES

  • Bastiaanssen, W.G.M., 1995. Estimation of Land surface parameters by remote sensing under clear-sky conditions. PhD thesis, Wageningen University, Wageningen, The Netherlands. - (PDF)
  • + (PDF)
  • Caselles, V., C. Coll, and E. Valor, 1997. Land surface emissivity and temperature determination in the whole HAPEX-Sahel area from AVHRR data. International Journal of Remote diff --git a/imagery/i.fft/i.fft.html b/imagery/i.fft/i.fft.html index abb7453af82..8eb63a9c8ae 100644 --- a/imagery/i.fft/i.fft.html +++ b/imagery/i.fft/i.fft.html @@ -40,12 +40,12 @@

    REFERENCES

    • M. Frigo and S. G. Johnson (1998): "FFTW: An Adaptive Software Architecture -for the FFT". See www.FFTW.org: FFTW is a C subroutine library +for the FFT". See www.FFTW.org: FFTW is a C subroutine library for computing the Discrete Fourier Transform (DFT) in one or more dimensions, of both real and complex data, and of arbitrary input size.
    • John A. Richards, 1986. Remote Sensing Digital Image Analysis, Springer-Verlag.
    • Personal communication, between program author and Ali R. Vali, -Space Research Center, University of Texas, Austin, 1990. +Space Research Center, University of Texas, Austin, 1990.

    SEE ALSO

    diff --git a/imagery/i.ifft/i.ifft.html b/imagery/i.ifft/i.ifft.html index 028f81f5895..eee7bc54e06 100644 --- a/imagery/i.ifft/i.ifft.html +++ b/imagery/i.ifft/i.ifft.html @@ -23,7 +23,7 @@

    REFERENCES

    • M. Frigo and S. G. Johnson (1998): "FFTW: An Adaptive Software -Architecture for the FFT". See www.fftw.org: +Architecture for the FFT". See www.fftw.org: FFTW is a C subroutine library for computing the Discrete Fourier Transform (DFT) in one or more dimensions, of both real and complex data, and of arbitrary input size.
    • diff --git a/imagery/i.landsat.toar/i.landsat.toar.html b/imagery/i.landsat.toar/i.landsat.toar.html index 821f7cb4cfe..4a792c26274 100644 --- a/imagery/i.landsat.toar/i.landsat.toar.html +++ b/imagery/i.landsat.toar/i.landsat.toar.html @@ -235,7 +235,7 @@

      DOS1 example

      Calculation of reflectance values from DN using DOS1 (metadata obtained -from p016r035_7x20020524.met.gz): +from p016r035_7x20020524.met.gz):
       i.landsat.toar input=lsat7_2002. output=lsat7_2002_toar. sensor=tm7 \
      diff --git a/imagery/i.ortho.photo/README b/imagery/i.ortho.photo/README
      index bc8313ce304..51260299d5b 100644
      --- a/imagery/i.ortho.photo/README
      +++ b/imagery/i.ortho.photo/README
      @@ -49,7 +49,7 @@ Workflow description:
       Open Source GIS: A GRASS GIS Approach, Second Edition, 2004
       by Markus Neteler and Helena Mitasova,
       Chapter 10 – PROCESSING OF AERIAL PHOTOS
      -http://grassbook.org/extra/sample-chapter/
      +https://grassbook.org/extra/sample-chapter/
       --> PDF
       
       ######################################################################
      diff --git a/imagery/i.ortho.photo/lib/TODO b/imagery/i.ortho.photo/lib/TODO
      index 792cb581378..df02ac3cf5d 100644
      --- a/imagery/i.ortho.photo/lib/TODO
      +++ b/imagery/i.ortho.photo/lib/TODO
      @@ -30,4 +30,4 @@ Possibly a lot is already done in lib/image3/ ?
       -----------------
       See also
       
      -http://trac.osgeo.org/grass/wiki/Grass7Planning
      +https://trac.osgeo.org/grass/wiki/Grass7Planning
      diff --git a/imagery/i.rectify/i.rectify.html b/imagery/i.rectify/i.rectify.html
      index 6451c8c9be9..7ef374b948e 100644
      --- a/imagery/i.rectify/i.rectify.html
      +++ b/imagery/i.rectify/i.rectify.html
      @@ -11,8 +11,8 @@ 

      DESCRIPTION

      are first, second, and third order polynomial and thin plate spline. Thin plate spline is recommended for ungeoreferenced satellite imagery where ground control points (GCPs) are included. Examples are -NOAA/AVHRR -and ENVISAT +NOAA/AVHRR +and ENVISAT imagery which include throusands of GCPs.

      diff --git a/imagery/i.vi/evi2.c b/imagery/i.vi/evi2.c index c56ad2f62e0..502fba957ab 100644 --- a/imagery/i.vi/evi2.c +++ b/imagery/i.vi/evi2.c @@ -7,7 +7,7 @@ * 2-band enhanced vegetation index without a blue band and its application to * AVHRR data Proc. SPIE 6679, Remote Sensing and Modeling of Ecosystems for * Sustainability IV, 667905 (October 09, 2007) doi:10.1117/12.734933 - * http://dx.doi.org/10.1117/12.734933 + * https://doi.org/10.1117/12.734933 */ double e_vi2(double redchan, double nirchan) { diff --git a/imagery/i.vi/i.vi.html b/imagery/i.vi/i.vi.html index 7e600600678..3597dc5f500 100644 --- a/imagery/i.vi/i.vi.html +++ b/imagery/i.vi/i.vi.html @@ -134,7 +134,7 @@

      Vegetation Indices

      vegetation index without a blue band and its application to AVHRR data. Proc. SPIE 6679, Remote Sensing and Modeling of Ecosystems for Sustainability IV, 667905 (october 09, 2007) -doi:10.1117/12.734933). +doi:10.1117/12.734933).
       evi2( redchan, nirchan )
      @@ -150,7 +150,7 @@ 

      Vegetation Indices

      Gitelson, Anatoly A.; Kaufman, Yoram J.; Merzlyak, Mark N. (1996) Use of a green channel in remote sensing of global vegetation from EOS- MODIS, Remote Sensing of Environment 58 (3), 289-298. -doi:10.1016/s0034-4257(96)00072-7 +doi:10.1016/s0034-4257(96)00072-7
       gari( redchan, nirchan, bluechan, greenchan )
      @@ -508,7 +508,7 @@ 

      Preparation: DN to reflectance

      Calculation of reflectance values from DN using DOS1 (metadata obtained -from p016r035_7x20020524.met.gz): +from p016r035_7x20020524.met.gz):

      @@ -596,8 +596,8 @@ 

      REFERENCES

      densities and moisture indicators in composite terrain; a remote sensing approach under clear skies in mediterranean climates. PhD thesis, Wageningen Agricultural Univ., The Netherland, 271 pp. -(PDF) -
    • Index DataBase: List of available Indices
    • +(PDF) +
    • Index DataBase: List of available Indices

    SEE ALSO

    diff --git a/imagery/imageryintro.html b/imagery/imageryintro.html index 9018b4871ae..c0ef2a48616 100644 --- a/imagery/imageryintro.html +++ b/imagery/imageryintro.html @@ -59,7 +59,7 @@

    Image processing in general

    using the DOS correction method. The more accurate way is using i.atcorr (which supports many satellite sensors). The atmospherically corrected sensor data represent -surface reflectance, +surface reflectance, which ranges theoretically from 0% to 100%. Note that this level of data correction is the proper level of correction to calculate vegetation indices. diff --git a/include/Make/Doxyfile_arch_html.in b/include/Make/Doxyfile_arch_html.in index 3f1e828494c..4c60088412a 100644 --- a/include/Make/Doxyfile_arch_html.in +++ b/include/Make/Doxyfile_arch_html.in @@ -18,7 +18,7 @@ # that follow. The default is UTF-8 which is also the encoding used for all # text before the first occurrence of this tag. Doxygen uses libiconv (or the # iconv built into libc) for the transcoding. See -# http://www.gnu.org/software/libiconv for the list of possible encodings. +# https://www.gnu.org/software/libiconv for the list of possible encodings. DOXYFILE_ENCODING = UTF-8 @@ -573,7 +573,7 @@ LAYOUT_FILE = # containing the references data. This must be a list of .bib files. The # .bib extension is automatically appended if omitted. Using this command # requires the bibtex tool to be installed. See also -# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style +# https://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style # of the bibliography can be controlled using LATEX_BIB_STYLE. To use this # feature you need bibtex and perl available in the search path. @@ -644,7 +644,7 @@ INPUT = . # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is # also the default input encoding. Doxygen uses libiconv (or the iconv built -# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# into libc) for the transcoding. See https://www.gnu.org/software/libiconv for # the list of possible encodings. INPUT_ENCODING = UTF-8 @@ -851,7 +851,7 @@ REFERENCES_LINK_SOURCE = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source -# tagging system (see http://www.gnu.org/software/global/global.html). You +# tagging system (see https://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO @@ -946,7 +946,7 @@ HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. # Doxygen will adjust the colors in the style sheet and background images # according to this color. Hue is specified as an angle on a colorwheel, -# see http://en.wikipedia.org/wiki/Hue for more information. +# see https://en.wikipedia.org/wiki/Hue for more information. # For instance the value 0 represents red, 60 is yellow, 120 is green, # 180 is cyan, 240 is blue, 300 purple, and 360 is red again. # The allowed range is 0 to 359. @@ -1337,7 +1337,7 @@ LATEX_SOURCE_CODE = NO # The LATEX_BIB_STYLE tag can be used to specify the style to use for the # bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See -# http://en.wikipedia.org/wiki/BibTeX for more info. +# https://en.wikipedia.org/wiki/BibTeX for more info. LATEX_BIB_STYLE = plain diff --git a/include/Make/Doxyfile_arch_latex.in b/include/Make/Doxyfile_arch_latex.in index 1962073feec..25f6ac1592f 100644 --- a/include/Make/Doxyfile_arch_latex.in +++ b/include/Make/Doxyfile_arch_latex.in @@ -18,7 +18,7 @@ # that follow. The default is UTF-8 which is also the encoding used for all # text before the first occurrence of this tag. Doxygen uses libiconv (or the # iconv built into libc) for the transcoding. See -# http://www.gnu.org/software/libiconv for the list of possible encodings. +# https://www.gnu.org/software/libiconv for the list of possible encodings. DOXYFILE_ENCODING = UTF-8 @@ -573,7 +573,7 @@ LAYOUT_FILE = # containing the references data. This must be a list of .bib files. The # .bib extension is automatically appended if omitted. Using this command # requires the bibtex tool to be installed. See also -# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style +# https://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style # of the bibliography can be controlled using LATEX_BIB_STYLE. To use this # feature you need bibtex and perl available in the search path. @@ -644,7 +644,7 @@ INPUT = . # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is # also the default input encoding. Doxygen uses libiconv (or the iconv built -# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# into libc) for the transcoding. See https://www.gnu.org/software/libiconv for # the list of possible encodings. INPUT_ENCODING = UTF-8 @@ -851,7 +851,7 @@ REFERENCES_LINK_SOURCE = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source -# tagging system (see http://www.gnu.org/software/global/global.html). You +# tagging system (see https://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO @@ -946,7 +946,7 @@ HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. # Doxygen will adjust the colors in the style sheet and background images # according to this color. Hue is specified as an angle on a colorwheel, -# see http://en.wikipedia.org/wiki/Hue for more information. +# see https://en.wikipedia.org/wiki/Hue for more information. # For instance the value 0 represents red, 60 is yellow, 120 is green, # 180 is cyan, 240 is blue, 300 purple, and 360 is red again. # The allowed range is 0 to 359. @@ -1337,7 +1337,7 @@ LATEX_SOURCE_CODE = NO # The LATEX_BIB_STYLE tag can be used to specify the style to use for the # bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See -# http://en.wikipedia.org/wiki/BibTeX for more info. +# https://en.wikipedia.org/wiki/BibTeX for more info. LATEX_BIB_STYLE = plain diff --git a/include/grass/defs/gprojects.h b/include/grass/defs/gprojects.h index 7ab5e47ddd6..e96200c1480 100644 --- a/include/grass/defs/gprojects.h +++ b/include/grass/defs/gprojects.h @@ -65,7 +65,7 @@ void GPJ_free_ellps(struct gpj_ellps *); #ifndef HAVE_PROJ_H /* PROJ.4's private datastructures copied from projects.h as removed from upstream; pending better solution. see: - http://trac.osgeo.org/proj/ticket/98 */ + https://trac.osgeo.org/proj/ticket/98 */ int pj_factors(LP, void *, double, struct FACTORS *); diff --git a/include/grass/gprojects.h b/include/grass/gprojects.h index 7872d6cb4b6..35f795d87ad 100644 --- a/include/grass/gprojects.h +++ b/include/grass/gprojects.h @@ -112,7 +112,7 @@ struct gpj_ellps { #ifndef HAVE_PROJ_H /* PROJ.4's private datastructures copied from projects.h as removed from upstream; pending better solution. see: - http://trac.osgeo.org/proj/ticket/98 */ + https://trac.osgeo.org/proj/ticket/98 */ /* In PROJ 5, the 'struct FACTORS' is back in as 'struct P5_FACTORS', * and old 'struct LP' is now back in as 'PJ_UV' */ diff --git a/lib/cairodriver/cairodriver.dox b/lib/cairodriver/cairodriver.dox index d7ce1ab60e2..ca3ac067e06 100644 --- a/lib/cairodriver/cairodriver.dox +++ b/lib/cairodriver/cairodriver.dox @@ -11,7 +11,7 @@ output, see Cairo website for details. GRASS Cairo display %driver was originally written by Lars Ahlzen (announcement). +href="https://lists.osgeo.org/pipermail/grass-dev/2007-October/033524.html">announcement). \section cairofunctions List of functions diff --git a/lib/db/README b/lib/db/README index 7268b4e182f..9dc8faf9ab6 100644 --- a/lib/db/README +++ b/lib/db/README @@ -26,7 +26,7 @@ DBMI Library Original author: Joel Jones (jjones * zorro.cecer.army.mil | jjones * uiuc.edu ) - Ref: http://lists.osgeo.org/pipermail/grass-dev/1995-February/002015.html + Ref: https://lists.osgeo.org/pipermail/grass-dev/1995-February/002015.html Directory contents: diff --git a/lib/db/dbmi_base/default_name.c b/lib/db/dbmi_base/default_name.c index f9904651a06..839060b44d9 100644 --- a/lib/db/dbmi_base/default_name.c +++ b/lib/db/dbmi_base/default_name.c @@ -123,7 +123,7 @@ int db_set_default_connection(void) * that here?) or $MAPSET/sqlite/mapname.sql as with dbf? */ - /* http://www.sqlite.org/lockingv3.html + /* https://www.sqlite.org/lockingv3.html * When SQLite creates a journal file on Unix, it opens the * directory that contains that file and calls fsync() on the * directory, in an effort to push the directory information to disk. diff --git a/lib/db/dbmilib.dox b/lib/db/dbmilib.dox index fdbac5fab36..0c85715e7f0 100644 --- a/lib/db/dbmilib.dox +++ b/lib/db/dbmilib.dox @@ -15,10 +15,10 @@ Interface) with its integrated drivers. At time of this writing following DBMI drivers for attribute storage are available: - DBF: xBase files (default) - - ODBC: to interface from http://www.unixodbc.org - - PostgreSQL driver (note that PostgreSQL can also be accessed through ODBC): http://www.postgresql.org + - ODBC: to interface from https://www.unixodbc.org + - PostgreSQL driver (note that PostgreSQL can also be accessed through ODBC): https://www.postgresql.org - mySQL: http://mysql.com/ - - SQLite: http://www.sqlite.org + - SQLite: https://www.sqlite.org These drivers are compiled depending on present DB related libraries and 'configure' settings. Only the DBF driver is always compiled. The diff --git a/lib/db/sqlp/sql.html b/lib/db/sqlp/sql.html index 730d0462c2a..eaed6a74b70 100644 --- a/lib/db/sqlp/sql.html +++ b/lib/db/sqlp/sql.html @@ -9,9 +9,9 @@ attribute table.

    GRASS GIS supports various RDBMS -(Relational +(Relational database management system) and embedded databases. SQL -(Structured Query +(Structured Query Language) queries are directly passed to the underlying database system. The set of supported SQL commands depends on the RDMBS and database driver selected. @@ -44,10 +44,10 @@

    Database drivers

    http://mysql.org/ --> odbcData storage via UnixODBC (PostgreSQL, Oracle, etc.) -http://www.unixodbc.org/ +https://www.unixodbc.org/ ogrData storage in OGR files -http://gdal.org/ +https://gdal.org/

    NOTES

    diff --git a/lib/gmath/gmathlib.dox b/lib/gmath/gmathlib.dox index a404595de04..77b516b8ebd 100644 --- a/lib/gmath/gmathlib.dox +++ b/lib/gmath/gmathlib.dox @@ -464,8 +464,8 @@ implemented.

    Getting BLAS/LAPACK (one package) if not already provided by the system: -
    http://www.netlib.org/lapack/ -
    http://netlib.bell-labs.com/netlib/master/readme.html +
    https://www.netlib.org/lapack/ +
    https://netlib.bell-labs.com/netlib/master/readme.html

    Pre-compiled binaries of LAPACK/BLAS are provided on many Linux diff --git a/lib/init/variables.html b/lib/init/variables.html index 6fd10d7f173..5dfd113dd85 100644 --- a/lib/init/variables.html +++ b/lib/init/variables.html @@ -392,7 +392,7 @@

    List of selected (GRASS related) shell environment variables

    TMPDIR, TEMP, TMP
    [Various GRASS GIS commands and wxGUI]
    - + The default wxGUI temporary directory is chosen from a platform-dependent list, but the user can control the selection of this directory by setting one of the TMPDIR, TEMP or TMP diff --git a/lib/vector/Vlib/buffer2.c b/lib/vector/Vlib/buffer2.c index 102b1ca350b..ce628d761ef 100644 --- a/lib/vector/Vlib/buffer2.c +++ b/lib/vector/Vlib/buffer2.c @@ -118,7 +118,7 @@ static void elliptic_tangent(double x, double y, double da, double db, /* * !!! This is not line in GRASS' sense. See - * http://en.wikipedia.org/wiki/Line_%28mathematics%29 + * https://en.wikipedia.org/wiki/Line_%28mathematics%29 */ static void line_coefficients(double x1, double y1, double x2, double y2, double *a, double *b, double *c) diff --git a/lib/vector/Vlib/legal_vname.c b/lib/vector/Vlib/legal_vname.c index cd2aa0f14ba..f51df6ace66 100644 --- a/lib/vector/Vlib/legal_vname.c +++ b/lib/vector/Vlib/legal_vname.c @@ -32,7 +32,7 @@ int Vect_legal_filename(const char *s) { /* full list of SQL keywords available at - http://www.postgresql.org/docs/8.2/static/sql-keywords-appendix.html + https://www.postgresql.org/docs/8.2/static/sql-keywords-appendix.html */ static const char *keywords[] = {"and", "or", "not", NULL}; char buf[GNAME_MAX]; diff --git a/lib/vector/vectorlib_pg.dox b/lib/vector/vectorlib_pg.dox index c3a072c6a14..d95b3dec1c2 100644 --- a/lib/vector/vectorlib_pg.dox +++ b/lib/vector/vectorlib_pg.dox @@ -10,14 +10,14 @@ by GRASS Development Team (https://grass.osgeo.org) write PostGIS data directly without any external library (like in the case of \ref vlibOgr). GRASS-PostGIS data provider is implemented using libpq +href="https://www.postgresql.org/docs/9.2/static/libpq.html">libpq library. Note that GRASS-PostGIS data provider is compiled only when GRASS is configured with --with-postgres switch. See the trac +href="https://trac.osgeo.org/grass/wiki/Grass7/VectorLib/PostGISInterface">trac page for more info. \section vlibFn List of functions diff --git a/locale/po/grassmods_ar.po b/locale/po/grassmods_ar.po index b21aefa5d0b..cbb43ec6e9e 100644 --- a/locale/po/grassmods_ar.po +++ b/locale/po/grassmods_ar.po @@ -71377,7 +71377,7 @@ msgid "Either or must be given" msgstr "طبقتين يجب تحديدهم" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_bn.po b/locale/po/grassmods_bn.po index 17a11f251b8..f3526d45180 100644 --- a/locale/po/grassmods_bn.po +++ b/locale/po/grassmods_bn.po @@ -65839,7 +65839,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_cs.po b/locale/po/grassmods_cs.po index c6f5f75df4c..0d17c962990 100644 --- a/locale/po/grassmods_cs.po +++ b/locale/po/grassmods_cs.po @@ -68271,7 +68271,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_de.po b/locale/po/grassmods_de.po index 8603cfda94d..7e994f4b379 100644 --- a/locale/po/grassmods_de.po +++ b/locale/po/grassmods_de.po @@ -68907,7 +68907,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_el.po b/locale/po/grassmods_el.po index 5b07d819bd2..e183723b634 100644 --- a/locale/po/grassmods_el.po +++ b/locale/po/grassmods_el.po @@ -66429,7 +66429,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_es.po b/locale/po/grassmods_es.po index 676e7382c2d..ca8a6727270 100644 --- a/locale/po/grassmods_es.po +++ b/locale/po/grassmods_es.po @@ -70595,7 +70595,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_fi.po b/locale/po/grassmods_fi.po index 15504ea84ae..692d9c0d9f2 100644 --- a/locale/po/grassmods_fi.po +++ b/locale/po/grassmods_fi.po @@ -65889,7 +65889,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_fr.po b/locale/po/grassmods_fr.po index f13cc33269f..8f4602fc6ec 100644 --- a/locale/po/grassmods_fr.po +++ b/locale/po/grassmods_fr.po @@ -68934,7 +68934,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_hu.po b/locale/po/grassmods_hu.po index 193acc17813..ee0f0929c11 100644 --- a/locale/po/grassmods_hu.po +++ b/locale/po/grassmods_hu.po @@ -66112,7 +66112,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_id_ID.po b/locale/po/grassmods_id_ID.po index c7159086153..d9a39bafe24 100644 --- a/locale/po/grassmods_id_ID.po +++ b/locale/po/grassmods_id_ID.po @@ -65729,7 +65729,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_it.po b/locale/po/grassmods_it.po index 3120ef6c35b..94368222e52 100644 --- a/locale/po/grassmods_it.po +++ b/locale/po/grassmods_it.po @@ -68276,7 +68276,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_ja.po b/locale/po/grassmods_ja.po index 3444ccaf5db..0dd3735b064 100644 --- a/locale/po/grassmods_ja.po +++ b/locale/po/grassmods_ja.po @@ -67358,7 +67358,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_ko.po b/locale/po/grassmods_ko.po index 5e3acc44adc..8d255c6f5ad 100644 --- a/locale/po/grassmods_ko.po +++ b/locale/po/grassmods_ko.po @@ -67003,7 +67003,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_lv.po b/locale/po/grassmods_lv.po index 717f25bac27..43e408d8721 100644 --- a/locale/po/grassmods_lv.po +++ b/locale/po/grassmods_lv.po @@ -67248,7 +67248,7 @@ msgid "Either or must be given" msgstr "2 līmeņiem jābūt norādītiem" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_ml.po b/locale/po/grassmods_ml.po index 201460df7bb..a3693866979 100644 --- a/locale/po/grassmods_ml.po +++ b/locale/po/grassmods_ml.po @@ -65839,7 +65839,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_pl.po b/locale/po/grassmods_pl.po index 8edda3da8e1..dccca2f5d0f 100644 --- a/locale/po/grassmods_pl.po +++ b/locale/po/grassmods_pl.po @@ -67713,7 +67713,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_pt.po b/locale/po/grassmods_pt.po index 63404997a1a..4a28f18ff64 100644 --- a/locale/po/grassmods_pt.po +++ b/locale/po/grassmods_pt.po @@ -67030,7 +67030,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_pt_BR.po b/locale/po/grassmods_pt_BR.po index 673f09c2d8c..d7bcb3c7f41 100644 --- a/locale/po/grassmods_pt_BR.po +++ b/locale/po/grassmods_pt_BR.po @@ -68320,7 +68320,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_ro.po b/locale/po/grassmods_ro.po index 46ac81a4b36..3f4174329a4 100644 --- a/locale/po/grassmods_ro.po +++ b/locale/po/grassmods_ro.po @@ -67214,7 +67214,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_ru.po b/locale/po/grassmods_ru.po index cc9bdc51a78..2630e39adcf 100644 --- a/locale/po/grassmods_ru.po +++ b/locale/po/grassmods_ru.po @@ -66746,7 +66746,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_si.po b/locale/po/grassmods_si.po index 7f42447aee9..b2f15092dbc 100644 --- a/locale/po/grassmods_si.po +++ b/locale/po/grassmods_si.po @@ -65839,7 +65839,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_sl.po b/locale/po/grassmods_sl.po index e2b72f76d56..56c5e73fd60 100644 --- a/locale/po/grassmods_sl.po +++ b/locale/po/grassmods_sl.po @@ -71740,7 +71740,7 @@ msgid "Either or must be given" msgstr "Uporabiš lahko ali 'from_table' ali 'select'" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_ta.po b/locale/po/grassmods_ta.po index d76c586fc00..4bd45b751d5 100644 --- a/locale/po/grassmods_ta.po +++ b/locale/po/grassmods_ta.po @@ -65897,7 +65897,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_th.po b/locale/po/grassmods_th.po index bb0898b05f1..a38947544d5 100644 --- a/locale/po/grassmods_th.po +++ b/locale/po/grassmods_th.po @@ -66270,7 +66270,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_tr.po b/locale/po/grassmods_tr.po index 6e58f486013..ef10aa29895 100644 --- a/locale/po/grassmods_tr.po +++ b/locale/po/grassmods_tr.po @@ -67181,7 +67181,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_uk.po b/locale/po/grassmods_uk.po index 8bf34d792ef..ded3fc09c7a 100644 --- a/locale/po/grassmods_uk.po +++ b/locale/po/grassmods_uk.po @@ -66059,7 +66059,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_vi.po b/locale/po/grassmods_vi.po index bfe8eb81909..cb4f0aa95a9 100644 --- a/locale/po/grassmods_vi.po +++ b/locale/po/grassmods_vi.po @@ -66307,7 +66307,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_zh.po b/locale/po/grassmods_zh.po index f5926443d90..3ec8942025d 100644 --- a/locale/po/grassmods_zh.po +++ b/locale/po/grassmods_zh.po @@ -66768,7 +66768,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/po/grassmods_zh_CN.po b/locale/po/grassmods_zh_CN.po index 9ba4d09e886..476cc510193 100644 --- a/locale/po/grassmods_zh_CN.po +++ b/locale/po/grassmods_zh_CN.po @@ -65730,7 +65730,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/locale/templates/grassmods.pot b/locale/templates/grassmods.pot index c339eb81069..3476f2faa63 100644 --- a/locale/templates/grassmods.pot +++ b/locale/templates/grassmods.pot @@ -65839,7 +65839,7 @@ msgid "Either or must be given" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:129 -msgid "'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)" +msgid "'gdalinfo' not found, install GDAL tools first (https://gdal.org)" msgstr "" #: ../scripts/i.in.spotvgt/i.in.spotvgt.py:146 diff --git a/macosx/ReadMe.md b/macosx/ReadMe.md index ac19f4c57de..86fb1c0ba38 100644 --- a/macosx/ReadMe.md +++ b/macosx/ReadMe.md @@ -230,7 +230,7 @@ build)*: To install the new Python GUI (see [REQUIREMENTS.html](../REQUIREMENTS.html) and [gui/wxpython/README](../gui/wxpython/README), wxpython installer -available at [wxpython.org](http://wxpython.org/)), add this to configure (fill +available at [wxpython.org](https://wxpython.org/)), add this to configure (fill in the correct version at x.x.x.x for the wxpython you have installed): ```bash diff --git a/mswindows/README.html b/mswindows/README.html index 2b6f87db703..91be0f9afbb 100644 --- a/mswindows/README.html +++ b/mswindows/README.html @@ -7,7 +7,7 @@ Instructions how to prepare a WinGRASS package installer has been moved to -the wiki +the wiki page. diff --git a/mswindows/external/rbatch/R.bat b/mswindows/external/rbatch/R.bat index d55a6b395a8..fd28421d126 100644 --- a/mswindows/external/rbatch/R.bat +++ b/mswindows/external/rbatch/R.bat @@ -1,7 +1,7 @@ @Echo OFF :: Software and documentation is (c) 2013 GKX Associates Inc. and -:: licensed under [GPL 2.0](http://www.gnu.org/licenses/gpl-2.0.html). +:: licensed under [GPL 2.0](https://www.gnu.org/licenses/gpl-2.0.html). :: Help is at bottom of script or just run script with single argument: help @@ -520,7 +520,7 @@ goto:eof :Rhelp echo (c) 2013 G. Grothendieck -echo License: GPL 2.0 ( http://www.gnu.org/licenses/gpl-2.0.html ) +echo License: GPL 2.0 ( https://www.gnu.org/licenses/gpl-2.0.html ) echo Launch script for R and associated functions. echo Usage: R.bat [subcommand] [arguments] echo Subcommands where (0) means takes no arguments; (A) means may need Admin priv diff --git a/mswindows/external/rbatch/README.grass b/mswindows/external/rbatch/README.grass index 85f32b7a9be..40bc7a307a7 100644 --- a/mswindows/external/rbatch/README.grass +++ b/mswindows/external/rbatch/README.grass @@ -13,7 +13,7 @@ at svn-revision 104 (2012-08-31). -- -See http://trac.osgeo.org/grass/ticket/1149#comment:9 +See https://trac.osgeo.org/grass/ticket/1149#comment:9 -- diff --git a/mswindows/external/rbatch/Rpathset.bat b/mswindows/external/rbatch/Rpathset.bat index 7873fc01907..590e9a58980 100644 --- a/mswindows/external/rbatch/Rpathset.bat +++ b/mswindows/external/rbatch/Rpathset.bat @@ -1,5 +1,5 @@ :: Software and documentation is (c) 2013 GKX Associates Inc. and -:: licensed under [GPL 2.0](http://www.gnu.org/licenses/gpl-2.0.html). +:: licensed under [GPL 2.0](https://www.gnu.org/licenses/gpl-2.0.html). :: Purpose: setup path to use R, Rtools and other utilities from cmd line. :: diff --git a/mswindows/external/rbatch/batchfiles.md b/mswindows/external/rbatch/batchfiles.md index 2c10e2bcf75..de26ff2748f 100644 --- a/mswindows/external/rbatch/batchfiles.md +++ b/mswindows/external/rbatch/batchfiles.md @@ -3,7 +3,7 @@ G. Grothendieck Software and documentation is (c) 2013 GKX Associates Inc. and licensed -under [GPL 2.0](http://www.gnu.org/licenses/gpl-2.0.html). +under [GPL 2.0](https://www.gnu.org/licenses/gpl-2.0.html). ## Introduction ## diff --git a/mswindows/external/rbatch/batchfiles.tex b/mswindows/external/rbatch/batchfiles.tex index da8d64664b7..acfa8c6e634 100644 --- a/mswindows/external/rbatch/batchfiles.tex +++ b/mswindows/external/rbatch/batchfiles.tex @@ -3,7 +3,7 @@ \section{Windows Batch Files for R} G. Grothendieck Software and documentation is (c) 2013 GKX Associates Inc. and licensed -under \href{http://www.gnu.org/licenses/gpl-2.0.html}{GPL 2.0}. +under \href{https://www.gnu.org/licenses/gpl-2.0.html}{GPL 2.0}. \subsection{Introduction} diff --git a/mswindows/external/rbatch/copydir.bat b/mswindows/external/rbatch/copydir.bat index f346560b3f0..9ab646e6e0c 100644 --- a/mswindows/external/rbatch/copydir.bat +++ b/mswindows/external/rbatch/copydir.bat @@ -1,6 +1,6 @@ @echo off :: Software and documentation is (c) 2013 GKX Associates Inc. and -:: licensed under [GPL 2.0](http://www.gnu.org/licenses/gpl-2.0.html). +:: licensed under [GPL 2.0](https://www.gnu.org/licenses/gpl-2.0.html). setlocal if not "%2"=="" goto:run echo Usage: copydir fromdir todir diff --git a/mswindows/external/rbatch/movedir.bat b/mswindows/external/rbatch/movedir.bat index 104d6a0d5f0..57fb0a7a498 100644 --- a/mswindows/external/rbatch/movedir.bat +++ b/mswindows/external/rbatch/movedir.bat @@ -1,6 +1,6 @@ @echo off :: Software and documentation is (c) 2013 GKX Associates Inc. and -:: licensed under [GPL 2.0](http://www.gnu.org/licenses/gpl-2.0.html). +:: licensed under [GPL 2.0](https://www.gnu.org/licenses/gpl-2.0.html). setlocal if not "%2"=="" goto:run echo Usage: copydir fromdir todir diff --git a/python/grass/docs/src/pygrass_index.rst b/python/grass/docs/src/pygrass_index.rst index 9e782e4c452..844e5578ae8 100644 --- a/python/grass/docs/src/pygrass_index.rst +++ b/python/grass/docs/src/pygrass_index.rst @@ -46,7 +46,7 @@ References Resources Analysis Support System (GRASS) Geographic Information System (GIS)*. ISPRS International Journal of Geo-Information. 2(1):201-219. `doi:10.3390/ijgi2010201 - `_ + `_ * `Python related articles in the GRASS GIS Wiki `_ * `GRASS GIS 8 Programmer's Manual @@ -54,7 +54,7 @@ References This project has been funded with support from the `Google Summer of Code 2012 -`_ +`_ .. Indices and tables diff --git a/python/grass/docs/src/pygrass_modules.rst b/python/grass/docs/src/pygrass_modules.rst index a668739a34f..854119057d6 100644 --- a/python/grass/docs/src/pygrass_modules.rst +++ b/python/grass/docs/src/pygrass_modules.rst @@ -200,4 +200,4 @@ Multiple GRASS modules can be joined into one object by :class:`~pygrass.modules.interface.module.MultiModule`. -.. _Popen: http://docs.python.org/library/subprocess.html#Popen +.. _Popen: https://docs.python.org/library/subprocess.html#Popen diff --git a/python/grass/docs/src/temporal_framework.rst b/python/grass/docs/src/temporal_framework.rst index 7e68de132a9..2443098b26a 100644 --- a/python/grass/docs/src/temporal_framework.rst +++ b/python/grass/docs/src/temporal_framework.rst @@ -414,7 +414,7 @@ Temporal shifting References ---------- -* Gebbert, S., Pebesma, E., 2014. *TGRASS: A temporal GIS for field based environmental modeling*. Environmental Modelling & Software. 2(1):201-219. `doi:10.1016/j.envsoft.2013.11.001 `_ +* Gebbert, S., Pebesma, E., 2014. *TGRASS: A temporal GIS for field based environmental modeling*. Environmental Modelling & Software. 2(1):201-219. `doi:10.1016/j.envsoft.2013.11.001 `_ * `TGRASS related articles in the GRASS GIS Wiki `_ * Supplementary material of the publication *The GRASS GIS Temporal Framework* to be published in diff --git a/python/grass/gunittest/reporters.py b/python/grass/gunittest/reporters.py index 57b0a8fc643..7c93872a656 100644 --- a/python/grass/gunittest/reporters.py +++ b/python/grass/gunittest/reporters.py @@ -107,7 +107,7 @@ def get_source_url(path, revision, line=None): :param revision: SVN revision (should be a number) :param line: line in the file (should be None for directories) """ - tracurl = "http://trac.osgeo.org/grass/browser/" + tracurl = "https://trac.osgeo.org/grass/browser/" if line: return "{tracurl}{path}?rev={revision}#L{line}".format(**locals()) return "{tracurl}{path}?rev={revision}".format(**locals()) diff --git a/python/grass/imaging/images2gif.py b/python/grass/imaging/images2gif.py index 4084dade509..d37ec0c4e32 100644 --- a/python/grass/imaging/images2gif.py +++ b/python/grass/imaging/images2gif.py @@ -58,7 +58,7 @@ Useful links: * http://tronche.com/computer-graphics/gif/ - * http://en.wikipedia.org/wiki/Graphics_Interchange_Format + * https://en.wikipedia.org/wiki/Graphics_Interchange_Format * http://www.w3.org/Graphics/GIF/spec-gif89a.txt """ diff --git a/python/grass/pygrass/modules/interface/module.py b/python/grass/pygrass/modules/interface/module.py index 392d7571015..7f70d82bac1 100644 --- a/python/grass/pygrass/modules/interface/module.py +++ b/python/grass/pygrass/modules/interface/module.py @@ -559,7 +559,7 @@ def __init__(self, cmd, *args, **kargs): # get the xml of the module self.xml = get_cmd_xml.communicate()[0] # transform and parse the xml into an Element class: - # http://docs.python.org/library/xml.etree.elementtree.html + # https://docs.python.org/library/xml.etree.elementtree.html tree = fromstring(self.xml) for e in tree: diff --git a/python/grass/script/utils.py b/python/grass/script/utils.py index 25eb70190c5..0a32a9e7b4e 100644 --- a/python/grass/script/utils.py +++ b/python/grass/script/utils.py @@ -321,7 +321,7 @@ def split(s): # source: -# http://stackoverflow.com/questions/4836710/ +# https://stackoverflow.com/questions/4836710/ # does-python-have-a-built-in-function-for-string-natural-sort/4836734#4836734 def natural_sort(items): """Returns sorted list using natural sort diff --git a/python/libgrass_interface_generator/ctypesgen/parser/yacc.py b/python/libgrass_interface_generator/ctypesgen/parser/yacc.py index f30cadb7a1a..9b57d110231 100644 --- a/python/libgrass_interface_generator/ctypesgen/parser/yacc.py +++ b/python/libgrass_interface_generator/ctypesgen/parser/yacc.py @@ -311,7 +311,7 @@ def restart(self): # certain kinds of advanced parsing situations where the lexer and parser interact with # each other or change states (i.e., manipulation of scope, lexer states, etc.). # - # See: http://www.gnu.org/software/bison/manual/html_node/Default-Reductions.html#Default-Reductions + # See: https://www.gnu.org/software/bison/manual/html_node/Default-Reductions.html#Default-Reductions def set_defaulted_states(self): self.defaulted_states = {} for state, actions in self.action.items(): diff --git a/python/libgrass_interface_generator/ctypesgen/printer_json/printer.py b/python/libgrass_interface_generator/ctypesgen/printer_json/printer.py index ab88af4dc40..4a201aa5702 100755 --- a/python/libgrass_interface_generator/ctypesgen/printer_json/printer.py +++ b/python/libgrass_interface_generator/ctypesgen/printer_json/printer.py @@ -7,7 +7,7 @@ # From: -# http://stackoverflow.com/questions/1036409/recursively-convert-python-object-graph-to-dictionary +# https://stackoverflow.com/questions/1036409/recursively-convert-python-object-graph-to-dictionary def todict(obj, classkey="Klass"): if isinstance(obj, dict): for k in obj.keys(): diff --git a/raster/r.buildvrt/r.buildvrt.html b/raster/r.buildvrt/r.buildvrt.html index d3a6d507bc1..67368179efb 100644 --- a/raster/r.buildvrt/r.buildvrt.html +++ b/raster/r.buildvrt/r.buildvrt.html @@ -20,7 +20,7 @@

    NOTES

    A GRASS virtual raster can be regarded as a simplified version of GDAL's -virtual raster format. +virtual raster format. The GRASS equivalent is simpler because issues like nodata, projection, resolution, resampling, masking are already handled by native GRASS raster routines. @@ -59,7 +59,7 @@

    SEE ALSO

    The equivalent GDAL utility -gdalbuildvrt +gdalbuildvrt

    AUTHOR

    diff --git a/raster/r.composite/r.composite.html b/raster/r.composite/r.composite.html index 4bd8e49cbe4..0ddd72592ea 100644 --- a/raster/r.composite/r.composite.html +++ b/raster/r.composite/r.composite.html @@ -47,7 +47,7 @@

    SEE ALSO

    r.rgb

    -Wikipedia Entry: Floyd-Steinberg dithering +Wikipedia Entry: Floyd-Steinberg dithering

    AUTHOR

    diff --git a/raster/r.external.out/r.external.out.html b/raster/r.external.out/r.external.out.html index baf48466ed3..c4b3bc65af1 100644 --- a/raster/r.external.out/r.external.out.html +++ b/raster/r.external.out/r.external.out.html @@ -70,7 +70,7 @@

    Complete workflow using only external geodata while processing in GRASS GIS<

    REFERENCES

    -GDAL Pages: http://www.gdal.org/
    +GDAL Pages: https://gdal.org/

    SEE ALSO

    diff --git a/raster/r.external/r.external.html b/raster/r.external/r.external.html index f20c3e059d6..1c69b2d3c3f 100644 --- a/raster/r.external/r.external.html +++ b/raster/r.external/r.external.html @@ -62,7 +62,7 @@

    Processing workflow without data import and export

    REFERENCES

    -GDAL Pages: http://www.gdal.org/
    +GDAL Pages: https://gdal.org/

    SEE ALSO

    diff --git a/raster/r.fill.stats/r.fill.stats.html b/raster/r.fill.stats/r.fill.stats.html index 3151d2c245a..fdc60119243 100644 --- a/raster/r.fill.stats/r.fill.stats.html +++ b/raster/r.fill.stats/r.fill.stats.html @@ -509,7 +509,7 @@

    SEE ALSO

    -Inverse Distance Weighting in Wikipedia +Inverse Distance Weighting in Wikipedia

    AUTHOR

    diff --git a/raster/r.geomorphon/r.geomorphon.html b/raster/r.geomorphon/r.geomorphon.html index 0eb675451f3..54af307b007 100644 --- a/raster/r.geomorphon/r.geomorphon.html +++ b/raster/r.geomorphon/r.geomorphon.html @@ -187,7 +187,7 @@

    REFERENCES

    109-112 (PDF)
  • Jasiewicz, J., Stepinski, T., 2013, Geomorphons - a pattern recognition approach to classification and mapping of landforms, -Geomorphology, vol. 182, 147-156 (DOI: 10.1016/j.geomorph.2012.11.005)
  • +Geomorphology, vol. 182, 147-156 (DOI: 10.1016/j.geomorph.2012.11.005)

    SEE ALSO

    diff --git a/raster/r.grow.distance/r.grow.distance.html b/raster/r.grow.distance/r.grow.distance.html index bc2788aae44..ee5e276a550 100644 --- a/raster/r.grow.distance/r.grow.distance.html +++ b/raster/r.grow.distance/r.grow.distance.html @@ -127,9 +127,9 @@

    SEE ALSO

    -Wikipedia Entry: +Wikipedia Entry: Euclidean Metric
    -Wikipedia Entry: +Wikipedia Entry: Manhattan Metric
    diff --git a/raster/r.in.gdal/r.in.gdal.html b/raster/r.in.gdal/r.in.gdal.html index f21f5682226..5af167a78e0 100644 --- a/raster/r.in.gdal/r.in.gdal.html +++ b/raster/r.in.gdal/r.in.gdal.html @@ -20,7 +20,7 @@

    GDAL supported raster formats

    Full details on all GDAL supported formats are available at:

    -http://www.gdal.org/formats_list.html +https://gdal.org/formats_list.html

    Selected formats out of the more than 140 supported formats: @@ -363,7 +363,7 @@

    GLOBE DEM

    Raster file import over network

    Since GDAL 2.x it is possible to import raster data over the network -(see GDAL Virtual File Systems) +(see GDAL Virtual File Systems) including Cloud Optimized GeoTIFF, i.e. access uncompressed and compressed raster data via a http(s) or ftp connection. As an example the import of the global SRTMGL1 V003 tiles at 1 arc second (about 30 meters) @@ -398,7 +398,7 @@

    HDF

    REFERENCES

    -GDAL Pages: http://www.gdal.org/ +GDAL Pages: https://gdal.org/

    SEE ALSO

    diff --git a/raster/r.in.xyz/r.in.xyz.html b/raster/r.in.xyz/r.in.xyz.html index 15d9f3565aa..42e5e1ee7f8 100644 --- a/raster/r.in.xyz/r.in.xyz.html +++ b/raster/r.in.xyz/r.in.xyz.html @@ -245,7 +245,7 @@

    Import of x,y,z ASCII into DEM

    Import of LiDAR data and DEM creation

    -Import the Jockey's +Import the Jockey's Ridge, NC, LIDAR dataset (compressed file "lidaratm2.txt.gz"), and process it into a clean DEM: diff --git a/raster/r.out.gdal/r.out.gdal.html b/raster/r.out.gdal/r.out.gdal.html index 9cb5b9d8156..06d269944c5 100644 --- a/raster/r.out.gdal/r.out.gdal.html +++ b/raster/r.out.gdal/r.out.gdal.html @@ -9,7 +9,7 @@

    DESCRIPTION

    (createopt="TFW=YES,COMPRESS=DEFLATE").

    For possible createopt and metaopt parameters please consult the individual -supported formats +supported formats pages on the GDAL website. The createopt parameter may be used to create TFW or World files ("TFW=YES","WORLDFILE=ON"). @@ -25,7 +25,7 @@

    DESCRIPTION

    SUPPORTED RASTER FORMATS

    -The set of supported +The set of supported raster formats written by r.out.gdal depends on the local GDAL installation, printed with the -l flag. Available may be (incomplete list):

    @@ -66,9 +66,9 @@

    NOTES

    Moreover, some GDAL-supported formats do not support all the data types possible in GDAL and GRASS. Use r.info to check the data type and range for your GRASS raster, refer to specific -format documentation (on the GDAL website), +format documentation (on the GDAL website), format vendor's documentation, and e.g. the Wikipedia article - + Typical boundaries of primitive integral types for details. @@ -368,7 +368,7 @@

    GDAL RELATED ERROR MESSAGES

    REFERENCES

    -GDAL Pages: https://gdal.org +GDAL Pages: https://gdal.org

    SEE ALSO

    diff --git a/raster/r.out.mpeg/r.out.mpeg.html b/raster/r.out.mpeg/r.out.mpeg.html index e035fce04c5..eb282acbbd9 100644 --- a/raster/r.out.mpeg/r.out.mpeg.html +++ b/raster/r.out.mpeg/r.out.mpeg.html @@ -2,7 +2,7 @@

    DESCRIPTION

    r.out.mpeg is a tool for combining a series of GRASS raster maps into a single MPEG-1 -(Motion +(Motion Pictures Experts Group) format file. MPEG-1 is a "lossy" video compression format, so the quality of each resulting frame of the animation will be much diminished from the diff --git a/raster/r.resamp.filter/r.resamp.filter.html b/raster/r.resamp.filter/r.resamp.filter.html index 0690a090b74..2872efd8774 100644 --- a/raster/r.resamp.filter/r.resamp.filter.html +++ b/raster/r.resamp.filter/r.resamp.filter.html @@ -14,7 +14,7 @@

    DESCRIPTION

    r.resamp.filter implements FIR (finite impulse response) filtering. All of the functions are low-pass filters, as they are symmetric. See -Wikipedia: Window function +Wikipedia: Window function for examples of common window functions and their frequency responses.

    @@ -63,7 +63,7 @@

    NOTES

    cover 3 times as large a time interval) as lanczos1 in order to get a similar frequency response (higher-order filters will fall off faster, but the frequency at which the fall-off starts should be the same). See -Wikipedia: Lanczos-kernel.svg +Wikipedia: Lanczos-kernel.svg for an illustration. If both graphs were drawn on the same axes, they would have roughly the same shape, but the a=3 window would have a longer tail. By scaling the axes to the same width, the a=3 window has a narrower diff --git a/raster/r.sim/r.sim.sediment/r.sim.sediment.html b/raster/r.sim/r.sim.sediment/r.sim.sediment.html index 025fa3f72b1..caebb9c308c 100644 --- a/raster/r.sim/r.sim.sediment/r.sim.sediment.html +++ b/raster/r.sim/r.sim.sediment/r.sim.sediment.html @@ -71,7 +71,7 @@

    REFERENCES

    In: Landscape erosion and landscape evolution modeling, Harmon R. and Doe W. eds., Kluwer Academic/Plenum Publishers, pp. 321-347.

    - + Neteler, M. and Mitasova, H., 2008, Open Source GIS: A GRASS GIS Approach. Third Edition. The International Series in Engineering and Computer Science: Volume 773. Springer New York Inc, p. 406. diff --git a/raster/r.sim/r.sim.water/r.sim.water.html b/raster/r.sim/r.sim.water/r.sim.water.html index 3c920473ca9..79cef1bfadc 100644 --- a/raster/r.sim/r.sim.water/r.sim.water.html +++ b/raster/r.sim/r.sim.water/r.sim.water.html @@ -237,7 +237,7 @@

    REFERENCES

    April 2015
  • Neteler, M. and Mitasova, H., 2008, -Open Source GIS: A GRASS GIS Approach. Third Edition. +Open Source GIS: A GRASS GIS Approach. Third Edition. The International Series in Engineering and Computer Science: Volume 773. Springer New York Inc, p. 406. diff --git a/raster/r.stream.extract/r.stream.extract.html b/raster/r.stream.extract/r.stream.extract.html index 22877936c93..acc9030d0b0 100644 --- a/raster/r.stream.extract/r.stream.extract.html +++ b/raster/r.stream.extract/r.stream.extract.html @@ -258,7 +258,7 @@

    REFERENCES

  • Holmgren, P. (1994). Multiple flow direction algorithms for runoff modelling in grid based elevation models: An empirical evaluation. -Hydrological Processes Vol 8(4), pp 327-334. DOI: 10.1002/hyp.3360080405
  • +Hydrological Processes Vol 8(4), pp 327-334. DOI: 10.1002/hyp.3360080405
  • Montgomery, D.R., Foufoula-Georgiou, E. (1993). Channel network source representation using digital elevation models. Water Resources Research Vol 29(12), pp 3925-3934.
  • diff --git a/raster/r.sun/TODO b/raster/r.sun/TODO index 3e54873977e..4d31c0314df 100644 --- a/raster/r.sun/TODO +++ b/raster/r.sun/TODO @@ -16,10 +16,10 @@ Update https://grasswiki.osgeo.org/wiki/R.sun #### -Fix http://trac.osgeo.org/grass/ticket/498 +Fix https://trac.osgeo.org/grass/ticket/498 pseudo-data test-case -http://trac.osgeo.org/grass/ticket/498#comment:22 +https://trac.osgeo.org/grass/ticket/498#comment:22 #spearfish (further north than NC so more defined shadows) g.region -d r.mapcalc "undulates = (2 + sin( row() * 2 ) + cos( col() * 2 )) * 500" diff --git a/raster/r.sun/r.sun.html b/raster/r.sun/r.sun.html index 189633f9f48..ec43813d51c 100644 --- a/raster/r.sun/r.sun.html +++ b/raster/r.sun/r.sun.html @@ -345,7 +345,7 @@

    REFERENCES

  • Neteler, M., Mitasova, H. (2002): Open Source GIS: A GRASS GIS Approach, Kluwer Academic Publishers. (Appendix explains formula; -r.sun script download) +r.sun script download)
  • Page, J. ed. (1986). Prediction of solar radiation on inclined surfaces. Solar energy R&D in the European Community, series F - Solar radiation data, diff --git a/raster/r.support/r.support.html b/raster/r.support/r.support.html index 111e46f653d..13fdf2a26af 100644 --- a/raster/r.support/r.support.html +++ b/raster/r.support/r.support.html @@ -5,12 +5,13 @@

    DESCRIPTION

    history, semantic label elements and title is supported. Category labels can also be copied from another raster map. -

    Raster band management

    +

    Raster semantic labels and band management

    + Raster semantic label concept is similar to dimension name in other GIS and -remote sensing applications. Most common usage will be assigning a -remote sensing platform sensor band ID to the raster, although any -identifier is supported. Raster semantic label is suggested to work with -imagery classification tools.
    +remote sensing applications. Most common usage will be assigning a remote +sensing platform sensor band identifier to the raster map metadata, although +any identifier is supported (see i.band.library). +Raster semantic label is suggested to work with imagery classification tools.

    EXAMPLES

    @@ -57,12 +58,14 @@

    NOTES

    SEE ALSO

    +i.band.library, r.category, r.describe, r.info, r.null, r.region, r.report, +r.semantic.label, r.timestamp diff --git a/raster/r.surf.fractal/r.surf.fractal.html b/raster/r.surf.fractal/r.surf.fractal.html index d564cbec4e1..2a2a3e3a060 100644 --- a/raster/r.surf.fractal/r.surf.fractal.html +++ b/raster/r.surf.fractal/r.surf.fractal.html @@ -11,7 +11,7 @@

    DESCRIPTION

    NOTE

    -This module requires the FFTW library +This module requires the FFTW library for computing Discrete Fourier Transforms.

    EXAMPLE

    diff --git a/raster/r.watershed/front/r.watershed.html b/raster/r.watershed/front/r.watershed.html index abe352a6948..d9a226412af 100644 --- a/raster/r.watershed/front/r.watershed.html +++ b/raster/r.watershed/front/r.watershed.html @@ -520,7 +520,7 @@

    REFERENCES

  • Holmgren P. (1994). Multiple flow direction algorithms for runoff modelling in grid based elevation models: An empirical evaluation. Hydrological Processes Vol 8(4), 327-334.
    -DOI: 10.1002/hyp.3360080405 +DOI: 10.1002/hyp.3360080405
  • Kinner D., Mitasova H., Harmon R., Toma L., Stallard R. (2005). GIS-based Stream Network Analysis for The Chagres River Basin, @@ -535,19 +535,19 @@

    REFERENCES

  • Metz M., Mitasova H., Harmon R. (2011). Efficient extraction of drainage networks from massive, radar-based elevation models with least cost path search, Hydrol. Earth Syst. Sci. Vol 15, 667-678.
    -DOI: 10.5194/hess-15-667-2011 +DOI: 10.5194/hess-15-667-2011
  • Moore I.D., Grayson R.B., Ladson A.R. (1991). Digital terrain modelling: a review of hydrogical, geomorphological, and biological applications, Hydrological Processes, Vol 5(1), 3-30
    -DOI: 10.1002/hyp.3360050103 +DOI: 10.1002/hyp.3360050103
  • Quinn P., K. Beven K., Chevallier P., Planchon O. (1991). The prediction of hillslope flow paths for distributed hydrological modelling using Digital Elevation Models, Hydrological Processes Vol 5(1), p.59-79.
    -DOI: 10.1002/hyp.3360050106 +DOI: 10.1002/hyp.3360050106
  • Weltz M. A., Renard K.G., Simanton J. R. (1987). Revised Universal Soil Loss Equation for Western Rangelands, U.S.A./Mexico Symposium of diff --git a/raster3d/r3.flow/r3.flow.html b/raster3d/r3.flow/r3.flow.html index f4f9510e7df..7a7c60fd21d 100644 --- a/raster3d/r3.flow/r3.flow.html +++ b/raster3d/r3.flow/r3.flow.html @@ -41,7 +41,7 @@

    Attributes

    NOTES

    r3.flow uses Runge-Kutta with adaptive step size -(Cash-Karp method). +(Cash-Karp method).

    EXAMPLES

    diff --git a/raster3d/r3.out.netcdf/main.c b/raster3d/r3.out.netcdf/main.c index 6bcdcbaf9f5..144c9085eef 100644 --- a/raster3d/r3.out.netcdf/main.c +++ b/raster3d/r3.out.netcdf/main.c @@ -17,7 +17,7 @@ * here: * http://cf-pcmdi.llnl.gov/documents/cf-conventions/1.6/cf-conventions.html#coordinate-system * https://cf-pcmdi.llnl.gov/trac/wiki/Cf2CrsWkt - * http://trac.osgeo.org/gdal/wiki/NetCDF_ProjectionTestingStatus + * https://trac.osgeo.org/gdal/wiki/NetCDF_ProjectionTestingStatus * *****************************************************************************/ diff --git a/raster3d/r3.out.netcdf/r3.out.netcdf.html b/raster3d/r3.out.netcdf/r3.out.netcdf.html index 9fb256a06d3..2dc69701d4d 100644 --- a/raster3d/r3.out.netcdf/r3.out.netcdf.html +++ b/raster3d/r3.out.netcdf/r3.out.netcdf.html @@ -22,7 +22,7 @@

    NOTES

    Spatial coordinates are exported as cell centered coordinates. The projection can be optionally stored in the metadata as crs attributes . The netCDF projection metadata storage follows the spatial_ref GDAL/netCDF suggestion -here +here and the netCDF CF 1.6 convention here using WKT projection information. Additional a PROJ string is diff --git a/scripts/d.polar/d.polar.html b/scripts/d.polar/d.polar.html index fad50649371..d1bbc2e6586 100644 --- a/scripts/d.polar/d.polar.html +++ b/scripts/d.polar/d.polar.html @@ -62,7 +62,7 @@

    REFERENCES

    J. Hofierka, H. Mitasova, and M. Neteler (2009): Terrain parameterization in GRASS. In T. Hengl and H.I. Reuter, editors, Geomorphometry: concepts, software, applications. Elsevier -(DOI) +(DOI)

    AUTHORS

    diff --git a/scripts/db.in.ogr/db.in.ogr.html b/scripts/db.in.ogr/db.in.ogr.html index 322f22840f0..70e7dddc1b1 100644 --- a/scripts/db.in.ogr/db.in.ogr.html +++ b/scripts/db.in.ogr/db.in.ogr.html @@ -1,7 +1,7 @@

    DESCRIPTION

    db.in.ogr imports attribute tables in various formats as -supported by the OGR library +supported by the OGR library on the local system (DBF, CSV, PostgreSQL, SQLite, MySQL, ODBC, etc.). Optionally a unique key (ID) column can be added to the table. @@ -12,7 +12,7 @@

    Import CSV file

    Limited type recognition can be done for Integer, Real, String, Date, Time and DateTime columns through a descriptive file with same name as the CSV file, but .csvt extension -(see details here). +(see details here).
     # NOTE: create koeppen_gridcode.csvt first for automated type recognition
    diff --git a/scripts/i.band.library/i.band.library.html b/scripts/i.band.library/i.band.library.html
    index b5d98d2607b..196f1319e3a 100644
    --- a/scripts/i.band.library/i.band.library.html
    +++ b/scripts/i.band.library/i.band.library.html
    @@ -95,11 +95,11 @@ 

    Band reference and semantic label relation

    NOTES

    -Semantic label concept is supported by temporal GRASS modules, -see t.register, -t.rast.list, -t.info -and t.rast.mapcalc +Semantic label concept is supported by temporal GRASS modules, see +t.register, +t.rast.list, +t.info +and t.rast.mapcalc modules for examples.

    Image collections

    diff --git a/scripts/i.in.spotvgt/i.in.spotvgt.py b/scripts/i.in.spotvgt/i.in.spotvgt.py index 666f3721761..9885caea5ec 100755 --- a/scripts/i.in.spotvgt/i.in.spotvgt.py +++ b/scripts/i.in.spotvgt/i.in.spotvgt.py @@ -20,7 +20,7 @@ ############################################################################# # # REQUIREMENTS: -# - gdal: http://www.gdal.org +# - gdal: https://gdal.org # # Notes: # * According to the faq (http://www.vgt.vito.be/faq/faq.html), SPOT vegetation @@ -125,9 +125,7 @@ def main(): # check for gdalinfo (just to check if installation is complete) if not gs.find_program("gdalinfo", "--help"): - gs.fatal( - _("'gdalinfo' not found, install GDAL tools first (http://www.gdal.org)") - ) + gs.fatal(_("'gdalinfo' not found, install GDAL tools first (https://gdal.org)")) pid = str(os.getpid()) tmpfile = gs.tempfile() diff --git a/scripts/i.pansharpen/i.pansharpen.html b/scripts/i.pansharpen/i.pansharpen.html index 9a50b84bc4e..0db14283be9 100644 --- a/scripts/i.pansharpen/i.pansharpen.html +++ b/scripts/i.pansharpen/i.pansharpen.html @@ -235,7 +235,7 @@

    REFERENCES

  • Neteler, M, D. Grasso, I. Michelazzi, L. Miori, S. Merler, and C. Furlanello (2005). An integrated toolbox for image registration, fusion and classification. International Journal of Geoinformatics, 1(1):51-61 - (PDF) + (PDF)
  • Pohl, C, and J.L van Genderen (1998). Multisensor image fusion in remote sensing: concepts, methods and application. Int. J. of Rem. Sens., 19, 823-854. diff --git a/scripts/r.grow/r.grow.html b/scripts/r.grow/r.grow.html index cbf0088ca3c..b1b037fe5bd 100644 --- a/scripts/r.grow/r.grow.html +++ b/scripts/r.grow/r.grow.html @@ -80,8 +80,8 @@

    SEE ALSO

    r.patch
    -

    Wikipedia Entry: Euclidean Metric
    -Wikipedia Entry: Manhattan Metric +

    Wikipedia Entry: Euclidean Metric
    +Wikipedia Entry: Manhattan Metric

    AUTHORS

    diff --git a/scripts/r.in.wms/r.in.wms.html b/scripts/r.in.wms/r.in.wms.html index ff95f3851ea..0031627991c 100644 --- a/scripts/r.in.wms/r.in.wms.html +++ b/scripts/r.in.wms/r.in.wms.html @@ -22,7 +22,7 @@

    NOTES

    When using GDAL WMS driver (driver=WMS_GDAL), the GDAL library needs to be built with WMS support, -see GDAL WMS manual page +see GDAL WMS manual page for details.

    Tiled WMS

    diff --git a/scripts/r.semantic.label/r.semantic.label.html b/scripts/r.semantic.label/r.semantic.label.html index 9ebcfce10a6..45ac7b9373e 100644 --- a/scripts/r.semantic.label/r.semantic.label.html +++ b/scripts/r.semantic.label/r.semantic.label.html @@ -25,10 +25,10 @@

    NOTES

    Semantic labels are supported by temporal GRASS modules. Name of STRDS can be extended by band identifier in order to filter the result by a semantic label. See -t.register, -t.rast.list, -t.info -and t.rast.mapcalc +t.register, +t.rast.list, +t.info +and t.rast.mapcalc modules for examples.

    EXAMPLES

    diff --git a/scripts/v.db.dropcolumn/v.db.dropcolumn.py b/scripts/v.db.dropcolumn/v.db.dropcolumn.py index 298a29133b3..fd34f36893f 100755 --- a/scripts/v.db.dropcolumn/v.db.dropcolumn.py +++ b/scripts/v.db.dropcolumn/v.db.dropcolumn.py @@ -86,7 +86,7 @@ def main(): if driver == "sqlite": # echo "Using special trick for SQLite" - # http://www.sqlite.org/faq.html#q11 + # https://www.sqlite.org/faq.html#q11 colnames = [] coltypes = [] for f in gs.db_describe(table, database=database, driver=driver)["cols"]: diff --git a/scripts/v.db.join/v.db.join.html b/scripts/v.db.join/v.db.join.html index e44705c55b5..436c86a7d43 100644 --- a/scripts/v.db.join/v.db.join.html +++ b/scripts/v.db.join/v.db.join.html @@ -16,8 +16,8 @@

    EXAMPLES

    Exercise to join North Carolina geological classes from a CSV table to the "geology" map of the North Carolina sample dataset (requires download -of legend CSV file nc_geology.csv -from External data for NC sample dataset): +of legend CSV file nc_geology.csv +from External data for NC sample dataset):
     # check original map attributes
    @@ -49,7 +49,7 @@ 

    EXAMPLES

    Soil map table join

    Joining the soil type explanations from table soils_legend -into the Spearfish soils map (download legend): +into the Spearfish soils map (download legend):
     g.copy vect=soils,mysoils
    diff --git a/scripts/v.db.reconnect.all/v.db.reconnect.all.py b/scripts/v.db.reconnect.all/v.db.reconnect.all.py
    index 9a9d46356a9..7a422f47f7f 100755
    --- a/scripts/v.db.reconnect.all/v.db.reconnect.all.py
    +++ b/scripts/v.db.reconnect.all/v.db.reconnect.all.py
    @@ -19,6 +19,8 @@
     # % keyword: vector
     # % keyword: attribute table
     # % keyword: database
    +# % keyword: DBF
    +# % keyword: SQLite
     # %end
     # %flag
     # % key: c
    diff --git a/scripts/v.import/v.import.html b/scripts/v.import/v.import.html
    index a530f5f3662..281136939e2 100644
    --- a/scripts/v.import/v.import.html
    +++ b/scripts/v.import/v.import.html
    @@ -1,7 +1,7 @@
     

    DESCRIPTION

    v.import imports vector data from files and database connections -supported by the OGR library into the +supported by the OGR library into the current project (previously called location) and mapset. If the coordinate reference system (CRS) of the input does not match the CRS of the project, the input is reprojected @@ -11,13 +11,13 @@

    DESCRIPTION

    Supported Vector Formats

    v.import uses the OGR library which supports various vector data -formats including ESRI -Shapefile, Mapinfo +formats including ESRI +Shapefile, Mapinfo File, UK .NTF, SDTS, TIGER, IHO S-57 (ENC), DGN, GML, GPX, AVCBin, REC, Memory, OGDI, and PostgreSQL, depending on the local OGR installation. For details see the OGR web site. The OGR (Simple Features Library) is part of the -GDAL library, hence GDAL needs to be +GDAL library, hence GDAL needs to be installed to use v.import.

    diff --git a/scripts/v.in.e00/v.in.e00.html b/scripts/v.in.e00/v.in.e00.html index ef027c192e2..931bec50cf6 100644 --- a/scripts/v.in.e00/v.in.e00.html +++ b/scripts/v.in.e00/v.in.e00.html @@ -12,7 +12,7 @@

    NOTES

    REFERENCES

    AVCE00 library (providing 'avcimport' and 'e00conv')
    -OGR vector library +OGR vector library

    SEE ALSO

    diff --git a/scripts/v.in.geonames/v.in.geonames.html b/scripts/v.in.geonames/v.in.geonames.html index f2657c878c3..a38aa770cc5 100644 --- a/scripts/v.in.geonames/v.in.geonames.html +++ b/scripts/v.in.geonames/v.in.geonames.html @@ -78,4 +78,4 @@

    SEE ALSO

    AUTHOR

    -Markus Neteler +Markus Neteler diff --git a/temporal/t.rast.algebra/t.rast.algebra.html b/temporal/t.rast.algebra/t.rast.algebra.html index 126ed5df9c2..b7fda851224 100644 --- a/temporal/t.rast.algebra/t.rast.algebra.html +++ b/temporal/t.rast.algebra/t.rast.algebra.html @@ -608,10 +608,10 @@

    REFERENCES

    Related publications:
    • Gebbert, S., Pebesma, E. 2014. TGRASS: A temporal GIS for field based environmental modeling. - Environmental Modelling & Software 53, 1-12 (DOI) + Environmental Modelling & Software 53, 1-12 (DOI) - preprint PDF
    • Gebbert, S., Pebesma, E. 2017. The GRASS GIS temporal framework. International Journal of - Geographical Information Science 31, 1273-1292 (DOI)
    • + Geographical Information Science 31, 1273-1292 (DOI)
    • Gebbert, S., Leppelt, T., Pebesma, E., 2019. A topology based spatio-temporal map algebra for big data analysis. Data 4, 86. (DOI)
    diff --git a/temporal/temporalintro.html b/temporal/temporalintro.html index c5eca6ead2c..2780efd8c85 100644 --- a/temporal/temporalintro.html +++ b/temporal/temporalintro.html @@ -262,11 +262,11 @@

    See also

    • Gebbert, S., Pebesma, E. 2014. TGRASS: A temporal GIS for field based environmental modeling. - Environmental Modelling & Software 53, 1-12 (DOI) + Environmental Modelling & Software 53, 1-12 (DOI) - preprint PDF
    • Gebbert, S., Pebesma, E. 2017. The GRASS GIS temporal framework. International Journal of - Geographical Information Science 31, 1273-1292 (DOI)
    • + Geographical Information Science 31, 1273-1292 (DOI)
    • Gebbert, S., Leppelt, T., Pebesma, E., 2019. A topology based spatio-temporal map algebra for big data analysis. Data 4, 86. (DOI)
    • diff --git a/vector/v.buffer/v.buffer.html b/vector/v.buffer/v.buffer.html index 8c835331630..06b2828cdfb 100644 --- a/vector/v.buffer/v.buffer.html +++ b/vector/v.buffer/v.buffer.html @@ -154,7 +154,7 @@

      Buffer inside input areas

      REFERENCES

      SEE ALSO

      diff --git a/vector/v.cluster/v.cluster.html b/vector/v.cluster/v.cluster.html index 0e92f266eb9..9447538afab 100644 --- a/vector/v.cluster/v.cluster.html +++ b/vector/v.cluster/v.cluster.html @@ -21,7 +21,7 @@

      DESCRIPTION

      separately for each observed density (distance to the farthest neighbor).

      dbscan

      -The Density-Based Spatial +The Density-Based Spatial Clustering of Applications with Noise is a commonly used clustering algorithm. A new cluster is started for a point with at least min - 1 neighbors within the maximum distance. These neighbors @@ -46,7 +46,7 @@

      density

      optics

      This method is Ordering Points to +href="https://en.wikipedia.org/wiki/OPTICS_algorithm">Ordering Points to Identify the Clustering Structure. It is controlled by the number of neighbor points (option min - 1). The core distance of a point is the distance to the farthest neighbor. The reachability of a diff --git a/vector/v.external.out/v.external.out.html b/vector/v.external.out/v.external.out.html index 1d82620f17c..f9c3575aa88 100644 --- a/vector/v.external.out/v.external.out.html +++ b/vector/v.external.out/v.external.out.html @@ -2,9 +2,9 @@

      DESCRIPTION

      v.external.out instructs GRASS to write vector maps in external data format (e.g. ESRI Shapefile, Mapinfo, and others) -using OGR library. PostGIS data can +using OGR library. PostGIS data can be also written by -built-in GRASS-PostGIS +built-in GRASS-PostGIS data provider.

      NOTES

      @@ -26,9 +26,9 @@

      NOTES

      by format option. See the list of valid creation options at OGR formats specification page, example -for ESRI +for ESRI Shapefile -or PostgreSQL/PostGIS +or PostgreSQL/PostGIS format (section "Layer Creation Options"). Options are comma-separated pairs (key=value), the options are case-insensitive, @@ -180,10 +180,10 @@

      Restore settings

      REFERENCES

      SEE ALSO

      diff --git a/vector/v.external/v.external.html b/vector/v.external/v.external.html index fb1512f8942..200d3726363 100644 --- a/vector/v.external/v.external.html +++ b/vector/v.external/v.external.html @@ -3,7 +3,7 @@

      DESCRIPTION

      v.external creates new vector map as a link to external OGR layer or PostGIS feature table. OGR (Simple Features Library) is part of the -GDAL library, so you need to install +GDAL library, so you need to install GDAL to use v.external for external OGR layers. Note that a PostGIS feature table can be linked also using built-in GRASS-PostGIS data driver (requires GRASS to be built with PostgreSQL support). @@ -140,7 +140,7 @@

      SEE ALSO

      -GDAL Library +GDAL Library
      PostGIS diff --git a/vector/v.in.dxf/v.in.dxf.html b/vector/v.in.dxf/v.in.dxf.html index 85d05623344..a08d2fbb5ee 100644 --- a/vector/v.in.dxf/v.in.dxf.html +++ b/vector/v.in.dxf/v.in.dxf.html @@ -45,7 +45,7 @@

      DESCRIPTION

      REFERENCES

      -AutoCad DXF (from Wikipedia, the free encyclopedia)
      +AutoCad DXF (from Wikipedia, the free encyclopedia)
      DXF References (Autodesk-supplied documentation)

      SEE ALSO

      diff --git a/vector/v.kernel/v.kernel.html b/vector/v.kernel/v.kernel.html index c2bd14c87b5..3a5a0162129 100644 --- a/vector/v.kernel/v.kernel.html +++ b/vector/v.kernel/v.kernel.html @@ -2,7 +2,7 @@

      DESCRIPTION

      v.kernel generates a raster density map from vector points data using a moving -kernel. Available kernel +kernel. Available kernel density functions are uniform, triangular, epanechnikov, quartic, triweight, gaussian, cosine, default is gaussian. @@ -20,7 +20,7 @@

      NOTES

      (integer). The density result stored as category may be multiplied by this number.

      For the gaussian kernel, standard deviation for the -gaussian function +gaussian function is set to 1/4 of the radius.

      With the -o flag (experimental) the command tries to calculate an @@ -54,7 +54,7 @@

      REFERENCES

      method for networks, its computational method and a GIS-based tool. International Journal of Geographical Information Science, Vol 23(1), pp. 7-32.
      -DOI: 10.1080/13658810802475491 +DOI: 10.1080/13658810802475491

    SEE ALSO

    diff --git a/vector/v.label.sa/v.label.sa.html b/vector/v.label.sa/v.label.sa.html index 65864c78a2e..2376c70771c 100644 --- a/vector/v.label.sa/v.label.sa.html +++ b/vector/v.label.sa/v.label.sa.html @@ -41,7 +41,7 @@

    SEE ALSO

    d.label
    d.labels
    ps.map -Wikipedia article on simulated annealing +Wikipedia article on simulated annealing

    AUTHOR

    diff --git a/vector/v.net.bridge/v.net.bridge.html b/vector/v.net.bridge/v.net.bridge.html index fedb0559d6c..accd2484a33 100644 --- a/vector/v.net.bridge/v.net.bridge.html +++ b/vector/v.net.bridge/v.net.bridge.html @@ -8,8 +8,8 @@

    NOTES

    the (sub-)network. A node is an articulation point if its removal would disconnect the (sub-)network. For more information and formal definitions check the wikipedia entries: -bridge -and articulation +bridge +and articulation point.

    The output of the module contains the selected diff --git a/vector/v.net.centrality/v.net.centrality.html b/vector/v.net.centrality/v.net.centrality.html index bd122149d34..28871b660e3 100644 --- a/vector/v.net.centrality/v.net.centrality.html +++ b/vector/v.net.centrality/v.net.centrality.html @@ -9,7 +9,7 @@

    NOTES

    stores them in the given columns of an attribute table, which is created and linked to the output map. For the description of these, please check the following -wikipedia article. +wikipedia article. If the column name is not given for a measure then that measure is not computed. If -a flag is set then points are added on nodes without points. Also, the points for which the output is computed diff --git a/vector/v.net.flow/v.net.flow.html b/vector/v.net.flow/v.net.flow.html index 66a617cb0e6..9a15c95301e 100644 --- a/vector/v.net.flow/v.net.flow.html +++ b/vector/v.net.flow/v.net.flow.html @@ -23,7 +23,7 @@

    NOTES

    flowing in the backward direction. Cut map contains the edges in the minimum cut.
    -A famous result +A famous result says that the total amount of water flowing is equal to the minimum cut. diff --git a/vector/v.net/v.net.html b/vector/v.net/v.net.html index ab112155589..baef25e5484 100644 --- a/vector/v.net/v.net.html +++ b/vector/v.net/v.net.html @@ -154,7 +154,7 @@

    NOTES

    EXAMPLES

    -The examples are North Carolina dataset based. +The examples are North Carolina dataset based.

    Create nodes globally for all line ends and intersections

    diff --git a/vector/v.out.ascii/v.out.ascii.html b/vector/v.out.ascii/v.out.ascii.html index 2eff87a01fa..d8b6440b1c7 100644 --- a/vector/v.out.ascii/v.out.ascii.html +++ b/vector/v.out.ascii/v.out.ascii.html @@ -109,7 +109,7 @@

    Point mode

    WKT mode

    WKT is abbreviation -for Well-known +for Well-known text.
    diff --git a/vector/v.out.dxf/v.out.dxf.html b/vector/v.out.dxf/v.out.dxf.html
    index 853e19472bd..95057f05f22 100644
    --- a/vector/v.out.dxf/v.out.dxf.html
    +++ b/vector/v.out.dxf/v.out.dxf.html
    @@ -12,7 +12,7 @@ 

    NOTES

    REFERENCES

    -AutoCad DXF (from Wikipedia, the free encyclopedia) +AutoCad DXF (from Wikipedia, the free encyclopedia)

    SEE ALSO

    diff --git a/vector/v.out.ogr/v.out.ogr.html b/vector/v.out.ogr/v.out.ogr.html index d9a2c84049b..664a5c35a1a 100644 --- a/vector/v.out.ogr/v.out.ogr.html +++ b/vector/v.out.ogr/v.out.ogr.html @@ -1,27 +1,27 @@

    DESCRIPTION

    v.out.ogr converts GRASS vector map layer to any of the -supported OGR vector formats +supported OGR vector formats (including OGC GeoPackage, ESRI Shapefile, SpatiaLite or GML).

    OGR (Simple Features Library) is part of the -GDAL library, so you need to +GDAL library, so you need to install this library to use v.out.ogr.

    The OGR library supports many various formats including:

    @@ -193,7 +193,7 @@

    Export to KML (Google Earth)

    REFERENCES

    diff --git a/vector/v.out.postgis/v.out.postgis.html b/vector/v.out.postgis/v.out.postgis.html index 104a9ad2dae..aa9bd459778 100644 --- a/vector/v.out.postgis/v.out.postgis.html +++ b/vector/v.out.postgis/v.out.postgis.html @@ -65,8 +65,8 @@

    NOTES

    "geom". Name of the geometry column can be changed by options=GEOMETRY_NAME=<column>. Note that for exporting vector features as simple features can be alternatively -used PostgreSQL driver -from OGR library +used PostgreSQL driver +from OGR library through v.out.ogr module.

    diff --git a/vector/v.surf.rst/v.surf.rst.html b/vector/v.surf.rst/v.surf.rst.html index 66a39ebc6f8..199ca4fc3ca 100644 --- a/vector/v.surf.rst/v.surf.rst.html +++ b/vector/v.surf.rst/v.surf.rst.html @@ -389,7 +389,7 @@

    REFERENCES

  • Mitas, L., and Mitasova H., 1988, General variational approach to the approximation problem, Computers and Mathematics with Applications, v.16, p. 983-992.
  • -
  • +
  • Neteler, M. and Mitasova, H., 2008, Open Source GIS: A GRASS GIS Approach, 3rd Edition, Springer, New York, 406 pages.
  • Talmi, A. and Gilat, G., 1977 : Method for Smooth Approximation of Data, diff --git a/vector/v.univar/main.c b/vector/v.univar/main.c index f84bf118fab..85217498035 100644 --- a/vector/v.univar/main.c +++ b/vector/v.univar/main.c @@ -19,7 +19,7 @@ /* TODO * - add flag to weigh by line/boundary length and area size * Roger Bivand on GRASS devel ml on July 2 2004 - * http://lists.osgeo.org/pipermail/grass-dev/2004-July/014976.html + * https://lists.osgeo.org/pipermail/grass-dev/2004-July/014976.html * "[...] calculating weighted means, weighting by line length * or area surface size [does not make sense]. I think it would be * better to treat each line or area as a discrete, unweighted, unit diff --git a/vector/v.vol.rst/v.vol.rst.html b/vector/v.vol.rst/v.vol.rst.html index 06fc55e5118..571a162162c 100644 --- a/vector/v.vol.rst/v.vol.rst.html +++ b/vector/v.vol.rst/v.vol.rst.html @@ -85,7 +85,7 @@

    Cross validation procedure

    representing the whole dataset.

    Example - (based on Slovakia3d dataset): + (based on Slovakia3d dataset):

     v.info -c precip3d
     g.region n=5530000 s=5275000 w=4186000 e=4631000 res=500 -p
    diff --git a/vector/v.voronoi/v.voronoi.html b/vector/v.voronoi/v.voronoi.html
    index 0b2c9e4cd40..e719c2c0038 100644
    --- a/vector/v.voronoi/v.voronoi.html
    +++ b/vector/v.voronoi/v.voronoi.html
    @@ -82,7 +82,7 @@ 

    REFERENCES

    Steve J. Fortune, (1987). A Sweepline Algorithm for Voronoi Diagrams, Algorithmica 2, 153-174 - (DOI). + (DOI).

    SEE ALSO

    From 86693f6ce763abc2fd1fd563b4b442bba2da8d3c Mon Sep 17 00:00:00 2001 From: Arohan Ajit Date: Fri, 25 Oct 2024 13:32:09 -0400 Subject: [PATCH 22/55] wxGUI: FIxed bare except in photo2image/ (#4582) --- .flake8 | 3 +-- gui/wxpython/photo2image/ip2i_manager.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.flake8 b/.flake8 index 7bc3070d15e..e73cc6d94c5 100644 --- a/.flake8 +++ b/.flake8 @@ -24,8 +24,7 @@ per-file-ignores = gui/scripts/d.wms.py: E501 gui/wxpython/image2target/g.gui.image2target.py: E501 gui/wxpython/nviz/*: E722 - gui/wxpython/photo2image/*: F841, E722, E265 - gui/wxpython/photo2image/g.gui.photo2image.py: E501, F841 + gui/wxpython/photo2image/g.gui.photo2image.py: E501 gui/wxpython/psmap/*: E501, E722 gui/wxpython/vdigit/*: F841, E722, F405, F403 gui/wxpython/animation/g.gui.animation.py: E501 diff --git a/gui/wxpython/photo2image/ip2i_manager.py b/gui/wxpython/photo2image/ip2i_manager.py index 711ec4191af..d0726a3bae2 100644 --- a/gui/wxpython/photo2image/ip2i_manager.py +++ b/gui/wxpython/photo2image/ip2i_manager.py @@ -163,7 +163,7 @@ def __init__( if p.returncode == 0: print("returncode = ", str(p.returncode)) self.Map.region = self.Map.GetRegion() - except: + except Exception: pass self.SwitchEnv("source") From 1a04b6401f7a3e1723e01fd213df6939ec7cf638 Mon Sep 17 00:00:00 2001 From: Arohan Ajit Date: Fri, 25 Oct 2024 13:33:31 -0400 Subject: [PATCH 23/55] r.fillnulls: Removed bare except from r.fillnulls (#4581) --- .flake8 | 1 - scripts/r.fillnulls/r.fillnulls.py | 8 ++++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/.flake8 b/.flake8 index e73cc6d94c5..c29f447c597 100644 --- a/.flake8 +++ b/.flake8 @@ -101,7 +101,6 @@ per-file-ignores = scripts/db.univar/db.univar.py: E501 scripts/d.frame/d.frame.py: E722 scripts/i.pansharpen/i.pansharpen.py: E722, E501 - scripts/r.fillnulls/r.fillnulls.py: E722 scripts/v.what.strds/v.what.strds.py: E501 # Line too long (esp. module interface definitions) scripts/*/*.py: E501 diff --git a/scripts/r.fillnulls/r.fillnulls.py b/scripts/r.fillnulls/r.fillnulls.py index a53d19a8a72..b22550db497 100755 --- a/scripts/r.fillnulls/r.fillnulls.py +++ b/scripts/r.fillnulls/r.fillnulls.py @@ -273,7 +273,7 @@ def main(): type="area", quiet=quiet, ) - except: + except CalledModuleError: gs.fatal( _( "abandoned. Removing temporary maps, restoring " @@ -481,7 +481,7 @@ def main(): tmp_rmaps.remove(holename + "_edges") tmp_rmaps.remove(holename + "_dem") tmp_vmaps.remove(holename) - except: + except ValueError: pass gs.warning( _( @@ -545,7 +545,7 @@ def main(): tmp_rmaps.remove(holename + "_grown") tmp_rmaps.remove(holename + "_edges") tmp_rmaps.remove(holename + "_dem") - except: + except ValueError: pass try: gs.run_command( @@ -569,7 +569,7 @@ def main(): ) try: tmp_vmaps.remove(holename) - except: + except ValueError: pass try: gs.run_command( From 9e1e85d6079f36962f19b32793b31f43c23b5a4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Fri, 25 Oct 2024 13:34:52 -0400 Subject: [PATCH 24/55] style: Fix if-else-block-instead-of-if-exp (SIM108) (part 3) (#4570) * style: Fix if-else-block-instead-of-if-exp (SIM108) in scripts/ Ruff rule: https://docs.astral.sh/ruff/rules/if-else-block-instead-of-if-exp * style: Fix if-else-block-instead-of-if-exp (SIM108) in python/ Ruff rule: https://docs.astral.sh/ruff/rules/if-else-block-instead-of-if-exp * checks: Rename inner variable shadowing type to _type in python/grass/temporal/gui_support.py * style: Manual fixes for if-else-block-instead-of-if-exp (SIM108) in python/ Ruff rule: https://docs.astral.sh/ruff/rules/if-else-block-instead-of-if-exp * style: Fix if-else-block-instead-of-if-exp (SIM108) in gui/ Ruff rule: https://docs.astral.sh/ruff/rules/if-else-block-instead-of-if-exp * checks: Rename inner variable shadowing list to _list in gui/wxpython/core/render.py * style: Manual fixes for if-else-block-instead-of-if-exp (SIM108) in gui/ Ruff rule: https://docs.astral.sh/ruff/rules/if-else-block-instead-of-if-exp * python: Add type annotations for grass.script.core.parser() * python: Add type annotations for is_time_absolute() and is_time_relative() in grass.temporal.AbstractDataset * style: Enable Checking for SIM108 * Update pyproject.toml to remove fixed issues * Update base.py Co-authored-by: Anna Petrasova --------- Co-authored-by: Anna Petrasova --- gui/wxpython/animation/dialogs.py | 5 +- gui/wxpython/animation/frame.py | 17 ++---- gui/wxpython/animation/temporal_manager.py | 6 +-- gui/wxpython/core/gcmd.py | 5 +- gui/wxpython/core/gconsole.py | 10 +--- gui/wxpython/core/menutree.py | 32 +++-------- gui/wxpython/core/render.py | 45 ++++------------ gui/wxpython/core/settings.py | 5 +- gui/wxpython/core/treemodel.py | 7 +-- gui/wxpython/core/utils.py | 5 +- gui/wxpython/core/workspace.py | 22 ++------ gui/wxpython/datacatalog/tree.py | 5 +- gui/wxpython/dbmgr/base.py | 37 +++---------- gui/wxpython/dbmgr/dialogs.py | 10 +--- gui/wxpython/dbmgr/sqlbuilder.py | 10 +--- gui/wxpython/gcp/manager.py | 21 ++------ gui/wxpython/gmodeler/dialogs.py | 16 ++---- gui/wxpython/gmodeler/model.py | 62 +++++----------------- gui/wxpython/gmodeler/panels.py | 14 ++--- gui/wxpython/gui_core/dialogs.py | 15 ++---- gui/wxpython/gui_core/forms.py | 41 +++----------- gui/wxpython/gui_core/gselect.py | 27 ++-------- gui/wxpython/gui_core/mapdisp.py | 5 +- gui/wxpython/gui_core/menu.py | 5 +- gui/wxpython/gui_core/preferences.py | 5 +- gui/wxpython/gui_core/prompt.py | 5 +- gui/wxpython/gui_core/treeview.py | 5 +- gui/wxpython/iclass/dialogs.py | 6 +-- gui/wxpython/iclass/digit.py | 12 ++--- gui/wxpython/image2target/ii2t_gis_set.py | 5 +- gui/wxpython/image2target/ii2t_manager.py | 22 ++------ gui/wxpython/iscatt/controllers.py | 10 +--- gui/wxpython/iscatt/core_c.py | 6 +-- gui/wxpython/iscatt/frame.py | 6 +-- gui/wxpython/iscatt/iscatt_core.py | 6 +-- gui/wxpython/lmgr/frame.py | 10 +--- gui/wxpython/lmgr/layertree.py | 24 ++------- gui/wxpython/lmgr/menudata.py | 10 +--- gui/wxpython/location_wizard/wizard.py | 5 +- gui/wxpython/main_window/frame.py | 10 +--- gui/wxpython/mapdisp/frame.py | 11 ++-- gui/wxpython/mapdisp/toolbars.py | 5 +- gui/wxpython/mapwin/buffered.py | 25 ++------- gui/wxpython/mapwin/decorations.py | 10 +--- gui/wxpython/modules/colorrules.py | 25 ++------- gui/wxpython/modules/extensions.py | 6 +-- gui/wxpython/modules/import_export.py | 10 +--- gui/wxpython/modules/mcalc_builder.py | 5 +- gui/wxpython/nviz/mapwindow.py | 5 +- gui/wxpython/nviz/tools.py | 42 ++++----------- gui/wxpython/nviz/workspace.py | 5 +- gui/wxpython/nviz/wxnviz.py | 17 ++---- gui/wxpython/photo2image/ip2i_manager.py | 15 ++---- gui/wxpython/psmap/dialogs.py | 57 ++++---------------- gui/wxpython/psmap/frame.py | 35 +++--------- gui/wxpython/psmap/utils.py | 10 +--- gui/wxpython/rdigit/controller.py | 5 +- gui/wxpython/timeline/frame.py | 14 +++-- gui/wxpython/tools/update_menudata.py | 5 +- gui/wxpython/tplot/frame.py | 5 +- gui/wxpython/vdigit/dialogs.py | 5 +- gui/wxpython/vdigit/mapwindow.py | 10 +--- gui/wxpython/vdigit/preferences.py | 22 ++------ gui/wxpython/vdigit/toolbars.py | 5 +- gui/wxpython/vdigit/wxdigit.py | 5 +- gui/wxpython/vdigit/wxdisplay.py | 12 ++--- gui/wxpython/vnet/dialogs.py | 7 +-- gui/wxpython/vnet/vnet_data.py | 32 +++-------- gui/wxpython/vnet/vnet_utils.py | 5 +- gui/wxpython/web_services/widgets.py | 10 +--- gui/wxpython/wxgui.py | 5 +- gui/wxpython/wxplot/scatter.py | 6 +-- pyproject.toml | 3 +- python/grass/script/core.py | 10 ++-- python/grass/temporal/abstract_dataset.py | 6 ++- 75 files changed, 225 insertions(+), 804 deletions(-) diff --git a/gui/wxpython/animation/dialogs.py b/gui/wxpython/animation/dialogs.py index 644553ec328..5a634b3bb16 100644 --- a/gui/wxpython/animation/dialogs.py +++ b/gui/wxpython/animation/dialogs.py @@ -1619,10 +1619,7 @@ def SetStdsProperties(self, layer): dlg.CenterOnParent() if dlg.ShowModal() == wx.ID_OK: layer = dlg.GetLayer() - if hidden: - signal = self.layerAdded - else: - signal = self.cmdChanged + signal = self.layerAdded if hidden else self.cmdChanged signal.emit(index=self._layerList.GetLayerIndex(layer), layer=layer) elif hidden: self._layerList.RemoveLayer(layer) diff --git a/gui/wxpython/animation/frame.py b/gui/wxpython/animation/frame.py index 6496920a5cd..42953803778 100644 --- a/gui/wxpython/animation/frame.py +++ b/gui/wxpython/animation/frame.py @@ -274,17 +274,11 @@ def OnStop(self, event): self.controller.EndAnimation() def OnOneDirectionReplay(self, event): - if event.IsChecked(): - mode = ReplayMode.REPEAT - else: - mode = ReplayMode.ONESHOT + mode = ReplayMode.REPEAT if event.IsChecked() else ReplayMode.ONESHOT self.controller.SetReplayMode(mode) def OnBothDirectionReplay(self, event): - if event.IsChecked(): - mode = ReplayMode.REVERSE - else: - mode = ReplayMode.ONESHOT + mode = ReplayMode.REVERSE if event.IsChecked() else ReplayMode.ONESHOT self.controller.SetReplayMode(mode) def OnAdjustSpeed(self, event): @@ -642,11 +636,8 @@ def _updateFrameIndex(self, index): } else: label = _("to %(to)s") % {"to": self.timeLabels[index][1]} - else: # noqa: PLR5501 - if self.temporalType == TemporalType.ABSOLUTE: - label = start - else: - label = "" + else: + label = start if self.temporalType == TemporalType.ABSOLUTE else "" self.label2.SetLabel(label) if self.temporalType == TemporalType.RELATIVE: self.indexField.SetValue(start) diff --git a/gui/wxpython/animation/temporal_manager.py b/gui/wxpython/animation/temporal_manager.py index ef782543089..1b5037639cf 100644 --- a/gui/wxpython/animation/temporal_manager.py +++ b/gui/wxpython/animation/temporal_manager.py @@ -259,10 +259,8 @@ def _getLabelsAndMaps(self, timeseries): elif self.temporalType == TemporalType.RELATIVE: unit = self.timeseriesInfo[timeseries]["unit"] - if self.granularityMode == GranularityMode.ONE_UNIT: - gran = 1 - else: - gran = granNum + gran = 1 if self.granularityMode == GranularityMode.ONE_UNIT else granNum + # start sampling - now it can be used for both interval and point data # after instance, there can be a gap or an interval # if it is a gap we remove it and put there the previous instance instead diff --git a/gui/wxpython/core/gcmd.py b/gui/wxpython/core/gcmd.py index a173e28c7f8..134ed756d23 100644 --- a/gui/wxpython/core/gcmd.py +++ b/gui/wxpython/core/gcmd.py @@ -709,10 +709,7 @@ def RunCommand( kwargs["stdin"] = subprocess.PIPE # Do not change the environment, only a local copy. - if env: - env = env.copy() - else: - env = os.environ.copy() + env = env.copy() if env else os.environ.copy() if parent: env["GRASS_MESSAGE_FORMAT"] = "standard" diff --git a/gui/wxpython/core/gconsole.py b/gui/wxpython/core/gconsole.py index a4b58435cf4..5b58c08cc55 100644 --- a/gui/wxpython/core/gconsole.py +++ b/gui/wxpython/core/gconsole.py @@ -310,10 +310,7 @@ def write(self, s): if "GRASS_INFO_PERCENT" in line: value = int(line.rsplit(":", 1)[1].strip()) - if value >= 0 and value < 100: - progressValue = value - else: - progressValue = 0 + progressValue = value if value >= 0 and value < 100 else 0 elif "GRASS_INFO_MESSAGE" in line: self.type = "message" self.message += line.split(":", 1)[1].strip() + "\n" @@ -632,10 +629,7 @@ def load_source(modname, filename): return - if env: - env = env.copy() - else: - env = os.environ.copy() + env = env.copy() if env else os.environ.copy() # activate computational region (set with g.region) # for all non-display commands. if compReg and "GRASS_REGION" in env: diff --git a/gui/wxpython/core/menutree.py b/gui/wxpython/core/menutree.py index fba33daf705..b8f60e9610a 100644 --- a/gui/wxpython/core/menutree.py +++ b/gui/wxpython/core/menutree.py @@ -108,30 +108,14 @@ def _createItem(self, item, node): shortcut = item.find("shortcut") # optional wxId = item.find("id") # optional icon = item.find("icon") # optional - if gcmd is not None: - gcmd = gcmd.text - else: - gcmd = "" - if desc.text: - desc = _(desc.text) - else: - desc = "" - if keywords is None or keywords.text is None: - keywords = "" - else: - keywords = keywords.text - if shortcut is not None: - shortcut = shortcut.text - else: - shortcut = "" - if wxId is not None: - wxId = eval("wx." + wxId.text) - else: - wxId = wx.ID_ANY - if icon is not None: - icon = icon.text - else: - icon = "" + gcmd = gcmd.text if gcmd is not None else "" + desc = _(desc.text) if desc.text else "" + keywords = ( + "" if keywords is None or keywords.text is None else keywords.text + ) + shortcut = shortcut.text if shortcut is not None else "" + wxId = eval("wx." + wxId.text) if wxId is not None else wx.ID_ANY + icon = icon.text if icon is not None else "" label = origLabel if gcmd: if self.menustyle == 1: diff --git a/gui/wxpython/core/render.py b/gui/wxpython/core/render.py index 2db3287bf78..989287cd4a5 100644 --- a/gui/wxpython/core/render.py +++ b/gui/wxpython/core/render.py @@ -100,10 +100,7 @@ def __init__( if mapfile: self.mapfile = mapfile else: - if ltype == "overlay": - tempfile_sfx = ".png" - else: - tempfile_sfx = ".ppm" + tempfile_sfx = ".png" if ltype == "overlay" else ".ppm" self.mapfile = get_tempfile_name(suffix=tempfile_sfx) @@ -790,10 +787,7 @@ def ReportProgress(self, env, layer=None): stText += "..." if self.progressInfo["range"] != len(self.progressInfo["rendered"]): - if stText: - stText = _("Rendering & ") + stText - else: - stText = _("Rendering...") + stText = _("Rendering & ") + stText if stText else _("Rendering...") self.updateProgress.emit( range=self.progressInfo["range"], @@ -1260,16 +1254,8 @@ def GetListOfLayers( :return: list of selected layers """ selected = [] - - if isinstance(ltype, str): - one_type = True - else: - one_type = False - - if one_type and ltype == "overlay": - llist = self.overlays - else: - llist = self.layers + one_type = bool(isinstance(ltype, str)) + llist = self.overlays if one_type and ltype == "overlay" else self.layers # ["raster", "vector", "wms", ... ] for layer in llist: @@ -1332,10 +1318,7 @@ def Render(self, force=False, windres=False): self.renderMgr.Render(force, windres) def _addLayer(self, layer, pos=-1): - if layer.type == "overlay": - llist = self.overlays - else: - llist = self.layers + llist = self.overlays if layer.type == "overlay" else self.layers # add maplayer to the list of layers if pos > -1: @@ -1426,12 +1409,9 @@ def DeleteLayer(self, layer, overlay=False): """ Debug.msg(3, "Map.DeleteLayer(): name=%s" % layer.name) - if overlay: - list = self.overlays - else: - list = self.layers + _list = self.overlays if overlay else self.layers - if layer in list: + if layer in _list: if layer.mapfile: base, mapfile = os.path.split(layer.mapfile) tempbase = mapfile.split(".")[0] @@ -1448,7 +1428,7 @@ def DeleteLayer(self, layer, overlay=False): if os.path.isfile(layer._legrow): os.remove(layer._legrow) - list.remove(layer) + _list.remove(layer) self.layerRemoved.emit(layer=layer) return layer @@ -1583,13 +1563,10 @@ def GetLayerIndex(self, layer, overlay=False): :return: layer index :return: -1 if layer not found """ - if overlay: - list = self.overlays - else: - list = self.layers + _list = self.overlays if overlay else self.layers - if layer in list: - return list.index(layer) + if layer in _list: + return _list.index(layer) return -1 diff --git a/gui/wxpython/core/settings.py b/gui/wxpython/core/settings.py index b155d9607af..05c6579e636 100644 --- a/gui/wxpython/core/settings.py +++ b/gui/wxpython/core/settings.py @@ -960,10 +960,7 @@ def _readLegacyFile(self, settings=None): del kv[0] idx = 0 while idx < len(kv): - if subkeyMaster: - subkey = [subkeyMaster, kv[idx]] - else: - subkey = kv[idx] + subkey = [subkeyMaster, kv[idx]] if subkeyMaster else kv[idx] value = kv[idx + 1] value = self._parseValue(value, read=True) self.Append(settings, group, key, subkey, value) diff --git a/gui/wxpython/core/treemodel.py b/gui/wxpython/core/treemodel.py index fb18384ba36..0ce69133e1b 100644 --- a/gui/wxpython/core/treemodel.py +++ b/gui/wxpython/core/treemodel.py @@ -294,15 +294,12 @@ def __init__(self, label=None, data=None): def label(self): return self._label - def match(self, key, value, case_sensitive=False): + def match(self, key, value, case_sensitive=False) -> bool: """Method used for searching according to command, keywords or description.""" if not self.data: return False - if isinstance(key, str): - keys = [key] - else: - keys = key + keys = [key] if isinstance(key, str) else key for key in keys: if key not in {"command", "keywords", "description"}: diff --git a/gui/wxpython/core/utils.py b/gui/wxpython/core/utils.py index 2b1f3f4997a..6a39a158555 100644 --- a/gui/wxpython/core/utils.py +++ b/gui/wxpython/core/utils.py @@ -864,10 +864,7 @@ def StoreEnvVariable(key, value=None, envFile=None): ) ) return - if windows: - expCmd = "set" - else: - expCmd = "export" + expCmd = "set" if windows else "export" for key, value in environ.items(): fd.write("%s %s=%s\n" % (expCmd, key, value)) diff --git a/gui/wxpython/core/workspace.py b/gui/wxpython/core/workspace.py index 22aa56bfe62..dd460a68195 100644 --- a/gui/wxpython/core/workspace.py +++ b/gui/wxpython/core/workspace.py @@ -169,11 +169,8 @@ def __processFile(self): size = None extentAttr = display.get("extent", "") - if extentAttr: - # w, s, e, n - extent = map(float, extentAttr.split(",")) - else: - extent = None + # w, s, e, n + extent = map(float, extentAttr.split(",")) if extentAttr else None # projection node_projection = display.find("projection") @@ -312,10 +309,7 @@ def __processLayer(self, layer): ) ) - if layer.find("selected") is not None: - selected = True - else: - selected = False + selected = layer.find("selected") is not None # # Vector digitizer settings @@ -330,10 +324,7 @@ def __processLayer(self, layer): # Nviz (3D settings) # node_nviz = layer.find("nviz") - if node_nviz is not None: - nviz = self.__processLayerNviz(node_nviz) - else: - nviz = None + nviz = self.__processLayerNviz(node_nviz) if node_nviz is not None else None return (cmd, selected, vdigit, nviz) @@ -729,10 +720,7 @@ def __processLayerNvizNode(self, node, tag, cast, dc=None): try: value = cast(node_tag.text) except ValueError: - if cast == str: - value = "" - else: - value = None + value = "" if cast == str else None if dc: dc[tag] = {} dc[tag]["value"] = value diff --git a/gui/wxpython/datacatalog/tree.py b/gui/wxpython/datacatalog/tree.py index 176f5231712..bf06fd11ab8 100644 --- a/gui/wxpython/datacatalog/tree.py +++ b/gui/wxpython/datacatalog/tree.py @@ -2016,10 +2016,7 @@ def _getNewMapName(self, message, title, value, element, mapset, env): mapset=mapset, ) dlg.SetValue(value) - if dlg.ShowModal() == wx.ID_OK: - name = dlg.GetValue() - else: - name = None + name = dlg.GetValue() if dlg.ShowModal() == wx.ID_OK else None dlg.Destroy() return name diff --git a/gui/wxpython/dbmgr/base.py b/gui/wxpython/dbmgr/base.py index 1af8d6fccb1..c5eb8877b0a 100644 --- a/gui/wxpython/dbmgr/base.py +++ b/gui/wxpython/dbmgr/base.py @@ -1542,10 +1542,7 @@ def OnDataItemEdit(self, event): column = tlist.columns[columnName[i]] if len(values[i]) > 0: try: - if missingKey is True: - idx = i - 1 - else: - idx = i + idx = i - 1 if missingKey else i if column["ctype"] != str: tlist.itemDataMap[item][idx] = column["ctype"]( @@ -1707,10 +1704,7 @@ def OnDataItemAdd(self, event): del values[0] # add new item to the tlist - if len(tlist.itemIndexMap) > 0: - index = max(tlist.itemIndexMap) + 1 - else: - index = 0 + index = max(tlist.itemIndexMap) + 1 if len(tlist.itemIndexMap) > 0 else 0 tlist.itemIndexMap.append(index) tlist.itemDataMap[index] = values @@ -1828,11 +1822,7 @@ def _drawSelected(self, zoom, selectedOnly=True): return tlist = self.FindWindowById(self.layerPage[self.selLayer]["data"]) - if selectedOnly: - fn = tlist.GetSelectedItems - else: - fn = tlist.GetItems - + fn = tlist.GetSelectedItems if selectedOnly else tlist.GetItems cats = list(map(int, fn())) digitToolbar = None @@ -1929,11 +1919,7 @@ def AddQueryMapLayer(self, selectedOnly=True): :return: True if map has been redrawn, False if no map is given """ tlist = self.FindWindowById(self.layerPage[self.selLayer]["data"]) - if selectedOnly: - fn = tlist.GetSelectedItems - else: - fn = tlist.GetItems - + fn = tlist.GetSelectedItems if selectedOnly else tlist.GetItems cats = {self.selLayer: fn()} if self.mapdisplay.Map.GetLayerIndex(self.qlayer) < 0: @@ -2237,10 +2223,7 @@ def ValidateSelectStatement(self, statement): break cols += c index += 1 - if cols == "*": - cols = None - else: - cols = cols.split(",") + cols = None if cols == "*" else cols.split(",") tablelen = len(self.dbMgrData["mapDBInfo"].layers[self.selLayer]["table"]) @@ -2251,10 +2234,7 @@ def ValidateSelectStatement(self, statement): if len(statement[index + 7 + tablelen :]) > 0: index = statement.lower().find("where ") - if index > -1: - where = statement[index + 6 :] - else: - where = None + where = statement[index + 6 :] if index > -1 else None else: where = None @@ -3324,10 +3304,7 @@ def _createAddPage(self): row = 0 for key in ("layer", "driver", "database", "table", "key", "addCat"): label, value = self.addLayerWidgets[key] - if not value: - span = (1, 2) - else: - span = (1, 1) + span = (1, 2) if not value else (1, 1) dataSizer.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0), span=span) if not value: diff --git a/gui/wxpython/dbmgr/dialogs.py b/gui/wxpython/dbmgr/dialogs.py index 0d7c6e9e523..8ec2b12f36b 100644 --- a/gui/wxpython/dbmgr/dialogs.py +++ b/gui/wxpython/dbmgr/dialogs.py @@ -393,10 +393,7 @@ def UpdateDialog(self, map=None, query=None, cats=None, fid=-1, action=None): """ if action: self.action = action - if action == "display": - enabled = False - else: - enabled = True + enabled = action != "display" self.closeDialog.Enable(enabled) self.FindWindowById(wx.ID_OK).Enable(enabled) @@ -420,10 +417,7 @@ def UpdateDialog(self, map=None, query=None, cats=None, fid=-1, action=None): idx = 0 for layer in data["Layer"]: layer = int(layer) - if data["Id"][idx] is not None: - tfid = int(data["Id"][idx]) - else: - tfid = 0 # Area / Volume + tfid = int(data["Id"][idx]) if data["Id"][idx] is not None else 0 if tfid not in self.cats: self.cats[tfid] = {} if layer not in self.cats[tfid]: diff --git a/gui/wxpython/dbmgr/sqlbuilder.py b/gui/wxpython/dbmgr/sqlbuilder.py index 5e6fe0e7706..51010e49677 100644 --- a/gui/wxpython/dbmgr/sqlbuilder.py +++ b/gui/wxpython/dbmgr/sqlbuilder.py @@ -574,10 +574,7 @@ def _add(self, element, value): idx1 = len("select") idx2 = sqlstr.lower().find("from") colstr = sqlstr[idx1:idx2].strip() - if colstr == "*": - cols = [] - else: - cols = colstr.split(",") + cols = [] if colstr == "*" else colstr.split(",") if value in cols: cols.remove(value) else: @@ -922,10 +919,7 @@ def _add(self, element, value): print(__doc__, file=sys.stderr) sys.exit() - if len(sys.argv) == 3: - layer = 1 - else: - layer = int(sys.argv[3]) + layer = 1 if len(sys.argv) == 3 else int(sys.argv[3]) if sys.argv[1] == "select": sqlBuilder = SQLBuilderSelect diff --git a/gui/wxpython/gcp/manager.py b/gui/wxpython/gcp/manager.py index 3b6dd398b51..74ede7189e9 100644 --- a/gui/wxpython/gcp/manager.py +++ b/gui/wxpython/gcp/manager.py @@ -469,11 +469,7 @@ def __init__(self, wizard, parent): def OnMaptype(self, event): """Change map type""" global maptype - - if event.GetInt() == 0: - maptype = "raster" - else: - maptype = "vector" + maptype = "raster" if event.GetInt() == 0 else "vector" def OnLocation(self, event): """Sets source location for map(s) to georectify""" @@ -1433,10 +1429,7 @@ def SetGCPSatus(self, item, itemIndex): else: item.SetPropertyVal("hide", False) if self.highest_only: - if itemIndex == self.highest_key: - wxPen = "highest" - else: - wxPen = "default" + wxPen = "highest" if itemIndex == self.highest_key else "default" elif self.mapcoordlist[key][5] > self.rmsthresh: wxPen = "highest" else: @@ -1676,10 +1669,7 @@ def OnFocus(self, event): pass def _onMouseLeftUpPointer(self, mapWindow, x, y): - if mapWindow == self.SrcMapWindow: - coordtype = "source" - else: - coordtype = "target" + coordtype = "source" if mapWindow == self.SrcMapWindow else "target" coord = (x, y) self.SetGCPData(coordtype, coord, self, confirm=True) @@ -1806,10 +1796,7 @@ def OnGeorect(self, event): self.grwiz.SwitchEnv("source") - if self.clip_to_region: - flags = "ac" - else: - flags = "a" + flags = "ac" if self.clip_to_region else "a" with wx.BusyInfo(_("Rectifying images, please wait..."), parent=self): wx.GetApp().Yield() diff --git a/gui/wxpython/gmodeler/dialogs.py b/gui/wxpython/gmodeler/dialogs.py index 7cd7cbd1147..c8dd7509e74 100644 --- a/gui/wxpython/gmodeler/dialogs.py +++ b/gui/wxpython/gmodeler/dialogs.py @@ -291,11 +291,7 @@ def GetPanel(self): def _getCmd(self): line = self.cmd_prompt.GetCurLine()[0].strip() - if len(line) == 0: - cmd = [] - else: - cmd = utils.split(str(line)) - return cmd + return [] if len(line) == 0 else utils.split(str(line)) def GetCmd(self): """Get command""" @@ -980,10 +976,7 @@ def Populate(self, data): checked.append(None) else: bId = action.GetBlockId() - if not bId: - bId = _("No") - else: - bId = _("Yes") + bId = _("No") if not bId else _("Yes") options = action.GetParameterizedParams() params = [] for f in options["flags"]: @@ -1110,10 +1103,7 @@ def MoveItems(self, items, up): idxList = {} itemsToSelect = [] for i in items: - if up: - idx = i - 1 - else: - idx = i + 1 + idx = i - 1 if up else i + 1 itemsToSelect.append(idx) idxList[model.GetItemIndex(modelActions[i])] = model.GetItemIndex( modelActions[idx] diff --git a/gui/wxpython/gmodeler/model.py b/gui/wxpython/gmodeler/model.py index fdf6ac63b36..15c4eaa8cd4 100644 --- a/gui/wxpython/gmodeler/model.py +++ b/gui/wxpython/gmodeler/model.py @@ -833,10 +833,7 @@ def Parameterize(self): if gtype in {"raster", "vector", "mapset", "file", "region", "dir"}: gisprompt = True prompt = gtype - if gtype == "raster": - element = "cell" - else: - element = gtype + element = "cell" if gtype == "raster" else gtype ptype = "string" else: gisprompt = False @@ -1102,10 +1099,7 @@ def _setPen(self): group="modeler", key="action", subkey=("width", "default") ) ) - if self.isEnabled: - style = wx.SOLID - else: - style = wx.DOT + style = wx.SOLID if self.isEnabled else wx.DOT pen = wx.Pen(wx.BLACK, width, style) self.SetPen(pen) @@ -1453,10 +1447,7 @@ def SetValue(self, value): self.SetLabel() for direction in ("from", "to"): for rel in self.GetRelations(direction): - if direction == "from": - action = rel.GetTo() - else: - action = rel.GetFrom() + action = rel.GetTo() if direction == "from" else rel.GetFrom() task = GUI(show=None).ParseCommand(cmd=action.GetLog(string=False)) task.set_param(rel.GetLabel(), self.value) @@ -1525,10 +1516,7 @@ def _getPen(self): group="modeler", key="action", subkey=("width", "default") ) ) - if self.intermediate: - style = wx.DOT - else: - style = wx.SOLID + style = wx.DOT if self.intermediate else wx.SOLID return wx.Pen(wx.BLACK, width, style) @@ -1718,10 +1706,7 @@ def __init__( def _setPen(self): """Set pen""" - if self.isEnabled: - style = wx.SOLID - else: - style = wx.DOT + style = wx.SOLID if self.isEnabled else wx.DOT pen = wx.Pen(wx.BLACK, 1, style) self.SetPen(pen) @@ -1986,10 +1971,7 @@ def __init__(self, tree): self.root = self.tree.getroot() # check if input is a valid GXM file if self.root is None or self.root.tag != "gxm": - if self.root is not None: - tagName = self.root.tag - else: - tagName = _("empty") + tagName = self.root.tag if self.root is not None else _("empty") raise GException(_("Details: unsupported tag name '{0}'.").format(tagName)) # list of actions, data @@ -2099,10 +2081,7 @@ def _processActions(self): aId = int(action.get("id", -1)) label = action.get("name") comment = action.find("comment") - if comment is not None: - commentString = comment.text - else: - commentString = "" + commentString = comment.text if comment is not None else "" self.actions.append( { @@ -2515,10 +2494,7 @@ def _data(self, dataList): # relations for ft in ("from", "to"): for rel in data.GetRelations(ft): - if ft == "from": - aid = rel.GetTo().GetId() - else: - aid = rel.GetFrom().GetId() + aid = rel.GetTo().GetId() if ft == "from" else rel.GetFrom().GetId() self.fd.write( '%s\n' % (" " * self.indent, ft, aid, rel.GetLabel()) @@ -2987,10 +2963,7 @@ def _write_input_outputs(self, item, intermediates): parameterized_params = item.GetParameterizedParams() for flag in parameterized_params["flags"]: - if flag["label"]: - desc = flag["label"] - else: - desc = flag["description"] + desc = flag["label"] or flag["description"] if flag["value"]: value = '\n{}default="{}"'.format( @@ -3256,12 +3229,7 @@ def _getPythonActionCmd(self, item, task, cmdIndent, variables={}): return ret def _getParamDesc(self, param): - if param["label"]: - desc = param["label"] - else: - desc = param["description"] - - return desc + return param["label"] or param["description"] def _getParamValue(self, param): if param["value"] and "output" not in param["name"]: @@ -3374,10 +3342,7 @@ def _writePython(self): for item in modelItems: parametrizedParams = item.GetParameterizedParams() for flag in parametrizedParams["flags"]: - if flag["label"]: - desc = flag["label"] - else: - desc = flag["description"] + desc = flag["label"] or flag["description"] self.fd.write( r"""# %option # % key: {flag_name} @@ -3398,10 +3363,7 @@ def _writePython(self): self.fd.write("# %end\n") for param in parametrizedParams["params"]: - if param["label"]: - desc = param["label"] - else: - desc = param["description"] + desc = param["label"] or param["description"] self.fd.write( r"""# %option # % key: {param_name} diff --git a/gui/wxpython/gmodeler/panels.py b/gui/wxpython/gmodeler/panels.py index 416a9b85592..fbdc2048620 100644 --- a/gui/wxpython/gmodeler/panels.py +++ b/gui/wxpython/gmodeler/panels.py @@ -622,10 +622,7 @@ def LoadModelFile(self, filename): item.Show(True) # relations/data for rel in item.GetRelations(): - if rel.GetFrom() == item: - dataItem = rel.GetTo() - else: - dataItem = rel.GetFrom() + dataItem = rel.GetTo() if rel.GetFrom() == item else rel.GetFrom() self._addEvent(dataItem) self.canvas.diagram.AddShape(dataItem) self.AddLine(rel) @@ -1663,13 +1660,8 @@ def GetScriptExt(self): """Get extension for script exporting. :return: script extension """ - if self.write_object == WriteActiniaFile: - ext = "json" - else: - # Python, PyWPS - ext = "py" - - return ext + # return "py" for Python, PyWPS + return "json" if self.write_object == WriteActiniaFile else "py" def SetWriteObject(self, script_type): """Set correct self.write_object depending on the script type. diff --git a/gui/wxpython/gui_core/dialogs.py b/gui/wxpython/gui_core/dialogs.py index a38836ac23e..27ce4523a76 100644 --- a/gui/wxpython/gui_core/dialogs.py +++ b/gui/wxpython/gui_core/dialogs.py @@ -466,10 +466,7 @@ def CreateNewVector( """ vExternalOut = grass.parse_command("v.external.out", flags="g") isNative = vExternalOut["format"] == "native" - if cmd[0] == "v.edit" and not isNative: - showType = True - else: - showType = False + showType = bool(cmd[0] == "v.edit" and not isNative) dlg = NewVectorDialog( parent, title=title, @@ -1340,10 +1337,7 @@ def ShowResult(self, group, returnCode, create): def GetSelectedGroup(self): """Return currently selected group (without mapset)""" g = self.groupSelect.GetValue().split("@")[0] - if self.edit_subg: - s = self.subGroupSelect.GetValue() - else: - s = None + s = self.subGroupSelect.GetValue() if self.edit_subg else None return g, s def GetGroupLayers(self, group, subgroup=None): @@ -1374,10 +1368,7 @@ def ApplyChanges(self): GMessage(parent=self, message=_("No subgroup selected.")) return 0 - if self.edit_subg: - subgroup = self.currentSubgroup - else: - subgroup = None + subgroup = self.currentSubgroup if self.edit_subg else None groups = self.GetExistGroups() if group in groups: diff --git a/gui/wxpython/gui_core/forms.py b/gui/wxpython/gui_core/forms.py index 2636b213df3..7172835f001 100644 --- a/gui/wxpython/gui_core/forms.py +++ b/gui/wxpython/gui_core/forms.py @@ -193,10 +193,7 @@ def run(self): if not pMap: pMap = self.task.get_param("input", raiseError=False) - if pMap: - map = pMap.get("value", "") - else: - map = None + map = pMap.get("value", "") if pMap else None # avoid running db.describe several times cparams = {} @@ -278,10 +275,7 @@ def run(self): elif p.get("element", "") in {"layer", "layer_all"}: # -> layer # get layer layer = p.get("value", "") - if layer != "": - layer = p.get("value", "") - else: - layer = p.get("default", "") + layer = p.get("value", "") if layer != "" else p.get("default", "") # get map name pMapL = self.task.get_param( @@ -722,10 +716,7 @@ def __init__( sizeFrame = self.GetBestSize() self.SetMinSize(sizeFrame) - if hasattr(self, "closebox"): - scale = 0.33 - else: - scale = 0.50 + scale = 0.33 if hasattr(self, "closebox") else 0.5 self.SetSize( wx.Size( round(sizeFrame[0]), @@ -813,10 +804,7 @@ def OnMapCreated(self, name, ltype, add: bool | None = None): :param ltype: layer type (prompt value) :param add: whether to display layer or not """ - if hasattr(self, "addbox") and self.addbox.IsChecked(): - add = True - else: - add = False + add = bool(hasattr(self, "addbox") and self.addbox.IsChecked()) if self._giface: self._giface.mapCreated.emit(name=name, ltype=ltype, add=add) @@ -1156,10 +1144,7 @@ def __init__(self, parent, giface, task, id=wx.ID_ANY, frame=None, *args, **kwar else: title_sizer = wx.BoxSizer(wx.HORIZONTAL) title_txt = StaticText(parent=which_panel) - if p["key_desc"]: - ltype = ",".join(p["key_desc"]) - else: - ltype = p["type"] + ltype = ",".join(p["key_desc"]) if p["key_desc"] else p["type"] # red star for required options if p.get("required", False): required_txt = StaticText(parent=which_panel, label="*") @@ -1900,10 +1885,7 @@ def __init__(self, parent, giface, task, id=wx.ID_ANY, frame=None, *args, **kwar win.Bind(wx.EVT_COMBOBOX, self.OnSetValue) elif prompt == "mapset": - if p.get("age", "old") == "old": - new = False - else: - new = True + new = p.get("age", "old") != "old" win = gselect.MapsetSelect( parent=which_panel, @@ -2008,10 +1990,7 @@ def __init__(self, parent, giface, task, id=wx.ID_ANY, frame=None, *args, **kwar # file selector elif p.get("prompt", "") != "color" and p.get("prompt", "") == "file": - if p.get("age", "new") == "new": - fmode = wx.FD_SAVE - else: - fmode = wx.FD_OPEN + fmode = wx.FD_SAVE if p.get("age", "new") == "new" else wx.FD_OPEN # check wildcard try: fExt = os.path.splitext(p.get("key_desc", ["*.*"])[0])[1] @@ -2770,11 +2749,7 @@ def OnVerbosity(self, event): event.Skip() def OnPageChange(self, event): - if not event: - sel = self.notebook.GetSelection() - else: - sel = event.GetSelection() - + sel = self.notebook.GetSelection() if not event else event.GetSelection() idx = self.notebook.GetPageIndexByName("manual") if idx > -1 and sel == idx: # calling LoadPage() is strangely time-consuming (only first call) diff --git a/gui/wxpython/gui_core/gselect.py b/gui/wxpython/gui_core/gselect.py index ff256803a97..67b8a1280e2 100644 --- a/gui/wxpython/gui_core/gselect.py +++ b/gui/wxpython/gui_core/gselect.py @@ -1394,10 +1394,7 @@ def __init__( super().__init__(parent, id=wx.ID_ANY, size=size, **kwargs) self.SetName("FormatSelect") - if ogr: - ftype = "ogr" - else: - ftype = "gdal" + ftype = "ogr" if ogr else "gdal" formats = [] for f in GetFormats()[ftype][srcType].items(): @@ -1504,10 +1501,7 @@ def __init__( self.protocolWidgets = {} self.pgWidgets = {} - if ogr: - fType = "ogr" - else: - fType = "gdal" + fType = "ogr" if ogr else "gdal" # file fileMask = "%(all)s (*)|*|" % {"all": _("All files")} @@ -2290,12 +2284,7 @@ def hasRastSameProjAsLocation(dsn, table=None): return projectionMatch def getProjMatchCaption(projectionMatch): - if projectionMatch == "0": - projectionMatchCaption = _("No") - else: - projectionMatchCaption = _("Yes") - - return projectionMatchCaption + return _("No") if projectionMatch == "0" else _("Yes") dsn = self.GetDsn() if not dsn: @@ -2440,15 +2429,9 @@ def OnHelp(self, event): """Show related manual page""" cmd = "" if self.dest: - if self.ogr: - cmd = "v.external.out" - else: - cmd = "r.external.out" + cmd = "v.external.out" if self.ogr else "r.external.out" elif self.link: - if self.ogr: - cmd = "v.external" - else: - cmd = "r.external" + cmd = "v.external" if self.ogr else "r.external" elif self.ogr: cmd = "v.in.ogr" else: diff --git a/gui/wxpython/gui_core/mapdisp.py b/gui/wxpython/gui_core/mapdisp.py index a2810c9892b..ea770defe8e 100644 --- a/gui/wxpython/gui_core/mapdisp.py +++ b/gui/wxpython/gui_core/mapdisp.py @@ -380,10 +380,7 @@ def StatusbarEnableLongHelp(self, enable=True): toolbar.EnableLongHelp(enable) def ShowAllToolbars(self, show=True): - if not show: # hide - action = self.RemoveToolbar - else: - action = self.AddToolbar + action = self.RemoveToolbar if not show else self.AddToolbar for toolbar in self.GetToolbarNames(): action(toolbar) diff --git a/gui/wxpython/gui_core/menu.py b/gui/wxpython/gui_core/menu.py index b284461af0a..34d6eeffd31 100644 --- a/gui/wxpython/gui_core/menu.py +++ b/gui/wxpython/gui_core/menu.py @@ -91,10 +91,7 @@ def _createMenuItem( menu.AppendSeparator() return - if command: - helpString = command + " -- " + description - else: - helpString = description + helpString = command + " -- " + description if command else description if shortcut: label += "\t" + shortcut diff --git a/gui/wxpython/gui_core/preferences.py b/gui/wxpython/gui_core/preferences.py index 724e4a5aec0..85e5313da0e 100644 --- a/gui/wxpython/gui_core/preferences.py +++ b/gui/wxpython/gui_core/preferences.py @@ -2268,10 +2268,7 @@ def OnEnableWheelZoom(self, event): """Enable/disable wheel zoom mode control""" choiceId = self.winId["display:mouseWheelZoom:selection"] choice = self.FindWindowById(choiceId) - if choice.GetSelection() == 2: - enable = False - else: - enable = True + enable = choice.GetSelection() != 2 scrollId = self.winId["display:scrollDirection:selection"] self.FindWindowById(scrollId).Enable(enable) diff --git a/gui/wxpython/gui_core/prompt.py b/gui/wxpython/gui_core/prompt.py index 6734de169a9..3857f04fb32 100644 --- a/gui/wxpython/gui_core/prompt.py +++ b/gui/wxpython/gui_core/prompt.py @@ -428,10 +428,7 @@ def GetWordLeft(self, withDelimiter=False, ignoredDelimiter=None): ignoredDelimiter = "" for char in set(" .,-=") - set(ignoredDelimiter): - if not withDelimiter: - delimiter = "" - else: - delimiter = char + delimiter = "" if not withDelimiter else char parts.append(delimiter + textLeft.rpartition(char)[2]) return min(parts, key=lambda x: len(x)) diff --git a/gui/wxpython/gui_core/treeview.py b/gui/wxpython/gui_core/treeview.py index a7660308843..2fde45feec8 100644 --- a/gui/wxpython/gui_core/treeview.py +++ b/gui/wxpython/gui_core/treeview.py @@ -209,10 +209,7 @@ class CTreeView(AbstractTreeViewMixin, CustomTreeCtrl): """Tree view class inheriting from wx.TreeCtrl""" def __init__(self, model, parent, **kw): - if hasAgw: - style = "agwStyle" - else: - style = "style" + style = "agwStyle" if hasAgw else "style" if style not in kw: kw[style] = ( diff --git a/gui/wxpython/iclass/dialogs.py b/gui/wxpython/iclass/dialogs.py index 9aaa7e31604..615e614689f 100644 --- a/gui/wxpython/iclass/dialogs.py +++ b/gui/wxpython/iclass/dialogs.py @@ -588,11 +588,7 @@ def ContrastColor(color): # gacek, # https://stackoverflow.com/questions/1855884/determine-font-color-based-on-background-color a = 1 - (0.299 * color[0] + 0.587 * color[1] + 0.114 * color[2]) / 255 - - if a < 0.5: - d = 0 - else: - d = 255 + d = 0 if a < 0.5 else 255 # maybe return just bool if text should be dark or bright return (d, d, d) diff --git a/gui/wxpython/iclass/digit.py b/gui/wxpython/iclass/digit.py index 85334993db1..7442c24ab5d 100644 --- a/gui/wxpython/iclass/digit.py +++ b/gui/wxpython/iclass/digit.py @@ -156,15 +156,9 @@ def CopyMap(self, name, tmp=False, update=False): poMapInfoNew = pointer(Map_info()) if not tmp: - if update: - open_fn = Vect_open_update - else: - open_fn = Vect_open_new - else: # noqa: PLR5501 - if update: - open_fn = Vect_open_tmp_update - else: - open_fn = Vect_open_tmp_new + open_fn = Vect_open_update if update else Vect_open_new + else: + open_fn = Vect_open_tmp_update if update else Vect_open_tmp_new if update: if open_fn(poMapInfoNew, name, "") == -1: diff --git a/gui/wxpython/image2target/ii2t_gis_set.py b/gui/wxpython/image2target/ii2t_gis_set.py index 6ed97bc46c1..0329516e04a 100644 --- a/gui/wxpython/image2target/ii2t_gis_set.py +++ b/gui/wxpython/image2target/ii2t_gis_set.py @@ -1014,10 +1014,7 @@ def OnSetDatabase(self, event): def OnBrowse(self, event): """'Browse' button clicked""" - if not event: - defaultPath = os.getenv("HOME") - else: - defaultPath = "" + defaultPath = os.getenv("HOME") if not event else "" dlg = wx.DirDialog( parent=self, diff --git a/gui/wxpython/image2target/ii2t_manager.py b/gui/wxpython/image2target/ii2t_manager.py index 3adcf5ef9bd..939c2fb0fe8 100644 --- a/gui/wxpython/image2target/ii2t_manager.py +++ b/gui/wxpython/image2target/ii2t_manager.py @@ -488,11 +488,7 @@ def __init__(self, wizard, parent): def OnMaptype(self, event): """Change map type""" global maptype - - if event.GetInt() == 0: - maptype = "raster" - else: - maptype = "vector" + maptype = "raster" if event.GetInt() == 0 else "vector" def OnLocation(self, event): """Sets source location for map(s) to georectify""" @@ -1416,10 +1412,7 @@ def SetGCPSatus(self, item, itemIndex): else: item.SetPropertyVal("hide", False) if self.highest_only: - if itemIndex == self.highest_key: - wxPen = "highest" - else: - wxPen = "default" + wxPen = "highest" if itemIndex == self.highest_key else "default" elif self.mapcoordlist[key][7] > self.rmsthresh: wxPen = "highest" else: @@ -1702,10 +1695,7 @@ def OnFocus(self, event): pass def _onMouseLeftUpPointer(self, mapWindow, x, y): - if mapWindow == self.SrcMapWindow: - coordtype = "source" - else: - coordtype = "target" + coordtype = "source" if mapWindow == self.SrcMapWindow else "target" coord = (x, y) self.SetGCPData(coordtype, coord, self, confirm=True) @@ -1761,11 +1751,7 @@ def OnGeorect(self, event): if maptype == "raster": self.grwiz.SwitchEnv("source") - - if self.clip_to_region: - flags = "ac" - else: - flags = "a" + flags = "ac" if self.clip_to_region else "a" with wx.BusyInfo(_("Rectifying images, please wait..."), parent=self): wx.GetApp().Yield() diff --git a/gui/wxpython/iscatt/controllers.py b/gui/wxpython/iscatt/controllers.py index fef4e95505e..06ca5d0b243 100644 --- a/gui/wxpython/iscatt/controllers.py +++ b/gui/wxpython/iscatt/controllers.py @@ -149,10 +149,7 @@ def SetBands(self, bands): callable=self.core.CleanUp, ondone=lambda event: self.CleanUpDone() ) - if self.show_add_scatt_plot: - show_add = True - else: - show_add = False + show_add = bool(self.show_add_scatt_plot) self.all_bands_to_bands = dict(zip(bands, [-1] * len(bands))) self.all_bands = bands @@ -697,10 +694,7 @@ def SetData(self): def AddCategory(self, cat_id=None, name=None, color=None, nstd=None): if cat_id is None: - if self.cats_ids: - cat_id = max(self.cats_ids) + 1 - else: - cat_id = 1 + cat_id = max(self.cats_ids) + 1 if self.cats_ids else 1 if self.scatt_mgr.data_set: self.scatt_mgr.thread.Run(callable=self.core.AddCategory, cat_id=cat_id) diff --git a/gui/wxpython/iscatt/core_c.py b/gui/wxpython/iscatt/core_c.py index 8be04964b90..a6e6ac5c8a0 100644 --- a/gui/wxpython/iscatt/core_c.py +++ b/gui/wxpython/iscatt/core_c.py @@ -214,11 +214,7 @@ def _regionToCellHead(region): } for k, v in region.items(): - if k in {"rows", "cols", "cells", "zone"}: # zone added in r65224 - v = int(v) - else: - v = float(v) - + v = int(v) if k in {"rows", "cols", "cells", "zone"} else float(v) if k in convert_dict: k = convert_dict[k] diff --git a/gui/wxpython/iscatt/frame.py b/gui/wxpython/iscatt/frame.py index 122aa053b9b..5350ecbd8a0 100644 --- a/gui/wxpython/iscatt/frame.py +++ b/gui/wxpython/iscatt/frame.py @@ -568,11 +568,7 @@ def OnCategoryRightUp(self, event): item = menu.Append(wx.ID_ANY, _("Change opacity level")) self.Bind(wx.EVT_MENU, self.OnPopupOpacityLevel, item) - if showed: - text = _("Hide") - else: - text = _("Show") - + text = _("Hide") if showed else _("Show") item = menu.Append(wx.ID_ANY, text) self.Bind( wx.EVT_MENU, diff --git a/gui/wxpython/iscatt/iscatt_core.py b/gui/wxpython/iscatt/iscatt_core.py index 09214d08e42..52cecbfb381 100644 --- a/gui/wxpython/iscatt/iscatt_core.py +++ b/gui/wxpython/iscatt/iscatt_core.py @@ -805,11 +805,7 @@ def _parseRegion(region_str): for param in region_str: k, v = param.split("=") - if k in {"rows", "cols", "cells"}: - v = int(v) - else: - v = float(v) - region[k] = v + region[k] = int(v) if k in {"rows", "cols", "cells"} else float(v) return region diff --git a/gui/wxpython/lmgr/frame.py b/gui/wxpython/lmgr/frame.py index 963a36e3a58..9879ce1d937 100644 --- a/gui/wxpython/lmgr/frame.py +++ b/gui/wxpython/lmgr/frame.py @@ -747,10 +747,7 @@ def OnLocationWizard(self, event): self._giface.grassdbChanged.emit( grassdb=grassdb, location=location, action="new", element="location" ) - if grassdb == gisenv["GISDBASE"]: - switch_grassdb = None - else: - switch_grassdb = grassdb + switch_grassdb = grassdb if grassdb != gisenv["GISDBASE"] else None if can_switch_mapset_interactive(self, grassdb, location, mapset): switch_mapset_interactively( self, @@ -1116,10 +1113,7 @@ def GetMenuCmd(self, event): :return: command as a list""" layer = None - if event: - cmd = self.menucmd[event.GetId()] - else: - cmd = "" + cmd = self.menucmd[event.GetId()] if event else "" try: cmdlist = cmd.split(" ") diff --git a/gui/wxpython/lmgr/layertree.py b/gui/wxpython/lmgr/layertree.py index 855896e35ab..350320d97a7 100644 --- a/gui/wxpython/lmgr/layertree.py +++ b/gui/wxpython/lmgr/layertree.py @@ -688,10 +688,7 @@ def OnLayerContextMenu(self, event): ) digitToolbar = self.mapdisplay.GetToolbar("vdigit") - if digitToolbar: - vdigitLayer = digitToolbar.GetLayer() - else: - vdigitLayer = None + vdigitLayer = digitToolbar.GetLayer() if digitToolbar else None layer = self.GetLayerInfo(self.layer_selected, key="maplayer") if vdigitLayer is not layer: item = wx.MenuItem( @@ -1569,10 +1566,7 @@ def AddLayer( name = None - if ctrl: - ctrlId = ctrl.GetId() - else: - ctrlId = None + ctrlId = ctrl.GetId() if ctrl else None # add a data object to hold the layer's command (does not # apply to generic command layers) @@ -1606,11 +1600,7 @@ def AddLayer( prevMapLayer = self.GetLayerInfo(prevItem, key="maplayer") prevItem = self.GetNextItem(prevItem) - - if prevMapLayer: - pos = self.Map.GetLayerIndex(prevMapLayer) - else: - pos = -1 + pos = self.Map.GetLayerIndex(prevMapLayer) if prevMapLayer else -1 maplayer = self.Map.AddLayer( pos=pos, @@ -2063,12 +2053,8 @@ def RecreateItem(self, dragItem, dropTarget, parent=None): # decide where to put recreated item if dropTarget is not None and dropTarget != self.GetRootItem(): - if parent: - # new item is a group - afteritem = parent - else: - # new item is a single layer - afteritem = dropTarget + # new item is a group (parent is truthy) or else new item is a single layer + afteritem = parent or dropTarget # dragItem dropped on group if self.GetLayerInfo(afteritem, key="type") == "group": diff --git a/gui/wxpython/lmgr/menudata.py b/gui/wxpython/lmgr/menudata.py index 59eb72ecb67..88f769af403 100644 --- a/gui/wxpython/lmgr/menudata.py +++ b/gui/wxpython/lmgr/menudata.py @@ -25,10 +25,7 @@ class LayerManagerMenuData(MenuTreeModelBuilder): def __init__(self, filename=None, message_handler=GError): - if filename: - expandAddons = False - else: - expandAddons = True + expandAddons = not filename fallback = os.path.join(WXGUIDIR, "xml", "menudata.xml") if not filename: @@ -57,10 +54,7 @@ def __init__(self, filename=None, message_handler=GError): class LayerManagerModuleTree(MenuTreeModelBuilder): def __init__(self, filename=None, message_handler=GError): - if filename: - expandAddons = False - else: - expandAddons = True + expandAddons = not filename fallback = os.path.join(WXGUIDIR, "xml", "module_tree_menudata.xml") if not filename: diff --git a/gui/wxpython/location_wizard/wizard.py b/gui/wxpython/location_wizard/wizard.py index 1f8de66dda6..d553b4e11d9 100644 --- a/gui/wxpython/location_wizard/wizard.py +++ b/gui/wxpython/location_wizard/wizard.py @@ -2760,10 +2760,7 @@ def CreateProj4String(self): # set ellipsoid parameters for item in ellipseparams: - if item[:4] == "f=1/": - item = " +rf=" + item[4:] - else: - item = " +" + item + item = " +rf=" + item[4:] if item[:4] == "f=1/" else " +" + item proj4string = "%s %s" % (proj4string, item) # set datum transform parameters if relevant diff --git a/gui/wxpython/main_window/frame.py b/gui/wxpython/main_window/frame.py index cef4aee7121..3574e7c8951 100644 --- a/gui/wxpython/main_window/frame.py +++ b/gui/wxpython/main_window/frame.py @@ -861,10 +861,7 @@ def OnLocationWizard(self, event): self._giface.grassdbChanged.emit( grassdb=grassdb, location=location, action="new", element="location" ) - if grassdb == gisenv["GISDBASE"]: - switch_grassdb = None - else: - switch_grassdb = grassdb + switch_grassdb = grassdb if grassdb != gisenv["GISDBASE"] else None if can_switch_mapset_interactive(self, grassdb, location, mapset): switch_mapset_interactively( self, @@ -1268,10 +1265,7 @@ def GetMenuCmd(self, event): :return: command as a list""" layer = None - if event: - cmd = self.menucmd[event.GetId()] - else: - cmd = "" + cmd = self.menucmd[event.GetId()] if event else "" try: cmdlist = cmd.split(" ") diff --git a/gui/wxpython/mapdisp/frame.py b/gui/wxpython/mapdisp/frame.py index 0a1660ff06a..3133341a334 100644 --- a/gui/wxpython/mapdisp/frame.py +++ b/gui/wxpython/mapdisp/frame.py @@ -783,10 +783,7 @@ def DOutFile(self, command, callback=None): # --overwrite continue if p == "format": # must be there - if self.IsPaneShown("3d"): - extType = "ppm" - else: - extType = val + extType = "ppm" if self.IsPaneShown("3d") else val if p == "output": # must be there name = val elif p == "size": @@ -798,10 +795,8 @@ def DOutFile(self, command, callback=None): elif ext[1:] != extType: extType = ext[1:] - if self.IsPaneShown("3d"): - bitmapType = "ppm" - else: - bitmapType = wx.BITMAP_TYPE_PNG # default type + # default type is PNG + bitmapType = "ppm" if self.IsPaneShown("3d") else wx.BITMAP_TYPE_PNG for each in ltype: if each["ext"] == extType: bitmapType = each["type"] diff --git a/gui/wxpython/mapdisp/toolbars.py b/gui/wxpython/mapdisp/toolbars.py index 4eb49846d4f..18459b26e17 100644 --- a/gui/wxpython/mapdisp/toolbars.py +++ b/gui/wxpython/mapdisp/toolbars.py @@ -285,10 +285,7 @@ def RemoveTool(self, tool): def ChangeToolsDesc(self, mode2d): """Change description of zoom tools for 2D/3D view""" - if mode2d: - icons = BaseIcons - else: - icons = NvizIcons + icons = BaseIcons if mode2d else NvizIcons for i, data in enumerate(self.controller.data): for tool in ("zoomIn", "zoomOut"): if data[0] == tool: diff --git a/gui/wxpython/mapwin/buffered.py b/gui/wxpython/mapwin/buffered.py index c4b07a94fd2..16b6b329ef6 100644 --- a/gui/wxpython/mapwin/buffered.py +++ b/gui/wxpython/mapwin/buffered.py @@ -344,10 +344,7 @@ def Draw( # TODO: find better solution if not pen: - if pdctype == "polyline": - pen = self.polypen - else: - pen = self.pen + pen = self.polypen if pdctype == "polyline" else self.pen if img and pdctype == "image": # self.imagedict[img]['coords'] = coords @@ -501,10 +498,7 @@ def Draw( elif pdctype == "text": # draw text on top of map if not img["active"]: return # only draw active text - if "rotation" in img: - rotation = float(img["rotation"]) - else: - rotation = 0.0 + rotation = float(img["rotation"]) if "rotation" in img else 0.0 w, h = self.GetFullTextExtent(img["text"])[0:2] pdc.SetFont(img["font"]) pdc.SetTextForeground(img["color"]) @@ -536,10 +530,7 @@ def TextBounds(self, textinfo, relcoords=False): :return: bbox of rotated text bbox (wx.Rect) :return: relCoords are text coord inside bbox """ - if "rotation" in textinfo: - rotation = float(textinfo["rotation"]) - else: - rotation = 0.0 + rotation = float(textinfo["rotation"]) if "rotation" in textinfo else 0.0 coords = textinfo["coords"] bbox = Rect(coords[0], coords[1], 0, 0) @@ -1469,10 +1460,7 @@ def OnMouseWheel(self, event): wheel = event.GetWheelRotation() Debug.msg(5, "BufferedWindow.MouseAction(): wheel=%d" % wheel) - if wheel > 0: - zoomtype = 1 - else: - zoomtype = -1 + zoomtype = 1 if wheel > 0 else -1 if UserSettings.Get(group="display", key="scrollDirection", subkey="selection"): zoomtype *= -1 # zoom 1/2 of the screen (TODO: settings) @@ -1504,10 +1492,7 @@ def OnDragging(self, event): previous = self.mouse["begin"] move = (current[0] - previous[0], current[1] - previous[1]) - if self.digit: - digitToolbar = self.toolbar - else: - digitToolbar = None + digitToolbar = self.toolbar if self.digit else None # dragging or drawing box with left button if self.mouse["use"] == "pan" or event.MiddleIsDown(): diff --git a/gui/wxpython/mapwin/decorations.py b/gui/wxpython/mapwin/decorations.py index 24db63d8492..9c643d17752 100644 --- a/gui/wxpython/mapwin/decorations.py +++ b/gui/wxpython/mapwin/decorations.py @@ -323,14 +323,8 @@ def ResizeLegend(self, begin, end, screenSize): """Resize legend according to given bbox coordinates.""" w = abs(begin[0] - end[0]) h = abs(begin[1] - end[1]) - if begin[0] < end[0]: - x = begin[0] - else: - x = end[0] - if begin[1] < end[1]: - y = begin[1] - else: - y = end[1] + x = min(end[0], begin[0]) + y = min(end[1], begin[1]) at = [ (screenSize[1] - (y + h)) / float(screenSize[1]) * 100, diff --git a/gui/wxpython/modules/colorrules.py b/gui/wxpython/modules/colorrules.py index 6f48006db44..dcb34619b57 100644 --- a/gui/wxpython/modules/colorrules.py +++ b/gui/wxpython/modules/colorrules.py @@ -977,10 +977,7 @@ def OnSelectionInput(self, event): self.cr_label.SetLabel(_("Enter raster category values or percents")) return - if info["datatype"] == "CELL": - mapRange = _("range") - else: - mapRange = _("fp range") + mapRange = _("range") if info["datatype"] == "CELL" else _("fp range") self.cr_label.SetLabel( _("Enter raster category values or percents (%(range)s = %(min)d-%(max)d)") % { @@ -1409,10 +1406,7 @@ def AddTemporaryColumn(self, type): idx += 1 self.properties["tmpColumn"] = name + "_" + str(idx) - if self.version7: - modul = "v.db.addcolumn" - else: - modul = "v.db.addcol" + modul = "v.db.addcolumn" if self.version7 else "v.db.addcol" RunCommand( modul, parent=self, @@ -1427,10 +1421,7 @@ def DeleteTemporaryColumn(self): return if self.inmap: - if self.version7: - modul = "v.db.dropcolumn" - else: - modul = "v.db.dropcol" + modul = "v.db.dropcolumn" if self.version7 else "v.db.dropcol" RunCommand( modul, map=self.inmap, @@ -1452,10 +1443,7 @@ def OnLayerSelection(self, event): self.sourceColumn.SetValue("cat") self.properties["sourceColumn"] = self.sourceColumn.GetValue() - if self.attributeType == "color": - type = ["character"] - else: - type = ["integer"] + type = ["character"] if self.attributeType == "color" else ["integer"] self.fromColumn.InsertColumns( vector=self.inmap, layer=vlayer, @@ -1502,10 +1490,7 @@ def OnAddColumn(self, event): self.columnsProp[self.attributeType]["name"] not in self.fromColumn.GetColumns() ): - if self.version7: - modul = "v.db.addcolumn" - else: - modul = "v.db.addcol" + modul = "v.db.addcolumn" if self.version7 else "v.db.addcol" RunCommand( modul, map=self.inmap, diff --git a/gui/wxpython/modules/extensions.py b/gui/wxpython/modules/extensions.py index f7822e0cb0e..7837a92589d 100644 --- a/gui/wxpython/modules/extensions.py +++ b/gui/wxpython/modules/extensions.py @@ -356,11 +356,7 @@ def _expandPrefix(self, c): def Load(self, url, full=True): """Load list of extensions""" self._emptyTree() - - if full: - flags = "g" - else: - flags = "l" + flags = "g" if full else "l" retcode, ret, msg = RunCommand( "g.extension", read=True, getErrorMsg=True, url=url, flags=flags, quiet=True ) diff --git a/gui/wxpython/modules/import_export.py b/gui/wxpython/modules/import_export.py index 6810484bfdd..db4e3b517a2 100644 --- a/gui/wxpython/modules/import_export.py +++ b/gui/wxpython/modules/import_export.py @@ -328,20 +328,14 @@ def AddLayers(self, returncode, cmd=None, userData=None): self.commandId += 1 layer, output = self.list.GetLayers()[self.commandId][:2] - if "@" not in output: - name = output + "@" + grass.gisenv()["MAPSET"] - else: - name = output + name = output + "@" + grass.gisenv()["MAPSET"] if "@" not in output else output # add imported layers into layer tree # an alternative would be emit signal (mapCreated) and (optionally) # connect to this signal llist = self._giface.GetLayerList() if self.importType == "gdal": - if userData: - nBands = int(userData.get("nbands", 1)) - else: - nBands = 1 + nBands = int(userData.get("nbands", 1)) if userData else 1 if UserSettings.Get(group="rasterLayer", key="opaque", subkey="enabled"): nFlag = True diff --git a/gui/wxpython/modules/mcalc_builder.py b/gui/wxpython/modules/mcalc_builder.py index 52630e55820..4294a9730de 100644 --- a/gui/wxpython/modules/mcalc_builder.py +++ b/gui/wxpython/modules/mcalc_builder.py @@ -681,10 +681,7 @@ def OnMCalcRun(self, event): self.log.RunCmd(cmd, onDone=self.OnDone) self.parent.Raise() else: - if self.overwrite.IsChecked(): - overwrite = True - else: - overwrite = False + overwrite = bool(self.overwrite.IsChecked()) params = {"expression": "%s=%s" % (name, expr), "overwrite": overwrite} if seed_flag: params["flags"] = "s" diff --git a/gui/wxpython/nviz/mapwindow.py b/gui/wxpython/nviz/mapwindow.py index 1eea5b278a9..d3f93f94938 100644 --- a/gui/wxpython/nviz/mapwindow.py +++ b/gui/wxpython/nviz/mapwindow.py @@ -382,10 +382,7 @@ def OnEraseBackground(self, event): def OnSize(self, event): size = self.GetClientSize() - if CheckWxVersion(version=[2, 9]): - context = self.context - else: - context = self.GetContext() + context = self.context if CheckWxVersion(version=[2, 9]) else self.GetContext() if self.size != size and context: Debug.msg( 3, "GLCanvas.OnSize(): w = %d, h = %d" % (size.width, size.height) diff --git a/gui/wxpython/nviz/tools.py b/gui/wxpython/nviz/tools.py index 7ced7d157e1..150fe519635 100644 --- a/gui/wxpython/nviz/tools.py +++ b/gui/wxpython/nviz/tools.py @@ -3210,10 +3210,7 @@ def _createControl( "style": style, "size": sizeW, } - if floatSlider: - slider = FloatSlider(**kwargs) - else: - slider = Slider(**kwargs) + slider = FloatSlider(**kwargs) if floatSlider else Slider(**kwargs) slider.SetName("slider") if bind[0]: @@ -3422,22 +3419,17 @@ def OnViewChange(self, event): self.AdjustSliderRange(slider=slider, value=value) - if winName == "height": - view = self.mapWindow.iview # internal - else: - view = self.mapWindow.view + # iview is internal + view = self.mapWindow.iview if winName == "height" else self.mapWindow.view if winName == "z-exag" and value >= 0: self.PostViewEvent(zExag=True) else: self.PostViewEvent(zExag=False) - if winName in {"persp", "twist"}: - convert = int - else: - convert = float - - view[winName]["value"] = convert(value) + view[winName]["value"] = ( + int(value) if winName in {"persp", "twist"} else float(value) + ) for win in self.win["view"][winName].values(): self.FindWindowById(win).SetValue(value) @@ -3650,10 +3642,8 @@ def EnablePage(self, name, enabled=True): def SetMapObjUseMap(self, nvizType, attrb, map=None): """Update dialog widgets when attribute type changed""" - if attrb in {"topo", "color", "shine"}: - incSel = -1 # decrement selection (no 'unset') - else: - incSel = 0 + # decrement selection (no 'unset') + incSel = -1 if attrb in {"topo", "color", "shine"} else 0 if nvizType == "volume" and attrb == "topo": return if map is True: # map @@ -3881,11 +3871,7 @@ def _get3dRange(self, name): def _getPercent(self, value, toPercent=True): """Convert values 0 - 255 to percents and vice versa""" value = int(value) - if toPercent: - value = int(value / 255.0 * 100) - else: - value = int(value / 100.0 * 255) - return value + return int(value / 255.0 * 100) if toPercent else int(value / 100.0 * 255) def OnSurfaceWireColor(self, event): """Set wire color""" @@ -4199,10 +4185,7 @@ def OnVectorHeightText(self, event): def OnVectorSurface(self, event): """Reference surface for vector map (lines/points)""" id = event.GetId() - if id == self.win["vector"]["lines"]["surface"]: - vtype = "lines" - else: - vtype = "points" + vtype = "lines" if id == self.win["vector"]["lines"]["surface"] else "points" checkList = self.FindWindowById(self.win["vector"][vtype]["surface"]) checked = [] surfaces = [] @@ -4278,10 +4261,7 @@ def OnCheckThematic(self, event): check = self.win["vector"][vtype]["thematic"]["check" + attrType] button = self.win["vector"][vtype]["thematic"]["button" + attrType] - if self.FindWindowById(check).GetValue(): - checked = True - else: - checked = False + checked = bool(self.FindWindowById(check).GetValue()) self.FindWindowById(button).Enable(checked) data = self.GetLayerData("vector") diff --git a/gui/wxpython/nviz/workspace.py b/gui/wxpython/nviz/workspace.py index 1e38aee239a..ac9e0582b2d 100644 --- a/gui/wxpython/nviz/workspace.py +++ b/gui/wxpython/nviz/workspace.py @@ -136,10 +136,7 @@ def SetVolumeDefaultProp(self): sel = UserSettings.Get( group="nviz", key="volume", subkey=["draw", "mode"] ) - if sel == 0: - desc = "isosurface" - else: - desc = "slice" + desc = "isosurface" if sel == 0 else "slice" data["draw"]["mode"] = { "value": sel, "desc": desc, diff --git a/gui/wxpython/nviz/wxnviz.py b/gui/wxpython/nviz/wxnviz.py index 5a223747277..35995d30e6b 100644 --- a/gui/wxpython/nviz/wxnviz.py +++ b/gui/wxpython/nviz/wxnviz.py @@ -885,11 +885,7 @@ def SetSurfaceAttr(self, id, attr, map, value): if map: ret = Nviz_set_attr(id, MAP_OBJ_SURF, attr, MAP_ATT, value, -1.0, self.data) else: - if attr == ATT_COLOR: - val = Nviz_color_from_str(value) - else: - val = float(value) - + val = Nviz_color_from_str(value) if attr == ATT_COLOR else float(value) ret = Nviz_set_attr(id, MAP_OBJ_SURF, attr, CONST_ATT, None, val, self.data) Debug.msg( @@ -1682,11 +1678,7 @@ def SetIsosurfaceAttr(self, id, isosurf_id, attr, map, value): if map: ret = GVL_isosurf_set_att_map(id, isosurf_id, attr, value) else: - if attr == ATT_COLOR: - val = Nviz_color_from_str(value) - else: - val = float(value) - + val = Nviz_color_from_str(value) if attr == ATT_COLOR else float(value) ret = GVL_isosurf_set_att_const(id, isosurf_id, attr, val) Debug.msg( @@ -2352,10 +2344,7 @@ def Resize(self): def Load(self): """Load image to texture""" - if self.image.HasAlpha(): - bytesPerPixel = 4 - else: - bytesPerPixel = 3 + bytesPerPixel = 4 if self.image.HasAlpha() else 3 bytes = bytesPerPixel * self.width * self.height rev_val = self.height - 1 im = (c_ubyte * bytes)() diff --git a/gui/wxpython/photo2image/ip2i_manager.py b/gui/wxpython/photo2image/ip2i_manager.py index d0726a3bae2..0e6168a8edd 100644 --- a/gui/wxpython/photo2image/ip2i_manager.py +++ b/gui/wxpython/photo2image/ip2i_manager.py @@ -797,10 +797,7 @@ def SetGCPSatus(self, item, itemIndex): else: item.SetPropertyVal("hide", False) if self.highest_only: - if itemIndex == self.highest_key: - wxPen = "highest" - else: - wxPen = "default" + wxPen = "highest" if itemIndex == self.highest_key else "default" else: # noqa: PLR5501 if self.mapcoordlist[key][5] > self.rmsthresh: wxPen = "highest" @@ -1042,10 +1039,7 @@ def OnFocus(self, event): pass def _onMouseLeftUpPointer(self, mapWindow, x, y): - if mapWindow == self.SrcMapWindow: - coordtype = "source" - else: - coordtype = "target" + coordtype = "source" if mapWindow == self.SrcMapWindow else "target" coord = (x, y) self.SetGCPData(coordtype, coord, self, confirm=True) @@ -1102,10 +1096,7 @@ def OnGeorect(self, event): if maptype == "raster": self.grwiz.SwitchEnv("source") - if self.clip_to_region: - flags = "ac" - else: - flags = "a" + flags = "ac" if self.clip_to_region else "a" with wx.BusyInfo(_("Rectifying images, please wait..."), parent=self): wx.GetApp().Yield() diff --git a/gui/wxpython/psmap/dialogs.py b/gui/wxpython/psmap/dialogs.py index f086d65dd36..428ae248c87 100644 --- a/gui/wxpython/psmap/dialogs.py +++ b/gui/wxpython/psmap/dialogs.py @@ -1256,10 +1256,7 @@ def OnMap(self, event): if self.scaleChoice.GetSelection() == 0: self.selectedMap = self.selected - if self.rasterTypeRadio.GetValue(): - mapType = "raster" - else: - mapType = "vector" + mapType = "raster" if self.rasterTypeRadio.GetValue() else "vector" self.scale[0], self.center[0], foo = AutoAdjust( self, @@ -1308,10 +1305,7 @@ def OnScaleChoice(self, event): self.vectorTypeRadio.Show() self.drawMap.Show() self.staticBox.SetLabel(" %s " % _("Map selection")) - if self.rasterTypeRadio.GetValue(): - stype = "raster" - else: - stype = "vector" + stype = "raster" if self.rasterTypeRadio.GetValue() else "vector" self.select.SetElementList(type=stype) self.mapText.SetLabel(self.mapOrRegionText[0]) @@ -1368,10 +1362,7 @@ def OnScaleChoice(self, event): def OnElementType(self, event): """Changes data in map selection tree ctrl popup""" - if self.rasterTypeRadio.GetValue(): - mapType = "raster" - else: - mapType = "vector" + mapType = "raster" if self.rasterTypeRadio.GetValue() else "vector" self.select.SetElementList(type=mapType) if self.mapType != mapType and event is not None: self.mapType = mapType @@ -1488,10 +1479,7 @@ def update(self): ) if self.mapType == "vector": raster = self.instruction.FindInstructionByType("raster") - if raster: - rasterId = raster.id - else: - rasterId = None + rasterId = raster.id if raster else None if rasterId: self.env["GRASS_REGION"] = gs.region_env( @@ -1562,10 +1550,7 @@ def update(self): region = gs.region(env=None) raster = self.instruction.FindInstructionByType("raster") - if raster: - rasterId = raster.id - else: - rasterId = None + rasterId = raster.id if raster else None if rasterId: # because of resolution self.env["GRASS_REGION"] = gs.region_env( @@ -3748,10 +3733,7 @@ def _vectorLegend(self, notebook): def sizePositionFont(self, legendType, parent, mainSizer): """Insert widgets for size, position and font control""" - if legendType == "raster": - legendDict = self.rLegendDict - else: - legendDict = self.vLegendDict + legendDict = self.rLegendDict if legendType == "raster" else self.vLegendDict panel = parent border = mainSizer @@ -4125,10 +4107,7 @@ def OnUp(self, event): self.vectorListCtrl.SetItemData(pos, idx1) self.vectorListCtrl.SetItemData(pos - 1, idx2) self.vectorListCtrl.SortItems(cmp) - if pos > 0: - selected = pos - 1 - else: - selected = 0 + selected = pos - 1 if pos > 0 else 0 self.vectorListCtrl.Select(selected) @@ -4463,11 +4442,7 @@ def updateDialog(self): else: self.rasterId = None - if raster: - currRaster = raster["raster"] - else: - currRaster = None - + currRaster = raster["raster"] if raster else None rasterType = getRasterType(map=currRaster) self.rasterCurrent.SetLabel( _("%(rast)s: type %(type)s") % {"rast": currRaster, "type": str(rasterType)} @@ -4995,10 +4970,7 @@ def _scalebarPanel(self): globalvar.IMGDIR, "scalebar-simple.png" ) for item, path in zip(["fancy", "simple"], imagePath): - if not os.path.exists(path): - bitmap = EmptyBitmap(0, 0) - else: - bitmap = wx.Bitmap(path) + bitmap = EmptyBitmap(0, 0) if not os.path.exists(path) else wx.Bitmap(path) self.sbCombo.Append(item="", bitmap=bitmap, clientData=item[0]) # self.sbCombo.Append( # item="simple", @@ -5882,11 +5854,7 @@ def _imagePanel(self, notebook): panel.image["scale"].SetFormat("%f") panel.image["scale"].SetDigits(1) - if self.imageDict["scale"]: - value = float(self.imageDict["scale"]) - else: - value = 0 - + value = float(self.imageDict["scale"]) if self.imageDict["scale"] else 0 panel.image["scale"].SetValue(value) gridSizer.Add(scaleLabel, pos=(0, 0), flag=wx.ALIGN_CENTER_VERTICAL) @@ -6579,10 +6547,7 @@ def __init__(self, parent, id, settings, env, type="rectangle", coordinates=None :param coordinates: begin and end point coordinate (wx.Point, wx.Point) """ - if type == "rectangle": - title = _("Rectangle settings") - else: - title = _("Line settings") + title = _("Rectangle settings") if type == "rectangle" else _("Line settings") PsmapDialog.__init__( self, parent=parent, id=id, title=title, settings=settings, env=env ) diff --git a/gui/wxpython/psmap/frame.py b/gui/wxpython/psmap/frame.py index e86b277252c..8926b8d1e75 100644 --- a/gui/wxpython/psmap/frame.py +++ b/gui/wxpython/psmap/frame.py @@ -369,10 +369,7 @@ def PSFile(self, filename=None, pdf=False): temp = False regOld = gs.region(env=self.env) - if pdf: - pdfname = filename - else: - pdfname = None + pdfname = filename if pdf else None # preview or pdf if not filename or (filename and pdf): temp = True @@ -569,10 +566,7 @@ def getFile(self, wildcard): s = "." + s suffix.append(s) raster = self.instruction.FindInstructionByType("raster") - if raster: - rasterId = raster.id - else: - rasterId = None + rasterId = raster.id if raster else None if rasterId and self.instruction[rasterId]["raster"]: mapName = self.instruction[rasterId]["raster"].split("@")[0] + suffix[0] @@ -1106,10 +1100,7 @@ def getInitMap(self): scale = mapInitRect.Get()[2] / realWidth initMap = self.instruction.FindInstructionByType("initMap") - if initMap: - id = initMap.id - else: - id = None + id = initMap.id if initMap else None if not id: id = NewId() @@ -2100,10 +2091,7 @@ def OnDragging(self, event): instr = self.instruction[self.dragId] points = instr["where"] # moving point - if self.currentLinePoint == 0: - pPaper = points[1] - else: - pPaper = points[0] + pPaper = points[1] if self.currentLinePoint == 0 else points[0] pCanvas = self.CanvasPaperCoordinates( rect=Rect2DPS(pPaper, (0, 0)), canvasToPaper=False )[:2] @@ -2532,10 +2520,7 @@ def DrawBitmap(self, pdc, filePath, rotation, bbox): pdc.DrawBitmap(bitmap, bbox[0], bbox[1], useMask=True) def DrawRotText(self, pdc, drawId, textDict, coords, bounds): - if textDict["rotate"]: - rot = float(textDict["rotate"]) - else: - rot = 0 + rot = float(textDict["rotate"]) if textDict["rotate"] else 0 if textDict["background"] != "none": background = textDict["background"] @@ -2691,16 +2676,10 @@ def UpdateMapLabel(self): """Updates map frame label""" vector = self.instruction.FindInstructionByType("vector") - if vector: - vectorId = vector.id - else: - vectorId = None + vectorId = vector.id if vector else None raster = self.instruction.FindInstructionByType("raster") - if raster: - rasterId = raster.id - else: - rasterId = None + rasterId = raster.id if raster else None rasterName = "None" if rasterId: diff --git a/gui/wxpython/psmap/utils.py b/gui/wxpython/psmap/utils.py index 6bb53acd9f0..4e754fafd39 100644 --- a/gui/wxpython/psmap/utils.py +++ b/gui/wxpython/psmap/utils.py @@ -93,10 +93,7 @@ class UnitConversion: def __init__(self, parent=None): self.parent = parent - if self.parent: - ppi = wx.ClientDC(self.parent).GetPPI() - else: - ppi = (72, 72) + ppi = wx.ClientDC(self.parent).GetPPI() if self.parent else (72, 72) self._unitsPage = { "inch": {"val": 1.0, "tr": _("inch")}, "point": {"val": 72.0, "tr": _("point")}, @@ -323,10 +320,7 @@ def ComputeSetRegion(self, mapDict, env): centerN = mapDict["center"][1] raster = self.instruction.FindInstructionByType("raster") - if raster: - rasterId = raster.id - else: - rasterId = None + rasterId = raster.id if raster else None if rasterId: env["GRASS_REGION"] = gs.region_env( diff --git a/gui/wxpython/rdigit/controller.py b/gui/wxpython/rdigit/controller.py index 8018ee04e5c..9b70a2cc468 100644 --- a/gui/wxpython/rdigit/controller.py +++ b/gui/wxpython/rdigit/controller.py @@ -447,10 +447,7 @@ def _createNewMap(self, mapName, backgroundMap, mapType): name = mapName.split("@")[0] background = backgroundMap.split("@")[0] types = {"CELL": "int", "FCELL": "float", "DCELL": "double"} - if background: - back = background - else: - back = "null()" + back = background or "null()" try: grast.mapcalc( exp="{name} = {mtype}({back})".format( diff --git a/gui/wxpython/timeline/frame.py b/gui/wxpython/timeline/frame.py index fa2b16ad49f..0829d8bc3a0 100644 --- a/gui/wxpython/timeline/frame.py +++ b/gui/wxpython/timeline/frame.py @@ -272,10 +272,9 @@ def _draw3dFigure(self): self.axes3d.clear() self.axes3d.grid(False) # self.axes3d.grid(True) - if self.temporalType == "absolute": - convert = mdates.date2num - else: - convert = lambda x: x # noqa: E731 + convert = ( + mdates.date2num if self.temporalType == "absolute" else lambda x: x + ) # noqa: E731 colors = cycle(COLORS) plots = [] @@ -321,10 +320,9 @@ def _draw2dFigure(self): """Draws 2D plot (temporal extents)""" self.axes2d.clear() self.axes2d.grid(True) - if self.temporalType == "absolute": - convert = mdates.date2num - else: - convert = lambda x: x # noqa: E731 + convert = ( + mdates.date2num if self.temporalType == "absolute" else lambda x: x + ) # noqa: E731 colors = cycle(COLORS) diff --git a/gui/wxpython/tools/update_menudata.py b/gui/wxpython/tools/update_menudata.py index 2f548da3087..08897e6147d 100644 --- a/gui/wxpython/tools/update_menudata.py +++ b/gui/wxpython/tools/update_menudata.py @@ -136,10 +136,7 @@ def main(argv=None): if argv is None: argv = sys.argv - if len(argv) > 1 and argv[1] == "-d": - printDiff = True - else: - printDiff = False + printDiff = bool(len(argv) > 1 and argv[1] == "-d") if len(argv) > 1 and argv[1] == "-h": print(sys.stderr, __doc__, file=sys.stderr) diff --git a/gui/wxpython/tplot/frame.py b/gui/wxpython/tplot/frame.py index 07825058e2d..584d97fbf24 100755 --- a/gui/wxpython/tplot/frame.py +++ b/gui/wxpython/tplot/frame.py @@ -756,10 +756,7 @@ def _writeCSV(self, x, y): """Used to write CSV file of plotted data""" import csv - if isinstance(y[0], list): - zipped = list(zip(x, *y)) - else: - zipped = list(zip(x, y)) + zipped = list(zip(x, *y)) if isinstance(y[0], list) else list(zip(x, y)) with open(self.csvpath, "w", newline="") as fi: writer = csv.writer(fi) if self.header: diff --git a/gui/wxpython/vdigit/dialogs.py b/gui/wxpython/vdigit/dialogs.py index 43b277b2ca7..2e7333cf122 100644 --- a/gui/wxpython/vdigit/dialogs.py +++ b/gui/wxpython/vdigit/dialogs.py @@ -431,10 +431,7 @@ def ApplyChanges(self, fid): if layer not in catsCurr[1].keys() or cat not in catsCurr[1][layer]: catList.append(cat) if catList != []: - if action == "catadd": - add = True - else: - add = False + add = action == "catadd" newfid = self.digit.SetLineCats(fid, layer, catList, add) if len(self.cats.keys()) == 1: diff --git a/gui/wxpython/vdigit/mapwindow.py b/gui/wxpython/vdigit/mapwindow.py index ff7e62ebaa9..db9ebf57caf 100644 --- a/gui/wxpython/vdigit/mapwindow.py +++ b/gui/wxpython/vdigit/mapwindow.py @@ -834,10 +834,7 @@ def OnLeftUpVarious(self, event): self.digit.GetDisplay().SelectAreaByPoint(pos1)["area"] != -1 ) else: - if action == "moveLine": - drawSeg = True - else: - drawSeg = False + drawSeg = action == "moveLine" nselected = self.digit.GetDisplay().SelectLinesByBox( bbox=(pos1, pos2), drawSeg=drawSeg @@ -1103,10 +1100,7 @@ def _onRightUp(self, event): GError(parent=self, message=_("No vector map selected for editing.")) if mapName: - if self.toolbar.GetAction("type") == "line": - line = True - else: - line = False + line = self.toolbar.GetAction("type") == "line" if len(self.polycoords) < 2: # ignore 'one-point' lines return diff --git a/gui/wxpython/vdigit/preferences.py b/gui/wxpython/vdigit/preferences.py index e565c60dfe9..b8fd9096510 100644 --- a/gui/wxpython/vdigit/preferences.py +++ b/gui/wxpython/vdigit/preferences.py @@ -622,10 +622,7 @@ def _createAttributesPage(self, notebook): layer = UserSettings.Get(group="vdigit", key="layer", subkey="value") mapLayer = self.parent.toolbars["vdigit"].GetLayer() tree = self.parent.tree - if tree: - item = tree.FindItemByData("maplayer", mapLayer) - else: - item = None + item = tree.FindItemByData("maplayer", mapLayer) if tree else None row = 0 for attrb in ["length", "area", "perimeter"]: # checkbox @@ -664,10 +661,7 @@ def _createAttributesPage(self, notebook): column.SetStringSelection( tree.GetLayerInfo(item, key="vdigit")["geomAttr"][attrb]["column"] ) - if attrb == "area": - type = "area" - else: - type = "length" + type = "area" if attrb == "area" else "length" unitsIdx = Units.GetUnitsIndex( type, tree.GetLayerInfo(item, key="vdigit")["geomAttr"][attrb]["units"], @@ -987,10 +981,7 @@ def UpdateSettings(self): # geometry attributes (workspace) mapLayer = self.parent.toolbars["vdigit"].GetLayer() tree = self._giface.GetLayerTree() - if tree: - item = tree.FindItemByData("maplayer", mapLayer) - else: - item = None + item = tree.FindItemByData("maplayer", mapLayer) if tree else None for key, val in self.geomAttrb.items(): checked = self.FindWindowById(val["check"]).IsChecked() column = self.FindWindowById(val["column"]).GetValue() @@ -999,11 +990,8 @@ def UpdateSettings(self): tree.SetLayerInfo(item, key="vdigit", value={"geomAttr": {}}) if checked: # enable - if key == "area": - type = key - else: - type = "length" - unitsKey = Units.GetUnitsKey(type, unitsIdx) + _type = key if key == "area" else "length" + unitsKey = Units.GetUnitsKey(_type, unitsIdx) tree.GetLayerInfo(item, key="vdigit")["geomAttr"][key] = { "column": column, "units": unitsKey, diff --git a/gui/wxpython/vdigit/toolbars.py b/gui/wxpython/vdigit/toolbars.py index 6c5c8b21212..a9cafe3dfb4 100644 --- a/gui/wxpython/vdigit/toolbars.py +++ b/gui/wxpython/vdigit/toolbars.py @@ -1291,10 +1291,7 @@ def UpdateListOfLayers(self, updateTool=False): layerNameList.append(layer.GetName()) if updateTool: # update toolbar - if not self.mapLayer: - value = _("Select vector map") - else: - value = layerNameSelected + value = _("Select vector map") if not self.mapLayer else layerNameSelected if not self.comboid: if not self.tools or "selector" in self.tools: diff --git a/gui/wxpython/vdigit/wxdigit.py b/gui/wxpython/vdigit/wxdigit.py index eda912284a0..10cac8710b5 100644 --- a/gui/wxpython/vdigit/wxdigit.py +++ b/gui/wxpython/vdigit/wxdigit.py @@ -1896,10 +1896,7 @@ def _addFeature(self, ftype, coords, layer, cat, snap, threshold): modeSnap, ) - if ftype == GV_AREA: - ltype = GV_BOUNDARY - else: - ltype = ftype + ltype = GV_BOUNDARY if ftype == GV_AREA else ftype newline = Vect_write_line(self.poMapInfo, ltype, self.poPoints, self.poCats) if newline < 0: self._error.WriteLine() diff --git a/gui/wxpython/vdigit/wxdisplay.py b/gui/wxpython/vdigit/wxdisplay.py index d8e4d0a14bf..39662afb19f 100644 --- a/gui/wxpython/vdigit/wxdisplay.py +++ b/gui/wxpython/vdigit/wxdisplay.py @@ -982,15 +982,9 @@ def OpenMap(self, name, mapset, update=True, tmp=False): # open existing map if update: - if tmp: - open_fn = Vect_open_tmp_update - else: - open_fn = Vect_open_update - else: # noqa: PLR5501 - if tmp: - open_fn = Vect_open_tmp_old - else: - open_fn = Vect_open_old + open_fn = Vect_open_tmp_update if tmp else Vect_open_update + else: + open_fn = Vect_open_tmp_old if tmp else Vect_open_old ret = open_fn(self.poMapInfo, name, mapset) diff --git a/gui/wxpython/vnet/dialogs.py b/gui/wxpython/vnet/dialogs.py index ee553a0b741..396f0821c10 100644 --- a/gui/wxpython/vnet/dialogs.py +++ b/gui/wxpython/vnet/dialogs.py @@ -458,7 +458,7 @@ def _createParametersPage(self): # , 'turn_layer', 'turn_cat_layer']: for sel in ["input", "arc_layer", "node_layer"]: - if sel == "input": + if sel == "input": # noqa: SIM108 btn = self.addToTreeBtn # elif sel == "turn_layer": # btn = self.createTtbBtn @@ -843,10 +843,7 @@ def _setInputData(self): def _parseMapStr(self, vectMapStr): """Create full map name (add current mapset if it is not present in name)""" mapValSpl = vectMapStr.strip().split("@") - if len(mapValSpl) > 1: - mapSet = mapValSpl[1] - else: - mapSet = grass.gisenv()["MAPSET"] + mapSet = mapValSpl[1] if len(mapValSpl) > 1 else grass.gisenv()["MAPSET"] mapName = mapValSpl[0] return mapName, mapSet diff --git a/gui/wxpython/vnet/vnet_data.py b/gui/wxpython/vnet/vnet_data.py index f2f17b0bfb5..9971c9a9699 100644 --- a/gui/wxpython/vnet/vnet_data.py +++ b/gui/wxpython/vnet/vnet_data.py @@ -355,10 +355,8 @@ def SetPointStatus(self, item, itemIndex): item.hide = False elif len(cats) > 1: idx = self.data[itemIndex][1] - if idx == 2: # End/To/Sink point - wxPen = "used2cat" - else: - wxPen = "used1cat" + # End/To/Sink point + wxPen = "used2cat" if idx == 2 else "used1cat" else: wxPen = "used1cat" @@ -841,10 +839,7 @@ def GetRelevantParams(self, analysis): cols = self.vnetProperties[analysis]["cmdParams"]["cols"] for col, v in cols.items(): - if "inputField" in col: - colInptF = v["inputField"] - else: - colInptF = col + colInptF = v["inputField"] if "inputField" in col else col relevant_params.append(colInptF) return relevant_params @@ -900,10 +895,7 @@ def HasTmpVectMap(self, vectMapName): """ mapValSpl = vectMapName.strip().split("@") - if len(mapValSpl) > 1: - mapSet = mapValSpl[1] - else: - mapSet = grass.gisenv()["MAPSET"] + mapSet = mapValSpl[1] if len(mapValSpl) > 1 else grass.gisenv()["MAPSET"] mapName = mapValSpl[0] fullName = mapName + "@" + mapSet @@ -1324,10 +1316,7 @@ def _parseLine(self, line, histStepData): del kv[0] idx = 0 while idx < len(kv): - if subkeyMaster: - subkey = [subkeyMaster, kv[idx]] - else: - subkey = kv[idx] + subkey = [subkeyMaster, kv[idx]] if subkeyMaster else kv[idx] value = kv[idx + 1] value = self._parseValue(value, read=True) if key not in histStepData: @@ -1444,21 +1433,14 @@ def DataValidator(self, row, col, value): self.turn_data[i_row][1] = new_to_angle for i_row in inside_new: - if col == 1: - angle = new_from_angle - else: - angle = new_to_angle + angle = new_from_angle if col == 1 else new_to_angle self.turn_data[i_row][1] = angle self.turn_data[i_row][2] = angle def RemoveDataValidator(self, row): """Angle recalculation due to direction remove""" - if row == 0: - prev_row = self.GetLinesCount() - 1 - else: - prev_row = row - 1 - + prev_row = self.GetLinesCount() - 1 if row == 0 else row - 1 remove_to_angle = self.turn_data[row][2] self.turn_data[prev_row][2] = remove_to_angle diff --git a/gui/wxpython/vnet/vnet_utils.py b/gui/wxpython/vnet/vnet_utils.py index e3cc11aee17..7157ac8a20e 100644 --- a/gui/wxpython/vnet/vnet_utils.py +++ b/gui/wxpython/vnet/vnet_utils.py @@ -34,10 +34,7 @@ def ParseMapStr(mapStr): """Create full map name (add current mapset if it is not present in name)""" mapValSpl = mapStr.strip().split("@") - if len(mapValSpl) > 1: - mapSet = mapValSpl[1] - else: - mapSet = grass.gisenv()["MAPSET"] + mapSet = mapValSpl[1] if len(mapValSpl) > 1 else grass.gisenv()["MAPSET"] mapName = mapValSpl[0] return mapName, mapSet diff --git a/gui/wxpython/web_services/widgets.py b/gui/wxpython/web_services/widgets.py index 473a8fb58a2..e54bee5603f 100644 --- a/gui/wxpython/web_services/widgets.py +++ b/gui/wxpython/web_services/widgets.py @@ -384,10 +384,7 @@ def _advancedSettsPage(self): continue if k in labels or k == "o": - if k != "o": - label = labels[k] - else: - label = param + label = labels[k] if k != "o" else param gridSizer.Add( label, flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL, pos=(row, 0) @@ -454,10 +451,7 @@ def _updateLayerOrderList(self, selected=None): """Update order in list.""" def getlayercaption(layer): - if layer["title"]: - cap = layer["title"] - else: - cap = layer["name"] + cap = layer["title"] or layer["name"] if layer["style"]: if layer["style"]["title"]: diff --git a/gui/wxpython/wxgui.py b/gui/wxpython/wxgui.py index 8fac39c4d5a..fe1d6f21054 100644 --- a/gui/wxpython/wxgui.py +++ b/gui/wxpython/wxgui.py @@ -139,10 +139,7 @@ def process_opt(opts, args): printHelp() elif o in {"-w", "--workspace"}: - if a != "": - workspaceFile = str(a) - else: - workspaceFile = args.pop(0) + workspaceFile = str(a) if a != "" else args.pop(0) return workspaceFile diff --git a/gui/wxpython/wxplot/scatter.py b/gui/wxpython/wxplot/scatter.py index c57a3e1fac9..d87a03208e4 100644 --- a/gui/wxpython/wxplot/scatter.py +++ b/gui/wxpython/wxplot/scatter.py @@ -176,11 +176,7 @@ def CreateDatalist(self, rpair): frequency can be in cell counts, percents, or area """ datalist = [] - - if self.scattertype == "bubble": - freqflag = "cn" - else: - freqflag = "n" + freqflag = "cn" if self.scattertype == "bubble" else "n" try: ret = RunCommand( diff --git a/pyproject.toml b/pyproject.toml index a428c79106f..3c5950f922b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -241,7 +241,6 @@ ignore = [ "S608", # hardcoded-sql-expression "SIM102", # collapsible-if "SIM105", # suppressible-exception - "SIM108", # if-else-block-instead-of-if-exp "SIM113", # enumerate-for-loop "SIM116", # if-else-block-instead-of-dict-lookup "SIM118", # in-dict-keys @@ -365,7 +364,7 @@ ignore = [ "temporal/t.rast.algebra/testsu*/*_algebra_arithmetic.py" = ["FLY002"] "temporal/t.rast.colors/t.rast.colors.py" = ["SIM115"] "temporal/t.rast.series/t.rast.series.py" = ["SIM115"] -"temporal/t.rast.what/t.rast.what.py" = ["E265", "E266", "SIM115"] +"temporal/t.rast.what/t.rast.what.py" = ["SIM115"] "temporal/t.register/testsu*/*_raster_different_local.py" = ["FLY002"] "temporal/t.register/testsu*/*_raster_mapmetadata.py" = ["FLY002"] "temporal/t.register/testsuite/test_t_register_raster.py" = ["FLY002"] diff --git a/python/grass/script/core.py b/python/grass/script/core.py index 0b51e7fdbe9..f51814a5900 100644 --- a/python/grass/script/core.py +++ b/python/grass/script/core.py @@ -18,6 +18,8 @@ .. sectionauthor:: Michael Barton """ +from __future__ import annotations + import os import sys import atexit @@ -855,9 +857,9 @@ def get_capture_stderr(): # interface to g.parser -def _parse_opts(lines): - options = {} - flags = {} +def _parse_opts(lines: list) -> tuple[dict[str, str], dict[str, bool]]: + options: dict[str, str] = {} + flags: dict[str, bool] = {} for line in lines: if not line: break @@ -887,7 +889,7 @@ def _parse_opts(lines): return (options, flags) -def parser(): +def parser() -> tuple[dict[str, str], dict[str, bool]]: """Interface to g.parser, intended to be run from the top-level, e.g.: :: diff --git a/python/grass/temporal/abstract_dataset.py b/python/grass/temporal/abstract_dataset.py index bf30afa21dd..6df2fa1f81e 100644 --- a/python/grass/temporal/abstract_dataset.py +++ b/python/grass/temporal/abstract_dataset.py @@ -10,6 +10,8 @@ :authors: Soeren Gebbert """ +from __future__ import annotations + from abc import ABCMeta, abstractmethod from .core import get_current_mapset, get_tgis_message_interface, init_dbif @@ -504,7 +506,7 @@ def update_all(self, dbif=None, execute=True, ident=None): dbif.close() return statement - def is_time_absolute(self): + def is_time_absolute(self) -> bool | None: """Return True in case the temporal type is absolute :return: True if temporal type is absolute, False otherwise @@ -513,7 +515,7 @@ def is_time_absolute(self): return self.base.get_ttype() == "absolute" return None - def is_time_relative(self): + def is_time_relative(self) -> bool | None: """Return True in case the temporal type is relative :return: True if temporal type is relative, False otherwise From ac491770cb2aa2b349333c9ecb6c1ab9d650278d Mon Sep 17 00:00:00 2001 From: Arohan Ajit Date: Fri, 25 Oct 2024 23:09:43 -0400 Subject: [PATCH 25/55] wxGUI: Reverted unused variable fix in wxgui/ (#4595) Seems to break 3D view --- gui/wxpython/wxgui.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gui/wxpython/wxgui.py b/gui/wxpython/wxgui.py index fe1d6f21054..83fed965ecd 100644 --- a/gui/wxpython/wxgui.py +++ b/gui/wxpython/wxgui.py @@ -161,7 +161,7 @@ def main(argv=None): app = GMApp(workspaceFile) # suppress wxPython logs - wx.LogNull() + q = wx.LogNull() # noqa: F841 set_raise_on_error(True) # register GUI PID From 652a2f8c895321d5ae3470603025e822f58315ec Mon Sep 17 00:00:00 2001 From: Anna Petrasova Date: Fri, 25 Oct 2024 23:10:19 -0400 Subject: [PATCH 26/55] wxGUI/nviz: fix imports (#4592) --- gui/wxpython/nviz/wxnviz.py | 88 ++++++++++++++++++++++--------------- 1 file changed, 53 insertions(+), 35 deletions(-) diff --git a/gui/wxpython/nviz/wxnviz.py b/gui/wxpython/nviz/wxnviz.py index 35995d30e6b..32c2541f14e 100644 --- a/gui/wxpython/nviz/wxnviz.py +++ b/gui/wxpython/nviz/wxnviz.py @@ -44,7 +44,6 @@ try: from ctypes import ( CFUNCTYPE, - UNCHECKED, byref, c_char_p, c_double, @@ -58,7 +57,9 @@ print("wxnviz.py: {}".format(e), file=sys.stderr) try: + from grass.lib.ctypes_preamble import UNCHECKED, String from grass.lib.gis import ( + Colors, G_find_raster2, G_find_raster3d, G_find_vector2, @@ -73,20 +74,15 @@ G_warning, ) from grass.lib.nviz import ( - ATT_COLOR, - ATT_EMIT, - ATT_MASK, - ATT_SHINE, - ATT_TOPO, - ATT_TRANSP, - CONST_ATT, - MAP_ATT, + DRAW_QUICK_SURFACE, + DRAW_QUICK_VLINES, + DRAW_QUICK_VOLUME, + DRAW_QUICK_VPOINTS, MAP_OBJ_SITE, MAP_OBJ_SURF, MAP_OBJ_UNDEFINED, MAP_OBJ_VECT, MAP_OBJ_VOL, - Colors, Nviz_change_exag, Nviz_color_from_str, Nviz_del_texture, @@ -153,6 +149,27 @@ nv_data, ) from grass.lib.ogsf import ( + ATT_COLOR, + ATT_EMIT, + ATT_MASK, + ATT_SHINE, + ATT_TOPO, + ATT_TRANSP, + CONST_ATT, + DM_FLAT, + DM_GOURAUD, + MAP_ATT, + MAX_ISOSURFS, + GP_delete_site, + GP_get_sitename, + GP_select_surf, + GP_set_style, + GP_set_style_thematic, + GP_set_trans, + GP_set_zmode, + GP_site_exists, + GP_unselect_surf, + GP_unset_style_thematic, GS_clear, GS_delete_surface, GS_get_cat_at_xy, @@ -177,6 +194,16 @@ GS_surf_exists, GS_write_ppm, GS_write_tif, + GV_delete_vector, + GV_get_vectname, + GV_select_surf, + GV_set_style, + GV_set_style_thematic, + GV_set_trans, + GV_surf_is_selected, + GV_unselect_surf, + GV_unset_style_thematic, + GV_vect_exists, GVL_delete_vol, GVL_get_trans, GVL_init_region, @@ -205,35 +232,13 @@ GVL_slice_set_transp, GVL_vol_exists, ) - from grass.lib.raster import Rast__init_window, Rast_unset_window, Vect_read_colors - from grass.lib.raster3d import ( - GP_delete_site, - GP_get_sitename, - GP_select_surf, - GP_set_style, - GP_set_style_thematic, - GP_set_trans, - GP_set_zmode, - GP_site_exists, - GP_unselect_surf, - GP_unset_style_thematic, - ) - from grass.lib.vector import ( - GV_delete_vector, - GV_get_vectname, - GV_select_surf, - GV_set_style, - GV_set_style_thematic, - GV_set_trans, - GV_surf_is_selected, - GV_unselect_surf, - GV_unset_style_thematic, - GV_vect_exists, - ) + from grass.lib.raster import Rast__init_window, Rast_unset_window + from grass.lib.vector import Vect_read_colors except (ImportError, OSError, TypeError) as e: print("wxnviz.py: {}".format(e), file=sys.stderr) import grass.script as gs + from core.debug import Debug from core.gcmd import DecodeString from core.globalvar import wxPythonPhoenix @@ -2432,3 +2437,16 @@ def GetCmd(self): def Corresponds(self, item): return sorted(self.GetCmd()) == sorted(item.GetCmd()) + + +__all__ = [ + "DM_FLAT", + "DM_GOURAUD", + "DRAW_QUICK_SURFACE", + "DRAW_QUICK_VLINES", + "DRAW_QUICK_VOLUME", + "DRAW_QUICK_VPOINTS", + "MAX_ISOSURFS", + "ImageTexture", + "Nviz", +] From 5af22b2d4eae997953bc62cd865ab0d09883459b Mon Sep 17 00:00:00 2001 From: Vaclav Petras Date: Fri, 25 Oct 2024 23:41:06 -0400 Subject: [PATCH 27/55] lib/iostream: Remove redundant template parameters (#4586) In C++20, repeating template parameter names with the name of the class is no longer allowed as it is redundant (https://cplusplus.github.io/CWG/issues/2237.html). The new code is valid also in C++17, but the old code is not accepted in C++20. --- include/grass/iostream/replacementHeap.h | 6 +++--- include/grass/iostream/replacementHeapBlock.h | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/grass/iostream/replacementHeap.h b/include/grass/iostream/replacementHeap.h index 485d4cef99b..30c309cdda2 100644 --- a/include/grass/iostream/replacementHeap.h +++ b/include/grass/iostream/replacementHeap.h @@ -101,10 +101,10 @@ class ReplacementHeap { public: // allocate array mergeHeap and the runs in runList - ReplacementHeap(size_t arity, queue *runList); + ReplacementHeap(size_t arity, queue *runList); // delete array mergeHeap - ~ReplacementHeap(); + ~ReplacementHeap(); // is heap empty? int empty() const { return (size == 0); } @@ -159,7 +159,7 @@ ReplacementHeap::ReplacementHeap(size_t g_arity, /*****************************************************************/ template -ReplacementHeap::~ReplacementHeap() +ReplacementHeap::~ReplacementHeap() { if (!empty()) { diff --git a/include/grass/iostream/replacementHeapBlock.h b/include/grass/iostream/replacementHeapBlock.h index c1596d67585..f4614eb838b 100644 --- a/include/grass/iostream/replacementHeapBlock.h +++ b/include/grass/iostream/replacementHeapBlock.h @@ -102,10 +102,10 @@ class ReplacementHeapBlock { public: // allocate array mergeHeap, where the streams are stored in runList - ReplacementHeapBlock(queue *> *runList); + ReplacementHeapBlock(queue *> *runList); // delete array mergeHeap - ~ReplacementHeapBlock(); + ~ReplacementHeapBlock(); // is heap empty? int empty() const { return (size == 0); } @@ -161,7 +161,7 @@ ReplacementHeapBlock::ReplacementHeapBlock( /*****************************************************************/ template -ReplacementHeapBlock::~ReplacementHeapBlock() +ReplacementHeapBlock::~ReplacementHeapBlock() { if (!empty()) { From 4616b9d4a276ac1f3f4024e14f155a55557e80a7 Mon Sep 17 00:00:00 2001 From: ShubhamDesai <42180509+ShubhamDesai@users.noreply.github.com> Date: Sat, 26 Oct 2024 16:06:20 -0400 Subject: [PATCH 28/55] lib/vector/Vlib: Fix Resource Leak issues in copy.c (#4533) --- lib/vector/Vlib/copy.c | 91 ++++++++++++++++++++++++++++-------------- 1 file changed, 61 insertions(+), 30 deletions(-) diff --git a/lib/vector/Vlib/copy.c b/lib/vector/Vlib/copy.c index bde7e577c8b..779b5ed4a0f 100644 --- a/lib/vector/Vlib/copy.c +++ b/lib/vector/Vlib/copy.c @@ -82,6 +82,8 @@ int Vect_copy_map_lines_field(struct Map_info *In, int field, struct Map_info *Out) { int ret, format, topo; + const char *geometry_type = NULL; + const char *map_name = NULL; if (Vect_level(In) < 1) G_fatal_error( @@ -127,24 +129,30 @@ int Vect_copy_map_lines_field(struct Map_info *In, int field, /* copy features */ ret += copy_lines_2(In, field, topo, Out); - if (topo == TOPO_NONE && + if (topo == TOPO_NONE) { /* check output feature type, centroids can be exported as * points; boundaries as linestrings */ - strcmp(Vect_get_finfo_geometry_type(Out), "polygon") == 0) { - /* copy areas - external formats and simple features access only */ - ret += Vect__copy_areas(In, field, Out); + geometry_type = Vect_get_finfo_geometry_type(Out); + if (geometry_type && strcmp(geometry_type, "polygon") == 0) { + /* copy areas - external formats and simple features access only + */ + ret += Vect__copy_areas(In, field, Out); + } + G_free((void *)geometry_type); } } else { /* -> copy features on level 1 */ - if (topo == TOPO_NONE) + if (topo == TOPO_NONE) { + map_name = Vect_get_full_name(In); G_warning(_("Vector map <%s> not open on topological level. " "Areas will be skipped!"), - Vect_get_full_name(In)); + map_name); + G_free((void *)map_name); + } ret += copy_lines_1(In, field, Out); } - return ret > 0 ? 1 : 0; } @@ -161,6 +169,7 @@ int Vect_copy_map_lines_field(struct Map_info *In, int field, int copy_lines_1(struct Map_info *In, int field, struct Map_info *Out) { int ret, type; + const char *map_name = NULL; struct line_pnts *Points; struct line_cats *Cats; @@ -174,8 +183,9 @@ int copy_lines_1(struct Map_info *In, int field, struct Map_info *Out) while (TRUE) { type = Vect_read_next_line(In, Points, Cats); if (type == -1) { - G_warning(_("Unable to read vector map <%s>"), - Vect_get_full_name(In)); + map_name = Vect_get_full_name(In); + G_warning(_("Unable to read vector map <%s>"), map_name); + G_free((void *)map_name); ret = 1; break; } @@ -193,7 +203,6 @@ int copy_lines_1(struct Map_info *In, int field, struct Map_info *Out) Vect_write_line(Out, type, Points, Cats); } - Vect_destroy_line_struct(Points); Vect_destroy_cats_struct(Cats); @@ -220,6 +229,7 @@ int copy_lines_2(struct Map_info *In, int field, int topo, struct Map_info *Out) struct line_cats *Cats, *CCats; const char *ftype = NULL; + const char *map_name = NULL; Points = Vect_new_line_struct(); CPoints = Vect_new_line_struct(); @@ -251,8 +261,9 @@ int copy_lines_2(struct Map_info *In, int field, int topo, struct Map_info *Out) G_percent(i, nlines, 2); type = Vect_read_line(In, Points, Cats, i); if (type == -1) { - G_warning(_("Unable to read vector map <%s>"), - Vect_get_full_name(In)); + map_name = Vect_get_full_name(In); + G_warning(_("Unable to read vector map <%s>"), map_name); + G_free((void *)map_name); ret = 1; break; /* free allocated space and return */ } @@ -364,7 +375,8 @@ int copy_lines_2(struct Map_info *In, int field, int topo, struct Map_info *Out) if (-1 == Vect_write_line(Out, type, Points, Cats)) { G_warning(_("Writing new feature failed")); - return 1; + ret = 1; + goto free_exit; } } @@ -372,12 +384,13 @@ int copy_lines_2(struct Map_info *In, int field, int topo, struct Map_info *Out) G_important_message( _("%d features without category or from different layer skipped"), nskipped); - +free_exit: Vect_destroy_line_struct(Points); Vect_destroy_line_struct(CPoints); Vect_destroy_line_struct(NPoints); Vect_destroy_cats_struct(Cats); Vect_destroy_cats_struct(CCats); + G_free((void *)ftype); return ret; } @@ -496,6 +509,7 @@ int is_isle(struct Map_info *Map, int area) int Vect__copy_areas(struct Map_info *In, int field, struct Map_info *Out) { int i, area, nareas, cat, isle, nisles, nparts_alloc, nskipped; + int ret = 0; struct line_pnts **Points; struct line_cats *Cats; @@ -567,7 +581,8 @@ int Vect__copy_areas(struct Map_info *In, int field, struct Map_info *Out) if (0 > V2__write_area_sfa(Out, (const struct line_pnts **)Points, nisles + 1, Cats)) { G_warning(_("Writing area %d failed"), area); - return -1; + ret = -1; + goto free_exit; } } #ifdef HAVE_POSTGRES @@ -575,7 +590,8 @@ int Vect__copy_areas(struct Map_info *In, int field, struct Map_info *Out) if (0 > V2__update_area_pg(Out, (const struct line_pnts **)Points, nisles + 1, cat)) { G_warning(_("Writing area %d failed"), area); - return -1; + ret = -1; + goto free_exit; } } #endif @@ -587,11 +603,13 @@ int Vect__copy_areas(struct Map_info *In, int field, struct Map_info *Out) nskipped); /* free allocated space for isles */ +free_exit: for (i = 0; i < nparts_alloc; i++) Vect_destroy_line_struct(Points[i]); Vect_destroy_cats_struct(Cats); + G_free(Points); - return 0; + return ret; } /*! @@ -615,6 +633,7 @@ int Vect_copy_tables(struct Map_info *In, struct Map_info *Out, int field) { int i, n, type; struct field_info *Fi; + const char *map_name = NULL; n = Vect_get_num_dblinks(In); @@ -631,20 +650,23 @@ int Vect_copy_tables(struct Map_info *In, struct Map_info *Out, int field) In->dblnk->field[i].number); return -1; } - if (field > 0 && Fi->number != field) + if (field > 0 && Fi->number != field) { + Vect_destroy_field_info(Fi); continue; + } if (Vect_copy_table(In, Out, Fi->number, Fi->number, Fi->name, type) != 0) { - + map_name = Vect_get_full_name(In); G_warning( _("Unable to copy table <%s> for layer %d from <%s> to <%s>"), - Fi->table, Fi->number, Vect_get_full_name(In), - Vect_get_name(Out)); + Fi->table, Fi->number, map_name, Vect_get_name(Out)); + G_free((void *)map_name); + Vect_destroy_field_info(Fi); return -1; } + Vect_destroy_field_info(Fi); } - return 0; } @@ -729,10 +751,10 @@ int Vect_copy_table_by_cats(struct Map_info *In, struct Map_info *Out, int field_in, int field_out, const char *field_name, int type, int *cats, int ncats) { - int ret; + int ret = 0; struct field_info *Fi, *Fin; const char *name, *key; - dbDriver *driver; + dbDriver *driver = NULL; G_debug(2, "Vect_copy_table_by_cats(): field_in = %d field_out = %d", field_in, field_out); @@ -757,7 +779,7 @@ int Vect_copy_table_by_cats(struct Map_info *In, struct Map_info *Out, if (ret == -1) { G_warning(_("Unable to add database link for vector map <%s>"), Out->name); - return -1; + goto free_exit; } if (cats) @@ -770,7 +792,8 @@ int Vect_copy_table_by_cats(struct Map_info *In, struct Map_info *Out, Fin->table, key, cats, ncats); if (ret == DB_FAILED) { G_warning(_("Unable to copy table <%s>"), Fin->table); - return -1; + ret = -1; + goto free_exit; } driver = db_start_driver_open_database(Fin->driver, @@ -779,22 +802,30 @@ int Vect_copy_table_by_cats(struct Map_info *In, struct Map_info *Out, if (!driver) { G_warning(_("Unable to open database <%s> with driver <%s>"), Fin->database, Fin->driver); - return -1; + ret = -1; + goto free_exit; } /* do not allow duplicate keys */ if (db_create_index2(driver, Fin->table, Fi->key) != DB_OK) { G_warning(_("Unable to create index")); - return -1; + ret = -1; + goto close_db_free_exit; } if (db_grant_on_table(driver, Fin->table, DB_PRIV_SELECT, DB_GROUP | DB_PUBLIC) != DB_OK) { G_warning(_("Unable to grant privileges on table <%s>"), Fin->table); - return -1; + ret = -1; + goto close_db_free_exit; } +close_db_free_exit: db_close_database_shutdown_driver(driver); - return 0; +free_exit: + Vect_destroy_field_info(Fi); + Vect_destroy_field_info(Fin); + + return ret; } From 791077766d2d93d4feea51b0973db73d3cf328d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Sun, 27 Oct 2024 05:24:18 -0400 Subject: [PATCH 29/55] style: Fix superfluous-else rules for raise, continue and break (RET506, RET507, RET508) (#4565) --- doc/python/m.distance.py | 3 +- gui/wxpython/animation/temporal_manager.py | 7 +- gui/wxpython/core/gcmd.py | 9 +- gui/wxpython/core/render.py | 16 +- gui/wxpython/dbmgr/base.py | 4 +- gui/wxpython/dbmgr/dialogs.py | 17 +- gui/wxpython/gui_core/widgets.py | 2 +- gui/wxpython/iclass/dialogs.py | 5 +- gui/wxpython/iscatt/frame.py | 5 +- gui/wxpython/location_wizard/wizard.py | 3 +- gui/wxpython/mapdisp/statusbar.py | 197 +++++++------ gui/wxpython/nviz/tools.py | 7 +- gui/wxpython/psmap/instructions.py | 4 +- gui/wxpython/timeline/frame.py | 2 +- gui/wxpython/tplot/frame.py | 2 +- gui/wxpython/vnet/dialogs.py | 15 +- gui/wxpython/vnet/vnet_data.py | 9 +- man/build_class_graphical.py | 2 +- pyproject.toml | 3 - python/grass/imaging/images2avi.py | 31 +-- python/grass/pygrass/gis/__init__.py | 2 +- python/grass/pygrass/messages/__init__.py | 3 +- .../pygrass/modules/interface/parameter.py | 10 +- python/grass/pygrass/raster/category.py | 2 +- python/grass/pygrass/vector/table.py | 3 +- python/grass/script/task.py | 3 +- python/grass/temporal/temporal_algebra.py | 82 +++--- python/grass/temporal/temporal_operator.py | 260 +++++++++--------- .../temporal/temporal_raster_base_algebra.py | 13 +- .../grass/temporal/temporal_vector_algebra.py | 2 +- scripts/db.in.ogr/db.in.ogr.py | 3 +- scripts/r.in.wms/wms_cap_parsers.py | 3 +- scripts/r.in.wms/wms_drv.py | 3 +- scripts/v.what.strds/v.what.strds.py | 3 +- .../t.vect.observe.strds.py | 3 +- 35 files changed, 352 insertions(+), 386 deletions(-) diff --git a/doc/python/m.distance.py b/doc/python/m.distance.py index 576760c3b40..2383cbfb669 100755 --- a/doc/python/m.distance.py +++ b/doc/python/m.distance.py @@ -82,8 +82,7 @@ def main(): line = sys.stdin.readline().strip() if not line: # EOF break - else: - coords.append(line.split(",")) + coords.append(line.split(",")) else: # read from coord= command line option p = None diff --git a/gui/wxpython/animation/temporal_manager.py b/gui/wxpython/animation/temporal_manager.py index 1b5037639cf..0f00cc6e329 100644 --- a/gui/wxpython/animation/temporal_manager.py +++ b/gui/wxpython/animation/temporal_manager.py @@ -297,10 +297,9 @@ def _getLabelsAndMaps(self, timeseries): # skip this one, already there followsPoint = False continue - else: - # append the last one (of point time) - listOfMaps.append(lastTimeseries) - end = None + # append the last one (of point time) + listOfMaps.append(lastTimeseries) + end = None else: # append series which is None listOfMaps.append(series) diff --git a/gui/wxpython/core/gcmd.py b/gui/wxpython/core/gcmd.py index 134ed756d23..dfd719b2ff0 100644 --- a/gui/wxpython/core/gcmd.py +++ b/gui/wxpython/core/gcmd.py @@ -311,9 +311,8 @@ def recv_some(p, t=0.1, e=1, tr=5, stderr=0): if r is None: if e: raise Exception(message) - else: - break - elif r: + break + if r: y.append(decode(r)) else: time.sleep(max((x - time.time()) / tr, 0)) @@ -415,7 +414,7 @@ def __init__( _("Error: ") + self.__GetError(), ) ) - elif rerr == sys.stderr: # redirect message to sys + if rerr == sys.stderr: # redirect message to sys stderr.write("Execution failed: '%s'" % (" ".join(self.cmd))) stderr.write( "%sDetails:%s%s" @@ -644,7 +643,7 @@ def _formatMsg(text): for line in text.splitlines(): if len(line) == 0: continue - elif ( + if ( "GRASS_INFO_MESSAGE" in line or "GRASS_INFO_WARNING" in line or "GRASS_INFO_ERROR" in line diff --git a/gui/wxpython/core/render.py b/gui/wxpython/core/render.py index 989287cd4a5..b5fdf34d7dd 100644 --- a/gui/wxpython/core/render.py +++ b/gui/wxpython/core/render.py @@ -1184,32 +1184,32 @@ def SetRegion(self, windres=False, windres3=False): if key == "north": grass_region += "north: %s; " % (region["n"]) continue - elif key == "south": + if key == "south": grass_region += "south: %s; " % (region["s"]) continue - elif key == "east": + if key == "east": grass_region += "east: %s; " % (region["e"]) continue - elif key == "west": + if key == "west": grass_region += "west: %s; " % (region["w"]) continue - elif key == "e-w resol": + if key == "e-w resol": grass_region += "e-w resol: %.10f; " % (region["ewres"]) continue - elif key == "n-s resol": + if key == "n-s resol": grass_region += "n-s resol: %.10f; " % (region["nsres"]) continue - elif key == "cols": + if key == "cols": if windres: continue grass_region += "cols: %d; " % region["cols"] continue - elif key == "rows": + if key == "rows": if windres: continue grass_region += "rows: %d; " % region["rows"] continue - elif key == "n-s resol3" and windres3: + if key == "n-s resol3" and windres3: grass_region += "n-s resol3: %f; " % (region["nsres3"]) elif key == "e-w resol3" and windres3: grass_region += "e-w resol3: %f; " % (region["ewres3"]) diff --git a/gui/wxpython/dbmgr/base.py b/gui/wxpython/dbmgr/base.py index c5eb8877b0a..aeb1a2b3090 100644 --- a/gui/wxpython/dbmgr/base.py +++ b/gui/wxpython/dbmgr/base.py @@ -1659,8 +1659,8 @@ def OnDataItemAdd(self, event): raise ValueError( _("Category number (column %s) is missing.") % keyColumn ) - else: - continue + + continue try: if tlist.columns[columnName[i]]["ctype"] == int: diff --git a/gui/wxpython/dbmgr/dialogs.py b/gui/wxpython/dbmgr/dialogs.py index 8ec2b12f36b..c94e2a71e40 100644 --- a/gui/wxpython/dbmgr/dialogs.py +++ b/gui/wxpython/dbmgr/dialogs.py @@ -648,15 +648,14 @@ def __init__( self.boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL) cId += 1 continue - else: - valueWin = SpinCtrl( - parent=self.dataPanel, - id=wx.ID_ANY, - value=value, - min=-1e9, - max=1e9, - size=(250, -1), - ) + valueWin = SpinCtrl( + parent=self.dataPanel, + id=wx.ID_ANY, + value=value, + min=-1e9, + max=1e9, + size=(250, -1), + ) else: valueWin = TextCtrl( parent=self.dataPanel, id=wx.ID_ANY, value=value, size=(250, -1) diff --git a/gui/wxpython/gui_core/widgets.py b/gui/wxpython/gui_core/widgets.py index 87a09a590d8..b787bf23037 100644 --- a/gui/wxpython/gui_core/widgets.py +++ b/gui/wxpython/gui_core/widgets.py @@ -1603,7 +1603,7 @@ def _loadSettings_v2(self, fd_lines): idx = line.find(";", i_last) if idx < 0: break - elif idx != 0: + if idx != 0: # find out whether it is separator # $$$$; - it is separator # $$$$$; - it is not separator diff --git a/gui/wxpython/iclass/dialogs.py b/gui/wxpython/iclass/dialogs.py index 615e614689f..c868c6e08cf 100644 --- a/gui/wxpython/iclass/dialogs.py +++ b/gui/wxpython/iclass/dialogs.py @@ -486,9 +486,8 @@ def GetSelectedIndices(self, state=wx.LIST_STATE_SELECTED): index = self.GetNextItem(lastFound, wx.LIST_NEXT_ALL, state) if index == -1: break - else: - lastFound = index - indices.append(index) + lastFound = index + indices.append(index) return indices def OnEdit(self, event): diff --git a/gui/wxpython/iscatt/frame.py b/gui/wxpython/iscatt/frame.py index 5350ecbd8a0..3addbad2f06 100644 --- a/gui/wxpython/iscatt/frame.py +++ b/gui/wxpython/iscatt/frame.py @@ -501,9 +501,8 @@ def GetSelectedIndices(self, state=wx.LIST_STATE_SELECTED): index = self.GetNextItem(lastFound, wx.LIST_NEXT_ALL, state) if index == -1: break - else: - lastFound = index - indices.append(index) + lastFound = index + indices.append(index) return indices def DeselectAll(self): diff --git a/gui/wxpython/location_wizard/wizard.py b/gui/wxpython/location_wizard/wizard.py index d553b4e11d9..9f3bf14c886 100644 --- a/gui/wxpython/location_wizard/wizard.py +++ b/gui/wxpython/location_wizard/wizard.py @@ -900,8 +900,7 @@ def OnPageChange(self, event=None): if param["type"] == "bool": if param["value"] is False: continue - else: - self.p4projparams += " +" + param["proj4"] + self.p4projparams += " +" + param["proj4"] elif param["value"] is None: wx.MessageBox( parent=self, diff --git a/gui/wxpython/mapdisp/statusbar.py b/gui/wxpython/mapdisp/statusbar.py index 4fea1ffcc81..8cf5c3b6ff7 100644 --- a/gui/wxpython/mapdisp/statusbar.py +++ b/gui/wxpython/mapdisp/statusbar.py @@ -542,23 +542,22 @@ def ReprojectENToMap(self, e, n, useDefinedProjection): ) if not settings: raise SbException(_("Projection not defined (check the settings)")) + # reproject values + projIn = settings + projOut = RunCommand("g.proj", flags="jf", read=True) + proj = projIn.split(" ")[0].split("=")[1] + if proj in {"ll", "latlong", "longlat"}: + e, n = utils.DMS2Deg(e, n) + proj, coord1 = utils.ReprojectCoordinates( + coord=(e, n), projIn=projIn, projOut=projOut, flags="d" + ) + e, n = coord1 else: - # reproject values - projIn = settings - projOut = RunCommand("g.proj", flags="jf", read=True) - proj = projIn.split(" ")[0].split("=")[1] - if proj in {"ll", "latlong", "longlat"}: - e, n = utils.DMS2Deg(e, n) - proj, coord1 = utils.ReprojectCoordinates( - coord=(e, n), projIn=projIn, projOut=projOut, flags="d" - ) - e, n = coord1 - else: - e, n = float(e), float(n) - proj, coord1 = utils.ReprojectCoordinates( - coord=(e, n), projIn=projIn, projOut=projOut, flags="d" - ) - e, n = coord1 + e, n = float(e), float(n) + proj, coord1 = utils.ReprojectCoordinates( + coord=(e, n), projIn=projIn, projOut=projOut, flags="d" + ) + e, n = coord1 elif self.mapFrame.GetMap().projinfo["proj"] == "ll": e, n = utils.DMS2Deg(e, n) else: @@ -620,32 +619,28 @@ def GetCenterString(self, map): if self.mapFrame.GetProperty("useDefinedProjection"): if not projection: raise SbException(_("Projection not defined (check the settings)")) - else: - proj, coord = utils.ReprojectCoordinates( - coord=(region["center_easting"], region["center_northing"]), - projOut=projection, - flags="d", - ) - if coord: - if proj in {"ll", "latlong", "longlat"} and format == "DMS": - return "%s" % utils.Deg2DMS( - coord[0], coord[1], precision=precision - ) - return "%.*f; %.*f" % (precision, coord[0], precision, coord[1]) - raise SbException(_("Error in projection (check the settings)")) - elif self.mapFrame.GetMap().projinfo["proj"] == "ll" and format == "DMS": + proj, coord = utils.ReprojectCoordinates( + coord=(region["center_easting"], region["center_northing"]), + projOut=projection, + flags="d", + ) + if coord: + if proj in {"ll", "latlong", "longlat"} and format == "DMS": + return "%s" % utils.Deg2DMS(coord[0], coord[1], precision=precision) + return "%.*f; %.*f" % (precision, coord[0], precision, coord[1]) + raise SbException(_("Error in projection (check the settings)")) + if self.mapFrame.GetMap().projinfo["proj"] == "ll" and format == "DMS": return "%s" % utils.Deg2DMS( region["center_easting"], region["center_northing"], precision=precision, ) - else: - return "%.*f; %.*f" % ( - precision, - region["center_easting"], - precision, - region["center_northing"], - ) + return "%.*f; %.*f" % ( + precision, + region["center_easting"], + precision, + region["center_northing"], + ) def SetCenter(self): """Set current map center as item value""" @@ -795,21 +790,19 @@ def ReprojectENFromMap(self, e, n, useDefinedProjection, precision, format): ) if not settings: raise SbException(_("Projection not defined (check the settings)")) - else: - # reproject values - proj, coord = utils.ReprojectCoordinates( - coord=(e, n), projOut=settings, flags="d" - ) - if coord: - e, n = coord - if proj in {"ll", "latlong", "longlat"} and format == "DMS": - return utils.Deg2DMS(e, n, precision=precision) - return "%.*f; %.*f" % (precision, e, precision, n) - raise SbException(_("Error in projection (check the settings)")) - elif self.mapFrame.GetMap().projinfo["proj"] == "ll" and format == "DMS": + # reproject values + proj, coord = utils.ReprojectCoordinates( + coord=(e, n), projOut=settings, flags="d" + ) + if coord: + e, n = coord + if proj in {"ll", "latlong", "longlat"} and format == "DMS": + return utils.Deg2DMS(e, n, precision=precision) + return "%.*f; %.*f" % (precision, e, precision, n) + raise SbException(_("Error in projection (check the settings)")) + if self.mapFrame.GetMap().projinfo["proj"] == "ll" and format == "DMS": return utils.Deg2DMS(e, n, precision=precision) - else: - return "%.*f; %.*f" % (precision, e, precision, n) + return "%.*f; %.*f" % (precision, e, precision, n) class SbRegionExtent(SbTextItem): @@ -872,54 +865,53 @@ def ReprojectRegionFromMap(self, region, useDefinedProjection, precision, format if not settings: raise SbException(_("Projection not defined (check the settings)")) - else: - projOut = settings - proj, coord1 = utils.ReprojectCoordinates( - coord=(region["w"], region["s"]), projOut=projOut, flags="d" - ) - proj, coord2 = utils.ReprojectCoordinates( - coord=(region["e"], region["n"]), projOut=projOut, flags="d" - ) - # useless, used in derived class - proj, coord3 = utils.ReprojectCoordinates( - coord=(0.0, 0.0), projOut=projOut, flags="d" - ) - proj, coord4 = utils.ReprojectCoordinates( - coord=(region["ewres"], region["nsres"]), projOut=projOut, flags="d" - ) - if coord1 and coord2: - if proj in {"ll", "latlong", "longlat"} and format == "DMS": - w, s = utils.Deg2DMS( - coord1[0], coord1[1], string=False, precision=precision - ) - e, n = utils.Deg2DMS( - coord2[0], coord2[1], string=False, precision=precision - ) - ewres, nsres = utils.Deg2DMS( - abs(coord3[0]) - abs(coord4[0]), - abs(coord3[1]) - abs(coord4[1]), - string=False, - hemisphere=False, - precision=precision, - ) - return self._formatRegion( - w=w, s=s, e=e, n=n, ewres=ewres, nsres=nsres - ) - w, s = coord1 - e, n = coord2 - ewres, nsres = coord3 - return self._formatRegion( - w=w, - s=s, - e=e, - n=n, - ewres=ewres, - nsres=nsres, + projOut = settings + proj, coord1 = utils.ReprojectCoordinates( + coord=(region["w"], region["s"]), projOut=projOut, flags="d" + ) + proj, coord2 = utils.ReprojectCoordinates( + coord=(region["e"], region["n"]), projOut=projOut, flags="d" + ) + # useless, used in derived class + proj, coord3 = utils.ReprojectCoordinates( + coord=(0.0, 0.0), projOut=projOut, flags="d" + ) + proj, coord4 = utils.ReprojectCoordinates( + coord=(region["ewres"], region["nsres"]), projOut=projOut, flags="d" + ) + if coord1 and coord2: + if proj in {"ll", "latlong", "longlat"} and format == "DMS": + w, s = utils.Deg2DMS( + coord1[0], coord1[1], string=False, precision=precision + ) + e, n = utils.Deg2DMS( + coord2[0], coord2[1], string=False, precision=precision + ) + ewres, nsres = utils.Deg2DMS( + abs(coord3[0]) - abs(coord4[0]), + abs(coord3[1]) - abs(coord4[1]), + string=False, + hemisphere=False, precision=precision, ) - raise SbException(_("Error in projection (check the settings)")) + return self._formatRegion( + w=w, s=s, e=e, n=n, ewres=ewres, nsres=nsres + ) + w, s = coord1 + e, n = coord2 + ewres, nsres = coord3 + return self._formatRegion( + w=w, + s=s, + e=e, + n=n, + ewres=ewres, + nsres=nsres, + precision=precision, + ) + raise SbException(_("Error in projection (check the settings)")) - elif self.mapFrame.GetMap().projinfo["proj"] == "ll" and format == "DMS": + if self.mapFrame.GetMap().projinfo["proj"] == "ll" and format == "DMS": w, s = utils.Deg2DMS( region["w"], region["s"], string=False, precision=precision ) @@ -930,13 +922,12 @@ def ReprojectRegionFromMap(self, region, useDefinedProjection, precision, format region["ewres"], region["nsres"], string=False, precision=precision ) return self._formatRegion(w=w, s=s, e=e, n=n, ewres=ewres, nsres=nsres) - else: - w, s = region["w"], region["s"] - e, n = region["e"], region["n"] - ewres, nsres = region["ewres"], region["nsres"] - return self._formatRegion( - w=w, s=s, e=e, n=n, ewres=ewres, nsres=nsres, precision=precision - ) + w, s = region["w"], region["s"] + e, n = region["e"], region["n"] + ewres, nsres = region["ewres"], region["nsres"] + return self._formatRegion( + w=w, s=s, e=e, n=n, ewres=ewres, nsres=nsres, precision=precision + ) class SbCompRegionExtent(SbRegionExtent): diff --git a/gui/wxpython/nviz/tools.py b/gui/wxpython/nviz/tools.py index 150fe519635..dce751e6b27 100644 --- a/gui/wxpython/nviz/tools.py +++ b/gui/wxpython/nviz/tools.py @@ -3933,8 +3933,7 @@ def OnSurfacePosition(self, event): self.win["surface"]["position"]["reset"], }: continue - else: - self.FindWindowById(win).SetValue(value) + self.FindWindowById(win).SetValue(value) data = self.GetLayerData("surface") id = data["surface"]["object"]["id"] @@ -4747,8 +4746,8 @@ def OnVolumePosition(self, event): self.win["volume"]["position"]["reset"], }: continue - else: - self.FindWindowById(win).SetValue(value) + + self.FindWindowById(win).SetValue(value) data = self.GetLayerData("volume") id = data["volume"]["object"]["id"] diff --git a/gui/wxpython/psmap/instructions.py b/gui/wxpython/psmap/instructions.py index 82560353806..dcdfb907383 100644 --- a/gui/wxpython/psmap/instructions.py +++ b/gui/wxpython/psmap/instructions.py @@ -223,7 +223,7 @@ def Read(self, filename): buffer = [] continue - elif line.startswith("paper"): + if line.startswith("paper"): instruction = "paper" isBuffer = True buffer.append(line) @@ -698,7 +698,7 @@ def Read(self, instruction, text, **kwargs): if line.split()[1].lower() in {"n", "no", "none"}: instr["border"] = "n" break - elif line.split()[1].lower() in {"y", "yes"}: + if line.split()[1].lower() in {"y", "yes"}: instr["border"] = "y" elif line.startswith("width"): instr["width"] = line.split()[1] diff --git a/gui/wxpython/timeline/frame.py b/gui/wxpython/timeline/frame.py index 0829d8bc3a0..c5c54982ed3 100644 --- a/gui/wxpython/timeline/frame.py +++ b/gui/wxpython/timeline/frame.py @@ -518,7 +518,7 @@ def _checkDatasets(self, datasets): if len(indices) == 0: raise GException(errorMsg) - elif len(indices) >= 2: + if len(indices) >= 2: dlg = wx.SingleChoiceDialog( self, message=_("Please specify the space time dataset <%s>.") % dataset, diff --git a/gui/wxpython/tplot/frame.py b/gui/wxpython/tplot/frame.py index 584d97fbf24..db798081c51 100755 --- a/gui/wxpython/tplot/frame.py +++ b/gui/wxpython/tplot/frame.py @@ -1175,7 +1175,7 @@ def _checkDatasets(self, datasets, typ): if len(indices) == 0: raise GException(errorMsg) - elif len(indices) >= 2: + if len(indices) >= 2: dlg = wx.SingleChoiceDialog( self, message=_("Please specify the space time dataset <%s>.") % dataset, diff --git a/gui/wxpython/vnet/dialogs.py b/gui/wxpython/vnet/dialogs.py index 396f0821c10..2979429a572 100644 --- a/gui/wxpython/vnet/dialogs.py +++ b/gui/wxpython/vnet/dialogs.py @@ -647,11 +647,11 @@ def _updateInputDbMgrData(self): if inpLayer in browseLayers: needLayers.append(inpLayer) continue - else: - wx.BeginBusyCursor() - self.inpDbMgrData["browse"].AddLayer(inpLayer) - wx.EndBusyCursor() - needLayers.append(inpLayer) + + wx.BeginBusyCursor() + self.inpDbMgrData["browse"].AddLayer(inpLayer) + wx.EndBusyCursor() + needLayers.append(inpLayer) for layer in browseLayers: if layer not in needLayers: @@ -1977,7 +1977,6 @@ def GetSelectedIndices(self, state=wx.LIST_STATE_SELECTED): index = self.GetNextItem(lastFound, wx.LIST_NEXT_ALL, state) if index == -1: break - else: - lastFound = index - indices.append(index) + lastFound = index + indices.append(index) return indices diff --git a/gui/wxpython/vnet/vnet_data.py b/gui/wxpython/vnet/vnet_data.py index 9971c9a9699..2074e037350 100644 --- a/gui/wxpython/vnet/vnet_data.py +++ b/gui/wxpython/vnet/vnet_data.py @@ -1187,9 +1187,8 @@ def _savePreviousHist(self, newHist, oldHist): if newHistStepsNum >= self.maxHistSteps: removedHistStep = removedHistData[line] = {} continue - else: - newHist.write("%s%s%s" % ("\n", line, "\n")) - self.histStepsNum = newHistStepsNum + newHist.write("%s%s%s" % ("\n", line, "\n")) + self.histStepsNum = newHistStepsNum elif newHistStepsNum >= self.maxHistSteps: self._parseLine(line, removedHistStep) else: @@ -1289,10 +1288,10 @@ def _getHistStepData(self, histStep): for line in hist: if not line.strip() and isSearchedHistStep: break - elif not line.strip(): + if not line.strip(): newHistStep = True continue - elif isSearchedHistStep: + if isSearchedHistStep: self._parseLine(line, histStepData) if newHistStep: diff --git a/man/build_class_graphical.py b/man/build_class_graphical.py index 554c950d3a8..83338f1942c 100644 --- a/man/build_class_graphical.py +++ b/man/build_class_graphical.py @@ -165,7 +165,7 @@ def generate_page_for_category( img_class = "linkimg" if skip_no_image and not img: continue - elif not img: + if not img: img = "grass_logo.png" img_class = "default-img" if basename.startswith("wxGUI"): diff --git a/pyproject.toml b/pyproject.toml index 3c5950f922b..d739653809e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -208,9 +208,6 @@ ignore = [ "RET501", # unnecessary-return-none "RET502", # implicit-return-value "RET503", # implicit-return - "RET506", # superfluous-else-raise - "RET507", # superfluous-else-continue - "RET508", # superfluous-else-break "RUF003", # ambiguous-unicode-character-comment "RUF005", # collection-literal-concatenation "RUF012", # mutable-class-default diff --git a/python/grass/imaging/images2avi.py b/python/grass/imaging/images2avi.py index 1b0d9d8cd20..9776b9c0db2 100644 --- a/python/grass/imaging/images2avi.py +++ b/python/grass/imaging/images2avi.py @@ -141,19 +141,18 @@ def writeAvi( print(gs.decode(outPut)) print(gs.decode(S.stderr.read())) raise RuntimeError(_("Could not write avi.")) - else: - try: - # Copy avi - shutil.copy(os.path.join(tempDir, "output.avi"), filename) - except Exception as err: - # Clean up - _cleanDir(tempDir) - if bg_task: - return str(err) - raise - + try: + # Copy avi + shutil.copy(os.path.join(tempDir, "output.avi"), filename) + except Exception as err: # Clean up _cleanDir(tempDir) + if bg_task: + return str(err) + raise + + # Clean up + _cleanDir(tempDir) def readAvi(filename, asNumpy=True): @@ -195,11 +194,11 @@ def readAvi(filename, asNumpy=True): # Clean up _cleanDir(tempDir) raise RuntimeError("Could not read avi.") - else: - # Read images - images = images2ims.readIms(os.path.join(tempDir, "im*.jpg"), asNumpy) - # Clean up - _cleanDir(tempDir) + + # Read images + images = images2ims.readIms(os.path.join(tempDir, "im*.jpg"), asNumpy) + # Clean up + _cleanDir(tempDir) # Done return images diff --git a/python/grass/pygrass/gis/__init__.py b/python/grass/pygrass/gis/__init__.py index 597c4bf75fa..29fecd3d699 100644 --- a/python/grass/pygrass/gis/__init__.py +++ b/python/grass/pygrass/gis/__init__.py @@ -114,7 +114,7 @@ def make_mapset(mapset, location=None, gisdbase=None): res = libgis.G_make_mapset(gisdbase, location, mapset) if res == -1: raise GrassError("Cannot create new mapset") - elif res == -2: + if res == -2: raise GrassError("Illegal name") diff --git a/python/grass/pygrass/messages/__init__.py b/python/grass/pygrass/messages/__init__.py index 36356433381..54d9af1b1c5 100644 --- a/python/grass/pygrass/messages/__init__.py +++ b/python/grass/pygrass/messages/__init__.py @@ -262,8 +262,7 @@ def fatal(self, message): if self.raise_on_error is True: raise FatalError(message) - else: - sys.exit(1) + sys.exit(1) def debug(self, level, message): """Send a debug message to stderr diff --git a/python/grass/pygrass/modules/interface/parameter.py b/python/grass/pygrass/modules/interface/parameter.py index 1ec5466bc74..d950cd40008 100644 --- a/python/grass/pygrass/modules/interface/parameter.py +++ b/python/grass/pygrass/modules/interface/parameter.py @@ -18,15 +18,15 @@ def _check_value(param, value): string = (bytes, str) def raiseexcpet(exc, param, ptype, value): - """Function to modifa the error message""" + """Function to modify the error message""" msg = req % (param.name, param.typedesc, ptype, value, str(exc)) if isinstance(exc, ValueError): raise ValueError(msg) - elif isinstance(exc, TypeError): + if isinstance(exc, TypeError): raise TypeError(msg) - else: - exc.message = msg - raise exc + + exc.message = msg + raise exc def check_string(value): """Function to check that a string parameter is already a string""" diff --git a/python/grass/pygrass/raster/category.py b/python/grass/pygrass/raster/category.py index fa4e8d37b12..9c34bb8390f 100644 --- a/python/grass/pygrass/raster/category.py +++ b/python/grass/pygrass/raster/category.py @@ -189,7 +189,7 @@ def _set_c_cat(self, label, min_cat, max_cat=None): return None if err == 0: raise GrassError(_("Null value detected")) - elif err == -1: + if err == -1: raise GrassError(_("Error executing: Rast_set_cat")) def __del__(self): diff --git a/python/grass/pygrass/vector/table.py b/python/grass/pygrass/vector/table.py index 5442d2f1e51..b83f751a0dd 100644 --- a/python/grass/pygrass/vector/table.py +++ b/python/grass/pygrass/vector/table.py @@ -134,8 +134,7 @@ def limit(self, number): """ if not isinstance(number, int): raise ValueError("Must be an integer.") - else: - self._limit = "LIMIT {number}".format(number=number) + self._limit = "LIMIT {number}".format(number=number) return self def group_by(self, *groupby): diff --git a/python/grass/script/task.py b/python/grass/script/task.py index 9867b3d8c49..758372938e3 100644 --- a/python/grass/script/task.py +++ b/python/grass/script/task.py @@ -153,8 +153,7 @@ def get_param(self, value, element="name", raiseError=True): _("Parameter element '%(element)s' not found: '%(value)s'") % {"element": element, "value": value} ) - else: - return None + return None def get_flag(self, aFlag): """Find and return a flag by name diff --git a/python/grass/temporal/temporal_algebra.py b/python/grass/temporal/temporal_algebra.py index 2429b61e35e..a27fa91cd1d 100644 --- a/python/grass/temporal/temporal_algebra.py +++ b/python/grass/temporal/temporal_algebra.py @@ -1156,11 +1156,7 @@ def set_temporal_extent_list(self, maplist, topolist=["EQUAL"], temporal="l"): if returncode == 0: break # Append map to result map list. - elif returncode == 1: - # print(map_new.get_id() + " " + - # str(map_new.get_temporal_extent_as_tuple())) - # print(map_new.condition_value) - # print(map_new.cmd_list) + if returncode == 1: # resultlist.append(map_new) resultdict[map_new.get_id()] = map_new @@ -1243,42 +1239,41 @@ def check_stds(self, input, clear=False, stds_type=None, check_type=True): _("Space time %s dataset <%s> not found") % (stds.get_new_map_instance(None).get_type(), id_input) ) + # Select temporal dataset entry from database. + stds.select(dbif=self.dbif) + if self.use_granularity: + # We create the maplist out of the map array from none-gap objects + maplist = [] + map_array = stds.get_registered_maps_as_objects_by_granularity( + gran=self.granularity, dbif=self.dbif + ) + for entry in map_array: + # Ignore gap objects + if entry[0].get_id() is not None: + maplist.append(entry[0]) else: - # Select temporal dataset entry from database. - stds.select(dbif=self.dbif) - if self.use_granularity: - # We create the maplist out of the map array from none-gap objects - maplist = [] - map_array = stds.get_registered_maps_as_objects_by_granularity( - gran=self.granularity, dbif=self.dbif - ) - for entry in map_array: - # Ignore gap objects - if entry[0].get_id() is not None: - maplist.append(entry[0]) - else: - maplist = stds.get_registered_maps_as_objects(dbif=self.dbif) - # Create map_value as empty list item. - for map_i in maplist: - if "map_value" not in dir(map_i): - map_i.map_value = [] - if "condition_value" not in dir(map_i): - map_i.condition_value = [] - # Set and check global temporal type variable and map. - if map_i.is_time_absolute() and self.temporaltype is None: - self.temporaltype = "absolute" - elif map_i.is_time_relative() and self.temporaltype is None: - self.temporaltype = "relative" - elif ( - map_i.is_time_absolute() and self.temporaltype == "relative" - ) or (map_i.is_time_relative() and self.temporaltype == "absolute"): - self.msgr.fatal( - _( - "Wrong temporal type of space time dataset " - "<%s> <%s> time is required" - ) - % (id_input, self.temporaltype) + maplist = stds.get_registered_maps_as_objects(dbif=self.dbif) + # Create map_value as empty list item. + for map_i in maplist: + if "map_value" not in dir(map_i): + map_i.map_value = [] + if "condition_value" not in dir(map_i): + map_i.condition_value = [] + # Set and check global temporal type variable and map. + if map_i.is_time_absolute() and self.temporaltype is None: + self.temporaltype = "absolute" + elif map_i.is_time_relative() and self.temporaltype is None: + self.temporaltype = "relative" + elif (map_i.is_time_absolute() and self.temporaltype == "relative") or ( + map_i.is_time_relative() and self.temporaltype == "absolute" + ): + self.msgr.fatal( + _( + "Wrong temporal type of space time dataset " + "<%s> <%s> time is required" ) + % (id_input, self.temporaltype) + ) elif isinstance(input, self.mapclass): # Check if the input is a single map and return it as list with one entry. maplist = [input] @@ -2637,9 +2632,9 @@ def p_expr_tmap_function(self, t): _("%s map <%s> not found in GRASS spatial database") % (map_i.get_type(), id_input) ) - else: - # Select dataset entry from database. - map_i.select(dbif=self.dbif) + + # Select dataset entry from database. + map_i.select(dbif=self.dbif) else: raise FatalError( _( @@ -3383,8 +3378,7 @@ def p_error(self, t): "syntax error on line %d, position %i token %s near '%s' expression " "'%s'" % (t.lineno, t.lexpos, t.type, t.value, self.expression) ) - else: - raise SyntaxError("Unexpected syntax error") + raise SyntaxError("Unexpected syntax error") if __name__ == "__main__": diff --git a/python/grass/temporal/temporal_operator.py b/python/grass/temporal/temporal_operator.py index 7d91ed0f65c..d99244c7c49 100644 --- a/python/grass/temporal/temporal_operator.py +++ b/python/grass/temporal/temporal_operator.py @@ -352,16 +352,16 @@ def p_relation_operator(self, t): # Check for correct type. if not self.optype == "relation": raise SyntaxError('Wrong optype "%s" must be "relation"' % self.optype) + + # Set three operator components. + if isinstance(t[2], list): + self.relations = t[2] else: - # Set three operator components. - if isinstance(t[2], list): - self.relations = t[2] - else: - self.relations = [t[2]] - self.temporal = None - self.function = None + self.relations = [t[2]] + self.temporal = None + self.function = None - t[0] = t[2] + t[0] = t[2] def p_relation_bool_operator(self, t): # {||, during} @@ -374,17 +374,17 @@ def p_relation_bool_operator(self, t): """ if not self.optype == "boolean": raise SyntaxError('Wrong optype "%s" must be "boolean"' % self.optype) + + # Set three operator components. + if isinstance(t[5], list): + self.relations = t[5] else: - # Set three operator components. - if isinstance(t[5], list): - self.relations = t[5] - else: - self.relations = [t[5]] - self.temporal = "l" - self.function = t[2] + t[3] - self.aggregate = t[2] + self.relations = [t[5]] + self.temporal = "l" + self.function = t[2] + t[3] + self.aggregate = t[2] - t[0] = t[2] + t[0] = t[2] def p_relation_bool_combi_operator(self, t): # {||, during, &} @@ -401,17 +401,17 @@ def p_relation_bool_combi_operator(self, t): """ if not self.optype == "boolean": raise SyntaxError('Wrong optype "%s" must be "boolean"' % self.optype) + + # Set three operator components. + if isinstance(t[5], list): + self.relations = t[5] else: - # Set three operator components. - if isinstance(t[5], list): - self.relations = t[5] - else: - self.relations = [t[5]] - self.temporal = "l" - self.function = t[2] + t[3] - self.aggregate = t[7] + self.relations = [t[5]] + self.temporal = "l" + self.function = t[2] + t[3] + self.aggregate = t[7] - t[0] = t[2] + t[0] = t[2] def p_relation_bool_combi_operator2(self, t): # {||, during, left} @@ -424,17 +424,17 @@ def p_relation_bool_combi_operator2(self, t): """ if not self.optype == "boolean": raise SyntaxError('Wrong optype "%s" must be "boolean"' % self.optype) + + # Set three operator components. + if isinstance(t[5], list): + self.relations = t[5] else: - # Set three operator components. - if isinstance(t[5], list): - self.relations = t[5] - else: - self.relations = [t[5]] - self.temporal = t[7] - self.function = t[2] + t[3] - self.aggregate = t[2] + self.relations = [t[5]] + self.temporal = t[7] + self.function = t[2] + t[3] + self.aggregate = t[2] - t[0] = t[2] + t[0] = t[2] def p_relation_bool_combi_operator3(self, t): # {||, during, |, left} @@ -451,17 +451,17 @@ def p_relation_bool_combi_operator3(self, t): """ if not self.optype == "boolean": raise SyntaxError('Wrong optype "%s" must be "relation"' % self.optype) + + # Set three operator components. + if isinstance(t[5], list): + self.relations = t[5] else: - # Set three operator components. - if isinstance(t[5], list): - self.relations = t[5] - else: - self.relations = [t[5]] - self.temporal = t[9] - self.function = t[2] + t[3] - self.aggregate = t[7] + self.relations = [t[5]] + self.temporal = t[9] + self.function = t[2] + t[3] + self.aggregate = t[7] - t[0] = t[2] + t[0] = t[2] def p_select_relation_operator(self, t): # {!:} @@ -477,27 +477,28 @@ def p_select_relation_operator(self, t): """ if not self.optype == "select": raise SyntaxError('Wrong optype "%s" must be "select"' % self.optype) - else: - if len(t) == 4: - # Set three operator components. - self.relations = ["equal", "equivalent"] - self.temporal = "l" - self.function = t[2] - elif len(t) == 6: - if isinstance(t[4], list): - self.relations = t[4] - else: - self.relations = [t[4]] - self.temporal = "l" - self.function = t[2] - elif len(t) == 8: - if isinstance(t[4], list): - self.relations = t[4] - else: - self.relations = [t[4]] - self.temporal = t[6] - self.function = t[2] - t[0] = t[2] + + if len(t) == 4: + # Set three operator components. + self.relations = ["equal", "equivalent"] + self.temporal = "l" + self.function = t[2] + elif len(t) == 6: + if isinstance(t[4], list): + self.relations = t[4] + else: + self.relations = [t[4]] + self.temporal = "l" + self.function = t[2] + elif len(t) == 8: + if isinstance(t[4], list): + self.relations = t[4] + else: + self.relations = [t[4]] + self.temporal = t[6] + self.function = t[2] + + t[0] = t[2] def p_hash_relation_operator(self, t): # {#} @@ -513,27 +514,28 @@ def p_hash_relation_operator(self, t): """ if not self.optype == "hash": raise SyntaxError('Wrong optype "%s" must be "hash"' % self.optype) - else: - if len(t) == 4: - # Set three operator components. - self.relations = ["equal"] - self.temporal = "l" - self.function = t[2] - elif len(t) == 6: - if isinstance(t[4], list): - self.relations = t[4] - else: - self.relations = [t[4]] - self.temporal = "l" - self.function = t[2] - elif len(t) == 8: - if isinstance(t[4], list): - self.relations = t[4] - else: - self.relations = [t[4]] - self.temporal = t[6] - self.function = t[2] - t[0] = t[2] + + if len(t) == 4: + # Set three operator components. + self.relations = ["equal"] + self.temporal = "l" + self.function = t[2] + elif len(t) == 6: + if isinstance(t[4], list): + self.relations = t[4] + else: + self.relations = [t[4]] + self.temporal = "l" + self.function = t[2] + elif len(t) == 8: + if isinstance(t[4], list): + self.relations = t[4] + else: + self.relations = [t[4]] + self.temporal = t[6] + self.function = t[2] + + t[0] = t[2] def p_raster_relation_operator(self, t): # {+} @@ -549,27 +551,28 @@ def p_raster_relation_operator(self, t): """ if not self.optype == "raster": raise SyntaxError('Wrong optype "%s" must be "raster"' % self.optype) - else: - if len(t) == 4: - # Set three operator components. - self.relations = ["equal"] - self.temporal = "l" - self.function = t[2] - elif len(t) == 6: - if isinstance(t[4], list): - self.relations = t[4] - else: - self.relations = [t[4]] - self.temporal = "l" - self.function = t[2] - elif len(t) == 8: - if isinstance(t[4], list): - self.relations = t[4] - else: - self.relations = [t[4]] - self.temporal = t[6] - self.function = t[2] - t[0] = t[2] + + if len(t) == 4: + # Set three operator components. + self.relations = ["equal"] + self.temporal = "l" + self.function = t[2] + elif len(t) == 6: + if isinstance(t[4], list): + self.relations = t[4] + else: + self.relations = [t[4]] + self.temporal = "l" + self.function = t[2] + elif len(t) == 8: + if isinstance(t[4], list): + self.relations = t[4] + else: + self.relations = [t[4]] + self.temporal = t[6] + self.function = t[2] + + t[0] = t[2] def p_overlay_relation_operator(self, t): # {+} @@ -585,27 +588,28 @@ def p_overlay_relation_operator(self, t): """ if not self.optype == "overlay": raise SyntaxError('Wrong optype "%s" must be "overlay"' % self.optype) - else: - if len(t) == 4: - # Set three operator components. - self.relations = ["equal"] - self.temporal = "l" - self.function = t[2] - elif len(t) == 6: - if isinstance(t[4], list): - self.relations = t[4] - else: - self.relations = [t[4]] - self.temporal = "l" - self.function = t[2] - elif len(t) == 8: - if isinstance(t[4], list): - self.relations = t[4] - else: - self.relations = [t[4]] - self.temporal = t[6] - self.function = t[2] - t[0] = t[2] + + if len(t) == 4: + # Set three operator components. + self.relations = ["equal"] + self.temporal = "l" + self.function = t[2] + elif len(t) == 6: + if isinstance(t[4], list): + self.relations = t[4] + else: + self.relations = [t[4]] + self.temporal = "l" + self.function = t[2] + elif len(t) == 8: + if isinstance(t[4], list): + self.relations = t[4] + else: + self.relations = [t[4]] + self.temporal = t[6] + self.function = t[2] + + t[0] = t[2] def p_relation(self, t): # The list of relations. Temporal and spatial relations are supported diff --git a/python/grass/temporal/temporal_raster_base_algebra.py b/python/grass/temporal/temporal_raster_base_algebra.py index cb2122f4a37..bb58c8405f7 100644 --- a/python/grass/temporal/temporal_raster_base_algebra.py +++ b/python/grass/temporal/temporal_raster_base_algebra.py @@ -610,7 +610,7 @@ def set_temporal_extent_list( if returncode == 0: break # Append map to result map list. - elif returncode == 1: + if returncode == 1: # print(map_new.cmd_list) # resultlist.append(map_new) if cmd_bool: @@ -969,12 +969,11 @@ def p_expr_spmap_function(self, t): _("%s map <%s> not found in GRASS spatial database") % (map_i.get_type(), id_input) ) - else: - # Select dataset entry from database. - map_i.select(dbif=self.dbif) - # Create command list for map object. - cmdstring = "(%s)" % (map_i.get_map_id()) - map_i.cmd_list = cmdstring + # Select dataset entry from database. + map_i.select(dbif=self.dbif) + # Create command list for map object. + cmdstring = "(%s)" % (map_i.get_map_id()) + map_i.cmd_list = cmdstring # Return map object. t[0] = cmdstring else: diff --git a/python/grass/temporal/temporal_vector_algebra.py b/python/grass/temporal/temporal_vector_algebra.py index 551c69783f5..2f28da0c7e5 100644 --- a/python/grass/temporal/temporal_vector_algebra.py +++ b/python/grass/temporal/temporal_vector_algebra.py @@ -386,7 +386,7 @@ def set_temporal_extent_list(self, maplist, topolist=["EQUAL"], temporal="l"): if returncode == 0: break # Append map to result map list. - elif returncode == 1: + if returncode == 1: # resultlist.append(map_new) resultdict[map_new.get_id()] = map_new if returncode == 0: diff --git a/scripts/db.in.ogr/db.in.ogr.py b/scripts/db.in.ogr/db.in.ogr.py index a95919f4936..b7d7b01b51e 100755 --- a/scripts/db.in.ogr/db.in.ogr.py +++ b/scripts/db.in.ogr/db.in.ogr.py @@ -115,8 +115,7 @@ def main(): "db.execute", input="-", stdin="DROP TABLE %s" % output ) break - else: - gs.fatal(_("Table <%s> already exists") % output) + gs.fatal(_("Table <%s> already exists") % output) # treat DB as real vector map... layer = db_table or None diff --git a/scripts/r.in.wms/wms_cap_parsers.py b/scripts/r.in.wms/wms_cap_parsers.py index 723a63f0b23..e9704651c7b 100644 --- a/scripts/r.in.wms/wms_cap_parsers.py +++ b/scripts/r.in.wms/wms_cap_parsers.py @@ -105,8 +105,7 @@ def __init__(self, cap_file, force_version=None): raise ParseError( _("Missing version attribute root node in Capabilities XML file") ) - else: - wms_version = self.getroot().attrib["version"] + wms_version = self.getroot().attrib["version"] if wms_version == "1.3.0": self.proj_tag = "CRS" diff --git a/scripts/r.in.wms/wms_drv.py b/scripts/r.in.wms/wms_drv.py index e1131918c4a..e825aabe438 100644 --- a/scripts/r.in.wms/wms_drv.py +++ b/scripts/r.in.wms/wms_drv.py @@ -155,8 +155,7 @@ def _download(self): sleep(sleep_time) continue - else: - gs.fatal(_("Unable to write data into tempfile.\n%s") % str(e)) + gs.fatal(_("Unable to write data into tempfile.\n%s") % str(e)) finally: temp_tile_opened.close() diff --git a/scripts/v.what.strds/v.what.strds.py b/scripts/v.what.strds/v.what.strds.py index 8be00f3536d..2c819fd0e44 100644 --- a/scripts/v.what.strds/v.what.strds.py +++ b/scripts/v.what.strds/v.what.strds.py @@ -202,8 +202,7 @@ def main(): if name is None: isvalid = False break - else: - mapname_list.append(name) + mapname_list.append(name) if isvalid: entry = mapmatrizes[0][i] diff --git a/temporal/t.vect.observe.strds/t.vect.observe.strds.py b/temporal/t.vect.observe.strds/t.vect.observe.strds.py index 547f60a3250..7e9ac225890 100755 --- a/temporal/t.vect.observe.strds/t.vect.observe.strds.py +++ b/temporal/t.vect.observe.strds/t.vect.observe.strds.py @@ -185,8 +185,7 @@ def main(): if name is None: isvalid = False break - else: - mapname_list.append(name) + mapname_list.append(name) if isvalid: entry = mapmatrizes[0][i] From ffcb9e1621579bbfbf56e5417cb7946b4d2fe9cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Sun, 27 Oct 2024 09:56:30 -0400 Subject: [PATCH 30/55] temporal: Add precise typing overloads to dataset_factory (#4600) * temporal: Add precise typing overloads to dataset_factory This enables type checkers like mypy or Pyright to understand the returned class from the string passed as the type argument * temporal: Add typing overloads to dataset_factory * temporal: Add dataset_factory implementation with str type for type argument * temporal: Remove dataset_factory overload that listed all literal types * temporal: Update dataset_factory file header * temporal: Add dataset_factory overload with str type for type argument * temporal: Accept None for id argument in dataset_factory overload as used in existing calls --- python/grass/temporal/factory.py | 109 +++++++++++++++++++++++-------- 1 file changed, 80 insertions(+), 29 deletions(-) diff --git a/python/grass/temporal/factory.py b/python/grass/temporal/factory.py index ba7f5e7d4f0..f246700ef44 100644 --- a/python/grass/temporal/factory.py +++ b/python/grass/temporal/factory.py @@ -1,23 +1,18 @@ """ Object factory -Usage: - -.. code-block:: python - - import grass.temporal as tgis - - tgis.register_maps_in_space_time_dataset(type, name, maps) - - -(C) 2012-2013 by the GRASS Development Team +(C) 2012-2024 by the GRASS Development Team This program is free software under the GNU General Public License (>=v2). Read the file COPYING that comes with GRASS for details. -:authors: Soeren Gebbert +:authors: Soeren Gebbert, Edouard Choinière """ +from __future__ import annotations + +from typing import Literal, overload + from .core import get_tgis_message_interface from .space_time_datasets import ( Raster3DDataset, @@ -31,7 +26,65 @@ ############################################################################### -def dataset_factory(type, id): +@overload +def dataset_factory(type: Literal["strds"], id: str) -> SpaceTimeRasterDataset: + pass + + +@overload +def dataset_factory(type: Literal["str3ds"], id: str) -> SpaceTimeRaster3DDataset: + pass + + +@overload +def dataset_factory(type: Literal["stvds"], id: str) -> SpaceTimeVectorDataset: + pass + + +@overload +def dataset_factory(type: Literal["rast", "raster"], id: str) -> RasterDataset: + pass + + +@overload +def dataset_factory( + type: Literal["raster_3d", "rast3d", "raster3d"], + id: str, +) -> Raster3DDataset: + pass + + +@overload +def dataset_factory(type: Literal["vect", "vector"], id: str) -> VectorDataset: + pass + + +@overload +def dataset_factory( + type: str, id: str +) -> ( + SpaceTimeRasterDataset + | SpaceTimeRaster3DDataset + | SpaceTimeVectorDataset + | RasterDataset + | Raster3DDataset + | VectorDataset + | None +): + pass + + +def dataset_factory( + type: str, id: str | None +) -> ( + SpaceTimeRasterDataset + | SpaceTimeRaster3DDataset + | SpaceTimeVectorDataset + | RasterDataset + | Raster3DDataset + | VectorDataset + | None +): """A factory functions to create space time or map datasets :param type: the dataset type: rast or raster; rast3d, raster3d or raster_3d; @@ -39,20 +92,18 @@ def dataset_factory(type, id): :param id: The id of the dataset ("name@mapset") """ if type == "strds": - sp = SpaceTimeRasterDataset(id) - elif type == "str3ds": - sp = SpaceTimeRaster3DDataset(id) - elif type == "stvds": - sp = SpaceTimeVectorDataset(id) - elif type in {"rast", "raster"}: - sp = RasterDataset(id) - elif type in {"raster_3d", "rast3d", "raster3d"}: - sp = Raster3DDataset(id) - elif type in {"vect", "vector"}: - sp = VectorDataset(id) - else: - msgr = get_tgis_message_interface() - msgr.error(_("Unknown dataset type: %s") % type) - return None - - return sp + return SpaceTimeRasterDataset(id) + if type == "str3ds": + return SpaceTimeRaster3DDataset(id) + if type == "stvds": + return SpaceTimeVectorDataset(id) + if type in {"rast", "raster"}: + return RasterDataset(id) + if type in {"raster_3d", "rast3d", "raster3d"}: + return Raster3DDataset(id) + if type in {"vect", "vector"}: + return VectorDataset(id) + + msgr = get_tgis_message_interface() + msgr.error(_("Unknown dataset type: %s") % type) + return None From 84afcf47aaf49dcea2eaec1c0d93143a2b7dc069 Mon Sep 17 00:00:00 2001 From: ShubhamDesai <42180509+ShubhamDesai@users.noreply.github.com> Date: Sun, 27 Oct 2024 17:35:45 -0400 Subject: [PATCH 31/55] r.in.poly: Fix Resource Leak issue in poly2rast.c (#4605) --- raster/r.in.poly/poly2rast.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/raster/r.in.poly/poly2rast.c b/raster/r.in.poly/poly2rast.c index e81d6f421a3..bb707d03e25 100644 --- a/raster/r.in.poly/poly2rast.c +++ b/raster/r.in.poly/poly2rast.c @@ -90,6 +90,7 @@ int poly_to_rast(char *input_file, char *raster_map, char *title, int nrows, if (stat < 0) { Rast_unopen(rfd); + fclose(ifd); return 1; } @@ -98,6 +99,7 @@ int poly_to_rast(char *input_file, char *raster_map, char *title, int nrows, Rast_short_history(raster_map, "raster", &history); Rast_command_history(&history); Rast_write_history(raster_map, &history); + fclose(ifd); return 0; } From 937b2f48d024e9913e5be37dc0b829f1e037160c Mon Sep 17 00:00:00 2001 From: ShubhamDesai <42180509+ShubhamDesai@users.noreply.github.com> Date: Sun, 27 Oct 2024 17:38:58 -0400 Subject: [PATCH 32/55] lib/gis: Fix resource leak issue in copy_dir.c (#4606) --- lib/gis/copy_dir.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/gis/copy_dir.c b/lib/gis/copy_dir.c index 226e25a5a39..8babbc2e964 100644 --- a/lib/gis/copy_dir.c +++ b/lib/gis/copy_dir.c @@ -141,8 +141,10 @@ int G_recursive_copy(const char *src, const char *dst) sprintf(path, "%s/%s", src, dp->d_name); sprintf(path2, "%s/%s", dst, dp->d_name); - if (G_recursive_copy(path, path2) != 0) + if (G_recursive_copy(path, path2) != 0) { + closedir(dirp); return 1; + } } closedir(dirp); From 7d101ed70a6cc87d5f40850ece3184b04d89ee95 Mon Sep 17 00:00:00 2001 From: ShubhamDesai <42180509+ShubhamDesai@users.noreply.github.com> Date: Mon, 28 Oct 2024 04:34:49 -0400 Subject: [PATCH 33/55] r.watershed: Fix Resource Leak issues in close_maps.c (#4607) --- raster/r.watershed/seg/close_maps.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/raster/r.watershed/seg/close_maps.c b/raster/r.watershed/seg/close_maps.c index 1669bbd89c3..56320428c32 100644 --- a/raster/r.watershed/seg/close_maps.c +++ b/raster/r.watershed/seg/close_maps.c @@ -325,6 +325,8 @@ int close_maps(void) } Rast_close(fd); + G_free(afbuf); + G_free(cbuf); Rast_init_colors(&colors); Rast_make_aspect_colors(&colors, -8, 8); From 24469d8dcb73fdcec1c59713de4a8c82ce3eea3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hern=C3=A1n=20De=20Angelis?= <51515911+dhdeangelis@users.noreply.github.com> Date: Mon, 28 Oct 2024 11:16:17 +0100 Subject: [PATCH 34/55] docs: v.build manual typo fix (#4604) --- vector/v.build/v.build.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/vector/v.build/v.build.html b/vector/v.build/v.build.html index 9f51afdb22b..c66da69110a 100644 --- a/vector/v.build/v.build.html +++ b/vector/v.build/v.build.html @@ -27,7 +27,7 @@

    NOTES

    If error vector map is specified, v.build checks:
      -
    • isolated bondaries (which are not forming any areas),
    • +
    • isolated boundaries (which are not forming any areas),
    • centroids outside of area,
    • duplicated centroids.
    @@ -38,7 +38,7 @@

    NOTES

    • lines or boundaries of zero length,
    • -
    • intersecting boundaries, ie. overlapping areas,
    • +
    • intersecting boundaries, i.e. overlapping areas,
    • areas without centroids that are not isles.
    @@ -46,7 +46,7 @@

    EXAMPLES

    Build topology

    -Note that option=build recreates also spatial and category +Note that option=build also recreates spatial and category indices, not only topology. For linked OGR layers (see v.external) also feature index is created. @@ -61,7 +61,7 @@

    Build topology

    Dump topology or indices

    Dump options print topology, spatial, category or feature index to -standard output. Such information can be printed also for vector maps +standard output. Such information can also be printed for vector maps from other mapsets. A description of the vector topology is available in the GRASS GIS 8 Programmer's Manual, section "Vector library topology management". From 6bceb98965a00957beb64fb1d05e29a96e0f87b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hern=C3=A1n=20De=20Angelis?= <51515911+dhdeangelis@users.noreply.github.com> Date: Mon, 28 Oct 2024 15:03:35 +0100 Subject: [PATCH 35/55] docs: v.outlier.html fix typos (#4610) --- vector/v.outlier/v.outlier.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vector/v.outlier/v.outlier.html b/vector/v.outlier/v.outlier.html index 3cd3ee46a5a..7e615364916 100644 --- a/vector/v.outlier/v.outlier.html +++ b/vector/v.outlier/v.outlier.html @@ -13,12 +13,12 @@

    DESCRIPTION

    (default), or only positive or only negative outliers. Filtering out only positive outliers can be useful to filter out vegetation returns (e.g. from forest canopies) from LIDAR point clouds, in order to -extract Digital Terrain Models. Filtering out only negative outliers +extract digital terrain models (DTMs). Filtering out only negative outliers can be useful to estimate vegetation height.

    -There is a flag to create a vector that can be visualizated by -qgis. That means that topology is build and the z coordinate is +There is a flag to create a vector that can be visualized in +QGIS. That means that topology is built and the z coordinate is considered as a category.

    EXAMPLES

    From b9a543a6233c186840d941d1bd600c7886409948 Mon Sep 17 00:00:00 2001 From: Arohan Ajit Date: Mon, 28 Oct 2024 10:09:56 -0400 Subject: [PATCH 36/55] i.pansharpen: Fixed bare except clause (#4596) --- .flake8 | 2 +- scripts/i.pansharpen/i.pansharpen.py | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.flake8 b/.flake8 index c29f447c597..e3b2ecf8251 100644 --- a/.flake8 +++ b/.flake8 @@ -100,7 +100,7 @@ per-file-ignores = scripts/v.import/v.import.py: E722, E501 scripts/db.univar/db.univar.py: E501 scripts/d.frame/d.frame.py: E722 - scripts/i.pansharpen/i.pansharpen.py: E722, E501 + scripts/i.pansharpen/i.pansharpen.py: E501 scripts/v.what.strds/v.what.strds.py: E501 # Line too long (esp. module interface definitions) scripts/*/*.py: E501 diff --git a/scripts/i.pansharpen/i.pansharpen.py b/scripts/i.pansharpen/i.pansharpen.py index e78581c8845..730701bfb91 100755 --- a/scripts/i.pansharpen/i.pansharpen.py +++ b/scripts/i.pansharpen/i.pansharpen.py @@ -93,6 +93,7 @@ # %end import os +from grass.exceptions import CalledModuleError try: import numpy as np @@ -458,7 +459,7 @@ def main(): gs.run_command( "g.remove", flags="f", type="raster", pattern="tmp%s*" % pid, quiet=True ) - except: + except CalledModuleError: pass @@ -523,7 +524,7 @@ def brovey(pan, ms1, ms2, ms3, out, pid, sproc): pb.wait(), pg.wait(), pr.wait() try: pb.terminate(), pg.terminate(), pr.terminate() - except: + except OSError: pass # Cleanup @@ -535,7 +536,7 @@ def brovey(pan, ms1, ms2, ms3, out, pid, sproc): type="raster", name="%s,%s,%s" % (panmatch1, panmatch2, panmatch3), ) - except: + except CalledModuleError: pass @@ -575,7 +576,7 @@ def ihs(pan, ms1, ms2, ms3, out, pid, sproc): # Cleanup try: gs.run_command("g.remove", flags="f", quiet=True, type="raster", name=panmatch) - except: + except CalledModuleError: pass @@ -701,7 +702,7 @@ def pca(pan, ms1, ms2, ms3, out, pid, sproc): pb.wait(), pg.wait(), pr.wait() try: pb.terminate(), pg.terminate(), pr.terminate() - except: + except OSError: pass # Cleanup From 94034a3adb01bd8bd415da452f7235b58e1b6a2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hern=C3=A1n=20De=20Angelis?= <51515911+dhdeangelis@users.noreply.github.com> Date: Tue, 29 Oct 2024 15:20:56 +0100 Subject: [PATCH 37/55] docs: v.to.db.html fix manual typo (#4615) --- vector/v.to.db/v.to.db.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vector/v.to.db/v.to.db.html b/vector/v.to.db/v.to.db.html index 99c2d5b3dbc..f0ba460d450 100644 --- a/vector/v.to.db/v.to.db.html +++ b/vector/v.to.db/v.to.db.html @@ -25,7 +25,7 @@

    NOTES

    all features of same category taken together.

    Line azimuth is calculated as angle from the North direction to the line endnode direction at the line statnode. By default it's reported in decimal degrees (0-360, CW) but -it also may be repored in radians with unit=radians. Azimuth value +it also may be reported in radians with unit=radians. Azimuth value -1 is used to report closed line with it's startnode and endnode being in same place. Azimuth values make sense only if every vector line has only one entry in database (unique CAT value). @@ -165,4 +165,4 @@

    SEE ALSO

    AUTHORS

    Radim Blazek, ITC-irst, Trento, Italy
    -Line sinuousity implemented by Wolf Bergenheim +Line sinuosity implemented by Wolf Bergenheim From ba809db39314aee6e59de23ed3615ea9daedfc23 Mon Sep 17 00:00:00 2001 From: Anna Petrasova Date: Tue, 29 Oct 2024 10:41:47 -0400 Subject: [PATCH 38/55] wxGUI/nviz: fix missing imports (#4611) --- gui/wxpython/nviz/wxnviz.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/gui/wxpython/nviz/wxnviz.py b/gui/wxpython/nviz/wxnviz.py index 32c2541f14e..d11e03d290b 100644 --- a/gui/wxpython/nviz/wxnviz.py +++ b/gui/wxpython/nviz/wxnviz.py @@ -158,6 +158,11 @@ CONST_ATT, DM_FLAT, DM_GOURAUD, + DM_GRID_SURF, + DM_GRID_WIRE, + DM_POLY, + DM_WIRE, + DM_WIRE_POLY, MAP_ATT, MAX_ISOSURFS, GP_delete_site, @@ -2442,6 +2447,11 @@ def Corresponds(self, item): __all__ = [ "DM_FLAT", "DM_GOURAUD", + "DM_GRID_SURF", + "DM_GRID_WIRE", + "DM_POLY", + "DM_WIRE", + "DM_WIRE_POLY", "DRAW_QUICK_SURFACE", "DRAW_QUICK_VLINES", "DRAW_QUICK_VOLUME", From e6fd11079b82d38745f875301c022914e0474887 Mon Sep 17 00:00:00 2001 From: Arohan Ajit Date: Tue, 29 Oct 2024 11:29:11 -0400 Subject: [PATCH 39/55] d.frame: Fix bare except clause (#4597) --- .flake8 | 1 - scripts/d.frame/d.frame.py | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.flake8 b/.flake8 index e3b2ecf8251..075fb37d075 100644 --- a/.flake8 +++ b/.flake8 @@ -99,7 +99,6 @@ per-file-ignores = scripts/v.unpack/v.unpack.py: E722, E501 scripts/v.import/v.import.py: E722, E501 scripts/db.univar/db.univar.py: E501 - scripts/d.frame/d.frame.py: E722 scripts/i.pansharpen/i.pansharpen.py: E501 scripts/v.what.strds/v.what.strds.py: E501 # Line too long (esp. module interface definitions) diff --git a/scripts/d.frame/d.frame.py b/scripts/d.frame/d.frame.py index ff77316f0ec..165dd712648 100755 --- a/scripts/d.frame/d.frame.py +++ b/scripts/d.frame/d.frame.py @@ -206,7 +206,7 @@ def calculate_frame(frame, at, width, height): """ try: b, t, l, r = list(map(float, at.split(","))) - except: + except ValueError: fatal(_("Invalid frame position: %s") % at) top = round(height - (t / 100.0 * height)) @@ -238,7 +238,7 @@ def create_frame(monitor, frame, at, overwrite=False): width = int(line.split("=", 1)[1].rsplit(" ", 1)[0]) elif "HEIGHT" in line: height = int(line.split("=", 1)[1].rsplit(" ", 1)[0]) - except: + except (ValueError, IndexError): pass if width < 0 or height < 0: From 6e5643d2b91372acc1a0106400670b61b41f1eb9 Mon Sep 17 00:00:00 2001 From: Arohan Ajit Date: Tue, 29 Oct 2024 14:03:17 -0400 Subject: [PATCH 40/55] v.import: Fixed E722 bare except (#4614) --- .flake8 | 2 +- scripts/v.import/v.import.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.flake8 b/.flake8 index 075fb37d075..21272791e52 100644 --- a/.flake8 +++ b/.flake8 @@ -97,7 +97,7 @@ per-file-ignores = scripts/db.out.ogr/db.out.ogr.py: F841 scripts/g.extension/g.extension.py: F841, E722, E501 scripts/v.unpack/v.unpack.py: E722, E501 - scripts/v.import/v.import.py: E722, E501 + scripts/v.import/v.import.py: E501 scripts/db.univar/db.univar.py: E501 scripts/i.pansharpen/i.pansharpen.py: E501 scripts/v.what.strds/v.what.strds.py: E501 diff --git a/scripts/v.import/v.import.py b/scripts/v.import/v.import.py index 4f579c4bf45..1e467cd190b 100755 --- a/scripts/v.import/v.import.py +++ b/scripts/v.import/v.import.py @@ -263,7 +263,7 @@ def main(): if OGRdatasource.lower().endswith("gml"): try: from osgeo import gdal - except: + except ImportError: gs.fatal( _( "Unable to load GDAL Python bindings (requires package " @@ -338,7 +338,7 @@ def main(): if OGRdatasource.lower().endswith("gml"): try: from osgeo import gdal - except: + except ImportError: gs.fatal( _( "Unable to load GDAL Python bindings (requires package " From 86497131a7d1999936d380d1f57870e87690b9db Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 29 Oct 2024 21:02:19 +0000 Subject: [PATCH 41/55] CI(deps): Lock file maintenance (#4564) --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index eacc92d3c4f..c507c1ec951 100644 --- a/flake.lock +++ b/flake.lock @@ -19,11 +19,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1728538411, - "narHash": "sha256-f0SBJz1eZ2yOuKUr5CA9BHULGXVSn6miBuUWdTyhUhU=", + "lastModified": 1730045389, + "narHash": "sha256-4spSNTZ6h8Xmvrr9oqfuxc9jarasGj1QOcsgw8BfNd8=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "b69de56fac8c2b6f8fd27f2eca01dcda8e0a4221", + "rev": "0fcb98acb6633445764dafe180e6833eb0f95208", "type": "github" }, "original": { From 9be02eeba6bfd198acb46aacf522f676fcd90fa2 Mon Sep 17 00:00:00 2001 From: Arohan Ajit Date: Wed, 30 Oct 2024 16:55:17 -0400 Subject: [PATCH 42/55] v.unpack: Fixed bare 'except' (#4616) * updated E722 * updated .flake8 * Update v.unpack.py --- .flake8 | 4 ++-- scripts/v.unpack/v.unpack.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.flake8 b/.flake8 index 21272791e52..4bc6b924620 100644 --- a/.flake8 +++ b/.flake8 @@ -95,8 +95,8 @@ per-file-ignores = scripts/r.semantic.label/r.semantic.label.py: E501 scripts/v.report/v.report.py: E721 scripts/db.out.ogr/db.out.ogr.py: F841 - scripts/g.extension/g.extension.py: F841, E722, E501 - scripts/v.unpack/v.unpack.py: E722, E501 + scripts/g.extension/g.extension.py: E501 + scripts/v.unpack/v.unpack.py: E501 scripts/v.import/v.import.py: E501 scripts/db.univar/db.univar.py: E501 scripts/i.pansharpen/i.pansharpen.py: E501 diff --git a/scripts/v.unpack/v.unpack.py b/scripts/v.unpack/v.unpack.py index c3a7a55deb7..7baa1042ccd 100644 --- a/scripts/v.unpack/v.unpack.py +++ b/scripts/v.unpack/v.unpack.py @@ -77,7 +77,7 @@ def main(): tar = tarfile.TarFile.open(name=input_base, mode="r") try: data_name = tar.getnames()[0] - except: + except IndexError: grass.fatal(_("Pack file unreadable")) if flags["p"]: From 9581ca185bf001301f3907fd3f1ca6da09e9e287 Mon Sep 17 00:00:00 2001 From: Arohan Ajit Date: Wed, 30 Oct 2024 17:14:00 -0400 Subject: [PATCH 43/55] wxGUI: Fixed bare 'except' in nviz/ (#4613) * updated E722 * updates * updates --------- Co-authored-by: Anna Petrasova --- .flake8 | 1 - gui/wxpython/nviz/mapwindow.py | 2 +- gui/wxpython/nviz/tools.py | 62 ++++++++++------------------------ 3 files changed, 19 insertions(+), 46 deletions(-) diff --git a/.flake8 b/.flake8 index 4bc6b924620..f0ac4155990 100644 --- a/.flake8 +++ b/.flake8 @@ -23,7 +23,6 @@ per-file-ignores = doc/python/m.distance.py: E501 gui/scripts/d.wms.py: E501 gui/wxpython/image2target/g.gui.image2target.py: E501 - gui/wxpython/nviz/*: E722 gui/wxpython/photo2image/g.gui.photo2image.py: E501 gui/wxpython/psmap/*: E501, E722 gui/wxpython/vdigit/*: F841, E722, F405, F403 diff --git a/gui/wxpython/nviz/mapwindow.py b/gui/wxpython/nviz/mapwindow.py index d3f93f94938..b6609427895 100644 --- a/gui/wxpython/nviz/mapwindow.py +++ b/gui/wxpython/nviz/mapwindow.py @@ -1390,7 +1390,7 @@ def LoadDataLayers(self): GError(parent=self, message=e.value) # when nviz.tools is not yet ready # during opening 3D view 2nd time - except: + except Exception: pass stop = gs.clock() diff --git a/gui/wxpython/nviz/tools.py b/gui/wxpython/nviz/tools.py index dce751e6b27..77f379ef019 100644 --- a/gui/wxpython/nviz/tools.py +++ b/gui/wxpython/nviz/tools.py @@ -160,7 +160,7 @@ def SetInitialMaps(self): else: try: selection = layers[0].GetName() - except: + except (AttributeError, IndexError): continue if ltype == "raster": self.FindWindowById(self.win["surface"]["map"]).SetValue(selection) @@ -734,24 +734,11 @@ def _createDataPage(self): self.mainPanelData = SP.ScrolledPanel(parent=self) self.mainPanelData.SetupScrolling(scroll_x=False) self.mainPanelData.AlwaysShowScrollbars(hflag=False) - try: # wxpython <= 2.8.10 - self.foldpanelData = fpb.FoldPanelBar( - parent=self.mainPanelData, - id=wx.ID_ANY, - style=fpb.FPB_DEFAULT_STYLE, - extraStyle=fpb.FPB_SINGLE_FOLD, - ) - except: - try: # wxpython >= 2.8.11 - self.foldpanelData = fpb.FoldPanelBar( - parent=self.mainPanelData, - id=wx.ID_ANY, - agwStyle=fpb.FPB_SINGLE_FOLD, - ) - except: # to be sure - self.foldpanelData = fpb.FoldPanelBar( - parent=self.mainPanelData, id=wx.ID_ANY, style=fpb.FPB_SINGLE_FOLD - ) + self.foldpanelData = fpb.FoldPanelBar( + parent=self.mainPanelData, + id=wx.ID_ANY, + agwStyle=fpb.FPB_SINGLE_FOLD, + ) self.foldpanelData.Bind(fpb.EVT_CAPTIONBAR, self.OnPressCaption) @@ -814,24 +801,11 @@ def _createAppearancePage(self): self.mainPanelAppear = SP.ScrolledPanel(parent=self) self.mainPanelAppear.SetupScrolling(scroll_x=False) self.mainPanelAppear.AlwaysShowScrollbars(hflag=False) - try: # wxpython <= 2.8.10 - self.foldpanelAppear = fpb.FoldPanelBar( - parent=self.mainPanelAppear, - id=wx.ID_ANY, - style=fpb.FPB_DEFAULT_STYLE, - extraStyle=fpb.FPB_SINGLE_FOLD, - ) - except: - try: # wxpython >= 2.8.11 - self.foldpanelAppear = fpb.FoldPanelBar( - parent=self.mainPanelAppear, - id=wx.ID_ANY, - agwStyle=fpb.FPB_SINGLE_FOLD, - ) - except: # to be sure - self.foldpanelAppear = fpb.FoldPanelBar( - parent=self.mainPanelAppear, id=wx.ID_ANY, style=fpb.FPB_SINGLE_FOLD - ) + self.foldpanelAppear = fpb.FoldPanelBar( + parent=self.mainPanelAppear, + id=wx.ID_ANY, + agwStyle=fpb.FPB_SINGLE_FOLD, + ) self.foldpanelAppear.Bind(fpb.EVT_CAPTIONBAR, self.OnPressCaption) # light page @@ -3360,7 +3334,7 @@ def OnSetSurface(self, event): name = event.GetString() try: self._getLayerPropertiesByName(name, mapType="raster")["surface"] - except: + except (AttributeError, TypeError, KeyError): self.EnablePage("fringe", False) return @@ -3384,7 +3358,7 @@ def OnSetVector(self, event): name = event.GetString() try: data = self._getLayerPropertiesByName(name, mapType="vector")["vector"] - except: + except (AttributeError, TypeError, KeyError): self.EnablePage("vector", False) return layer = self._getMapLayerByName(name, mapType="vector") @@ -3396,7 +3370,7 @@ def OnSetRaster3D(self, event): name = event.GetString() try: data = self._getLayerPropertiesByName(name, mapType="raster_3d")["volume"] - except: + except (AttributeError, TypeError, KeyError): self.EnablePage("volume", False) return @@ -4925,7 +4899,7 @@ def OnCPlaneSelection(self, event): try: planeIndex = int(plane.split()[-1]) - 1 self.EnablePage("cplane", enabled=True) - except: + except (ValueError, IndexError): planeIndex = -1 self.EnablePage("cplane", enabled=False) self.mapWindow.SelectCPlane(planeIndex) @@ -4942,7 +4916,7 @@ def OnCPlaneChanging(self, event): plane = self.FindWindowById(self.win["cplane"]["planes"]).GetStringSelection() try: planeIndex = int(plane.split()[-1]) - 1 - except: # TODO disabled page + except (ValueError, IndexError): # TODO disabled page planeIndex = -1 if event.GetId() in ( @@ -4984,7 +4958,7 @@ def OnCPlaneShading(self, event): plane = self.FindWindowById(self.win["cplane"]["planes"]).GetStringSelection() try: planeIndex = int(plane.split()[-1]) - 1 - except: # TODO disabled page + except (ValueError, IndexError): # TODO disabled page planeIndex = -1 self.mapWindow.cplanes[planeIndex]["shading"] = shading @@ -4999,7 +4973,7 @@ def OnCPlaneReset(self, event): plane = self.FindWindowById(self.win["cplane"]["planes"]).GetStringSelection() try: planeIndex = int(plane.split()[-1]) - 1 - except: # TODO disabled page + except (ValueError, IndexError): # TODO disabled page planeIndex = -1 self.mapWindow.cplanes[planeIndex] = copy.deepcopy( From 528763fb33ed7c696ea7fa19505b5d9ad02fb62e Mon Sep 17 00:00:00 2001 From: ShubhamDesai <42180509+ShubhamDesai@users.noreply.github.com> Date: Wed, 30 Oct 2024 17:28:17 -0400 Subject: [PATCH 44/55] lib/ogsf: Dereference after null check in gvl2.c (#4588) Dereference after null check --- lib/ogsf/gvl2.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/ogsf/gvl2.c b/lib/ogsf/gvl2.c index 473d3e9406e..2c861c4b5ad 100644 --- a/lib/ogsf/gvl2.c +++ b/lib/ogsf/gvl2.c @@ -316,10 +316,16 @@ void GVL_get_dims(int id, int *rows, int *cols, int *depths) *rows = gvl->rows; *cols = gvl->cols; *depths = gvl->depths; - } - G_debug(3, "GVL_get_dims() id=%d, rows=%d, cols=%d, depths=%d", - gvl->gvol_id, gvl->rows, gvl->cols, gvl->depths); + G_debug(3, "GVL_get_dims() id=%d, rows=%d, cols=%d, depths=%d", + gvl->gvol_id, gvl->rows, gvl->cols, gvl->depths); + } + else { + G_debug(2, + "GVL_get_dims(): Attempted to access a null volume structure " + "for id=%d", + id); + } return; } From 00f51c9e7c22b9643de2b472bc4f6ef4296ceb90 Mon Sep 17 00:00:00 2001 From: Arohan Ajit Date: Thu, 31 Oct 2024 11:27:33 -0400 Subject: [PATCH 45/55] v.report: Updated instance checks (#4618) --- .flake8 | 1 - scripts/v.report/v.report.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.flake8 b/.flake8 index f0ac4155990..3adda73f281 100644 --- a/.flake8 +++ b/.flake8 @@ -92,7 +92,6 @@ per-file-ignores = scripts/r.in.wms/wms_drv.py: E402, E722 scripts/r.in.wms/srs.py: E722 scripts/r.semantic.label/r.semantic.label.py: E501 - scripts/v.report/v.report.py: E721 scripts/db.out.ogr/db.out.ogr.py: F841 scripts/g.extension/g.extension.py: E501 scripts/v.unpack/v.unpack.py: E501 diff --git a/scripts/v.report/v.report.py b/scripts/v.report/v.report.py index 29d9d3c914e..80e9e8a1189 100755 --- a/scripts/v.report/v.report.py +++ b/scripts/v.report/v.report.py @@ -224,7 +224,7 @@ def main(): # calculate percentages records4 = [float(r[-1]) * 100 / total for r in records3] - if type(records1[0]) == int: + if isinstance(records1[0], int): records3 = [[r1] + [r4] for r1, r4 in zip(records1, records4)] else: records3 = [r1 + [r4] for r1, r4 in zip(records1, records4)] From ba0a4951958b20b0c1fca339c4fa92714095bacc Mon Sep 17 00:00:00 2001 From: Vaclav Petras Date: Thu, 31 Oct 2024 12:49:36 -0400 Subject: [PATCH 46/55] r.mask.status: Always output name of the mask (#4531) For both active and inactive raster mask, show the name of the raster which is used (or would be used) for the mask. This will allow tools like r.mask or GUI to do lower-level operations with or around mask without a need to know about defaults or user mechanism to change the name. I'm repurposing the existing 'name' (full_name) key which is now always set (as opposed to being null when no mask is present) as the 'present' boolean key already has the information on the mask presence. I'm renaming full_name to name because that creates a simpler interface (which is whole point of outputting full name as opposed to two keys to get name and mapset). --- include/grass/defs/raster.h | 1 + lib/raster/mask_info.c | 21 ++++++++++++ raster/r.mask.status/main.c | 34 +++++++------------ raster/r.mask.status/r.mask.status.html | 20 ++++++++--- .../r.mask.status/tests/r_mask_status_test.py | 23 +++++++------ 5 files changed, 63 insertions(+), 36 deletions(-) diff --git a/include/grass/defs/raster.h b/include/grass/defs/raster.h index 7f358562c72..bbdc8bfeaa1 100644 --- a/include/grass/defs/raster.h +++ b/include/grass/defs/raster.h @@ -392,6 +392,7 @@ int Rast_option_to_interp_type(const struct Option *); /* mask_info.c */ char *Rast_mask_info(void); +char *Rast_mask_name(void); bool Rast_mask_status(char *, char *, bool *, char *, char *); int Rast__mask_info(char *, char *); bool Rast_mask_is_present(void); diff --git a/lib/raster/mask_info.c b/lib/raster/mask_info.c index 317bab75b63..25d61341ebe 100644 --- a/lib/raster/mask_info.c +++ b/lib/raster/mask_info.c @@ -49,6 +49,27 @@ char *Rast_mask_info(void) return G_store(text); } +/** + * @brief Retrieves the name of the raster mask to use. + * + * The returned raster map name is fully qualified, i.e., in the form + % "name@mapset". + * + * The mask name is "MASK@", where is the current + * mapset. + * + * The memory for the returned mask name is dynamically allocated using + * G_store(). It is the caller's responsibility to free the memory with + * G_free() when it is no longer needed. + * + * @returns A dynamically allocated string containing the mask name. + */ +char *Rast_mask_name(void) +{ + // Mask name is always "MASK@". + return G_fully_qualified_name("MASK", G_mapset()); +} + /** * @brief Get raster mask status information * diff --git a/raster/r.mask.status/main.c b/raster/r.mask.status/main.c index 16790adf35c..b0a7b9185c0 100644 --- a/raster/r.mask.status/main.c +++ b/raster/r.mask.status/main.c @@ -89,7 +89,7 @@ int report_status(struct Parameters *params) } // Mask raster - char *full_mask = G_fully_qualified_name(name, mapset); + char *full_mask = Rast_mask_name(); // Underlying raster if applicable char *full_underlying = NULL; if (is_mask_reclass) @@ -99,10 +99,7 @@ int report_status(struct Parameters *params) JSON_Value *root_value = json_value_init_object(); JSON_Object *root_object = json_object(root_value); json_object_set_boolean(root_object, "present", present); - if (present) - json_object_set_string(root_object, "full_name", full_mask); - else - json_object_set_null(root_object, "full_name"); + json_object_set_string(root_object, "name", full_mask); if (is_mask_reclass) json_object_set_string(root_object, "is_reclass_of", full_underlying); @@ -121,9 +118,7 @@ int report_status(struct Parameters *params) printf("1"); else printf("0"); - printf("\nfull_name="); - if (present) - printf("%s", full_mask); + printf("\nname=%s", full_mask); printf("\nis_reclass_of="); if (is_mask_reclass) printf("%s", full_underlying); @@ -135,19 +130,16 @@ int report_status(struct Parameters *params) printf("true"); else printf("false"); - printf("\nfull_name: "); - if (present) - printf("|-\n %s", full_mask); - else - printf("null"); - // Null values in YAML can be an empty (no) value (rather than null), - // so we could use that, but using the explicit null as a reasonable - // starting point. + printf("\nname: "); + printf("|-\n %s", full_mask); printf("\nis_reclass_of: "); // Using block scalar with |- to avoid need for escaping. // Alternatively, we could check mapset naming limits against YAML // escaping needs for different types of strings and do the necessary // escaping here. + // Null values in YAML can be an empty (no) value (rather than null), + // so we could use that, but using the explicit null as a reasonable + // starting point. if (is_mask_reclass) printf("|-\n %s", full_underlying); else @@ -155,14 +147,14 @@ int report_status(struct Parameters *params) printf("\n"); } else { - if (present) - printf(_("Mask is active")); - else - printf(_("Mask is not present")); if (present) { - printf("\n"); + printf(_("Mask is active")); printf(_("Mask name: %s"), full_mask); } + else { + printf(_("Mask is not present")); + printf(_("If activated, mask name will be: %s"), full_mask); + } if (is_mask_reclass) { printf("\n"); printf(_("Mask is a raster reclassified from: %s"), diff --git a/raster/r.mask.status/r.mask.status.html b/raster/r.mask.status/r.mask.status.html index 248ee3ea317..cb3897820f5 100644 --- a/raster/r.mask.status/r.mask.status.html +++ b/raster/r.mask.status/r.mask.status.html @@ -1,11 +1,21 @@

    DESCRIPTION

    The r.mask.status reports information about the 2D raster mask and its -status. If the mask is present, the tool reports a full name of the raster (name -including the mapset) which represents the mask. It can also report full name of -the underlying raster if the mask is reclassified from another raster. - -

    +status. The tool reports whether the mask is present or not. For both active +and inactive mask, the tool reports a full name of the raster (name including +the mapset) which represents or would represent the mask. +It can also report full name of the underlying raster if the mask is +reclassified from another raster. + +The tool can be used to check if the mask is currently set +(present boolean in JSON), what is raster name used to represent +the mask (name string in JSON), and whether the raster is +reclassifed from another (is_reclass_of string or null in JSON). +YAML and shell script style outputs are following the JSON output if possible. +The plain text format outputs multi-line human-readable information in natural +language. + +

    With the -t flag, no output is printed, instead a return code is used to indicate presence or absence. The convention is the same same the POSIX test utility, so r.mask.status returns 0 when the mask is diff --git a/raster/r.mask.status/tests/r_mask_status_test.py b/raster/r.mask.status/tests/r_mask_status_test.py index deafdfb145b..a5d406ad581 100644 --- a/raster/r.mask.status/tests/r_mask_status_test.py +++ b/raster/r.mask.status/tests/r_mask_status_test.py @@ -15,10 +15,11 @@ def test_json_no_mask(session_no_data): session = session_no_data data = gs.parse_command("r.mask.status", format="json", env=session.env) assert "present" in data - assert "full_name" in data + assert "name" in data + assert data["name"], "Mask name needs to be always set" + assert data["name"] == "MASK@PERMANENT", "Default mask name and current mapset" assert "is_reclass_of" in data assert data["present"] is False - assert not data["full_name"] assert not data["is_reclass_of"] @@ -28,13 +29,13 @@ def test_json_with_r_mask(session_with_data): gs.run_command("r.mask", raster="a", env=session.env) data = gs.parse_command("r.mask.status", format="json", env=session.env) assert data["present"] is True - assert data["full_name"] == "MASK@PERMANENT" + assert data["name"] == "MASK@PERMANENT" assert data["is_reclass_of"] == "a@PERMANENT" # Now remove the mask. gs.run_command("r.mask", flags="r", env=session.env) data = gs.parse_command("r.mask.status", format="json", env=session.env) assert data["present"] is False - assert not data["full_name"] + assert data["name"] == "MASK@PERMANENT" assert not data["is_reclass_of"] @@ -44,13 +45,13 @@ def test_json_with_g_copy(session_with_data): gs.run_command("g.copy", raster="a,MASK", env=session.env) data = gs.parse_command("r.mask.status", format="json", env=session.env) assert data["present"] is True - assert data["full_name"] == "MASK@PERMANENT" + assert data["name"] == "MASK@PERMANENT" assert not data["is_reclass_of"] # Now remove the mask. gs.run_command("g.remove", type="raster", name="MASK", flags="f", env=session.env) data = gs.parse_command("r.mask.status", format="json", env=session.env) assert data["present"] is False - assert not data["full_name"] + assert data["name"] == "MASK@PERMANENT" assert not data["is_reclass_of"] @@ -60,13 +61,13 @@ def test_shell(session_with_data): gs.run_command("r.mask", raster="a", env=session.env) data = gs.parse_command("r.mask.status", format="shell", env=session.env) assert int(data["present"]) - assert data["full_name"] == "MASK@PERMANENT" + assert data["name"] == "MASK@PERMANENT" assert data["is_reclass_of"] == "a@PERMANENT" # Now remove the mask. gs.run_command("r.mask", flags="r", env=session.env) data = gs.parse_command("r.mask.status", format="shell", env=session.env) assert not int(data["present"]) - assert not data["full_name"] + assert data["name"] == "MASK@PERMANENT" assert not data["is_reclass_of"] @@ -78,14 +79,14 @@ def test_yaml(session_with_data): text = gs.read_command("r.mask.status", format="yaml", env=session.env) data = yaml.safe_load(text) assert data["present"] is True - assert data["full_name"] == "MASK@PERMANENT" + assert data["name"] == "MASK@PERMANENT" assert data["is_reclass_of"] == "a@PERMANENT" # Now remove the mask. gs.run_command("r.mask", flags="r", env=session.env) text = gs.read_command("r.mask.status", format="yaml", env=session.env) data = yaml.safe_load(text) assert data["present"] is False - assert not data["full_name"] + assert data["name"] == "MASK@PERMANENT" assert not data["is_reclass_of"] @@ -101,6 +102,8 @@ def test_plain(session_with_data): gs.run_command("r.mask", flags="r", env=session.env) text = gs.read_command("r.mask.status", format="plain", env=session.env) assert text + assert "MASK@PERMANENT" in text + assert "a@PERMANENT" not in text def test_without_parameters(session_no_data): From f9f01e1e40ab9eb8a28fd91717178935946e6606 Mon Sep 17 00:00:00 2001 From: Stefan Blumentrath Date: Thu, 31 Oct 2024 20:23:21 +0100 Subject: [PATCH 47/55] r.buildvrt: document performance issues with external data (#4441) * document performance issue * address code review * Apply suggestions from code review Co-authored-by: Markus Neteler * consistent recommendation * remove leftover dot --------- Co-authored-by: Markus Neteler --- raster/r.buildvrt/r.buildvrt.html | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/raster/r.buildvrt/r.buildvrt.html b/raster/r.buildvrt/r.buildvrt.html index 67368179efb..d5118ba5150 100644 --- a/raster/r.buildvrt/r.buildvrt.html +++ b/raster/r.buildvrt/r.buildvrt.html @@ -12,6 +12,8 @@

    NOTES

    the original raster maps which is only valid if the original raster maps remain in the originally indicated mapset. A VRT can also be built from raster maps registered with r.external. +However, GRASS VRTs built from external registered data (see below) +are known to have performance issues.

    Reading the whole VRT is slower than reading the equivalent single @@ -48,12 +50,23 @@

    VRT from a DEM in the North Carolina sample dataset

    r.buildvrt file=tilelist.csv output=elev_state_50m_vrt
    +

    KNOWN ISSUES

    + +Users may experience significant performance degradation with virtual rasters built +with r.buildvrt over GDAL-linked (r.external) raster maps, +especially on slower file systems with latency like NFS. Performance degradation +may also occur on local file systems, but is usually less severe. For such use cases +consider using the GRASS GIS addon +r.buildvrt.gdal +or building GDAL VRTs, e.g. with gdalbuildvrt. +

    SEE ALSO

    r.tile, r.patch, r.external +r.buildvrt.gdal

    From d5a87229ae30cf04ff90f7cfcdc923ec0afa5a36 Mon Sep 17 00:00:00 2001 From: Arohan Ajit Date: Thu, 31 Oct 2024 16:12:20 -0400 Subject: [PATCH 48/55] db.out.ogr: Removed unused variable (#4617) --- .flake8 | 2 +- scripts/db.out.ogr/db.out.ogr.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.flake8 b/.flake8 index 3adda73f281..33920703ca6 100644 --- a/.flake8 +++ b/.flake8 @@ -94,7 +94,7 @@ per-file-ignores = scripts/r.semantic.label/r.semantic.label.py: E501 scripts/db.out.ogr/db.out.ogr.py: F841 scripts/g.extension/g.extension.py: E501 - scripts/v.unpack/v.unpack.py: E501 + scripts/v.unpack/v.unpack.py: E501n scripts/v.import/v.import.py: E501 scripts/db.univar/db.univar.py: E501 scripts/i.pansharpen/i.pansharpen.py: E501 diff --git a/scripts/db.out.ogr/db.out.ogr.py b/scripts/db.out.ogr/db.out.ogr.py index 4fdfed23648..4fe5b4f9854 100755 --- a/scripts/db.out.ogr/db.out.ogr.py +++ b/scripts/db.out.ogr/db.out.ogr.py @@ -67,7 +67,6 @@ def main(): layer = options["layer"] format = options["format"] output = options["output"] - table = options["table"] if format.lower() == "dbf": format = "ESRI_Shapefile" From 5b9b46a0cb1606ea7fd0c69d5145ce879b9a6c31 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 31 Oct 2024 20:37:29 +0000 Subject: [PATCH 49/55] CI(deps): Update softprops/action-gh-release action to v2.0.9 (#4624) --- .github/workflows/create_release_draft.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/create_release_draft.yml b/.github/workflows/create_release_draft.yml index efefb0fd0c7..fb71e35d2ff 100644 --- a/.github/workflows/create_release_draft.yml +++ b/.github/workflows/create_release_draft.yml @@ -73,7 +73,7 @@ jobs: sha256sum ${{ env.GRASS }}.tar.xz > ${{ env.GRASS }}.tar.xz.sha256 - name: Publish draft distribution to GitHub (for tags only) if: startsWith(github.ref, 'refs/tags/') - uses: softprops/action-gh-release@c062e08bd532815e2082a85e87e3ef29c3e6d191 # v2.0.8 + uses: softprops/action-gh-release@e7a8f85e1c67a31e6ed99a94b41bd0b71bbee6b8 # v2.0.9 with: name: GRASS GIS ${{ github.ref_name }} body: | From 3f0b69fdf56879fcd35d36da51c0227765948dca Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 31 Oct 2024 17:23:31 -0400 Subject: [PATCH 50/55] CI(deps): Update docker/dockerfile Docker tag to v1.11 (#4621) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Dockerfile | 2 +- docker/ubuntu/Dockerfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index a5c6ab1ee1d..6b928fb46c9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -# syntax=docker/dockerfile:1.10@sha256:865e5dd094beca432e8c0a1d5e1c465db5f998dca4e439981029b3b81fb39ed5 +# syntax=docker/dockerfile:1.11@sha256:1f2be5a2aa052cbd9aedf893d17c63277c3d1c51b3fb0f3b029c6b34f658d057 # Note: This file must be kept in sync in ./Dockerfile and ./docker/ubuntu/Dockerfile. # Changes to this file must be copied over to the other file. diff --git a/docker/ubuntu/Dockerfile b/docker/ubuntu/Dockerfile index a5c6ab1ee1d..6b928fb46c9 100644 --- a/docker/ubuntu/Dockerfile +++ b/docker/ubuntu/Dockerfile @@ -1,4 +1,4 @@ -# syntax=docker/dockerfile:1.10@sha256:865e5dd094beca432e8c0a1d5e1c465db5f998dca4e439981029b3b81fb39ed5 +# syntax=docker/dockerfile:1.11@sha256:1f2be5a2aa052cbd9aedf893d17c63277c3d1c51b3fb0f3b029c6b34f658d057 # Note: This file must be kept in sync in ./Dockerfile and ./docker/ubuntu/Dockerfile. # Changes to this file must be copied over to the other file. From 7d9bbac1f28a6e5f093e4bac55f6b0d6c7227272 Mon Sep 17 00:00:00 2001 From: Arohan Ajit Date: Thu, 31 Oct 2024 22:18:23 -0400 Subject: [PATCH 51/55] r.in.wms: Removed bare 'except' and repositioned imports (#4622) --- .flake8 | 3 --- scripts/r.in.wms/srs.py | 2 +- scripts/r.in.wms/wms_drv.py | 23 ++++++++++------------- scripts/r.in.wms/wms_gdal_drv.py | 2 +- 4 files changed, 12 insertions(+), 18 deletions(-) diff --git a/.flake8 b/.flake8 index 33920703ca6..ab4038e4749 100644 --- a/.flake8 +++ b/.flake8 @@ -88,9 +88,6 @@ per-file-ignores = python/grass/*/*/__init__.py: F403 python/grass/*/*/*/__init__.py: F403 # E402 module level import not at top of file - scripts/r.in.wms/wms_gdal_drv.py: E722 - scripts/r.in.wms/wms_drv.py: E402, E722 - scripts/r.in.wms/srs.py: E722 scripts/r.semantic.label/r.semantic.label.py: E501 scripts/db.out.ogr/db.out.ogr.py: F841 scripts/g.extension/g.extension.py: E501 diff --git a/scripts/r.in.wms/srs.py b/scripts/r.in.wms/srs.py index 8d996fcde94..752f71d8151 100644 --- a/scripts/r.in.wms/srs.py +++ b/scripts/r.in.wms/srs.py @@ -79,7 +79,7 @@ def __init__(self, srs): # code is always the last value try: self.code = int(values[-1]) - except: + except (IndexError, ValueError): self.code = values[-1] elif len(values) == 2: # it's an authority:code code diff --git a/scripts/r.in.wms/wms_drv.py b/scripts/r.in.wms/wms_drv.py index e825aabe438..f9dc42d2383 100644 --- a/scripts/r.in.wms/wms_drv.py +++ b/scripts/r.in.wms/wms_drv.py @@ -18,13 +18,13 @@ """ import socket -import grass.script as gs - from time import sleep +import grass.script as gs + try: from osgeo import gdal -except: +except ImportError: gs.fatal( _( "Unable to load GDAL Python bindings (requires package 'python-gdal' " @@ -32,21 +32,18 @@ ) ) -import numpy as np - -np.arrayrange = np.arange - -from math import pi, floor - -from urllib.error import HTTPError from http.client import HTTPException - +from math import floor, pi +from urllib.error import HTTPError from xml.etree.ElementTree import ParseError -from wms_base import GetEpsg, GetSRSParamVal, WMSBase +import numpy as np -from wms_cap_parsers import WMTSCapabilitiesTree, OnEarthCapabilitiesTree from srs import Srs +from wms_base import GetEpsg, GetSRSParamVal, WMSBase +from wms_cap_parsers import OnEarthCapabilitiesTree, WMTSCapabilitiesTree + +np.arrayrange = np.arange class WMSDrv(WMSBase): diff --git a/scripts/r.in.wms/wms_gdal_drv.py b/scripts/r.in.wms/wms_gdal_drv.py index 830be2b593e..869f71195a2 100644 --- a/scripts/r.in.wms/wms_gdal_drv.py +++ b/scripts/r.in.wms/wms_gdal_drv.py @@ -17,7 +17,7 @@ try: from osgeo import gdal -except: +except ImportError: gs.fatal( _( "Unable to load GDAL Python bindings (requires package 'python-gdal' being " From 4385b2650bcc5432080b29756c855ba0a05d6036 Mon Sep 17 00:00:00 2001 From: Michael Barton Date: Thu, 31 Oct 2024 21:26:09 -0500 Subject: [PATCH 52/55] lib: Add new SRTM_percent color table (#4608) This color table uses the color ramp from the srtm_plus color table for terrain to create colors for relative elevation (spread over the range of elevations in a raster map) rather than absolute elevation in meters. This applies srtm colors in a way similar to the way the elevation color table applies them. This color table is especially useful in creating nice looking elevation maps and shading relief maps. --- lib/gis/colors.desc | 1 + lib/gis/colors/srtm_percent | 7 +++++++ 2 files changed, 8 insertions(+) create mode 100644 lib/gis/colors/srtm_percent diff --git a/lib/gis/colors.desc b/lib/gis/colors.desc index 673c0db8f91..c501e00c93b 100644 --- a/lib/gis/colors.desc +++ b/lib/gis/colors.desc @@ -48,6 +48,7 @@ sepia: yellowish-brown through to white slope: r.slope.aspect-type slope colors for raster values 0-90 soilmoisture: soilmoisture color table (0.0-1.0) srtm: color palette for Shuttle Radar Topography Mission elevation +srtm_percent: color palette for Shuttle Radar Topography Mission using relative elevation srtm_plus: color palette for Shuttle Radar Topography Mission elevation (with seafloor colors) terrain: global elevation color table covering -11000 to +8850m viridis: perceptually uniform sequential color table viridis diff --git a/lib/gis/colors/srtm_percent b/lib/gis/colors/srtm_percent new file mode 100644 index 00000000000..a8e0d857f76 --- /dev/null +++ b/lib/gis/colors/srtm_percent @@ -0,0 +1,7 @@ +0% 57 151 105 +25% 117 194 93 +40% 230 230 128 +55% 214 187 98 +70% 185 154 100 +80% 150 120 80 +100% 220 220 220 From 4964f451589a1428c48112f8e9349450e1e2edb0 Mon Sep 17 00:00:00 2001 From: Arohan Ajit Date: Fri, 1 Nov 2024 11:54:21 -0400 Subject: [PATCH 53/55] r.in.wms: Replace long-deprecated `np.arrayrange` alias with `np.arange` (#4629) --- scripts/r.in.wms/wms_drv.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/scripts/r.in.wms/wms_drv.py b/scripts/r.in.wms/wms_drv.py index f9dc42d2383..f5e8cbeb914 100644 --- a/scripts/r.in.wms/wms_drv.py +++ b/scripts/r.in.wms/wms_drv.py @@ -43,8 +43,6 @@ from wms_base import GetEpsg, GetSRSParamVal, WMSBase from wms_cap_parsers import OnEarthCapabilitiesTree, WMTSCapabilitiesTree -np.arrayrange = np.arange - class WMSDrv(WMSBase): def _download(self): @@ -288,9 +286,9 @@ def _pct2rgb(self, src_filename, dst_filename): # Build color table lookup = [ - np.arrayrange(256), - np.arrayrange(256), - np.arrayrange(256), + np.arange(256), + np.arange(256), + np.arange(256), np.ones(256) * 255, ] From cb3d12b490528b595729589e373887bc5a5923a6 Mon Sep 17 00:00:00 2001 From: Vaclav Petras Date: Fri, 1 Nov 2024 17:23:39 -0400 Subject: [PATCH 54/55] grass.script: Pass environment to message functions (#4630) While the message functions (fatal, warning, message, info, debug, verbose, percent) have env parameter, grass.script was not consistently passing the env parameter to these functions. This fixes all the clear cases in functions which themselves have env (but does not touch any which don't have it where the fix needs to be more complex). These functions can now be called and produce these messages even for non-global sessions. --- python/grass/script/core.py | 10 ++++++---- python/grass/script/db.py | 7 ++++--- python/grass/script/raster.py | 8 ++++++-- python/grass/script/raster3d.py | 5 ++++- python/grass/script/vector.py | 9 +++++---- 5 files changed, 25 insertions(+), 14 deletions(-) diff --git a/python/grass/script/core.py b/python/grass/script/core.py index f51814a5900..e6de4331b43 100644 --- a/python/grass/script/core.py +++ b/python/grass/script/core.py @@ -1447,7 +1447,7 @@ def list_strings(type, pattern=None, mapset=None, exclude=None, flag="", env=Non :return: list of elements """ if type == "cell": - verbose(_('Element type should be "raster" and not "%s"') % type) + verbose(_('Element type should be "raster" and not "%s"') % type, env=env) result = [] for line in read_command( @@ -1520,7 +1520,9 @@ def list_grouped( flag += "t" for i in range(len(types)): if types[i] == "cell": - verbose(_('Element type should be "raster" and not "%s"') % types[i]) + verbose( + _('Element type should be "raster" and not "%s"') % types[i], env=env + ) types[i] = "raster" result = {} if check_search_path: @@ -1543,7 +1545,7 @@ def list_grouped( try: name, mapset = line.split("@") except ValueError: - warning(_("Invalid element '%s'") % line) + warning(_("Invalid element '%s'") % line, env=env) continue if store_types: @@ -1701,7 +1703,7 @@ def mapsets(search_path=False, env=None): flags = "p" if search_path else "l" mapsets = read_command("g.mapsets", flags=flags, sep="newline", quiet=True, env=env) if not mapsets: - fatal(_("Unable to list mapsets")) + fatal(_("Unable to list mapsets"), env=env) return mapsets.splitlines() diff --git a/python/grass/script/db.py b/python/grass/script/db.py index 60813379501..5591b92d4ca 100644 --- a/python/grass/script/db.py +++ b/python/grass/script/db.py @@ -55,7 +55,7 @@ def db_describe(table, env=None, **args): args.pop("driver") s = read_command("db.describe", flags="c", table=table, env=env, **args) if not s: - fatal(_("Unable to describe table <%s>") % table) + fatal(_("Unable to describe table <%s>") % table, env=env) cols = [] result = {} @@ -179,7 +179,8 @@ def db_select(sql=None, filename=None, table=None, env=None, **args): "Programmer error: '%(sql)s', '%(filename)s', or '%(table)s' must be \ provided" ) - % {"sql": "sql", "filename": "filename", "table": "table"} + % {"sql": "sql", "filename": "filename", "table": "table"}, + env=env, ) if "sep" not in args: @@ -188,7 +189,7 @@ def db_select(sql=None, filename=None, table=None, env=None, **args): try: run_command("db.select", quiet=True, flags="c", output=fname, env=env, **args) except CalledModuleError: - fatal(_("Fetching data failed")) + fatal(_("Fetching data failed"), env=env) ofile = open(fname) result = [tuple(x.rstrip(os.linesep).split(args["sep"])) for x in ofile] diff --git a/python/grass/script/raster.py b/python/grass/script/raster.py index d82780d7c5c..aaf9e0179b0 100644 --- a/python/grass/script/raster.py +++ b/python/grass/script/raster.py @@ -66,7 +66,8 @@ def raster_history(map, overwrite=False, env=None): "Unable to write history for <%(map)s>. " "Raster map <%(map)s> not found in current mapset." ) - % {"map": map} + % {"map": map}, + env=env, ) return False @@ -143,7 +144,10 @@ def mapcalc( overwrite=overwrite, ) except CalledModuleError: - fatal(_("An error occurred while running r.mapcalc with expression: %s") % e) + fatal( + _("An error occurred while running r.mapcalc with expression: %s") % e, + env=env, + ) def mapcalc_start( diff --git a/python/grass/script/raster3d.py b/python/grass/script/raster3d.py index e3db5398158..1a4a2782984 100644 --- a/python/grass/script/raster3d.py +++ b/python/grass/script/raster3d.py @@ -108,4 +108,7 @@ def mapcalc3d( overwrite=overwrite, ) except CalledModuleError: - fatal(_("An error occurred while running r3.mapcalc with expression: %s") % e) + fatal( + _("An error occurred while running r3.mapcalc with expression: %s") % e, + env=env, + ) diff --git a/python/grass/script/vector.py b/python/grass/script/vector.py index 2d484f7d590..4adf3e38da1 100644 --- a/python/grass/script/vector.py +++ b/python/grass/script/vector.py @@ -87,7 +87,7 @@ def vector_layer_db(map, layer, env=None): try: f = vector_db(map, env=env)[int(layer)] except KeyError: - fatal(_("Database connection not defined for layer %s") % layer) + fatal(_("Database connection not defined for layer %s") % layer, env=env) return f @@ -250,7 +250,8 @@ def vector_db_select(map, layer=1, env=None, **kwargs): except KeyError: error( _("Missing layer %(layer)d in vector map <%(map)s>") - % {"layer": layer, "map": map} + % {"layer": layer, "map": map}, + env=env, ) return {"columns": [], "values": {}} @@ -259,13 +260,13 @@ def vector_db_select(map, layer=1, env=None, **kwargs): if key not in kwargs["columns"].split(","): # add key column if missing include_key = False - debug("Adding key column to the output") + debug("Adding key column to the output", env=env) kwargs["columns"] += "," + key ret = read_command("v.db.select", map=map, layer=layer, env=env, **kwargs) if not ret: - error(_("vector_db_select() failed")) + error(_("vector_db_select() failed"), env=env) return {"columns": [], "values": {}} columns = [] From 0824e8842edde3af2588d3865d12ba67493666f0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 2 Nov 2024 01:16:45 +0000 Subject: [PATCH 55/55] CI(deps): Update ruff to v0.7.2 (#4631) --- .github/workflows/python-code-quality.yml | 2 +- .pre-commit-config.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/python-code-quality.yml b/.github/workflows/python-code-quality.yml index aa6bd33724f..f7f741a7bb1 100644 --- a/.github/workflows/python-code-quality.yml +++ b/.github/workflows/python-code-quality.yml @@ -36,7 +36,7 @@ jobs: # renovate: datasource=pypi depName=bandit BANDIT_VERSION: "1.7.10" # renovate: datasource=pypi depName=ruff - RUFF_VERSION: "0.7.1" + RUFF_VERSION: "0.7.2" runs-on: ${{ matrix.os }} permissions: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2f3216877de..fd6d6c67f50 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -37,7 +37,7 @@ repos: ) - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.7.1 + rev: v0.7.2 hooks: # Run the linter. - id: ruff