Skip to content

Commit 9d6b146

Browse files
jsignellgadomski
andauthored
Allow future extensions to be used (#1231)
* Allow future extensions to be used * Pre-compile the regex * Update changelog --------- Co-authored-by: Pete Gadomski <pete.gadomski@gmail.com>
1 parent 0984fac commit 9d6b146

File tree

11 files changed

+81
-12
lines changed

11 files changed

+81
-12
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## [Unreleased]
44

5+
### Added
6+
7+
- More permissive schema_uri matching to allow future versions of extension schemas ([#1231](https://github.com/stac-utils/pystac/pull/1231))
8+
59
## [v1.8.4] - 2023-09-22
610

711
### Added

pystac/extensions/base.py

+11-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import re
2+
import warnings
13
from abc import ABC, abstractmethod
24
from typing import (
35
Any,
@@ -14,6 +16,8 @@
1416

1517
import pystac
1618

19+
VERSION_REGEX = re.compile("/v[0-9].[0-9].*/")
20+
1721

1822
class SummariesExtension:
1923
"""Base class for extending the properties in :attr:`pystac.Collection.summaries`
@@ -115,6 +119,10 @@ def get_schema_uri(cls) -> str:
115119
@classmethod
116120
def get_schema_uris(cls) -> List[str]:
117121
"""Gets a list of schema URIs associated with this extension."""
122+
warnings.warn(
123+
"get_schema_uris is deprecated and will be removed in v2",
124+
DeprecationWarning,
125+
)
118126
return [cls.get_schema_uri()]
119127

120128
@classmethod
@@ -140,8 +148,10 @@ def remove_from(cls, obj: S) -> None:
140148
def has_extension(cls, obj: S) -> bool:
141149
"""Check if the given object implements this extension by checking
142150
:attr:`pystac.STACObject.stac_extensions` for this extension's schema URI."""
151+
schema_startswith = re.split(VERSION_REGEX, cls.get_schema_uri())[0] + "/"
152+
143153
return obj.stac_extensions is not None and any(
144-
uri in obj.stac_extensions for uri in cls.get_schema_uris()
154+
uri.startswith(schema_startswith) for uri in obj.stac_extensions
145155
)
146156

147157
@classmethod

pystac/extensions/classification.py

+10-3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from __future__ import annotations
44

55
import re
6+
import warnings
67
from typing import (
78
Any,
89
Dict,
@@ -510,6 +511,10 @@ def get_schema_uri(cls) -> str:
510511

511512
@classmethod
512513
def get_schema_uris(cls) -> List[str]:
514+
warnings.warn(
515+
"get_schema_uris is deprecated and will be removed in v2",
516+
DeprecationWarning,
517+
)
513518
return [SCHEMA_URI_PATTERN.format(version=v) for v in SUPPORTED_VERSIONS]
514519

515520
@classmethod
@@ -637,9 +642,11 @@ def bitfields(self, v: Optional[List[Bitfield]]) -> None:
637642

638643
class ClassificationExtensionHooks(ExtensionHooks):
639644
schema_uri: str = SCHEMA_URI_PATTERN.format(version=DEFAULT_VERSION)
640-
prev_extension_ids = set(ClassificationExtension.get_schema_uris()) - set(
641-
[ClassificationExtension.get_schema_uri()]
642-
)
645+
prev_extension_ids = {
646+
SCHEMA_URI_PATTERN.format(version=v)
647+
for v in SUPPORTED_VERSIONS
648+
if v != DEFAULT_VERSION
649+
}
643650
stac_object_types = {pystac.STACObjectType.ITEM}
644651

645652
def migrate(

pystac/extensions/eo.py

+5
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
from __future__ import annotations
44

5+
import warnings
56
from typing import (
67
Any,
78
Dict,
@@ -385,6 +386,10 @@ def get_schema_uri(cls) -> str:
385386

386387
@classmethod
387388
def get_schema_uris(cls) -> List[str]:
389+
warnings.warn(
390+
"get_schema_uris is deprecated and will be removed in v2",
391+
DeprecationWarning,
392+
)
388393
return SCHEMA_URIS
389394

390395
@classmethod

pystac/extensions/grid.py

+5
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from __future__ import annotations
44

55
import re
6+
import warnings
67
from typing import Any, Dict, List, Optional, Pattern, Set, Union
78

89
import pystac
@@ -86,6 +87,10 @@ def get_schema_uri(cls) -> str:
8687

8788
@classmethod
8889
def get_schema_uris(cls) -> List[str]:
90+
warnings.warn(
91+
"get_schema_uris is deprecated and will be removed in v2",
92+
DeprecationWarning,
93+
)
8994
return SCHEMA_URIS
9095

9196
@classmethod

pystac/extensions/label.py

+5
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
from __future__ import annotations
44

5+
import warnings
56
from typing import Any, Dict, Iterable, List, Optional, Sequence, Union, cast
67

78
import pystac
@@ -696,6 +697,10 @@ def get_schema_uri(cls) -> str:
696697

697698
@classmethod
698699
def get_schema_uris(cls) -> List[str]:
700+
warnings.warn(
701+
"get_schema_uris is deprecated and will be removed in v2",
702+
DeprecationWarning,
703+
)
699704
return SCHEMA_URIS
700705

701706
@classmethod

pystac/extensions/mgrs.py

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from pystac.extensions.hooks import ExtensionHooks
99

1010
SCHEMA_URI: str = "https://stac-extensions.github.io/mgrs/v1.0.0/schema.json"
11+
SCHEMA_STARTSWITH: str = "https://stac-extensions.github.io/mgrs/"
1112
PREFIX: str = "mgrs:"
1213

1314
# Field names

pystac/extensions/projection.py

+5
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from __future__ import annotations
44

55
import json
6+
import warnings
67
from typing import Any, Dict, Generic, Iterable, List, Optional, TypeVar, Union, cast
78

89
import pystac
@@ -265,6 +266,10 @@ def get_schema_uri(cls) -> str:
265266

266267
@classmethod
267268
def get_schema_uris(cls) -> List[str]:
269+
warnings.warn(
270+
"get_schema_uris is deprecated and will be removed in v2",
271+
DeprecationWarning,
272+
)
268273
return SCHEMA_URIS
269274

270275
@classmethod

pystac/extensions/raster.py

+6
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
from __future__ import annotations
44

5+
import warnings
56
from typing import (
67
Any,
78
Dict,
@@ -32,6 +33,7 @@
3233
"https://stac-extensions.github.io/raster/v1.0.0/schema.json",
3334
SCHEMA_URI,
3435
]
36+
SCHEMA_STARTWITH = "https://stac-extensions.github.io/raster/"
3537
BANDS_PROP = "raster:bands"
3638

3739

@@ -715,6 +717,10 @@ def get_schema_uri(cls) -> str:
715717

716718
@classmethod
717719
def get_schema_uris(cls) -> List[str]:
720+
warnings.warn(
721+
"get_schema_uris is deprecated and will be removed in v2",
722+
DeprecationWarning,
723+
)
718724
return SCHEMA_URIS
719725

720726
@classmethod

tests/extensions/test_classification.py

+7-6
Original file line numberDiff line numberDiff line change
@@ -94,12 +94,13 @@ def test_bitfield_object() -> None:
9494

9595

9696
def test_get_schema_uri(landsat_item: Item) -> None:
97-
assert any(
98-
[
99-
uri in landsat_item.stac_extensions
100-
for uri in ClassificationExtension.get_schema_uris()
101-
]
102-
)
97+
with pytest.raises(DeprecationWarning):
98+
assert any(
99+
[
100+
uri in landsat_item.stac_extensions
101+
for uri in ClassificationExtension.get_schema_uris()
102+
]
103+
)
103104

104105

105106
def test_ext_raises_if_item_does_not_conform(plain_item: Item) -> None:

tests/extensions/test_projection.py

+22-2
Original file line numberDiff line numberDiff line change
@@ -552,10 +552,10 @@ def test_summaries_adds_uri(self) -> None:
552552

553553
def test_older_extension_version(projection_landsat8_item: Item) -> None:
554554
old = "https://stac-extensions.github.io/projection/v1.0.0/schema.json"
555-
new = "https://stac-extensions.github.io/projection/v1.1.0/schema.json"
555+
current = "https://stac-extensions.github.io/projection/v1.1.0/schema.json"
556556

557557
stac_extensions = set(projection_landsat8_item.stac_extensions)
558-
stac_extensions.remove(new)
558+
stac_extensions.remove(current)
559559
stac_extensions.add(old)
560560
item_as_dict = projection_landsat8_item.to_dict(
561561
include_self_link=False, transform_hrefs=False
@@ -565,6 +565,26 @@ def test_older_extension_version(projection_landsat8_item: Item) -> None:
565565
assert ProjectionExtension.has_extension(item)
566566
assert old in item.stac_extensions
567567

568+
migrated_item = pystac.Item.from_dict(item_as_dict, migrate=True)
569+
assert ProjectionExtension.has_extension(migrated_item)
570+
assert current in migrated_item.stac_extensions
571+
572+
573+
def test_newer_extension_version(projection_landsat8_item: Item) -> None:
574+
new = "https://stac-extensions.github.io/projection/v2.0.0/schema.json"
575+
current = "https://stac-extensions.github.io/projection/v1.1.0/schema.json"
576+
577+
stac_extensions = set(projection_landsat8_item.stac_extensions)
578+
stac_extensions.remove(current)
579+
stac_extensions.add(new)
580+
item_as_dict = projection_landsat8_item.to_dict(
581+
include_self_link=False, transform_hrefs=False
582+
)
583+
item_as_dict["stac_extensions"] = list(stac_extensions)
584+
item = Item.from_dict(item_as_dict)
585+
assert ProjectionExtension.has_extension(item)
586+
assert new in item.stac_extensions
587+
568588
migrated_item = pystac.Item.from_dict(item_as_dict, migrate=True)
569589
assert ProjectionExtension.has_extension(migrated_item)
570590
assert new in migrated_item.stac_extensions

0 commit comments

Comments
 (0)