From 27c21d3b726795ab8b48b7f78ed3ee33cbb5ad3b Mon Sep 17 00:00:00 2001 From: Wouter Remijn Date: Tue, 4 Jun 2024 14:49:31 +0200 Subject: [PATCH 1/3] check simple geometry --- README.md | 1 + geopackage_validator/validations/__init__.py | 4 ++ .../validations/geometry_simple_check.py | 45 ++++++++++++++++++ tests/data/test_geometry_simple.gpkg | Bin 0 -> 98304 bytes tests/test_validate.py | 1 + .../validations/test_geometry_simple_check.py | 18 +++++++ 6 files changed, 69 insertions(+) create mode 100644 geopackage_validator/validations/geometry_simple_check.py create mode 100644 tests/data/test_geometry_simple.gpkg create mode 100644 tests/validations/test_geometry_simple_check.py diff --git a/README.md b/README.md index c80cdb1..9cb2ca3 100644 --- a/README.md +++ b/README.md @@ -110,6 +110,7 @@ The current checks are (see also the 'show-validations' command): | RC20 | It is recommended that all (MULTI)POLYGON geometries have a counter-clockwise orientation for their exterior ring, and a clockwise direction for all interior rings. | | RQ21 | All layer and column names shall not be longer than 57 characters. | | RQ22 | Only the following EPSG spatial reference systems are allowed: 28992, 3034, 3035, 3040, 3041, 3042, 3043, 3044, 3045, 3046, 3047, 3048, 3049, 3857, 4258, 4326, 4936, 4937, 5730, 7409. | +| RQ23 | Geometry should be simple. | | UNKNOWN_WARNINGS | It is recommended that the unexpected (GDAL) warnings are looked into. | \* Legacy requirements are only executed with the validate command when explicitly requested in the validation set. diff --git a/geopackage_validator/validations/__init__.py b/geopackage_validator/validations/__init__.py index b42de20..cbbe0c3 100644 --- a/geopackage_validator/validations/__init__.py +++ b/geopackage_validator/validations/__init__.py @@ -7,6 +7,9 @@ GeometryTypeEqualsGpkgDefinitionValidator, ) from geopackage_validator.validations.geometry_valid_check import ValidGeometryValidator +from geopackage_validator.validations.geometry_simple_check import ( + SimpleGeometryValidator, +) from geopackage_validator.validations.layerfeature_check import ( OGRIndexValidator, NonEmptyLayerValidator, @@ -45,6 +48,7 @@ "FeatureIdValidator", "GeometryTypeValidator", "ValidGeometryValidator", + "SimpleGeometryValidator", "OGRIndexValidator", "NonEmptyLayerValidator", "LayerNameValidator", diff --git a/geopackage_validator/validations/geometry_simple_check.py b/geopackage_validator/validations/geometry_simple_check.py new file mode 100644 index 0000000..4073d70 --- /dev/null +++ b/geopackage_validator/validations/geometry_simple_check.py @@ -0,0 +1,45 @@ +from typing import Iterable, Tuple +from geopackage_validator.validations import validator +from geopackage_validator import utils + + +SQL_TEMPLATE = """SELECT +count(rowid) AS count, +cast(rowid AS INTEGER) AS row_id +FROM "{table_name}" WHERE ST_IsSimple("{column_name}") = 0""" + + +def query_geometry_simple(dataset) -> Iterable[Tuple[str, str, int]]: + columns = utils.dataset_geometry_tables(dataset) + + for table_name, column_name, _ in columns: + + validations = dataset.ExecuteSQL( + SQL_TEMPLATE.format(table_name=table_name, column_name=column_name) + ) + for count, row_id in validations: + if count > 0: + yield table_name, column_name, count, row_id + dataset.ReleaseResultSet(validations) + + +class SimpleGeometryValidator(validator.Validator): + """Geometries should be simple.""" + + code = 23 + level = validator.ValidationLevel.ERROR + message = "Found not simple geometry in table: {table_name}, column {column_name}, {count} {count_label}, example id {row_id}" + + def check(self) -> Iterable[str]: + result = query_geometry_simple(self.dataset) + + return [ + self.message.format( + table_name=table_name, + column_name=column_name, + count=count, + count_label=("time" if count == 1 else "times"), + row_id=row_id, + ) + for table_name, column_name, count, row_id in result + ] diff --git a/tests/data/test_geometry_simple.gpkg b/tests/data/test_geometry_simple.gpkg new file mode 100644 index 0000000000000000000000000000000000000000..e2a04e874c80094cff2c54545ed2036117e20ab2 GIT binary patch literal 98304 zcmeI5+jAS&ea9EPft19H6U%VQC^}k41yF$`E(A$PmLrHS7LO2Hj5C8!X z009sH0T2KI5C8!X009vAln9Jnq8X2l4b#7U=l+`+=^g%~k#%~40|Y<-1V8`;KmY_l z00jOY5_s&}{pVYQ5$0mgcgLA{RaDect)^&Xiewf@O5EaBvWbVcRx;^V=d)|9g8&;y zaOp&ABpX!V5L{4(V69`CKxcT4U31 zR-}iUBA?YnMXZ$-VPjn?uvE`@Ccez&xXc<`5j08LEQ)-s#Mcz5EXiyj8m1IxLNmdr zam=(ND2TGA2o;_-l~j}jU3@Y!H#-xVs~@ozakU^+M7|^xw3?#VF-DKzY^zL3sHh?@ z3aTc_Wi~)tA{Y#|P1Nx>lGJ=Ss|YTh&C!N5 z0#l7#Q|U}@(W!kY+L(_0HyQU$=HlSxYF;jiB}o>Gq}=ubJ2DAL9>*3LD58&(zXiuRU`Ap326!)Qpo=E zKPU}dqwe-d+P!oyktK7}x_U)XlM1?>kNu0~PG)4omFOiOip@>i9mx`*J~S7K%u@fE zn+!*1!{JDD#>skTgOQ-K_0B}XGkVNt=s`x~FV)ST4OoqD2G``W;TCM5ZYmwU!L+Gy z#gd$|Jc%^vt3;AXQ7lMRp+Y}(KUYajCfd44>g?5xby2BFMScD68vPDKe{g^R2!H?x zfB*=900@8p2!H?xfB*=5+5|RT=cAXR!#CaZ=%Je~8c(-J^c|)hUX`jF6}o97XqyU+ zaEJ>B!_yPNnTg2ViCquROwL4Rz8+`Zc|xe>@$sL&|6BSe^UizUGOz!T(9egr z&e6ZF(T^DVg98LW00ck)1V8`;KmY_l00ck)1VG>!C*bLg4ms@{VEzA$H!Rc#0T2KI z5C8!X009sH0T2KI5C8!ifrHln=KufykQx2ZCX7=M009sH0T2KI5C8!X009sH0T2Lz zXOV!%)f;7S|NmKRI_L}nAOHd&00JNY0w4eaAOHd&00P|;IQ;(q2h8XP-RA{K5C8!X z009sH0T2KI5C8!X009sHfm0^=)?NUf|95=2NC^TU00JNY z0w4eaAOHd&00JNY0%wiDVgLW189Qs*LLU$S0T2KI5C8!X009sH0T2KI5CDObB%t5_ z$NK*yi6So$009sH0T2KI5C8!X009sH0T4KQ1oZd+Vf}yh+65Yc00@8p2!H?xfB*=9 z00@8p2!Oyz62Sfclcb5fKmY_l00ck)1V8`;KmY_l00cnbY!VnA`6V;v`XMv&KNtRC z{n| z4==gR-AQLSl1yc}Opc^eo$0)UN)RqSzeqCado)2JnIc(kiJQ-nOgx$8eDT}qOfEpY zre35b6HR!tA`)+h4qh+$rc|p4^yL+#P?J?n5hPi=PU^KZsz(ZfEY~#hrbsHHsuFEo zkV(kvC-)XPs;Mu<-J5KYf0=~*Hwc$n*n4%6b~c4)f&^6J~!GFpp`G&2sBD z-GF(@_SjU+(HgtJ_qE{xPj)e$G2Y(Tb3KYy~L6BSmHA>;boyJk{tI&j-=A`H@~zLuvImg%5i$v(THntvx8#S zMX9{5(H^8NvC(~*9_<`=P{IvqoBHQAuS#!;WFei`E7VZQjNEaKoKL6dYj5JTII{78 z*R(2G$t0KKnN{){w`yk)u=%JzU`tk_$*NV}MoaG=lZjM&4t|p1?$G`yHP2;D+_XQ_ zL|Id9sQv!^ubgvxqEXjlGt2gN;Z?DtAJ@aqAKIF_guOPcEo!fGKvh&;Dt0zbRg(Gb z4!C;gPG_jF?IcS>J7rr@mbI#SVl3O5$;g{lPamC{4P@50vvJf7L6d|EuZSgH-BF3J zF6d93AMmV2yY^E`zSCFr_PFqfal1XUv#xJnZu+bB3}(Jit87+f)oA|qz`@S8ZWlSY zu>)q#PLAEkMBCXAodgcDjkicHnOfDIsNr?h&LCS$Q(w~y(`%{PtN`bf9lKVT(L? z*wH4=B?ph5l{tpAmoT*ZLciNHHRak}YZ_*)tkBjn`zu2Md%!@aLE58j?Q%%RQxXMj zQxRz?n{sn-Sm5r&^GoK)+aILC)y@86LYJ7oC zYs++eqjSbwa=AIe5lhfVXU8Q?s)|1E)zyis)rqUc+||YFSC_9}Eq&b^@XECoUgPeSgz9+QtFH_S?dGI!&cb!W=yu=28drsP;ZFP*ci+EWJgC zBg--xy{tWoI!;X~(xJ+6_%4biNtTQ(+RU-t?)<}pA28>cFf%;nel+0g`}^K+^-MEA zW5T0}8*^^`Bie z@{}xBFLq_8=6dJp?6f711MRfFvU<9`p5t##m~87x9F1)~keI zJ>`9hlVrL2MfdnUx_K5m$mi?30p_y(xQ6PKNrPsyM{N;1wJx<)3#W}V=Y7fg&PH=% za`6i$TTgdvk7=ka>YlM4wM93_O||Y&o_m*h+nB1H>YtmJ20VAK9XhcUx9M(>N+)@0 zec{p!cz$>5%WluLYp(sP&6#O4+L)9!FTdC_uWF0zSiE#>2m~5AIqd=1CX%h&f@-1G zvDC3G`O6}&6-3gxRBu`52S{t-e*Z|hXYW*74uyZt3GC&bGv^GUPw0!ydu_+OO;qph z?0FnK%9)$wr!^n5t9pcv*;KkQ#4(I3@j17wlc@g6mj?8KVbvHH>bH$l@!_T@7sR&9 zFSLvcZIM2GcOpPj`t|SsyGFMe`hx=mKmY_l00ck)1V8`;KmY_l00cnbgbD2SyZV^D zk;Dqqd+Q;?y!(^MnJ4cs@&EY!Zxr97pa1&3KU;tQr{nRzdc5>c->09h9$J1s{j~)D zB|sc*OI&whY^^&Gr9>%;<+FTtQ?90w4eaAOHd& z00JNY0w4eaAOHd&@L3b^xO$^QPXFiLT>n2|MxT7vDxo|O009sH0T2KI5C8!X009sH z0TB575|CX3(MuB#uQ;vMtuMM8U-D8kMHK0`_~`Sa)-`S8`qb3c*488y*$@g3gt9nE z9~UsCZit0YI5_oE^NUtSx-Er1aB89^S9bL0|GP&2hM_+=KmY_l00ck)1V8`;KmY_l z00ck)1fB^3p?00JNY0w4eaAOHd&00JNY0w4ea zCq!WQ0>@lnK4Q+ld+u+~{o2s$?mzDTNuStrm-%SqABVqx;TtDZ%&BLySNe7Lcp*CY z=xg=&dYaEqaC*!FZ+%yy{u1kHCn4+YikW00!DR@0gzQ)nzmubBtk+qm2uF5P7dz8+u7bJ@Dt=q44QcCswV zZ?qdpK(EoVu-zG9CRjZvK}UpX6MN!UP3OCLWSa<|tWAX5ZQ>4Ln+`(%baDMypkvWG>mUHN{;e2#Qd^R0ue}Z+73(>*H=_53(B&(vLom9J;xmnF> zVLaSne6qMTY4b0=uRLPMX%+Nrb$Gk+D{hYsQP#Sb^jHI9{Pq&p z)d0YoMX)}(Rutu$K5}sS++`(`T#jc}$!pwdz!cF1{JT-&_T0bk+P&Fz9rSeF)IgVe z;pqD7$qv=NC}@IzH+I?W;d$3?ylcIc8hu@PH;NmA7mu#Fk&g8lACBDhs>wC~?(|pO zo@{n-_inekccFD%-PeE8UEfYe)o7SI=Ek`_gnQ3z9?2iP2@|WplvE5U#M-$8t>FqIfYsLt-1G+GqrlL z`Xu<^Vc(o9*C*=6W7leBg=#Bn)K^uK<#ME@3gl+n^#lp&(|9^@uGF?f#b-1tufKiW zPi4(8uTvep^_kNvK4*YtcYMMCyUx@CX!Xtq4g*gO@Y>S?yyP`T&i$#nm2}}Sb?bC$ emUh$YJ~s>5C)%8`>Z?_XjsxdYFW%axjQ Date: Wed, 5 Jun 2024 11:01:19 +0200 Subject: [PATCH 2/3] combined valid and simple validators, fixed some RQ docs --- README.md | 10 ++-- geopackage_validator/validate.py | 3 +- geopackage_validator/validations/__init__.py | 8 +-- .../validations/geometry_simple_check.py | 45 -------------- .../validations/geometry_type_check.py | 2 +- .../validations/geometry_valid_check.py | 58 ++++++++++++++++--- .../validations/name_length_check.py | 4 +- geopackage_validator/validations/srs_check.py | 2 +- .../validations/table_definitions_check.py | 2 +- tests/test_validate.py | 1 - .../validations/test_geometry_simple_check.py | 18 ------ .../validations/test_geometry_valid_check.py | 34 +++++++++-- 12 files changed, 97 insertions(+), 90 deletions(-) delete mode 100644 geopackage_validator/validations/geometry_simple_check.py delete mode 100644 tests/validations/test_geometry_simple_check.py diff --git a/README.md b/README.md index 9cb2ca3..dc07b9b 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ The current checks are (see also the 'show-validations' command): | RQ2 | Layers must have at least one feature. | | RQ3 | _LEGACY:_ * Layer features should have an allowed geometry_type (one of POINT, LINESTRING, POLYGON, MULTIPOINT, MULTILINESTRING, or MULTIPOLYGON). | | RQ4 | The geopackage should have no views defined. | -| RQ5 | Geometry should be valid. | +| RQ5 | _LEGACY:_ * Geometry should be valid. | | RQ6 | Column names must start with a letter, and valid characters are lowercase a-z, numbers or underscores. | | RQ7 | Tables should have a feature id column with unique index. | | RQ8 | Geopackage must conform to given JSON or YAML definitions. | @@ -104,13 +104,13 @@ The current checks are (see also the 'show-validations' command): | RQ14 | The geometry_type_name from the gpkg_geometry_columns table must be one of POINT, LINESTRING, POLYGON, MULTIPOINT, MULTILINESTRING, or MULTIPOLYGON. | | RQ15 | All table geometries must match the geometry_type_name from the gpkg_geometry_columns table. | | RQ16 | _LEGACY:_ * All layer and column names shall not be longer than 53 characters. | +| RQ21 | All layer and column names shall not be longer than 57 characters. | +| RQ22 | Only the following EPSG spatial reference systems are allowed: 28992, 3034, 3035, 3040, 3041, 3042, 3043, 3044, 3045, 3046, 3047, 3048, 3049, 3857, 4258, 4326, 4936, 4937, 5730, 7409. | +| RQ23 | Geometry should be valid and simple. | | RC17 | It is recommended to name all GEOMETRY type columns 'geom'. | | RC18 | It is recommended to give all GEOMETRY type columns the same name. | | RC19 | It is recommended to only use multidimensional geometry coordinates (elevation and measurement) when necessary. | -| RC20 | It is recommended that all (MULTI)POLYGON geometries have a counter-clockwise orientation for their exterior ring, and a clockwise direction for all interior rings. | -| RQ21 | All layer and column names shall not be longer than 57 characters. | -| RQ22 | Only the following EPSG spatial reference systems are allowed: 28992, 3034, 3035, 3040, 3041, 3042, 3043, 3044, 3045, 3046, 3047, 3048, 3049, 3857, 4258, 4326, 4936, 4937, 5730, 7409. | -| RQ23 | Geometry should be simple. | +| RC20 | It is recommended that all (MULTI)POLYGON geometries have a counter-clockwise orientation for their exterior ring, and a clockwise direction for all interior rings. | | UNKNOWN_WARNINGS | It is recommended that the unexpected (GDAL) warnings are looked into. | \* Legacy requirements are only executed with the validate command when explicitly requested in the validation set. diff --git a/geopackage_validator/validate.py b/geopackage_validator/validate.py index 019cab0..e52f7e4 100644 --- a/geopackage_validator/validate.py +++ b/geopackage_validator/validate.py @@ -19,13 +19,14 @@ RQ0 = "RQ0" RQ3 = "RQ3" +RQ5 = "RQ5" RQ8 = "RQ8" RQ12 = "RQ12" RQ16 = "RQ16" # Drop legacy requirements -DROP_LEGACY_RQ_FROM_ALL = [RQ0, RQ3, RQ12, RQ16] +DROP_LEGACY_RQ_FROM_ALL = [RQ0, RQ3, RQ5, RQ12, RQ16] def validators_to_use( diff --git a/geopackage_validator/validations/__init__.py b/geopackage_validator/validations/__init__.py index cbbe0c3..d910f1d 100644 --- a/geopackage_validator/validations/__init__.py +++ b/geopackage_validator/validations/__init__.py @@ -6,9 +6,9 @@ GpkgGeometryTypeNameValidator, GeometryTypeEqualsGpkgDefinitionValidator, ) -from geopackage_validator.validations.geometry_valid_check import ValidGeometryValidator -from geopackage_validator.validations.geometry_simple_check import ( - SimpleGeometryValidator, +from geopackage_validator.validations.geometry_valid_check import ( + ValidGeometryValidator, + ValidGeometryValidatorV0, ) from geopackage_validator.validations.layerfeature_check import ( OGRIndexValidator, @@ -48,7 +48,7 @@ "FeatureIdValidator", "GeometryTypeValidator", "ValidGeometryValidator", - "SimpleGeometryValidator", + "ValidGeometryValidatorV0", "OGRIndexValidator", "NonEmptyLayerValidator", "LayerNameValidator", diff --git a/geopackage_validator/validations/geometry_simple_check.py b/geopackage_validator/validations/geometry_simple_check.py deleted file mode 100644 index 4073d70..0000000 --- a/geopackage_validator/validations/geometry_simple_check.py +++ /dev/null @@ -1,45 +0,0 @@ -from typing import Iterable, Tuple -from geopackage_validator.validations import validator -from geopackage_validator import utils - - -SQL_TEMPLATE = """SELECT -count(rowid) AS count, -cast(rowid AS INTEGER) AS row_id -FROM "{table_name}" WHERE ST_IsSimple("{column_name}") = 0""" - - -def query_geometry_simple(dataset) -> Iterable[Tuple[str, str, int]]: - columns = utils.dataset_geometry_tables(dataset) - - for table_name, column_name, _ in columns: - - validations = dataset.ExecuteSQL( - SQL_TEMPLATE.format(table_name=table_name, column_name=column_name) - ) - for count, row_id in validations: - if count > 0: - yield table_name, column_name, count, row_id - dataset.ReleaseResultSet(validations) - - -class SimpleGeometryValidator(validator.Validator): - """Geometries should be simple.""" - - code = 23 - level = validator.ValidationLevel.ERROR - message = "Found not simple geometry in table: {table_name}, column {column_name}, {count} {count_label}, example id {row_id}" - - def check(self) -> Iterable[str]: - result = query_geometry_simple(self.dataset) - - return [ - self.message.format( - table_name=table_name, - column_name=column_name, - count=count, - count_label=("time" if count == 1 else "times"), - row_id=row_id, - ) - for table_name, column_name, count, row_id in result - ] diff --git a/geopackage_validator/validations/geometry_type_check.py b/geopackage_validator/validations/geometry_type_check.py index fbefa81..ea0b638 100644 --- a/geopackage_validator/validations/geometry_type_check.py +++ b/geopackage_validator/validations/geometry_type_check.py @@ -84,7 +84,7 @@ def aggregate(results): class GeometryTypeValidator(validator.Validator): - """Layer features should have an allowed geometry_type (one of POINT, LINESTRING, POLYGON, MULTIPOINT, MULTILINESTRING, or MULTIPOLYGON).""" + """LEGACY: * Layer features should have an allowed geometry_type (one of POINT, LINESTRING, POLYGON, MULTIPOINT, MULTILINESTRING, or MULTIPOLYGON).""" code = 3 level = validator.ValidationLevel.ERROR diff --git a/geopackage_validator/validations/geometry_valid_check.py b/geopackage_validator/validations/geometry_valid_check.py index bec7336..2904e46 100644 --- a/geopackage_validator/validations/geometry_valid_check.py +++ b/geopackage_validator/validations/geometry_valid_check.py @@ -2,8 +2,7 @@ from geopackage_validator.validations import validator from geopackage_validator import utils - -SQL_TEMPLATE = """SELECT reason, count(reason) AS count, row_id +SQL_ONLY_VALID_TEMPLATE = """SELECT reason, count(reason) AS count, row_id FROM( SELECT CASE INSTR(ST_IsValidReason("{column_name}"), '[') @@ -16,28 +15,73 @@ ) GROUP BY reason;""" +SQL_VALID_TEMPLATE = """SELECT reason, count(reason) AS count, row_id +FROM( + SELECT + CASE ST_IsValid("{column_name}") + WHEN 0 + THEN + CASE INSTR(ST_IsValidReason("{column_name}"), '[') + WHEN 0 + THEN ST_IsValidReason("{column_name}") + ELSE substr(ST_IsValidReason("{column_name}"), 0, INSTR(ST_IsValidReason("{column_name}"), '[')) + END + ELSE + CASE ST_IsSimple("{column_name}") + WHEN 0 + THEN 'Not Simple' + END + END AS reason, + cast(rowid AS INTEGER) AS row_id + FROM "{table_name}" WHERE ST_IsValid("{column_name}") = 0 OR ST_IsSimple("{column_name}") = 0 +) +GROUP BY reason;""" -def query_geometry_valid(dataset) -> Iterable[Tuple[str, str, str, int]]: + +def query_geometry_valid(dataset, sql_template) -> Iterable[Tuple[str, str, str, int]]: columns = utils.dataset_geometry_tables(dataset) for table_name, column_name, _ in columns: validations = dataset.ExecuteSQL( - SQL_TEMPLATE.format(table_name=table_name, column_name=column_name) + sql_template.format(table_name=table_name, column_name=column_name) ) for reason, count, row_id in validations: yield table_name, column_name, reason, count, row_id dataset.ReleaseResultSet(validations) -class ValidGeometryValidator(validator.Validator): - """Geometries should be valid.""" +class ValidGeometryValidatorV0(validator.Validator): + """Legacy: * Geometries should be valid.""" code = 5 level = validator.ValidationLevel.ERROR message = "Found invalid geometry in table: {table_name}, column {column_name}, reason: {reason}, {count} {count_label}, example id {row_id}" def check(self) -> Iterable[str]: - result = query_geometry_valid(self.dataset) + result = query_geometry_valid(self.dataset, SQL_ONLY_VALID_TEMPLATE) + + return [ + self.message.format( + table_name=table_name, + column_name=column_name, + reason=reason, + count=count, + count_label=("time" if count == 1 else "times"), + row_id=row_id, + ) + for table_name, column_name, reason, count, row_id in result + ] + + +class ValidGeometryValidator(validator.Validator): + """Geometries should be valid and simple.""" + + code = 23 + level = validator.ValidationLevel.ERROR + message = "Found invalid geometry in table: {table_name}, column {column_name}, reason: {reason}, {count} {count_label}, example id {row_id}" + + def check(self) -> Iterable[str]: + result = query_geometry_valid(self.dataset, SQL_VALID_TEMPLATE) return [ self.message.format( diff --git a/geopackage_validator/validations/name_length_check.py b/geopackage_validator/validations/name_length_check.py index 6e8f174..7ee839f 100644 --- a/geopackage_validator/validations/name_length_check.py +++ b/geopackage_validator/validations/name_length_check.py @@ -21,7 +21,7 @@ def query_names(dataset) -> Iterable[Tuple[str, str, int]]: class NameLengthValidatorV0(validator.Validator): - f"""All names must be maximally {LEGACY_MAX_LENGTH} characters long.""" + """LEGACY: * All names must be maximally 53 characters long.""" code = 16 level = validator.ValidationLevel.ERROR @@ -42,7 +42,7 @@ def check_columns(cls, names: Iterable[Tuple[str, str, int]]) -> List[str]: class NameLengthValidator(validator.Validator): - f"""All names must be maximally {MAX_LENGTH} characters long.""" + """All names must be maximally 57 characters long.""" code = 21 level = validator.ValidationLevel.ERROR diff --git a/geopackage_validator/validations/srs_check.py b/geopackage_validator/validations/srs_check.py index 6ac0056..7a348ee 100644 --- a/geopackage_validator/validations/srs_check.py +++ b/geopackage_validator/validations/srs_check.py @@ -32,7 +32,7 @@ def srs_equal_check_query(dataset) -> Iterable[str]: class SrsValidatorV0(validator.Validator): - """Only the following EPSG spatial reference systems are allowed: 28992, 3034, 3035, 3038, 3039, 3040, 3041, 3042, 3043, 3044, 3045, 3046, 3047, 3048, 3049, 3050, 3051, 4258, 4936, 4937, 5730, 7409.""" + """LEGACY: * Only the following EPSG spatial reference systems are allowed: 28992, 3034, 3035, 3038, 3039, 3040, 3041, 3042, 3043, 3044, 3045, 3046, 3047, 3048, 3049, 3050, 3051, 4258, 4936, 4937, 5730, 7409.""" code = 12 level = validator.ValidationLevel.ERROR diff --git a/geopackage_validator/validations/table_definitions_check.py b/geopackage_validator/validations/table_definitions_check.py index 4715d23..f3d047b 100644 --- a/geopackage_validator/validations/table_definitions_check.py +++ b/geopackage_validator/validations/table_definitions_check.py @@ -116,7 +116,7 @@ def check_table_definitions(self, definitions_current: TableDefinition): class TableDefinitionValidatorV0(validator.Validator): - """Geopackage must conform to table names in the given JSON definitions.""" + """LEGACY: * Geopackage must conform to table names in the given JSON definitions.""" code = 0 level = validator.ValidationLevel.ERROR diff --git a/tests/test_validate.py b/tests/test_validate.py index c23a659..bdeff13 100644 --- a/tests/test_validate.py +++ b/tests/test_validate.py @@ -24,7 +24,6 @@ def test_determine_validations_to_use_none(): "RQ1", "RQ2", "RQ4", - "RQ5", "RQ6", "RQ7", "RQ9", diff --git a/tests/validations/test_geometry_simple_check.py b/tests/validations/test_geometry_simple_check.py deleted file mode 100644 index 0afd025..0000000 --- a/tests/validations/test_geometry_simple_check.py +++ /dev/null @@ -1,18 +0,0 @@ -from geopackage_validator.utils import open_dataset -from geopackage_validator.validations.geometry_simple_check import query_geometry_simple - - -def test_with_gpkg(): - dataset = open_dataset("tests/data/test_geometry_simple.gpkg") - checks = list(query_geometry_simple(dataset)) - assert len(checks) == 1 - assert checks[0][0] == "test_geometry_simple" - assert checks[0][1] == "geometry" - assert checks[0][2] == 1 - assert checks[0][3] == 1 - - -def test_with_gpkg_allcorrect(): - dataset = open_dataset("tests/data/test_allcorrect.gpkg") - checks = list(query_geometry_simple(dataset)) - assert len(checks) == 0 diff --git a/tests/validations/test_geometry_valid_check.py b/tests/validations/test_geometry_valid_check.py index a72e61c..8aba940 100644 --- a/tests/validations/test_geometry_valid_check.py +++ b/tests/validations/test_geometry_valid_check.py @@ -1,10 +1,36 @@ from geopackage_validator.utils import open_dataset -from geopackage_validator.validations.geometry_valid_check import query_geometry_valid +from geopackage_validator.validations.geometry_valid_check import ( + query_geometry_valid, + SQL_ONLY_VALID_TEMPLATE, + SQL_VALID_TEMPLATE, +) -def test_with_gpkg(): +def test_with_gpkg_valid(): dataset = open_dataset("tests/data/test_geometry_valid.gpkg") - checks = list(query_geometry_valid(dataset)) + checks = list(query_geometry_valid(dataset, SQL_ONLY_VALID_TEMPLATE)) + assert len(checks) == 1 + assert checks[0][0] == "test_geometry_valid" + assert checks[0][1] == "geometry" + assert checks[0][2] == "Self-intersection" + assert checks[0][3] == 1 + assert checks[0][4] == 1 + + +def test_with_gpkg_simple(): + dataset = open_dataset("tests/data/test_geometry_simple.gpkg") + checks = list(query_geometry_valid(dataset, SQL_VALID_TEMPLATE)) + assert len(checks) == 1 + assert checks[0][0] == "test_geometry_simple" + assert checks[0][1] == "geometry" + assert checks[0][2] == "Not Simple" + assert checks[0][3] == 1 + assert checks[0][4] == 1 + + +def test_with_gpkg_valid_simple(): + dataset = open_dataset("tests/data/test_geometry_valid.gpkg") + checks = list(query_geometry_valid(dataset, SQL_VALID_TEMPLATE)) assert len(checks) == 1 assert checks[0][0] == "test_geometry_valid" assert checks[0][1] == "geometry" @@ -15,5 +41,5 @@ def test_with_gpkg(): def test_with_gpkg_allcorrect(): dataset = open_dataset("tests/data/test_allcorrect.gpkg") - checks = list(query_geometry_valid(dataset)) + checks = list(query_geometry_valid(dataset, SQL_VALID_TEMPLATE)) assert len(checks) == 0 From 001d66505365a547d586f793b9b9d53bed048fee Mon Sep 17 00:00:00 2001 From: Wouter Remijn Date: Wed, 5 Jun 2024 12:28:32 +0200 Subject: [PATCH 3/3] added no-legacy flag to show-validations --- geopackage_validator/cli.py | 11 +++++++++-- geopackage_validator/validate.py | 14 ++++++++++++-- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/geopackage_validator/cli.py b/geopackage_validator/cli.py index cd7dadc..e0ae4c4 100644 --- a/geopackage_validator/cli.py +++ b/geopackage_validator/cli.py @@ -420,6 +420,12 @@ def geopackage_validator_command_generate_table_definitions( name="show-validations", help="Show all the possible validations that can be executed in the validate command.", ) +@click.option( + "--no-legacy", + required=False, + is_flag=True, + help="Output without Legacy checks", +) @click.option( "--yaml", required=False, @@ -427,9 +433,10 @@ def geopackage_validator_command_generate_table_definitions( help="Output yaml", ) @click_log.simple_verbosity_option(logger) -def geopackage_validator_command_show_validations(yaml): +def geopackage_validator_command_show_validations(no_legacy, yaml): try: - validation_codes = validate.get_validation_descriptions() + legacy = not no_legacy + validation_codes = validate.get_validation_descriptions(legacy) output.print_output(validation_codes, yaml, yaml_indent=5) except Exception: logger.exception("Error while listing validations") diff --git a/geopackage_validator/validate.py b/geopackage_validator/validate.py index e52f7e4..9eefe1e 100644 --- a/geopackage_validator/validate.py +++ b/geopackage_validator/validate.py @@ -194,10 +194,20 @@ def gdal_error_handler(err_class, err_num, error): ) -def get_validation_descriptions(): +def get_validation_descriptions(legacy): validation_classes = get_validator_classes() + + if legacy: + return OrderedDict( + (klass.validation_code, klass.__doc__) for klass in validation_classes + ) + + rq_drop_list = DROP_LEGACY_RQ_FROM_ALL + return OrderedDict( - (klass.validation_code, klass.__doc__) for klass in validation_classes + (klass.validation_code, klass.__doc__) + for klass in validation_classes + if klass.validation_code not in rq_drop_list )