@@ -95,10 +95,17 @@ class Context(Enum):
95
95
ITEM_SEARCH = "Item Search"
96
96
FEATURES = "Features"
97
97
COLLECTIONS = "Collections"
98
- ITEM_SEARCH_FILTER = "Item Search - Filter Ext"
99
- FEATURES_FILTER = "Features - Filter Ext"
100
98
CHILDREN = "Children Ext"
101
99
BROWSEABLE = "Browseable Ext"
100
+ ITEM_SEARCH_FILTER = "Item Search - Filter Ext"
101
+ ITEM_SEARCH_SORT = "Item Search - Sort Ext"
102
+ ITEM_SEARCH_FIELDS = "Item Search - Fields Ext"
103
+ ITEM_SEARCH_QUERY = "Item Search - Query Ext"
104
+ FEATURES_FILTER = "Features - Filter Ext"
105
+ FEATURES_SORT = "Features - Sort Ext"
106
+ FEATURES_FIELDS = "Features - Fields Ext"
107
+ FEATURES_QUERY = "Features - Query Ext"
108
+ FEATURES_TXN = "Features - Transaction Ext"
102
109
103
110
def __str__ (self ) -> str :
104
111
return self .value
@@ -148,19 +155,14 @@ def __iadd__(self, x: Union[Tuple[str, str], str]) -> "Warnings":
148
155
cc_core_regex = re .compile (r"https://api\.stacspec\.org/(.+)/core" )
149
156
cc_browseable_regex = re .compile (r"https://api\.stacspec\.org/(.+)/browseable" )
150
157
cc_children_regex = re .compile (r"https://api\.stacspec\.org/(.+)/children" )
151
-
152
158
cc_collections_regex = re .compile (r"https://api\.stacspec\.org/(.+)/collections" )
153
-
154
159
cc_features_regex = re .compile (r"https://api\.stacspec\.org/(.+)/ogcapi-features" )
155
160
cc_features_transaction_regex = re .compile (
156
161
r"https://api\.stacspec\.org/(.+)/ogcapi-features/extensions/transaction"
157
162
)
158
163
cc_features_fields_regex = re .compile (
159
164
r"https://api\.stacspec\.org/(.+)/ogcapi-features#fields"
160
165
)
161
- cc_features_context_regex = re .compile (
162
- r"https://api\.stacspec\.org/(.+)/ogcapi-features#context"
163
- )
164
166
cc_features_sort_regex = re .compile (
165
167
r"https://api\.stacspec\.org/(.+)/ogcapi-features#sort"
166
168
)
@@ -172,13 +174,9 @@ def __iadd__(self, x: Union[Tuple[str, str], str]) -> "Warnings":
172
174
)
173
175
174
176
cc_item_search_regex = re .compile (r"https://api\.stacspec\.org/(.+)/item-search" )
175
-
176
177
cc_item_search_fields_regex = re .compile (
177
178
r"https://api\.stacspec\.org/(.+)/item-search#fields"
178
179
)
179
- cc_item_search_context_regex = re .compile (
180
- r"https://api\.stacspec\.org/(.+)/item-search#context"
181
- )
182
180
cc_item_search_sort_regex = re .compile (
183
181
r"https://api\.stacspec\.org/(.+)/item-search#sort"
184
182
)
@@ -333,13 +331,17 @@ def stac_check(
333
331
context : Context ,
334
332
method : Method = Method .GET ,
335
333
) -> None :
336
- linter = Linter (url )
337
- if not linter .valid_stac :
338
- errors += (
339
- f"[{ context } ] { method } { url } is not a valid STAC object: { linter .error_msg } "
340
- )
341
- if msgs := linter .best_practices_msg [1 :]: # first msg is a header
342
- warnings += f"[{ context } ] { method } { url } has these stac-check recommendations: { '' .join (msgs )} "
334
+ try :
335
+ linter = Linter (url )
336
+ if not linter .valid_stac :
337
+ errors += f"[{ context } ] { method } { url } is not a valid STAC object: { linter .error_msg } "
338
+ if msgs := linter .best_practices_msg [1 :]: # first msg is a header, so skip
339
+ warnings += f"[{ context } ] { method } { url } has these stac-check recommendations: { ',' .join ([x .strip () for x in msgs ])} "
340
+ except KeyError as e :
341
+ # see https://github.com/stac-utils/stac-check/issues/104
342
+ errors += f"[{ Context .CORE } ] Error running stac-check, probably because an item doesn't have a bbox defined, which is okay!: { e } "
343
+ except Exception as e :
344
+ errors += f"[{ Context .CORE } ] Error while running stac-check: { e } "
343
345
344
346
345
347
def retrieve (
@@ -423,7 +425,7 @@ def validate_core_landing_page_body(
423
425
):
424
426
warnings += "STAC API Specification v1.0.0-rc.2 is the latest version, but API advertises an older version or older versions."
425
427
426
- if not any ( cc_core_regex . fullmatch ( x ) for x in conforms_to ):
428
+ if not supports ( conforms_to , cc_core_regex ):
427
429
errors += ("CORE-4" , "/: STAC API - Core not contained in 'conformsTo'" )
428
430
429
431
if "browseable" in conformance_classes and not any (
@@ -467,7 +469,7 @@ def validate_core_landing_page_body(
467
469
return False
468
470
469
471
if "item-search" in conformance_classes :
470
- if not any ( cc_item_search_regex . fullmatch ( x ) for x in conforms_to ):
472
+ if not supports ( conforms_to , cc_item_search_regex ):
471
473
errors += (
472
474
"CORE-9" ,
473
475
"/: Item Search configured for validation, but not contained in 'conformsTo'" ,
@@ -483,12 +485,20 @@ def validate_core_landing_page_body(
483
485
)
484
486
return False
485
487
488
+ if "children" in conformance_classes and not any (
489
+ cc_children_regex .fullmatch (x ) for x in conforms_to
490
+ ):
491
+ errors += (
492
+ "CORE-6" ,
493
+ "/: Children configured for validation, but not contained in 'conformsTo'" ,
494
+ )
495
+
486
496
return True
487
497
488
498
489
499
def validate_api (
490
500
root_url : str ,
491
- conformance_classes : List [str ],
501
+ ccs_to_validate : List [str ],
492
502
collection : Optional [str ],
493
503
geometry : Optional [str ],
494
504
auth_bearer_token : Optional [str ],
@@ -520,7 +530,7 @@ def validate_api(
520
530
landing_page_headers ,
521
531
errors ,
522
532
warnings ,
523
- conformance_classes ,
533
+ ccs_to_validate ,
524
534
collection ,
525
535
geometry ,
526
536
):
@@ -529,21 +539,21 @@ def validate_api(
529
539
logger .info ("Validating STAC API - Core conformance class." )
530
540
validate_core (landing_page_body , errors , warnings , r_session )
531
541
532
- if "browseable" in conformance_classes :
542
+ if "browseable" in ccs_to_validate :
533
543
logger .info ("Validating STAC API - Browseable conformance class." )
534
544
validate_browseable (landing_page_body , errors , warnings , r_session )
535
545
536
- if "children" in conformance_classes :
546
+ if "children" in ccs_to_validate :
537
547
logger .info ("Validating STAC API - Children conformance class." )
538
548
validate_children (landing_page_body , errors , warnings , r_session )
539
549
540
- if "collections" in conformance_classes :
550
+ if "collections" in ccs_to_validate :
541
551
logger .info ("Validating STAC API - Collections conformance class." )
542
552
validate_collections (landing_page_body , collection , errors , warnings , r_session )
543
553
544
554
conforms_to = landing_page_body .get ("conformsTo" , [])
545
555
546
- if "features" in conformance_classes :
556
+ if "features" in ccs_to_validate :
547
557
logger .info ("Validating STAC API - Features conformance class." )
548
558
validate_collections (landing_page_body , collection , errors , warnings , r_session )
549
559
validate_features (
@@ -556,7 +566,7 @@ def validate_api(
556
566
r_session ,
557
567
)
558
568
559
- if "item-search" in conformance_classes :
569
+ if "item-search" in ccs_to_validate :
560
570
logger .info ("Validating STAC API - Item Search conformance class." )
561
571
validate_item_search (
562
572
root_url = root_url ,
@@ -566,7 +576,7 @@ def validate_api(
566
576
warnings = warnings ,
567
577
errors = errors ,
568
578
geometry = geometry , # type:ignore
569
- conformance_classes = conformance_classes ,
579
+ conformance_classes = ccs_to_validate ,
570
580
r_session = r_session ,
571
581
)
572
582
@@ -685,6 +695,11 @@ def validate_core(
685
695
f"[{ Context .CORE } ] Error while traversing Catalog child/item links to find Items: { e } "
686
696
"This can be reproduced with 'list(pystac.Catalog.from_file(root_url).get_all_items())'"
687
697
)
698
+ except UnicodeEncodeError as e :
699
+ # see https://github.com/jjrom/resto/issues/356#issuecomment-1443818163
700
+ errors += f"[{ Context .CORE } ] Error while traversing Catalog, a non-ascii character is encoded incorrectly somewhere: { e } "
701
+ except Exception as e :
702
+ errors += f"[{ Context .CORE } ] Error while traversing Catalog with pystac: { e } "
688
703
689
704
690
705
def validate_browseable (
@@ -1101,24 +1116,25 @@ def validate_features(
1101
1116
r_session = r_session ,
1102
1117
)
1103
1118
1104
- # Validate Extensions
1105
- #
1106
- # if any(cc_features_fields_regex.fullmatch(x) for x in conforms_to):
1107
- # logger.info("STAC API - Features - Fields extension conformance class found.")
1108
- #
1109
- # if any(cc_features_context_regex.fullmatch(x) for x in conforms_to):
1110
- # logger.info("STAC API - Features - Context extension conformance class found.")
1111
- #
1112
- # if any(cc_features_sort_regex.fullmatch(x) for x in conforms_to):
1113
- # logger.info("STAC API - Features - Sort extension conformance class found.")
1114
- #
1115
- # if any(cc_features_query_regex.fullmatch(x) for x in conforms_to):
1116
- # logger.info("STAC API - Features - Query extension conformance class found.")
1117
- #
1118
- # if any(cc_features_filter_regex.fullmatch(x) for x in conforms_to):
1119
- # logger.info("STAC API - Features - Filter extension conformance class found.")
1120
-
1121
- if any (cc_features_filter_regex .fullmatch (x ) for x in conforms_to ):
1119
+ if supports (conforms_to , cc_features_fields_regex ):
1120
+ logger .info ("STAC API - Features - Fields extension conformance class found." )
1121
+ logger .info ("STAC API - Features - Fields extension is not yet supported." )
1122
+
1123
+ if supports (conforms_to , cc_features_transaction_regex ):
1124
+ logger .info (
1125
+ "STAC API - Features - Transaction extension conformance class found."
1126
+ )
1127
+ logger .info ("STAC API - Features - Transaction extension is not yet supported." )
1128
+
1129
+ if supports (conforms_to , cc_features_sort_regex ):
1130
+ logger .info ("STAC API - Features - Sort extension conformance class found." )
1131
+ logger .info ("STAC API - Features - Sort extension is not yet supported." )
1132
+
1133
+ if supports (conforms_to , cc_features_query_regex ):
1134
+ logger .info ("STAC API - Features - Query extension conformance class found." )
1135
+ logger .info ("STAC API - Features - Query extension is not yet supported." )
1136
+
1137
+ if supports (conforms_to , cc_features_filter_regex ):
1122
1138
logger .info ("STAC API - Features - Filter Extension conformance class found." )
1123
1139
validate_features_filter (
1124
1140
root_body = root_body ,
@@ -1218,18 +1234,16 @@ def validate_item_search(
1218
1234
r_session = r_session ,
1219
1235
)
1220
1236
1221
- # if any(cc_item_search_fields_regex.fullmatch(x) for x in conforms_to):
1222
- # logger.info("STAC API - Item Search - Fields extension conformance class found.")
1223
- #
1224
- # if any(cc_item_search_context_regex.fullmatch(x) for x in conforms_to):
1225
- # logger.info("STAC API - Item Search - Context extension conformance class found.")
1226
- #
1227
- # if any(cc_item_search_sort_regex.fullmatch(x) for x in conforms_to):
1228
- # logger.info("STAC API - Item Search - Sort extension conformance class found.")
1229
- #
1230
- # if any(cc_item_search_query_regex.fullmatch(x) for x in conforms_to):
1231
- # logger.info("STAC API - Item Search - Query extension conformance class found.")
1232
- #
1237
+ if supports (conforms_to , cc_item_search_fields_regex ):
1238
+ logger .info (
1239
+ "STAC API - Item Search - Fields extension conformance class found."
1240
+ )
1241
+
1242
+ if supports (conforms_to , cc_item_search_sort_regex ):
1243
+ logger .info ("STAC API - Item Search - Sort extension conformance class found." )
1244
+
1245
+ if supports (conforms_to , cc_item_search_query_regex ):
1246
+ logger .info ("STAC API - Item Search - Query extension conformance class found." )
1233
1247
1234
1248
if any (
1235
1249
x .endswith ("item-search#filter:basic-cql" )
0 commit comments