Skip to content

Commit 28a9e45

Browse files
committed
Configure whether to open assets URLs during validation, and http headers
1 parent 08968fa commit 28a9e45

File tree

2 files changed

+97
-14
lines changed

2 files changed

+97
-14
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ PyYAML = "^6.0.1"
2525
Shapely = ">=1.8.4"
2626
more_itertools = ">=8.14,<11.0"
2727
stac-check = "^1.3.1"
28-
stac-validator = "^3.2.0"
28+
stac-validator = "^3.4.0"
2929
deepdiff = ">=6.2.3,<9.0.0"
3030

3131
[tool.poetry.dev-dependencies]

src/stac_api_validator/validations.py

Lines changed: 96 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,8 @@ def stac_validate(
331331
errors: Errors,
332332
context: Context,
333333
method: Method = Method.GET,
334+
open_assets_urls: bool = True,
335+
headers: dict = {},
334336
) -> None:
335337
if not body:
336338
errors += f"[{context}] : {method} {url} body was empty when running stac-validate and stac-check"
@@ -350,8 +352,14 @@ def stac_validate(
350352
errors += f"[{context}] : {method} {url} '{body.get('id')}' failed pystac hydration: {e}"
351353

352354
if _type in ["Collection", "Feature"]:
355+
logger.debug(f"stac-validator validation: {url}")
353356
if not (
354-
stac_validator := StacValidate(links=True, assets=True)
357+
stac_validator := StacValidate(
358+
links=True,
359+
assets=True,
360+
assets_open_urls=open_assets_urls,
361+
headers=headers,
362+
)
355363
).validate_dict(body):
356364
errors += f"[{context}] : {method} {url} failed stac-validator validation: {stac_validator.message}"
357365

@@ -365,9 +373,11 @@ def stac_check(
365373
warnings: Warnings,
366374
context: Context,
367375
method: Method = Method.GET,
376+
open_assets_urls: bool = True,
377+
headers: dict = {},
368378
) -> None:
369379
try:
370-
linter = Linter(url)
380+
linter = Linter(url, assets_open_urls=open_assets_urls, headers=headers)
371381
if not linter.valid_stac:
372382
errors += f"[{context}] : {method} {url} is not a valid STAC object: {linter.error_msg}"
373383
if msgs := linter.best_practices_msg[1:]: # first msg is a header, so skip
@@ -548,6 +558,7 @@ def validate_api(
548558
query_config: QueryConfig,
549559
transaction_collection: Optional[str],
550560
headers: Optional[Dict[str, str]],
561+
open_assets_urls: bool = True,
551562
) -> Tuple[Warnings, Errors]:
552563
warnings = Warnings()
553564
errors = Errors()
@@ -598,13 +609,17 @@ def validate_api(
598609

599610
if "collections" in ccs_to_validate:
600611
logger.info("Validating STAC API - Collections conformance class.")
601-
validate_collections(landing_page_body, collection, errors, warnings, r_session)
612+
validate_collections(
613+
landing_page_body, collection, errors, warnings, r_session, open_assets_urls
614+
)
602615

603616
conforms_to = landing_page_body.get("conformsTo", [])
604617

605618
if "features" in ccs_to_validate:
606619
logger.info("Validating STAC API - Features conformance class.")
607-
validate_collections(landing_page_body, collection, errors, warnings, r_session)
620+
validate_collections(
621+
landing_page_body, collection, errors, warnings, r_session, open_assets_urls
622+
)
608623
validate_features(
609624
landing_page_body,
610625
conforms_to,
@@ -613,7 +628,8 @@ def validate_api(
613628
warnings,
614629
errors,
615630
r_session,
616-
validate_pagination=validate_pagination,
631+
validate_pagination,
632+
open_assets_urls,
617633
)
618634

619635
if "transaction" in ccs_to_validate:
@@ -664,6 +680,7 @@ def validate_api(
664680
conformance_classes=ccs_to_validate,
665681
r_session=r_session,
666682
validate_pagination=validate_pagination,
683+
open_assets_urls=open_assets_urls,
667684
)
668685

669686
if "item-search#fields" in ccs_to_validate:
@@ -963,6 +980,7 @@ def validate_collections(
963980
errors: Errors,
964981
warnings: Warnings,
965982
r_session: Session,
983+
open_assets_urls: bool = True,
966984
) -> None:
967985
if not (data_link := link_by_rel(root_body["links"], "data")):
968986
errors += f"[{Context.COLLECTIONS}] /: Link[rel=data] must href /collections"
@@ -1019,7 +1037,15 @@ def validate_collections(
10191037
)
10201038
else:
10211039
for body in collections_list:
1022-
stac_validate(collections_url, body, errors, Context.COLLECTIONS)
1040+
stac_validate(
1041+
collections_url,
1042+
body,
1043+
errors,
1044+
Context.COLLECTIONS,
1045+
Method.GET,
1046+
open_assets_urls,
1047+
r_session.headers,
1048+
)
10231049

10241050
collection_url = f"{data_link['href']}/{collection}"
10251051
_, body, resp_headers = retrieve(
@@ -1047,8 +1073,24 @@ def validate_collections(
10471073
if not link_by_rel(body.get("links", []), "parent"):
10481074
errors += f"[{Context.COLLECTIONS}] : {collection_url} does not have parent link"
10491075

1050-
stac_validate(collection_url, body, errors, Context.COLLECTIONS)
1051-
stac_check(collection_url, errors, warnings, Context.COLLECTIONS)
1076+
stac_validate(
1077+
collection_url,
1078+
body,
1079+
errors,
1080+
Context.COLLECTIONS,
1081+
Method.GET,
1082+
open_assets_urls,
1083+
r_session.headers,
1084+
)
1085+
stac_check(
1086+
collection_url,
1087+
errors,
1088+
warnings,
1089+
Context.COLLECTIONS,
1090+
Method.GET,
1091+
open_assets_urls,
1092+
r_session.headers,
1093+
)
10521094

10531095
# todo: collection pagination
10541096

@@ -1062,6 +1104,7 @@ def validate_features(
10621104
errors: Errors,
10631105
r_session: Session,
10641106
validate_pagination: bool,
1107+
open_assets_urls: bool = True,
10651108
) -> None:
10661109
if not geometry:
10671110
errors += f"[{Context.FEATURES}] Geometry parameter required for running Features validations."
@@ -1132,7 +1175,15 @@ def validate_features(
11321175
if not body:
11331176
errors += f"[{Context.FEATURES}] GET {collection_items_url} returned an empty body"
11341177
else:
1135-
stac_validate(collection_items_url, body, errors, Context.FEATURES)
1178+
stac_validate(
1179+
collection_items_url,
1180+
body,
1181+
errors,
1182+
Context.FEATURES,
1183+
Method.GET,
1184+
open_assets_urls,
1185+
r_session.headers,
1186+
)
11361187

11371188
item_url = link_by_rel(body.get("features", [])[0]["links"], "self")[
11381189
"href"
@@ -1147,7 +1198,15 @@ def validate_features(
11471198
r_session=r_session,
11481199
)
11491200

1150-
stac_validate(item_url, body, errors, Context.FEATURES)
1201+
stac_validate(
1202+
item_url,
1203+
body,
1204+
errors,
1205+
Context.FEATURES,
1206+
Method.GET,
1207+
open_assets_urls,
1208+
r_session.headers,
1209+
)
11511210
stac_check(item_url, errors, warnings, Context.FEATURES)
11521211

11531212
# Validate Features non-existent item
@@ -1195,7 +1254,15 @@ def validate_features(
11951254
if not link_by_rel(body.get("links", []), "root"):
11961255
errors += f"[{Context.FEATURES}] GET {collection_items_url} does not have root link"
11971256

1198-
stac_validate(collection_items_url, body, errors, Context.FEATURES)
1257+
stac_validate(
1258+
collection_items_url,
1259+
body,
1260+
errors,
1261+
Context.FEATURES,
1262+
Method.GET,
1263+
open_assets_urls,
1264+
r_session.headers,
1265+
)
11991266

12001267
item = next(iter(body.get("features", [])), None)
12011268

@@ -1233,7 +1300,15 @@ def validate_features(
12331300
if not link_by_rel(body.get("links", []), "parent"):
12341301
errors += f"[{Context.FEATURES}] GET {item_url} does not have parent link"
12351302

1236-
stac_validate(item_url, body, errors, Context.FEATURES)
1303+
stac_validate(
1304+
item_url,
1305+
body,
1306+
errors,
1307+
Context.FEATURES,
1308+
Method.GET,
1309+
open_assets_urls,
1310+
r_session.headers,
1311+
)
12371312
stac_check(item_url, errors, warnings, Context.FEATURES)
12381313

12391314
if validate_pagination:
@@ -1270,6 +1345,7 @@ def validate_item_search(
12701345
conformance_classes: List[str],
12711346
r_session: Session,
12721347
validate_pagination: bool,
1348+
open_assets_urls: bool = True,
12731349
) -> None:
12741350
links = root_body.get("links")
12751351

@@ -1317,7 +1393,14 @@ def validate_item_search(
13171393
)
13181394

13191395
if body:
1320-
stac_validate(search_url, body, errors, Context.ITEM_SEARCH)
1396+
stac_validate(
1397+
search_url,
1398+
body,
1399+
errors,
1400+
Context.ITEM_SEARCH,
1401+
open_assets_urls,
1402+
r_session.headers,
1403+
)
13211404

13221405
validate_item_search_limit(search_url, methods, errors, r_session)
13231406
validate_item_search_bbox_xor_intersects(search_url, methods, errors, r_session)

0 commit comments

Comments
 (0)