diff --git a/.flake8 b/.flake8 index f31f62798..c5ab79442 100644 --- a/.flake8 +++ b/.flake8 @@ -1,14 +1,3 @@ [flake8] -max-line-length = 100 - -## IGNORES - -# E126: yapf conflicts with "continuation line over-indented for hanging indent" - -# E127: flake8 reporting incorrect continuation line indent errors -# on multi-line and multi-level indents - -# W503: flake8 reports this as incorrect, and scripts/format_code -# changes code to it, so let format_code win. - -ignore = E126,E127,W503 \ No newline at end of file +max-line-length = 88 +extend-ignore = E203, W503, E731, E722 \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d6d1eef6..3046532d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,12 +4,26 @@ ### Added +- Added type annotations across the library ([#309](https://github.com/stac-utils/pystac/pull/309)) +- Added assets to collections ([#309](https://github.com/stac-utils/pystac/pull/309)) +- `item_assets` extension ([#309](https://github.com/stac-utils/pystac/pull/309)) +- `datacube` extension ([#309](https://github.com/stac-utils/pystac/pull/309)) +- Added specific errors: `ExtensionAlreadyExistsError`, `ExtensionTypeError`, and `RequiredPropertyMissing`; moved custom exceptions to `pystac.errors` ([#309](https://github.com/stac-utils/pystac/pull/309)) + ### Fixed ### Changed +- API change: The extension API changed significantly. See ([#309](https://github.com/stac-utils/pystac/pull/309)) for more details. +- API change: Refactored the global STAC_IO object to an instance-specific `StacIO` implementation. STAC_IO is deprecated and will be removed next release. ([#309](https://github.com/stac-utils/pystac/pull/309)) +- Asset.get_absolute_href returns None if no absolute href can be inferred (previously the relative href that was passed in was returned) ([#309](https://github.com/stac-utils/pystac/pull/309)) + ### Removed +- Removed `properties` from Collections ([#309](https://github.com/stac-utils/pystac/pull/309)) +- Removed `LinkMixin`, and implemented those methods on `STACObject` directly. STACObject was the only class using LinkMixin and this should not effect users ([#309](https://github.com/stac-utils/pystac/pull/309) +- Removed `single-file-stac` extension; this extension is being removed in favor of ItemCollection usage ([#309](https://github.com/stac-utils/pystac/pull/309) + ## [v0.5.6] ### Added diff --git a/README.md b/README.md index da67308aa..4e6e96de2 100644 --- a/README.md +++ b/README.md @@ -114,6 +114,14 @@ To build and develop the documentation locally, make sure sphinx is available (w > make livehtml ``` +> Note: You will see some warnings along the lines of +> ``` +> WARNING: duplicate object description of pystac.Collection.id, +> other instance in api, use :noindex: for one of them +> ``` +> for some of the +> classes. This is expected due to [sphinx-doc/sphinx#8664](https://github.com/sphinx-doc/sphinx/issues/8664). + Use 'make' without arguments to see a list of available commands. __Note__: `nbsphinx` requires that a local `pystac` is installed; use `pip install -e .`. diff --git a/docs/api.rst b/docs/api.rst index 74a304fdc..9279dfbb1 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -127,13 +127,6 @@ Link :members: :undoc-members: -LinkType -~~~~~~~~ - -.. autoclass:: pystac.LinkType - :members: - :undoc-members: - MediaType ~~~~~~~~~ @@ -149,7 +142,7 @@ STAC_IO STAC_IO is the utility mechanism that PySTAC uses for reading and writing. Users of PySTAC can hook into PySTAC by overriding members to utilize their own IO methods. -.. autoclass:: pystac.STAC_IO +.. autoclass:: pystac.stac_io.STAC_IO :members: :undoc-members: @@ -193,17 +186,20 @@ ExtensionError Extensions ---------- -.. autoclass:: pystac.extensions.Extensions - :members: - :undoc-members: +**TEMPORARILY REMOVED** +.. .. autoclass:: pystac.extensions.Extensions +.. :members: +.. :undoc-members: ExtensionIndex ~~~~~~~~~~~~~~ -An ExtensionIndex is accessed through the :attr:`STACObject.ext ` property and is the primary way to access information and functionality around STAC extensions. +**TEMPORARILY REMOVED** + +.. An ExtensionIndex is accessed through the :attr:`STACObject.ext ` property and is the primary way to access information and functionality around STAC extensions. -.. autoclass:: pystac.stac_object.ExtensionIndex - :members: __getitem__, __getattr__, enable, implements +.. .. autoclass:: pystac.stac_object.ExtensionIndex +.. :members: __getitem__, __getattr__, enable, implements EO Extension @@ -214,17 +210,21 @@ These classes are representations of the `EO Extension Spec `_. -.. automodule:: pystac.extensions.single_file_stac - :members: create_single_file_stac +**TEMPORARILY REMOVED** + +.. .. automodule:: pystac.extensions.single_file_stac +.. :members: create_single_file_stac SingleFileSTACCatalogExt ~~~~~~~~~~~~~~~~~~~~~~~~ -.. autoclass:: pystac.extensions.single_file_stac.SingleFileSTACCatalogExt - :members: - :undoc-members: +**TEMPORARILY REMOVED** + +.. .. autoclass:: pystac.extensions.single_file_stac.SingleFileSTACCatalogExt +.. :members: +.. :undoc-members: Version Extension ----------------- @@ -363,18 +379,22 @@ Implements the `Version Extension `_ and the relevant `Best Practices `_ for more information. +See the STAC documentation on `Additional Fields for Assets `_ and the relevant `Best Practices `__ for more information. The implementation of this feature in PySTAC uses the method described here and is consistent across Item and ItemExtensions. The bare property names represent values for the Item only, but for each property where it is possible to set on both the Item or the Asset there is a ``get_`` and ``set_`` methods that optionally take an Asset. For the ``get_`` methods, if the property is found on the Asset, the Asset's value is used; otherwise the Item's value will be used. For the ``set_`` method, if an Asset is passed in the value will be applied to the Asset and not the Item. diff --git a/mypy.ini b/mypy.ini new file mode 100644 index 000000000..132834a06 --- /dev/null +++ b/mypy.ini @@ -0,0 +1,3 @@ +[mypy] +ignore_missing_imports = True +disallow_untyped_defs = True \ No newline at end of file diff --git a/pystac/__init__.py b/pystac/__init__.py index 529cdab4e..d9a17eb5f 100644 --- a/pystac/__init__.py +++ b/pystac/__init__.py @@ -3,59 +3,74 @@ """ # flake8: noqa - - -class STACError(Exception): - """A STACError is raised for errors relating to STAC, e.g. for - invalid formats or trying to operate on a STAC that does not have - the required information available. - """ - pass - - -from pystac.version import (__version__, get_stac_version, set_stac_version) -from pystac.stac_io import STAC_IO -from pystac.extensions import Extensions -from pystac.stac_object import (STACObject, STACObjectType) -from pystac.media_type import MediaType -from pystac.link import (Link, HIERARCHICAL_LINKS) -from pystac.catalog import (Catalog, CatalogType) -from pystac.collection import (Collection, Extent, SpatialExtent, TemporalExtent, Provider) -from pystac.item import (Item, Asset, CommonMetadata) - -from pystac.serialization import stac_object_from_dict +from pystac.errors import ( + STACError, # type:ignore + STACTypeError, # type:ignore + ExtensionAlreadyExistsError, # type:ignore + ExtensionTypeError, # type:ignore + RequiredPropertyMissing, # type:ignore + STACValidationError, # type:ignore +) + +from typing import Any, Dict, Optional +from pystac.version import ( + __version__, + get_stac_version, # type:ignore + set_stac_version, # type:ignore +) +from pystac.stac_io import StacIO # type:ignore +from pystac.stac_object import STACObject, STACObjectType # type:ignore +from pystac.media_type import MediaType # type:ignore +from pystac.link import Link, HIERARCHICAL_LINKS # type:ignore +from pystac.catalog import Catalog, CatalogType # type:ignore +from pystac.collection import ( + Collection, # type:ignore + Extent, # type:ignore + SpatialExtent, # type:ignore + TemporalExtent, # type:ignore + Provider, # type:ignore + Summaries, # type:ignore + RangeSummary, # type:ignore +) +from pystac.item import Item, Asset, CommonMetadata # type:ignore import pystac.validation -STAC_IO.stac_object_from_dict = stac_object_from_dict - -from pystac import extensions +import pystac.extensions.hooks +import pystac.extensions.datacube import pystac.extensions.eo +import pystac.extensions.file +import pystac.extensions.item_assets import pystac.extensions.label import pystac.extensions.pointcloud import pystac.extensions.projection import pystac.extensions.sar import pystac.extensions.sat import pystac.extensions.scientific -import pystac.extensions.single_file_stac import pystac.extensions.timestamps import pystac.extensions.version import pystac.extensions.view -import pystac.extensions.file - -STAC_EXTENSIONS = extensions.base.RegisteredSTACExtensions([ - extensions.eo.EO_EXTENSION_DEFINITION, extensions.label.LABEL_EXTENSION_DEFINITION, - extensions.pointcloud.POINTCLOUD_EXTENSION_DEFINITION, - extensions.projection.PROJECTION_EXTENSION_DEFINITION, extensions.sar.SAR_EXTENSION_DEFINITION, - extensions.sat.SAT_EXTENSION_DEFINITION, extensions.scientific.SCIENTIFIC_EXTENSION_DEFINITION, - extensions.single_file_stac.SFS_EXTENSION_DEFINITION, - extensions.timestamps.TIMESTAMPS_EXTENSION_DEFINITION, - extensions.version.VERSION_EXTENSION_DEFINITION, extensions.view.VIEW_EXTENSION_DEFINITION, - extensions.file.FILE_EXTENSION_DEFINITION -]) - -def read_file(href): +EXTENSION_HOOKS = pystac.extensions.hooks.RegisteredExtensionHooks( + [ + pystac.extensions.datacube.DATACUBE_EXTENSION_HOOKS, + pystac.extensions.eo.EO_EXTENSION_HOOKS, + pystac.extensions.file.FILE_EXTENSION_HOOKS, + pystac.extensions.item_assets.ITEM_ASSETS_EXTENSION_HOOKS, + pystac.extensions.label.LABEL_EXTENSION_HOOKS, + pystac.extensions.pointcloud.POINTCLOUD_EXTENSION_HOOKS, + pystac.extensions.projection.PROJECTION_EXTENSION_HOOKS, + pystac.extensions.sar.SAR_EXTENSION_HOOKS, + pystac.extensions.sat.SAT_EXTENSION_HOOKS, + pystac.extensions.scientific.SCIENTIFIC_EXTENSION_HOOKS, + pystac.extensions.timestamps.TIMESTAMPS_EXTENSION_HOOKS, + pystac.extensions.version.VERSION_EXTENSION_HOOKS, + pystac.extensions.view.VIEW_EXTENSION_HOOKS, + ] +) + + +def read_file(href: str) -> STACObject: """Reads a STAC object from a file. This method will return either a Catalog, a Collection, or an Item based on what the @@ -73,7 +88,9 @@ def read_file(href): return STACObject.from_file(href) -def write_file(obj, include_self_link=True, dest_href=None): +def write_file( + obj: STACObject, include_self_link: bool = True, dest_href: Optional[str] = None +) -> None: """Writes a STACObject to a file. This will write only the Catalog, Collection or Item ``obj``. It will not attempt @@ -96,7 +113,12 @@ def write_file(obj, include_self_link=True, dest_href=None): obj.save_object(include_self_link=include_self_link, dest_href=dest_href) -def read_dict(d, href=None, root=None): +def read_dict( + d: Dict[str, Any], + href: Optional[str] = None, + root: Optional[Catalog] = None, + stac_io: Optional[StacIO] = None, +) -> STACObject: """Reads a STAC object from a dict representing the serialized JSON version of the STAC object. @@ -112,5 +134,9 @@ def read_dict(d, href=None, root=None): root (Catalog or Collection): Optional root of the catalog for this object. If provided, the root's resolved object cache can be used to search for previously resolved instances of the STAC object. + stac_io: Optional StacIO instance to use for reading. If None, the + default instance will be used. """ - return stac_object_from_dict(d, href, root) + if stac_io is None: + stac_io = StacIO.default() + return stac_io.stac_object_from_dict(d, href, root) diff --git a/pystac/asset.py b/pystac/asset.py new file mode 100644 index 000000000..7c8353df3 --- /dev/null +++ b/pystac/asset.py @@ -0,0 +1,166 @@ +from copy import copy +from typing import Any, Dict, List, Optional, TYPE_CHECKING, Union + +import pystac +from pystac.utils import is_absolute_href, make_absolute_href + +if TYPE_CHECKING: + from pystac.collection import Collection as Collection_Type + from pystac.item import Item as Item_Type + + +class Asset: + """An object that contains a link to data associated with an Item or Collection that + can be downloaded or streamed. + + Args: + href (str): Link to the asset object. Relative and absolute links are both + allowed. + title (str): Optional displayed title for clients and users. + description (str): A description of the Asset providing additional details, + such as how it was processed or created. CommonMark 0.29 syntax MAY be used + for rich text representation. + media_type (str): Optional description of the media type. Registered Media Types + are preferred. See :class:`~pystac.MediaType` for common media types. + roles ([str]): Optional, Semantic roles (i.e. thumbnail, overview, + data, metadata) of the asset. + properties (dict): Optional, additional properties for this asset. This is used + by extensions as a way to serialize and deserialize properties on asset + object JSON. + + Attributes: + href (str): Link to the asset object. Relative and absolute links are both + allowed. + title (str): Optional displayed title for clients and users. + description (str): A description of the Asset providing additional details, + such as how it was processed or created. CommonMark 0.29 syntax MAY be + used for rich text representation. + media_type (str): Optional description of the media type. Registered Media Types + are preferred. See :class:`~pystac.MediaType` for common media types. + properties (dict): Optional, additional properties for this asset. This is used + by extensions as a way to serialize and deserialize properties on asset + object JSON. + owner: The Item or Collection this asset belongs to, or None if it has no owner. + """ + + def __init__( + self, + href: str, + title: Optional[str] = None, + description: Optional[str] = None, + media_type: Optional[str] = None, + roles: Optional[List[str]] = None, + properties: Optional[Dict[str, Any]] = None, + ) -> None: + self.href = href + self.title = title + self.description = description + self.media_type = media_type + self.roles = roles + + if properties is not None: + self.properties = properties + else: + self.properties = {} + + # The Item which owns this Asset. + self.owner: Optional[Union[pystac.Item, pystac.Collection]] = None + + def set_owner(self, obj: Union["Collection_Type", "Item_Type"]) -> None: + """Sets the owning item of this Asset. + + The owning item will be used to resolve relative HREFs of this asset. + + Args: + obj: The Collection or Item that owns this asset. + """ + self.owner = obj + + def get_absolute_href(self) -> Optional[str]: + """Gets the absolute href for this asset, if possible. + + If this Asset has no associated Item, and the asset HREF is a relative path, + this method will return None. + + Returns: + str: The absolute HREF of this asset, or None if an absolute HREF could not + be determined. + """ + if is_absolute_href(self.href): + return self.href + else: + if self.owner is not None: + return make_absolute_href(self.href, self.owner.get_self_href()) + else: + return None + + def to_dict(self) -> Dict[str, Any]: + """Generate a dictionary representing the JSON of this Asset. + + Returns: + dict: A serialization of the Asset that can be written out as JSON. + """ + + d: Dict[str, Any] = {"href": self.href} + + if self.media_type is not None: + d["type"] = self.media_type + + if self.title is not None: + d["title"] = self.title + + if self.description is not None: + d["description"] = self.description + + if self.properties is not None and len(self.properties) > 0: + for k, v in self.properties.items(): + d[k] = v + + if self.roles is not None: + d["roles"] = self.roles + + return d + + def clone(self) -> "Asset": + """Clones this asset. + + Returns: + Asset: The clone of this asset. + """ + return Asset( + href=self.href, + title=self.title, + description=self.description, + media_type=self.media_type, + roles=self.roles, + properties=self.properties, + ) + + def __repr__(self) -> str: + return "".format(self.href) + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "Asset": + """Constructs an Asset from a dict. + + Returns: + Asset: The Asset deserialized from the JSON dict. + """ + d = copy(d) + href = d.pop("href") + media_type = d.pop("type", None) + title = d.pop("title", None) + description = d.pop("description", None) + roles = d.pop("roles", None) + properties = None + if any(d): + properties = d + + return Asset( + href=href, + media_type=media_type, + title=title, + description=description, + roles=roles, + properties=properties, + ) diff --git a/pystac/cache.py b/pystac/cache.py index 7ffc98d36..117b0f23d 100644 --- a/pystac/cache.py +++ b/pystac/cache.py @@ -1,10 +1,15 @@ from collections import ChainMap from copy import copy +from typing import Any, Dict, List, Optional, TYPE_CHECKING, Tuple, Union, cast import pystac +if TYPE_CHECKING: + from pystac.stac_object import STACObject as STACObject_Type + from pystac.collection import Collection as Collection_Type -def get_cache_key(stac_object): + +def get_cache_key(stac_object: "STACObject_Type") -> Tuple[str, bool]: """Produce a cache key for the given STAC object. If a self href is set, use that as the cache key. @@ -20,12 +25,12 @@ def get_cache_key(stac_object): if href is not None: return (href, True) else: - ids = [] - obj = stac_object + ids: List[str] = [] + obj: Optional[pystac.STACObject] = stac_object while obj is not None: ids.append(obj.id) obj = obj.get_parent() - return ('/'.join(ids), False) + return ("/".join(ids), False) class ResolvedObjectCache: @@ -50,16 +55,23 @@ class ResolvedObjectCache: to the cached STACObject. hrefs_to_objects (Dict[str, STACObject]): STAC Object HREFs matched to their cached object. - ids_to_collections (Dict[str, Collection]): Map of collection IDs to collections. + ids_to_collections (Dict[str, Collection]): Map of collection IDs + to collections. """ - def __init__(self, id_keys_to_objects=None, hrefs_to_objects=None, ids_to_collections=None): + + def __init__( + self, + id_keys_to_objects: Optional[Dict[str, "STACObject_Type"]] = None, + hrefs_to_objects: Optional[Dict[str, "STACObject_Type"]] = None, + ids_to_collections: Dict[str, "Collection_Type"] = None, + ): self.id_keys_to_objects = id_keys_to_objects or {} self.hrefs_to_objects = hrefs_to_objects or {} self.ids_to_collections = ids_to_collections or {} - self._collection_cache = None + self._collection_cache: Optional[ResolvedObjectCollectionCache] = None - def get_or_cache(self, obj): + def get_or_cache(self, obj: "STACObject_Type") -> "STACObject_Type": """Gets the STACObject that is the cached version of the given STACObject; or, if none exists, sets the cached object to the given object. @@ -68,8 +80,8 @@ def get_or_cache(self, obj): against the cache. Returns: - STACObject: Either the cached object that has the same cache key as the given - object, or the given object. + STACObject: Either the cached object that has the same cache key as the + given object, or the given object. """ key, is_href = get_cache_key(obj) if is_href: @@ -85,15 +97,16 @@ def get_or_cache(self, obj): self.cache(obj) return obj - def get(self, obj): + def get(self, obj: "STACObject_Type") -> Optional["STACObject_Type"]: """Get the cached object that has the same cache key as the given object. Args: - obj (STACObject): The given object who's cache key will be checked against the cache. + obj (STACObject): The given object who's cache key will be checked against + the cache. Returns: - STACObject or None: Either the cached object that has the same cache key as the given - object, or None + STACObject or None: Either the cached object that has the same cache key as + the given object, or None """ key, is_href = get_cache_key(obj) if is_href: @@ -101,7 +114,7 @@ def get(self, obj): else: return self.id_keys_to_objects.get(key) - def get_by_href(self, href): + def get_by_href(self, href: str) -> Optional["STACObject_Type"]: """Gets the cached object at href. Args: @@ -112,7 +125,7 @@ def get_by_href(self, href): """ return self.hrefs_to_objects.get(href) - def get_collection_by_id(self, id): + def get_collection_by_id(self, id: str) -> Optional["Collection_Type"]: """Retrieved a cached Collection by its ID. Args: @@ -124,7 +137,7 @@ def get_collection_by_id(self, id): """ return self.ids_to_collections.get(id) - def cache(self, obj): + def cache(self, obj: "STACObject_Type") -> None: """Set the given object into the cache. Args: @@ -136,10 +149,10 @@ def cache(self, obj): else: self.id_keys_to_objects[key] = obj - if obj.STAC_OBJECT_TYPE == pystac.STACObjectType.COLLECTION: + if isinstance(obj, pystac.Collection): self.ids_to_collections[obj.id] = obj - def remove(self, obj): + def remove(self, obj: "STACObject_Type") -> None: """Removes any cached object that matches the given object's cache key. Args: @@ -155,21 +168,25 @@ def remove(self, obj): if obj.STAC_OBJECT_TYPE == pystac.STACObjectType.COLLECTION: self.id_keys_to_objects.pop(obj.id, None) - def __contains__(self, obj): + def __contains__(self, obj: "STACObject_Type") -> bool: key, is_href = get_cache_key(obj) - return key in self.hrefs_to_objects if is_href else key in self.id_keys_to_objects + return ( + key in self.hrefs_to_objects if is_href else key in self.id_keys_to_objects + ) - def contains_collection_id(self, collection_id): + def contains_collection_id(self, collection_id: str) -> bool: """Returns True if there is a collection with given collection ID is cached.""" return collection_id in self.ids_to_collections - def as_collection_cache(self): + def as_collection_cache(self) -> "CollectionCache": if self._collection_cache is None: self._collection_cache = ResolvedObjectCollectionCache(self) return self._collection_cache @staticmethod - def merge(first, second): + def merge( + first: "ResolvedObjectCache", second: "ResolvedObjectCache" + ) -> "ResolvedObjectCache": """Merges two ResolvedObjectCache. The merged cache will give preference to the first argument; that is, if there @@ -184,17 +201,25 @@ def merge(first, second): Returns: ResolvedObjectCache: The resulting merged cache. """ - merged = ResolvedObjectCache(id_keys_to_objects=dict( - ChainMap(copy(first.id_keys_to_objects), copy(second.id_keys_to_objects))), - hrefs_to_objects=dict( - ChainMap(copy(first.hrefs_to_objects), - copy(second.hrefs_to_objects))), - ids_to_collections=dict( - ChainMap(copy(first.ids_to_collections), - copy(second.ids_to_collections)))) + merged = ResolvedObjectCache( + id_keys_to_objects=dict( + ChainMap( + copy(first.id_keys_to_objects), copy(second.id_keys_to_objects) + ) + ), + hrefs_to_objects=dict( + ChainMap(copy(first.hrefs_to_objects), copy(second.hrefs_to_objects)) + ), + ids_to_collections=dict( + ChainMap( + copy(first.ids_to_collections), copy(second.ids_to_collections) + ) + ), + ) merged._collection_cache = ResolvedObjectCollectionCache.merge( - merged, first._collection_cache, second._collection_cache) + merged, first._collection_cache, second._collection_cache + ) return merged @@ -203,58 +228,93 @@ class CollectionCache: """Cache of collections that can be used to avoid re-reading Collection JSON in :func:`pystac.serialization.merge_common_properties `. - The CollectionCache will contain collections as either as dicts or PySTAC Collections, - and will set Collection JSON that it reads in order to merge in common properties. + The CollectionCache will contain collections as either as dicts or PySTAC + Collections, and will set Collection JSON that it reads in order to merge + in common properties. """ - def __init__(self, cached_ids=None, cached_hrefs=None): + + def __init__( + self, + cached_ids: Dict[str, Union["Collection_Type", Dict[str, Any]]] = None, + cached_hrefs: Dict[str, Union["Collection_Type", Dict[str, Any]]] = None, + ): self.cached_ids = cached_ids or {} self.cached_hrefs = cached_hrefs or {} - def get_by_id(self, collection_id): + def get_by_id( + self, collection_id: str + ) -> Optional[Union["Collection_Type", Dict[str, Any]]]: return self.cached_ids.get(collection_id) - def get_by_href(self, href): + def get_by_href( + self, href: str + ) -> Optional[Union["Collection_Type", Dict[str, Any]]]: return self.cached_hrefs.get(href) - def contains_id(self, collection_id): + def contains_id(self, collection_id: str) -> bool: return collection_id in self.cached_ids - def cache(self, collection, href=None): + def cache( + self, + collection: Union["Collection_Type", Dict[str, Any]], + href: Optional[str] = None, + ) -> None: """Caches a collection JSON.""" - self.cached_ids[collection['id']] = collection + if isinstance(collection, pystac.Collection): + self.cached_ids[collection.id] = collection + else: + self.cached_ids[collection["id"]] = collection if href is not None: self.cached_hrefs[href] = collection class ResolvedObjectCollectionCache(CollectionCache): - def __init__(self, resolved_object_cache, cached_ids=None, cached_hrefs=None): + def __init__( + self, + resolved_object_cache: ResolvedObjectCache, + cached_ids: Dict[str, Union["Collection_Type", Dict[str, Any]]] = None, + cached_hrefs: Dict[str, Union["Collection_Type", Dict[str, Any]]] = None, + ): super().__init__(cached_ids, cached_hrefs) self.resolved_object_cache = resolved_object_cache - def get_by_id(self, collection_id): + def get_by_id( + self, collection_id: str + ) -> Optional[Union["Collection_Type", Dict[str, Any]]]: result = self.resolved_object_cache.get_collection_by_id(collection_id) if result is None: return super().get_by_id(collection_id) else: return result - def get_by_href(self, href): + def get_by_href( + self, href: str + ) -> Optional[Union["Collection_Type", Dict[str, Any]]]: result = self.resolved_object_cache.get_by_href(href) if result is None: return super().get_by_href(href) else: - return result - - def contains_id(self, collection_id): - return (self.resolved_object_cache.contains_collection_id(collection_id) - or super().contains_id(collection_id)) - - def cache(self, collection, href=None): + return cast(pystac.Collection, result) + + def contains_id(self, collection_id: str) -> bool: + return self.resolved_object_cache.contains_collection_id( + collection_id + ) or super().contains_id(collection_id) + + def cache( + self, + collection: Union["Collection_Type", Dict[str, Any]], + href: Optional[str] = None, + ) -> None: super().cache(collection, href) @staticmethod - def merge(resolved_object_cache, first, second): + def merge( + resolved_object_cache: ResolvedObjectCache, + first: Optional["ResolvedObjectCollectionCache"], + second: Optional["ResolvedObjectCollectionCache"], + ) -> "ResolvedObjectCollectionCache": first_cached_ids = {} if first is not None: first_cached_ids = copy(first.cached_ids) @@ -274,4 +334,5 @@ def merge(resolved_object_cache, first, second): return ResolvedObjectCollectionCache( resolved_object_cache, cached_ids=dict(ChainMap(first_cached_ids, second_cached_ids)), - cached_hrefs=dict(ChainMap(first_cached_hrefs, second_cached_hrefs))) + cached_hrefs=dict(ChainMap(first_cached_hrefs, second_cached_hrefs)), + ) diff --git a/pystac/catalog.py b/pystac/catalog.py index 35da624a4..428f9c84c 100644 --- a/pystac/catalog.py +++ b/pystac/catalog.py @@ -1,49 +1,68 @@ import os from copy import deepcopy from enum import Enum +from typing import ( + Any, + Callable, + Dict, + Iterable, + List, + Optional, + TYPE_CHECKING, + Tuple, + Union, + cast, +) import pystac -from pystac import STACError from pystac.stac_object import STACObject -from pystac.layout import (BestPracticesLayoutStrategy, LayoutTemplate) +from pystac.layout import ( + BestPracticesLayoutStrategy, + HrefLayoutStrategy, + LayoutTemplate, +) from pystac.link import Link from pystac.cache import ResolvedObjectCache -from pystac.utils import (is_absolute_href, make_absolute_href) +from pystac.utils import is_absolute_href, make_absolute_href + +if TYPE_CHECKING: + from pystac.item import Asset as Asset_Type, Item as Item_Type + from pystac.collection import Collection as Collection_Type class CatalogType(str, Enum): - def __str__(self): + def __str__(self) -> str: return str(self.value) - SELF_CONTAINED = 'SELF_CONTAINED' + SELF_CONTAINED = "SELF_CONTAINED" """A 'self-contained catalog' is one that is designed for portability. Users may want to download a catalog from online and be able to use it on their local computer, so all links need to be relative. See: `The best practices documentation on self-contained catalogs `_ - """ # noqa E501 + """ # noqa E501 - ABSOLUTE_PUBLISHED = 'ABSOLUTE_PUBLISHED' + ABSOLUTE_PUBLISHED = "ABSOLUTE_PUBLISHED" """ Absolute Published Catalog is a catalog that uses absolute links for everything, both in the links objects and in the asset hrefs. See: `The best practices documentation on published catalogs `_ - """ # noqa E501 + """ # noqa E501 - RELATIVE_PUBLISHED = 'RELATIVE_PUBLISHED' + RELATIVE_PUBLISHED = "RELATIVE_PUBLISHED" """ Relative Published Catalog is a catalog that uses relative links for everything, but includes an absolute self link at the root catalog, to identify its online location. See: `The best practices documentation on published catalogs `_ - """ # noqa E501 + """ # noqa E501 @classmethod - def determine_type(cls, stac_json): + def determine_type(cls, stac_json: Dict[str, Any]) -> Optional["CatalogType"]: """Determines the catalog type based on a STAC JSON dict. Only applies to Catalogs or Collections @@ -52,16 +71,16 @@ def determine_type(cls, stac_json): stac_json (dict): The STAC JSON dict to determine the catalog type Returns: - str or None: The catalog type of the catalog or collection. + Optional[CatalogType]: The catalog type of the catalog or collection. Will return None if it cannot be determined. """ self_link = None relative = False - for link in stac_json['links']: - if link['rel'] == 'self': + for link in stac_json["links"]: + if link["rel"] == "self": self_link = link else: - relative |= not is_absolute_href(link['href']) + relative |= not is_absolute_href(link["href"]) if self_link: if relative: @@ -89,8 +108,8 @@ class Catalog(STACObject): representation. title (str or None): Optional short descriptive one-line title for the catalog. stac_extensions (List[str]): Optional list of extensions the Catalog implements. - href (str or None): Optional HREF for this catalog, which be set as the catalog's - self link's HREF. + href (str or None): Optional HREF for this catalog, which be set as the + catalog's self link's HREF. catalog_type (str or None): Optional catalog type for this catalog. Must be one of the values in :class`~pystac.CatalogType`. @@ -98,27 +117,39 @@ class Catalog(STACObject): id (str): Identifier for the catalog. description (str): Detailed multi-line description to fully explain the catalog. title (str or None): Optional short descriptive one-line title for the catalog. - stac_extensions (List[str] or None): Optional list of extensions the Catalog implements. - extra_fields (dict or None): Extra fields that are part of the top-level JSON properties - of the Catalog. + stac_extensions (List[str] or None): Optional list of extensions the Catalog + implements. + extra_fields (dict or None): Extra fields that are part of the top-level JSON + properties of the Catalog. links (List[Link]): A list of :class:`~pystac.Link` objects representing all links associated with this Catalog. - catalog_type (str or None): The catalog type, or None if not known. + catalog_type (str): The catalog type. Defaults to ABSOLUTE_PUBLISHED """ STAC_OBJECT_TYPE = pystac.STACObjectType.CATALOG + _stac_io: Optional[pystac.StacIO] = None + """Optional instance of StacIO that will be used by default + for any IO operations on objects contained by this catalog. + Set while reading in a catalog. This is set when a catalog + is read by a StacIO instance.""" + DEFAULT_FILE_NAME = "catalog.json" - """Default file name that will be given to this STAC object in a cononical format.""" - def __init__(self, - id, - description, - title=None, - stac_extensions=None, - extra_fields=None, - href=None, - catalog_type=CatalogType.ABSOLUTE_PUBLISHED): - super().__init__(stac_extensions) + """Default file name that will be given to this STAC object in + a canonical format. + """ + + def __init__( + self, + id: str, + description: str, + title: Optional[str] = None, + stac_extensions: Optional[List[str]] = None, + extra_fields: Optional[Dict[str, Any]] = None, + href: Optional[str] = None, + catalog_type: CatalogType = CatalogType.ABSOLUTE_PUBLISHED, + ): + super().__init__(stac_extensions or []) self.id = id self.description = description @@ -135,23 +166,32 @@ def __init__(self, if href is not None: self.set_self_href(href) - self.catalog_type = catalog_type + self.catalog_type: CatalogType = catalog_type self._resolved_objects.cache(self) - def __repr__(self): - return ''.format(self.id) + def __repr__(self) -> str: + return "".format(self.id) - def set_root(self, root): + def set_root(self, root: Optional["Catalog"]) -> None: STACObject.set_root(self, root) if root is not None: - root._resolved_objects = ResolvedObjectCache.merge(root._resolved_objects, - self._resolved_objects) - - def is_relative(self): - return self.catalog_type in [CatalogType.RELATIVE_PUBLISHED, CatalogType.SELF_CONTAINED] - - def add_child(self, child, title=None, strategy=None): + root._resolved_objects = ResolvedObjectCache.merge( + root._resolved_objects, self._resolved_objects + ) + + def is_relative(self) -> bool: + return self.catalog_type in [ + CatalogType.RELATIVE_PUBLISHED, + CatalogType.SELF_CONTAINED, + ] + + def add_child( + self, + child: Union["Catalog", "Collection_Type"], + title: Optional[str] = None, + strategy: Optional[HrefLayoutStrategy] = None, + ) -> None: """Adds a link to a child :class:`~pystac.Catalog` or :class:`~pystac.Collection`. This method will set the child's parent to this object, and its root to this Catalog's root. @@ -159,11 +199,13 @@ def add_child(self, child, title=None, strategy=None): Args: child (Catalog or Collection): The child to add. title (str): Optional title to give to the :class:`~pystac.Link` + strategy (HrefLayoutStrategy): The layout strategy to use for setting the + self href of the child. """ # Prevent typo confusion if isinstance(child, pystac.Item): - raise STACError('Cannot add item as child. Use add_item instead.') + raise pystac.STACError("Cannot add item as child. Use add_item instead.") if strategy is None: strategy = BestPracticesLayoutStrategy() @@ -179,8 +221,10 @@ def add_child(self, child, title=None, strategy=None): self.add_link(Link.child(child, title=title)) - def add_children(self, children): - """Adds links to multiple :class:`~pystac.Catalog` or `~pystac.Collection`s. + def add_children( + self, children: Iterable[Union["Catalog", "Collection_Type"]] + ) -> None: + """Adds links to multiple :class:`~pystac.Catalog` or `~pystac.Collection` objects. This method will set each child's parent to this object, and their root to this Catalog's root. @@ -190,7 +234,12 @@ def add_children(self, children): for child in children: self.add_child(child) - def add_item(self, item, title=None, strategy=None): + def add_item( + self, + item: "Item_Type", + title: Optional[str] = None, + strategy: Optional[HrefLayoutStrategy] = None, + ) -> None: """Adds a link to an :class:`~pystac.Item`. This method will set the item's parent to this object, and its root to this Catalog's root. @@ -202,7 +251,7 @@ def add_item(self, item, title=None, strategy=None): # Prevent typo confusion if isinstance(item, pystac.Catalog): - raise STACError('Cannot add catalog as item. Use add_child instead.') + raise pystac.STACError("Cannot add catalog as item. Use add_child instead.") if strategy is None: strategy = BestPracticesLayoutStrategy() @@ -218,7 +267,7 @@ def add_item(self, item, title=None, strategy=None): self.add_link(Link.item(item, title=title)) - def add_items(self, items): + def add_items(self, items: Iterable["Item_Type"]) -> None: """Adds links to multiple :class:`~pystac.Item` s. This method will set each item's parent to this object, and their root to this Catalog's root. @@ -229,16 +278,20 @@ def add_items(self, items): for item in items: self.add_item(item) - def get_child(self, id, recursive=False): + def get_child( + self, id: str, recursive: bool = False + ) -> Optional[Union["Catalog", "Collection_Type"]]: """Gets the child of this catalog with the given ID, if it exists. Args: id (str): The ID of the child to find. - recursive (bool): If True, search this catalog and all children for the item; - otherwise, only search the children of this catalog. Defaults to False. + recursive (bool): If True, search this catalog and all children for the + item; otherwise, only search the children of this catalog. Defaults + to False. Return: - Item or None: The item with the given ID, or None if not found. + Optional Catalog or Collection: The child with the given ID, + or None if not found. """ if not recursive: return next((c for c in self.get_children() if c.id == id), None) @@ -249,24 +302,27 @@ def get_child(self, id, recursive=False): return child return None - def get_children(self): + def get_children(self) -> Iterable[Union["Catalog", "Collection_Type"]]: """Return all children of this catalog. Return: - Generator[Catalog or Collection]: Generator of children who's parent + Iterable[Catalog or Collection]: Iterable of children who's parent is this catalog. """ - return self.get_stac_objects('child') + return map( + lambda x: cast(Union[pystac.Catalog, pystac.Collection], x), + self.get_stac_objects("child"), + ) - def get_child_links(self): + def get_child_links(self) -> List[Link]: """Return all child links of this catalog. Return: List[Link]: List of links of this catalog with ``rel == 'child'`` """ - return self.get_links('child') + return self.get_links("child") - def clear_children(self): + def clear_children(self) -> None: """Removes all children from this catalog. Return: @@ -275,36 +331,36 @@ def clear_children(self): child_ids = [child.id for child in self.get_children()] for child_id in child_ids: self.remove_child(child_id) - return self - def remove_child(self, child_id): + def remove_child(self, child_id: str) -> None: """Removes an child from this catalog. Args: child_id (str): The ID of the child to remove. """ - new_links = [] + new_links: List[pystac.Link] = [] root = self.get_root() for link in self.links: - if link.rel != 'child': + if link.rel != "child": new_links.append(link) else: link.resolve_stac_object(root=root) - if link.target.id != child_id: + child = cast("Catalog", link.target) + if child.id != child_id: new_links.append(link) else: - child = link.target child.set_parent(None) child.set_root(None) self.links = new_links - def get_item(self, id, recursive=False): + def get_item(self, id: str, recursive: bool = False) -> Optional["Item_Type"]: """Returns an item with a given ID. Args: id (str): The ID of the item to find. - recursive (bool): If True, search this catalog and all children for the item; - otherwise, only search the items of this catalog. Defaults to False. + recursive (bool): If True, search this catalog and all children for the + item; otherwise, only search the items of this catalog. Defaults + to False. Return: Item or None: The item with the given ID, or None if not found. @@ -312,21 +368,21 @@ def get_item(self, id, recursive=False): if not recursive: return next((i for i in self.get_items() if i.id == id), None) else: - for root, children, items in self.walk(): + for root, _, _ in self.walk(): item = root.get_item(id, recursive=False) if item is not None: return item return None - def get_items(self): + def get_items(self) -> Iterable["Item_Type"]: """Return all items of this catalog. Return: - Generator[Item]: Generator of items who's parent is this catalog. + Iterable[Item]: Generator of items who's parent is this catalog. """ - return self.get_stac_objects('item') + return map(lambda x: cast(pystac.Item, x), self.get_stac_objects("item")) - def clear_items(self): + def clear_items(self) -> None: """Removes all items from this catalog. Return: @@ -334,35 +390,34 @@ def clear_items(self): """ for link in self.get_item_links(): if link.is_resolved(): - item = link.target + item = cast(pystac.Item, link.target) item.set_parent(None) item.set_root(None) - self.links = [link for link in self.links if link.rel != 'item'] - return self + self.links = [link for link in self.links if link.rel != "item"] - def remove_item(self, item_id): + def remove_item(self, item_id: str) -> None: """Removes an item from this catalog. Args: item_id (str): The ID of the item to remove. """ - new_links = [] + new_links: List[pystac.Link] = [] root = self.get_root() for link in self.links: - if link.rel != 'item': + if link.rel != "item": new_links.append(link) else: link.resolve_stac_object(root=root) - if link.target.id != item_id: + item = cast(pystac.Item, link.target) + if item.id != item_id: new_links.append(link) else: - item = link.target item.set_parent(None) item.set_root(None) self.links = new_links - def get_all_items(self): + def get_all_items(self) -> Iterable["Item_Type"]: """Get all items from this catalog and all subcatalogs. Will traverse any subcatalogs recursively. @@ -375,49 +430,51 @@ def get_all_items(self): for child in self.get_children(): yield from child.get_all_items() - def get_item_links(self): + def get_item_links(self) -> List[Link]: """Return all item links of this catalog. Return: List[Link]: List of links of this catalog with ``rel == 'item'`` """ - return self.get_links('item') + return self.get_links("item") - def to_dict(self, include_self_link=True): + def to_dict(self, include_self_link: bool = True) -> Dict[str, Any]: links = self.links if not include_self_link: - links = filter(lambda l: l.rel != 'self', links) - - d = { - 'type': self.STAC_OBJECT_TYPE.value.title(), - 'id': self.id, - 'stac_version': pystac.get_stac_version(), - 'description': self.description, - 'links': [link.to_dict() for link in links] + links = [x for x in links if x.rel != "self"] + + d: Dict[str, Any] = { + "type": self.STAC_OBJECT_TYPE.value.title(), + "id": self.id, + "stac_version": pystac.get_stac_version(), + "description": self.description, + "links": [link.to_dict() for link in links], } if self.stac_extensions is not None: - d['stac_extensions'] = self.stac_extensions + d["stac_extensions"] = self.stac_extensions for key in self.extra_fields: d[key] = self.extra_fields[key] if self.title is not None: - d['title'] = self.title + d["title"] = self.title return d - def clone(self): - clone = Catalog(id=self.id, - description=self.description, - title=self.title, - stac_extensions=self.stac_extensions, - extra_fields=deepcopy(self.extra_fields), - catalog_type=self.catalog_type) + def clone(self) -> "Catalog": + clone = Catalog( + id=self.id, + description=self.description, + title=self.title, + stac_extensions=self.stac_extensions, + extra_fields=deepcopy(self.extra_fields), + catalog_type=self.catalog_type, + ) clone._resolved_objects.cache(clone) for link in self.links: - if link.rel == 'root': + if link.rel == "root": # Catalog __init__ sets correct root to clone; don't reset # if the root link points to self root_is_self = link.is_resolved() and link.target is self @@ -429,7 +486,7 @@ def clone(self): return clone - def make_all_asset_hrefs_relative(self): + def make_all_asset_hrefs_relative(self) -> None: """Makes all the HREFs of assets belonging to items in this catalog and all children to be relative, recursively. """ @@ -437,7 +494,7 @@ def make_all_asset_hrefs_relative(self): for item in items: item.make_asset_hrefs_relative() - def make_all_asset_hrefs_absolute(self): + def make_all_asset_hrefs_absolute(self) -> None: """Makes all the HREFs of assets belonging to items in this catalog and all children to be absolute, recursively. """ @@ -445,7 +502,12 @@ def make_all_asset_hrefs_absolute(self): for item in items: item.make_asset_hrefs_absolute() - def normalize_and_save(self, root_href, catalog_type=None, strategy=None): + def normalize_and_save( + self, + root_href: str, + catalog_type: Optional[CatalogType] = None, + strategy: Optional[HrefLayoutStrategy] = None, + ) -> None: """Normalizes link HREFs to the given root_href, and saves the catalog. This is a convenience method that simply calls :func:`Catalog.normalize_hrefs @@ -453,18 +515,22 @@ def normalize_and_save(self, root_href, catalog_type=None, strategy=None): in sequence. Args: - root_href (str): The absolute HREF that all links will be normalized against. + root_href (str): The absolute HREF that all links will be normalized + against. catalog_type (str): The catalog type that dictates the structure of the catalog to save. Use a member of :class:`~pystac.CatalogType`. - Defaults to the root catalog.catalog_type or the current catalog catalog_type - if there is no root catalog. - strategy (HrefLayoutStrategy): The layout strategy to use in setting the HREFS - for this catalog. Defaults to :class:`~pystac.layout.BestPracticesLayoutStrategy` + Defaults to the root catalog.catalog_type or the current catalog + catalog_type if there is no root catalog. + strategy (HrefLayoutStrategy): The layout strategy to use in setting the + HREFS for this catalog. Defaults to + :class:`~pystac.layout.BestPracticesLayoutStrategy` """ self.normalize_hrefs(root_href, strategy=strategy) self.save(catalog_type) - def normalize_hrefs(self, root_href, strategy=None): + def normalize_hrefs( + self, root_href: str, strategy: Optional[HrefLayoutStrategy] = None + ) -> None: """Normalize HREFs will regenerate all link HREFs based on an absolute root_href and the canonical catalog layout as specified in the STAC specification's best practices. @@ -478,30 +544,34 @@ def normalize_hrefs(self, root_href, strategy=None): See: `STAC best practices document `_ for the canonical layout of a STAC. - """ # noqa E501 + """ # noqa E501 if strategy is None: - strategy = BestPracticesLayoutStrategy() + _strategy: HrefLayoutStrategy = BestPracticesLayoutStrategy() + else: + _strategy = strategy # Normalizing requires an absolute path if not is_absolute_href(root_href): root_href = make_absolute_href(root_href, os.getcwd(), start_is_dir=True) - def process_item(item, _root_href): + def process_item(item: "Item_Type", _root_href: str) -> Callable[[], None]: item.resolve_links() - new_self_href = strategy.get_href(item, _root_href) + new_self_href = _strategy.get_href(item, _root_href) - def fn(): + def fn() -> None: item.set_self_href(new_self_href) return fn - def process_catalog(cat, _root_href, is_root): - setter_funcs = [] + def process_catalog( + cat: Catalog, _root_href: str, is_root: bool + ) -> List[Callable[[], None]]: + setter_funcs: List[Callable[[], None]] = [] cat.resolve_links() - new_self_href = strategy.get_href(cat, _root_href, is_root) + new_self_href = _strategy.get_href(cat, _root_href, is_root) new_root = os.path.dirname(new_self_href) for item in cat.get_items(): @@ -510,7 +580,7 @@ def process_catalog(cat, _root_href, is_root): for child in cat.get_children(): setter_funcs.extend(process_catalog(child, new_root, is_root=False)) - def fn(): + def fn() -> None: cat.set_self_href(new_self_href) setter_funcs.append(fn) @@ -525,11 +595,17 @@ def fn(): for fn in setter_funcs: fn() - return self - - def generate_subcatalogs(self, template, defaults=None, parent_ids=None, **kwargs): + def generate_subcatalogs( + self, + template: str, + defaults: Optional[Dict[str, Any]] = None, + parent_ids: Optional[List[str]] = None, + **kwargs: Any, + ) -> List["Catalog"]: """Walks through the catalog and generates subcatalogs - for items based on the template string. See :class:`~pystac.layout.LayoutTemplate` + for items based on the template string. + + See :class:`~pystac.layout.LayoutTemplate` for details on the construction of template strings. This template string will be applied to the items, and subcatalogs will be created that separate and organize the items based on template values. @@ -541,32 +617,37 @@ def generate_subcatalogs(self, template, defaults=None, parent_ids=None, **kwarg that will be used if the property cannot be found on the item. parent_ids (List[str]): Optional list of the parent catalogs' - identifiers. If the bottom-most subcatalags already match the + identifiers. If the bottom-most subcatalogs already match the template, no subcatalog is added. Returns: [catalog]: List of new catalogs created """ - result = [] + result: List[Catalog] = [] parent_ids = parent_ids or list() parent_ids.append(self.id) for child in self.get_children(): result.extend( - child.generate_subcatalogs(template, - defaults=defaults, - parent_ids=parent_ids.copy())) + child.generate_subcatalogs( + template, defaults=defaults, parent_ids=parent_ids.copy() + ) + ) layout_template = LayoutTemplate(template, defaults=defaults) - keep_item_links = [] - item_links = [lk for lk in self.links if lk.rel == 'item'] + keep_item_links: List[Link] = [] + item_links = [lk for lk in self.links if lk.rel == "item"] for link in item_links: link.resolve_stac_object(root=self.get_root()) - item = link.target + item = cast(pystac.Item, link.target) item_parts = layout_template.get_template_values(item) id_iter = reversed(parent_ids) - if all(['{}'.format(id) == next(id_iter, None) - for id in reversed(item_parts.values())]): + if all( + [ + "{}".format(id) == next(id_iter, None) + for id in reversed(list(item_parts.values())) + ] + ): # Skip items for which the sub-catalog structure already # matches the template. The list of parent IDs can include more # elements on the root side, so compare the reversed sequences. @@ -574,29 +655,30 @@ def generate_subcatalogs(self, template, defaults=None, parent_ids=None, **kwarg continue curr_parent = self for k, v in item_parts.items(): - subcat_id = '{}'.format(v) + subcat_id = "{}".format(v) subcat = curr_parent.get_child(subcat_id) if subcat is None: - subcat_desc = 'Catalog of items from {} with {} of {}'.format( - curr_parent.id, k, v) + subcat_desc = "Catalog of items from {} with {} of {}".format( + curr_parent.id, k, v + ) subcat = pystac.Catalog(id=subcat_id, description=subcat_desc) curr_parent.add_child(subcat) result.append(subcat) curr_parent = subcat # resolve collection link so when added back points to correct location - link = item.get_single_link('collection') - if link is not None: - link.resolve_stac_object() + col_link = item.get_single_link("collection") + if col_link is not None: + col_link.resolve_stac_object() curr_parent.add_item(item) # keep only non-item links and item links that have not been moved elsewhere - self.links = [lk for lk in self.links if lk.rel != 'item'] + keep_item_links + self.links = [lk for lk in self.links if lk.rel != "item"] + keep_item_links return result - def save(self, catalog_type=None): + def save(self, catalog_type: Optional[CatalogType] = None) -> None: """Save this catalog and all it's children/item to files determined by the object's self link HREF. @@ -609,15 +691,15 @@ def save(self, catalog_type=None): Note: If the catalog type is ``CatalogType.ABSOLUTE_PUBLISHED``, all self links will be included, and hierarchical links be absolute URLs. - If the catalog type is ``CatalogType.RELATIVE_PUBLISHED``, this catalog's self - link will be included, but no child catalog will have self links, and + If the catalog type is ``CatalogType.RELATIVE_PUBLISHED``, this catalog's + self link will be included, but no child catalog will have self links, and hierarchical links will be relative URLs - If the catalog type is ``CatalogType.SELF_CONTAINED``, no self links will be - included and hierarchical links will be relative URLs. + If the catalog type is ``CatalogType.SELF_CONTAINED``, no self links will + be included and hierarchical links will be relative URLs. """ root = self.get_root() if root is None: - raise Exception('There is no root catalog') + raise Exception("There is no root catalog") if catalog_type is not None: root.catalog_type = catalog_type @@ -626,29 +708,36 @@ def save(self, catalog_type=None): for child_link in self.get_child_links(): if child_link.is_resolved(): - child_link.target.save() + cast(Catalog, child_link.target).save() for item_link in self.get_item_links(): if item_link.is_resolved(): - item_link.target.save_object(include_self_link=items_include_self_link) + cast(pystac.Item, item_link.target).save_object( + include_self_link=items_include_self_link + ) include_self_link = False - # include a self link if this is the root catalog or if ABSOLUTE_PUBLISHED catalog - if ((self.get_self_href() == self.get_root_link().get_absolute_href() - and root.catalog_type != CatalogType.SELF_CONTAINED) - or root.catalog_type == CatalogType.ABSOLUTE_PUBLISHED): + # include a self link if this is the root catalog + # or if ABSOLUTE_PUBLISHED catalog + if root.catalog_type == CatalogType.ABSOLUTE_PUBLISHED: include_self_link = True + elif root.catalog_type != CatalogType.SELF_CONTAINED: + root_link = self.get_root_link() + if root_link and root_link.get_absolute_href() == self.get_self_href(): + include_self_link = True self.save_object(include_self_link=include_self_link) + if catalog_type is not None: + self.catalog_type = catalog_type - self.catalog_type = catalog_type - - def walk(self): + def walk( + self, + ) -> Iterable[Tuple["Catalog", Iterable["Catalog"], Iterable["Item_Type"]]]: """Walks through children and items of catalogs. - For each catalog in the STAC's tree rooted at this catalog (including this catalog - itself), it yields a 3-tuple (root, subcatalogs, items). The root in that - 3-tuple refers to the current catalog being walked, the subcatalogs are any + For each catalog in the STAC's tree rooted at this catalog (including this + catalog itself), it yields a 3-tuple (root, subcatalogs, items). The root in + that 3-tuple refers to the current catalog being walked, the subcatalogs are any catalogs or collections for which the root is a parent, and items represents any items that have the root as a parent. @@ -665,7 +754,7 @@ def walk(self): for child in self.get_children(): yield from child.walk() - def validate_all(self): + def validate_all(self) -> None: """Validates each catalog, collection contained within this catalog. Walks through the children and items of the catalog and validates each @@ -681,36 +770,41 @@ def validate_all(self): for item in self.get_items(): item.validate() - def _object_links(self): - return ['child', 'item'] + (pystac.STAC_EXTENSIONS.get_extended_object_links(self)) + def _object_links(self) -> List[str]: + return ["child", "item"] + ( + pystac.EXTENSION_HOOKS.get_extended_object_links(self) or [] + ) - def map_items(self, item_mapper): + def map_items( + self, + item_mapper: Callable[["Item_Type"], Union["Item_Type", List["Item_Type"]]], + ) -> "Catalog": """Creates a copy of a catalog, with each item passed through the item_mapper function. Args: - item_mapper (Callable): A function that takes in an item, and returns either - an item or list of items. The item that is passed into the item_mapper - is a copy, so the method can mutate it safely. + item_mapper (Callable): A function that takes in an item, and returns + either an item or list of items. The item that is passed into the + item_mapper is a copy, so the method can mutate it safely. Returns: Catalog: A full copy of this catalog, with items manipulated according to the item_mapper function. """ - new_cat = self.full_copy() + new_cat = cast(Catalog, self.full_copy()) - def process_catalog(catalog): + def process_catalog(catalog: Catalog) -> None: for child in catalog.get_children(): process_catalog(child) - item_links = [] + item_links: List[Link] = [] for item_link in catalog.get_item_links(): item_link.resolve_stac_object(root=self.get_root()) - mapped = item_mapper(item_link.target) + mapped = item_mapper(cast(pystac.Item, item_link.target)) if mapped is None: - raise Exception('item_mapper cannot return None.') - if type(mapped) is not list: + raise Exception("item_mapper cannot return None.") + if isinstance(mapped, pystac.Item): item_link.target = mapped item_links.append(item_link) else: @@ -724,25 +818,34 @@ def process_catalog(catalog): process_catalog(new_cat) return new_cat - def map_assets(self, asset_mapper): + def map_assets( + self, + asset_mapper: Callable[ + [str, "Asset_Type"], + Union["Asset_Type", Tuple[str, "Asset_Type"], Dict[str, "Asset_Type"]], + ], + ) -> "Catalog": """Creates a copy of a catalog, with each Asset for each Item passed through the asset_mapper function. Args: - asset_mapper (Callable): A function that takes in an key and an Asset, and returns - either an Asset, a (key, Asset), or a dictionary of Assets with unique keys. - The Asset that is passed into the item_mapper is a copy, so the method can - mutate it safely. + asset_mapper (Callable): A function that takes in an key and an Asset, and + returns either an Asset, a (key, Asset), or a dictionary of Assets with + unique keys. The Asset that is passed into the item_mapper is a copy, + so the method can mutate it safely. Returns: Catalog: A full copy of this catalog, with assets manipulated according to the asset_mapper function. """ - def apply_asset_mapper(tup): + + def apply_asset_mapper( + tup: Tuple[str, "Asset_Type"] + ) -> List[Tuple[str, pystac.Asset]]: k, v = tup result = asset_mapper(k, v) if result is None: - raise Exception('asset_mapper cannot return None.') + raise Exception("asset_mapper cannot return None.") if isinstance(result, pystac.Asset): return [(k, result)] elif isinstance(result, tuple): @@ -750,19 +853,21 @@ def apply_asset_mapper(tup): else: assets = list(result.items()) if len(assets) < 1: - raise Exception('asset_mapper must return a non-empy list') + raise Exception("asset_mapper must return a non-empty list") return assets - def item_mapper(item): + def item_mapper(item: pystac.Item) -> pystac.Item: new_assets = [ - x for result in map(apply_asset_mapper, item.assets.items()) for x in result + x + for result in map(apply_asset_mapper, item.assets.items()) + for x in result ] item.assets = dict(new_assets) return item return self.map_items(item_mapper) - def describe(self, include_hrefs=False, _indent=0): + def describe(self, include_hrefs: bool = False, _indent: int = 0) -> None: """Prints out information about this Catalog and all contained STACObjects. @@ -770,46 +875,72 @@ def describe(self, include_hrefs=False, _indent=0): include_hrefs (bool) - If True, print out each object's self link HREF along with the object ID. """ - s = '{}* {}'.format(' ' * _indent, self) + s = "{}* {}".format(" " * _indent, self) if include_hrefs: - s += ' {}'.format(self.get_self_href()) + s += " {}".format(self.get_self_href()) print(s) for child in self.get_children(): child.describe(include_hrefs=include_hrefs, _indent=_indent + 4) for item in self.get_items(): - s = '{}* {}'.format(' ' * (_indent + 2), item) + s = "{}* {}".format(" " * (_indent + 2), item) if include_hrefs: - s += ' {}'.format(item.get_self_href()) + s += " {}".format(item.get_self_href()) print(s) @classmethod - def from_dict(cls, d, href=None, root=None): + def from_dict( + cls, + d: Dict[str, Any], + href: Optional[str] = None, + root: Optional["Catalog"] = None, + migrate: bool = False, + ) -> "Catalog": + if migrate: + result = pystac.read_dict(d, href=href, root=root) + if not isinstance(result, Catalog): + raise pystac.STACError(f"{result} is not a Catalog") + return result + catalog_type = CatalogType.determine_type(d) d = deepcopy(d) - id = d.pop('id') - description = d.pop('description') - title = d.pop('title', None) - stac_extensions = d.pop('stac_extensions', None) - links = d.pop('links') + id = d.pop("id") + description = d.pop("description") + title = d.pop("title", None) + stac_extensions = d.pop("stac_extensions", None) + links = d.pop("links") - d.pop('stac_version') + d.pop("stac_version") - cat = Catalog(id=id, - description=description, - title=title, - stac_extensions=stac_extensions, - extra_fields=d, - href=href, - catalog_type=catalog_type) + cat = Catalog( + id=id, + description=description, + title=title, + stac_extensions=stac_extensions, + extra_fields=d, + href=href, + catalog_type=catalog_type or CatalogType.ABSOLUTE_PUBLISHED, + ) for link in links: - if link['rel'] == 'root': + if link["rel"] == "root": # Remove the link that's generated in Catalog's constructor. - cat.remove_links('root') + cat.remove_links("root") - if link['rel'] != 'self' or href is None: + if link["rel"] != "self" or href is None: cat.add_link(Link.from_dict(link)) return cat + + def full_copy( + self, root: Optional["Catalog"] = None, parent: Optional["Catalog"] = None + ) -> "Catalog": + return cast(Catalog, super().full_copy(root, parent)) + + @classmethod + def from_file(cls, href: str, stac_io: Optional[pystac.StacIO] = None) -> "Catalog": + result = super().from_file(href, stac_io) + if not isinstance(result, Catalog): + raise pystac.STACTypeError(f"{result} is not a {Catalog}.") + return result diff --git a/pystac/collection.py b/pystac/collection.py index 668658a15..0dafe09b7 100644 --- a/pystac/collection.py +++ b/pystac/collection.py @@ -1,287 +1,35 @@ -from collections import abc -from datetime import datetime +from copy import copy, deepcopy +from datetime import datetime as Datetime +from typing import ( + Any, + Dict, + Generic, + Iterable, + List, + Optional, + TYPE_CHECKING, + Tuple, + Type, + TypeVar, + Union, + cast, +) + import dateutil.parser from dateutil import tz -from copy import (copy, deepcopy) -from pystac import (STACObjectType, CatalogType) + +import pystac +from pystac import STACObjectType, CatalogType +from pystac.asset import Asset from pystac.catalog import Catalog +from pystac.layout import HrefLayoutStrategy from pystac.link import Link -from pystac.utils import datetime_to_str - - -class Collection(Catalog): - """A Collection extends the Catalog spec with additional metadata that helps - enable discovery. - - Args: - id (str): Identifier for the collection. Must be unique within the STAC. - description (str): Detailed multi-line description to fully explain the collection. - `CommonMark 0.28 syntax `_ MAY be used for rich text - representation. - extent (Extent): Spatial and temporal extents that describe the bounds of - all items contained within this Collection. - title (str or None): Optional short descriptive one-line title for the collection. - stac_extensions (List[str]): Optional list of extensions the Collection implements. - href (str or None): Optional HREF for this collection, which be set as the collection's - self link's HREF. - catalog_type (str or None): Optional catalog type for this catalog. Must - be one of the values in :class`~pystac.CatalogType`. - license (str): Collection's license(s) as a `SPDX License identifier - `_, `various`, or `proprietary`. If collection includes - data with multiple different licenses, use `various` and add a link for each. - Defaults to 'proprietary'. - keywords (List[str]): Optional list of keywords describing the collection. - providers (List[Provider]): Optional list of providers of this Collection. - properties (dict): Optional dict of common fields across referenced items. - summaries (dict): An optional map of property summaries, - either a set of values or statistics such as a range. - extra_fields (dict or None): Extra fields that are part of the top-level JSON properties - of the Collection. - - Attributes: - id (str): Identifier for the collection. - description (str): Detailed multi-line description to fully explain the collection. - extent (Extent): Spatial and temporal extents that describe the bounds of - all items contained within this Collection. - title (str or None): Optional short descriptive one-line title for the collection. - stac_extensions (List[str]): Optional list of extensions the Collection implements. - keywords (List[str] or None): Optional list of keywords describing the collection. - providers (List[Provider] or None): Optional list of providers of this Collection. - properties (dict or None): Optional dict of common fields across referenced items. - summaries (dict or None): An optional map of property summaries, - either a set of values or statistics such as a range. - links (List[Link]): A list of :class:`~pystac.Link` objects representing - all links associated with this Collection. - extra_fields (dict or None): Extra fields that are part of the top-level JSON properties - of the Catalog. - """ - - STAC_OBJECT_TYPE = STACObjectType.COLLECTION - - DEFAULT_FILE_NAME = "collection.json" - """Default file name that will be given to this STAC object in a cononical format.""" - def __init__(self, - id, - description, - extent, - title=None, - stac_extensions=None, - href=None, - extra_fields=None, - catalog_type=None, - license='proprietary', - keywords=None, - providers=None, - properties=None, - summaries=None): - super(Collection, self).__init__(id, description, title, stac_extensions, extra_fields, - href, catalog_type) - self.extent = extent - self.license = license - - self.stac_extensions = stac_extensions - self.keywords = keywords - self.providers = providers - self.properties = properties - self.summaries = summaries - - def __repr__(self): - return ''.format(self.id) - - def add_item(self, item, title=None): - super(Collection, self).add_item(item, title) - item.set_collection(self) - - def to_dict(self, include_self_link=True): - d = super(Collection, self).to_dict(include_self_link) - d['extent'] = self.extent.to_dict() - d['license'] = self.license - if self.stac_extensions is not None: - d['stac_extensions'] = self.stac_extensions - if self.keywords is not None: - d['keywords'] = self.keywords - if self.providers is not None: - d['providers'] = list(map(lambda x: x.to_dict(), self.providers)) - if self.properties is not None: - d['properties'] = self.properties - if self.summaries is not None: - d['summaries'] = self.summaries - - return d - - def clone(self): - clone = Collection(id=self.id, - description=self.description, - extent=self.extent.clone(), - title=self.title, - stac_extensions=self.stac_extensions, - extra_fields=self.extra_fields, - catalog_type=self.catalog_type, - license=self.license, - keywords=self.keywords, - providers=self.providers, - properties=self.properties, - summaries=self.summaries) - - clone._resolved_objects.cache(clone) - - for link in self.links: - if link.rel == 'root': - # Collection __init__ sets correct root to clone; don't reset - # if the root link points to self - root_is_self = link.is_resolved() and link.target is self - if not root_is_self: - clone.set_root(None) - clone.add_link(link.clone()) - else: - clone.add_link(link.clone()) - - return clone - - @classmethod - def from_dict(cls, d, href=None, root=None): - catalog_type = CatalogType.determine_type(d) - - d = deepcopy(d) - id = d.pop('id') - description = d.pop('description') - license = d.pop('license') - extent = Extent.from_dict(d.pop('extent')) - title = d.get('title') - stac_extensions = d.get('stac_extensions') - keywords = d.get('keywords') - providers = d.get('providers') - if providers is not None: - providers = list(map(lambda x: Provider.from_dict(x), providers)) - properties = d.get('properties') - summaries = d.get('summaries') - links = d.pop('links') - - d.pop('stac_version') - - collection = Collection(id=id, - description=description, - extent=extent, - title=title, - stac_extensions=stac_extensions, - extra_fields=d, - license=license, - keywords=keywords, - providers=providers, - properties=properties, - summaries=summaries, - href=href, - catalog_type=catalog_type) - - for link in links: - if link['rel'] == 'root': - # Remove the link that's generated in Catalog's constructor. - collection.remove_links('root') - - if link['rel'] != 'self' or href is None: - collection.add_link(Link.from_dict(link)) - - return collection - - def update_extent_from_items(self): - """ - Update datetime and bbox based on all items to a single bbox and time window. - """ - self.extent = Extent.from_items(self.get_all_items()) +from pystac.utils import datetime_to_str, get_required +if TYPE_CHECKING: + from pystac.item import Item as Item_Type -class Extent: - """Describes the spatio-temporal extents of a Collection. - - Args: - spatial (SpatialExtent): Potential spatial extent covered by the collection. - temporal (TemporalExtent): Potential temporal extent covered by the collection. - - Attributes: - spatial (SpatialExtent): Potential spatial extent covered by the collection. - temporal (TemporalExtent): Potential temporal extent covered by the collection. - """ - def __init__(self, spatial, temporal): - self.spatial = spatial - self.temporal = temporal - - def to_dict(self): - """Generate a dictionary representing the JSON of this Extent. - - Returns: - dict: A serializion of the Extent that can be written out as JSON. - """ - d = {'spatial': self.spatial.to_dict(), 'temporal': self.temporal.to_dict()} - - return d - - def clone(self): - """Clones this object. - - Returns: - Extent: The clone of this extent. - """ - return Extent(spatial=copy(self.spatial), temporal=copy(self.temporal)) - - @staticmethod - def from_dict(d): - """Constructs an Extent from a dict. - - Returns: - Extent: The Extent deserialized from the JSON dict. - """ - - # Handle pre-0.8 spatial extents - spatial_extent_dict = d['spatial'] - if isinstance(spatial_extent_dict, list): - spatial_extent_dict = {'bbox': [spatial_extent_dict]} - - # Handle pre-0.8 temporal extents - temporal_extent_dict = d['temporal'] - if isinstance(temporal_extent_dict, list): - temporal_extent_dict = {'interval': [temporal_extent_dict]} - - return Extent(SpatialExtent.from_dict(spatial_extent_dict), - TemporalExtent.from_dict(temporal_extent_dict)) - - @staticmethod - def from_items(items): - """Create an Extent based on the datetimes and bboxes of a list of items. - - Args: - items (List[Item]): A list of items to derive the extent from. - - Returns: - Extent: An Extent that spatially and temporally covers all of the - given items. - """ - def extract_extent_props(item): - return item.bbox + [ - item.datetime, item.common_metadata.start_datetime, - item.common_metadata.end_datetime - ] - - xmins, ymins, xmaxs, ymaxs, datetimes, starts, ends = zip(*map(extract_extent_props, items)) - - if not any(datetimes + starts): - start_timestamp = None - else: - start_timestamp = min([ - dt if dt.tzinfo else dt.replace(tzinfo=tz.UTC) - for dt in filter(None, datetimes + starts) - ]) - if not any(datetimes + ends): - end_timestamp = None - else: - end_timestamp = max([ - dt if dt.tzinfo else dt.replace(tzinfo=tz.UTC) - for dt in filter(None, datetimes + ends) - ]) - - spatial = SpatialExtent([[min(xmins), min(ymins), max(xmaxs), max(ymaxs)]]) - temporal = TemporalExtent([[start_timestamp, end_timestamp]]) - - return Extent(spatial, temporal) +T = TypeVar("T") class SpatialExtent: @@ -299,43 +47,43 @@ class SpatialExtent: array must be 2*n where n is the number of dimensions. For example, a 2D Collection with only one bbox would be [[xmin, ymin, xmax, ymax]] """ - def __init__(self, bboxes): + + def __init__(self, bboxes: Union[List[List[float]], List[float]]) -> None: # A common mistake is to pass in a single bbox instead of a list of bboxes. # Account for this by transforming the input in that case. - if isinstance(bboxes, abc.Sequence): - if not isinstance(bboxes[0], abc.Sequence): - bboxes = [bboxes] - - self.bboxes = bboxes + if isinstance(bboxes, list) and isinstance(bboxes[0], float): + self.bboxes: List[List[float]] = [cast(List[float], bboxes)] + else: + self.bboxes = cast(List[List[float]], bboxes) - def to_dict(self): + def to_dict(self) -> Dict[str, Any]: """Generate a dictionary representing the JSON of this SpatialExtent. Returns: - dict: A serializion of the SpatialExtent that can be written out as JSON. + dict: A serialization of the SpatialExtent that can be written out as JSON. """ - d = {'bbox': self.bboxes} + d = {"bbox": self.bboxes} return d - def clone(self): + def clone(self) -> "SpatialExtent": """Clones this object. Returns: SpatialExtent: The clone of this object. """ - return SpatialExtent(self.bboxes) + return SpatialExtent(deepcopy(self.bboxes)) @staticmethod - def from_dict(d): + def from_dict(d: Dict[str, Any]) -> "SpatialExtent": """Constructs an SpatialExtent from a dict. Returns: SpatialExtent: The SpatialExtent deserialized from the JSON dict. """ - return SpatialExtent(bboxes=d['bbox']) + return SpatialExtent(bboxes=d["bbox"]) @staticmethod - def from_coordinates(coordinates): + def from_coordinates(coordinates: List[Any]) -> "SpatialExtent": """Constructs a SpatialExtent from a set of coordinates. This method will only produce a single bbox that covers all points @@ -348,10 +96,19 @@ def from_coordinates(coordinates): SpatialExtent: A SpatialExtent with a single bbox that covers the given coordinates. """ - def process_coords(link, xmin=None, ymin=None, xmax=None, ymax=None): - for coord in link: - if type(coord[0]) is list: - xmin, ymin, xmax, ymax = process_coords(coord, xmin, ymin, xmax, ymax) + + def process_coords( + coord_lists: List[Any], + xmin: Optional[float] = None, + ymin: Optional[float] = None, + xmax: Optional[float] = None, + ymax: Optional[float] = None, + ) -> Tuple[Optional[float], Optional[float], Optional[float], Optional[float]]: + for coord in coord_lists: + if isinstance(coord[0], list): + xmin, ymin, xmax, ymax = process_coords( + coord, xmin, ymin, xmax, ymax + ) else: x, y = coord if xmin is None or x < xmin: @@ -366,6 +123,11 @@ def process_coords(link, xmin=None, ymin=None, xmax=None, ymax=None): xmin, ymin, xmax, ymax = process_coords(coordinates) + if xmin is None or ymin is None or xmax is None or ymax is None: + raise ValueError( + f"Could not determine bounds from coordinate sequence {coordinates}" + ) + return SpatialExtent([[xmin, ymin, xmax, ymax]]) @@ -381,62 +143,64 @@ class TemporalExtent: Attributes: intervals (List[List[datetime]]): A list of two datetimes wrapped in a list, - representing the temporal extent of a Collection. Open date ranges are represented - by either the start (the first element of the interval) or the end (the - second element of the interval) being None. + representing the temporal extent of a Collection. Open date ranges are + represented by either the start (the first element of the interval) or the + end (the second element of the interval) being None. Note: Datetimes are required to be in UTC. """ - def __init__(self, intervals): + + def __init__( + self, intervals: Union[List[List[Optional[Datetime]]], List[Optional[Datetime]]] + ): # A common mistake is to pass in a single interval instead of a # list of intervals. Account for this by transforming the input # in that case. - if isinstance(intervals, abc.Sequence): - if not isinstance(intervals[0], abc.Sequence): - intervals = [intervals] - - self.intervals = intervals + if isinstance(intervals, list) and isinstance(intervals[0], Datetime): + self.intervals = [cast(List[Optional[Datetime]], intervals)] + else: + self.intervals = cast(List[List[Optional[Datetime]]], intervals) - def to_dict(self): + def to_dict(self) -> Dict[str, Any]: """Generate a dictionary representing the JSON of this TemporalExtent. Returns: - dict: A serializion of the TemporalExtent that can be written out as JSON. + dict: A serialization of the TemporalExtent that can be written out as JSON. """ - encoded_intervals = [] + encoded_intervals: List[List[Optional[str]]] = [] for i in self.intervals: start = None end = None - if i[0]: + if i[0] is not None: start = datetime_to_str(i[0]) - if i[1]: + if i[1] is not None: end = datetime_to_str(i[1]) encoded_intervals.append([start, end]) - d = {'interval': encoded_intervals} + d = {"interval": encoded_intervals} return d - def clone(self): + def clone(self) -> "TemporalExtent": """Clones this object. Returns: TemporalExtent: The clone of this object. """ - return TemporalExtent(intervals=copy(self.intervals)) + return TemporalExtent(intervals=deepcopy(self.intervals)) @staticmethod - def from_dict(d): + def from_dict(d: Dict[str, Any]) -> "TemporalExtent": """Constructs an TemporalExtent from a dict. Returns: TemporalExtent: The TemporalExtent deserialized from the JSON dict. """ - parsed_intervals = [] - for i in d['interval']: + parsed_intervals: List[List[Optional[Datetime]]] = [] + for i in d["interval"]: start = None end = None @@ -449,21 +213,150 @@ def from_dict(d): return TemporalExtent(intervals=parsed_intervals) @staticmethod - def from_now(): + def from_now() -> "TemporalExtent": """Constructs an TemporalExtent with a single open interval that has the start time as the current time. Returns: TemporalExtent: The resulting TemporalExtent. """ - return TemporalExtent(intervals=[[datetime.utcnow().replace(microsecond=0), None]]) + return TemporalExtent( + intervals=[[Datetime.utcnow().replace(microsecond=0), None]] + ) + + +class Extent: + """Describes the spatiotemporal extents of a Collection. + + Args: + spatial (SpatialExtent): Potential spatial extent covered by the collection. + temporal (TemporalExtent): Potential temporal extent covered by the collection. + + Attributes: + spatial (SpatialExtent): Potential spatial extent covered by the collection. + temporal (TemporalExtent): Potential temporal extent covered by the collection. + """ + + def __init__(self, spatial: SpatialExtent, temporal: TemporalExtent): + self.spatial = spatial + self.temporal = temporal + + def to_dict(self) -> Dict[str, Any]: + """Generate a dictionary representing the JSON of this Extent. + + Returns: + dict: A serialization of the Extent that can be written out as JSON. + """ + d = {"spatial": self.spatial.to_dict(), "temporal": self.temporal.to_dict()} + + return d + + def clone(self) -> "Extent": + """Clones this object. + + Returns: + Extent: The clone of this extent. + """ + return Extent(spatial=copy(self.spatial), temporal=copy(self.temporal)) + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "Extent": + """Constructs an Extent from a dict. + + Returns: + Extent: The Extent deserialized from the JSON dict. + """ + + # Handle pre-0.8 spatial extents + spatial_extent = d["spatial"] + if isinstance(spatial_extent, list): + spatial_extent_dict: Dict[str, Any] = {"bbox": [spatial_extent]} + else: + spatial_extent_dict = spatial_extent + + # Handle pre-0.8 temporal extents + temporal_extent = d["temporal"] + if isinstance(temporal_extent, list): + temporal_extent_dict: Dict[str, Any] = {"interval": [temporal_extent]} + else: + temporal_extent_dict = temporal_extent + + return Extent( + SpatialExtent.from_dict(spatial_extent_dict), + TemporalExtent.from_dict(temporal_extent_dict), + ) + + @staticmethod + def from_items(items: Iterable["Item_Type"]) -> "Extent": + """Create an Extent based on the datetimes and bboxes of a list of items. + + Args: + items (List[Item]): A list of items to derive the extent from. + + Returns: + Extent: An Extent that spatially and temporally covers all of the + given items. + """ + bounds_values: List[List[float]] = [ + [float("inf")], + [float("inf")], + [float("-inf")], + [float("-inf")], + ] + datetimes: List[Datetime] = [] + starts: List[Datetime] = [] + ends: List[Datetime] = [] + + for item in items: + if item.bbox is not None: + for i in range(0, 4): + bounds_values[i].append(item.bbox[i]) + if item.datetime is not None: + datetimes.append(item.datetime) + if item.common_metadata.start_datetime is not None: + starts.append(item.common_metadata.start_datetime) + if item.common_metadata.end_datetime is not None: + ends.append(item.common_metadata.end_datetime) + + if not any(datetimes + starts): + start_timestamp = None + else: + start_timestamp = min( + [ + dt if dt.tzinfo else dt.replace(tzinfo=tz.UTC) + for dt in datetimes + starts + ] + ) + if not any(datetimes + ends): + end_timestamp = None + else: + end_timestamp = max( + [ + dt if dt.tzinfo else dt.replace(tzinfo=tz.UTC) + for dt in datetimes + ends + ] + ) + + spatial = SpatialExtent( + [ + [ + min(bounds_values[0]), + min(bounds_values[1]), + max(bounds_values[2]), + max(bounds_values[3]), + ] + ] + ) + temporal = TemporalExtent([[start_timestamp, end_timestamp]]) + + return Extent(spatial, temporal) class Provider: """Provides information about a provider of STAC data. A provider is any of the organizations that captured or processed the content of the collection and therefore - influenced the data offered by this collection. May also include information about the - final storage provider hosting the data. + influenced the data offered by this collection. May also include information about + the final storage provider hosting the data. Args: name (str): The name of the organization or the individual. @@ -485,36 +378,381 @@ class Provider: url (str): Optional homepage on which the provider describes the dataset and publishes contact information. """ - def __init__(self, name, description=None, roles=None, url=None): + + def __init__( + self, + name: str, + description: Optional[str] = None, + roles: Optional[List[str]] = None, + url: Optional[str] = None, + ): self.name = name self.description = description self.roles = roles self.url = url - def to_dict(self): + def to_dict(self) -> Dict[str, Any]: """Generate a dictionary representing the JSON of this Provider. Returns: - dict: A serializion of the Provider that can be written out as JSON. + dict: A serialization of the Provider that can be written out as JSON. """ - d = {'name': self.name} + d: Dict[str, Any] = {"name": self.name} if self.description is not None: - d['description'] = self.description + d["description"] = self.description if self.roles is not None: - d['roles'] = self.roles + d["roles"] = self.roles if self.url is not None: - d['url'] = self.url + d["url"] = self.url return d @staticmethod - def from_dict(d): + def from_dict(d: Dict[str, Any]) -> "Provider": """Constructs an Provider from a dict. Returns: TemporalExtent: The Provider deserialized from the JSON dict. """ - return Provider(name=d['name'], - description=d.get('description'), - roles=d.get('roles'), - url=d.get('url')) + return Provider( + name=d["name"], + description=d.get("description"), + roles=d.get("roles"), + url=d.get("url"), + ) + + +class RangeSummary(Generic[T]): + def __init__(self, minimum: T, maximum: T): + self.minimum = minimum + self.maximum = maximum + + def to_dict(self) -> Dict[str, Any]: + return {"minimum": self.minimum, "maximum": self.maximum} + + @classmethod + def from_dict(cls, d: Dict[str, Any], typ: Type[T] = Any) -> "RangeSummary[T]": + minimum: Optional[T] = get_required(d.get("minimum"), "RangeSummary", "minimum") + maximum: Optional[T] = get_required(d.get("maximum"), "RangeSummary", "maximum") + return cls(minimum=minimum, maximum=maximum) + + +class Summaries: + def __init__(self, summaries: Dict[str, Any]) -> None: + self._summaries = summaries + + self.lists: Dict[str, List[Any]] = {} + self.ranges: Dict[str, RangeSummary[Any]] = {} + self.schemas: Dict[str, Dict[str, Any]] = {} + self.other: Dict[str, Any] = {} + + for prop_key, summary in summaries.items(): + self.add(prop_key, summary) + + def get_list(self, prop: str, typ: Type[T]) -> Optional[List[T]]: + return self.lists.get(prop) + + def get_range(self, prop: str, typ: Type[T]) -> Optional[RangeSummary[T]]: + return self.ranges.get(prop) + + def get_schema(self, prop: str) -> Optional[Dict[str, Any]]: + return self.schemas.get(prop) + + def add( + self, + prop_key: str, + summary: Union[List[Any], RangeSummary[Any], Dict[str, Any]], + ) -> None: + if isinstance(summary, list): + self.lists[prop_key] = summary + elif isinstance(summary, dict): + if "minimum" in summary: + self.ranges[prop_key] = RangeSummary[Any].from_dict( + cast(Dict[str, Any], summary) + ) + else: + self.schemas[prop_key] = summary + elif isinstance(summary, RangeSummary): + self.ranges[prop_key] = summary + else: + self.other[prop_key] = summary + + def remove(self, prop_key: str) -> None: + self.lists.pop(prop_key, None) + self.ranges.pop(prop_key, None) + self.schemas.pop(prop_key, None) + self.other.pop(prop_key, None) + + def is_empty(self): + return not ( + any(self.lists) or any(self.ranges) or any(self.schemas) or any(self.other) + ) + + def to_dict(self) -> Dict[str, Any]: + return { + **self.lists, + **{k: v.to_dict() for k, v in self.ranges.items()}, + **self.schemas, + **self.other, + } + + @classmethod + def empty(cls) -> "Summaries": + return Summaries({}) + + +class Collection(Catalog): + """A Collection extends the Catalog spec with additional metadata that helps + enable discovery. + + Args: + id (str): Identifier for the collection. Must be unique within the STAC. + description (str): Detailed multi-line description to fully explain the + collection. `CommonMark 0.28 syntax `_ MAY + be used for rich text representation. + extent (Extent): Spatial and temporal extents that describe the bounds of + all items contained within this Collection. + title (str or None): Optional short descriptive one-line title for the + collection. + stac_extensions (List[str]): Optional list of extensions the Collection + implements. + href (str or None): Optional HREF for this collection, which be set as the + collection's self link's HREF. + catalog_type (str or None): Optional catalog type for this catalog. Must + be one of the values in :class`~pystac.CatalogType`. + license (str): Collection's license(s) as a + `SPDX License identifier `_, + `various`, or `proprietary`. If collection includes + data with multiple different licenses, use `various` and add a link for + each. Defaults to 'proprietary'. + keywords (List[str]): Optional list of keywords describing the collection. + providers (List[Provider]): Optional list of providers of this Collection. + summaries (dict): An optional map of property summaries, + either a set of values or statistics such as a range. + extra_fields (dict or None): Extra fields that are part of the top-level + JSON properties of the Collection. + + Attributes: + id (str): Identifier for the collection. + description (str): Detailed multi-line description to fully explain the + collection. + extent (Extent): Spatial and temporal extents that describe the bounds of + all items contained within this Collection. + title (str or None): Optional short descriptive one-line title for the + collection. + stac_extensions (List[str]): Optional list of extensions the Collection + implements. + keywords (List[str] or None): Optional list of keywords describing the + collection. + providers (List[Provider] or None): Optional list of providers of this + Collection. + assets (Optional[Dict[str, Asset]]): Optional map of Assets + summaries (dict or None): An optional map of property summaries, + either a set of values or statistics such as a range. + links (List[Link]): A list of :class:`~pystac.Link` objects representing + all links associated with this Collection. + extra_fields (dict or None): Extra fields that are part of the top-level + JSON properties of the Catalog. + """ + + STAC_OBJECT_TYPE = STACObjectType.COLLECTION + + DEFAULT_FILE_NAME = "collection.json" + """Default file name that will be given to this STAC object + in a canonical format.""" + + def __init__( + self, + id: str, + description: str, + extent: Extent, + title: Optional[str] = None, + stac_extensions: Optional[List[str]] = None, + href: Optional[str] = None, + extra_fields: Optional[Dict[str, Any]] = None, + catalog_type: Optional[CatalogType] = None, + license: str = "proprietary", + keywords: Optional[List[str]] = None, + providers: Optional[List[Provider]] = None, + summaries: Optional[Summaries] = None, + ): + super().__init__( + id, + description, + title, + stac_extensions, + extra_fields, + href, + catalog_type or CatalogType.ABSOLUTE_PUBLISHED, + ) + self.extent = extent + self.license = license + + self.stac_extensions: List[str] = stac_extensions or [] + self.keywords = keywords + self.providers = providers + self.summaries = summaries or Summaries.empty() + + self.assets: Dict[str, Asset] = {} + + def __repr__(self) -> str: + return "".format(self.id) + + def add_item( + self, + item: "Item_Type", + title: Optional[str] = None, + strategy: Optional[HrefLayoutStrategy] = None, + ) -> None: + super().add_item(item, title, strategy) + item.set_collection(self) + + def to_dict(self, include_self_link: bool = True) -> Dict[str, Any]: + d = super().to_dict(include_self_link) + d["extent"] = self.extent.to_dict() + d["license"] = self.license + if self.stac_extensions is not None: + d["stac_extensions"] = self.stac_extensions + if self.keywords is not None: + d["keywords"] = self.keywords + if self.providers is not None: + d["providers"] = list(map(lambda x: x.to_dict(), self.providers)) + if not self.summaries.is_empty(): + d["summaries"] = self.summaries.to_dict() + if any(self.assets): + d["assets"] = {k: v.to_dict() for k, v in self.assets.items()} + + return d + + def clone(self) -> "Collection": + clone = Collection( + id=self.id, + description=self.description, + extent=self.extent.clone(), + title=self.title, + stac_extensions=self.stac_extensions, + extra_fields=self.extra_fields, + catalog_type=self.catalog_type, + license=self.license, + keywords=self.keywords, + providers=self.providers, + summaries=self.summaries, + ) + + clone._resolved_objects.cache(clone) + + for link in self.links: + if link.rel == "root": + # Collection __init__ sets correct root to clone; don't reset + # if the root link points to self + root_is_self = link.is_resolved() and link.target is self + if not root_is_self: + clone.set_root(None) + clone.add_link(link.clone()) + else: + clone.add_link(link.clone()) + + return clone + + @classmethod + def from_dict( + cls, + d: Dict[str, Any], + href: Optional[str] = None, + root: Optional[Catalog] = None, + migrate: bool = False, + ) -> "Collection": + if migrate: + result = pystac.read_dict(d, href=href, root=root) + if not isinstance(result, Collection): + raise pystac.STACError(f"{result} is not a Catalog") + return result + + catalog_type = CatalogType.determine_type(d) + + d = deepcopy(d) + id = d.pop("id") + description = d.pop("description") + license = d.pop("license") + extent = Extent.from_dict(d.pop("extent")) + title = d.get("title") + stac_extensions = d.get("stac_extensions") + keywords = d.get("keywords") + providers = d.get("providers") + if providers is not None: + providers = list(map(lambda x: Provider.from_dict(x), providers)) + summaries = d.get("summaries") + if summaries is not None: + summaries = Summaries(summaries) + + assets: Optional[Dict[str, Any]] = d.get("assets", None) + links = d.pop("links") + + d.pop("stac_version") + + collection = Collection( + id=id, + description=description, + extent=extent, + title=title, + stac_extensions=stac_extensions, + extra_fields=d, + license=license, + keywords=keywords, + providers=providers, + summaries=summaries, + href=href, + catalog_type=catalog_type, + ) + + for link in links: + if link["rel"] == "root": + # Remove the link that's generated in Catalog's constructor. + collection.remove_links("root") + + if link["rel"] != "self" or href is None: + collection.add_link(Link.from_dict(link)) + + if assets is not None: + for asset_key, asset_dict in assets.items(): + collection.add_asset(asset_key, Asset(asset_dict)) + + return collection + + def get_assets(self) -> Dict[str, Asset]: + """Get this item's assets. + + Returns: + Dict[str, Asset]: A copy of the dictionary of this item's assets. + """ + return dict(self.assets.items()) + + def add_asset(self, key: str, asset: Asset) -> None: + """Adds an Asset to this item. + + Args: + key (str): The unique key of this asset. + asset (Asset): The Asset to add. + """ + asset.set_owner(self) + self.assets[key] = asset + + def update_extent_from_items(self) -> None: + """ + Update datetime and bbox based on all items to a single bbox and time window. + """ + self.extent = Extent.from_items(self.get_all_items()) + + def full_copy( + self, root: Optional["Catalog"] = None, parent: Optional["Catalog"] = None + ) -> "Collection": + return cast(Collection, super().full_copy(root, parent)) + + @classmethod + def from_file( + cls, href: str, stac_io: Optional[pystac.StacIO] = None + ) -> "Collection": + result = super().from_file(href, stac_io) + if not isinstance(result, Collection): + raise pystac.STACTypeError(f"{result} is not a {Collection}.") + return result diff --git a/pystac/errors.py b/pystac/errors.py new file mode 100644 index 000000000..39bad4c7a --- /dev/null +++ b/pystac/errors.py @@ -0,0 +1,70 @@ +from typing import Any, Optional, Union + + +class STACError(Exception): + """A STACError is raised for errors relating to STAC, e.g. for + invalid formats or trying to operate on a STAC that does not have + the required information available. + """ + + pass + + +class STACTypeError(Exception): + """A STACTypeError is raised when encountering a representation of + a STAC entity that is not correct for the context; for example, if + a Catalog JSON was read in as an Item. + """ + + pass + + +class ExtensionTypeError(Exception): + """An ExtensionTypeError is raised when an extension is used against + an object that the extension does not apply to + """ + + pass + + +class ExtensionAlreadyExistsError(Exception): + """An ExtensionAlreadyExistsError is raised when extension hooks + are registered with PySTAC if there are already hooks registered + for an extension with the same ID.""" + + pass + + +class RequiredPropertyMissing(Exception): + """This error is raised when a required value was expected + to be there but was missing or None. This will happen, for example, + in an extension that has required properties, where the required + property is missing from the extended object + + Args: + obj: Description of the object that will have a property missing. + Should include a __repr__ that identifies the object for the + error message, or be a string that describes the object. + prop: The property that is missing + """ + + def __init__( + self, obj: Union[str, Any], prop: str, msg: Optional[str] = None + ) -> None: + msg = msg or f"{repr(obj)} does not have required property {prop}" + super().__init__(msg) + + +class STACValidationError(Exception): + """Represents a validation error. Thrown by validation calls if the STAC JSON + is invalid. + + Args: + source (object): Source of the exception. Type will be determined by the + validation implementation. For the default JsonSchemaValidator this will a + the ``jsonschema.ValidationError``. + """ + + def __init__(self, message: str, source: Optional[Any] = None): + super().__init__(message) + self.source = source diff --git a/pystac/extensions/__init__.py b/pystac/extensions/__init__.py index 1f944a7d6..e69de29bb 100644 --- a/pystac/extensions/__init__.py +++ b/pystac/extensions/__init__.py @@ -1,32 +0,0 @@ -# flake8: noqa -from enum import Enum - - -class ExtensionError(Exception): - """An error related to the construction of extensions. - """ - pass - - -class Extensions(str, Enum): - """Enumerates the IDs of common extensions.""" - def __str__(self): - return str(self.value) - - CHECKSUM = 'checksum' - COLLECTION_ASSETS = 'collection-assets' - DATACUBE = 'datacube' - EO = 'eo' - ITEM_ASSETS = 'item-assets' - LABEL = 'label' - POINTCLOUD = 'pointcloud' - PROJECTION = 'projection' - SAR = 'sar' - SAT = 'sat' - SCIENTIFIC = 'scientific' - SINGLE_FILE_STAC = 'single-file-stac' - TILED_ASSETS = 'tiled-assets' - TIMESTAMPS = 'timestamps' - VERSION = 'version' - VIEW = 'view' - FILE = 'file' diff --git a/pystac/extensions/base.py b/pystac/extensions/base.py index e053f8f8a..191f4521e 100644 --- a/pystac/extensions/base.py +++ b/pystac/extensions/base.py @@ -1,277 +1,77 @@ -from abc import (ABC, abstractmethod) +from abc import ABC, abstractmethod +from typing import Generic, Iterable, List, Optional, Dict, Any, Type, TypeVar, Union -from pystac.catalog import Catalog -from pystac.collection import Collection -from pystac.item import Item -from pystac.extensions import ExtensionError +import pystac -class ExtendedObject: - """ExtendedObject maps STACObject classes (Catalog, Collection and Item) to - extension classes (classes that implement one of CatalogExtension, CollectionExtesion, - or ItemCollection). When an extension is registered with PySTAC it uses the registered - list of ExtendedObject to determine how to handle extending objects, e.g. when item.ext.label - is called, it searches for the ExtendedObject associated with the label extension that - maps Item to LabelItemExt. - - Args: - stac_object_class: The STAC object class that is being extended. - extension_class: The class of the extension, e.g. LabelItemExt - """ - def __init__(self, stac_object_class, extension_class): - if stac_object_class is Catalog: - if not issubclass(extension_class, CatalogExtension): - raise ExtensionError( - "Classes extending catalogs must inherit from CatalogExtension") - if stac_object_class is Collection: - if not issubclass(extension_class, CollectionExtension): - raise ExtensionError( - "Classes extending collections must inherit from CollectionExtension") - if stac_object_class is Item: - if not issubclass(extension_class, ItemExtension): - raise ExtensionError("Classes extending item must inherit from ItemExtension") - - self.stac_object_class = stac_object_class - self.extension_class = extension_class +class SummariesExtension: + def __init__(self, collection: pystac.Collection) -> None: + self.summaries = collection.summaries + def _set_summary( + self, + prop_key: str, + v: Optional[Union[List[Any], pystac.RangeSummary[Any], Dict[str, Any]]], + ) -> None: + if v is None: + self.summaries.remove(prop_key) + else: + self.summaries.add(prop_key, v) -class ExtensionDefinition: - """Defines an extension that can be registered with PySTAC. - Args: - extension_id: The ID for the extension. This is the same idea that will appear in - the ``stac_extensions`` property of implementing objects, and will be used to refer - to the extension in PySTAC. - extended_objects (List[ExtendedObject]): The list of ExtendedObjects which map STACObject - types to their extension. Should only contain one entry per stac object type. - """ - def __init__(self, extension_id, extended_objects): - self.extension_id = extension_id - self.extended_objects = extended_objects +P = TypeVar("P") -class CatalogExtension(ABC): - @classmethod - def _from_object(cls, stac_object): - return cls.from_catalog(stac_object) +class PropertiesExtension(ABC): + properties: Dict[str, Any] + additional_read_properties: Optional[Iterable[Dict[str, Any]]] = None - @classmethod - @abstractmethod - def from_catalog(cls, catalog): - raise NotImplementedError("from_catalog") + def _get_property(self, prop_name: str, typ: Type[P] = Type[Any]) -> Optional[P]: + result: Optional[typ] = self.properties.get(prop_name) + if result is not None: + return result + if self.additional_read_properties is not None: + for props in self.additional_read_properties: + result = props.get(prop_name) + if result is not None: + return result + return None - @classmethod - @abstractmethod - def _object_links(cls): - raise NotImplementedError("_object_links") + def _set_property( + self, prop_name: str, v: Optional[Any], pop_if_none: bool = True + ) -> None: + if v is None and pop_if_none: + self.properties.pop(prop_name, None) + else: + self.properties[prop_name] = v - @classmethod - def enable_extension(cls, stac_object): - """Enables the extension for the given stac_object. - Child classes can choose to override this method in order to - modify the stac_object when an extension is enabled. - """ - pass +S = TypeVar("S", bound=pystac.STACObject) -class CollectionExtension(ABC): - @classmethod - def _from_object(cls, stac_object): - return cls.from_collection(stac_object) - - @classmethod - @abstractmethod - def from_collection(cls, catalog): - raise NotImplementedError("from_collection") +class ExtensionManagementMixin(Generic[S], ABC): @classmethod @abstractmethod - def _object_links(cls): - raise NotImplementedError("_object_links") - - @classmethod - def enable_extension(cls, stac_object): - """Enables the extension for the given stac_object. - Child classes can choose to override this method in order to - modify the stac_object when an extension is enabled. - """ + def get_schema_uri(cls) -> str: pass - -class ItemExtension(ABC): @classmethod - def _from_object(cls, stac_object): - return cls.from_item(stac_object) - - @classmethod - @abstractmethod - def from_item(cls, item): - raise NotImplementedError("from_item") + def add_to(cls, obj: S) -> None: + if obj.stac_extensions is None: + obj.stac_extensions = [cls.get_schema_uri()] + else: + obj.stac_extensions.append(cls.get_schema_uri()) @classmethod - @abstractmethod - def _object_links(cls): - raise NotImplementedError("_object_links") + def remove_from(cls, obj: S) -> None: + if obj.stac_extensions is not None: + obj.stac_extensions = [ + uri for uri in obj.stac_extensions if uri != cls.get_schema_uri() + ] @classmethod - def enable_extension(cls, stac_object): - """Enables the extension for the given stac_object. - Child classes can choose to override this method in order to - modify the stac_object when an extension is enabled. - """ - pass - - def _set_property(self, key, value, asset): - ''' - Set an Item or an Asset property. - - If an Asset is supplied, sets the property on the Asset. - Otherwise sets the Item's value. - - If the passed value to set is None, the property key is removed from - the dictionary of properties. - - It's recommended to use this method from extensions, instead of implementing - the logic for that in the corresponding subclasses. - - Args: - key (str): The name of the property - value (Object): the value to set - asset: The Asset to modify. If None, the property will be set in the Item - ''' - target = self.item.properties if asset is None else asset.properties - if value is None: - target.pop(key, None) - else: - target[key] = value - - -class RegisteredSTACExtensions: - def __init__(self, extension_definitions): - self.extensions = dict([(e.extension_id, e) for e in extension_definitions]) - - def is_registered_extension(self, extension_id): - """Determines whether or not the given extension ID has been registered.""" - return extension_id in self.extensions - - def get_registered_extensions(self): - """Returns the list of registered extension IDs.""" - return list(self.extensions.keys()) - - def add_extension(self, extension_definition): - e_id = extension_definition.extension_id - if e_id in self.extensions: - raise ExtensionError("ExtensionDefinition with id '{}' already exists.".format(e_id)) - - self.extensions[e_id] = extension_definition - - def remove_extension(self, extension_id): - """Remove an extension from PySTAC.""" - if extension_id not in self.extensions: - raise ExtensionError( - "ExtensionDefinition with id '{}' is not registered.".format(extension_id)) - del self.extensions[extension_id] - - def get_extension_class(self, extension_id, stac_object_class): - """Gets the extension class for a given stac object class if one exists, otherwise - returns None - """ - ext = self.extensions.get(extension_id) - if ext is None: - raise ExtensionError("No ExtensionDefinition registered with id '{}'. " - "Is the extension ID correct, or are you forgetting to call " - "'add_extension' for a custom extension?".format(extension_id)) - - ext_classes = [ - e.extension_class for e in ext.extended_objects - if issubclass(stac_object_class, e.stac_object_class) - ] - - ext_class = None - if len(ext_classes) == 0: - return None - elif len(ext_classes) == 1: - ext_class = ext_classes[0] - else: - # Need to check collection extensions before catalogs. - sort_key = {} - for c in ext_classes: - for i, base_cl in enumerate([ItemExtension, CollectionExtension, CatalogExtension]): - if issubclass(c, base_cl): - sort_key[c] = i - break - if c not in sort_key: - sort_key[c] = -1 - - ext_class = sorted(ext_classes, key=lambda c: sort_key[c])[0] - - return ext_class - - def extend_object(self, extension_id, stac_object): - """Returns the extension object for the given STACObject and the given - extension_id - """ - ext_class = self.get_extension_class(extension_id, type(stac_object)) - - if ext_class is None: - raise ExtensionError("Extension '{}' does not extend objects of type {}".format( - extension_id, type(stac_object))) - - return ext_class._from_object(stac_object) - - def get_extended_object_links(self, stac_object): - if stac_object.stac_extensions is None: - return [] - return [ - link_rel for e_id in stac_object.stac_extensions if e_id in self.extensions - for e_obj in self.extensions[e_id].extended_objects - if issubclass(type(stac_object), e_obj.stac_object_class) - for link_rel in e_obj.extension_class._object_links() - ] - - def can_extend(self, extension_id, stac_object_class): - """Returns True if the extension can extend the given object type. - - Args: - extension_id (str): The extension ID to check. - stac_object_class: the class of the object to check. Will check against subclasses, - so will return the correct result even if the object is a subclass of Catalog, - Collection or Item. - - Returns: - bool - """ - ext = self.extensions.get(extension_id) - - # Check to make sure this is a registered extension. - if ext is None: - raise ExtensionError("'{}' is not a registered extension".format(extension_id)) - - return any([ - e.extension_class for e in ext.extended_objects - if issubclass(stac_object_class, e.stac_object_class) - ]) - - def enable_extension(self, extension_id, stac_object): - """Enables the extension for the given object. - - This will at least ensure the extension ID is in the object's "stac_extensions" - property. Some extensions may make additional modifications to the object. - """ - # Check to make sure this is a registered extension. - if not self.is_registered_extension(extension_id): - raise ExtensionError("'{}' is not an extension " - "registered with PySTAC".format(extension_id)) - - ext_class = self.get_extension_class(extension_id, type(stac_object)) - - if ext_class is None: - raise ExtensionError("Extension '{}' does not extend objects of type {}".format( - extension_id, type(stac_object))) - - if stac_object.stac_extensions is None: - stac_object.stac_extensions = [extension_id] - elif extension_id not in stac_object.stac_extensions: - stac_object.stac_extensions.append(extension_id) - - ext_class.enable_extension(stac_object) + def has_extension(cls, obj: S) -> bool: + return ( + obj.stac_extensions is not None + and cls.get_schema_uri() in obj.stac_extensions + ) diff --git a/pystac/extensions/datacube.py b/pystac/extensions/datacube.py new file mode 100644 index 000000000..118366c9f --- /dev/null +++ b/pystac/extensions/datacube.py @@ -0,0 +1,389 @@ +"""Implements the Datacube extension. + +https://github.com/stac-extensions/datacube +""" + +from abc import ABC +from typing import Any, Dict, Generic, List, Optional, Set, TypeVar, Union, cast + +import pystac +from pystac.extensions.base import ( + ExtensionManagementMixin, + PropertiesExtension, +) +from pystac.extensions.hooks import ExtensionHooks +from pystac.utils import get_required, map_opt + +T = TypeVar("T", pystac.Collection, pystac.Item, pystac.Asset) + +SCHEMA_URI = "https://stac-extensions.github.io/datacube/v1.0.0/schema.json" + +DIMENSIONS_PROP = "cube:dimensions" + +# Dimension properties +DIM_TYPE_PROP = "type" +DIM_DESC_PROP = "description" +DIM_AXIS_PROP = "axis" +DIM_EXTENT_PROP = "extent" +DIM_VALUES_PROP = "values" +DIM_STEP_PROP = "step" +DIM_REF_SYS_PROP = "reference_system" +DIM_UNIT_PROP = "unit" + + +class Dimension(ABC): + def __init__(self, properties: Dict[str, Any]) -> None: + self.properties = properties + + @property + def dim_type(self) -> str: + return get_required( + self.properties.get(DIM_TYPE_PROP), "cube:dimension", DIM_TYPE_PROP + ) + + @dim_type.setter + def dim_type(self, v: str) -> None: + self.properties[DIM_TYPE_PROP] = v + + @property + def description(self) -> Optional[str]: + return self.properties.get(DIM_DESC_PROP) + + @description.setter + def description(self, v: Optional[str]) -> None: + if v is None: + self.properties.pop(DIM_DESC_PROP, None) + else: + self.properties[DIM_DESC_PROP] = v + + def to_dict(self) -> Dict[str, Any]: + return self.properties + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "Dimension": + dim_type = d.get(DIM_TYPE_PROP) + if dim_type is None: + raise pystac.RequiredPropertyMissing("cube_dimension", DIM_TYPE_PROP) + if dim_type == "spatial": + axis = d.get(DIM_AXIS_PROP) + if axis is None: + raise pystac.RequiredPropertyMissing("cube_dimension", DIM_AXIS_PROP) + if axis == "z": + return VerticalSpatialDimension(d) + else: + return HorizontalSpatialDimension(d) + elif dim_type == "temporal": + # The v1.0.0 spec says that AdditionalDimensions can have + # type 'temporal', but it is unclear how to differentiate that + # from a temporal dimension. Just key off of type for now. + # See https://github.com/stac-extensions/datacube/issues/5 + return TemporalDimension(d) + else: + return AdditionalDimension(d) + + +class HorizontalSpatialDimension(Dimension): + @property + def axis(self) -> str: + return get_required( + self.properties.get(DIM_AXIS_PROP), "cube:dimension", DIM_AXIS_PROP + ) + + @axis.setter + def axis(self, v: str) -> None: + self.properties[DIM_TYPE_PROP] = v + + @property + def extent(self) -> List[float]: + return get_required( + self.properties.get(DIM_EXTENT_PROP), "cube:dimension", DIM_EXTENT_PROP + ) + + @extent.setter + def extent(self, v: List[float]) -> None: + self.properties[DIM_EXTENT_PROP] = v + + @property + def values(self) -> Optional[List[float]]: + return self.properties.get(DIM_VALUES_PROP) + + @values.setter + def values(self, v: Optional[List[float]]) -> None: + if v is None: + self.properties.pop(DIM_VALUES_PROP, None) + else: + self.properties[DIM_VALUES_PROP] = v + + @property + def step(self) -> Optional[float]: + return self.properties.get(DIM_STEP_PROP) + + @step.setter + def step(self, v: Optional[float]) -> None: + self.properties[DIM_STEP_PROP] = v + + def clear_step(self) -> None: + """Setting step to None sets it to the null value, + which means irregularly spaced steps. Use clear_step + to remove it from the properties.""" + self.properties.pop(DIM_STEP_PROP, None) + + @property + def reference_system(self) -> Optional[Union[str, float, Dict[str, Any]]]: + return self.properties.get(DIM_REF_SYS_PROP) + + @reference_system.setter + def reference_system(self, v: Optional[Union[str, float, Dict[str, Any]]]) -> None: + if v is None: + self.properties.pop(DIM_REF_SYS_PROP, None) + else: + self.properties[DIM_REF_SYS_PROP] = v + + +class VerticalSpatialDimension(Dimension): + @property + def axis(self) -> str: + return get_required( + self.properties.get(DIM_AXIS_PROP), "cube:dimension", DIM_AXIS_PROP + ) + + @axis.setter + def axis(self, v: str) -> None: + self.properties[DIM_TYPE_PROP] = v + + @property + def extent(self) -> Optional[List[Optional[float]]]: + return self.properties.get(DIM_EXTENT_PROP) + + @extent.setter + def extent(self, v: Optional[List[Optional[float]]]) -> None: + if v is None: + self.properties.pop(DIM_EXTENT_PROP, None) + else: + self.properties[DIM_EXTENT_PROP] = v + + @property + def values(self) -> Optional[Union[List[float], List[str]]]: + return self.properties.get(DIM_VALUES_PROP) + + @values.setter + def values(self, v: Optional[Union[List[float], List[str]]]) -> None: + if v is None: + self.properties.pop(DIM_VALUES_PROP, None) + else: + self.properties[DIM_VALUES_PROP] = v + + @property + def step(self) -> Optional[float]: + return self.properties.get(DIM_STEP_PROP) + + @step.setter + def step(self, v: Optional[float]) -> None: + self.properties[DIM_STEP_PROP] = v + + def clear_step(self) -> None: + """Setting step to None sets it to the null value, + which means irregularly spaced steps. Use clear_step + to remove it from the properties.""" + self.properties.pop(DIM_STEP_PROP, None) + + @property + def unit(self) -> Optional[str]: + return self.properties.get(DIM_UNIT_PROP) + + @unit.setter + def unit(self, v: Optional[str]) -> None: + if v is None: + self.properties.pop(DIM_UNIT_PROP, None) + else: + self.properties[DIM_UNIT_PROP] = v + + @property + def reference_system(self) -> Optional[Union[str, float, Dict[str, Any]]]: + return self.properties.get(DIM_REF_SYS_PROP) + + @reference_system.setter + def reference_system(self, v: Optional[Union[str, float, Dict[str, Any]]]) -> None: + if v is None: + self.properties.pop(DIM_REF_SYS_PROP, None) + else: + self.properties[DIM_REF_SYS_PROP] = v + + +class TemporalDimension(Dimension): + @property + def extent(self) -> Optional[List[Optional[str]]]: + return self.properties.get(DIM_EXTENT_PROP) + + @extent.setter + def extent(self, v: Optional[List[Optional[str]]]) -> None: + if v is None: + self.properties.pop(DIM_EXTENT_PROP, None) + else: + self.properties[DIM_EXTENT_PROP] = v + + @property + def values(self) -> Optional[List[str]]: + return self.properties.get(DIM_VALUES_PROP) + + @values.setter + def values(self, v: Optional[List[str]]) -> None: + if v is None: + self.properties.pop(DIM_VALUES_PROP, None) + else: + self.properties[DIM_VALUES_PROP] = v + + @property + def step(self) -> Optional[str]: + return self.properties.get(DIM_STEP_PROP) + + @step.setter + def step(self, v: Optional[str]) -> None: + self.properties[DIM_STEP_PROP] = v + + def clear_step(self) -> None: + """Setting step to None sets it to the null value, + which means irregularly spaced steps. Use clear_step + to remove it from the properties.""" + self.properties.pop(DIM_STEP_PROP, None) + + +class AdditionalDimension(Dimension): + @property + def extent(self) -> Optional[List[Optional[float]]]: + return self.properties.get(DIM_EXTENT_PROP) + + @extent.setter + def extent(self, v: Optional[List[Optional[float]]]) -> None: + if v is None: + self.properties.pop(DIM_EXTENT_PROP, None) + else: + self.properties[DIM_EXTENT_PROP] = v + + @property + def values(self) -> Optional[Union[List[str], List[float]]]: + return self.properties.get(DIM_VALUES_PROP) + + @values.setter + def values(self, v: Optional[Union[List[str], List[float]]]) -> None: + if v is None: + self.properties.pop(DIM_VALUES_PROP, None) + else: + self.properties[DIM_VALUES_PROP] = v + + @property + def step(self) -> Optional[float]: + return self.properties.get(DIM_STEP_PROP) + + @step.setter + def step(self, v: Optional[float]) -> None: + self.properties[DIM_STEP_PROP] = v + + def clear_step(self) -> None: + """Setting step to None sets it to the null value, + which means irregularly spaced steps. Use clear_step + to remove it from the properties.""" + self.properties.pop(DIM_STEP_PROP, None) + + @property + def unit(self) -> Optional[str]: + return self.properties.get(DIM_UNIT_PROP) + + @unit.setter + def unit(self, v: Optional[str]) -> None: + if v is None: + self.properties.pop(DIM_UNIT_PROP, None) + else: + self.properties[DIM_UNIT_PROP] = v + + @property + def reference_system(self) -> Optional[Union[str, float, Dict[str, Any]]]: + return self.properties.get(DIM_REF_SYS_PROP) + + @reference_system.setter + def reference_system(self, v: Optional[Union[str, float, Dict[str, Any]]]) -> None: + if v is None: + self.properties.pop(DIM_REF_SYS_PROP, None) + else: + self.properties[DIM_REF_SYS_PROP] = v + + +class DatacubeExtension( + Generic[T], + PropertiesExtension, + ExtensionManagementMixin[Union[pystac.Collection, pystac.Item]], +): + def apply(self, dimensions: Dict[str, Dimension]) -> None: + self.dimensions = dimensions + + @property + def dimensions(self) -> Dict[str, Dimension]: + return get_required( + map_opt( + lambda d: {k: Dimension.from_dict(v) for k, v in d.items()}, + self._get_property(DIMENSIONS_PROP, Dict[str, Any]), + ), + self, + DIMENSIONS_PROP, + ) + + @dimensions.setter + def dimensions(self, v: Dict[str, Dimension]) -> None: + self._set_property(DIMENSIONS_PROP, {k: dim.to_dict() for k, dim in v.items()}) + + @classmethod + def get_schema_uri(cls) -> str: + return SCHEMA_URI + + @staticmethod + def ext(obj: T) -> "DatacubeExtension[T]": + if isinstance(obj, pystac.Collection): + return cast(DatacubeExtension[T], CollectionDatacubeExtension(obj)) + if isinstance(obj, pystac.Item): + return cast(DatacubeExtension[T], ItemDatacubeExtension(obj)) + elif isinstance(obj, pystac.Asset): + return cast(DatacubeExtension[T], AssetDatacubeExtension(obj)) + else: + raise pystac.ExtensionTypeError( + f"Datacube extension does not apply to type {type(obj)}" + ) + + +class CollectionDatacubeExtension(DatacubeExtension[pystac.Collection]): + def __init__(self, collection: pystac.Collection): + self.collection = collection + self.properties = collection.extra_fields + + def __repr__(self) -> str: + return "".format(self.collection.id) + + +class ItemDatacubeExtension(DatacubeExtension[pystac.Item]): + def __init__(self, item: pystac.Item): + self.item = item + self.properties = item.properties + + def __repr__(self) -> str: + return "".format(self.item.id) + + +class AssetDatacubeExtension(DatacubeExtension[pystac.Asset]): + def __init__(self, asset: pystac.Asset): + self.asset_href = asset.href + self.properties = asset.properties + if asset.owner and isinstance(asset.owner, pystac.Item): + self.additional_read_properties = [asset.owner.properties] + + def __repr__(self) -> str: + return "".format(self.asset_href) + + +class DatacubeExtensionHooks(ExtensionHooks): + schema_uri: str = SCHEMA_URI + prev_extension_ids: Set[str] = set(["datacube"]) + stac_object_types: Set[pystac.STACObjectType] = set( + [pystac.STACObjectType.COLLECTION, pystac.STACObjectType.ITEM] + ) + + +DATACUBE_EXTENSION_HOOKS = DatacubeExtensionHooks() diff --git a/pystac/extensions/eo.py b/pystac/extensions/eo.py index 91b54e783..56209f54d 100644 --- a/pystac/extensions/eo.py +++ b/pystac/extensions/eo.py @@ -1,143 +1,29 @@ -"""Implement the Electro-Optical (EO) extension. +"""Implements the Electro-Optical (EO) extension. https://github.com/stac-extensions/eo """ -from pystac import Extensions -from pystac.item import Item -from pystac.extensions.base import (ItemExtension, ExtensionDefinition, ExtendedObject) +import re +from typing import Any, Dict, Generic, List, Optional, Set, Tuple, TypeVar, cast +import pystac +from pystac.collection import RangeSummary +from pystac.extensions.base import ( + ExtensionManagementMixin, + PropertiesExtension, + SummariesExtension, +) +from pystac.extensions.hooks import ExtensionHooks +from pystac.extensions import view +from pystac.serialization.identify import STACJSONDescription, STACVersionID +from pystac.utils import get_required, map_opt -class EOItemExt(ItemExtension): - """EOItemExt is the extension of the Item in the eo extension which - represents a snapshot of the earth for a single date and time. - - Args: - item (Item): The item to be extended. - - Attributes: - item (Item): The Item that is being extended. - - Note: - Using EOItemExt to directly wrap an item will add the 'eo' extension ID to - the item's stac_extensions. - """ - def __init__(self, item): - if item.stac_extensions is None: - item.stac_extensions = [Extensions.EO] - elif Extensions.EO not in item.stac_extensions: - item.stac_extensions.append(Extensions.EO) - - self.item = item - - def apply(self, bands, cloud_cover=None): - """Applies label extension properties to the extended Item. - - Args: - bands (List[Band]): a list of :class:`~pystac.Band` objects that represent - the available bands. - cloud_cover (float or None): The estimate of cloud cover as a percentage (0-100) of the - entire scene. If not available the field should not be provided. - """ - self.bands = bands - self.cloud_cover = cloud_cover - - @property - def bands(self): - """Get or sets a list of :class:`~pystac.Band` objects that represent - the available bands. - - Returns: - List[Band] - """ - return self.get_bands() - - @bands.setter - def bands(self, v): - self.set_bands(v) - - def get_bands(self, asset=None): - """Gets an Item or an Asset bands. - - If an Asset is supplied and the bands property exists on the Asset, - returns the Asset's value. Otherwise returns the Item's value or - all the asset's eo bands - - Returns: - List[Band] - """ - if asset is not None and 'eo:bands' in asset.properties: - bands = asset.properties.get('eo:bands') - else: - bands = self.item.properties.get('eo:bands') - - # get assets with eo:bands even if not in item - if asset is None and bands is None: - bands = [] - for (key, value) in self.item.get_assets().items(): - if 'eo:bands' in value.properties: - bands.extend(value.properties.get('eo:bands')) - - if bands is not None: - bands = [Band(b) for b in bands] +T = TypeVar("T", pystac.Item, pystac.Asset) - return bands +SCHEMA_URI = "https://stac-extensions.github.io/eo/v1.0.0/schema.json" - def set_bands(self, bands, asset=None): - """Set an Item or an Asset bands. - - If an Asset is supplied, sets the property on the Asset. - Otherwise sets the Item's value. - """ - band_dicts = [b.to_dict() for b in bands] - self._set_property('eo:bands', band_dicts, asset) - - @property - def cloud_cover(self): - """Get or sets the estimate of cloud cover as a percentage (0-100) of the - entire scene. If not available the field should not be provided. - - Returns: - float or None - """ - return self.get_cloud_cover() - - @cloud_cover.setter - def cloud_cover(self, v): - self.set_cloud_cover(v) - - def get_cloud_cover(self, asset=None): - """Gets an Item or an Asset cloud_cover. - - If an Asset is supplied and the Item property exists on the Asset, - returns the Asset's value. Otherwise returns the Item's value - - Returns: - float - """ - if asset is None or 'eo:cloud_cover' not in asset.properties: - return self.item.properties.get('eo:cloud_cover') - else: - return asset.properties.get('eo:cloud_cover') - - def set_cloud_cover(self, cloud_cover, asset=None): - """Set an Item or an Asset cloud_cover. - - If an Asset is supplied, sets the property on the Asset. - Otherwise sets the Item's value. - """ - self._set_property('eo:cloud_cover', cloud_cover, asset) - - def __repr__(self): - return ''.format(self.item.id) - - @classmethod - def _object_links(cls): - return [] - - @classmethod - def from_item(cls, item): - return cls(item) +BANDS_PROP = "eo:bands" +CLOUD_COVER_PROP = "eo:cloud_cover" class Band: @@ -145,28 +31,31 @@ class Band: Use Band.create to create a new Band. """ - def __init__(self, properties): + + def __init__(self, properties: Dict[str, Any]) -> None: self.properties = properties - def apply(self, - name, - common_name=None, - description=None, - center_wavelength=None, - full_width_half_max=None): + def apply( + self, + name: str, + common_name: Optional[str] = None, + description: Optional[str] = None, + center_wavelength: Optional[float] = None, + full_width_half_max: Optional[float] = None, + ) -> None: """ Sets the properties for this Band. Args: name (str): The name of the band (e.g., "B01", "B02", "B1", "B5", "QA"). - common_name (str): The name commonly used to refer to the band to make it easier - to search for bands across instruments. See the `list of accepted common names - `_. + common_name (str): The name commonly used to refer to the band to make it + easier to search for bands across instruments. See the `list of + accepted common names `_. description (str): Description to fully explain the band. center_wavelength (float): The center wavelength of the band, in micrometers (μm). full_width_half_max (float): Full width at half maximum (FWHM). The width of the band, as measured at half the maximum transmission, in micrometers (μm). - """ + """ # noqa self.name = name self.common_name = common_name self.description = description @@ -174,12 +63,14 @@ def apply(self, self.full_width_half_max = full_width_half_max @classmethod - def create(cls, - name, - common_name=None, - description=None, - center_wavelength=None, - full_width_half_max=None): + def create( + cls, + name: str, + common_name: Optional[str] = None, + description: Optional[str] = None, + center_wavelength: Optional[float] = None, + full_width_half_max: Optional[float] = None, + ) -> "Band": """ Creates a new band. @@ -192,100 +83,102 @@ def create(cls, center_wavelength (float): The center wavelength of the band, in micrometers (μm). full_width_half_max (float): Full width at half maximum (FWHM). The width of the band, as measured at half the maximum transmission, in micrometers (μm). - """ + """ # noqa b = cls({}) - b.apply(name=name, - common_name=common_name, - description=description, - center_wavelength=center_wavelength, - full_width_half_max=full_width_half_max) + b.apply( + name=name, + common_name=common_name, + description=description, + center_wavelength=center_wavelength, + full_width_half_max=full_width_half_max, + ) return b @property - def name(self): + def name(self) -> str: """Get or sets the name of the band (e.g., "B01", "B02", "B1", "B5", "QA"). Returns: str """ - return self.properties.get('name') + return get_required(self.properties["name"], self, "name") @name.setter - def name(self, v): - self.properties['name'] = v + def name(self, v: str) -> None: + self.properties["name"] = v @property - def common_name(self): + def common_name(self) -> Optional[str]: """Get or sets the name commonly used to refer to the band to make it easier to search for bands across instruments. See the `list of accepted common names `_. Returns: - str - """ - return self.properties.get('common_name') + Optional[str] + """ # noqa + return self.properties.get("common_name") @common_name.setter - def common_name(self, v): + def common_name(self, v: Optional[str]) -> None: if v is not None: - self.properties['common_name'] = v + self.properties["common_name"] = v else: - self.properties.pop('common_name', None) + self.properties.pop("common_name", None) @property - def description(self): + def description(self) -> Optional[str]: """Get or sets the description to fully explain the band. CommonMark 0.29 syntax MAY be used for rich text representation. Returns: str """ - return self.properties.get('description') + return self.properties.get("description") @description.setter - def description(self, v): + def description(self, v: Optional[str]) -> None: if v is not None: - self.properties['description'] = v + self.properties["description"] = v else: - self.properties.pop('description', None) + self.properties.pop("description", None) @property - def center_wavelength(self): + def center_wavelength(self) -> Optional[float]: """Get or sets the center wavelength of the band, in micrometers (μm). Returns: float """ - return self.properties.get('center_wavelength') + return self.properties.get("center_wavelength") @center_wavelength.setter - def center_wavelength(self, v): + def center_wavelength(self, v: Optional[float]) -> None: if v is not None: - self.properties['center_wavelength'] = v + self.properties["center_wavelength"] = v else: - self.properties.pop('center_wavelength', None) + self.properties.pop("center_wavelength", None) @property - def full_width_half_max(self): + def full_width_half_max(self) -> Optional[float]: """Get or sets the full width at half maximum (FWHM). The width of the band, as measured at half the maximum transmission, in micrometers (μm). Returns: [float] """ - return self.properties.get('full_width_half_max') + return self.properties.get("full_width_half_max") @full_width_half_max.setter - def full_width_half_max(self, v): + def full_width_half_max(self, v: Optional[float]) -> None: if v is not None: - self.properties['full_width_half_max'] = v + self.properties["full_width_half_max"] = v else: - self.properties.pop('full_width_half_max', None) + self.properties.pop("full_width_half_max", None) - def __repr__(self): - return ''.format(self.name) + def __repr__(self) -> str: + return "".format(self.name) - def to_dict(self): + def to_dict(self) -> Dict[str, Any]: """Returns the dictionary representing the JSON of this Band. Returns: @@ -294,7 +187,7 @@ def to_dict(self): return self.properties @staticmethod - def band_range(common_name): + def band_range(common_name: str) -> Optional[Tuple[float, float]]: """Gets the band range for a common band name. Args: @@ -303,30 +196,30 @@ def band_range(common_name): Returns: Tuple[float, float] or None: The band range for this name as (min, max), or None if this is not a recognized common name. - """ # noqa E501 + """ # noqa E501 name_to_range = { - 'coastal': (0.40, 0.45), - 'blue': (0.45, 0.50), - 'green': (0.50, 0.60), - 'red': (0.60, 0.70), - 'yellow': (0.58, 0.62), - 'pan': (0.50, 0.70), - 'rededge': (0.70, 0.75), - 'nir': (0.75, 1.00), - 'nir08': (0.75, 0.90), - 'nir09': (0.85, 1.05), - 'cirrus': (1.35, 1.40), - 'swir16': (1.55, 1.75), - 'swir22': (2.10, 2.30), - 'lwir': (10.5, 12.5), - 'lwir11': (10.5, 11.5), - 'lwir12': (11.5, 12.5) + "coastal": (0.40, 0.45), + "blue": (0.45, 0.50), + "green": (0.50, 0.60), + "red": (0.60, 0.70), + "yellow": (0.58, 0.62), + "pan": (0.50, 0.70), + "rededge": (0.70, 0.75), + "nir": (0.75, 1.00), + "nir08": (0.75, 0.90), + "nir09": (0.85, 1.05), + "cirrus": (1.35, 1.40), + "swir16": (1.55, 1.75), + "swir22": (2.10, 2.30), + "lwir": (10.5, 12.5), + "lwir11": (10.5, 11.5), + "lwir12": (11.5, 12.5), } return name_to_range.get(common_name) @staticmethod - def band_description(common_name): + def band_description(common_name: str) -> Optional[str]: """Returns a description of the band for one with a common name. Args: @@ -335,11 +228,265 @@ def band_description(common_name): Returns: str or None: If a recognized common name, returns a description including the band range. Otherwise returns None. - """ # noqa E501 + """ # noqa E501 r = Band.band_range(common_name) if r is not None: - r = "Common name: {}, Range: {} to {}".format(common_name, r[0], r[1]) - return r + return "Common name: {}, Range: {} to {}".format(common_name, r[0], r[1]) + return None + + +class EOExtension( + Generic[T], PropertiesExtension, ExtensionManagementMixin[pystac.Item] +): + """EOItemExt is the extension of the Item in the eo extension which + represents a snapshot of the earth for a single date and time. + + Args: + item (Item): The item to be extended. + + Attributes: + item (Item): The Item that is being extended. + + Note: + Using EOItemExt to directly wrap an item will add the 'eo' extension ID to + the item's stac_extensions. + """ + + def apply(self, bands: List[Band], cloud_cover: Optional[float] = None) -> None: + """Applies label extension properties to the extended Item. + + Args: + bands (List[Band]): a list of :class:`~pystac.Band` objects that represent + the available bands. + cloud_cover (float or None): The estimate of cloud cover as a percentage + (0-100) of the entire scene. If not available the field should not be + provided. + """ + self.bands = bands + self.cloud_cover = cloud_cover + + @property + def bands(self) -> Optional[List[Band]]: + """Get or sets a list of :class:`~pystac.Band` objects that represent + the available bands. + """ + return self._get_bands() + + def _get_bands(self) -> Optional[List[Band]]: + return map_opt( + lambda bands: [Band(b) for b in bands], + self._get_property(BANDS_PROP, List[Dict[str, Any]]), + ) + + @bands.setter + def bands(self, v: Optional[List[Band]]) -> None: + self._set_property( + BANDS_PROP, map_opt(lambda bands: [b.to_dict() for b in bands], v) + ) + + @property + def cloud_cover(self) -> Optional[float]: + """Get or sets the estimate of cloud cover as a percentage (0-100) of the + entire scene. If not available the field should not be provided. + + Returns: + float or None + """ + return self._get_property(CLOUD_COVER_PROP, float) + @cloud_cover.setter + def cloud_cover(self, v: Optional[float]) -> None: + self._set_property(CLOUD_COVER_PROP, v) + + @classmethod + def get_schema_uri(cls) -> str: + return SCHEMA_URI + + @staticmethod + def ext(obj: T) -> "EOExtension[T]": + if isinstance(obj, pystac.Item): + return cast(EOExtension[T], ItemEOExtension(obj)) + elif isinstance(obj, pystac.Asset): + return cast(EOExtension[T], AssetEOExtension(obj)) + else: + raise pystac.ExtensionTypeError( + f"EO extension does not apply to type {type(obj)}" + ) + + @staticmethod + def summaries(obj: pystac.Collection) -> "SummariesEOExtension": + return SummariesEOExtension(obj) + + +class ItemEOExtension(EOExtension[pystac.Item]): + def __init__(self, item: pystac.Item): + self.item = item + self.properties = item.properties + + def _get_bands(self) -> Optional[List[Band]]: + """Get or sets a list of :class:`~pystac.Band` objects that represent + the available bands. + """ + bands = self._get_property(BANDS_PROP, List[Dict[str, Any]]) -EO_EXTENSION_DEFINITION = ExtensionDefinition(Extensions.EO, [ExtendedObject(Item, EOItemExt)]) + # get assets with eo:bands even if not in item + if bands is None: + asset_bands: List[Dict[str, Any]] = [] + for _, value in self.item.get_assets().items(): + if BANDS_PROP in value.properties: + asset_bands.extend( + cast(List[Dict[str, Any]], value.properties.get(BANDS_PROP)) + ) + if any(asset_bands): + bands = asset_bands + + if bands is not None: + return [Band(b) for b in bands] + return None + + def __repr__(self) -> str: + return "".format(self.item.id) + + +class AssetEOExtension(EOExtension[pystac.Asset]): + def __init__(self, asset: pystac.Asset): + self.asset_href = asset.href + self.properties = asset.properties + if asset.owner and isinstance(asset.owner, pystac.Item): + self.additional_read_properties = [asset.owner.properties] + + def __repr__(self) -> str: + return "".format(self.asset_href) + + +class SummariesEOExtension(SummariesExtension): + @property + def bands(self) -> Optional[List[Band]]: + """Get or sets a list of :class:`~pystac.Band` objects that represent + the available bands. + """ + return map_opt( + lambda bands: [Band(b) for b in bands], + self.summaries.get_list(BANDS_PROP, Dict[str, Any]), + ) + + @bands.setter + def bands(self, v: Optional[List[Band]]) -> None: + self._set_summary(BANDS_PROP, map_opt(lambda x: [b.to_dict() for b in x], v)) + + @property + def cloud_cover(self) -> Optional[RangeSummary[float]]: + """Get or sets the range of cloud cover from the summary.""" + return self.summaries.get_range(CLOUD_COVER_PROP, float) + + @cloud_cover.setter + def cloud_cover(self, v: Optional[RangeSummary[float]]) -> None: + self._set_summary(CLOUD_COVER_PROP, v) + + +class EOExtensionHooks(ExtensionHooks): + schema_uri: str = SCHEMA_URI + prev_extension_ids: Set[str] = set(["eo"]) + stac_object_types: Set[pystac.STACObjectType] = set([pystac.STACObjectType.ITEM]) + + def migrate( + self, obj: Dict[str, Any], version: STACVersionID, info: STACJSONDescription + ) -> None: + if version < "0.5": + if "eo:crs" in obj["properties"]: + # Try to pull out the EPSG code. + # Otherwise, just leave it alone. + wkt = obj["properties"]["eo:crs"] + matches = list(re.finditer(r'AUTHORITY\[[^\]]*\"(\d+)"\]', wkt)) + if len(matches) > 0: + epsg_code = matches[-1].group(1) + obj["properties"].pop("eo:crs") + obj["properties"]["eo:epsg"] = int(epsg_code) + + if version < "0.6": + # Change eo:bands from a dict to a list. eo:bands on an asset + # is an index instead of a dict key. eo:bands is in properties. + bands_dict = obj["eo:bands"] + keys_to_indices: Dict[str, int] = {} + bands: List[Dict[str, Any]] = [] + for i, (k, band) in enumerate(bands_dict.items()): + keys_to_indices[k] = i + bands.append(band) + + obj.pop("eo:bands") + obj["properties"]["eo:bands"] = bands + for k, asset in obj["assets"].items(): + if "eo:bands" in asset: + asset_band_indices: List[int] = [] + for bk in asset["eo:bands"]: + asset_band_indices.append(keys_to_indices[bk]) + asset["eo:bands"] = sorted(asset_band_indices) + + if version < "0.9": + # Some eo fields became common_metadata + if ( + "eo:platform" in obj["properties"] + and "platform" not in obj["properties"] + ): + obj["properties"]["platform"] = obj["properties"]["eo:platform"] + del obj["properties"]["eo:platform"] + + if ( + "eo:instrument" in obj["properties"] + and "instruments" not in obj["properties"] + ): + obj["properties"]["instruments"] = [obj["properties"]["eo:instrument"]] + del obj["properties"]["eo:instrument"] + + if ( + "eo:constellation" in obj["properties"] + and "constellation" not in obj["properties"] + ): + obj["properties"]["constellation"] = obj["properties"][ + "eo:constellation" + ] + del obj["properties"]["eo:constellation"] + + # Some eo fields became view extension fields + eo_to_view_fields = [ + "off_nadir", + "azimuth", + "incidence_angle", + "sun_azimuth", + "sun_elevation", + ] + + for field in eo_to_view_fields: + if "eo:{}".format(field) in obj["properties"]: + if "stac_extensions" not in obj: + obj["stac_extensions"] = [] + if view.SCHEMA_URI not in obj["stac_extensions"]: + obj["stac_extensions"].append(view.SCHEMA_URI) + if not "view:{}".format(field) in obj["properties"]: + obj["properties"]["view:{}".format(field)] = obj["properties"][ + "eo:{}".format(field) + ] + del obj["properties"]["eo:{}".format(field)] + + if version < "1.0.0-beta.1" and info.object_type == pystac.STACObjectType.ITEM: + # gsd moved from eo to common metadata + if "eo:gsd" in obj["properties"]: + obj["properties"]["gsd"] = obj["properties"]["eo:gsd"] + del obj["properties"]["eo:gsd"] + + # The way bands were declared in assets changed. + # In 1.0.0-beta.1 they are inlined into assets as + # opposed to having indices back into a property-level array. + if "eo:bands" in obj["properties"]: + bands = obj["properties"]["eo:bands"] + for asset in obj["assets"].values(): + if "eo:bands" in asset: + new_bands: List[Dict[str, Any]] = [] + for band_index in asset["eo:bands"]: + new_bands.append(bands[band_index]) + asset["eo:bands"] = new_bands + + super().migrate(obj, version, info) + + +EO_EXTENSION_HOOKS: ExtensionHooks = EOExtensionHooks() diff --git a/pystac/extensions/file.py b/pystac/extensions/file.py index 636218dd4..1ce4bc2c7 100644 --- a/pystac/extensions/file.py +++ b/pystac/extensions/file.py @@ -1,16 +1,39 @@ -"""Implement the Label extension. +"""Implements the File extension. https://github.com/stac-extensions/file - """ + import enum +from typing import Any, Dict, Generic, List, Optional, Set, TypeVar, cast + +import pystac +from pystac.extensions.base import ( + ExtensionManagementMixin, + PropertiesExtension, + SummariesExtension, +) +from pystac.extensions.hooks import ExtensionHooks +from pystac.serialization.identify import ( + OldExtensionShortIDs, + STACJSONDescription, + STACVersionID, +) +from pystac.utils import map_opt + +T = TypeVar("T", pystac.Item, pystac.Asset) -from pystac import Extensions -from pystac.item import Item -from pystac.extensions.base import (ItemExtension, ExtensionDefinition, ExtendedObject) +SCHEMA_URI = "https://stac-extensions.github.io/file/v1.0.0/schema.json" +DATA_TYPE_PROP = "file:data_type" +SIZE_PROP = "file:size" +NODATA_PROP = "file:nodata" +CHECKSUM_PROP = "file:checksum" + + +class FileDataType(str, enum.Enum): + def __str__(self) -> str: + return str(self.value) -class FileDataType(enum.Enum): INT8 = "int8" INT16 = "int16" INT32 = "int32" @@ -29,7 +52,9 @@ class FileDataType(enum.Enum): OTHER = "other" -class FileItemExt(ItemExtension): +class FileExtension( + Generic[T], PropertiesExtension, ExtensionManagementMixin[pystac.Item] +): """FileItemExt is the extension of the Item in the file extension which adds file related details such as checksum, data type and size for assets. @@ -43,15 +68,14 @@ class FileItemExt(ItemExtension): Using FileItemExt to directly wrap an item will add the 'file' extension ID to the item's stac_extensions. """ - def __init__(self, item): - if item.stac_extensions is None: - item.stac_extensions = [Extensions.FILE] - elif Extensions.FILE not in item.stac_extensions: - item.stac_extensions.append(Extensions.FILE) - - self.item = item - def apply(self, data_type=None, size=None, nodata=None, checksum=None): + def apply( + self, + data_type: Optional[FileDataType] = None, + size: Optional[int] = None, + nodata: Optional[List[Any]] = None, + checksum: Optional[str] = None, + ) -> None: """Applies file extension properties to the extended Item. Args: @@ -66,167 +90,175 @@ def apply(self, data_type=None, size=None, nodata=None, checksum=None): self.nodata = nodata self.checksum = checksum - def _set_property(self, key, value, asset): - target = self.item.properties if asset is None else asset.properties - if value is None: - target.pop(key, None) - else: - target[key] = value - @property - def data_type(self): + def data_type(self) -> Optional[FileDataType]: """Get or sets the data_type of the file. Returns: FileDataType """ - return self.get_data_type() + return map_opt( + lambda s: FileDataType(s), self._get_property(DATA_TYPE_PROP, str) + ) @data_type.setter - def data_type(self, v): - self.set_data_type(v) - - def get_data_type(self, asset=None): - """Gets an Item or an Asset data_type. - - If an Asset is supplied and the data_type property exists on the Asset, - returns the Asset's value. Otherwise returns the Item's value - - Returns: - FileDataType - """ - if asset is not None and 'file:data_type' in asset.properties: - data_type = asset.properties.get('file:data_type') - else: - data_type = self.item.properties.get('file:data_type') - - if data_type is not None: - return FileDataType(data_type) - - def set_data_type(self, data_type, asset=None): - """Set an Item or an Asset data_type. - - If an Asset is supplied, sets the property on the Asset. - Otherwise sets the Item's value. - """ - self._set_property('file:data_type', data_type.value, asset) + def data_type(self, v: Optional[FileDataType]) -> None: + self._set_property(DATA_TYPE_PROP, str(v)) @property - def size(self): + def size(self) -> Optional[int]: """Get or sets the size in bytes of the file Returns: int or None """ - return self.get_size() + return self._get_property(SIZE_PROP, int) @size.setter - def size(self, v): - self.set_size(v) + def size(self, v: Optional[int]) -> None: + self._set_property(SIZE_PROP, v) + + @property + def nodata(self) -> Optional[List[Any]]: + """Get or sets the no data values""" + return self._get_property(NODATA_PROP, List[Any]) - def get_size(self, asset=None): - """Gets an Item or an Asset file size. + @nodata.setter + def nodata(self, v: Optional[List[Any]]) -> None: + self._set_property(NODATA_PROP, v) - If an Asset is supplied and the Item property exists on the Asset, - returns the Asset's value. Otherwise returns the Item's value + @property + def checksum(self) -> Optional[str]: + """Get or sets the checksum Returns: - float + str or None """ - if asset is None or 'file:size' not in asset.properties: - return self.item.properties.get('file:size') - else: - return asset.properties.get('file:size') + return self._get_property(CHECKSUM_PROP, str) - def set_size(self, size, asset=None): - """Set an Item or an Asset size. + @checksum.setter + def checksum(self, v: Optional[str]) -> None: + self._set_property(CHECKSUM_PROP, v) - If an Asset is supplied, sets the property on the Asset. - Otherwise sets the Item's value. - """ - self._set_property('file:size', size, asset) + @classmethod + def get_schema_uri(cls) -> str: + return SCHEMA_URI + + @staticmethod + def ext(obj: T) -> "FileExtension[T]": + if isinstance(obj, pystac.Item): + return cast(FileExtension[T], ItemFileExtension(obj)) + elif isinstance(obj, pystac.Asset): + return cast(FileExtension[T], AssetFileExtension(obj)) + else: + raise pystac.ExtensionTypeError( + f"File extension does not apply to type {type(obj)}" + ) - @property - def nodata(self): - """Get or sets the no data values + @staticmethod + def summaries(obj: pystac.Collection) -> "SummariesFileExtension": + return SummariesFileExtension(obj) - Returns: - int or None - """ - return self.get_nodata() - @nodata.setter - def nodata(self, v): - self.set_nodata(v) +class ItemFileExtension(FileExtension[pystac.Item]): + def __init__(self, item: pystac.Item): + self.item = item + self.properties = item.properties - def get_nodata(self, asset=None): - """Gets an Item or an Asset nodata values. + def __repr__(self) -> str: + return "".format(self.item.id) - If an Asset is supplied and the Item property exists on the Asset, - returns the Asset's value. Otherwise returns the Item's value - Returns: - list[object] - """ - if asset is None or 'file:nodata' not in asset.properties: - return self.item.properties.get('file:nodata') - else: - return asset.properties.get('file:nodata') +class AssetFileExtension(FileExtension[pystac.Asset]): + def __init__(self, asset: pystac.Asset): + self.asset_href = asset.href + self.properties = asset.properties + if asset.owner and isinstance(asset.owner, pystac.Item): + self.additional_read_properties = [asset.owner.properties] - def set_nodata(self, nodata, asset=None): - """Set an Item or an Asset nodata values. + def __repr__(self) -> str: + return "".format(self.asset_href) - If an Asset is supplied, sets the property on the Asset. - Otherwise sets the Item's value. - """ - self._set_property('file:nodata', nodata, asset) +class SummariesFileExtension(SummariesExtension): @property - def checksum(self): - """Get or sets the checksum + def data_type(self) -> Optional[List[FileDataType]]: + """Get or sets the data_type of the file. Returns: - str or None + FileDataType """ - return self.get_checksum() - - @checksum.setter - def checksum(self, v): - self.set_checksum(v) + return map_opt( + lambda x: [FileDataType(t) for t in x], + self.summaries.get_list(DATA_TYPE_PROP, str), + ) - def get_checksum(self, asset=None): - """Gets an Item or an Asset checksum. + @data_type.setter + def data_type(self, v: Optional[List[FileDataType]]) -> None: + self._set_summary(DATA_TYPE_PROP, map_opt(lambda x: [str(t) for t in x], v)) - If an Asset is supplied and the Item property exists on the Asset, - returns the Asset's value. Otherwise returns the Item's value + @property + def size(self) -> Optional[pystac.RangeSummary[int]]: + """Get or sets the size in bytes of the file Returns: - list[object] - """ - if asset is None or 'file:checksum' not in asset.properties: - return self.item.properties.get('file:checksum') - else: - return asset.properties.get('file:checksum') - - def set_checksum(self, checksum, asset=None): - """Set an Item or an Asset checksum. - - If an Asset is supplied, sets the property on the Asset. - Otherwise sets the Item's value. + int or None """ - self._set_property('file:checksum', checksum, asset) + return self.summaries.get_range(SIZE_PROP, int) - def __repr__(self): - return ''.format(self.item.id) - - @classmethod - def _object_links(cls): - return [] - - @classmethod - def from_item(cls, item): - return cls(item) + @size.setter + def size(self, v: Optional[pystac.RangeSummary[int]]) -> None: + self._set_summary(SIZE_PROP, v) + @property + def nodata(self) -> Optional[List[Any]]: + """Get or sets the list of no data values""" + return self.summaries.get_list(NODATA_PROP, List[Any]) -FILE_EXTENSION_DEFINITION = ExtensionDefinition(Extensions.FILE, - [ExtendedObject(Item, FileItemExt)]) + @nodata.setter + def nodata(self, v: Optional[List[Any]]) -> None: + self._set_summary(NODATA_PROP, v) + + +class FileExtensionHooks(ExtensionHooks): + schema_uri: str = SCHEMA_URI + prev_extension_ids: Set[str] = set(["file"]) + stac_object_types: Set[pystac.STACObjectType] = set([pystac.STACObjectType.ITEM]) + + def migrate( + self, obj: Dict[str, Any], version: STACVersionID, info: STACJSONDescription + ) -> None: + # The checksum field was previously it's own extension. + old_checksum: Optional[Dict[str, str]] = None + if info.version_range.latest_valid_version() < "v1.0.0-rc.2": + if OldExtensionShortIDs.CHECKSUM.value in info.extensions: + old_item_checksum = obj["properties"].get("checksum:multihash") + if old_item_checksum is not None: + if old_checksum is None: + old_checksum = {} + old_checksum["__item__"] = old_item_checksum + for asset_key, asset in obj["assets"].items(): + old_asset_checksum = asset.get("checksum:multihash") + if old_asset_checksum is not None: + if old_checksum is None: + old_checksum = {} + old_checksum[asset_key] = old_asset_checksum + + try: + obj["stac_extensions"].remove(OldExtensionShortIDs.CHECKSUM.value) + except ValueError: + pass + + super().migrate(obj, version, info) + + if old_checksum is not None: + if SCHEMA_URI not in obj["stac_extensions"]: + obj["stac_extensions"].append(SCHEMA_URI) + for key in old_checksum: + if key == "__item__": + obj["properties"][CHECKSUM_PROP] = old_checksum[key] + else: + obj["assets"][key][CHECKSUM_PROP] = old_checksum[key] + + +FILE_EXTENSION_HOOKS = FileExtensionHooks() diff --git a/pystac/extensions/hooks.py b/pystac/extensions/hooks.py new file mode 100644 index 000000000..33a7583d6 --- /dev/null +++ b/pystac/extensions/hooks.py @@ -0,0 +1,98 @@ +from abc import ABC, abstractmethod +from functools import lru_cache +from typing import Any, Dict, Iterable, List, Optional, Set, TYPE_CHECKING + +import pystac +from pystac.serialization.identify import STACJSONDescription, STACVersionID + +if TYPE_CHECKING: + from pystac.stac_object import STACObject as STACObject_Type + + +class ExtensionHooks(ABC): + @property + @abstractmethod + def schema_uri(self) -> str: + """The schema_uri for the current version of this extension""" + pass + + @property + @abstractmethod + def prev_extension_ids(self) -> List[str]: + """A list of previous extension IDs (schema URIs or old short ids) + that should be migrated to the latest schema URI in the 'stac_extensions' + property. Override with a class attribute so that the list of previous + IDs is only created once. + """ + pass + + @property + @abstractmethod + def stac_object_types(self) -> Set[pystac.STACObjectType]: + """A set of STACObjectType for which migration logic will be applied.""" + pass + + @lru_cache() + def _get_stac_object_types(self) -> Set[str]: + """Translation of stac_object_types to strings, cached""" + return set([x.value for x in self.stac_object_types]) + + def get_object_links(self, obj: "STACObject_Type") -> Optional[List[str]]: + return None + + def migrate( + self, obj: Dict[str, Any], version: STACVersionID, info: STACJSONDescription + ) -> None: + """Migrate a STAC Object in dict format from a previous version. + The base implementation will update the stac_extensions to the latest + schema ID. This method will only be called for STAC objects that have been + identified as a previous version of STAC. Implementations should directly + manipulate the obj dict. Remember to call super() in order to change out + the old 'stac_extension' entry with the latest schema URI. + """ + # Migrate schema versions + for prev_id in self.prev_extension_ids: + if prev_id in info.extensions: + try: + i = obj["stac_extensions"].index(prev_id) + obj["stac_extensions"][i] = self.schema_uri + except ValueError: + obj["stac_extensions"].append(self.schema_uri) + break + + +class RegisteredExtensionHooks: + def __init__(self, hooks: Iterable[ExtensionHooks]): + self.hooks = dict([(e.schema_uri, e) for e in hooks]) + + def add_extension_hooks(self, hooks: ExtensionHooks) -> None: + e_id = hooks.schema_uri + if e_id in self.hooks: + raise pystac.ExtensionAlreadyExistsError( + "ExtensionDefinition with id '{}' already exists.".format(e_id) + ) + + self.hooks[e_id] = hooks + + def remove_extension_hooks(self, extension_id: str) -> None: + if extension_id in self.hooks: + del self.hooks[extension_id] + + def get_extended_object_links(self, obj: "STACObject_Type") -> List[str]: + result: Optional[List[str]] = None + for ext in obj.stac_extensions: + if ext in self.hooks: + ext_result = self.hooks[ext].get_object_links(obj) + if ext_result is not None: + if result is None: + result = ext_result + else: + result.extend(ext_result) + return result or [] + + def migrate( + self, obj: Dict[str, Any], version: STACVersionID, info: STACJSONDescription + ) -> None: + for hooks in self.hooks.values(): + if info.object_type in hooks._get_stac_object_types(): + hooks.migrate(obj, version, info) diff --git a/pystac/extensions/item_assets.py b/pystac/extensions/item_assets.py new file mode 100644 index 000000000..a5f2b44be --- /dev/null +++ b/pystac/extensions/item_assets.py @@ -0,0 +1,144 @@ +"""Implements the Item Assets Definition extension. + +https://github.com/stac-extensions/item-assets +""" + +from typing import Any, Dict, List, Optional, Set + +import pystac +from pystac.extensions.base import ExtensionManagementMixin +from pystac.extensions.hooks import ExtensionHooks +from pystac.serialization.identify import STACJSONDescription, STACVersionID +from pystac.utils import get_required + +SCHEMA_URI = "https://stac-extensions.github.io/item-assets/v1.0.0/schema.json" + +ITEM_ASSETS_PROP = "item_assets" + +ASSET_TITLE_PROP = "title" +ASSET_DESC_PROP = "description" +ASSET_TYPE_PROP = "type" +ASSET_ROLES_PROP = "roles" + + +class AssetDefinition: + def __init__(self, properties: Dict[str, Any]) -> None: + self.properties = properties + + @property + def title(self) -> Optional[str]: + self.properties.get(ASSET_TITLE_PROP) + + @title.setter + def title(self, v: Optional[str]) -> None: + if v is None: + self.properties.pop(ASSET_TITLE_PROP, None) + else: + self.properties[ASSET_TITLE_PROP] = v + + @property + def description(self) -> Optional[str]: + self.properties.get(ASSET_DESC_PROP) + + @description.setter + def description(self, v: Optional[str]) -> None: + if v is None: + self.properties.pop(ASSET_DESC_PROP, None) + else: + self.properties[ASSET_DESC_PROP] = v + + @property + def media_type(self) -> Optional[str]: + self.properties.get(ASSET_TYPE_PROP) + + @media_type.setter + def media_type(self, v: Optional[str]) -> None: + if v is None: + self.properties.pop(ASSET_TYPE_PROP, None) + else: + self.properties[ASSET_TYPE_PROP] = v + + @property + def roles(self) -> Optional[List[str]]: + self.properties.get(ASSET_ROLES_PROP) + + @roles.setter + def roles(self, v: Optional[List[str]]) -> None: + if v is None: + self.properties.pop(ASSET_ROLES_PROP, None) + else: + self.properties[ASSET_ROLES_PROP] = v + + def create_asset(self, href: str) -> pystac.Asset: + return pystac.Asset( + href=href, + title=self.title, + description=self.description, + media_type=self.media_type, + roles=self.roles, + properties={ + k: v + for k, v in self.properties + if k + not in set( + [ + ASSET_TITLE_PROP, + ASSET_DESC_PROP, + ASSET_TYPE_PROP, + ASSET_ROLES_PROP, + ] + ) + }, + ) + + +class ItemAssetsExtension(ExtensionManagementMixin[pystac.Collection]): + def __init__(self, collection: pystac.Collection) -> None: + self.collection = collection + + @property + def item_assets(self) -> Dict[str, AssetDefinition]: + result = get_required( + self.collection.extra_fields.get(ITEM_ASSETS_PROP), self, ITEM_ASSETS_PROP + ) + return {k: AssetDefinition(v) for k, v in result.items()} + + @item_assets.setter + def item_assets(self, v: Dict[str, AssetDefinition]) -> None: + self.collection.extra_fields[ITEM_ASSETS_PROP] = { + k: asset_def.properties for k, asset_def in v.items() + } + + def __repr__(self) -> str: + return f"" + + @classmethod + def get_schema_uri(cls) -> str: + return SCHEMA_URI + + @classmethod + def ext(cls, collection: pystac.Collection) -> "ItemAssetsExtension": + return cls(collection) + + +class ItemAssetsExtensionHooks(ExtensionHooks): + schema_uri: str = SCHEMA_URI + prev_extension_ids: Set[str] = set(["asset", "item-assets"]) + stac_object_types: Set[pystac.STACObjectType] = set( + [pystac.STACObjectType.COLLECTION] + ) + + def migrate( + self, obj: Dict[str, Any], version: STACVersionID, info: STACJSONDescription + ) -> None: + # Handle that the "item-assets" extension had the id of "assets", before + # collection assets (since removed) took over the ID of "assets" + if version < "1.0.0-beta.1" and "asset" in info.extensions: + if "assets" in obj: + obj["item_assets"] = obj["assets"] + del obj["assets"] + + super().migrate(obj, version, info) + + +ITEM_ASSETS_EXTENSION_HOOKS = ItemAssetsExtensionHooks() diff --git a/pystac/extensions/label.py b/pystac/extensions/label.py index 56d7a8ac6..a8d9ae9b8 100644 --- a/pystac/extensions/label.py +++ b/pystac/extensions/label.py @@ -1,387 +1,283 @@ -"""STAC Model classes for Label extension. +"""Implements the Label extension. https://github.com/stac-extensions/label """ + from enum import Enum +from pystac.extensions.base import ExtensionManagementMixin +from typing import Any, Dict, Iterable, List, Optional, Set, Union, cast + +import pystac +from pystac.serialization.identify import STACJSONDescription, STACVersionID +from pystac.extensions.hooks import ExtensionHooks -from pystac import STACError -from pystac.extensions import Extensions -from pystac.extensions.base import (ItemExtension, ExtensionDefinition, ExtendedObject) -from pystac.item import (Item, Asset) -from pystac.link import Link +SCHEMA_URI = "https://stac-extensions.github.io/label/v1.0.0/schema.json" class LabelType(str, Enum): """Enumerates valid label types (RASTER or VECTOR).""" - def __str__(self): + + def __str__(self) -> str: return str(self.value) - VECTOR = 'vector' - RASTER = 'raster' + VECTOR = "vector" + RASTER = "raster" ALL = [VECTOR, RASTER] """Convenience attribute for checking if values are valid label types""" -class LabelItemExt(ItemExtension): - """A LabelItemExt is the extension of the Item in the label extension which - represents a polygon, set of polygons, or raster data defining - labels and label metadata and should be part of a Collection. - - Args: - item (Item): The item to be extended. +class LabelClasses: + """Defines the list of possible class names (e.g., tree, building, car, hippo) - Attributes: - item (Item): The Item that is being extended. + Use LabelClasses.create to create a new instance of LabelClasses from + property values. + """ - See: - `Item fields in the label extension spec `_ + def __init__(self, properties: Dict[str, Any]): + self.properties = properties - Note: - Using LabelItemExt to directly wrap an item will add the 'label' extension ID to - the item's stac_extensions. - """ # noqa E501 - - def __init__(self, item): - if item.stac_extensions is None: - item.stac_extensions = [Extensions.LABEL] - elif Extensions.LABEL not in item.stac_extensions: - item.stac_extensions.append(Extensions.LABEL) - - self.item = item - - def apply(self, - label_description, - label_type, - label_properties=None, - label_classes=None, - label_tasks=None, - label_methods=None, - label_overviews=None): - """Applies label extension properties to the extended Item. + def apply( + self, + classes: Union[List[str], List[int], List[float]], + name: Optional[str] = None, + ) -> None: + """Sets the properties for this LabelClasses. Args: - label_description (str): A description of the label, how it was created, - and what it is recommended for - label_type (str): An ENUM of either vector label type or raster label type. Use - one of :class:`~pystac.LabelType`. - label_properties (list or None): These are the names of the property field(s) in each - Feature of the label asset's FeatureCollection that contains the classes - (keywords from label:classes if the property defines classes). - If labels are rasters, this should be None. - label_classes (List[LabelClass]): Optional, but reqiured if ussing categorical data. - A list of LabelClasses defining the list of possible class names for each - label:properties. (e.g., tree, building, car, hippo) - label_tasks (List[str]): Recommended to be a subset of 'regression', 'classification', - 'detection', or 'segmentation', but may be an arbitrary value. - label_methods: Recommended to be a subset of 'automated' or 'manual', - but may be an arbitrary value. - label_overviews (List[LabelOverview]): Optional list of LabelOverview classes - that store counts (for classification-type data) or summary statistics (for - continuous numerical/regression data). - """ # noqa E501 - self.label_description = label_description - self.label_type = label_type - self.label_properties = label_properties - self.label_classes = label_classes - self.label_tasks = label_tasks - self.label_methods = label_methods - self.label_overviews = label_overviews - - @property - def label_description(self): - """Get or sets a description of the label, how it was created, - and what it is recommended for. - - Returns: - str + classes (List[str] or List[int] or List[float]): The different possible + class values. + name (str): The property key within the asset's each Feature corresponding + to class labels. If labels are raster-formatted, do not supply; + required otherwise. """ - return self.item.properties.get('label:description') + self.classes = classes + self.name = name - @label_description.setter - def label_description(self, v): - self.item.properties['label:description'] = v + @classmethod + def create( + cls, + classes: Union[List[str], List[int], List[float]], + name: Optional[str] = None, + ) -> "LabelClasses": + """Creates a new LabelClasses. - @property - def label_type(self): - """Gets or sets an ENUM of either vector label type or raster label type (one - of :class:`~pystac.LabelType`). + Args: + classes (List[str] or List[int] or List[float]): The different possible + class values. + name (str): The property key within the asset's each Feature corresponding + to class labels. If labels are raster-formatted, do not supply; + required otherwise. Returns: - str + LabelClasses """ - return self.item.properties.get('label:type') - - @label_type.setter - def label_type(self, v): - if v not in LabelType.ALL: - raise STACError("label_type must be one of " - "{}. Invalid input: {}".format(LabelType.ALL, v)) - - self.item.properties['label:type'] = v + c = cls({}) + c.apply(classes, name) + return c @property - def label_properties(self): - """Label Properties - - Gets or sets the names of the property field(s) in each - Feature of the label asset's FeatureCollection that contains the classes - (keywords from label:classes if the property defines classes). - If labels are rasters, this should be None. + def classes(self) -> Union[List[str], List[int], List[float]]: + """Get or sets the class values. Returns: - List[str] or None + List[str] or List[int] or List[float] """ - return self.item.properties.get('label:properties') + result = self.properties.get("classes") + if result is None: + raise pystac.STACError( + f"LabelClasses does not contain classes property: {self.properties}" + ) + return result - @label_properties.setter - def label_properties(self, v): - if v is not None: - if not type(v) is list: - raise STACError("label_properties must be a list! Invalid input: {}".format(v)) + @classes.setter + def classes(self, v: Union[List[str], List[int], List[float]]) -> None: + if not type(v) is list: + raise pystac.STACError( + "classes must be a list! Invalid input: {}".format(v) + ) - self.item.properties['label:properties'] = v + self.properties["classes"] = v @property - def label_classes(self): - """Get or set a list of LabelClasses defining the list of possible class names for each - label:properties. (e.g., tree, building, car, hippo). - - Optional, but reqiured if using categorical data. - - Returns: - List[LabelClasses] or None + def name(self) -> Optional[str]: + """Get or sets the property key within the asset's each Feature corresponding to + class labels. If labels are raster-formatted, do not supply; required otherwise. """ - label_classes = self.item.properties.get('label:classes') - if label_classes is not None: - return [LabelClasses(classes) for classes in label_classes] - else: - return None + return self.properties.get("name") - @label_classes.setter - def label_classes(self, v): - if v is None: - self.item.properties.pop('label:classes', None) + @name.setter + def name(self, v: Optional[str]) -> None: + if v is not None: + self.properties["name"] = v else: - if not type(v) is list: - raise STACError("label_classes must be a list! Invalid input: {}".format(v)) + self.properties.pop("name", None) - classes = [x.to_dict() for x in v] - self.item.properties['label:classes'] = classes + def __repr__(self) -> str: + return "".format( + ",".join([str(x) for x in self.classes]) + ) - @property - def label_tasks(self): - """Get or set a list of tasks these labels apply to. Usually a subset of 'regression', - 'classification', 'detection', or 'segmentation', but may be arbitrary values. + def to_dict(self) -> Dict[str, Any]: + """Returns the dictionary representing the JSON of this LabelClasses. Returns: - List[str] or None + dict: The wrapped dict of the LabelClasses that can be written out as JSON. """ - return self.item.properties.get('label:tasks') - - @label_tasks.setter - def label_tasks(self, v): - if v is None: - self.item.properties.pop('label:tasks', None) - else: - if not type(v) is list: - raise STACError("label_tasks must be a list! Invalid input: {}".format(v)) - - self.item.properties['label:tasks'] = v + return self.properties - @property - def label_methods(self): - """Get or set a list of methods used for labeling. Usually a subset of 'automated' or 'manual', - but may be arbitrary values. - Returns: - List[str] or None - """ - return self.item.properties.get('label:methods') +class LabelCount: + """Contains counts for categorical data. - @label_methods.setter - def label_methods(self, v): - if v is None: - self.item.properties.pop('label:methods', None) - else: - if not type(v) is list: - raise STACError("label_methods must be a list! Invalid input: {}".format(v)) + Use LabelCount.create to create a new LabelCount + """ - self.item.properties['label:methods'] = v + def __init__(self, properties: Dict[str, Any]): + self.properties = properties - @property - def label_overviews(self): - """Get or set a list of LabelOverview classes - that store counts (for classification-type data) or summary statistics (for - continuous numerical/regression data). + def apply(self, name: str, count: int) -> None: + """Sets the properties for this LabelCount. - Returns: - List[LabelOverview] or None + Args: + name (str): One of the different possible classes within the property. + count (int): The number of occurrences of the class. """ - overviews = self.item.properties.get('label:overviews') - if overviews is not None: - return [LabelOverview(overview) for overview in overviews] - else: - return None - - @label_overviews.setter - def label_overviews(self, v): - if v is None: - self.item.properties.pop('label:overviews', None) - else: - if not type(v) is list: - raise STACError("label_overviews must be a list! Invalid input: {}".format(v)) - - overviews = [x.to_dict() for x in v] - self.item.properties['label:overviews'] = overviews - - def __repr__(self): - return ''.format(self.item.id) + self.name = name + self.count = count - def add_source(self, source_item, title=None, assets=None): - """Adds a link to a source item. + @classmethod + def create(cls, name: str, count: int) -> "LabelCount": + """Creates a LabelCount. Args: - source_item (Item): Source imagery that the LabelItem applies to. - title (str): Optional title for the link. - assets (List[str]): Optional list of assets that determine what - assets in the source item this label item data applies to. + name (str): One of the different possible classes within the property. + count (int): The number of occurrences of the class. """ - properties = None - if assets is not None: - properties = {'label:assets': assets} - link = Link('source', - source_item, - title=title, - media_type='application/json', - properties=properties) - self.item.add_link(link) - - def get_sources(self): - """Gets any source items that describe the source imagery used to generate - this LabelItem. + x = cls({}) + x.apply(name, count) + return x + + @property + def name(self) -> str: + """Get or sets the class that this count represents. Returns: - Generator[Items]: A possibly empty list of source imagery items. Determined by - links of this LabelItem that have ``rel=='source'``. + str """ - return self.item.get_stac_objects('source') + result = self.properties.get("name") + if result is None: + raise pystac.STACError( + f"Label count has no name property: {self.properties}" + ) + return result - def add_labels(self, href, title=None, media_type=None, properties=None): - """Adds a label asset to this LabelItem. + @name.setter + def name(self, v: str) -> None: + self.properties["name"] = v - Args: - href (str): Link to the asset object. Relative and absolute links are both allowed. - title (str): Optional displayed title for clients and users. - media_type (str): Optional description of the media type. Registered Media Types - are preferred. See :class:`~pystac.MediaType` for common media types. - properties (dict): Optional, additional properties for this asset. This is used by - extensions as a way to serialize and deserialize properties on asset - object JSON. + @property + def count(self) -> int: + """Get or sets the number of occurrences of the class. + + Returns: + int """ + result = self.properties.get("count") + if result is None: + raise pystac.STACError( + f"Label count has no count property: {self.properties}" + ) + return result - self.item.add_asset( - "labels", Asset(href=href, title=title, media_type=media_type, properties=properties)) + @count.setter + def count(self, v: int) -> None: + self.properties["count"] = v - def add_geojson_labels(self, href, title=None, properties=None): - """Adds a GeoJSON label asset to this LabelItem. + def to_dict(self) -> Dict[str, Any]: + """Returns the dictionary representing the JSON of this LabelCount. - Args: - href (str): Link to the asset object. Relative and absolute links are both allowed. - title (str): Optional displayed title for clients and users. - properties (dict): Optional, additional properties for this asset. This is used by - extensions as a way to serialize and deserialize properties on asset - object JSON. + Returns: + dict: The wrapped dict of the LabelCount that can be written out as JSON. """ - self.add_labels(href, title=title, properties=properties, media_type='application/geo+json') - - @classmethod - def _object_links(cls): - return ['source'] - - @classmethod - def from_item(cls, item): - return cls(item) + return {"name": self.name, "count": self.count} -class LabelClasses: - """Defines the list of possible class names (e.g., tree, building, car, hippo) +class LabelStatistics: + """Contains statistics for regression/continuous numeric value data. - Use LabelClasses.create to create a new instance of LabelClasses from property values. + Use LabelStatistics.create to create a new instance. """ - def __init__(self, properties): + + def __init__(self, properties: Dict[str, Any]) -> None: self.properties = properties - def apply(self, classes, name=None): - """Sets the properties for this LabelClasses. + def apply(self, name: str, value: float) -> None: + """Sets the property values for this instance. Args: - classes (List[str] or List[int] or List[float]): The different possible class values. - name (str): The property key within the asset's each Feature corresponding to - class labels. If labels are raster-formatted, do not supply; required otherwise. + name (str): The name of the statistic being reported. + value (float): The value of the statistic """ - self.classes = classes self.name = name + self.value = value @classmethod - def create(cls, classes, name=None): - """Creates a new LabelClasses. + def create(cls, name: str, value: float) -> "LabelStatistics": + """Sets the property values for this instance. Args: - classes (List[str] or List[int] or List[float]): The different possible class values. - name (str): The property key within the asset's each Feature corresponding to - class labels. If labels are raster-formatted, do not supply; required otherwise. - - Returns: - LabelClasses + name (str): The name of the statistic being reported. + value (float): The value of the statistic """ - c = cls({}) - c.apply(classes, name) - return c + x = cls({}) + x.apply(name, value) + return x @property - def classes(self): - """Get or sets the class values. + def name(self) -> str: + """Get or sets the name of the statistic being reported. Returns: - List[str] or List[int] or List[float] + str """ - return self.properties.get('classes') + result = self.properties.get("name") + if result is None: + raise pystac.STACError( + f"Label statistics has no name property: {self.properties}" + ) + return result - @classes.setter - def classes(self, v): - if not type(v) is list: - raise STACError("classes must be a list! Invalid input: {}".format(v)) - - self.properties['classes'] = v + @name.setter + def name(self, v: str) -> None: + self.properties["name"] = v @property - def name(self): - """Get or sets the property key within the asset's each Feature corresponding to - class labels. If labels are raster-formatted, do not supply; required otherwise. + def value(self) -> float: + """Get or sets the value of the statistic Returns: - str + float """ - return self.properties.get('name') + result = self.properties.get("value") + if result is None: + raise pystac.STACError( + f"Label statistics has no value property: {self.properties}" + ) + return result - @name.setter - def name(self, v): - if v is not None: - self.properties['name'] = v - else: - self.properties.pop('name', None) - - def __repr__(self): - return ''.format(','.join(self.classes)) + @value.setter + def value(self, v: float) -> None: + self.properties["value"] = v - def to_dict(self): - """Returns the dictionary representing the JSON of this LabelClasses. + def to_dict(self) -> Dict[str, Any]: + """Returns the dictionary representing the JSON of this LabelStatistics. Returns: - dict: The wrapped dict of the LabelClasses that can be written out as JSON. + dict: The wrapped dict of the LabelStatistics that can be written out as + JSON. """ - return self.properties + return {"name": self.name, "value": self.value} class LabelOverview: @@ -390,20 +286,28 @@ class LabelOverview: Use LabelOverview.create to create a new LabelOverview. """ - def __init__(self, properties): + + def __init__(self, properties: Dict[str, Any]): self.properties = properties - def apply(self, property_key, counts=None, statistics=None): + def apply( + self, + property_key: Optional[str], + counts: Optional[List[LabelCount]] = None, + statistics: Optional[List[LabelStatistics]] = None, + ) -> None: """Sets the properties for this LabelOverview. Either ``counts`` or ``statistics``, or both, can be placed in an overview; at least one is required. Args: - property_key (str): The property key within the asset corresponding to class labels. - counts (List[LabelCounts]): Optional list of LabelCounts containing counts + property_key (str): The property key within the asset corresponding to + class labels that these counts or statistics are referencing. If the + label data is raster data, this should be None. + counts: Optional list of LabelCounts containing counts for categorical data. - statistics (List[Statistics]): Optional list of Statistics containing statistics for + statistics: Optional list of statistics containing statistics for regression/continuous numeric value data. """ self.property_key = property_key @@ -411,17 +315,23 @@ def apply(self, property_key, counts=None, statistics=None): self.statistics = statistics @classmethod - def create(cls, property_key, counts=None, statistics=None): + def create( + cls, + property_key: Optional[str], + counts: Optional[List[LabelCount]] = None, + statistics: Optional[List[LabelStatistics]] = None, + ) -> "LabelOverview": """Creates a new LabelOverview. Either ``counts`` or ``statistics``, or both, can be placed in an overview; at least one is required. Args: - property_key (str): The property key within the asset corresponding to class labels. - counts (List[LabelCounts]): Optional list of LabelCounts containing counts for + property_key (str): The property key within the asset corresponding to + class labels. + counts: Optional list of LabelCounts containing counts for categorical data. - statistics (List[Statistics]): Optional list of Statistics containing statistics for + statistics: Optional list of Statistics containing statistics for regression/continuous numeric value data. """ x = LabelOverview({}) @@ -429,65 +339,69 @@ def create(cls, property_key, counts=None, statistics=None): return x @property - def property_key(self): + def property_key(self) -> Optional[str]: """Get or sets the property key within the asset corresponding to class labels. Returns: str """ - return self.properties.get('property_key') + return self.properties.get("property_key") @property_key.setter - def property_key(self, v): - self.properties['property_key'] = v + def property_key(self, v: Optional[str]) -> None: + self.properties["property_key"] = v @property - def counts(self): + def counts(self) -> Optional[List[LabelCount]]: """Get or sets the list of LabelCounts containing counts for categorical data. Returns: List[LabelCount] """ - counts = self.properties.get('counts') - if counts is not None: - counts = [LabelCount(c) for c in counts] - return counts + counts = self.properties.get("counts") + if counts is None: + return None + return [LabelCount(c) for c in counts] @counts.setter - def counts(self, v): + def counts(self, v: Optional[List[LabelCount]]) -> None: if v is None: - self.properties.pop('counts', None) + self.properties.pop("counts", None) else: - if not type(v) is list: - raise STACError("counts must be a list! Invalid input: {}".format(v)) + if not isinstance(v, list): + raise pystac.STACError( + "counts must be a list! Invalid input: {}".format(v) + ) - self.properties['counts'] = [c.to_dict() for c in v] + self.properties["counts"] = [c.to_dict() for c in v] @property - def statistics(self): + def statistics(self) -> Optional[List[LabelStatistics]]: """Get or sets the list of Statistics containing statistics for regression/continuous numeric value data. Returns: List[Statistics] """ - statistics = self.properties.get('statistics') - if statistics is not None: - statistics = [LabelStatistics(s) for s in statistics] + statistics = self.properties.get("statistics") + if statistics is None: + return None - return statistics + return [LabelStatistics(s) for s in statistics] @statistics.setter - def statistics(self, v): + def statistics(self, v: Optional[List[LabelStatistics]]) -> None: if v is None: - self.properties.pop('statistics', None) + self.properties.pop("statistics", None) else: - if not type(v) is list: - raise STACError("statistics must be a list! Invalid input: {}".format(v)) + if not isinstance(v, list): + raise pystac.STACError( + "statistics must be a list! Invalid input: {}".format(v) + ) - self.properties['statistics'] = [s.to_dict() for s in v] + self.properties["statistics"] = [s.to_dict() for s in v] - def merge_counts(self, other): + def merge_counts(self, other: "LabelOverview") -> "LabelOverview": """Merges the counts associated with this overview with another overview. Creates a new LabelOverview. @@ -498,7 +412,7 @@ def merge_counts(self, other): LabelOverview: A new LabelOverview with the counts merged. This will drop any statistics associated with either of the LabelOverviews. """ - assert (self.property_key == other.property_key) + assert self.property_key == other.property_key new_counts = None if self.counts is None: @@ -507,9 +421,9 @@ def merge_counts(self, other): if other.counts is None: new_counts = self.counts else: - count_by_prop = {} + count_by_prop: Dict[str, int] = {} - def add_counts(counts): + def add_counts(counts: List[LabelCount]) -> None: for c in counts: if c.name not in count_by_prop: count_by_prop[c.name] = c.count @@ -518,10 +432,10 @@ def add_counts(counts): add_counts(self.counts) add_counts(other.counts) - new_counts = [LabelCount(k, v) for k, v in count_by_prop.items()] + new_counts = [LabelCount.create(k, v) for k, v in count_by_prop.items()] return LabelOverview.create(self.property_key, counts=new_counts) - def to_dict(self): + def to_dict(self) -> Dict[str, Any]: """Returns the dictionary representing the JSON of this LabelOverview. Returns: @@ -530,135 +444,364 @@ def to_dict(self): return self.properties -class LabelCount: - """Contains counts for categorical data. +class LabelExtension(ExtensionManagementMixin[pystac.Item]): + """A LabelItemExt is the extension of the Item in the label extension which + represents a polygon, set of polygons, or raster data defining + labels and label metadata and should be part of a Collection. - Use LabelCount.create to create a new LabelCount - """ - def __init__(self, properties): - self.properties = properties + Args: + item (Item): The item to be extended. - def apply(self, name, count): - """Sets the properties for this LabelCount. + Attributes: + item (Item): The Item that is being extended. - Args: - name (str): One of the different possible classes within the property. - count (int): The number of occurrences of the class. - """ - self.name = name - self.count = count + See: + `Item fields in the label extension spec `_ - @classmethod - def create(cls, name, count): - """Creates a LabelCount. + Note: + Using LabelItemExt to directly wrap an item will add the 'label' extension ID to + the item's stac_extensions. + """ # noqa E501 + + def __init__(self, item: pystac.Item) -> None: + self.obj = item + self.schema_uri = SCHEMA_URI + + def apply( + self, + label_description: str, + label_type: LabelType, + label_properties: Optional[List[str]] = None, + label_classes: Optional[List[LabelClasses]] = None, + label_tasks: Optional[List[str]] = None, + label_methods: Optional[List[str]] = None, + label_overviews: Optional[List[LabelOverview]] = None, + ) -> None: + """Applies label extension properties to the extended Item. Args: - name (str): One of the different possible classes within the property. - count (int): The number of occurrences of the class. - """ - x = cls({}) - x.apply(name, count) - return x + label_description (str): A description of the label, how it was created, + and what it is recommended for + label_type (str): An ENUM of either vector label type or raster label type. Use + one of :class:`~pystac.LabelType`. + label_properties (list or None): These are the names of the property field(s) in each + Feature of the label asset's FeatureCollection that contains the classes + (keywords from label:classes if the property defines classes). + If labels are rasters, this should be None. + label_classes (List[LabelClass]): Optional, but required if using categorical data. + A list of LabelClasses defining the list of possible class names for each + label:properties. (e.g., tree, building, car, hippo) + label_tasks (List[str]): Recommended to be a subset of 'regression', 'classification', + 'detection', or 'segmentation', but may be an arbitrary value. + label_methods: Recommended to be a subset of 'automated' or 'manual', + but may be an arbitrary value. + label_overviews (List[LabelOverview]): Optional list of LabelOverview classes + that store counts (for classification-type data) or summary statistics (for + continuous numerical/regression data). + """ # noqa E501 + self.label_description = label_description + self.label_type = label_type + self.label_properties = label_properties + self.label_classes = label_classes + self.label_tasks = label_tasks + self.label_methods = label_methods + self.label_overviews = label_overviews @property - def name(self): - """Get or sets the class that this count represents. + def label_description(self) -> str: + """Get or sets a description of the label, how it was created, + and what it is recommended for. Returns: str """ - return self.properties.get('name') + result = self.obj.properties.get("label:description") + if result is None: + raise pystac.STACError(f"label:description not set for item {self.obj.id}") + return result - @name.setter - def name(self, v): - self.properties['name'] = v + @label_description.setter + def label_description(self, v: str) -> None: + self.obj.properties["label:description"] = v @property - def count(self): - """Get or sets the number of occurrences of the class. + def label_type(self) -> LabelType: + """Gets or sets an ENUM of either vector label type or raster label type.""" + result = self.obj.properties.get("label:type") + if result is None: + raise pystac.STACError(f"label:type is not set for item {self.obj.id}") + return LabelType(result) - Returns: - int - """ - return self.properties.get('count') + @label_type.setter + def label_type(self, v: LabelType) -> None: + if v not in LabelType.ALL: + raise pystac.STACError( + "label_type must be one of " + "{}. Invalid input: {}".format(LabelType.ALL, v) + ) - @count.setter - def count(self, v): - self.properties['count'] = v + self.obj.properties["label:type"] = v - def to_dict(self): - """Returns the dictionary representing the JSON of this LabelCount. + @property + def label_properties(self) -> Optional[List[str]]: + """Label Properties + + Gets or sets the names of the property field(s) in each + Feature of the label asset's FeatureCollection that contains the classes + (keywords from label:classes if the property defines classes). + If labels are rasters, this should be None. Returns: - dict: The wrapped dict of the LabelCount that can be written out as JSON. + List[str] or None """ - return {'name': self.name, 'count': self.count} + return self.obj.properties.get("label:properties") + @label_properties.setter + def label_properties(self, v: Optional[List[str]]) -> None: + if v is not None: + if not isinstance(v, list): + raise pystac.STACError( + "label_properties must be a list! Invalid input: {}".format(v) + ) -class LabelStatistics: - """Contains statistics for regression/continuous numeric value data. + self.obj.properties["label:properties"] = v - Use LabelStatistics.create to create a new instance. - """ - def __init__(self, properties): - self.properties = properties + @property + def label_classes(self) -> Optional[List[LabelClasses]]: + """Get or set a list of LabelClasses defining the list of possible class names for each + label:properties. (e.g., tree, building, car, hippo). - def apply(self, name, value): - """Sets the property values for this instance. + Optional, but required if using categorical data. - Args: - name (str): The name of the statistic being reported. - value (float): The value of the statistic + Returns: + List[LabelClasses] or None """ - self.name = name - self.value = value + label_classes = self.obj.properties.get("label:classes") + if label_classes is not None: + return [LabelClasses(classes) for classes in label_classes] + else: + return None - @classmethod - def create(cls, name, value): - """Sets the property values for this instance. + @label_classes.setter + def label_classes(self, v: Optional[List[LabelClasses]]) -> None: + if v is None: + self.obj.properties.pop("label:classes", None) + else: + if not isinstance(v, list): + raise pystac.STACError( + "label_classes must be a list! Invalid input: {}".format(v) + ) - Args: - name (str): The name of the statistic being reported. - value (float): The value of the statistic + classes = [x.to_dict() for x in v] + self.obj.properties["label:classes"] = classes + + @property + def label_tasks(self) -> Optional[List[str]]: + """Get or set a list of tasks these labels apply to. Usually a subset of 'regression', + 'classification', 'detection', or 'segmentation', but may be arbitrary + values. + + Returns: + List[str] or None """ - x = cls({}) - x.apply(name, value) - return x + return self.obj.properties.get("label:tasks") + + @label_tasks.setter + def label_tasks(self, v: Optional[List[str]]) -> None: + if v is None: + self.obj.properties.pop("label:tasks", None) + else: + if not isinstance(v, list): + raise pystac.STACError( + "label_tasks must be a list! Invalid input: {}".format(v) + ) + + self.obj.properties["label:tasks"] = v @property - def name(self): - """Get or sets the name of the statistic being reported. + def label_methods(self) -> Optional[List[str]]: + """Get or set a list of methods used for labeling. + + Usually a subset of 'automated' or 'manual', but may be arbitrary values. Returns: - str + List[str] or None """ - return self.properties.get('name') + return self.obj.properties.get("label:methods") - @name.setter - def name(self, v): - self.properties['name'] = v + @label_methods.setter + def label_methods(self, v: Optional[List[str]]) -> None: + if v is None: + self.obj.properties.pop("label:methods", None) + else: + if not isinstance(v, list): + raise pystac.STACError( + "label_methods must be a list! Invalid input: {}".format(v) + ) + + self.obj.properties["label:methods"] = v @property - def value(self): - """Get or sets the value of the statistic + def label_overviews(self) -> Optional[List[LabelOverview]]: + """Get or set a list of LabelOverview classes + that store counts (for classification-type data) or summary statistics (for + continuous numerical/regression data). Returns: - int or float + List[LabelOverview] or None """ - return self.properties.get('value') + overviews = self.obj.properties.get("label:overviews") + if overviews is not None: + return [LabelOverview(overview) for overview in overviews] + else: + return None - @value.setter - def value(self, v): - self.properties['value'] = v + @label_overviews.setter + def label_overviews(self, v: Optional[List[LabelOverview]]) -> None: + if v is None: + self.obj.properties.pop("label:overviews", None) + else: + if not isinstance(v, list): + raise pystac.STACError( + "label_overviews must be a list! Invalid input: {}".format(v) + ) - def to_dict(self): - """Returns the dictionary representing the JSON of this LabelStatistics. + overviews = [x.to_dict() for x in v] + self.obj.properties["label:overviews"] = overviews + + def __repr__(self) -> str: + return "".format(self.obj.id) + + def add_source( + self, + source_item: pystac.Item, + title: Optional[str] = None, + assets: Optional[List[str]] = None, + ) -> None: + """Adds a link to a source item. + + Args: + source_item (Item): Source imagery that the LabelItem applies to. + title (str): Optional title for the link. + assets (List[str]): Optional list of assets that determine what + assets in the source item this label item data applies to. + """ + properties = None + if assets is not None: + properties = {"label:assets": assets} + link = pystac.Link( + "source", + source_item, + title=title, + media_type="application/json", + properties=properties, + ) + self.obj.add_link(link) + + def get_sources(self) -> Iterable[pystac.Item]: + """Gets any source items that describe the source imagery used to generate + this LabelItem. Returns: - dict: The wrapped dict of the LabelStatistics that can be written out as JSON. + Generator[Items]: A possibly empty list of source imagery items. Determined + by links of this LabelItem that have ``rel=='source'``. + """ + return map(lambda x: cast(pystac.Item, x), self.obj.get_stac_objects("source")) + + def add_labels( + self, + href: str, + title: Optional[str] = None, + media_type: Optional[str] = None, + properties: Optional[Dict[str, Any]] = None, + ) -> None: + """Adds a label asset to this LabelItem. + + Args: + href (str): Link to the asset object. Relative and absolute links are both + allowed. + title (str): Optional displayed title for clients and users. + media_type (str): Optional description of the media type. Registered Media + Types are preferred. See :class:`~pystac.MediaType` for common + media types. + properties (dict): Optional, additional properties for this asset. This is + used by extensions as a way to serialize and deserialize properties on + asset object JSON. + """ + + self.obj.add_asset( + "labels", + pystac.Asset( + href=href, title=title, media_type=media_type, properties=properties + ), + ) + + def add_geojson_labels( + self, + href: str, + title: Optional[str] = None, + properties: Optional[Dict[str, Any]] = None, + ) -> None: + """Adds a GeoJSON label asset to this LabelItem. + + Args: + href (str): Link to the asset object. Relative and absolute links are both + allowed. + title (str): Optional displayed title for clients and users. + properties (dict): Optional, additional properties for this asset. This is + used by extensions as a way to serialize and deserialize properties on + asset object JSON. """ - return {'name': self.name, 'value': self.value} + self.add_labels( + href, + title=title, + properties=properties, + media_type=pystac.MediaType.GEOJSON, + ) + + @classmethod + def get_schema_uri(cls) -> str: + return SCHEMA_URI + + @classmethod + def ext(cls, obj: pystac.Item) -> "LabelExtension": + return cls(obj) + + +class LabelExtensionHooks(ExtensionHooks): + schema_uri: str = SCHEMA_URI + prev_extension_ids: Set[str] = set(["label"]) + stac_object_types: Set[pystac.STACObjectType] = set([pystac.STACObjectType.ITEM]) + + def get_object_links(self, so: pystac.STACObject) -> Optional[List[str]]: + if isinstance(so, pystac.Item): + return ["source"] + return None + + def migrate( + self, obj: Dict[str, Any], version: STACVersionID, info: STACJSONDescription + ) -> None: + if info.object_type == pystac.STACObjectType.ITEM and version < "1.0.0": + props = obj["properties"] + # Migrate 0.8.0-rc1 non-pluralized forms + # As it's a common mistake, convert for any pre-1.0.0 version. + if "label:property" in props and "label:properties" not in props: + props["label:properties"] = props["label:property"] + del props["label:property"] + + if "label:task" in props and "label:tasks" not in props: + props["label:tasks"] = props["label:task"] + del props["label:task"] + + if "label:overview" in props and "label:overviews" not in props: + props["label:overviews"] = props["label:overview"] + del props["label:overview"] + + if "label:method" in props and "label:methods" not in props: + props["label:methods"] = props["label:method"] + del props["label:method"] + + super().migrate(obj, version, info) -LABEL_EXTENSION_DEFINITION = ExtensionDefinition(Extensions.LABEL, - [ExtendedObject(Item, LabelItemExt)]) +LABEL_EXTENSION_HOOKS: ExtensionHooks = LabelExtensionHooks() diff --git a/pystac/extensions/pointcloud.py b/pystac/extensions/pointcloud.py index c8ce3e1ba..466c7ee98 100644 --- a/pystac/extensions/pointcloud.py +++ b/pystac/extensions/pointcloud.py @@ -1,389 +1,138 @@ -"""Implement the Point Cloud extension. +"""Implements the Point Cloud extension. https://github.com/stac-extensions/pointcloud """ -from pystac import Extensions, STACError -from pystac.item import Item -from pystac.extensions.base import (ItemExtension, ExtensionDefinition, ExtendedObject) +from typing import Any, Dict, Generic, List, Optional, Set, TypeVar, cast -class PointcloudItemExt(ItemExtension): - """PointcloudItemExt is the extension of an Item in the PointCloud Extension. - The Pointclout extension adds pointcloud information to STAC Items. - - Args: - item (Item): The item to be extended. - - Attributes: - item (Item): The Item that is being extended. - - """ - def __init__(self, item): - if item.stac_extensions is None: - item.stac_extensions = [Extensions.POINTCLOUD] - elif Extensions.POINTCLOUD not in item.stac_extensions: - item.stac_extensions.append(Extensions.POINTCLOUD) +import pystac +from pystac.extensions.base import ( + ExtensionManagementMixin, + PropertiesExtension, +) +from pystac.extensions.hooks import ExtensionHooks +from pystac.utils import map_opt - self.item = item +T = TypeVar("T", pystac.Item, pystac.Asset) - def apply(self, count, type, encoding, schemas, density=None, statistics=None, epsg=None): - """Applies Pointcloud extension properties to the extended Item. +SCHEMA_URI = "https://stac-extensions.github.io/pointcloud/v1.0.0/schema.json" - Args: - count (int): REQUIRED. The number of points in the cloud. - type (str): REQUIRED. Phenomenology type for the point cloud. Possible valid - values might include lidar, eopc, radar, sonar, or otherThe type of file - or data format of the cloud. - encoding (str): REQUIRED. Content encoding or format of the data. - schemas (List[dict]): REQUIRED. A sequential array of items that define the - dimensions and their types. - density (dict or None): Number of points per square unit area. - statistics (List[int] or None): A sequential array of items mapping to pc:schemas - defines per-channel statistics. - epsg (str): An EPSG code for the projected coordinates of the pointcloud. - """ - self.count = count - self.type = type - self.encoding = encoding - self.schemas = schemas - self.density = density - self.statistics = statistics - self.epsg = epsg - - @property - def count(self): - """Get or sets the count property of the datasource. - - Returns: - int - """ - return self.get_count() - - @count.setter - def count(self, v): - self.set_count(v) - - def get_count(self, asset=None): - """Gets an Item or an Asset count. - - If an Asset is supplied and the Item property exists on the Asset, - returns the Asset's value. Otherwise returns the Item's value - - Returns: - int - """ - if asset is None or 'pc:count' not in asset.properties: - return self.item.properties.get('pc:count') - else: - return asset.properties.get('pc:count') - - def set_count(self, count, asset=None): - """Set an Item or an Asset count. - - If an Asset is supplied, sets the property on the Asset. - Otherwise sets the Item's value. - """ - self._set_property('pc:count', count, asset) - - @property - def type(self): - """Get or sets the pc:type prop on the Item - - Returns: - str - """ - return self.get_type() - - @type.setter - def type(self, v): - self.set_type(v) - - def get_type(self, asset=None): - """Gets an Item or an Asset type. - - If an Asset is supplied and the Item property exists on the Asset, - returns the Asset's value. Otherwise returns the Item's value - - Returns: - str - """ - if asset is None or 'pc:type' not in asset.properties: - return self.item.properties.get('pc:type') - else: - return asset.properties.get('pc:type') - - def set_type(self, type, asset=None): - """Set an Item or an Asset type. - - If an Asset is supplied, sets the property on the Asset. - Otherwise sets the Item's value. - """ - self._set_property('pc:type', type, asset) - - @property - def encoding(self): - """Get or sets the content-encoding for the item. - - The content-encoding is the underlying encoding format for the point cloud. - Examples may include: laszip, ascii, binary, etc. - - Returns: - str - """ - return self.get_encoding() - - @encoding.setter - def encoding(self, v): - self.set_encoding(v) - - def get_encoding(self, asset=None): - """Gets an Item or an Asset encoding. - - If an Asset is supplied and the Item property exists on the Asset, - returns the Asset's value. Otherwise returns the Item's value - - Returns: - str - """ - if asset is None or 'pc:encoding' not in asset.properties: - return self.item.properties.get('pc:encoding') - else: - return asset.properties.get('pc:encoding') - - def set_encoding(self, encoding, asset=None): - """Set an Item or an Asset encoding. - - If an Asset is supplied, sets the property on the Asset. - Otherwise sets the Item's value. - """ - self._set_property('pc:encoding', encoding, asset) - - @property - def schemas(self): - """Get or sets a - - The schemas represent the structure of the data attributes in the pointcloud, - and is represented as a sequential array of items that define the dimensions - and their types, - - Returns: - List[PointcloudSchema] - """ - return self.get_schemas() - - @schemas.setter - def schemas(self, v): - self.set_schemas(v) - - def get_schemas(self, asset=None): - """Gets an Item or an Asset projection geometry. - - If an Asset is supplied and the Item property exists on the Asset, - returns the Asset's value. Otherwise returns the Item's value - - Returns: - List[PointcloudSchema] - """ - if asset is None or 'pc:schemas' not in asset.properties: - schemas = self.item.properties.get('pc:schemas') - return [PointcloudSchema(s) for s in schemas] - else: - return [PointcloudSchema.create(s) for s in asset.properties.get('pc:schemas')] - - def set_schemas(self, schemas, asset=None): - """Set an Item or an Asset schema - - If an Asset is supplied, sets the property on the Asset. - Otherwise sets the Item's value. - """ - dicts = [s.to_dict() for s in schemas] - self._set_property('pc:schemas', dicts, asset) - - @property - def density(self): - """Get or sets the density for the item. - - Density is defined as the number of points per square unit area. - - Returns: - int - """ - return self.get_density() - - @density.setter - def density(self, v): - self.set_density(v) - - def get_density(self, asset=None): - """Gets an Item or an Asset density. - - If an Asset is supplied and the Item property exists on the Asset, - returns the Asset's value. Otherwise returns the Item's value - - Returns: - int - """ - if asset is None or 'pc:density' not in asset.properties: - return self.item.properties.get('pc:density') - else: - return asset.properties.get('pc:density') - - def set_density(self, density, asset=None): - """Set an Item or an Asset density property. - - If an Asset is supplied, sets the property on the Asset. - Otherwise sets the Item's value. - """ - self._set_property('pc:density', density, asset) - - @property - def statistics(self): - """Get or sets the statistics for each property of the dataset. - - A sequential array of items mapping to pc:schemas defines per-channel statistics. - - Example:: - - item.ext.pointcloud.statistics = [{ 'name': 'red', 'min': 0, 'max': 255 }] - - Returns: - List[dict] - """ - return self.get_statistics() - - @statistics.setter - def statistics(self, v): - self.set_statistics(v) - - def get_statistics(self, asset=None): - """Gets an Item or an Asset centroid. - - If an Asset is supplied and the Item property exists on the Asset, - returns the Asset's value. Otherwise returns the Item's value - - Returns: - List[PointCloudStatistics] or None - """ - if asset is None or 'pc:statistics' not in asset.properties: - stats = self.item.properties.get('pc:statistics') - if stats: - return [PointcloudStatistic(s) for s in stats] - else: - return None - else: - return [PointcloudStatistic.create(s) for s in asset.properties.get('pc:statistics')] - - def set_statistics(self, statistics, asset=None): - """Set an Item or an Asset centroid. - - If an Asset is supplied, sets the property on the Asset. - Otherwise sets the Item's value. - """ - if statistics is not None: - statistics = [s.to_dict() for s in statistics] - self._set_property('pc:statistics', statistics, asset) - - @classmethod - def _object_links(cls): - return [] - - @classmethod - def from_item(cls, item): - return cls(item) +COUNT_PROP = "pc:count" +TYPE_PROP = "pc:type" +ENCODING_PROP = "pc:encoding" +SCHEMAS_PROP = "pc:schemas" +DENSITY_PROP = "pc:density" +STATISTICS_PROP = "pc:statistics" class PointcloudSchema: """Defines a schema for dimension of a pointcloud (e.g., name, size, type) - Use PointCloudSchema.create to create a new instance of PointCloudSchema from properties. + Use PointCloudSchema.create to create a new instance of PointCloudSchema from + properties. """ - def __init__(self, properties): + + def __init__(self, properties: Dict[str, Any]) -> None: self.properties = properties - def apply(self, name, size, type): + def apply(self, name: str, size: int, type: str) -> None: """Sets the properties for this PointCloudSchema. Args: name (str): The name of dimension. size (int): The size of the dimension in bytes. Whole bytes are supported. - type (str): Dimension type. Valid values are `floating`, `unsigned`, and `signed` + type (str): Dimension type. Valid values are `floating`, `unsigned`, and + `signed` """ - self.properties['name'] = name - self.properties['size'] = size - self.properties['type'] = type + self.properties["name"] = name + self.properties["size"] = size + self.properties["type"] = type @classmethod - def create(cls, *args): + def create(cls, name: str, size: int, type: str) -> "PointcloudSchema": """Creates a new PointCloudSchema. Args: name (str): The name of dimension. size (int): The size of the dimension in bytes. Whole bytes are supported. - type (str): Dimension type. Valid values are `floating`, `unsigned`, and `signed` + type (str): Dimension type. Valid values are `floating`, `unsigned`, and + `signed` Returns: PointCloudSchema """ c = cls({}) - c.apply(*args) + c.apply(name=name, size=size, type=type) return c @property - def size(self): + def size(self) -> int: """Get or sets the size value. Returns: int """ - return self.properties.get('size') + result = self.properties.get("size") + if result is None: + raise pystac.STACError( + f"Pointcloud schema does not have size property: {self.properties}" + ) + return result @size.setter - def size(self, v): - if not type(v) is int: - raise STACError("size must be an int! Invalid input: {}".format(v)) + def size(self, v: int) -> None: + if not isinstance(v, int): + raise pystac.STACError("size must be an int! Invalid input: {}".format(v)) - self.properties['size'] = v + self.properties["size"] = v @property - def name(self): + def name(self) -> str: """Get or sets the name property for this PointCloudSchema. Returns: str """ - return self.properties.get('name') + result = self.properties.get("name") + if result is None: + raise pystac.STACError( + f"Pointcloud schema does not have name property: {self.properties}" + ) + return result @name.setter - def name(self, v): - if v is not None: - self.properties['name'] = v - else: - self.properties.pop('name', None) + def name(self, v: str) -> None: + self.properties["name"] = v @property - def type(self): + def type(self) -> str: """Get or sets the type property. Valid values are `floating`, `unsigned`, and `signed` Returns: str """ - return self.properties.get('type') + result = self.properties.get("type") + if result is None: + raise pystac.STACError( + f"Pointcloud schema has no type property: {self.properties}" + ) + return result @type.setter - def type(self, v): - if v is not None: - self.properties['type'] = v - else: - self.properties.pop('type', None) + def type(self, v: str) -> None: + self.properties["type"] = v - def __repr__(self): - return ''.format(self.name, self.size, self.type) + def __repr__(self) -> str: + return "".format( + self.name, self.size, self.type + ) - def to_dict(self): + def to_dict(self) -> Dict[str, Any]: """Returns the dictionary representing the JSON of this PointCloudSchema. Returns: - dict: The wrapped dict of the PointCloudSchema that can be written out as JSON. + dict: The wrapped dict of the PointCloudSchema that can be written out as + JSON. """ return self.properties @@ -391,60 +140,66 @@ def to_dict(self): class PointcloudStatistic: """Defines a single statistic for Pointcloud channel or dimension - Use PointcloudStatistic.create to create a new instance of LabelClasses from property values. + Use PointcloudStatistic.create to create a new instance of LabelClasses from + property values. """ - def __init__(self, properties): + + def __init__(self, properties: Dict[str, Any]) -> None: self.properties = properties - def apply(self, - name, - position=None, - average=None, - count=None, - maximum=None, - minimum=None, - stddev=None, - variance=None): + def apply( + self, + name: str, + position: Optional[int] = None, + average: Optional[float] = None, + count: Optional[int] = None, + maximum: Optional[float] = None, + minimum: Optional[float] = None, + stddev: Optional[float] = None, + variance: Optional[float] = None, + ) -> None: """Sets the properties for this PointcloudStatistic. Args: name (str): REQUIRED. The name of the channel. position (int): Position of the channel in the schema. - average (float) The average of the channel. + average (float): The average of the channel. count (int): The number of elements in the channel. - maximum (float): The maximum value of the channel. - minimum (float): The minimum value of the channel. + maximum (float): The maximum value of the channel. + minimum (float): The minimum value of the channel. stddev (float): The standard deviation of the channel. variance (float): The variance of the channel. """ - self.properties['name'] = name - self.properties['position'] = position - self.properties['average'] = average - self.properties['count'] = count - self.properties['maximum'] = maximum - self.properties['minimum'] = minimum - self.properties['stddev'] = stddev - self.properties['variance'] = variance + self.properties["name"] = name + self.properties["position"] = position + self.properties["average"] = average + self.properties["count"] = count + self.properties["maximum"] = maximum + self.properties["minimum"] = minimum + self.properties["stddev"] = stddev + self.properties["variance"] = variance @classmethod - def create(cls, - name, - position=None, - average=None, - count=None, - maximum=None, - minimum=None, - stddev=None, - variance=None): + def create( + cls, + name: str, + position: Optional[int] = None, + average: Optional[float] = None, + count: Optional[int] = None, + maximum: Optional[float] = None, + minimum: Optional[float] = None, + stddev: Optional[float] = None, + variance: Optional[float] = None, + ) -> "PointcloudStatistic": """Creates a new PointcloudStatistic class. Args: name (str): REQUIRED. The name of the channel. position (int): Position of the channel in the schema. - average (float) The average of the channel. + average (float) The average of the channel. count (int): The number of elements in the channel. - maximum (float): The maximum value of the channel. - minimum (float): The minimum value of the channel. + maximum (float): The maximum value of the channel. + minimum (float): The minimum value of the channel. stddev (float): The standard deviation of the channel. variance (float): The variance of the channel. @@ -452,148 +207,360 @@ def create(cls, LabelClasses """ c = cls({}) - c.apply(name, ) + c.apply( + name=name, + position=position, + average=average, + count=count, + maximum=maximum, + minimum=minimum, + stddev=stddev, + variance=variance, + ) return c @property - def name(self): + def name(self) -> str: """Get or sets the name property Returns: str """ - return self.properties.get('name') + result = self.properties.get("name") + if result is None: + raise pystac.STACError( + f"Pointcloud statistics does not have name property: {self.properties}" + ) + return result @name.setter - def name(self, v): + def name(self, v: str) -> None: if v is not None: - self.properties['name'] = v + self.properties["name"] = v else: - self.properties.pop('name', None) + self.properties.pop("name", None) @property - def position(self): + def position(self) -> Optional[int]: """Get or sets the position property Returns: int """ - return self.properties.get('position') + return self.properties.get("position") @position.setter - def position(self, v): + def position(self, v: Optional[int]) -> None: if v is not None: - self.properties['position'] = v + self.properties["position"] = v else: - self.properties.pop('position', None) + self.properties.pop("position", None) @property - def average(self): + def average(self) -> Optional[float]: """Get or sets the average property Returns: float """ - return self.properties.get('average') + return self.properties.get("average") @average.setter - def average(self, v): + def average(self, v: Optional[float]) -> None: if v is not None: - self.properties['average'] = v + self.properties["average"] = v else: - self.properties.pop('average', None) + self.properties.pop("average", None) @property - def count(self): + def count(self) -> Optional[int]: """Get or sets the count property Returns: int """ - return self.properties.get('count') + return self.properties.get("count") @count.setter - def count(self, v): + def count(self, v: Optional[int]) -> None: if v is not None: - self.properties['count'] = v + self.properties["count"] = v else: - self.properties.pop('count', None) + self.properties.pop("count", None) @property - def maximum(self): + def maximum(self) -> Optional[float]: """Get or sets the maximum property Returns: float """ - return self.properties.get('maximum') + return self.properties.get("maximum") @maximum.setter - def maximum(self, v): + def maximum(self, v: Optional[float]) -> None: if v is not None: - self.properties['maximum'] = v + self.properties["maximum"] = v else: - self.properties.pop('maximum', None) + self.properties.pop("maximum", None) @property - def minimum(self): + def minimum(self) -> Optional[float]: """Get or sets the minimum property Returns: float """ - return self.properties.get('minimum') + return self.properties.get("minimum") @minimum.setter - def minimum(self, v): + def minimum(self, v: Optional[float]) -> None: if v is not None: - self.properties['minimum'] = v + self.properties["minimum"] = v else: - self.properties.pop('minimum', None) + self.properties.pop("minimum", None) @property - def stddev(self): + def stddev(self) -> Optional[float]: """Get or sets the stddev property Returns: float """ - return self.properties.get('stddev') + return self.properties.get("stddev") @stddev.setter - def stddev(self, v): + def stddev(self, v: Optional[float]) -> None: if v is not None: - self.properties['stddev'] = v + self.properties["stddev"] = v else: - self.properties.pop('stddev', None) + self.properties.pop("stddev", None) @property - def variance(self): + def variance(self) -> Optional[float]: """Get or sets the variance property Returns: float """ - return self.properties.get('variance') + return self.properties.get("variance") @variance.setter - def variance(self, v): + def variance(self, v: Optional[float]) -> None: if v is not None: - self.properties['variance'] = v + self.properties["variance"] = v else: - self.properties.pop('variance', None) + self.properties.pop("variance", None) - def __repr__(self): - return ''.format(str(self.properties)) + def __repr__(self) -> str: + return "".format(str(self.properties)) - def to_dict(self): + def to_dict(self) -> Dict[str, Any]: """Returns the dictionary representing the JSON of this PointcloudStatistic. Returns: - dict: The wrapped dict of the PointcloudStatistic that can be written out as JSON. + dict: The wrapped dict of the PointcloudStatistic that can be written out + as JSON. """ return self.properties -POINTCLOUD_EXTENSION_DEFINITION = ExtensionDefinition(Extensions.POINTCLOUD, - [ExtendedObject(Item, PointcloudItemExt)]) +class PointcloudExtension( + Generic[T], PropertiesExtension, ExtensionManagementMixin[pystac.Item] +): + """PointcloudItemExt is the extension of an Item in the PointCloud Extension. + The Pointclout extension adds pointcloud information to STAC Items. + + Args: + item (Item): The item to be extended. + + Attributes: + item (Item): The Item that is being extended. + + """ + + def apply( + self, + count: int, + type: str, + encoding: str, + schemas: List[PointcloudSchema], + density: Optional[float] = None, + statistics: Optional[List[PointcloudStatistic]] = None, + epsg: Optional[int] = None, + ) -> None: # TODO: Remove epsg per spec + """Applies Pointcloud extension properties to the extended Item. + + Args: + count (int): REQUIRED. The number of points in the cloud. + type (str): REQUIRED. Phenomenology type for the point cloud. Possible valid + values might include lidar, eopc, radar, sonar, or otherThe type of file + or data format of the cloud. + encoding (str): REQUIRED. Content encoding or format of the data. + schemas (List[PointcloudSchema]): REQUIRED. A sequential array of items + that define the + dimensions and their types. + density (float or None): Number of points per square unit area. + statistics (List[int] or None): A sequential array of items mapping to + pc:schemas defines per-channel statistics. + epsg (str): An EPSG code for the projected coordinates of the pointcloud. + """ + self.count = count + self.type = type + self.encoding = encoding + self.schemas = schemas + self.density = density + self.statistics = statistics + self.epsg = epsg + + @property + def count(self) -> int: + """Get or sets the count property of the datasource. + + Returns: + int + """ + result = self._get_property(COUNT_PROP, int) + if result is None: + raise pystac.RequiredPropertyMissing(self, COUNT_PROP) + return result + + @count.setter + def count(self, v: int) -> None: + self._set_property(COUNT_PROP, v, pop_if_none=False) + + @property + def type(self) -> str: + """Get or sets the pc:type prop on the Item + + Returns: + str + """ + result = self._get_property(TYPE_PROP, str) + if result is None: + raise pystac.RequiredPropertyMissing(self, TYPE_PROP) + return result + + @type.setter + def type(self, v: str) -> None: + self._set_property(TYPE_PROP, v, pop_if_none=False) + + @property + def encoding(self) -> str: + """Get or sets the content-encoding for the item. + + The content-encoding is the underlying encoding format for the point cloud. + Examples may include: laszip, ascii, binary, etc. + + Returns: + str + """ + result = self._get_property(ENCODING_PROP, str) + if result is None: + raise pystac.RequiredPropertyMissing(self, ENCODING_PROP) + return result + + @encoding.setter + def encoding(self, v: str) -> None: + self._set_property(ENCODING_PROP, v, pop_if_none=False) + + @property + def schemas(self) -> List[PointcloudSchema]: + """Get or sets a + + The schemas represent the structure of the data attributes in the pointcloud, + and is represented as a sequential array of items that define the dimensions + and their types, + + Returns: + List[PointcloudSchema] + """ + result = self._get_property(SCHEMAS_PROP, List[Dict[str, Any]]) + if result is None: + raise pystac.RequiredPropertyMissing(self, SCHEMAS_PROP) + return [PointcloudSchema(s) for s in result] + + @schemas.setter + def schemas(self, v: List[PointcloudSchema]) -> None: + self._set_property(SCHEMAS_PROP, [x.to_dict() for x in v], pop_if_none=False) + + @property + def density(self) -> Optional[float]: + """Get or sets the density for the item. + + Density is defined as the number of points per square unit area. + + Returns: + int + """ + return self._get_property(DENSITY_PROP, float) + + @density.setter + def density(self, v: Optional[float]) -> None: + self._set_property(DENSITY_PROP, v) + + @property + def statistics(self) -> Optional[List[PointcloudStatistic]]: + """Get or sets the statistics for each property of the dataset. + + A sequential array of items mapping to pc:schemas defines per-channel + statistics. + + Example:: + + item.ext.pointcloud.statistics = [{ 'name': 'red', 'min': 0, 'max': 255 }] + """ + result = self._get_property(STATISTICS_PROP, List[Dict[str, Any]]) + return map_opt(lambda stats: [PointcloudStatistic(s) for s in stats], result) + + @statistics.setter + def statistics(self, v: Optional[List[PointcloudStatistic]]) -> None: + set_value = map_opt(lambda stats: [s.to_dict() for s in stats], v) + self._set_property(STATISTICS_PROP, set_value) + + @classmethod + def get_schema_uri(cls) -> str: + return SCHEMA_URI + + @staticmethod + def ext(obj: T) -> "PointcloudExtension[T]": + if isinstance(obj, pystac.Item): + return cast(PointcloudExtension[T], ItemPointcloudExtension(obj)) + elif isinstance(obj, pystac.Asset): + return cast(PointcloudExtension[T], AssetPointcloudExtension(obj)) + else: + raise pystac.ExtensionTypeError( + f"File extension does not apply to type {type(obj)}" + ) + + +class ItemPointcloudExtension(PointcloudExtension[pystac.Item]): + def __init__(self, item: pystac.Item): + self.item = item + self.properties = item.properties + + def __repr__(self) -> str: + return "".format(self.item.id) + + +class AssetPointcloudExtension(PointcloudExtension[pystac.Asset]): + def __init__(self, asset: pystac.Asset): + self.asset_href = asset.href + self.properties = asset.properties + if asset.owner and isinstance(asset.owner, pystac.Item): + self.additional_read_properties = [asset.owner.properties] + self.repr_id = f"href={asset.href} item.id={asset.owner.id}" + else: + self.repr_id = f"href={asset.href}" + + def __repr__(self) -> str: + return f"" + + +class PointcloudExtensionHooks(ExtensionHooks): + schema_uri: str = SCHEMA_URI + prev_extension_ids: Set[str] = set(["pointcloud"]) + stac_object_types: Set[pystac.STACObjectType] = set([pystac.STACObjectType.ITEM]) + + +POINTCLOUD_EXTENSION_HOOKS = PointcloudExtensionHooks() diff --git a/pystac/extensions/projection.py b/pystac/extensions/projection.py index a0c7e285e..a90df7c2d 100644 --- a/pystac/extensions/projection.py +++ b/pystac/extensions/projection.py @@ -1,13 +1,34 @@ -"""Implement the projection extension. +"""Implements the Projection extension. https://github.com/stac-extensions/projection """ -from pystac import Extensions -from pystac.item import Item -from pystac.extensions.base import (ItemExtension, ExtensionDefinition, ExtendedObject) +from typing import Any, Dict, Generic, List, Optional, Set, TypeVar, cast -class ProjectionItemExt(ItemExtension): +import pystac +from pystac.extensions.hooks import ExtensionHooks +from pystac.extensions.base import ( + ExtensionManagementMixin, + PropertiesExtension, +) + +T = TypeVar("T", pystac.Item, pystac.Asset) + +SCHEMA_URI = "https://stac-extensions.github.io/projection/v1.0.0/schema.json" + +EPSG_PROP = "proj:epsg" +WKT2_PROP = "proj:wkt2" +PROJJSON_PROP = "proj:projjson" +GEOM_PROP = "proj:geometry" +BBOX_PROP = "proj:bbox" +CENTROID_PROP = "proj:centroid" +SHAPE_PROP = "proj:shape" +TRANSFORM_PROP = "proj:transform" + + +class ProjectionExtension( + Generic[T], PropertiesExtension, ExtensionManagementMixin[pystac.Item] +): """ProjectionItemExt is the extension of an Item in the Projection Extension. The Projection extension adds projection information to STAC Items. @@ -18,45 +39,45 @@ class ProjectionItemExt(ItemExtension): item (Item): The Item that is being extended. Note: - Using ProjectionItemExt to directly wrap an item will add the 'proj' extension ID to - the item's stac_extensions. + Using ProjectionItemExt to directly wrap an item will add the 'proj' extension + ID to the item's stac_extensions. """ - def __init__(self, item): - if item.stac_extensions is None: - item.stac_extensions = [Extensions.PROJECTION] - elif Extensions.PROJECTION not in item.stac_extensions: - item.stac_extensions.append(Extensions.PROJECTION) + def __init__(self, item: pystac.Item) -> None: self.item = item - def apply(self, - epsg, - wkt2=None, - projjson=None, - geometry=None, - bbox=None, - centroid=None, - shape=None, - transform=None): + def apply( + self, + epsg: Optional[int], + wkt2: Optional[str] = None, + projjson: Optional[Dict[str, Any]] = None, + geometry: Optional[Dict[str, Any]] = None, + bbox: Optional[List[float]] = None, + centroid: Optional[Dict[str, float]] = None, + shape: Optional[List[int]] = None, + transform: Optional[List[float]] = None, + ) -> None: """Applies Projection extension properties to the extended Item. Args: epsg (int or None): REQUIRED. EPSG code of the datasource. - wkt2 (str or None): WKT2 string representing the Coordinate Reference System (CRS) that - the ``geometry`` and ``bbox`` fields represent + wkt2 (str or None): WKT2 string representing the Coordinate Reference + System (CRS) that the ``geometry`` and ``bbox`` fields represent projjson (dict or None): PROJJSON dict representing the Coordinate Reference System (CRS) that the ``geometry`` and ``bbox`` fields represent - geometry (dict or None): GeoJSON Polygon dict that defines the footprint of this Item. + geometry (dict or None): GeoJSON Polygon dict that defines the footprint of + this Item. bbox (List[float] or None): Bounding box of the Item in the asset CRS in 2 or 3 dimensions. centroid (dict or None): A dict with members 'lat' and 'lon' that defines coordinates representing the centroid of the item in the asset data CRS. - Coordinates are defined in latitude and longitude, even if the data coordinate - system may not use lat/long. - shape (List[int] or None): Number of pixels in Y and X directions for the default grid. - transform (List[float] or None): The affine transformation coefficients for the - default grid + Coordinates are defined in latitude and longitude, even if the data + coordinate system may not use lat/long. + shape (List[int] or None): Number of pixels in Y and X directions for the + default grid. + transform (List[float] or None): The affine transformation coefficients for + the default grid """ self.epsg = epsg self.wkt2 = wkt2 @@ -68,97 +89,56 @@ def apply(self, self.transform = transform @property - def epsg(self): + def epsg(self) -> Optional[int]: """Get or sets the EPSG code of the datasource. - A Coordinate Reference System (CRS) is the data reference system (sometimes called a - 'projection') used by the asset data, and can usually be referenced using an - `EPSG code `_. - If the asset data does not have a CRS, such as in the case of non-rectified imagery with - Ground Control Points, epsg should be set to None. - It should also be set to null if a CRS exists, but for which there is no valid EPSG code. + A Coordinate Reference System (CRS) is the data reference system (sometimes + called a 'projection') used by the asset data, and can usually be referenced + using an `EPSG code `_. + If the asset data does not have a CRS, such as in the case of non-rectified + imagery with Ground Control Points, epsg should be set to None. + It should also be set to null if a CRS exists, but for which there is no valid + EPSG code. Returns: int """ - return self.get_epsg() + return self._get_property(EPSG_PROP, int) @epsg.setter - def epsg(self, v): - self.set_epsg(v) - - def get_epsg(self, asset=None): - """Gets an Item or an Asset epsg. - - If an Asset is supplied and the Item property exists on the Asset, - returns the Asset's value. Otherwise returns the Item's value - - Returns: - int - """ - if asset is None or 'proj:epsg' not in asset.properties: - return self.item.properties.get('proj:epsg') - else: - return asset.properties.get('proj:epsg') - - def set_epsg(self, epsg, asset=None): - """Set an Item or an Asset epsg. - - If an Asset is supplied, sets the property on the Asset. - Otherwise sets the Item's value. - """ - self._set_property('proj:epsg', epsg, asset) + def epsg(self, v: Optional[int]) -> None: + self._set_property(EPSG_PROP, v, pop_if_none=False) @property - def wkt2(self): + def wkt2(self) -> Optional[str]: """Get or sets the WKT2 string representing the Coordinate Reference System (CRS) that the proj:geometry and proj:bbox fields represent - This value is a `WKT2 string `_. - If the data does not have a CRS, such as in the case of non-rectified imagery with Ground - Control Points, wkt2 should be set to null. It should also be set to null if a CRS exists, - but for which a WKT2 string does not exist. + This value is a + `WKT2 string `_. + If the data does not have a CRS, such as in the case of non-rectified imagery + with Ground Control Points, wkt2 should be set to null. It should also be set + to null if a CRS exists, but for which a WKT2 string does not exist. Returns: str """ - return self.get_wkt2() + return self._get_property(WKT2_PROP, str) @wkt2.setter - def wkt2(self, v): - self.set_wkt2(v) - - def get_wkt2(self, asset=None): - """Gets an Item or an Asset wkt2. - - If an Asset is supplied and the Item property exists on the Asset, - returns the Asset's value. Otherwise returns the Item's value - - Returns: - str - """ - if asset is None or 'proj:wkt2' not in asset.properties: - return self.item.properties.get('proj:wkt2') - else: - return asset.properties.get('proj:wkt2') - - def set_wkt2(self, wkt2, asset=None): - """Set an Item or an Asset wkt2. - - If an Asset is supplied, sets the property on the Asset. - Otherwise sets the Item's value. - """ - self._set_property('proj:wkt2', wkt2, asset) + def wkt2(self, v: Optional[str]) -> None: + self._set_property(WKT2_PROP, v) @property - def projjson(self): + def projjson(self) -> Optional[Dict[str, Any]]: """Get or sets the PROJJSON string representing the Coordinate Reference System (CRS) that the proj:geometry and proj:bbox fields represent - This value is a `PROJJSON object `_. - If the data does not have a CRS, such as in the case of non-rectified imagery with Ground - Control Points, projjson should be set to null. It should also be set to null if a - CRS exists, but for which a PROJJSON string does not exist. + This value is a + `PROJJSON object `_. + If the data does not have a CRS, such as in the case of non-rectified imagery + with Ground Control Points, projjson should be set to null. It should also be + set to null if a CRS exists, but for which a PROJJSON string does not exist. The schema for this object can be found `here `_. @@ -166,203 +146,93 @@ def projjson(self): Returns: dict """ - return self.get_projjson() + return self._get_property(PROJJSON_PROP, Dict[str, Any]) @projjson.setter - def projjson(self, v): - self.set_projjson(v) - - def get_projjson(self, asset=None): - """Gets an Item or an Asset projjson. - - If an Asset is supplied and the Item property exists on the Asset, - returns the Asset's value. Otherwise returns the Item's value - - Returns: - dict - """ - if asset is None or 'proj:projjson' not in asset.properties: - return self.item.properties.get('proj:projjson') - else: - return asset.properties.get('proj:projjson') - - def set_projjson(self, projjson, asset=None): - """Set an Item or an Asset projjson. - - If an Asset is supplied, sets the property on the Asset. - Otherwise sets the Item's value. - """ - self._set_property('proj:projjson', projjson, asset) + def projjson(self, v: Optional[Dict[str, Any]]) -> None: + self._set_property(PROJJSON_PROP, v) @property - def geometry(self): + def geometry(self) -> Optional[Dict[str, Any]]: """Get or sets a Polygon GeoJSON dict representing the footprint of this item. This dict should be formatted according the Polygon object format specified in `RFC 7946, sections 3.1.6 `_, - except not necessarily in EPSG:4326 as required by RFC7946. Specified based on the - ``epsg``, ``projjson`` or ``wkt2`` fields (not necessarily EPSG:4326). - Ideally, this will be represented by a Polygon with five coordinates, as the item in - the asset data CRS should be a square aligned to the original CRS grid. + except not necessarily in EPSG:4326 as required by RFC7946. Specified based on + the ``epsg``, ``projjson`` or ``wkt2`` fields (not necessarily EPSG:4326). + Ideally, this will be represented by a Polygon with five coordinates, as the + item in the asset data CRS should be a square aligned to the original CRS grid. Returns: dict """ - return self.get_geometry() + return self._get_property(GEOM_PROP, Dict[str, Any]) @geometry.setter - def geometry(self, v): - self.set_geometry(v) - - def get_geometry(self, asset=None): - """Gets an Item or an Asset projection geometry. - - If an Asset is supplied and the Item property exists on the Asset, - returns the Asset's value. Otherwise returns the Item's value - - Returns: - dict - """ - if asset is None or 'proj:geometry' not in asset.properties: - return self.item.properties.get('proj:geometry') - else: - return asset.properties.get('proj:geometry') - - def set_geometry(self, geometry, asset=None): - """Set an Item or an Asset projection geometry. - - If an Asset is supplied, sets the property on the Asset. - Otherwise sets the Item's value. - """ - self._set_property('proj:geometry', geometry, asset) + def geometry(self, v: Optional[Dict[str, Any]]) -> None: + self._set_property(GEOM_PROP, v) @property - def bbox(self): + def bbox(self) -> Optional[List[float]]: """Get or sets the bounding box of the assets represented by this item in the asset data CRS. - Specified as 4 or 6 coordinates based on the CRS defined in the ``epsg``, ``projjson`` - or ``wkt2`` properties. First two numbers are coordinates of the lower left corner, - followed by coordinates of upper right corner, e.g., + Specified as 4 or 6 coordinates based on the CRS defined in the ``epsg``, + ``projjson`` or ``wkt2`` properties. First two numbers are coordinates of the + lower left corner, followed by coordinates of upper right corner, e.g., [west, south, east, north], [xmin, ymin, xmax, ymax], [left, down, right, up], - or [west, south, lowest, east, north, highest]. The length of the array must be 2*n - where n is the number of dimensions. + or [west, south, lowest, east, north, highest]. The length of the array + must be 2*n where n is the number of dimensions. Returns: List[float] """ - return self.get_bbox() + return self._get_property(BBOX_PROP, List[float]) @bbox.setter - def bbox(self, v): - self.set_bbox(v) - - def get_bbox(self, asset=None): - """Gets an Item or an Asset projection bbox. - - If an Asset is supplied and the Item property exists on the Asset, - returns the Asset's value. Otherwise returns the Item's value - - Returns: - List[float] - """ - if asset is None or 'proj:bbox' not in asset.properties: - return self.item.properties.get('proj:bbox') - else: - return asset.properties.get('proj:bbox') - - def set_bbox(self, bbox, asset=None): - """Set an Item or an Asset projection bbox. - - If an Asset is supplied, sets the property on the Asset. - Otherwise sets the Item's value. - """ - self._set_property('proj:bbox', bbox, asset) + def bbox(self, v: Optional[List[float]]) -> None: + self._set_property(BBOX_PROP, v) @property - def centroid(self): + def centroid(self) -> Optional[Dict[str, float]]: """Get or sets coordinates representing the centroid of the item in the asset data CRS. - Coordinates are defined in latitude and longitude, even if the data coordinate system - does not use lat/long. + Coordinates are defined in latitude and longitude, even if the data coordinate + system does not use lat/long. - Exmample:: + Example:: item.ext.proj.centroid = { 'lat': 0.0, 'lon': 0.0 } Returns: dict """ - return self.get_centroid() + return self._get_property(CENTROID_PROP, Dict[str, float]) @centroid.setter - def centroid(self, v): - self.set_centroid(v) - - def get_centroid(self, asset=None): - """Gets an Item or an Asset centroid. - - If an Asset is supplied and the Item property exists on the Asset, - returns the Asset's value. Otherwise returns the Item's value - - Returns: - dict - """ - if asset is None or 'proj:centroid' not in asset.properties: - return self.item.properties.get('proj:centroid') - else: - return asset.properties.get('proj:centroid') - - def set_centroid(self, centroid, asset=None): - """Set an Item or an Asset centroid. - - If an Asset is supplied, sets the property on the Asset. - Otherwise sets the Item's value. - """ - self._set_property('proj:centroid', centroid, asset) + def centroid(self, v: Optional[Dict[str, float]]) -> None: + self._set_property(CENTROID_PROP, v) @property - def shape(self): + def shape(self) -> Optional[List[int]]: """Get or sets the number of pixels in Y and X directions for the default grid. - The shape is an array of integers that represents the number of pixels in the most - common pixel grid used by the item's assets. The number of pixels should be specified - in Y, X order. If the shape is defined in an item's properties it is used as the default - shape for all assets that don't have an overriding shape. + The shape is an array of integers that represents the number of pixels in the + most common pixel grid used by the item's assets. The number of pixels should + be specified in Y, X order. If the shape is defined in an item's properties it + is used as the default shape for all assets that don't have an overriding shape. Returns: List[int] """ - return self.get_shape() + return self._get_property(SHAPE_PROP, List[int]) @shape.setter - def shape(self, v): - self.set_shape(v) - - def get_shape(self, asset=None): - """Gets an Item or an Asset shape. - - If an Asset is supplied and the Item property exists on the Asset, - returns the Asset's value. Otherwise returns the Item's value - - Returns: - List[int] - """ - if asset is None or 'proj:shape' not in asset.properties: - return self.item.properties.get('proj:shape') - else: - return asset.properties.get('proj:shape') - - def set_shape(self, shape, asset=None): - """Set an Item or an Asset shape. - - If an Asset is supplied, sets the property on the Asset. - Otherwise sets the Item's value. - """ - self._set_property('proj:shape', shape, asset) + def shape(self, v: Optional[List[int]]) -> None: + self._set_property(SHAPE_PROP, v) @property - def transform(self): + def transform(self) -> Optional[List[float]]: """Get or sets the the affine transformation coefficients for the default grid. The transform is a linear mapping from pixel coordinate space (Pixel, Line) to @@ -376,42 +246,52 @@ def transform(self): Returns: List[float] """ # noqa: E501 - return self.get_transform() + return self._get_property(TRANSFORM_PROP, List[float]) @transform.setter - def transform(self, v): - self.set_transform(v) + def transform(self, v: Optional[List[float]]) -> None: + self._set_property(TRANSFORM_PROP, v) - def get_transform(self, asset=None): - """Gets an Item or an Asset transform. + @classmethod + def get_schema_uri(cls) -> str: + return SCHEMA_URI + + @staticmethod + def ext(obj: T) -> "ProjectionExtension[T]": + if isinstance(obj, pystac.Item): + return cast(ProjectionExtension[T], ItemProjectionExtension(obj)) + elif isinstance(obj, pystac.Asset): + return cast(ProjectionExtension[T], AssetProjectionExtension(obj)) + else: + raise pystac.ExtensionTypeError( + f"File extension does not apply to type {type(obj)}" + ) - If an Asset is supplied and the Item property exists on the Asset, - returns the Asset's value. Otherwise returns the Item's value - Returns: - List[float] - """ - if asset is None or 'proj:transform' not in asset.properties: - return self.item.properties.get('proj:transform') - else: - return asset.properties.get('proj:transform') +class ItemProjectionExtension(ProjectionExtension[pystac.Item]): + def __init__(self, item: pystac.Item): + self.item = item + self.properties = item.properties - def set_transform(self, transform, asset=None): - """Set an Item or an Asset transform. + def __repr__(self) -> str: + return "".format(self.item.id) - If an Asset is supplied, sets the property on the Asset. - Otherwise sets the Item's value. - """ - self._set_property('proj:transform', transform, asset) - @classmethod - def _object_links(cls): - return [] +class AssetProjectionExtension(ProjectionExtension[pystac.Asset]): + def __init__(self, asset: pystac.Asset): + self.asset_href = asset.href + self.properties = asset.properties + if asset.owner and isinstance(asset.owner, pystac.Item): + self.additional_read_properties = [asset.owner.properties] - @classmethod - def from_item(cls, item): - return cls(item) + def __repr__(self) -> str: + return "".format(self.asset_href) + + +class ProjectionExtensionHooks(ExtensionHooks): + schema_uri: str = SCHEMA_URI + prev_extension_ids: Set[str] = set(["proj", "projection"]) + stac_object_types: Set[pystac.STACObjectType] = set([pystac.STACObjectType.ITEM]) -PROJECTION_EXTENSION_DEFINITION = ExtensionDefinition(Extensions.PROJECTION, - [ExtendedObject(Item, ProjectionItemExt)]) +PROJECTION_EXTENSION_HOOKS = ProjectionExtensionHooks() diff --git a/pystac/extensions/sar.py b/pystac/extensions/sar.py index bf279a7b1..62e7f97fb 100644 --- a/pystac/extensions/sar.py +++ b/pystac/extensions/sar.py @@ -1,59 +1,66 @@ -"""Implement the STAC Synthetic-Aperture Radar (SAR) Extension. +"""Implements the Synthetic-Aperture Radar (SAR) extension. https://github.com/stac-extensions/sar """ import enum -from typing import List, Optional, TypeVar +from typing import Any, Dict, Generic, List, Optional, Set, TypeVar, cast import pystac -from pystac import Extensions -from pystac.extensions import base +from pystac.serialization.identify import STACJSONDescription, STACVersionID +from pystac.extensions.base import ExtensionManagementMixin +from pystac.extensions.projection import ProjectionExtension +from pystac.extensions.hooks import ExtensionHooks +from pystac.utils import get_required, map_opt + +T = TypeVar("T", pystac.Item, pystac.Asset) + +SCHEMA_URI = "https://stac-extensions.github.io/sar/v1.0.0/schema.json" # Required -INSTRUMENT_MODE: str = 'sar:instrument_mode' -FREQUENCY_BAND: str = 'sar:frequency_band' -POLARIZATIONS: str = 'sar:polarizations' -PRODUCT_TYPE: str = 'sar:product_type' +INSTRUMENT_MODE: str = "sar:instrument_mode" +FREQUENCY_BAND: str = "sar:frequency_band" +POLARIZATIONS: str = "sar:polarizations" +PRODUCT_TYPE: str = "sar:product_type" # Not required -CENTER_FREQUENCY: str = 'sar:center_frequency' -RESOLUTION_RANGE: str = 'sar:resolution_range' -RESOLUTION_AZIMUTH: str = 'sar:resolution_azimuth' -PIXEL_SPACING_RANGE: str = 'sar:pixel_spacing_range' -PIXEL_SPACING_AZIMUTH: str = 'sar:pixel_spacing_azimuth' -LOOKS_RANGE: str = 'sar:looks_range' -LOOKS_AZIMUTH: str = 'sar:looks_azimuth' -LOOKS_EQUIVALENT_NUMBER: str = 'sar:looks_equivalent_number' -OBSERVATION_DIRECTION: str = 'sar:observation_direction' - -SarItemExtType = TypeVar('SarItemExtType') - - -class FrequencyBand(enum.Enum): - P: str = 'P' - L: str = 'L' - S: str = 'S' - C: str = 'C' - X: str = 'X' - KU: str = 'Ku' - K: str = 'K' - KA: str = 'Ka' +CENTER_FREQUENCY: str = "sar:center_frequency" +RESOLUTION_RANGE: str = "sar:resolution_range" +RESOLUTION_AZIMUTH: str = "sar:resolution_azimuth" +PIXEL_SPACING_RANGE: str = "sar:pixel_spacing_range" +PIXEL_SPACING_AZIMUTH: str = "sar:pixel_spacing_azimuth" +LOOKS_RANGE: str = "sar:looks_range" +LOOKS_AZIMUTH: str = "sar:looks_azimuth" +LOOKS_EQUIVALENT_NUMBER: str = "sar:looks_equivalent_number" +OBSERVATION_DIRECTION: str = "sar:observation_direction" + + +class FrequencyBand(str, enum.Enum): + P = "P" + L = "L" + S = "S" + C = "C" + X = "X" + KU = "Ku" + K = "K" + KA = "Ka" class Polarization(enum.Enum): - HH: str = 'HH' - VV: str = 'VV' - HV: str = 'HV' - VH: str = 'VH' + HH = "HH" + VV = "VV" + HV = "HV" + VH = "VH" class ObservationDirection(enum.Enum): - LEFT: str = 'left' - RIGHT: str = 'right' + LEFT = "left" + RIGHT = "right" -class SarItemExt(base.ItemExtension): +class SarExtension( + Generic[T], ProjectionExtension[T], ExtensionManagementMixin[pystac.Item] +): """SarItemExt extends Item to add sar properties to a STAC Item. Args: @@ -66,54 +73,57 @@ class SarItemExt(base.ItemExtension): Using SarItemExt to directly wrap an item will add the 'sar' extension ID to the item's stac_extensions. """ - item: pystac.Item - - def __init__(self, an_item: pystac.Item) -> None: - self.item = an_item - - def apply(self, - instrument_mode: str, - frequency_band: FrequencyBand, - polarizations: List[Polarization], - product_type: str, - center_frequency: Optional[float] = None, - resolution_range: Optional[float] = None, - resolution_azimuth: Optional[float] = None, - pixel_spacing_range: Optional[float] = None, - pixel_spacing_azimuth: Optional[float] = None, - looks_range: Optional[int] = None, - looks_azimuth: Optional[int] = None, - looks_equivalent_number: Optional[float] = None, - observation_direction: Optional[ObservationDirection] = None): + + def apply( + self, + instrument_mode: str, + frequency_band: FrequencyBand, + polarizations: List[Polarization], + product_type: str, + center_frequency: Optional[float] = None, + resolution_range: Optional[float] = None, + resolution_azimuth: Optional[float] = None, + pixel_spacing_range: Optional[float] = None, + pixel_spacing_azimuth: Optional[float] = None, + looks_range: Optional[int] = None, + looks_azimuth: Optional[int] = None, + looks_equivalent_number: Optional[float] = None, + observation_direction: Optional[ObservationDirection] = None, + ) -> None: """Applies sar extension properties to the extended Item. Args: - instrument_mode (str): The name of the sensor acquisition mode that is commonly used. - This should be the short name, if available. For example, WV for "Wave mode." - frequency_band (FrequencyBand): The common name for the frequency band to make it easier - to search for bands across instruments. See section "Common Frequency Band Names" - for a list of accepted names. + instrument_mode (str): The name of the sensor acquisition mode that is + commonly used. This should be the short name, if available. For example, + WV for "Wave mode." + frequency_band (FrequencyBand): The common name for the frequency band to + make it easier to search for bands across instruments. See section + "Common Frequency Band Names" for a list of accepted names. polarizations (List[Polarization]): Any combination of polarizations. product_type (str): The product type, for example SSC, MGD, or SGC. center_frequency (float): Optional center frequency of the instrument in gigahertz (GHz). - resolution_range (float): Optional range resolution, which is the maximum ability to - distinguish two adjacent targets perpendicular to the flight path, in meters (m). - resolution_azimuth (float): Optional azimuth resolution, which is the maximum ability - to distinguish two adjacent targets parallel to the flight path, in meters (m). - pixel_spacing_range (float): Optional range pixel spacing, which is the distance - between adjacent pixels perpendicular to the flight path, in meters (m). Strongly - RECOMMENDED to be specified for products of type GRD. - pixel_spacing_azimuth (float): Optional azimuth pixel spacing, which is the distance - between adjacent pixels parallel to the flight path, in meters (m). Strongly - RECOMMENDED to be specified for products of type GRD. - looks_range (int): Optional number of groups of signal samples (looks) perpendicular - to the flight path. - looks_azimuth (int): Optional number of groups of signal samples (looks) parallel - to the flight path. + resolution_range (float): Optional range resolution, which is the maximum + ability to distinguish two adjacent targets perpendicular to the flight + path, in meters (m). + resolution_azimuth (float): Optional azimuth resolution, which is the + maximum ability to distinguish two adjacent targets parallel to the + flight path, in meters (m). + pixel_spacing_range (float): Optional range pixel spacing, which is the + distance between adjacent pixels perpendicular to the flight path, + in meters (m). Strongly RECOMMENDED to be specified for + products of type GRD. + pixel_spacing_azimuth (float): Optional azimuth pixel spacing, which is the + distance between adjacent pixels parallel to the flight path, in + meters (m). Strongly RECOMMENDED to be specified for products of + type GRD. + looks_range (int): Optional number of groups of signal samples (looks) + perpendicular to the flight path. + looks_azimuth (int): Optional number of groups of signal samples (looks) + parallel to the flight path. looks_equivalent_number (float): Optional equivalent number of looks (ENL). - observation_direction (ObservationDirection): Optional Antenna pointing direction - relative to the flight trajectory of the satellite. + observation_direction (ObservationDirection): Optional Antenna pointing + direction relative to the flight trajectory of the satellite. """ self.instrument_mode = instrument_mode self.frequency_band = frequency_band @@ -138,14 +148,6 @@ def apply(self, if observation_direction: self.observation_direction = observation_direction - @classmethod - def from_item(cls: SarItemExtType, an_item: pystac.Item) -> SarItemExtType: - return cls(an_item) - - @classmethod - def _object_links(cls) -> List: - return [] - @property def instrument_mode(self) -> str: """Get or sets an instrument mode string for the item. @@ -153,11 +155,13 @@ def instrument_mode(self) -> str: Returns: str """ - return self.item.properties.get(INSTRUMENT_MODE) + return get_required( + self._get_property(INSTRUMENT_MODE, str), self, INSTRUMENT_MODE + ) @instrument_mode.setter def instrument_mode(self, v: str) -> None: - self.item.properties[INSTRUMENT_MODE] = v + self._set_property(INSTRUMENT_MODE, v, pop_if_none=False) @property def frequency_band(self) -> FrequencyBand: @@ -166,11 +170,17 @@ def frequency_band(self) -> FrequencyBand: Returns: FrequencyBand """ - return FrequencyBand(self.item.properties.get(FREQUENCY_BAND)) + return get_required( + map_opt( + lambda x: FrequencyBand(x), self._get_property(FREQUENCY_BAND, str) + ), + self, + FREQUENCY_BAND, + ) @frequency_band.setter def frequency_band(self, v: FrequencyBand) -> None: - self.item.properties[FREQUENCY_BAND] = v.value + self._set_property(FREQUENCY_BAND, v.value, pop_if_none=False) @property def polarizations(self) -> List[Polarization]: @@ -179,13 +189,20 @@ def polarizations(self) -> List[Polarization]: Returns: List[Polarization] """ - return [Polarization(v) for v in self.item.properties.get(POLARIZATIONS)] + return get_required( + map_opt( + lambda values: [Polarization(v) for v in values], + self._get_property(POLARIZATIONS, List[str]), + ), + self, + POLARIZATIONS, + ) @polarizations.setter def polarizations(self, values: List[Polarization]) -> None: if not isinstance(values, list): raise pystac.STACError(f'polarizations must be a list. Invalid "{values}"') - self.item.properties[POLARIZATIONS] = [v.value for v in values] + self._set_property(POLARIZATIONS, [v.value for v in values], pop_if_none=False) @property def product_type(self) -> str: @@ -194,130 +211,166 @@ def product_type(self) -> str: Returns: str """ - return self.item.properties.get(PRODUCT_TYPE) + return get_required(self._get_property(PRODUCT_TYPE, str), self, PRODUCT_TYPE) @product_type.setter def product_type(self, v: str) -> None: - self.item.properties[PRODUCT_TYPE] = v + self._set_property(PRODUCT_TYPE, v, pop_if_none=False) @property - def center_frequency(self) -> float: - """Get or sets a center frequency for the item. - - Returns: - float - """ - return self.item.properties.get(CENTER_FREQUENCY) + def center_frequency(self) -> Optional[float]: + """Get or sets a center frequency for the item.""" + return self._get_property(CENTER_FREQUENCY, float) @center_frequency.setter - def center_frequency(self, v: float) -> None: - self.item.properties[CENTER_FREQUENCY] = v + def center_frequency(self, v: Optional[float]) -> None: + self._set_property(CENTER_FREQUENCY, v) @property - def resolution_range(self) -> float: - """Get or sets a resolution range for the item. - - Returns: - float - """ - return self.item.properties.get(RESOLUTION_RANGE) + def resolution_range(self) -> Optional[float]: + """Get or sets a resolution range for the item.""" + return self._get_property(RESOLUTION_RANGE, float) @resolution_range.setter - def resolution_range(self, v: float) -> None: - self.item.properties[RESOLUTION_RANGE] = v + def resolution_range(self, v: Optional[float]) -> None: + self._set_property(RESOLUTION_RANGE, v) @property - def resolution_azimuth(self) -> float: - """Get or sets a resolution azimuth for the item. - - Returns: - float - """ - return self.item.properties.get(RESOLUTION_AZIMUTH) + def resolution_azimuth(self) -> Optional[float]: + """Get or sets a resolution azimuth for the item.""" + return self._get_property(RESOLUTION_AZIMUTH, float) @resolution_azimuth.setter - def resolution_azimuth(self, v: float) -> None: - self.item.properties[RESOLUTION_AZIMUTH] = v + def resolution_azimuth(self, v: Optional[float]) -> None: + self._set_property(RESOLUTION_AZIMUTH, v) @property - def pixel_spacing_range(self) -> float: - """Get or sets a pixel spacing range for the item. - - Returns: - float - """ - return self.item.properties.get(PIXEL_SPACING_RANGE) + def pixel_spacing_range(self) -> Optional[float]: + """Get or sets a pixel spacing range for the item.""" + return self._get_property(PIXEL_SPACING_RANGE, float) @pixel_spacing_range.setter - def pixel_spacing_range(self, v: float) -> None: - self.item.properties[PIXEL_SPACING_RANGE] = v + def pixel_spacing_range(self, v: Optional[float]) -> None: + self._set_property(PIXEL_SPACING_RANGE, v) @property - def pixel_spacing_azimuth(self) -> float: - """Get or sets a pixel spacing azimuth for the item. - - Returns: - float - """ - return self.item.properties.get(PIXEL_SPACING_AZIMUTH) + def pixel_spacing_azimuth(self) -> Optional[float]: + """Get or sets a pixel spacing azimuth for the item.""" + return self._get_property(PIXEL_SPACING_AZIMUTH, float) @pixel_spacing_azimuth.setter - def pixel_spacing_azimuth(self, v: float) -> None: - self.item.properties[PIXEL_SPACING_AZIMUTH] = v + def pixel_spacing_azimuth(self, v: Optional[float]) -> None: + self._set_property(PIXEL_SPACING_AZIMUTH, v) @property - def looks_range(self) -> int: - """Get or sets a looks range for the item. - - Returns: - int - """ - return self.item.properties.get(LOOKS_RANGE) + def looks_range(self) -> Optional[int]: + """Get or sets a looks range for the item.""" + return self._get_property(LOOKS_RANGE, int) @looks_range.setter - def looks_range(self, v: int) -> None: - self.item.properties[LOOKS_RANGE] = v + def looks_range(self, v: Optional[int]) -> None: + self._set_property(LOOKS_RANGE, v) @property - def looks_azimuth(self) -> int: - """Get or sets a looks azimuth for the item. - - Returns: - int - """ - return self.item.properties.get(LOOKS_AZIMUTH) + def looks_azimuth(self) -> Optional[int]: + """Get or sets a looks azimuth for the item.""" + return self._get_property(LOOKS_AZIMUTH, int) @looks_azimuth.setter - def looks_azimuth(self, v: int) -> None: - self.item.properties[LOOKS_AZIMUTH] = v + def looks_azimuth(self, v: Optional[int]) -> None: + self._set_property(LOOKS_AZIMUTH, v) @property - def looks_equivalent_number(self) -> float: - """Get or sets a looks equivalent number for the item. - - Returns: - float - """ - return self.item.properties.get(LOOKS_EQUIVALENT_NUMBER) + def looks_equivalent_number(self) -> Optional[float]: + """Get or sets a looks equivalent number for the item.""" + return self._get_property(LOOKS_EQUIVALENT_NUMBER, float) @looks_equivalent_number.setter - def looks_equivalent_number(self, v: float) -> None: - self.item.properties[LOOKS_EQUIVALENT_NUMBER] = v + def looks_equivalent_number(self, v: Optional[float]) -> None: + self._set_property(LOOKS_EQUIVALENT_NUMBER, v) @property - def observation_direction(self) -> ObservationDirection: - """Get or sets an observation direction for the item. - - Returns: - ObservationDirection - """ - return ObservationDirection(self.item.properties.get(OBSERVATION_DIRECTION)) + def observation_direction(self) -> Optional[ObservationDirection]: + """Get or sets an observation direction for the item.""" + result = self._get_property(OBSERVATION_DIRECTION, str) + if result is None: + return None + return ObservationDirection(result) @observation_direction.setter - def observation_direction(self, v: ObservationDirection) -> None: - self.item.properties[OBSERVATION_DIRECTION] = v.value + def observation_direction(self, v: Optional[ObservationDirection]) -> None: + self._set_property(OBSERVATION_DIRECTION, map_opt(lambda x: x.value, v)) - -SAR_EXTENSION_DEFINITION = base.ExtensionDefinition(Extensions.SAR, [ - base.ExtendedObject(pystac.Item, SarItemExt), -]) + @classmethod + def get_schema_uri(cls) -> str: + return SCHEMA_URI + + @staticmethod + def ext(obj: T) -> "SarExtension[T]": + if isinstance(obj, pystac.Item): + return cast(SarExtension[T], ItemSarExtension(obj)) + elif isinstance(obj, pystac.Asset): + return cast(SarExtension[T], AssetSarExtension(obj)) + else: + raise pystac.ExtensionTypeError( + f"File extension does not apply to type {type(obj)}" + ) + + +class ItemSarExtension(SarExtension[pystac.Item]): + def __init__(self, item: pystac.Item): + self.item = item + self.properties = item.properties + + def __repr__(self) -> str: + return "".format(self.item.id) + + +class AssetSarExtension(SarExtension[pystac.Asset]): + def __init__(self, asset: pystac.Asset): + self.asset_href = asset.href + self.properties = asset.properties + if asset.owner and isinstance(asset.owner, pystac.Item): + self.additional_read_properties = [asset.owner.properties] + + def __repr__(self) -> str: + return "".format(self.asset_href) + + +class SarExtensionHooks(ExtensionHooks): + schema_uri = SCHEMA_URI + prev_extension_ids: Set[str] = set(["sar"]) + stac_object_types: Set[pystac.STACObjectType] = set([pystac.STACObjectType.ITEM]) + + def migrate( + self, obj: Dict[str, Any], version: STACVersionID, info: STACJSONDescription + ) -> None: + if version < "0.9": + # Some sar fields became common_metadata + if ( + "sar:platform" in obj["properties"] + and "platform" not in obj["properties"] + ): + obj["properties"]["platform"] = obj["properties"]["sar:platform"] + del obj["properties"]["sar:platform"] + + if ( + "sar:instrument" in obj["properties"] + and "instruments" not in obj["properties"] + ): + obj["properties"]["instruments"] = [obj["properties"]["sar:instrument"]] + del obj["properties"]["sar:instrument"] + + if ( + "sar:constellation" in obj["properties"] + and "constellation" not in obj["properties"] + ): + obj["properties"]["constellation"] = obj["properties"][ + "sar:constellation" + ] + del obj["properties"]["sar:constellation"] + + super().migrate(obj, version, info) + + +SAR_EXTENSION_HOOKS: ExtensionHooks = SarExtensionHooks() diff --git a/pystac/extensions/sat.py b/pystac/extensions/sat.py index d2f87c942..ce0cd3460 100644 --- a/pystac/extensions/sat.py +++ b/pystac/extensions/sat.py @@ -1,27 +1,36 @@ -"""Implement the Satellite (SAT) Extension. +"""Implements the Satellite extension. https://github.com/stac-extensions/sat """ import enum -from typing import List, Optional +from typing import Generic, Optional, Set, TypeVar, cast import pystac -from pystac import Extensions -from pystac import item -from pystac.extensions import base +from pystac.extensions.base import ( + ExtensionManagementMixin, + PropertiesExtension, +) +from pystac.extensions.hooks import ExtensionHooks +from pystac.utils import map_opt -ORBIT_STATE: str = 'sat:orbit_state' -RELATIVE_ORBIT: str = 'sat:relative_orbit' +T = TypeVar("T", pystac.Item, pystac.Asset) + +SCHEMA_URI = "https://stac-extensions.github.io/sat/v1.0.0/schema.json" + +ORBIT_STATE: str = "sat:orbit_state" +RELATIVE_ORBIT: str = "sat:relative_orbit" class OrbitState(enum.Enum): - ASCENDING: str = 'ascending' - DESCENDING: str = 'descending' - GEOSTATIONARY: str = 'geostationary' + ASCENDING = "ascending" + DESCENDING = "descending" + GEOSTATIONARY = "geostationary" -class SatItemExt(base.ItemExtension): +class SatExtension( + Generic[T], PropertiesExtension, ExtensionManagementMixin[pystac.Item] +): """SatItemExt extends Item to add sat properties to a STAC Item. Args: @@ -34,36 +43,27 @@ class SatItemExt(base.ItemExtension): Using SatItemExt to directly wrap an item will add the 'sat' extension ID to the item's stac_extensions. """ - item: pystac.Item - - def __init__(self, an_item: item.Item) -> None: - self.item = an_item - def apply(self, orbit_state: Optional[OrbitState] = None, relative_orbit: Optional[str] = None): + def apply( + self, + orbit_state: Optional[OrbitState] = None, + relative_orbit: Optional[int] = None, + ) -> None: """Applies ext extension properties to the extended Item. - Must specify at least one of orbit_state or relative_orbit. + Must specify at least one of orbit_state or relative_orbit in order + for the sat extension to properties to be valid. Args: - orbit_state (OrbitState): Optional state of the orbit. Either ascending or descending - for polar orbiting satellites, or geostationary for geosynchronous satellites. - relative_orbit (int): Optional non-negative integer of the orbit number at the time - of acquisition. + orbit_state (OrbitState): Optional state of the orbit. Either ascending or + descending for polar orbiting satellites, or geostationary for + geosynchronous satellites. + relative_orbit (int): Optional non-negative integer of the orbit number at + the time of acquisition. """ - if orbit_state is None and relative_orbit is None: - raise pystac.STACError('Must provide at least one of: orbit_state or relative_orbit') - if orbit_state: - self.orbit_state = orbit_state - if relative_orbit: - self.relative_orbit = relative_orbit - - @classmethod - def from_item(cls, an_item: item.Item): - return cls(an_item) - @classmethod - def _object_links(cls) -> List: - return [] + self.orbit_state = orbit_state + self.relative_orbit = relative_orbit @property def orbit_state(self) -> Optional[OrbitState]: @@ -72,43 +72,65 @@ def orbit_state(self) -> Optional[OrbitState]: Returns: OrbitState or None """ - if ORBIT_STATE not in self.item.properties: - return - return OrbitState(self.item.properties.get(ORBIT_STATE)) + return map_opt(lambda x: OrbitState(x), self._get_property(ORBIT_STATE, str)) @orbit_state.setter def orbit_state(self, v: Optional[OrbitState]) -> None: - if v is None: - if self.relative_orbit is None: - raise pystac.STACError('Must set relative_orbit before clearing orbit_state') - if ORBIT_STATE in self.item.properties: - del self.item.properties[ORBIT_STATE] - else: - self.item.properties[ORBIT_STATE] = v.value + self._set_property(ORBIT_STATE, map_opt(lambda x: x.value, v)) @property - def relative_orbit(self) -> int: + def relative_orbit(self) -> Optional[int]: """Get or sets a relative orbit number of the item. Returns: int or None """ - return self.item.properties.get(RELATIVE_ORBIT) + return self._get_property(RELATIVE_ORBIT, int) @relative_orbit.setter - def relative_orbit(self, v: int) -> None: - if v is None and self.orbit_state is None: - raise pystac.STACError('Must set orbit_state before clearing relative_orbit') - if v is None: - if RELATIVE_ORBIT in self.item.properties: - del self.item.properties[RELATIVE_ORBIT] - return - if v < 0: - raise pystac.STACError(f'relative_orbit must be >= 0. Found {v}.') - - self.item.properties[RELATIVE_ORBIT] = v - - -SAT_EXTENSION_DEFINITION = base.ExtensionDefinition(Extensions.SAT, [ - base.ExtendedObject(pystac.Item, SatItemExt), -]) + def relative_orbit(self, v: Optional[int]) -> None: + self._set_property(RELATIVE_ORBIT, v) + + @classmethod + def get_schema_uri(cls) -> str: + return SCHEMA_URI + + @staticmethod + def ext(obj: T) -> "SatExtension[T]": + if isinstance(obj, pystac.Item): + return cast(SatExtension[T], ItemSatExtension(obj)) + elif isinstance(obj, pystac.Asset): + return cast(SatExtension[T], AssetSatExtension(obj)) + else: + raise pystac.ExtensionTypeError( + f"File extension does not apply to type {type(obj)}" + ) + + +class ItemSatExtension(SatExtension[pystac.Item]): + def __init__(self, item: pystac.Item): + self.item = item + self.properties = item.properties + + def __repr__(self) -> str: + return "".format(self.item.id) + + +class AssetSatExtension(SatExtension[pystac.Asset]): + def __init__(self, asset: pystac.Asset): + self.asset_href = asset.href + self.properties = asset.properties + if asset.owner and isinstance(asset.owner, pystac.Item): + self.additional_read_properties = [asset.owner.properties] + + def __repr__(self) -> str: + return "".format(self.asset_href) + + +class SatExtensionHooks(ExtensionHooks): + schema_uri: str = SCHEMA_URI + prev_extension_ids: Set[str] = set(["sat"]) + stac_object_types: Set[pystac.STACObjectType] = set([pystac.STACObjectType.ITEM]) + + +SAT_EXTENSION_HOOKS = SatExtensionHooks() diff --git a/pystac/extensions/scientific.py b/pystac/extensions/scientific.py index 270244414..26cc719a9 100644 --- a/pystac/extensions/scientific.py +++ b/pystac/extensions/scientific.py @@ -1,4 +1,4 @@ -"""Implement the scientific extension. +"""Implements the scientific extension. https://github.com/stac-extensions/scientific @@ -8,23 +8,31 @@ """ import copy -from typing import Dict, List, Optional +from typing import Any, Dict, Generic, List, Optional, Set, TypeVar, Union, cast from urllib import parse import pystac -from pystac import Extensions -from pystac.extensions import base +from pystac.extensions.base import ( + ExtensionManagementMixin, + PropertiesExtension, +) +from pystac.extensions.hooks import ExtensionHooks +from pystac.utils import map_opt + +T = TypeVar("T", pystac.Collection, pystac.Item) + +SCHEMA_URI = "https://stac-extensions.github.io/scientific/v1.0.0/schema.json" # STAC fields strings. -PREFIX: str = 'sci:' -DOI: str = PREFIX + 'doi' -CITATION: str = PREFIX + 'citation' -PUBLICATIONS: str = PREFIX + 'publications' +PREFIX: str = "sci:" +DOI: str = PREFIX + "doi" +CITATION: str = PREFIX + "citation" +PUBLICATIONS: str = PREFIX + "publications" # Link type. -CITE_AS: str = 'cite-as' +CITE_AS: str = "cite-as" -DOI_URL_BASE = 'https://doi.org/' +DOI_URL_BASE = "https://doi.org/" def doi_to_url(doi: str) -> str: @@ -33,31 +41,32 @@ def doi_to_url(doi: str) -> str: class Publication: """Helper for Publication entries.""" + def __init__(self, doi: str, citation: str) -> None: self.doi = doi self.citation = citation - def __eq__(self, other): + def __eq__(self, other: Any) -> bool: if not isinstance(other, Publication): return NotImplemented return self.doi == other.doi and self.citation == other.citation def __repr__(self) -> str: - return f'' + return f"" def to_dict(self) -> Dict[str, str]: - return copy.deepcopy({'doi': self.doi, 'citation': self.citation}) + return copy.deepcopy({"doi": self.doi, "citation": self.citation}) @staticmethod - def from_dict(d: Dict[str, str]): - return Publication(d['doi'], d['citation']) + def from_dict(d: Dict[str, str]) -> "Publication": + return Publication(d["doi"], d["citation"]) def get_link(self) -> pystac.Link: return pystac.Link(CITE_AS, doi_to_url(self.doi)) -def remove_link(links: List[pystac.Link], doi: str): +def remove_link(links: List[pystac.Link], doi: str) -> None: url = doi_to_url(doi) for i, a_link in enumerate(links): if a_link.rel != CITE_AS: @@ -67,28 +76,22 @@ def remove_link(links: List[pystac.Link], doi: str): break -class ScientificItemExt(base.ItemExtension): - """ScientificItemExt extends Item to add citations and DOIs to a STAC Item. - - Args: - item (Item): The item to be extended. +class ScientificExtension( + Generic[T], + PropertiesExtension, + ExtensionManagementMixin[Union[pystac.Collection, pystac.Item]], +): + """ScientificItemExt extends Item to add citations and DOIs to a STAC Item.""" - Attributes: - item (Item): The item that is being extended. + def __init__(self, obj: pystac.STACObject) -> None: + self.obj = obj - Note: - Using ScientificItemExt to directly wrap an item will add the 'scientific' - extension ID to the item's stac_extensions. - """ - item: pystac.Item - - def __init__(self, an_item: pystac.Item) -> None: - self.item = an_item - - def apply(self, - doi: Optional[str] = None, - citation: Optional[str] = None, - publications: Optional[List[Publication]] = None) -> None: + def apply( + self, + doi: Optional[str] = None, + citation: Optional[str] = None, + publications: Optional[List[Publication]] = None, + ) -> None: """Applies scientific extension properties to the extended Item. Args: @@ -97,216 +100,137 @@ def apply(self, publications (List[Publication]): Optional list of relevant publications referencing and describing the data. """ - if doi: - self.doi = doi - if citation: - self.citation = citation - if publications: - self.publications = publications - - @classmethod - def from_item(cls, an_item: pystac.Item): - return cls(an_item) - - @classmethod - def _object_links(cls) -> List: - return [] + self.doi = doi + self.citation = citation + self.publications = publications @property - def doi(self) -> str: + def doi(self) -> Optional[str]: """Get or sets the DOI for the item. Returns: str """ - return self.item.properties.get(DOI) + return self._get_property(DOI, str) @doi.setter - def doi(self, v: str) -> None: - if DOI in self.item.properties: - if v == self.item.properties[DOI]: + def doi(self, v: Optional[str]) -> None: + if DOI in self.properties: + if v == self.properties[DOI]: return - remove_link(self.item.links, self.item.properties[DOI]) + remove_link(self.obj.links, self.properties[DOI]) - self.item.properties[DOI] = v - url = doi_to_url(self.doi) - self.item.add_link(pystac.Link(CITE_AS, url)) + if v is not None: + self.properties[DOI] = v + url = doi_to_url(v) + self.obj.add_link(pystac.Link(CITE_AS, url)) @property - def citation(self) -> str: + def citation(self) -> Optional[str]: """Get or sets the citation for the item. Returns: str """ - return self.item.properties.get(CITATION) + return self._get_property(CITATION, str) @citation.setter - def citation(self, v: str) -> None: - self.item.properties[CITATION] = v + def citation(self, v: Optional[str]) -> None: + self._set_property(CITATION, v) @property - def publications(self) -> List[Publication]: + def publications(self) -> Optional[List[Publication]]: """Get or sets the publication list for the item. Returns: List of Publication instances. """ - return [Publication.from_dict(pub) for pub in self.item.properties.get(PUBLICATIONS, [])] + return map_opt( + lambda pubs: [Publication.from_dict(pub) for pub in pubs], + self._get_property(PUBLICATIONS, List[Dict[str, Any]]), + ) @publications.setter - def publications(self, v: List[Publication]) -> None: - self.item.properties[PUBLICATIONS] = [pub.to_dict() for pub in v] - for pub in v: - self.item.add_link(pub.get_link()) + def publications(self, v: Optional[List[Publication]]) -> None: + self._set_property( + PUBLICATIONS, map_opt(lambda pubs: [pub.to_dict() for pub in pubs], v) + ) + if v is not None: + for pub in v: + self.obj.add_link(pub.get_link()) # None for publication will clear all. def remove_publication(self, publication: Optional[Publication] = None) -> None: """Removes publications from the item. Args: - publication (Publication): The specific publication to remove of None to remove all. + publication (Publication): The specific publication to remove of None to + remove all. """ - if PUBLICATIONS not in self.item.properties: + if PUBLICATIONS not in self.properties: return if not publication: - for one_pub in self.item.ext.scientific.publications: - remove_link(self.item.links, one_pub.doi) + pubs = self.publications + if pubs is not None: + for one_pub in pubs: + remove_link(self.obj.links, one_pub.doi) - del self.item.properties[PUBLICATIONS] + del self.properties[PUBLICATIONS] return # One publication and link to remove - remove_link(self.item.links, publication.doi) + remove_link(self.obj.links, publication.doi) to_remove = publication.to_dict() - self.item.properties[PUBLICATIONS].remove(to_remove) - - if not self.item.properties[PUBLICATIONS]: - del self.item.properties[PUBLICATIONS] - - -class ScientificCollectionExt(base.CollectionExtension): - """ScientificCollectionExt extends Collection to add citations and DOIs to a STAC Collection. - - Args: - collection (Collection): The collection to be extended. + self.properties[PUBLICATIONS].remove(to_remove) - Attributes: - collection (Collection): The collection that is being extended. - - Note: - Using ScientificCollectionExt to directly wrap a collection will add the 'scientific' - extension ID to the collection's stac_extensions. - """ - collection: pystac.Collection - - def __init__(self, a_collection): - self.collection = a_collection - - def apply(self, - doi: Optional[str] = None, - citation: Optional[str] = None, - publications: Optional[List[Publication]] = None): - """Applies scientific extension properties to the extended Collection. - - Args: - doi (str): Optional DOI string for the collection. Must not be a DOI link. - citation (str): Optional human-readable reference. - publications (List[Publication]): Optional list of relevant publications - referencing and describing the data. - """ - if doi: - self.doi = doi - if citation: - self.citation = citation - if publications: - self.publications = publications - - @classmethod - def from_collection(cls, a_collection: pystac.Collection): - return cls(a_collection) + if not self.properties[PUBLICATIONS]: + del self.properties[PUBLICATIONS] @classmethod - def _object_links(cls) -> List: - return [] - - @property - def doi(self) -> str: - """Get or sets the DOI for the collection. + def get_schema_uri(cls) -> str: + return SCHEMA_URI - Returns: - str - """ - return self.collection.extra_fields.get(DOI) - - @doi.setter - def doi(self, v: str) -> None: - if DOI in self.collection.extra_fields: - if v == self.collection.extra_fields[DOI]: - return - remove_link(self.collection.links, self.collection.extra_fields[DOI]) - self.collection.extra_fields[DOI] = v - url = doi_to_url(self.doi) - self.collection.add_link(pystac.Link(CITE_AS, url)) - - @property - def citation(self) -> str: - """Get or sets the citation for the collection. - - Returns: - str - """ - return self.collection.extra_fields.get(CITATION) - - @citation.setter - def citation(self, v: str) -> None: - self.collection.extra_fields[CITATION] = v - - @property - def publications(self) -> List[Publication]: - """Get or sets the publication list for the collection. - - Returns: - List of Publication instances. - """ - return [ - Publication.from_dict(p) for p in self.collection.extra_fields.get(PUBLICATIONS, []) - ] + @staticmethod + def ext(obj: T) -> "ScientificExtension[T]": + if isinstance(obj, pystac.Collection): + return cast(ScientificExtension[T], CollectionScientificExtension(obj)) + if isinstance(obj, pystac.Item): + return cast(ScientificExtension[T], ItemScientificExtension(obj)) + else: + raise pystac.ExtensionTypeError( + f"File extension does not apply to type {type(obj)}" + ) + + +class CollectionScientificExtension(ScientificExtension[pystac.Collection]): + def __init__(self, collection: pystac.Collection): + self.collection = collection + self.properties = collection.extra_fields + self.links = collection.links + super().__init__(self.collection) - @publications.setter - def publications(self, v: List[Publication]) -> None: - self.collection.extra_fields[PUBLICATIONS] = [pub.to_dict() for pub in v] - for pub in v: - self.collection.add_link(pub.get_link()) + def __repr__(self) -> str: + return "".format(self.collection.id) - # None for publication will clear all. - def remove_publication(self, publication: Optional[Publication] = None) -> None: - """Removes publications from the collection. - Args: - publication (Publication): The specific publication to remove of None to remove all. - """ - if PUBLICATIONS not in self.collection.extra_fields: - return - - if not publication: - for one_pub in self.collection.ext.scientific.publications: - remove_link(self.collection.links, one_pub.doi) +class ItemScientificExtension(ScientificExtension[pystac.Item]): + def __init__(self, item: pystac.Item): + self.item = item + self.properties = item.properties + self.links = item.links + super().__init__(self.item) - del self.collection.extra_fields[PUBLICATIONS] - return + def __repr__(self) -> str: + return "".format(self.item.id) - # One publication and link to remove - remove_link(self.collection.links, publication.doi) - to_remove = publication.to_dict() - self.collection.extra_fields[PUBLICATIONS].remove(to_remove) - if not self.collection.extra_fields[PUBLICATIONS]: - del self.collection.extra_fields[PUBLICATIONS] +class ScientificExtensionHooks(ExtensionHooks): + schema_uri: str = SCHEMA_URI + prev_extension_ids: Set[str] = set(["scientific"]) + stac_object_types: Set[pystac.STACObjectType] = set( + [pystac.STACObjectType.COLLECTION, pystac.STACObjectType.ITEM] + ) -SCIENTIFIC_EXTENSION_DEFINITION = base.ExtensionDefinition(Extensions.SCIENTIFIC, [ - base.ExtendedObject(pystac.Item, ScientificItemExt), - base.ExtendedObject(pystac.Collection, ScientificCollectionExt) -]) +SCIENTIFIC_EXTENSION_HOOKS = ScientificExtensionHooks() diff --git a/pystac/extensions/single_file_stac.py b/pystac/extensions/single_file_stac.py deleted file mode 100644 index ed1fa2a95..000000000 --- a/pystac/extensions/single_file_stac.py +++ /dev/null @@ -1,141 +0,0 @@ -"""Implement the Single File STAC extension. - -https://github.com/stac-extensions/single-file-stac -""" -from pystac.catalog import Catalog - -import pystac -from pystac import (STACError, Extensions) -from pystac.collection import Collection -from pystac.extensions.base import (CatalogExtension, ExtensionDefinition, ExtendedObject) - - -def create_single_file_stac(catalog): - """Creates a Single File STAC from a STAC catalog. - - This method will recursively collect any collections and items in the catalog - and return a new catalog with the same properties as the old one, with cleared - links and the 'collections' and 'features' property of the Single File STAC holding - each of the respective collected STAC objects. - - Collections will be filtered to only those referenced by items via the collection_id. - All links in the items and collections will be cleared in the Single File STAC. - - Args: - catalog (Catalog): Catalog to walk while constructin the Single File STAC - """ - collections = {} - items = [] - for root, _, cat_items in catalog.walk(): - if issubclass(type(root), Collection): - new_collection = root.clone() - new_collection.clear_links() - collections[root.id] = new_collection - for item in cat_items: - new_item = item.clone() - new_item.clear_links() - items.append(new_item) - - filtered_collections = [] - for item in items: - if item.collection_id in collections: - filtered_collections.append(collections[item.collection_id]) - collections.pop(item.collection_id) - - result = catalog.clone() - result.clear_links() - result.ext.enable(Extensions.SINGLE_FILE_STAC) - result.ext[Extensions.SINGLE_FILE_STAC].apply(features=items, collections=filtered_collections) - - return result - - -class SingleFileSTACCatalogExt(CatalogExtension): - """An extension of Catalog that provides a set of Collections and Items - as a single file catalog. A SingleFileSTAC - is a self contained catalog that contains everything that would normally be in a - linked set of STAC files. - - Args: - catalog (Catalog): The catalog to be extended. - - Attributes: - catalog (Catalog): The catalog that is being extended. - - Note: - Using SingleFileSTACCatalogExt to directly wrap a Catalog will - add the 'proj' extension ID to the catalog's stac_extensions. - """ - def __init__(self, catalog): - if catalog.stac_extensions is None: - catalog.stac_extensions = [Extensions.SINGLE_FILE_STAC] - elif Extensions.SINGLE_FILE_STAC not in catalog.stac_extensions: - catalog.stac_extensions.append(Extensions.SINGLE_FILE_STAC) - - self.catalog = catalog - - def apply(self, features, collections=None): - """ - Args: - features (List[Item]): List of items contained by - this SingleFileSTAC. - collections (List[Collection]): Optional list of collections that are - used by any of the Items in the catalog. - """ - self.features = features - self.collections = collections - - @classmethod - def enable_extension(cls, catalog): - # Ensure the 'type' property is correct so that the Catalog is valid GeoJSON. - catalog.extra_fields['type'] = 'FeatureCollection' - - @property - def features(self): - """Get or sets a list of :class:`~pystac.Item` contained in this Single File STAC. - - Returns: - List[Item] - """ - features = self.catalog.extra_fields.get('features') - if features is None: - raise STACError('Invalid Single File STAC: does not have "features" property.') - - return [pystac.read_dict(feature) for feature in features] - - @features.setter - def features(self, v): - self.catalog.extra_fields['features'] = [item.to_dict() for item in v] - - @property - def collections(self): - """Get or sets a list of :class:`~pystac.Collection` objects contained - in this Single File STAC. - - Returns: - List[Band] - """ - collections = self.catalog.extra_fields.get('collections') - - if collections is not None: - collections = [pystac.read_dict(col) for col in collections] - return collections - - @collections.setter - def collections(self, v): - if v is not None: - self.catalog.extra_fields['collections'] = [col.to_dict() for col in v] - else: - self.catalog.extra_fields.pop('collections', None) - - @classmethod - def _object_links(cls): - return [] - - @classmethod - def from_catalog(cls, catalog): - return SingleFileSTACCatalogExt(catalog) - - -SFS_EXTENSION_DEFINITION = ExtensionDefinition(Extensions.SINGLE_FILE_STAC, - [ExtendedObject(Catalog, SingleFileSTACCatalogExt)]) diff --git a/pystac/extensions/timestamps.py b/pystac/extensions/timestamps.py index 8a86172f5..e05b1db25 100644 --- a/pystac/extensions/timestamps.py +++ b/pystac/extensions/timestamps.py @@ -1,45 +1,41 @@ -"""Implement the timestamps extension. +"""Implements the Timestamps extension. https://github.com/stac-extensions/timestamps """ -import pystac -from pystac import Extensions -from pystac.extensions.base import (ExtendedObject, ExtensionDefinition, ItemExtension) -from pystac.item import Item -from pystac.utils import datetime_to_str, str_to_datetime +from datetime import datetime as Datetime +from typing import Generic, Optional, Set, TypeVar, cast -class TimestampsItemExt(ItemExtension): - """TimestampsItemExt is the extension of an Item in that - allows to specify additional timestamps for assets and metadata. +import pystac +from pystac.extensions.base import ( + ExtensionManagementMixin, + PropertiesExtension, +) +from pystac.extensions.hooks import ExtensionHooks +from pystac.utils import datetime_to_str, map_opt, str_to_datetime - Args: - item (Item): The item to be extended. +T = TypeVar("T", pystac.Item, pystac.Asset) - Attributes: - item (Item): The Item that is being extended. +SCHEMA_URI = "https://stac-extensions.github.io/timestamps/v1.0.0/schema.json" - Note: - Using TimestampsItemExt to directly wrap an item will add the 'timestamps' - extension ID to the item's stac_extensions. - """ - def __init__(self, item): - if item.stac_extensions is None: - item.stac_extensions = [Extensions.TIMESTAMPS] - elif Extensions.TIMESTAMPS not in item.stac_extensions: - item.stac_extensions.append(Extensions.TIMESTAMPS) +PUBLISHED_PROP = "published" +EXPIRES_PROP = "expires" +UNPUBLISHED_PROP = "unpublished" - self.item = item - @classmethod - def from_item(cls, item): - return cls(item) - - @classmethod - def _object_links(cls): - return [] +class TimestampsExtension( + Generic[T], PropertiesExtension, ExtensionManagementMixin[pystac.Item] +): + """TimestampsItemExt is the extension of an Item in that + allows to specify additional timestamps for assets and metadata. + """ - def apply(self, published=None, expires=None, unpublished=None): + def apply( + self, + published: Optional[Datetime] = None, + expires: Optional[Datetime] = None, + unpublished: Optional[Datetime] = None, + ) -> None: """Applies timestamps extension properties to the extended Item. Args: @@ -50,143 +46,112 @@ def apply(self, published=None, expires=None, unpublished=None): unpublished (datetime or None): Date and time the corresponding data was unpublished. """ - if published is None and expires is None and unpublished is None: - raise pystac.STACError("timestamps extension needs at least one property value.") - self.published = published self.expires = expires self.unpublished = unpublished - def _timestamp_getter(self, key, asset=None): - if asset is not None and key in asset.properties: - timestamp_str = asset.properties.get(key) - else: - timestamp_str = self.item.properties.get(key) - - timestamp = None - if timestamp_str is not None: - timestamp = str_to_datetime(timestamp_str) - - return timestamp - - def _timestamp_setter(self, timestamp, key, asset=None): - if timestamp is not None: - timestamp = datetime_to_str(timestamp) - self._set_property(key, timestamp, asset) - @property - def published(self): + def published(self) -> Optional[Datetime]: """Get or sets a datetime objects that represent the date and time that the corresponding data was published the first time. - Returns: - datetime - """ - return self.get_published() - - @published.setter - def published(self, v): - self.set_published(v) - - def get_published(self, asset=None): - """Get an Item or Asset published datetime - - If an Asset is supplied and the published property exists on the Asset, - return the Asset's value. Otherwise return the Item's value. 'Published' + 'Published' has a different meaning depending on where it is used. If available in - the asset properties, it refers to the timestamps valid for the actual data linked - to the Asset Object. If it comes from the Item properties, it's referencing to - the timestamp valid for the metadata. + the asset properties, it refers to the timestamps valid for the actual data + linked to the Asset Object. If it comes from the Item properties, it's + referencing to the timestamp valid for the metadata. Returns: datetime """ - return self._timestamp_getter('published', asset) + return map_opt(str_to_datetime, self._get_property(PUBLISHED_PROP, str)) - def set_published(self, published, asset=None): - """Set an Item or asset published datetime - - If an Asset is supplied, sets the property on the Asset. - Otherwise sets the Item's value. - """ - self._timestamp_setter(published, 'published', asset) + @published.setter + def published(self, v: Optional[Datetime]) -> None: + self._set_property(PUBLISHED_PROP, map_opt(datetime_to_str, v)) @property - def expires(self): + def expires(self) -> Optional[Datetime]: """Get or sets a datetime objects that represent the date and time the corresponding data expires (is not valid any longer). + 'Unpublished' + has a different meaning depending on where it is used. If available in + the asset properties, it refers to the timestamps valid for the actual data + linked to the Asset Object. If it comes from the Item properties, it's + referencing to the timestamp valid for the metadata. + Returns: datetime """ - return self.get_expires() + return map_opt(str_to_datetime, self._get_property(EXPIRES_PROP, str)) @expires.setter - def expires(self, v): - self.set_expires(v) + def expires(self, v: Optional[Datetime]) -> None: + self._set_property(EXPIRES_PROP, map_opt(datetime_to_str, v)) - def get_expires(self, asset=None): - """Get an Item or Asset expires datetime + @property + def unpublished(self) -> Optional[Datetime]: + """Get or sets a datetime objects that represent + the Date and time the corresponding data was unpublished. - If an Asset is supplied and the expires property exists on the Asset, - return the Asset's value. Otherwise return the Item's value. 'Unpublished' + 'Unpublished' has a different meaning depending on where it is used. If available in - the asset properties, it refers to the timestamps valid for the actual data linked - to the Asset Object. If it comes from the Item properties, it's referencing to - the timestamp valid for the metadata. + the asset properties, it refers to the timestamps valid for the actual data + linked to the Asset Object. If it comes from the Item properties, it's + referencing to the timestamp valid for the metadata. Returns: datetime """ - return self._timestamp_getter('expires', asset) + return map_opt(str_to_datetime, self._get_property(UNPUBLISHED_PROP, str)) - def set_expires(self, expires, asset=None): - """Set an Item or asset expires datetime + @unpublished.setter + def unpublished(self, v: Optional[Datetime]) -> None: + self._set_property(UNPUBLISHED_PROP, map_opt(datetime_to_str, v)) - If an Asset is supplied, sets the property on the Asset. - Otherwise sets the Item's value. - """ - self._timestamp_setter(expires, 'expires', asset) + @classmethod + def get_schema_uri(cls) -> str: + return SCHEMA_URI + + @staticmethod + def ext(obj: T) -> "TimestampsExtension[T]": + if isinstance(obj, pystac.Item): + return cast(TimestampsExtension[T], ItemTimestampsExtension(obj)) + elif isinstance(obj, pystac.Asset): + return cast(TimestampsExtension[T], AssetTimestampsExtension(obj)) + else: + raise pystac.ExtensionTypeError( + f"File extension does not apply to type {type(obj)}" + ) - @property - def unpublished(self): - """Get or sets a datetime objects that represent - the Date and time the corresponding data was unpublished. - Returns: - datetime - """ - return self.get_unpublished() +class ItemTimestampsExtension(TimestampsExtension[pystac.Item]): + def __init__(self, item: pystac.Item): + self.item = item + self.properties = item.properties - @unpublished.setter - def unpublished(self, v): - self.set_unpublished(v) + def __repr__(self) -> str: + return "".format(self.item.id) - def get_unpublished(self, asset=None): - """Get an Item or Asset unpublished datetime - If an Asset is supplied and the unpublished property exists on the Asset, - return the Asset's value. Otherwise return the Item's value. 'Unpublished' - has a different meaning depending on where it is used. If available in - the asset properties, it refers to the timestamps valid for the actual data linked - to the Asset Object. If it comes from the Item properties, it's referencing to - the timestamp valid for the metadata. +class AssetTimestampsExtension(TimestampsExtension[pystac.Asset]): + def __init__(self, asset: pystac.Asset): + self.asset_href = asset.href + self.properties = asset.properties + if asset.owner and isinstance(asset.owner, pystac.Item): + self.additional_read_properties = [asset.owner.properties] - Returns: - datetime - """ - return self._timestamp_getter('unpublished', asset) + def __repr__(self) -> str: + return "".format(self.asset_href) - def set_unpublished(self, unpublished, asset=None): - """Set an Item or asset unpublished datetime - If an Asset is supplied, sets the property on the Asset. - Otherwise sets the Item's value. - """ - self._timestamp_setter(unpublished, 'unpublished', asset) +class TimestampsExtensionHooks(ExtensionHooks): + schema_uri: str = SCHEMA_URI + prev_extension_ids: Set[str] = set(["timestamps"]) + stac_object_types: Set[pystac.STACObjectType] = set([pystac.STACObjectType.ITEM]) -TIMESTAMPS_EXTENSION_DEFINITION = ExtensionDefinition(Extensions.TIMESTAMPS, - [ExtendedObject(Item, TimestampsItemExt)]) +TIMESTAMPS_EXTENSION_HOOKS = TimestampsExtensionHooks() diff --git a/pystac/extensions/version.py b/pystac/extensions/version.py index bdaeba698..d41133008 100644 --- a/pystac/extensions/version.py +++ b/pystac/extensions/version.py @@ -1,31 +1,41 @@ -"""Implement the version extension. +"""Implements the Version extension. https://github.com/stac-extensions/version - -Note that the version/schema.json does not know about the links. """ -from typing import List, Optional +from pystac.utils import get_required, map_opt +from typing import Generic, List, Optional, Set, TypeVar, Union, cast import pystac -from pystac import Extensions -from pystac.extensions import base +from pystac.extensions.base import ( + ExtensionManagementMixin, + PropertiesExtension, +) +from pystac.extensions.hooks import ExtensionHooks + +T = TypeVar("T", pystac.Collection, pystac.Item) + +SCHEMA_URI = "https://stac-extensions.github.io/version/v1.0.0/schema.json" # STAC fields - These are unusual for an extension in that they do not have # a prefix. e.g. nothing like "ver:" -VERSION: str = 'version' -DEPRECATED: str = 'deprecated' +VERSION: str = "version" +DEPRECATED: str = "deprecated" # Link "rel" attribute values. -LATEST: str = 'latest-version' -PREDECESSOR: str = 'predecessor-version' -SUCCESSOR: str = 'successor-version' +LATEST: str = "latest-version" +PREDECESSOR: str = "predecessor-version" +SUCCESSOR: str = "successor-version" # Media type for links. -MEDIA_TYPE: str = 'application/json' +MEDIA_TYPE: str = "application/json" -class VersionItemExt(base.ItemExtension): +class VersionExtension( + Generic[T], + PropertiesExtension, + ExtensionManagementMixin[Union[pystac.Collection, pystac.Item]], +): """VersionItemExt extends Item to add version and deprecated properties along with links to the latest, predecessor, and successor Items. @@ -39,17 +49,20 @@ class VersionItemExt(base.ItemExtension): Using VersionItemExt to directly wrap an item will add the 'version' extension ID to the item's stac_extensions. """ - item: pystac.Item - def __init__(self, an_item) -> None: - self.item = an_item + obj: pystac.STACObject - def apply(self, - version: str, - deprecated: Optional[bool] = None, - latest: Optional[pystac.Item] = None, - predecessor: Optional[pystac.Item] = None, - successor: Optional[pystac.Item] = None) -> None: + def __init__(self, obj: pystac.STACObject) -> None: + self.obj = obj + + def apply( + self, + version: str, + deprecated: Optional[bool] = None, + latest: Optional[T] = None, + predecessor: Optional[T] = None, + successor: Optional[T] = None, + ) -> None: """Applies version extension properties to the extended Item. Args: @@ -78,210 +91,110 @@ def version(self) -> str: Returns: str """ - return self.item.properties.get(VERSION) + return get_required(self._get_property(VERSION, str), self, VERSION) @version.setter def version(self, v: str) -> None: - self.item.properties[VERSION] = v + self._set_property(VERSION, v, pop_if_none=False) @property - def deprecated(self) -> bool: - """Get or sets is the item is deprecated. - - Returns: - bool - """ - return bool(self.item.properties.get(DEPRECATED)) + def deprecated(self) -> Optional[bool]: + """Get or sets is the item is deprecated.""" + return self._get_property(DEPRECATED, bool) @deprecated.setter - def deprecated(self, v: bool) -> None: - if not isinstance(v, bool): - raise pystac.STACError(DEPRECATED + ' must be a bool') - self.item.properties[DEPRECATED] = v + def deprecated(self, v: Optional[bool]) -> None: + self._set_property(DEPRECATED, v) @property - def latest(self) -> Optional[pystac.Item]: - """Get or sets the most recent item. - - Returns: - Item or None - """ - return next(self.item.get_stac_objects(LATEST), None) + def latest(self) -> Optional[T]: + """Get or sets the most recent version.""" + return map_opt( + lambda x: cast(T, x), next(iter(self.obj.get_stac_objects(LATEST)), None) + ) @latest.setter - def latest(self, source_item: pystac.Item) -> None: - self.item.clear_links(LATEST) - if source_item: - self.item.add_link(pystac.Link(LATEST, source_item, MEDIA_TYPE)) + def latest(self, item: Optional[T]) -> None: + self.obj.clear_links(LATEST) + if item is not None: + self.obj.add_link(pystac.Link(LATEST, item, MEDIA_TYPE)) @property - def predecessor(self) -> Optional[pystac.Item]: - """Get or sets the previous item. - - Returns: - Item or None - """ - return next(self.item.get_stac_objects(PREDECESSOR), None) + def predecessor(self) -> Optional[T]: + """Get or sets the previous item.""" + return map_opt( + lambda x: cast(T, x), + next(iter(self.obj.get_stac_objects(PREDECESSOR)), None), + ) @predecessor.setter - def predecessor(self, source_item: pystac.Item) -> None: - self.item.clear_links(PREDECESSOR) - if source_item: - self.item.add_link(pystac.Link(PREDECESSOR, source_item, MEDIA_TYPE)) + def predecessor(self, item: Optional[T]) -> None: + self.obj.clear_links(PREDECESSOR) + if item is not None: + self.obj.add_link(pystac.Link(PREDECESSOR, item, MEDIA_TYPE)) @property - def successor(self) -> Optional[pystac.Item]: - """Get or sets the next item. - - Returns: - Item or None - """ - return next(self.item.get_stac_objects(SUCCESSOR), None) + def successor(self) -> Optional[T]: + """Get or sets the next item.""" + return map_opt( + lambda x: cast(T, x), next(iter(self.obj.get_stac_objects(SUCCESSOR)), None) + ) @successor.setter - def successor(self, source_item: pystac.Item) -> None: - self.item.clear_links(SUCCESSOR) - if source_item: - self.item.add_link(pystac.Link(SUCCESSOR, source_item, MEDIA_TYPE)) - - @classmethod - def from_item(cls, an_item: pystac.Item): - return cls(an_item) + def successor(self, item: Optional[T]) -> None: + self.obj.clear_links(SUCCESSOR) + if item is not None: + self.obj.add_link(pystac.Link(SUCCESSOR, item, MEDIA_TYPE)) @classmethod - def _object_links(cls) -> List[str]: - return [LATEST, PREDECESSOR, SUCCESSOR] - - -class VersionCollectionExt(base.CollectionExtension): - """VersionCollectionExt extends Collection to add version and deprecated properties - along with links to the latest, predecessor, and successor Collections. - - Args: - a_collection (Collection): The collection to be extended. - - Attributes: - collection (Collection): The collection that is being extended. - - Note: - Using VersionCollectionExt to directly wrap a collection will add the - 'version' extension ID to the collections's stac_extensions. - """ - collection: pystac.Collection - - def __init__(self, a_collection) -> None: - self.collection = a_collection - - @property - def version(self) -> str: - """Get or sets a version string of the collection. - - Returns: - str - """ - return self.collection.extra_fields.get(VERSION) - - @version.setter - def version(self, v) -> None: - self.collection.extra_fields[VERSION] = v + def get_schema_uri(cls) -> str: + return SCHEMA_URI - @property - def deprecated(self) -> bool: - """Get or sets is the collection is deprecated. + @staticmethod + def ext(obj: T) -> "VersionExtension[T]": + if isinstance(obj, pystac.Collection): + return cast(VersionExtension[T], CollectionVersionExtension(obj)) + if isinstance(obj, pystac.Item): + return cast(VersionExtension[T], ItemVersionExtension(obj)) + else: + raise pystac.ExtensionTypeError( + f"File extension does not apply to type {type(obj)}" + ) - Returns: - bool - """ - return bool(self.collection.extra_fields.get(DEPRECATED)) - @deprecated.setter - def deprecated(self, v) -> None: - if not isinstance(v, bool): - raise pystac.STACError(DEPRECATED + ' must be a bool') - self.collection.extra_fields[DEPRECATED] = v +class CollectionVersionExtension(VersionExtension[pystac.Collection]): + def __init__(self, collection: pystac.Collection): + self.collection = collection + self.properties = collection.extra_fields + self.links = collection.links + super().__init__(self.collection) - @property - def latest(self) -> Optional[pystac.Collection]: - """Get or sets the most recent collection. + def __repr__(self) -> str: + return "".format(self.collection.id) - Returns: - Collection or None - """ - return next(self.collection.get_stac_objects(LATEST), None) - @latest.setter - def latest(self, source_collection) -> None: - self.collection.clear_links(LATEST) - if source_collection: - self.collection.add_link(pystac.Link(LATEST, source_collection, MEDIA_TYPE)) +class ItemVersionExtension(VersionExtension[pystac.Item]): + def __init__(self, item: pystac.Item): + self.item = item + self.properties = item.properties + self.links = item.links + super().__init__(self.item) - @property - def predecessor(self) -> Optional[pystac.Collection]: - """Get or sets the previous collection. + def __repr__(self) -> str: + return "".format(self.item.id) - Returns: - Collection or None - """ - return next(self.collection.get_stac_objects(PREDECESSOR), None) - - @predecessor.setter - def predecessor(self, source_collection) -> None: - self.collection.clear_links(PREDECESSOR) - if source_collection: - self.collection.add_link(pystac.Link(PREDECESSOR, source_collection, MEDIA_TYPE)) - - @property - def successor(self) -> Optional[pystac.Collection]: - """Get or sets the next collection. - Returns: - Collection or None - """ - return next(self.collection.get_stac_objects(SUCCESSOR), None) - - @successor.setter - def successor(self, source_collection) -> None: - self.collection.clear_links(SUCCESSOR) - if source_collection: - self.collection.add_link(pystac.Link(SUCCESSOR, source_collection, MEDIA_TYPE)) +class VersionExtensionHooks(ExtensionHooks): + schema_uri = SCHEMA_URI + prev_extension_ids: Set[str] = set(["version"]) + stac_object_types: Set[pystac.STACObjectType] = set( + [pystac.STACObjectType.COLLECTION, pystac.STACObjectType.ITEM] + ) - @classmethod - def from_collection(cls, a_collection: pystac.Collection): - return cls(a_collection) - - @classmethod - def _object_links(cls) -> List[str]: - return [LATEST, PREDECESSOR, SUCCESSOR] - - def apply(self, - version: str, - deprecated: Optional[str] = None, - latest: Optional[pystac.Collection] = None, - predecessor=None, - successor=None) -> None: - """Applies version extension properties to the extended Collection. - - Args: - version (str): The version string for the collection. - deprecated (bool): Optional flag set to True if an Collection is - deprecated with the potential to be removed. Defaults to false - if not present. - latest (Collection): Collection with the latest (e.g., current) version. - predecessor (Collection): Collection with the previous version. - successor (Collection): Collection with the next most recent version. - """ - self.version = version - if deprecated is not None: - self.deprecated = deprecated - if latest: - self.latest = latest - if predecessor: - self.predecessor = predecessor - if successor: - self.successor = successor + def get_object_links(self, so: pystac.STACObject) -> Optional[List[str]]: + if isinstance(so, pystac.Collection) or isinstance(so, pystac.Item): + return [LATEST, PREDECESSOR, SUCCESSOR] + return None -VERSION_EXTENSION_DEFINITION = base.ExtensionDefinition(Extensions.VERSION, [ - base.ExtendedObject(pystac.Item, VersionItemExt), - base.ExtendedObject(pystac.Collection, VersionCollectionExt) -]) +VERSION_EXTENSION_HOOKS: ExtensionHooks = VersionExtensionHooks() diff --git a/pystac/extensions/view.py b/pystac/extensions/view.py index 57be7f247..f164c04c1 100644 --- a/pystac/extensions/view.py +++ b/pystac/extensions/view.py @@ -2,18 +2,35 @@ https://github.com/stac-extensions/view """ + +from typing import Generic, Optional, Set, TypeVar, cast + import pystac -from pystac import Extensions -from pystac.item import Item -from pystac.extensions.base import (ItemExtension, ExtensionDefinition, ExtendedObject) -from typing import Optional +from pystac.extensions.base import ( + ExtensionManagementMixin, + PropertiesExtension, +) +from pystac.extensions.hooks import ExtensionHooks + +T = TypeVar("T", pystac.Item, pystac.Asset) + +SCHEMA_URI = "https://stac-extensions.github.io/view/v1.0.0/schema.json" + +OFF_NADIR_PROP = "view:off_nadir" +INCIDENCE_ANGLE_PROP = "view:incidence_angle" +AZIMUTH_PROP = "view:azimuth" +SUN_AZIMUTH_PROP = "view:sun_azimuth" +SUN_ELEVATION_PROP = "view:sun_elevation" -class ViewItemExt(ItemExtension): +class ViewExtension( + Generic[T], PropertiesExtension, ExtensionManagementMixin[pystac.Item] +): """ViewItemExt is the extension of the Item in the View Geometry Extension. + View Geometry adds metadata related to angles of sensors and other radiance angles - that affect the view of resulting data. It will often be combined with other extensions that - describe the actual data, such as the eo, sat or sar extensions. + that affect the view of resulting data. It will often be combined with other + extensions that describe the actual data, such as the eo, sat or sar extensions. Args: item (Item): The item to be extended. @@ -25,90 +42,56 @@ class ViewItemExt(ItemExtension): Using ViewItemExt to directly wrap an item will add the 'view' extension ID to the item's stac_extensions. """ - def __init__(self, item): - if item.stac_extensions is None: - item.stac_extensions = [Extensions.VIEW] - elif Extensions.VIEW not in item.stac_extensions: - item.stac_extensions.append(Extensions.VIEW) - - self.item = item - def apply(self, - off_nadir: Optional[float] = None, - incidence_angle: Optional[float] = None, - azimuth: Optional[float] = None, - sun_azimuth: Optional[float] = None, - sun_elevation: Optional[float] = None): + def apply( + self, + off_nadir: Optional[float] = None, + incidence_angle: Optional[float] = None, + azimuth: Optional[float] = None, + sun_azimuth: Optional[float] = None, + sun_elevation: Optional[float] = None, + ) -> None: """Applies View Geometry extension properties to the extended Item. Args: off_nadir (float): The angle from the sensor between nadir (straight down) and the scene center. Measured in degrees (0-90). - incidence_angle (float): The incidence angle is the angle between the vertical (normal) - to the intercepting surface and the line of sight back to the satellite at - the scene center. Measured in degrees (0-90). - azimuth (float): Viewing azimuth angle. The angle measured from the sub-satellite - point (point on the ground below the platform) between the scene center and true - north. Measured clockwise from north in degrees (0-360). - sun_azimuth (float): Sun azimuth angle. From the scene center point on the ground, this - is the angle between truth north and the sun. Measured clockwise in degrees (0-360). - sun_elevation (float): Sun elevation angle. The angle from the tangent of the scene - center point to the sun. Measured from the horizon in degrees (0-90). - """ - if (off_nadir is None and incidence_angle is None and azimuth is None - and sun_azimuth is None and sun_elevation is None): - raise pystac.STACError( - 'Must provide at least one of: off_nadir, incidence_angle, azimuth, sun_azimuth, sun_elevation' # noqa: E501 - ) - if off_nadir: - self.off_nadir = off_nadir - if incidence_angle: - self.incidence_angle = incidence_angle - if azimuth: - self.azimuth = azimuth - if sun_azimuth: - self.sun_azimuth = sun_azimuth - if sun_elevation: - self.sun_elevation = sun_elevation + incidence_angle (float): The incidence angle is the angle between the + vertical (normal) to the intercepting surface and the line of sight + back to the satellite at the scene center. Measured in degrees (0-90). + azimuth (float): Viewing azimuth angle. The angle measured from the + sub-satellite point (point on the ground below the platform) between + the scene center and true north. Measured clockwise from north in + degrees (0-360). + sun_azimuth (float): Sun azimuth angle. From the scene center point on the + ground, this is the angle between truth north and the sun. Measured + clockwise in degrees (0-360). + sun_elevation (float): Sun elevation angle. The angle from the tangent of + the scene center point to the sun. Measured from the horizon in + degrees (0-90). + """ + self.off_nadir = off_nadir + self.incidence_angle = incidence_angle + self.azimuth = azimuth + self.sun_azimuth = sun_azimuth + self.sun_elevation = sun_elevation @property - def off_nadir(self): + def off_nadir(self) -> Optional[float]: """Get or sets the angle from the sensor between nadir (straight down) and the scene center. Measured in degrees (0-90). Returns: float """ - return self.get_off_nadir() + return self._get_property(OFF_NADIR_PROP, float) @off_nadir.setter - def off_nadir(self, v): - self.set_off_nadir(v) - - def get_off_nadir(self, asset=None): - """Gets an Item or an Asset off_nadir. - - If an Asset is supplied and the Item property exists on the Asset, - returns the Asset's value. Otherwise returns the Item's value - - Returns: - float - """ - if asset is None or 'view:off_nadir' not in asset.properties: - return self.item.properties.get('view:off_nadir') - else: - return asset.properties.get('view:off_nadir') - - def set_off_nadir(self, off_nadir, asset=None): - """Set an Item or an Asset off_nadir. - - If an Asset is supplied, sets the property on the Asset. - Otherwise sets the Item's value. - """ - self._set_property('view:off_nadir', off_nadir, asset) + def off_nadir(self, v: Optional[float]) -> None: + self._set_property(OFF_NADIR_PROP, v) @property - def incidence_angle(self): + def incidence_angle(self) -> Optional[float]: """Get or sets the incidence angle is the angle between the vertical (normal) to the intercepting surface and the line of sight back to the satellite at the scene center. Measured in degrees (0-90). @@ -116,151 +99,100 @@ def incidence_angle(self): Returns: float """ - return self.get_incidence_angle() + return self._get_property(INCIDENCE_ANGLE_PROP, float) @incidence_angle.setter - def incidence_angle(self, v): - self.set_incidence_angle(v) - - def get_incidence_angle(self, asset=None): - """Gets an Item or an Asset incidence_angle. - - If an Asset is supplied and the Item property exists on the Asset, - returns the Asset's value. Otherwise returns the Item's value - - Returns: - float - """ - if asset is None or 'view:incidence_angle' not in asset.properties: - return self.item.properties.get('view:incidence_angle') - else: - return asset.properties.get('view:incidence_angle') - - def set_incidence_angle(self, incidence_angle, asset=None): - """Set an Item or an Asset incidence_angle. - - If an Asset is supplied, sets the property on the Asset. - Otherwise sets the Item's value. - """ - self._set_property('view:incidence_angle', incidence_angle, asset) + def incidence_angle(self, v: Optional[float]) -> None: + self._set_property(INCIDENCE_ANGLE_PROP, v) @property - def azimuth(self): - """Get or sets the viewing azimuth angle. The angle measured from the sub-satellite + def azimuth(self) -> Optional[float]: + """Get or sets the viewing azimuth angle. + + The angle measured from the sub-satellite point (point on the ground below the platform) between the scene center and true north. Measured clockwise from north in degrees (0-360). Returns: float """ - return self.get_azimuth() + return self._get_property(AZIMUTH_PROP, float) @azimuth.setter - def azimuth(self, v): - self.set_azimuth(v) - - def get_azimuth(self, asset=None): - """Gets an Item or an Asset azimuth. - - If an Asset is supplied and the Item property exists on the Asset, - returns the Asset's value. Otherwise returns the Item's value - - Returns: - float - """ - if asset is None or 'view:azimuth' not in asset.properties: - return self.item.properties.get('view:azimuth') - else: - return asset.properties.get('view:azimuth') - - def set_azimuth(self, azimuth, asset=None): - """Set an Item or an Asset azimuth. - - If an Asset is supplied, sets the property on the Asset. - Otherwise sets the Item's value. - """ - self._set_property('view:azimuth', azimuth, asset) + def azimuth(self, v: Optional[float]) -> None: + self._set_property(AZIMUTH_PROP, v) @property - def sun_azimuth(self): - """Get or sets the sun azimuth angle. From the scene center point on the ground, this - is the angle between truth north and the sun. Measured clockwise in degrees (0-360). + def sun_azimuth(self) -> Optional[float]: + """Get or sets the sun azimuth angle. - Returns: - float - """ - return self.get_sun_azimuth() - - @sun_azimuth.setter - def sun_azimuth(self, v): - self.set_sun_azimuth(v) - - def get_sun_azimuth(self, asset=None): - """Gets an Item or an Asset sun_azimuth. - - If an Asset is supplied and the Item property exists on the Asset, - returns the Asset's value. Otherwise returns the Item's value + From the scene center point on the ground, this + is the angle between truth north and the sun. Measured clockwise in + degrees (0-360). Returns: float """ - if asset is None or 'view:sun_azimuth' not in asset.properties: - return self.item.properties.get('view:sun_azimuth') - else: - return asset.properties.get('view:sun_azimuth') + return self._get_property(SUN_AZIMUTH_PROP, float) - def set_sun_azimuth(self, sun_azimuth, asset=None): - """Set an Item or an Asset sun_azimuth. - - If an Asset is supplied, sets the property on the Asset. - Otherwise sets the Item's value. - """ - self._set_property('view:sun_azimuth', sun_azimuth, asset) + @sun_azimuth.setter + def sun_azimuth(self, v: Optional[float]) -> None: + self._set_property(SUN_AZIMUTH_PROP, v) @property - def sun_elevation(self): + def sun_elevation(self) -> Optional[float]: """Get or sets the sun elevation angle. The angle from the tangent of the scene center point to the sun. Measured from the horizon in degrees (0-90). Returns: float """ - return self.get_sun_elevation() + return self._get_property(SUN_ELEVATION_PROP, float) @sun_elevation.setter - def sun_elevation(self, v): - self.set_sun_elevation(v) + def sun_elevation(self, v: Optional[float]) -> None: + self._set_property(SUN_ELEVATION_PROP, v) - def get_sun_elevation(self, asset=None): - """Gets an Item or an Asset sun_elevation. + @classmethod + def get_schema_uri(cls) -> str: + return SCHEMA_URI + + @staticmethod + def ext(obj: T) -> "ViewExtension[T]": + if isinstance(obj, pystac.Item): + return cast(ViewExtension[T], ItemViewExtension(obj)) + elif isinstance(obj, pystac.Asset): + return cast(ViewExtension[T], AssetViewExtension(obj)) + else: + raise pystac.ExtensionTypeError( + f"View extension does not apply to type {type(obj)}" + ) - If an Asset is supplied and the Item property exists on the Asset, - returns the Asset's value. Otherwise returns the Item's value - Returns: - float - """ - if asset is None or 'view:sun_elevation' not in asset.properties: - return self.item.properties.get('view:sun_elevation') - else: - return asset.properties.get('view:sun_elevation') +class ItemViewExtension(ViewExtension[pystac.Item]): + def __init__(self, item: pystac.Item): + self.item = item + self.properties = item.properties - def set_sun_elevation(self, sun_elevation, asset=None): - """Set an Item or an Asset sun_elevation. + def __repr__(self) -> str: + return "".format(self.item.id) - If an Asset is supplied, sets the property on the Asset. - Otherwise sets the Item's value. - """ - self._set_property('view:sun_elevation', sun_elevation, asset) - @classmethod - def _object_links(cls): - return [] +class AssetViewExtension(ViewExtension[pystac.Asset]): + def __init__(self, asset: pystac.Asset): + self.asset_href = asset.href + self.properties = asset.properties + if asset.owner and isinstance(asset.owner, pystac.Item): + self.additional_read_properties = [asset.owner.properties] - @classmethod - def from_item(cls, item): - return cls(item) + def __repr__(self) -> str: + return "".format(self.asset_href) + + +class ViewExtensionHooks(ExtensionHooks): + schema_uri = SCHEMA_URI + prev_extension_ids: Set[str] = set(["view"]) + stac_object_types: Set[pystac.STACObjectType] = set([pystac.STACObjectType.ITEM]) -VIEW_EXTENSION_DEFINITION = ExtensionDefinition(Extensions.VIEW, - [ExtendedObject(Item, ViewItemExt)]) +VIEW_EXTENSION_HOOKS = ViewExtensionHooks() diff --git a/pystac/item.py b/pystac/item.py index 3de409b1b..2b319d028 100644 --- a/pystac/item.py +++ b/pystac/item.py @@ -1,515 +1,25 @@ from copy import copy, deepcopy +from datetime import datetime as Datetime +from pystac.catalog import Catalog +from typing import Any, Dict, List, Optional, Union, cast import dateutil.parser import pystac -from pystac import (STACError, STACObjectType) +from pystac import STACError, STACObjectType +from pystac.asset import Asset from pystac.link import Link from pystac.stac_object import STACObject -from pystac.utils import (is_absolute_href, make_absolute_href, make_relative_href, datetime_to_str, - str_to_datetime) +from pystac.utils import ( + is_absolute_href, + make_absolute_href, + make_relative_href, + datetime_to_str, + str_to_datetime, +) from pystac.collection import Collection, Provider -class Item(STACObject): - """An Item is the core granular entity in a STAC, containing the core metadata - that enables any client to search or crawl online catalogs of spatial 'assets' - - satellite imagery, derived data, DEM's, etc. - - Args: - id (str): Provider identifier. Must be unique within the STAC. - geometry (dict): Defines the full footprint of the asset represented by this item, - formatted according to `RFC 7946, section 3.1 (GeoJSON) - `_. - bbox (List[float] or None): Bounding Box of the asset represented by this item using - either 2D or 3D geometries. The length of the array must be 2*n where n is the - number of dimensions. Could also be None in the case of a null geometry. - datetime (datetime or None): Datetime associated with this item. If None, - a start_datetime and end_datetime must be supplied in the properties. - properties (dict): A dictionary of additional metadata for the item. - stac_extensions (List[str]): Optional list of extensions the Item implements. - href (str or None): Optional HREF for this item, which be set as the item's - self link's HREF. - collection (Collection or str): The Collection or Collection ID that this item - belongs to. - extra_fields (dict or None): Extra fields that are part of the top-level JSON properties - of the Item. - - Attributes: - id (str): Provider identifier. Unique within the STAC. - geometry (dict): Defines the full footprint of the asset represented by this item, - formatted according to `RFC 7946, section 3.1 (GeoJSON) - `_. - bbox (List[float] or None): Bounding Box of the asset represented by this item using - either 2D or 3D geometries. The length of the array is 2*n where n is the - number of dimensions. Could also be None in the case of a null geometry. - datetime (datetime or None): Datetime associated with this item. If None, - the start_datetime and end_datetime in the common_metadata - will supply the datetime range of the Item. - properties (dict): A dictionary of additional metadata for the item. - stac_extensions (List[str] or None): Optional list of extensions the Item implements. - collection (Collection or None): Collection that this item is a part of. - links (List[Link]): A list of :class:`~pystac.Link` objects representing - all links associated with this STACObject. - assets (Dict[str, Asset]): Dictionary of asset objects that can be downloaded, - each with a unique key. - collection_id (str or None): The Collection ID that this item belongs to, if any. - extra_fields (dict or None): Extra fields that are part of the top-level JSON properties - of the Item. - """ - - STAC_OBJECT_TYPE = STACObjectType.ITEM - - def __init__(self, - id, - geometry, - bbox, - datetime, - properties, - stac_extensions=None, - href=None, - collection=None, - extra_fields=None): - super().__init__(stac_extensions) - - self.id = id - self.geometry = geometry - self.bbox = bbox - self.datetime = datetime - self.properties = properties - if extra_fields is None: - self.extra_fields = {} - else: - self.extra_fields = extra_fields - - self.assets = {} - - if datetime is None: - if 'start_datetime' not in properties or \ - 'end_datetime' not in properties: - raise STACError('Invalid Item: If datetime is None, ' - 'a start_datetime and end_datetime ' - 'must be supplied in ' - 'the properties.') - - if href is not None: - self.set_self_href(href) - - if collection is not None: - if isinstance(collection, Collection): - self.set_collection(collection) - else: - self.collection_id = collection - else: - self.collection_id = None - - def __repr__(self): - return ''.format(self.id) - - def set_self_href(self, href): - """Sets the absolute HREF that is represented by the ``rel == 'self'`` - :class:`~pystac.Link`. - - Changing the self HREF of the item will ensure that all asset HREFs - remain valid. If asset HREFs are relative, the HREFs will change - to point to the same location based on the new item self HREF, - either by making them relative to the new location or making them - absolute links if the new location does not share the same protocol - as the old location. - - Args: - href (str): The absolute HREF of this object. If the given HREF - is not absolute, it will be transformed to an absolute - HREF based on the current working directory. If this is None - the call will clear the self HREF link. - """ - prev_href = self.get_self_href() - super().set_self_href(href) - new_href = self.get_self_href() # May have been made absolute. - - if prev_href is not None and new_href is not None: - # Make sure relative asset links remain valid. - for asset in self.assets.values(): - asset_href = asset.href - if not is_absolute_href(asset_href): - abs_href = make_absolute_href(asset_href, prev_href) - new_relative_href = make_relative_href(abs_href, new_href) - asset.href = new_relative_href - - def get_datetime(self, asset=None): - """Gets an Item or an Asset datetime. - - If an Asset is supplied and the Item property exists on the Asset, - returns the Asset's value. Otherwise returns the Item's value. - - Returns: - datetime or None - """ - if asset is None or 'datetime' not in asset.properties: - return self.datetime - else: - return str_to_datetime(asset.properties.get('datetime')) - - def set_datetime(self, datetime, asset=None): - """Set an Item or an Asset datetime. - - If an Asset is supplied, sets the property on the Asset. - Otherwise sets the Item's value. - """ - if asset is None: - self.datetime = datetime - else: - asset.properties['datetime'] = datetime_to_str(datetime) - - def get_assets(self): - """Get this item's assets. - - Returns: - Dict[str, Asset]: A copy of the dictionary of this item's assets. - """ - return dict(self.assets.items()) - - def add_asset(self, key, asset): - """Adds an Asset to this item. - - Args: - key (str): The unique key of this asset. - asset (Asset): The Asset to add. - """ - asset.set_owner(self) - self.assets[key] = asset - return self - - def make_asset_hrefs_relative(self): - """Modify each asset's HREF to be relative to this item's self HREF. - - Returns: - Item: self - """ - - self_href = None - for asset in self.assets.values(): - href = asset.href - if is_absolute_href(href): - if self_href is None: - self_href = self.get_self_href() - if self_href is None: - raise STACError('Cannot make asset HREFs relative ' - 'if no self_href is set.') - asset.href = make_relative_href(asset.href, self_href) - return self - - def make_asset_hrefs_absolute(self): - """Modify each asset's HREF to be absolute. - - Any asset HREFs that are relative will be modified to absolute based on this - item's self HREF. - - Returns: - Item: self - """ - self_href = None - for asset in self.assets.values(): - href = asset.href - if not is_absolute_href(href): - if self_href is None: - self_href = self.get_self_href() - if self_href is None: - raise STACError('Cannot make relative asset HREFs absolute ' - 'if no self_href is set.') - asset.href = make_absolute_href(asset.href, self_href) - - return self - - def set_collection(self, collection): - """Set the collection of this item. - - This method will replace any existing Collection link and attribute for - this item. - - Args: - collection (Collection or None): The collection to set as this - item's collection. If None, will clear the collection. - - Returns: - Item: self - """ - self.remove_links('collection') - self.collection_id = None - if collection is not None: - self.add_link(Link.collection(collection)) - self.collection_id = collection.id - - return self - - def get_collection(self): - """Gets the collection of this item, if one exists. - - Returns: - Collection or None: If this item belongs to a collection, returns - a reference to the collection. Otherwise returns None. - """ - collection_link = self.get_single_link('collection') - if collection_link is None: - return None - else: - return collection_link.resolve_stac_object().target - - def to_dict(self, include_self_link=True): - links = self.links - if not include_self_link: - links = filter(lambda x: x.rel != 'self', links) - - assets = dict(map(lambda x: (x[0], x[1].to_dict()), self.assets.items())) - - if self.datetime is not None: - self.properties['datetime'] = datetime_to_str(self.datetime) - else: - self.properties['datetime'] = None - - d = { - 'type': 'Feature', - 'stac_version': pystac.get_stac_version(), - 'id': self.id, - 'properties': self.properties, - 'geometry': self.geometry, - 'links': [link.to_dict() for link in links], - 'assets': assets - } - - if self.bbox is not None: - d['bbox'] = self.bbox - - if self.stac_extensions is not None: - d['stac_extensions'] = self.stac_extensions - - if self.collection_id: - d['collection'] = self.collection_id - - for key in self.extra_fields: - d[key] = self.extra_fields[key] - - return d - - def clone(self): - clone = Item(id=self.id, - geometry=deepcopy(self.geometry), - bbox=copy(self.bbox), - datetime=copy(self.datetime), - properties=deepcopy(self.properties), - stac_extensions=deepcopy(self.stac_extensions), - collection=self.collection_id) - for link in self.links: - clone.add_link(link.clone()) - - for k, asset in self.assets.items(): - clone.add_asset(k, asset.clone()) - - return clone - - def _object_links(self): - return ['collection'] + (pystac.STAC_EXTENSIONS.get_extended_object_links(self)) - - @classmethod - def from_dict(cls, d, href=None, root=None): - d = deepcopy(d) - id = d.pop('id') - geometry = d.pop('geometry') - properties = d.pop('properties') - bbox = d.pop('bbox', None) - stac_extensions = d.get('stac_extensions') - collection_id = d.pop('collection', None) - - datetime = properties.get('datetime') - if datetime is not None: - datetime = dateutil.parser.parse(datetime) - links = d.pop('links') - assets = d.pop('assets') - - d.pop('type') - d.pop('stac_version') - - item = Item(id=id, - geometry=geometry, - bbox=bbox, - datetime=datetime, - properties=properties, - stac_extensions=stac_extensions, - collection=collection_id, - extra_fields=d) - - has_self_link = False - for link in links: - has_self_link |= link['rel'] == 'self' - item.add_link(Link.from_dict(link)) - - if not has_self_link and href is not None: - item.add_link(Link.self_href(href)) - - for k, v in assets.items(): - asset = Asset.from_dict(v) - asset.set_owner(item) - item.assets[k] = asset - - return item - - @property - def common_metadata(self): - """Access the item's common metadat fields as a CommonMetadata object - - Returns: - CommonMetada: contains all common metadata fields in the items properties - """ - return CommonMetadata(self.properties) - - -class Asset: - """An object that contains a link to data associated with the Item that can be - downloaded or streamed. - - Args: - href (str): Link to the asset object. Relative and absolute links are both allowed. - title (str): Optional displayed title for clients and users. - description (str): A description of the Asset providing additional details, such as - how it was processed or created. CommonMark 0.29 syntax MAY be used for rich - text representation. - media_type (str): Optional description of the media type. Registered Media Types - are preferred. See :class:`~pystac.MediaType` for common media types. - roles ([str]): Optional, Semantic roles (i.e. thumbnail, overview, data, metadata) - of the asset. - properties (dict): Optional, additional properties for this asset. This is used by - extensions as a way to serialize and deserialize properties on asset - object JSON. - - Attributes: - href (str): Link to the asset object. Relative and absolute links are both allowed. - title (str): Optional displayed title for clients and users. - description (str): A description of the Asset providing additional details, such as - how it was processed or created. CommonMark 0.29 syntax MAY be used for rich - text representation. - media_type (str): Optional description of the media type. Registered Media Types - are preferred. See :class:`~pystac.MediaType` for common media types. - properties (dict): Optional, additional properties for this asset. This is used by - extensions as a way to serialize and deserialize properties on asset - object JSON. - owner (Item or None): The Item this asset belongs to. - """ - def __init__(self, - href, - title=None, - description=None, - media_type=None, - roles=None, - properties=None): - self.href = href - self.title = title - self.description = description - self.media_type = media_type - self.roles = roles - - if properties is not None: - self.properties = properties - else: - self.properties = {} - - # The Item which owns this Asset. - self.owner = None - - def set_owner(self, item): - """Sets the owning item of this Asset. - - The owning item will be used to resolve relative HREFs of this asset. - - Args: - item (Item): The Item that owns this asset. - """ - self.owner = item - - def get_absolute_href(self): - """Gets the absolute href for this asset, if possible. - - If this Asset has no associated Item, this will return whatever the - href is (as it cannot determine the absolute path, if the asset - href is relative). - - Returns: - str: The absolute HREF of this asset, or a relative HREF is an abslolute HREF - cannot be determined. - """ - if not is_absolute_href(self.href): - if self.owner is not None: - return make_absolute_href(self.href, self.owner.get_self_href()) - - return self.href - - def to_dict(self): - """Generate a dictionary representing the JSON of this Asset. - - Returns: - dict: A serializion of the Asset that can be written out as JSON. - """ - - d = {'href': self.href} - - if self.media_type is not None: - d['type'] = self.media_type - - if self.title is not None: - d['title'] = self.title - - if self.description is not None: - d['description'] = self.description - - if self.properties is not None and len(self.properties) > 0: - for k, v in self.properties.items(): - d[k] = v - - if self.roles is not None: - d['roles'] = self.roles - - return d - - def clone(self): - """Clones this asset. - - Returns: - Asset: The clone of this asset. - """ - return Asset(href=self.href, - title=self.title, - description=self.description, - media_type=self.media_type, - roles=self.roles, - properties=self.properties) - - def __repr__(self): - return ''.format(self.href) - - @staticmethod - def from_dict(d): - """Constructs an Asset from a dict. - - Returns: - Asset: The Asset deserialized from the JSON dict. - """ - d = copy(d) - href = d.pop('href') - media_type = d.pop('type', None) - title = d.pop('title', None) - description = d.pop('description', None) - roles = d.pop('roles', None) - properties = None - if any(d): - properties = d - - return Asset(href=href, - media_type=media_type, - title=title, - description=description, - roles=roles, - properties=properties) - - class CommonMetadata: """Object containing fields that are not included in core item schema but are still commonly used. All attributes are defined within the properties of @@ -518,42 +28,41 @@ class CommonMetadata: Args: properties (dict): Dictionary of attributes that is the Item's properties """ - def __init__(self, properties): + + def __init__(self, properties: Dict[str, Any]): self.properties = properties # Basics @property - def title(self): + def title(self) -> Optional[str]: """Get or set the item's title Returns: str: Human readable title describing the item """ - return self.properties.get('title') + return self.properties.get("title") @title.setter - def title(self, v): - self.properties['title'] = v + def title(self, v: Optional[str]) -> None: + self.properties["title"] = v @property - def description(self): + def description(self) -> Optional[str]: """Get or set the item's description Returns: str: Detailed description of the item """ - return self.properties.get('description') + return self.properties.get("description") @description.setter - def description(self, v): - self.properties['description'] = v + def description(self, v: Optional[str]) -> None: + self.properties["description"] = v # Date and Time Range @property - def start_datetime(self): - """Get or set the item's start_datetime. All datetime attributes have - setters that can take either a string or a datetime, but always stores - the attribute as a string + def start_datetime(self) -> Optional[Datetime]: + """Get or set the item's start_datetime. Returns: datetime: Start date and time for the item @@ -561,10 +70,10 @@ def start_datetime(self): return self.get_start_datetime() @start_datetime.setter - def start_datetime(self, v): + def start_datetime(self, v: Optional[Datetime]) -> None: self.set_start_datetime(v) - def get_start_datetime(self, asset=None): + def get_start_datetime(self, asset: Optional[Asset] = None) -> Optional[Datetime]: """Gets an Item or an Asset start_datetime. If an Asset is supplied and the Item property exists on the Asset, @@ -573,29 +82,35 @@ def get_start_datetime(self, asset=None): Returns: datetime """ - if asset is None or 'start_datetime' not in asset.properties: - start_datetime = self.properties.get('start_datetime') + if asset is None or "start_datetime" not in asset.properties: + start_datetime = self.properties.get("start_datetime") else: - start_datetime = asset.properties.get('start_datetime') + start_datetime = asset.properties.get("start_datetime") if start_datetime: start_datetime = str_to_datetime(start_datetime) return start_datetime - def set_start_datetime(self, start_datetime, asset=None): + def set_start_datetime( + self, start_datetime: Optional[Datetime], asset: Optional[Asset] = None + ) -> None: """Set an Item or an Asset start_datetime. If an Asset is supplied, sets the property on the Asset. Otherwise sets the Item's value. """ if asset is None: - self.properties['start_datetime'] = datetime_to_str(start_datetime) + self.properties["start_datetime"] = ( + None if start_datetime is None else datetime_to_str(start_datetime) + ) else: - asset.properties['start_datetime'] = datetime_to_str(start_datetime) + asset.properties["start_datetime"] = ( + None if start_datetime is None else datetime_to_str(start_datetime) + ) @property - def end_datetime(self): + def end_datetime(self) -> Optional[Datetime]: """Get or set the item's end_datetime. All datetime attributes have setters that can take either a string or a datetime, but always stores the attribute as a string @@ -606,10 +121,10 @@ def end_datetime(self): return self.get_end_datetime() @end_datetime.setter - def end_datetime(self, v): + def end_datetime(self, v: Optional[Datetime]) -> None: self.set_end_datetime(v) - def get_end_datetime(self, asset=None): + def get_end_datetime(self, asset: Optional[Asset] = None) -> Optional[Datetime]: """Gets an Item or an Asset end_datetime. If an Asset is supplied and the Item property exists on the Asset, @@ -618,30 +133,36 @@ def get_end_datetime(self, asset=None): Returns: datetime """ - if asset is None or 'end_datetime' not in asset.properties: - end_datetime = self.properties.get('end_datetime') + if asset is None or "end_datetime" not in asset.properties: + end_datetime = self.properties.get("end_datetime") else: - end_datetime = asset.properties.get('end_datetime') + end_datetime = asset.properties.get("end_datetime") if end_datetime: end_datetime = str_to_datetime(end_datetime) return end_datetime - def set_end_datetime(self, end_datetime, asset=None): + def set_end_datetime( + self, end_datetime: Optional[Datetime], asset: Optional[Asset] = None + ) -> None: """Set an Item or an Asset end_datetime. If an Asset is supplied, sets the property on the Asset. Otherwise sets the Item's value. """ if asset is None: - self.properties['end_datetime'] = datetime_to_str(end_datetime) + self.properties["end_datetime"] = ( + None if end_datetime is None else datetime_to_str(end_datetime) + ) else: - asset.properties['end_datetime'] = datetime_to_str(end_datetime) + asset.properties["end_datetime"] = ( + None if end_datetime is None else datetime_to_str(end_datetime) + ) # License @property - def license(self): + def license(self) -> Optional[str]: """Get or set the current license Returns: @@ -650,10 +171,10 @@ def license(self): return self.get_license() @license.setter - def license(self, v): + def license(self, v: Optional[str]) -> None: self.set_license(v) - def get_license(self, asset=None): + def get_license(self, asset: Optional[Asset] = None) -> Optional[str]: """Gets an Item or an Asset license. If an Asset is supplied and the Item property exists on the Asset, @@ -662,25 +183,27 @@ def get_license(self, asset=None): Returns: str """ - if asset is None or 'license' not in asset.properties: - return self.properties.get('license') + if asset is None or "license" not in asset.properties: + return self.properties.get("license") else: - return asset.properties.get('license') + return asset.properties.get("license") - def set_license(self, license, asset=None): + def set_license( + self, license: Optional[str], asset: Optional[Asset] = None + ) -> None: """Set an Item or an Asset license. If an Asset is supplied, sets the property on the Asset. Otherwise sets the Item's value. """ if asset is None: - self.properties['license'] = license + self.properties["license"] = license else: - asset.properties['license'] = license + asset.properties["license"] = license # Providers @property - def providers(self): + def providers(self) -> Optional[List[Provider]]: """Get or set a list of the item's providers. The setter can take either a Provider object or a dict but always stores each provider as a dict @@ -691,10 +214,10 @@ def providers(self): return self.get_providers() @providers.setter - def providers(self, v): + def providers(self, v: Optional[List[Provider]]) -> None: self.set_providers(v) - def get_providers(self, asset=None): + def get_providers(self, asset: Optional[Asset] = None) -> Optional[List[Provider]]: """Gets an Item or an Asset providers. If an Asset is supplied and the Item property exists on the Asset, @@ -703,31 +226,40 @@ def get_providers(self, asset=None): Returns: List[Provider] """ - if asset is None or 'providers' not in asset.properties: - providers = self.properties.get('providers') + if asset is None or "providers" not in asset.properties: + providers = self.properties.get("providers") else: - providers = asset.properties.get('providers') + providers = asset.properties.get("providers") if providers is not None: providers = [Provider.from_dict(d) for d in providers] return providers - def set_providers(self, providers, asset=None): + def set_providers( + self, providers: Optional[List[Provider]], asset: Optional[Asset] = None + ) -> None: """Set an Item or an Asset providers. If an Asset is supplied, sets the property on the Asset. Otherwise sets the Item's value. """ - providers_dicts = [d.to_dict() for d in providers] if asset is None: - self.properties['providers'] = providers_dicts + if providers is None: + self.properties.pop("providers", None) + else: + providers_dicts = [d.to_dict() for d in providers] + self.properties["providers"] = providers_dicts else: - asset.properties['providers'] = providers_dicts + if providers is None: + asset.properties.pop("providers", None) + else: + providers_dicts = [d.to_dict() for d in providers] + asset.properties["providers"] = providers_dicts # Instrument @property - def platform(self): + def platform(self) -> Optional[str]: """Get or set the item's platform attribute Returns: @@ -737,10 +269,10 @@ def platform(self): return self.get_platform() @platform.setter - def platform(self, v): + def platform(self, v: Optional[str]) -> None: self.set_platform(v) - def get_platform(self, asset=None): + def get_platform(self, asset: Optional[Asset] = None) -> Optional[str]: """Gets an Item or an Asset platform. If an Asset is supplied and the Item property exists on the Asset, @@ -749,24 +281,26 @@ def get_platform(self, asset=None): Returns: str """ - if asset is None or 'platform' not in asset.properties: - return self.properties.get('platform') + if asset is None or "platform" not in asset.properties: + return self.properties.get("platform") else: - return asset.properties.get('platform') + return asset.properties.get("platform") - def set_platform(self, platform, asset=None): + def set_platform( + self, platform: Optional[str], asset: Optional[Asset] = None + ) -> None: """Set an Item or an Asset platform. If an Asset is supplied, sets the property on the Asset. Otherwise sets the Item's value. """ if asset is None: - self.properties['platform'] = platform + self.properties["platform"] = platform else: - asset.properties['platform'] = platform + asset.properties["platform"] = platform @property - def instruments(self): + def instruments(self) -> Optional[List[str]]: """Get or set the names of the instruments used Returns: @@ -775,36 +309,38 @@ def instruments(self): return self.get_instruments() @instruments.setter - def instruments(self, v): + def instruments(self, v: Optional[List[str]]) -> None: self.set_instruments(v) - def get_instruments(self, asset=None): + def get_instruments(self, asset: Optional[Asset] = None) -> Optional[List[str]]: """Gets an Item or an Asset instruments. If an Asset is supplied and the Item property exists on the Asset, returns the Asset's value. Otherwise returns the Item's value Returns: - List[str] + Optional[List[str]] """ - if asset is None or 'instruments' not in asset.properties: - return self.properties.get('instruments') + if asset is None or "instruments" not in asset.properties: + return self.properties.get("instruments") else: - return asset.properties.get('instruments') + return asset.properties.get("instruments") - def set_instruments(self, instruments, asset=None): + def set_instruments( + self, instruments: Optional[List[str]], asset: Optional[Asset] = None + ) -> None: """Set an Item or an Asset instruments. If an Asset is supplied, sets the property on the Asset. Otherwise sets the Item's value. """ if asset is None: - self.properties['instruments'] = instruments + self.properties["instruments"] = instruments else: - asset.properties['instruments'] = instruments + asset.properties["instruments"] = instruments @property - def constellation(self): + def constellation(self) -> Optional[str]: """Get or set the name of the constellation associate with an item Returns: @@ -813,10 +349,10 @@ def constellation(self): return self.get_constellation() @constellation.setter - def constellation(self, v): + def constellation(self, v: Optional[str]) -> None: self.set_constellation(v) - def get_constellation(self, asset=None): + def get_constellation(self, asset: Optional[Asset] = None) -> Optional[str]: """Gets an Item or an Asset constellation. If an Asset is supplied and the Item property exists on the Asset, @@ -825,24 +361,26 @@ def get_constellation(self, asset=None): Returns: str """ - if asset is None or 'constellation' not in asset.properties: - return self.properties.get('constellation') + if asset is None or "constellation" not in asset.properties: + return self.properties.get("constellation") else: - return asset.properties.get('constellation') + return asset.properties.get("constellation") - def set_constellation(self, constellation, asset=None): + def set_constellation( + self, constellation: Optional[str], asset: Optional[Asset] = None + ) -> None: """Set an Item or an Asset constellation. If an Asset is supplied, sets the property on the Asset. Otherwise sets the Item's value. """ if asset is None: - self.properties['constellation'] = constellation + self.properties["constellation"] = constellation else: - asset.properties['constellation'] = constellation + asset.properties["constellation"] = constellation @property - def mission(self): + def mission(self) -> Optional[str]: """Get or set the name of the mission associated with an item Returns: @@ -851,10 +389,10 @@ def mission(self): return self.get_mission() @mission.setter - def mission(self, v): + def mission(self, v: Optional[str]) -> None: self.set_mission(v) - def get_mission(self, asset=None): + def get_mission(self, asset: Optional[Asset] = None) -> Optional[str]: """Gets an Item or an Asset mission. If an Asset is supplied and the Item property exists on the Asset, @@ -863,36 +401,38 @@ def get_mission(self, asset=None): Returns: str """ - if asset is None or 'mission' not in asset.properties: - return self.properties.get('mission') + if asset is None or "mission" not in asset.properties: + return self.properties.get("mission") else: - return asset.properties.get('mission') + return asset.properties.get("mission") - def set_mission(self, mission, asset=None): + def set_mission( + self, mission: Optional[str], asset: Optional[Asset] = None + ) -> None: """Set an Item or an Asset mission. If an Asset is supplied, sets the property on the Asset. Otherwise sets the Item's value. """ if asset is None: - self.properties['mission'] = mission + self.properties["mission"] = mission else: - asset.properties['mission'] = mission + asset.properties["mission"] = mission @property - def gsd(self): + def gsd(self) -> Optional[float]: """Get or sets the Ground Sample Distance at the sensor. Returns: - [float]: Ground Sample Distance at the senso + [float]: Ground Sample Distance at the sensor """ return self.get_gsd() @gsd.setter - def gsd(self, v): + def gsd(self, v: Optional[float]) -> None: self.set_gsd(v) - def get_gsd(self, asset=None): + def get_gsd(self, asset: Optional[Asset] = None) -> Optional[float]: """Gets an Item or an Asset gsd. If an Asset is supplied and the Item property exists on the Asset, @@ -901,25 +441,25 @@ def get_gsd(self, asset=None): Returns: float """ - if asset is None or 'gsd' not in asset.properties: - return self.properties.get('gsd') + if asset is None or "gsd" not in asset.properties: + return self.properties.get("gsd") else: - return asset.properties.get('gsd') + return asset.properties.get("gsd") - def set_gsd(self, gsd, asset=None): + def set_gsd(self, gsd: Optional[float], asset: Optional[Asset] = None) -> None: """Set an Item or an Asset gsd. If an Asset is supplied, sets the property on the Asset. Otherwise sets the Item's value. """ if asset is None: - self.properties['gsd'] = gsd + self.properties["gsd"] = gsd else: - asset.properties['gsd'] = gsd + asset.properties["gsd"] = gsd # Metadata @property - def created(self): + def created(self) -> Optional[Datetime]: """Get or set the metadata file's creation date. All datetime attributes have setters that can take either a string or a datetime, but always stores the attribute as a string @@ -930,58 +470,64 @@ def created(self): return self.get_created() @created.setter - def created(self, v): + def created(self, v: Optional[Datetime]) -> None: self.set_created(v) - def get_created(self, asset=None): + def get_created(self, asset: Optional[Asset] = None) -> Optional[Datetime]: """Gets an Item or an Asset created time. If an Asset is supplied and the Item property exists on the Asset, returns the Asset's value. Otherwise returns the Item's value. Note: - ``created`` and ``updated`` have different meaning depending on where they are used. - If those fields are available in the Item `properties`, it's referencing to the - creation and update times of the metadata. Having those fields in the Item `assets` - refers to the creation and update times of the actual data linked to - in the Asset Object. + ``created`` and ``updated`` have different meaning depending on where they + are used. If those fields are available in the Item `properties`, it's + referencing to the creation and update times of the metadata. Having those + fields in the Item `assets` refers to the creation and update times of the + actual data linked to in the Asset Object. Returns: datetime """ - if asset is None or 'created' not in asset.properties: - created = self.properties.get('created') + if asset is None or "created" not in asset.properties: + created = self.properties.get("created") else: - created = asset.properties.get('created') + created = asset.properties.get("created") if created: created = str_to_datetime(created) return created - def set_created(self, created, asset=None): + def set_created( + self, created: Optional[Datetime], asset: Optional[Asset] = None + ) -> None: """Set an Item or an Asset created time. If an Asset is supplied, sets the property on the Asset. Otherwise sets the Item's value. """ if asset is None: - self.properties['created'] = datetime_to_str(created) + self.properties["created"] = ( + None if created is None else datetime_to_str(created) + ) else: - asset.properties['created'] = datetime_to_str(created) + asset.properties["created"] = ( + None if created is None else datetime_to_str(created) + ) @property - def updated(self): + def updated(self) -> Optional[Datetime]: """Get or set the metadata file's update date. All datetime attributes have setters that can take either a string or a datetime, but always stores the attribute as a string Note: - ``created`` and ``updated`` have different meaning depending on where they are used. - If those fields are available in the Item `properties`, it's referencing to the - creation and update times of the metadata. Having those fields in the Item `assets` - refers to the creation and update times of the actual data linked to - in the Asset Object. + ``created`` and ``updated`` have different meaning depending on where they + are used. If those fields are available in the Item `properties`, it's + referencing to the creation and update times of the metadata. Having those + fields in the Item `assets` refers to the creation and update times of the + actual data linked to in the Asset Object. Returns: @@ -991,42 +537,444 @@ def updated(self): return self.get_updated() @updated.setter - def updated(self, v): + def updated(self, v: Optional[Datetime]) -> None: self.set_updated(v) - def get_updated(self, asset=None): + def get_updated(self, asset: Optional[Asset] = None) -> Optional[Datetime]: """Gets an Item or an Asset updated time. If an Asset is supplied and the Item property exists on the Asset, returns the Asset's value. Otherwise returns the Item's value. Note: - ``created`` and ``updated`` have different meaning depending on where they are used. - If those fields are available in the Item `properties`, it's referencing to the - creation and update times of the metadata. Having those fields in the Item `assets` - refers to the creation and update times of the actual data linked to - in the Asset Object. + ``created`` and ``updated`` have different meaning depending on where they + are used. If those fields are available in the Item `properties`, it's + referencing to the creation and update times of the metadata. Having those + fields in the Item `assets` refers to the creation and update times of the + actual data linked to in the Asset Object. Returns: datetime """ - if asset is None or 'updated' not in asset.properties: - updated = self.properties.get('updated') + if asset is None or "updated" not in asset.properties: + updated = self.properties.get("updated") else: - updated = asset.properties.get('updated') + updated = asset.properties.get("updated") if updated: updated = str_to_datetime(updated) return updated - def set_updated(self, updated, asset=None): + def set_updated( + self, updated: Optional[Datetime], asset: Optional[Asset] = None + ) -> None: """Set an Item or an Asset updated time. If an Asset is supplied, sets the property on the Asset. Otherwise sets the Item's value. """ if asset is None: - self.properties['updated'] = datetime_to_str(updated) + self.properties["updated"] = ( + None if updated is None else datetime_to_str(updated) + ) + else: + asset.properties["updated"] = ( + None if updated is None else datetime_to_str(updated) + ) + + +class Item(STACObject): + """An Item is the core granular entity in a STAC, containing the core metadata + that enables any client to search or crawl online catalogs of spatial 'assets' - + satellite imagery, derived data, DEM's, etc. + + Args: + id (str): Provider identifier. Must be unique within the STAC. + geometry (dict): Defines the full footprint of the asset represented by this + item, formatted according to + `RFC 7946, section 3.1 (GeoJSON) `_. + bbox (List[float] or None): Bounding Box of the asset represented by this item + using either 2D or 3D geometries. The length of the array must be 2*n + where n is the number of dimensions. Could also be None in the case of a + null geometry. + datetime (datetime or None): Datetime associated with this item. If None, + a start_datetime and end_datetime must be supplied in the properties. + properties (dict): A dictionary of additional metadata for the item. + stac_extensions (List[str]): Optional list of extensions the Item implements. + href (str or None): Optional HREF for this item, which be set as the item's + self link's HREF. + collection (Collection or str): The Collection or Collection ID that this item + belongs to. + extra_fields (dict or None): Extra fields that are part of the top-level JSON + properties of the Item. + + Attributes: + id (str): Provider identifier. Unique within the STAC. + geometry (dict): Defines the full footprint of the asset represented by this + item, formatted according to + `RFC 7946, section 3.1 (GeoJSON) `_. + bbox (List[float] or None): Bounding Box of the asset represented by this item + using either 2D or 3D geometries. The length of the array is 2*n where n + is the number of dimensions. Could also be None in the case of a null + geometry. + datetime (datetime or None): Datetime associated with this item. If None, + the start_datetime and end_datetime in the common_metadata + will supply the datetime range of the Item. + properties (dict): A dictionary of additional metadata for the item. + stac_extensions (List[str] or None): Optional list of extensions the Item + implements. + collection (Collection or None): Collection that this item is a part of. + links (List[Link]): A list of :class:`~pystac.Link` objects representing + all links associated with this STACObject. + assets (Dict[str, Asset]): Dictionary of asset objects that can be downloaded, + each with a unique key. + collection_id (str or None): The Collection ID that this item belongs to, if + any. + extra_fields (dict or None): Extra fields that are part of the top-level JSON + properties of the Item. + """ + + STAC_OBJECT_TYPE = STACObjectType.ITEM + + def __init__( + self, + id: str, + geometry: Optional[Dict[str, Any]], + bbox: Optional[List[float]], + datetime: Optional[Datetime], + properties: Dict[str, Any], + stac_extensions: Optional[List[str]] = None, + href: Optional[str] = None, + collection: Optional[Union[str, Collection]] = None, + extra_fields: Optional[Dict[str, Any]] = None, + ): + super().__init__(stac_extensions or []) + + self.id = id + self.geometry = geometry + self.bbox = bbox + self.properties = properties + if extra_fields is None: + self.extra_fields = {} + else: + self.extra_fields = extra_fields + + self.assets: Dict[str, Asset] = {} + + self.datetime: Optional[Datetime] = None + if datetime is None: + if "start_datetime" not in properties or "end_datetime" not in properties: + raise STACError( + "Invalid Item: If datetime is None, " + "a start_datetime and end_datetime " + "must be supplied in " + "the properties." + ) + self.datetime = None + else: + self.datetime = datetime + + if href is not None: + self.set_self_href(href) + + self.collection_id: Optional[str] = None + if collection is not None: + if isinstance(collection, Collection): + self.set_collection(collection) + else: + self.collection_id = collection + + def __repr__(self) -> str: + return "".format(self.id) + + def set_self_href(self, href: Optional[str]) -> None: + """Sets the absolute HREF that is represented by the ``rel == 'self'`` + :class:`~pystac.Link`. + + Changing the self HREF of the item will ensure that all asset HREFs + remain valid. If asset HREFs are relative, the HREFs will change + to point to the same location based on the new item self HREF, + either by making them relative to the new location or making them + absolute links if the new location does not share the same protocol + as the old location. + + Args: + href (str): The absolute HREF of this object. If the given HREF + is not absolute, it will be transformed to an absolute + HREF based on the current working directory. If this is None + the call will clear the self HREF link. + """ + prev_href = self.get_self_href() + super().set_self_href(href) + new_href = self.get_self_href() # May have been made absolute. + + if prev_href is not None and new_href is not None: + # Make sure relative asset links remain valid. + for asset in self.assets.values(): + asset_href = asset.href + if not is_absolute_href(asset_href): + abs_href = make_absolute_href(asset_href, prev_href) + new_relative_href = make_relative_href(abs_href, new_href) + asset.href = new_relative_href + + def get_datetime(self, asset: Optional[Asset] = None) -> Optional[Datetime]: + """Gets an Item or an Asset datetime. + + If an Asset is supplied and the Item property exists on the Asset, + returns the Asset's value. Otherwise returns the Item's value. + + Returns: + datetime or None + """ + if asset is None or "datetime" not in asset.properties: + return self.datetime + else: + asset_dt = asset.properties.get("datetime") + if asset_dt is None: + return None + else: + return str_to_datetime(asset_dt) + + def set_datetime(self, datetime: Datetime, asset: Optional[Asset] = None) -> None: + """Set an Item or an Asset datetime. + + If an Asset is supplied, sets the property on the Asset. + Otherwise sets the Item's value. + """ + if asset is None: + self.datetime = datetime + else: + asset.properties["datetime"] = datetime_to_str(datetime) + + def get_assets(self) -> Dict[str, Asset]: + """Get this item's assets. + + Returns: + Dict[str, Asset]: A copy of the dictionary of this item's assets. + """ + return dict(self.assets.items()) + + def add_asset(self, key: str, asset: Asset) -> None: + """Adds an Asset to this item. + + Args: + key (str): The unique key of this asset. + asset (Asset): The Asset to add. + """ + asset.set_owner(self) + self.assets[key] = asset + + def make_asset_hrefs_relative(self) -> "Item": + """Modify each asset's HREF to be relative to this item's self HREF. + + Returns: + Item: self + """ + + self_href = None + for asset in self.assets.values(): + href = asset.href + if is_absolute_href(href): + if self_href is None: + self_href = self.get_self_href() + if self_href is None: + raise STACError( + "Cannot make asset HREFs relative " + "if no self_href is set." + ) + asset.href = make_relative_href(asset.href, self_href) + return self + + def make_asset_hrefs_absolute(self) -> "Item": + """Modify each asset's HREF to be absolute. + + Any asset HREFs that are relative will be modified to absolute based on this + item's self HREF. + + Returns: + Item: self + """ + self_href = None + for asset in self.assets.values(): + href = asset.href + if not is_absolute_href(href): + if self_href is None: + self_href = self.get_self_href() + if self_href is None: + raise STACError( + "Cannot make relative asset HREFs absolute " + "if no self_href is set." + ) + asset.href = make_absolute_href(asset.href, self_href) + + return self + + def set_collection(self, collection: Optional[Collection]) -> "Item": + """Set the collection of this item. + + This method will replace any existing Collection link and attribute for + this item. + + Args: + collection (Collection or None): The collection to set as this + item's collection. If None, will clear the collection. + + Returns: + Item: self + """ + self.remove_links("collection") + self.collection_id = None + if collection is not None: + self.add_link(Link.collection(collection)) + self.collection_id = collection.id + + return self + + def get_collection(self) -> Optional[Collection]: + """Gets the collection of this item, if one exists. + + Returns: + Collection or None: If this item belongs to a collection, returns + a reference to the collection. Otherwise returns None. + """ + collection_link = self.get_single_link("collection") + if collection_link is None: + return None + else: + return cast(Collection, collection_link.resolve_stac_object().target) + + def to_dict(self, include_self_link: bool = True) -> Dict[str, Any]: + links = self.links + if not include_self_link: + links = [x for x in links if x.rel != "self"] + + assets = {k: v.to_dict() for k, v in self.assets.items()} + + if self.datetime is not None: + self.properties["datetime"] = datetime_to_str(self.datetime) else: - asset.properties['updated'] = datetime_to_str(updated) + self.properties["datetime"] = None + + d: Dict[str, Any] = { + "type": "Feature", + "stac_version": pystac.get_stac_version(), + "id": self.id, + "properties": self.properties, + "geometry": self.geometry, + "links": [link.to_dict() for link in links], + "assets": assets, + } + + if self.bbox is not None: + d["bbox"] = self.bbox + + if self.stac_extensions is not None: + d["stac_extensions"] = self.stac_extensions + + if self.collection_id: + d["collection"] = self.collection_id + + for key in self.extra_fields: + d[key] = self.extra_fields[key] + + return d + + def clone(self) -> "Item": + clone = Item( + id=self.id, + geometry=deepcopy(self.geometry), + bbox=copy(self.bbox), + datetime=copy(self.datetime), + properties=deepcopy(self.properties), + stac_extensions=deepcopy(self.stac_extensions), + collection=self.collection_id, + ) + for link in self.links: + clone.add_link(link.clone()) + + for k, asset in self.assets.items(): + clone.add_asset(k, asset.clone()) + + return clone + + def _object_links(self) -> List[str]: + return ["collection"] + (pystac.EXTENSION_HOOKS.get_extended_object_links(self)) + + @classmethod + def from_dict( + cls, + d: Dict[str, Any], + href: Optional[str] = None, + root: Optional[Catalog] = None, + migrate: bool = False, + ) -> "Item": + if migrate: + result = pystac.read_dict(d, href=href, root=root) + if not isinstance(result, Item): + raise pystac.STACError(f"{result} is not a Catalog") + return result + + d = deepcopy(d) + id = d.pop("id") + geometry = d.pop("geometry") + properties = d.pop("properties") + bbox = d.pop("bbox", None) + stac_extensions = d.get("stac_extensions") + collection_id = d.pop("collection", None) + + datetime = properties.get("datetime") + if datetime is not None: + datetime = dateutil.parser.parse(datetime) + links = d.pop("links") + assets = d.pop("assets") + + d.pop("type") + d.pop("stac_version") + + item = cls( + id=id, + geometry=geometry, + bbox=bbox, + datetime=datetime, + properties=properties, + stac_extensions=stac_extensions, + collection=collection_id, + extra_fields=d, + ) + + has_self_link = False + for link in links: + has_self_link |= link["rel"] == "self" + item.add_link(Link.from_dict(link)) + + if not has_self_link and href is not None: + item.add_link(Link.self_href(href)) + + for k, v in assets.items(): + asset = Asset.from_dict(v) + asset.set_owner(item) + item.assets[k] = asset + + return item + + @property + def common_metadata(self) -> CommonMetadata: + """Access the item's common metadat fields as a CommonMetadata object + + Returns: + CommonMetada: contains all common metadata fields in the items properties + """ + return CommonMetadata(self.properties) + + def full_copy( + self, root: Optional["Catalog"] = None, parent: Optional["Catalog"] = None + ) -> "Item": + return cast(Item, super().full_copy(root, parent)) + + @classmethod + def from_file(cls, href: str, stac_io: Optional[pystac.StacIO] = None) -> "Item": + result = super().from_file(href, stac_io) + if not isinstance(result, Item): + raise pystac.STACTypeError(f"{result} is not a {Item}.") + return result diff --git a/pystac/layout.py b/pystac/layout.py index 25c02d352..da6dd48ea 100644 --- a/pystac/layout.py +++ b/pystac/layout.py @@ -1,15 +1,23 @@ -from abc import (abstractmethod, ABC) +from abc import abstractmethod, ABC from collections import OrderedDict import os from string import Formatter +from typing import Any, Callable, Dict, List, Optional, TYPE_CHECKING, Union import pystac +if TYPE_CHECKING: + from pystac.stac_object import STACObject as STACObject_Type + from pystac.catalog import Catalog as Catalog_Type + from pystac.collection import Collection as Collection_Type + from pystac.item import Item as Item_Type + class TemplateError(Exception): """Exception thrown when an error occurs during converting a template string into data for :class:`~pystac.layout.LayoutTemplate` """ + pass @@ -64,75 +72,96 @@ class LayoutTemplate: """ # Special template vars specific to Items - ITEM_TEMPLATE_VARS = ['date', 'year', 'month', 'day', 'collection'] + ITEM_TEMPLATE_VARS = ["date", "year", "month", "day", "collection"] - def __init__(self, template, defaults=None): + def __init__(self, template: str, defaults: Dict[str, str] = None) -> None: self.template = template self.defaults = defaults or {} # Generate list of template vars - template_vars = [] + template_vars: List[str] = [] for formatter_parse_result in Formatter().parse(template): v = formatter_parse_result[1] if v is not None: - if formatter_parse_result[2] != '': - v = '{}:{}'.format(v, formatter_parse_result[2]) + if formatter_parse_result[2] != "": + v = "{}:{}".format(v, formatter_parse_result[2]) template_vars.append(v) self.template_vars = template_vars - def _get_template_value(self, stac_object, template_var): + def _get_template_value( + self, stac_object: "STACObject_Type", template_var: str + ) -> Any: if template_var in self.ITEM_TEMPLATE_VARS: - if stac_object.STAC_OBJECT_TYPE == pystac.STACObjectType.ITEM: + if isinstance(stac_object, pystac.Item): # Datetime dt = stac_object.datetime if dt is None: dt = stac_object.common_metadata.start_datetime if dt is None: - raise TemplateError('Item {} does not have a datetime or ' - 'datetime range set; cannot template {} in {}'.format( - stac_object, template_var, self.template)) + raise TemplateError( + "Item {} does not have a datetime or " + "datetime range set; cannot template {} in {}".format( + stac_object, template_var, self.template + ) + ) - if template_var == 'year': + if template_var == "year": return dt.year - if template_var == 'month': + if template_var == "month": return dt.month - if template_var == 'day': + if template_var == "day": return dt.day - if template_var == 'date': + if template_var == "date": return dt.date().isoformat() # Collection - if template_var == 'collection': + if template_var == "collection": if stac_object.collection_id is not None: return stac_object.collection_id raise TemplateError( - 'Item {} does not have a collection ID set; cannot template {} in {}'. - format(stac_object, template_var, self.template)) + f"Item {stac_object} does not have a collection ID set; " + f"cannot template {template_var} in {self.template}" + ) else: - raise TemplateError('"{}" cannot be used to template non-Item {} in {}'.format( - template_var, stac_object, self.template)) + raise TemplateError( + '"{}" cannot be used to template non-Item {} in {}'.format( + template_var, stac_object, self.template + ) + ) # Allow dot-notation properties for arbitrary object values. - props = template_var.split('.') - prop_location = None - error = TemplateError('Cannot find property {} on {} for template {}'.format( - template_var, stac_object, self.template)) + props = template_var.split(".") + prop_source: Optional[Union[pystac.STACObject, Dict[str, Any]]] = None + error = TemplateError( + "Cannot find property {} on {} for template {}".format( + template_var, stac_object, self.template + ) + ) try: + if hasattr(stac_object, props[0]): - prop_location = stac_object - elif hasattr( - stac_object, - "properties") and stac_object.properties and props[0] in stac_object.properties: - prop_location = stac_object.properties - elif hasattr(stac_object, "extra_fields" - ) and stac_object.extra_fields and props[0] in stac_object.extra_fields: - prop_location = stac_object.extra_fields - else: + prop_source = stac_object + + if prop_source is None and hasattr(stac_object, "properties"): + obj_props: Optional[ + Dict[str, Any] + ] = stac_object.properties # type:ignore + if obj_props is not None and props[0] in obj_props: + prop_source = obj_props + + if prop_source is None and hasattr(stac_object, "extra_fields"): + extra_fields: Optional[ + Dict[str, Any] + ] = stac_object.extra_fields # type:ignore + if extra_fields is not None and props[0] in extra_fields: + prop_source = extra_fields + + if prop_source is None: raise error - v = prop_location - for prop in template_var.split('.'): + v: Any = prop_source + for prop in template_var.split("."): if type(v) is dict: if prop not in v: raise error @@ -148,7 +177,7 @@ def _get_template_value(self, stac_object, template_var): return v - def get_template_values(self, stac_object): + def get_template_values(self, stac_object: "STACObject_Type") -> Dict[str, Any]: """Gets a dictionary of template variables to values derived from the given stac_object. If the template vars cannot be found in the stac object, and defaults was supplied to this template, a default @@ -168,10 +197,11 @@ def get_template_values(self, stac_object): derived from the stac object and there is no default, this error will be raised. """ - return OrderedDict([(k, self._get_template_value(stac_object, k)) - for k in self.template_vars]) + return OrderedDict( + [(k, self._get_template_value(stac_object, k)) for k in self.template_vars] + ) - def substitute(self, stac_object): + def substitute(self, stac_object: "STACObject_Type") -> str: """Substitutes the values derived from :meth:`~pystac.layout.LayoutTemplate.get_template_values` into the template string for this template. @@ -181,7 +211,7 @@ def substitute(self, stac_object): variable values from. Returns: - [str]: The original template supplied to this LayoutTemplate + str: The original template supplied to this LayoutTemplate with template variables replaced by the values derived from this stac object. @@ -194,33 +224,39 @@ def substitute(self, stac_object): s = self.template for key, value in parts.items(): - s = s.replace('${' + '{}'.format(key) + '}', '{}'.format(value)) + s = s.replace("${" + "{}".format(key) + "}", "{}".format(value)) return s class HrefLayoutStrategy(ABC): """Base class for HREF Layout strategies.""" - def get_href(self, stac_object, parent_dir, is_root=False): - stac_object_type = stac_object.STAC_OBJECT_TYPE - if stac_object_type == pystac.STACObjectType.CATALOG: - return self.get_catalog_href(stac_object, parent_dir, is_root) - elif stac_object_type == pystac.STACObjectType.COLLECTION: - return self.get_collection_href(stac_object, parent_dir, is_root) - elif stac_object_type == pystac.STACObjectType.ITEM: + + def get_href( + self, stac_object: "STACObject_Type", parent_dir: str, is_root: bool = False + ) -> str: + if isinstance(stac_object, pystac.Item): return self.get_item_href(stac_object, parent_dir) + elif isinstance(stac_object, pystac.Collection): + return self.get_collection_href(stac_object, parent_dir, is_root) + elif isinstance(stac_object, pystac.Catalog): + return self.get_catalog_href(stac_object, parent_dir, is_root) else: - raise pystac.STACError('Unknown STAC object type {}'.format(stac_object_type)) + raise pystac.STACError("Unknown STAC object type {}".format(stac_object)) @abstractmethod - def get_catalog_href(self, cat, parent_dir, is_root): + def get_catalog_href( + self, cat: "Catalog_Type", parent_dir: str, is_root: bool + ) -> str: pass @abstractmethod - def get_collection_href(self, col, parent_dir, is_root): + def get_collection_href( + self, col: "Collection_Type", parent_dir: str, is_root: bool + ) -> str: pass @abstractmethod - def get_item_href(self, item, parent_dir): + def get_item_href(self, item: "Item_Type", parent_dir: str) -> str: pass @@ -244,33 +280,40 @@ class CustomLayoutStrategy(HrefLayoutStrategy): use if a function is not provided for a stac object type. Defaults to :class:`~pystac.layout.BestPracticesLayoutStrategy` """ - def __init__(self, - catalog_func=None, - collection_func=None, - item_func=None, - fallback_strategy=None): + + def __init__( + self, + catalog_func: Optional[Callable[["Catalog_Type", str, bool], str]] = None, + collection_func: Optional[Callable[["Collection_Type", str, bool], str]] = None, + item_func: Optional[Callable[["Item_Type", str], str]] = None, + fallback_strategy: Optional[HrefLayoutStrategy] = None, + ): self.item_func = item_func self.collection_func = collection_func self.catalog_func = catalog_func if fallback_strategy is None: fallback_strategy = BestPracticesLayoutStrategy() - self.fallback_strategy = fallback_strategy + self.fallback_strategy: HrefLayoutStrategy = fallback_strategy - def get_catalog_href(self, cat, parent_dir, is_root): + def get_catalog_href( + self, cat: "Catalog_Type", parent_dir: str, is_root: bool + ) -> str: if self.catalog_func is not None: result = self.catalog_func(cat, parent_dir, is_root) if result is not None: return result return self.fallback_strategy.get_catalog_href(cat, parent_dir, is_root) - def get_collection_href(self, col, parent_dir, is_root): + def get_collection_href( + self, col: "Collection_Type", parent_dir: str, is_root: bool + ) -> str: if self.collection_func is not None: result = self.collection_func(col, parent_dir, is_root) if result is not None: return result return self.fallback_strategy.get_collection_href(col, parent_dir, is_root) - def get_item_href(self, item, parent_dir): + def get_item_href(self, item: "Item_Type", parent_dir: str) -> str: if self.item_func is not None: result = self.item_func(item, parent_dir) if result is not None: @@ -302,48 +345,61 @@ class TemplateLayoutStrategy(HrefLayoutStrategy): use if a template is not provided. Defaults to :class:`~pystac.layout.BestPracticesLayoutStrategy` """ - def __init__(self, - catalog_template=None, - collection_template=None, - item_template=None, - fallback_strategy=None): - self.catalog_template = LayoutTemplate( - catalog_template) if catalog_template is not None else None - self.collection_template = LayoutTemplate( - collection_template) if collection_template is not None else None - self.item_template = LayoutTemplate(item_template) if item_template is not None else None + + def __init__( + self, + catalog_template: Optional[str] = None, + collection_template: Optional[str] = None, + item_template: Optional[str] = None, + fallback_strategy: Optional[HrefLayoutStrategy] = None, + ): + self.catalog_template = ( + LayoutTemplate(catalog_template) if catalog_template is not None else None + ) + self.collection_template = ( + LayoutTemplate(collection_template) + if collection_template is not None + else None + ) + self.item_template = ( + LayoutTemplate(item_template) if item_template is not None else None + ) if fallback_strategy is None: fallback_strategy = BestPracticesLayoutStrategy() - self.fallback_strategy = fallback_strategy + self.fallback_strategy: HrefLayoutStrategy = fallback_strategy - def get_catalog_href(self, cat, parent_dir, is_root): + def get_catalog_href( + self, cat: "Catalog_Type", parent_dir: str, is_root: bool + ) -> str: if is_root or self.catalog_template is None: return self.fallback_strategy.get_catalog_href(cat, parent_dir, is_root) else: template_path = self.catalog_template.substitute(cat) - if not template_path.endswith('.json'): + if not template_path.endswith(".json"): template_path = os.path.join(template_path, cat.DEFAULT_FILE_NAME) return os.path.join(parent_dir, template_path) - def get_collection_href(self, col, parent_dir, is_root): + def get_collection_href( + self, col: "Collection_Type", parent_dir: str, is_root: bool + ) -> str: if is_root or self.collection_template is None: return self.fallback_strategy.get_collection_href(col, parent_dir, is_root) else: template_path = self.collection_template.substitute(col) - if not template_path.endswith('.json'): + if not template_path.endswith(".json"): template_path = os.path.join(template_path, col.DEFAULT_FILE_NAME) return os.path.join(parent_dir, template_path) - def get_item_href(self, item, parent_dir): + def get_item_href(self, item: "Item_Type", parent_dir: str) -> str: if self.item_template is None: return self.fallback_strategy.get_item_href(item, parent_dir) else: template_path = self.item_template.substitute(item) - if not template_path.endswith('.json'): - template_path = os.path.join(template_path, '{}.json'.format(item.id)) + if not template_path.endswith(".json"): + template_path = os.path.join(template_path, "{}.json".format(item.id)) return os.path.join(parent_dir, template_path) @@ -362,23 +418,28 @@ class BestPracticesLayoutStrategy(HrefLayoutStrategy): All paths are appended to the parent directory. """ - def get_catalog_href(self, cat, parent_dir, is_root): + + def get_catalog_href( + self, cat: "Catalog_Type", parent_dir: str, is_root: bool + ) -> str: if is_root: cat_root = parent_dir else: - cat_root = os.path.join(parent_dir, '{}'.format(cat.id)) + cat_root = os.path.join(parent_dir, "{}".format(cat.id)) return os.path.join(cat_root, cat.DEFAULT_FILE_NAME) - def get_collection_href(self, col, parent_dir, is_root): + def get_collection_href( + self, col: "Collection_Type", parent_dir: str, is_root: bool + ) -> str: if is_root: col_root = parent_dir else: - col_root = os.path.join(parent_dir, '{}'.format(col.id)) + col_root = os.path.join(parent_dir, "{}".format(col.id)) return os.path.join(col_root, col.DEFAULT_FILE_NAME) - def get_item_href(self, item, parent_dir): - item_root = os.path.join(parent_dir, '{}'.format(item.id)) + def get_item_href(self, item: "Item_Type", parent_dir: str) -> str: + item_root = os.path.join(parent_dir, "{}".format(item.id)) - return os.path.join(item_root, '{}.json'.format(item.id)) + return os.path.join(item_root, "{}.json".format(item.id)) diff --git a/pystac/link.py b/pystac/link.py index 67bde52d7..3e7be46f4 100644 --- a/pystac/link.py +++ b/pystac/link.py @@ -1,11 +1,16 @@ from copy import copy +from typing import Any, Dict, Optional, TYPE_CHECKING, Union, cast import pystac -from pystac import STACError -from pystac.stac_io import STAC_IO -from pystac.utils import (make_absolute_href, make_relative_href, is_absolute_href) +from pystac.utils import make_absolute_href, make_relative_href, is_absolute_href -HIERARCHICAL_LINKS = ['root', 'child', 'parent', 'collection', 'item', 'items'] +if TYPE_CHECKING: + from pystac.stac_object import STACObject as STACObject_Type + from pystac.item import Item as Item_Type + from pystac.catalog import Catalog as Catalog_Type + from pystac.collection import Collection as Collection_Type + +HIERARCHICAL_LINKS = ["root", "child", "parent", "collection", "item", "items"] class Link: @@ -30,8 +35,8 @@ class Link: media_type (str): Optional description of the media type. Registered Media Types are preferred. See :class:`~pystac.MediaType` for common media types. title (str): Optional title for this link. - properties (dict): Optional, additional properties for this link. This is used by - extensions as a way to serialize and deserialize properties on link + properties (dict): Optional, additional properties for this link. This is used + by extensions as a way to serialize and deserialize properties on link object JSON. Attributes: @@ -39,35 +44,57 @@ class Link: target (str or STACObject): The target of the link. If the link is unresolved, or the link is to something that is not a STACObject, the target is an HREF. If resolved, the target is a STACObject. - media_type (str or None): Optional description of the media type. Registered Media Types - are preferred. See :class:`~pystac.MediaType` for common media types. + media_type (str or None): Optional description of the media type. + Registered Media Types are preferred. See + :class:`~pystac.MediaType` for common media types. title (str or None): Optional title for this link. properties (dict or None): Optional, additional properties for this link. This is used by extensions as a way to serialize and deserialize properties on link object JSON. owner (STACObject or None): The owner of this link. The link will use - its owner's root catalog :class:`~pystac.resolved_object_cache.ResolvedObjectCache` - to resolve objects, and will create absolute HREFs from relative HREFs against + its owner's root catalog + :class:`~pystac.resolved_object_cache.ResolvedObjectCache` to resolve + objects, and will create absolute HREFs from relative HREFs against the owner's self HREF. """ - def __init__(self, rel, target, media_type=None, title=None, properties=None): + + def __init__( + self, + rel: str, + target: Union[str, "STACObject_Type"], + media_type: Optional[str] = None, + title: Optional[str] = None, + properties: Optional[Dict[str, Any]] = None, + ) -> None: self.rel = rel - self.target = target # An object or an href + self.target: Union[str, "STACObject_Type"] = target # An object or an href self.media_type = media_type self.title = title self.properties = properties - self.owner = None + self.owner: Optional["STACObject_Type"] = None - def set_owner(self, owner): + def set_owner(self, owner: Optional["STACObject_Type"]) -> "Link": """Sets the owner of this link. Args: - owner (STACObject): The owner of this link. + owner: The owner of this link. Pass None to clear. """ self.owner = owner return self - def get_href(self): + @property + def href(self) -> str: + """Returns the HREF for this link. + + If the href is None, this will throw an exception. + Use get_href if there may not be an href. + """ + result = self.get_href() + if result is None: + raise ValueError(f"{self} does not have an HREF set.") + return result + + def get_href(self) -> Optional[str]: """Gets the HREF for this link. Returns: @@ -78,21 +105,37 @@ def get_href(self): """ # get the self href if self.is_resolved(): - href = self.target.get_self_href() + href = cast(pystac.STACObject, self.target).get_self_href() else: - href = self.target + href = cast(Optional[str], self.target) if href and is_absolute_href(href) and self.owner and self.owner.get_root(): root = self.owner.get_root() - rel_links = HIERARCHICAL_LINKS + \ - pystac.STAC_EXTENSIONS.get_extended_object_links(self.owner) + rel_links = ( + HIERARCHICAL_LINKS + + pystac.EXTENSION_HOOKS.get_extended_object_links(self.owner) + ) # if a hierarchical link with an owner and root, and relative catalog - if root.is_relative() and self.rel in rel_links: - href = make_relative_href(href, self.owner.get_self_href()) + if root and root.is_relative() and self.rel in rel_links: + owner_href = self.owner.get_self_href() + if owner_href is not None: + href = make_relative_href(href, owner_href) return href - def get_absolute_href(self): + @property + def absolute_href(self) -> str: + """Returns the absolute HREF for this link. + + If the href is None, this will throw an exception. + Use get_absolute_href if there may not be an href set. + """ + result = self.get_absolute_href() + if result is None: + raise ValueError(f"{self} does not have an HREF set.") + return result + + def get_absolute_href(self) -> Optional[str]: """Gets the absolute href for this link, if possible. Returns: @@ -101,19 +144,19 @@ def get_absolute_href(self): and has an unresolved target, this will return a relative HREF. """ if self.is_resolved(): - href = self.target.get_self_href() + href = cast(pystac.STACObject, self.target).get_self_href() else: - href = self.target + href = cast(Optional[str], self.target) - if self.owner is not None: + if href is not None and self.owner is not None: href = make_absolute_href(href, self.owner.get_self_href()) return href - def __repr__(self): - return ''.format(self.rel, self.target) + def __repr__(self) -> str: + return "".format(self.rel, self.target) - def resolve_stac_object(self, root=None): + def resolve_stac_object(self, root: Optional["Catalog_Type"] = None) -> "Link": """Resolves a STAC object from the HREF of this link, if the link is not already resolved. @@ -128,22 +171,37 @@ def resolve_stac_object(self, root=None): # If it's a relative link, base it off the parent. if not is_absolute_href(target_href): if self.owner is None: - raise STACError('Relative path {} encountered ' - 'without owner or start_href.'.format(target_href)) + raise pystac.STACError( + "Relative path {} encountered " + "without owner or start_href.".format(target_href) + ) start_href = self.owner.get_self_href() if start_href is None: - raise STACError('Relative path {} encountered ' - 'without owner "self" link set.'.format(target_href)) + raise pystac.STACError( + "Relative path {} encountered " + 'without owner "self" link set.'.format(target_href) + ) target_href = make_absolute_href(target_href, start_href) obj = None + stac_io: Optional[pystac.StacIO] = None + if root is not None: obj = root._resolved_objects.get_by_href(target_href) + stac_io = root._stac_io if obj is None: - obj = STAC_IO.read_stac_object(target_href, root=root) + + if stac_io is None: + if self.owner is not None: + if isinstance(self.owner, pystac.Catalog): + stac_io = self.owner._stac_io + if stac_io is None: + stac_io = pystac.StacIO.default() + + obj = stac_io.read_stac_object(target_href, root=root) obj.set_self_href(target_href) if root is not None: obj = root._resolved_objects.get_or_cache(obj) @@ -153,12 +211,16 @@ def resolve_stac_object(self, root=None): self.target = obj - if self.owner and self.rel in ['child', 'item']: + if ( + self.owner + and self.rel in ["child", "item"] + and isinstance(self.owner, pystac.Catalog) + ): self.target.set_parent(self.owner) return self - def is_resolved(self): + def is_resolved(self) -> bool: """Determines if the link's target is a resolved STACObject. Returns: @@ -166,22 +228,22 @@ def is_resolved(self): """ return not isinstance(self.target, str) - def to_dict(self): + def to_dict(self) -> Dict[str, Any]: """Generate a dictionary representing the JSON of this serialized Link. Returns: - dict: A serializion of the Link that can be written out as JSON. + dict: A serialization of the Link that can be written out as JSON. """ - d = {'rel': self.rel} + d: Dict[str, Any] = {"rel": self.rel} - d['href'] = self.get_href() + d["href"] = self.get_href() if self.media_type is not None: - d['type'] = self.media_type + d["type"] = self.media_type if self.title is not None: - d['title'] = self.title + d["title"] = self.title if self.properties: for k, v in self.properties.items(): @@ -189,7 +251,7 @@ def to_dict(self): return d - def clone(self): + def clone(self) -> "Link": """Clones this link. This makes a copy of all link information, but does not clone a STACObject @@ -199,10 +261,15 @@ def clone(self): Link: The cloned link. """ - return Link(rel=self.rel, target=self.target, media_type=self.media_type, title=self.title) + return Link( + rel=self.rel, + target=self.target, + media_type=self.media_type, + title=self.title, + ) @staticmethod - def from_dict(d): + def from_dict(d: Dict[str, Any]) -> "Link": """Deserializes a Link from a dict. Args: @@ -212,43 +279,49 @@ def from_dict(d): Link: Link instance constructed from the dict. """ d = copy(d) - rel = d.pop('rel') - href = d.pop('href') - media_type = d.pop('type', None) - title = d.pop('title', None) + rel = d.pop("rel") + href = d.pop("href") + media_type = d.pop("type", None) + title = d.pop("title", None) properties = None if any(d): properties = d - return Link(rel=rel, target=href, media_type=media_type, title=title, properties=properties) + return Link( + rel=rel, + target=href, + media_type=media_type, + title=title, + properties=properties, + ) @staticmethod - def root(c): + def root(c: "Catalog_Type") -> "Link": """Creates a link to a root Catalog or Collection.""" - return Link('root', c, media_type='application/json') + return Link("root", c, media_type="application/json") @staticmethod - def parent(c): + def parent(c: "Catalog_Type") -> "Link": """Creates a link to a parent Catalog or Collection.""" - return Link('parent', c, media_type='application/json') + return Link("parent", c, media_type="application/json") @staticmethod - def collection(c): + def collection(c: "Collection_Type") -> "Link": """Creates a link to an item's Collection.""" - return Link('collection', c, media_type='application/json') + return Link("collection", c, media_type="application/json") @staticmethod - def self_href(href): + def self_href(href: str) -> "Link": """Creates a self link to a file's location.""" - return Link('self', href, media_type='application/json') + return Link("self", href, media_type="application/json") @staticmethod - def child(c, title=None): + def child(c: "Catalog_Type", title: Optional[str] = None) -> "Link": """Creates a link to a child Catalog or Collection.""" - return Link('child', c, title=title, media_type='application/json') + return Link("child", c, title=title, media_type="application/json") @staticmethod - def item(item, title=None): + def item(item: "Item_Type", title: Optional[str] = None) -> "Link": """Creates a link to an Item.""" - return Link('item', item, title=title, media_type='application/json') + return Link("item", item, title=title, media_type="application/json") diff --git a/pystac/media_type.py b/pystac/media_type.py index 5bc4c2798..b74c5f51d 100644 --- a/pystac/media_type.py +++ b/pystac/media_type.py @@ -2,21 +2,21 @@ class MediaType(str, Enum): - """A list of common media types that can be used in STAC Asset and Link metadata. - """ - def __str__(self): + """A list of common media types that can be used in STAC Asset and Link metadata.""" + + def __str__(self) -> str: return str(self.value) - COG = 'image/tiff; application=geotiff; profile=cloud-optimized' - GEOJSON = 'application/geo+json' - GEOPACKAGE = 'application/geopackage+sqlite3' - GEOTIFF = 'image/tiff; application=geotiff' - HDF = 'application/x-hdf' # Hierarchical Data Format versions 4 and earlier. - HDF5 = 'application/x-hdf5' # Hierarchical Data Format version 5 - JPEG = 'image/jpeg' - JPEG2000 = 'image/jp2' - JSON = 'application/json' - PNG = 'image/png' - TEXT = 'text/plain' - TIFF = 'image/tiff' - XML = 'application/xml' + COG = "image/tiff; application=geotiff; profile=cloud-optimized" + GEOJSON = "application/geo+json" + GEOPACKAGE = "application/geopackage+sqlite3" + GEOTIFF = "image/tiff; application=geotiff" + HDF = "application/x-hdf" # Hierarchical Data Format versions 4 and earlier. + HDF5 = "application/x-hdf5" # Hierarchical Data Format version 5 + JPEG = "image/jpeg" + JPEG2000 = "image/jp2" + JSON = "application/json" + PNG = "image/png" + TEXT = "text/plain" + TIFF = "image/tiff" + XML = "application/xml" diff --git a/pystac/serialization/__init__.py b/pystac/serialization/__init__.py index 89ac837c8..ad1d6999a 100644 --- a/pystac/serialization/__init__.py +++ b/pystac/serialization/__init__.py @@ -1,13 +1,23 @@ # flake8: noqa -from pystac import (Catalog, Collection, Item, Extensions, STACObjectType) - -from pystac.serialization.identify import (STACJSONDescription, STACVersionRange, STACVersionID, - identify_stac_object, identify_stac_object_type) +from typing import Any, Dict, Optional, TYPE_CHECKING + +import pystac +from pystac.serialization.identify import ( + STACVersionRange, # type:ignore + identify_stac_object, + identify_stac_object_type, +) from pystac.serialization.common_properties import merge_common_properties from pystac.serialization.migrate import migrate_to_latest +if TYPE_CHECKING: + from pystac.stac_object import STACObject + from pystac.catalog import Catalog + -def stac_object_from_dict(d, href=None, root=None): +def stac_object_from_dict( + d: Dict[str, Any], href: Optional[str] = None, root: Optional["Catalog"] = None +) -> "STACObject": """Determines how to deserialize a dictionary into a STAC object. Args: @@ -18,10 +28,9 @@ def stac_object_from_dict(d, href=None, root=None): If provided, the root's resolved object cache can be used to search for previously resolved instances of the STAC object. - Note: This is used internally in STAC_IO to deserialize STAC Objects. - It is in the top level __init__ in order to avoid circular dependencies. + Note: This is used internally in StacIO instances to deserialize STAC Objects. """ - if identify_stac_object_type(d) == STACObjectType.ITEM: + if identify_stac_object_type(d) == pystac.STACObjectType.ITEM: collection_cache = None if root is not None: collection_cache = root._resolved_objects.as_collection_cache() @@ -31,13 +40,15 @@ def stac_object_from_dict(d, href=None, root=None): info = identify_stac_object(d) - d, info = migrate_to_latest(d, info) + d = migrate_to_latest(d, info) + + if info.object_type == pystac.STACObjectType.CATALOG: + return pystac.Catalog.from_dict(d, href=href, root=root, migrate=False) - if info.object_type == STACObjectType.CATALOG: - return Catalog.from_dict(d, href=href, root=root) + if info.object_type == pystac.STACObjectType.COLLECTION: + return pystac.Collection.from_dict(d, href=href, root=root, migrate=False) - if info.object_type == STACObjectType.COLLECTION: - return Collection.from_dict(d, href=href, root=root) + if info.object_type == pystac.STACObjectType.ITEM: + return pystac.Item.from_dict(d, href=href, root=root, migrate=False) - if info.object_type == STACObjectType.ITEM: - return Item.from_dict(d, href=href, root=root) + raise ValueError(f"Unknown STAC object type {info.object_type}") diff --git a/pystac/serialization/common_properties.py b/pystac/serialization/common_properties.py index ea430228f..4da6eadee 100644 --- a/pystac/serialization/common_properties.py +++ b/pystac/serialization/common_properties.py @@ -1,12 +1,20 @@ -from pystac import Collection -from pystac.utils import make_absolute_href -from pystac.stac_io import STAC_IO +from typing import Any, Dict, Iterable, List, Optional, Union, cast + +import pystac +from pystac.cache import CollectionCache from pystac.serialization.identify import STACVersionID +from pystac.utils import make_absolute_href -def merge_common_properties(item_dict, collection_cache=None, json_href=None): +def merge_common_properties( + item_dict: Dict[str, Any], + collection_cache: Optional[CollectionCache] = None, + json_href: Optional[str] = None, +) -> bool: """Merges Collection properties into an Item. + Note: This is only applicable to reading old STAC versions (pre 1.0.0-beta.1). + Args: item_dict (dict): JSON dict of the Item which properties should be merged into. @@ -20,74 +28,86 @@ def merge_common_properties(item_dict, collection_cache=None, json_href=None): """ properties_merged = False - collection = None - collection_id = None - collection_href = None + collection: Optional[Union[pystac.Collection, Dict[str, Any]]] = None + collection_id: Optional[str] = None + collection_href: Optional[str] = None - stac_version = item_dict.get('stac_version') + stac_version = item_dict.get("stac_version") # The commons extension was removed in 1.0.0-beta.1, so if this is an earlier STAC # item we don't have to bother with merging. - if stac_version is not None and STACVersionID(stac_version) > '0.9.0': + if ( + stac_version is not None + and STACVersionID(stac_version) > "0.9.0" # type:ignore + ): return False # Check to see if this is a 0.9.0 item that # doesn't extend the commons extension, in which case # we don't have to merge. - if stac_version is not None and stac_version == '0.9.0': - stac_extensions = item_dict.get('stac_extensions') - if type(stac_extensions) is list: - if 'commons' not in stac_extensions: + if stac_version is not None and stac_version == "0.9.0": + stac_extensions = item_dict.get("stac_extensions") + if isinstance(stac_extensions, list): + if "commons" not in stac_extensions: return False else: return False # Try the cache if we have a collection ID. - if 'collection' in item_dict: - collection_id = item_dict['collection'] + collection_id = item_dict.get("collection") + if collection_id is not None: if collection_cache is not None: collection = collection_cache.get_by_id(collection_id) # Next, try the collection link. if collection is None: - links = item_dict['links'] - # Account for 0.5 links, which were dicts - if isinstance(links, dict): - links = list(links.values()) + if isinstance(item_dict["links"], dict): + links = list(cast(Iterable[Dict[str, Any]], item_dict["links"].values())) + else: + links = cast(List[Dict[str, Any]], item_dict["links"]) - collection_link = next((link for link in links if link['rel'] == 'collection'), None) + collection_link = next( + (link for link in links if link["rel"] == "collection"), None + ) if collection_link is not None: - collection_href = collection_link['href'] - if json_href is not None: - collection_href = make_absolute_href(collection_href, json_href) - if collection_cache is not None: - collection = collection_cache.get_by_href(collection_href) + collection_href = cast(Dict[str, Any], collection_link).get("href") + if collection_href is not None: + if json_href is not None: + collection_href = make_absolute_href(collection_href, json_href) + if collection_cache is not None: + collection = collection_cache.get_by_href(collection_href) - if collection is None: - collection = STAC_IO.read_json(collection_href) + if collection is None: + collection = pystac.StacIO.default().read_json(collection_href) if collection is not None: collection_id = None - collection_props = None - if isinstance(collection, Collection): + collection_props: Optional[Dict[str, Any]] = None + if isinstance(collection, pystac.Collection): collection_id = collection.id - collection_props = collection.properties - elif type(collection) is dict: - collection_id = collection['id'] - if 'properties' in collection: - collection_props = collection['properties'] + collection_props = collection.extra_fields.get("properties") + elif isinstance(collection, dict): + collection_id = collection["id"] + if "properties" in collection: + collection_props = collection["properties"] else: - raise ValueError('{} is expected to be a Collection or ' - 'dict but is neither.'.format(collection)) + raise ValueError( + "{} is expected to be a Collection or " + "dict but is neither.".format(collection) + ) if collection_props is not None: for k in collection_props: - if k not in item_dict['properties']: + if k not in item_dict["properties"]: properties_merged = True - item_dict['properties'][k] = collection_props[k] + item_dict["properties"][k] = collection_props[k] - if collection_cache is not None and not collection_cache.contains_id(collection_id): + if ( + collection_cache is not None + and collection_id is not None + and not collection_cache.contains_id(collection_id) + ): collection_cache.cache(collection, href=collection_href) return properties_merged diff --git a/pystac/serialization/identify.py b/pystac/serialization/identify.py index d41b0673a..da20ad139 100644 --- a/pystac/serialization/identify.py +++ b/pystac/serialization/identify.py @@ -1,32 +1,34 @@ +from enum import Enum from functools import total_ordering +from typing import Any, Dict, List, Optional, Set, TYPE_CHECKING, Union, cast -from pystac import STACObjectType +import pystac from pystac.version import STACVersion -from pystac.extensions import Extensions +if TYPE_CHECKING: + from pystac.stac_object import STACObjectType as STACObjectType_Type -class STACJSONDescription: - """Describes the STAC object information for a STAC object represented in JSON - Attributes: - object_type (str): Describes the STAC object type. One of :class:`~pystac.STACObjectType`. - version_range (STACVersionRange): The STAC version range that describes what - has been identified as potential valid versions of the stac object. - common_extensions (List[str]): List of common extension IDs implemented by this - STAC object. - custom_extensions (List[str]): List of custom extensions (URIs to JSON Schemas) - used by this STAC Object. - """ - def __init__(self, object_type, version_range, common_extensions, custom_extensions): - self.object_type = object_type - self.version_range = version_range - self.common_extensions = common_extensions - self.custom_extensions = custom_extensions +class OldExtensionShortIDs(Enum): + """Enumerates the IDs of common extensions.""" - def __repr__(self): - return '<{} {} common_ext={} custom_ext={}>'.format(self.object_type, self.version_range, - ','.join(self.common_extensions), - ','.join(self.custom_extensions)) + CHECKSUM = "checksum" + COLLECTION_ASSETS = "collection-assets" + DATACUBE = "datacube" # TODO + EO = "eo" + ITEM_ASSETS = "item-assets" # TODO + LABEL = "label" + POINTCLOUD = "pointcloud" + PROJECTION = "projection" + SAR = "sar" + SAT = "sat" + SCIENTIFIC = "scientific" + SINGLE_FILE_STAC = "single-file-stac" + TILED_ASSETS = "tiled-assets" + TIMESTAMPS = "timestamps" + VERSION = "version" + VIEW = "view" + FILE = "file" @total_ordering @@ -34,29 +36,30 @@ class STACVersionID: """Defines STAC versions in an object that is orderable based on version number. For instance, ``1.0.0-beta.2 < 1.0.0`` """ - def __init__(self, version_string): + + def __init__(self, version_string: str) -> None: self.version_string = version_string # Account for RC or beta releases in version - version_parts = version_string.split('-') + version_parts = version_string.split("-") self.version_core = version_parts[0] if len(version_parts) == 1: self.version_prerelease = None else: - self.version_prerelease = '-'.join(version_parts[1:]) + self.version_prerelease = "-".join(version_parts[1:]) - def __str__(self): + def __str__(self) -> str: return self.version_string - def __eq__(self, other): + def __eq__(self, other: Any) -> bool: if type(other) is str: other = STACVersionID(other) return self.version_string == other.version_string - def __ne__(self, other): + def __ne__(self, other: Any) -> bool: return not self.__eq__(other) - def __lt__(self, other): + def __lt__(self, other: Any) -> bool: if type(other) is str: other = STACVersionID(other) if self.version_core < other.version_core: @@ -66,13 +69,19 @@ def __lt__(self, other): else: return self.version_prerelease is not None and ( other.version_prerelease is None - or other.version_prerelease > self.version_prerelease) + or other.version_prerelease > self.version_prerelease + ) class STACVersionRange: """Defines a range of STAC versions.""" - def __init__(self, min_version='0.4.0', max_version=None): - if type(min_version) is str: + + def __init__( + self, + min_version: Union[str, STACVersionID] = "0.4.0", + max_version: Optional[Union[str, STACVersionID]] = None, + ): + if isinstance(min_version, str): self.min_version = STACVersionID(min_version) else: self.min_version = min_version @@ -80,180 +89,216 @@ def __init__(self, min_version='0.4.0', max_version=None): if max_version is None: self.max_version = STACVersionID(STACVersion.DEFAULT_STAC_VERSION) else: - if type(max_version) is str: + if isinstance(max_version, str): self.max_version = STACVersionID(max_version) else: self.max_version = max_version - def set_min(self, v): + def set_min(self, v: STACVersionID) -> None: if self.min_version < v: if v < self.max_version: self.min_version = v else: self.min_version = self.max_version - def set_max(self, v): + def set_max(self, v: STACVersionID) -> None: if v < self.max_version: if self.min_version < v: self.max_version = v else: self.max_version = self.min_version - def set_to_single(self, v): + def set_to_single(self, v: STACVersionID) -> None: self.set_min(v) self.set_max(v) - def latest_valid_version(self): + def latest_valid_version(self) -> STACVersionID: return self.max_version - def contains(self, v): - if type(v) is str: + def contains(self, v: Union[str, STACVersionID]) -> bool: + if isinstance(v, str): v = STACVersionID(v) - return self.min_version <= v and v <= self.max_version + return self.min_version <= v and v <= self.max_version # type:ignore - def is_single_version(self): - return self.min_version >= self.max_version + def is_single_version(self) -> bool: + return self.min_version >= self.max_version # type:ignore - def is_earlier_than(self, v): - if type(v) is str: + def is_earlier_than(self, v: Union[str, STACVersionID]) -> bool: + if isinstance(v, str): v = STACVersionID(v) return self.max_version < v - def is_later_than(self, v): - if type(v) is str: + def is_later_than(self, v: Union[str, STACVersionID]) -> bool: + if isinstance(v, str): v = STACVersionID(v) return v < self.min_version - def __repr__(self): - return ''.format(self.min_version, self.max_version) + def __repr__(self) -> str: + return "".format(self.min_version, self.max_version) + + +class STACJSONDescription: + """Describes the STAC object information for a STAC object represented in JSON + + Attributes: + object_type (str): Describes the STAC object type. One of + :class:`~pystac.STACObjectType`. + version_range (STACVersionRange): The STAC version range that describes what + has been identified as potential valid versions of the stac object. + extensions (List[str]): List of extension schema URIs for extensions this + object implements + """ + + def __init__( + self, + object_type: "STACObjectType_Type", + version_range: STACVersionRange, + extensions: Set[str], + ) -> None: + self.object_type = object_type + self.version_range = version_range + self.extensions = extensions + def __repr__(self) -> str: + return "<{} {} ext={}>".format( + self.object_type, self.version_range, ",".join(self.extensions) + ) -def _identify_stac_extensions(object_type, d, version_range): + +def _identify_stac_extensions( + object_type: str, d: Dict[str, Any], version_range: STACVersionRange +) -> List[str]: """Identifies extensions for STAC Objects that don't list their extensions in a 'stac_extensions' property. Returns a list of stac_extensions. May mutate the version_range to update min or max version. """ - stac_extensions = set([]) + stac_extensions: Set[str] = set([]) # assets (collection assets) - if object_type == STACObjectType.ITEMCOLLECTION: - if 'assets' in d: - stac_extensions.add('assets') - version_range.set_min('0.8.0') + if object_type == pystac.STACObjectType.ITEMCOLLECTION: + if "assets" in d: + stac_extensions.add("assets") + version_range.set_min(STACVersionID("0.8.0")) # checksum - if 'links' in d: + if "links" in d: found_checksum = False - for link in d['links']: - if any(filter(lambda p: p.startswith('checksum:'), link)): + for link in d["links"]: + # Account for old links as dicts + if isinstance(link, str): + link_props = cast(Dict[str, Any], d["links"][link]).keys() + else: + link_props = cast(Dict[str, Any], link).keys() + + if any(prop.startswith("checksum:") for prop in link_props): found_checksum = True - stac_extensions.add(Extensions.CHECKSUM) + stac_extensions.add(OldExtensionShortIDs.CHECKSUM.value) if not found_checksum: - if 'assets' in d: - for asset in d['assets']: - if any(filter(lambda p: p.startswith('checksum:'), link)): + if "assets" in d: + for asset in d["assets"].values(): + asset_props = cast(Dict[str, Any], asset).keys() + if any(prop.startswith("checksum:") for prop in asset_props): found_checksum = True - stac_extensions.add(Extensions.CHECKSUM) + stac_extensions.add(OldExtensionShortIDs.CHECKSUM.value) if found_checksum: - version_range.set_min('0.6.2') + version_range.set_min(STACVersionID("0.6.2")) # datacube - if object_type == STACObjectType.ITEM: - if any(filter(lambda k: k.startswith('cube:'), d['properties'])): - stac_extensions.add(Extensions.DATACUBE) - version_range.set_min('0.6.1') + if object_type == pystac.STACObjectType.ITEM: + if any(k.startswith("cube:") for k in cast(Dict[str, Any], d["properties"])): + stac_extensions.add(OldExtensionShortIDs.DATACUBE.value) + version_range.set_min(STACVersionID("0.6.1")) # datetime-range (old extension) - if object_type == STACObjectType.ITEM: - if 'dtr:start_datetime' in d['properties']: - stac_extensions.add('datetime-range') - version_range.set_min('0.6.0') + if object_type == pystac.STACObjectType.ITEM: + if "dtr:start_datetime" in d["properties"]: + stac_extensions.add("datetime-range") + version_range.set_min(STACVersionID("0.6.0")) # eo - if object_type == STACObjectType.ITEM: - if any(filter(lambda k: k.startswith('eo:'), d['properties'])): - stac_extensions.add(Extensions.EO) - if 'eo:epsg' in d['properties']: - if d['properties']['eo:epsg'] is None: - version_range.set_min('0.6.1') - if 'eo:crs' in d['properties']: - version_range.set_max('0.4.1') - if 'eo:constellation' in d['properties']: - version_range.set_min('0.6.0') - if 'eo:bands' in d: - stac_extensions.add(Extensions.EO) - version_range.set_max('0.5.2') + if object_type == pystac.STACObjectType.ITEM: + if any(k.startswith("eo:") for k in cast(Dict[str, Any], d["properties"])): + stac_extensions.add(OldExtensionShortIDs.EO.value) + if "eo:epsg" in d["properties"]: + if d["properties"]["eo:epsg"] is None: + version_range.set_min(STACVersionID("0.6.1")) + if "eo:crs" in d["properties"]: + version_range.set_max(STACVersionID("0.4.1")) + if "eo:constellation" in d["properties"]: + version_range.set_min(STACVersionID("0.6.0")) + if "eo:bands" in d: + stac_extensions.add(OldExtensionShortIDs.EO.value) + version_range.set_max(STACVersionID("0.5.2")) # pointcloud - if object_type == STACObjectType.ITEM: - if any(filter(lambda k: k.startswith('pc:'), d['properties'])): - stac_extensions.add(Extensions.POINTCLOUD) - version_range.set_min('0.6.2') + if object_type == pystac.STACObjectType.ITEM: + if any(k.startswith("pc:") for k in cast(Dict[str, Any], d["properties"])): + stac_extensions.add(OldExtensionShortIDs.POINTCLOUD.value) + version_range.set_min(STACVersionID("0.6.2")) # sar - if object_type == STACObjectType.ITEM: - if any(filter(lambda k: k.startswith('sar:'), d['properties'])): - stac_extensions.add(Extensions.SAR) - version_range.set_min('0.6.2') - if version_range.contains('0.6.2'): + if object_type == pystac.STACObjectType.ITEM: + if any(k.startswith("sar:") for k in cast(Dict[str, Any], d["properties"])): + stac_extensions.add(OldExtensionShortIDs.SAR.value) + version_range.set_min(STACVersionID("0.6.2")) + if version_range.contains("0.6.2"): for prop in [ - 'sar:absolute_orbit', 'sar:resolution', 'sar:pixel_spacing', 'sar:looks' + "sar:absolute_orbit", + "sar:resolution", + "sar:pixel_spacing", + "sar:looks", ]: - if prop in d['properties']: - if isinstance(d['properties'][prop], list): - version_range.set_max('0.6.2') - if version_range.contains('0.7.0'): + if prop in d["properties"]: + if isinstance(d["properties"][prop], list): + version_range.set_max(STACVersionID("0.6.2")) + if version_range.contains("0.7.0"): for prop in [ - 'sar:incidence_angle', 'sar:relative_orbit', 'sar:observation_direction', - 'sar:resolution_range', 'sar:resolution_azimuth', 'sar:pixel_spacing_range', - 'sar:pixel_spacing_azimuth', 'sar:looks_range', 'sar:looks_azimuth', - 'sar:looks_equivalent_number' + "sar:incidence_angle", + "sar:relative_orbit", + "sar:observation_direction", + "sar:resolution_range", + "sar:resolution_azimuth", + "sar:pixel_spacing_range", + "sar:pixel_spacing_azimuth", + "sar:looks_range", + "sar:looks_azimuth", + "sar:looks_equivalent_number", ]: - if prop in d['properties']: - version_range.set_min('0.7.0') - if 'sar:absolute_orbit' in d['properties'] and not isinstance( - d['properties']['sar:absolute_orbit'], list): - version_range.set_min('0.7.0') - if 'sar:off_nadir' in d['properties']: - version_range.set_max('0.6.2') + if prop in d["properties"]: + version_range.set_min(STACVersionID("0.7.0")) + if "sar:absolute_orbit" in d["properties"] and not isinstance( + d["properties"]["sar:absolute_orbit"], list + ): + version_range.set_min(STACVersionID("0.7.0")) + if "sar:off_nadir" in d["properties"]: + version_range.set_max(STACVersionID("0.6.2")) # scientific - if object_type == STACObjectType.ITEM or object_type == STACObjectType.COLLECTION: - if 'properties' in d: - if any(filter(lambda k: k.startswith('sci:'), d['properties'])): - stac_extensions.add(Extensions.SCIENTIFIC) - version_range.set_min('0.6.0') + if ( + object_type == pystac.STACObjectType.ITEM + or object_type == pystac.STACObjectType.COLLECTION + ): + if "properties" in d: + prop_keys = cast(Dict[str, Any], d["properties"]).keys() + if any(k.startswith("sci:") for k in prop_keys): + stac_extensions.add(OldExtensionShortIDs.SCIENTIFIC.value) + version_range.set_min(STACVersionID("0.6.0")) # Single File STAC - if object_type == STACObjectType.ITEMCOLLECTION: - if 'collections' in d: - stac_extensions.add(Extensions.SINGLE_FILE_STAC) - version_range.set_min('0.8.0') - if 'stac_extensions' not in d: - version_range.set_max('0.8.1') + if object_type == pystac.STACObjectType.ITEMCOLLECTION: + if "collections" in d: + stac_extensions.add(OldExtensionShortIDs.SINGLE_FILE_STAC.value) + version_range.set_min(STACVersionID("0.8.0")) + if "stac_extensions" not in d: + version_range.set_max(STACVersionID("0.8.1")) return list(stac_extensions) -def _split_extensions(stac_extensions): - """Split extensions into common_extensions and custom_extensions""" - - common_extensions = [] - custom_extensions = [] - for ext in stac_extensions: - # Custom extensions are a URI - if ext.endswith('.json') or '/' in ext: - custom_extensions.append(ext) - else: - common_extensions.append(ext) - - return (common_extensions, custom_extensions) - - -def identify_stac_object_type(json_dict): +def identify_stac_object_type(json_dict: Dict[str, Any]) -> "STACObjectType_Type": """Determines the STACObjectType of the provided JSON dict. Args: @@ -264,30 +309,32 @@ def identify_stac_object_type(json_dict): """ object_type = None - if 'type' in json_dict: # Try to identify using 'type' property - for t in STACObjectType: - if json_dict['type'].lower() == t.value.lower(): + if "type" in json_dict: # Try to identify using 'type' property + for t in pystac.STACObjectType: + if json_dict["type"].lower() == t.value.lower(): object_type = t break if object_type is None: # Use old-approach based on other properties # Identify pre-1.0 ITEMCOLLECTION (since removed) - if 'type' in json_dict and 'assets' not in json_dict: - if 'stac_version' in json_dict and json_dict['stac_version'].startswith('0'): - if json_dict['type'] == 'FeatureCollection': - object_type = STACObjectType.ITEMCOLLECTION - - if 'extent' in json_dict: - object_type = STACObjectType.COLLECTION - elif 'assets' in json_dict: - object_type = STACObjectType.ITEM + if "type" in json_dict and "assets" not in json_dict: + if "stac_version" in json_dict and json_dict["stac_version"].startswith( + "0" + ): + if json_dict["type"] == "FeatureCollection": + object_type = pystac.STACObjectType.ITEMCOLLECTION + + if "extent" in json_dict: + object_type = pystac.STACObjectType.COLLECTION + elif "assets" in json_dict: + object_type = pystac.STACObjectType.ITEM else: - object_type = STACObjectType.CATALOG + object_type = pystac.STACObjectType.CATALOG return object_type -def identify_stac_object(json_dict): +def identify_stac_object(json_dict: Dict[str, Any]) -> STACJSONDescription: """Determines the STACJSONDescription of the provided JSON dict. Args: @@ -301,47 +348,63 @@ def identify_stac_object(json_dict): version_range = STACVersionRange() - stac_version = json_dict.get('stac_version') - stac_extensions = json_dict.get('stac_extensions', None) + stac_version = json_dict.get("stac_version") + stac_extensions = json_dict.get("stac_extensions", None) if stac_version is None: - if object_type == STACObjectType.CATALOG or object_type == STACObjectType.COLLECTION: - version_range.set_max('0.5.2') - elif object_type == STACObjectType.ITEM: - version_range.set_max('0.7.0') + if ( + object_type == pystac.STACObjectType.CATALOG + or object_type == pystac.STACObjectType.COLLECTION + ): + version_range.set_max(STACVersionID("0.5.2")) + elif object_type == pystac.STACObjectType.ITEM: + version_range.set_max(STACVersionID("0.7.0")) else: # ItemCollection - version_range.set_min('0.8.0') + version_range.set_min(STACVersionID("0.8.0")) else: version_range.set_to_single(stac_version) if stac_extensions is not None: - version_range.set_min('0.8.0') + version_range.set_min(STACVersionID("0.8.0")) if stac_extensions is None: # If this is post-0.8, we can assume there are no extensions # if the stac_extensions property doesn't exist for everything # but ItemCollection (except after 0.9.0, when ItemCollection also got # the stac_extensions property). - if version_range.is_earlier_than('0.8.0') or \ - (object_type == STACObjectType.ITEMCOLLECTION and not version_range.is_later_than( - '0.8.1')): - stac_extensions = _identify_stac_extensions(object_type, json_dict, version_range) + if version_range.is_earlier_than("0.8.0") or ( + object_type == pystac.STACObjectType.ITEMCOLLECTION + and not version_range.is_later_than("0.8.1") + ): + stac_extensions = _identify_stac_extensions( + object_type, json_dict, version_range + ) else: stac_extensions = [] + # Between 1.0.0-beta.2 and 1.0.0-RC1, STAC extensions changed from + # being split between 'common' and custom extensions, with common + # extensions having short names that were used in the stac_extensions + # property list, to being mostly externalized from the core spec and + # always identified with the schema URI as the identifier. This + # code translates the short name IDs used pre-1.0.0-RC1 to the + # relevant extension schema uri identifier. + if not version_range.is_single_version(): # Final Checks - if 'links' in json_dict: + if "links" in json_dict: # links were a dictionary only in 0.5 - if 'links' in json_dict and isinstance(json_dict['links'], dict): - version_range.set_to_single('0.5.2') + if "links" in json_dict and isinstance(json_dict["links"], dict): + version_range.set_to_single(STACVersionID("0.5.2")) # self links became non-required in 0.7.0 - if not version_range.is_earlier_than('0.7.0') and \ - not any(filter(lambda l: l['rel'] == 'self', - json_dict['links'])): - version_range.set_min('0.7.0') - - common_extensions, custom_extensions = _split_extensions(stac_extensions) - return STACJSONDescription(object_type, version_range, common_extensions, custom_extensions) + if not version_range.is_earlier_than("0.7.0") and not any( + filter( + lambda l: cast(Dict[str, Any], l)["rel"] == "self", + json_dict["links"], + ) + ): + version_range.set_min(STACVersionID("0.7.0")) + + return STACJSONDescription(object_type, version_range, set(stac_extensions)) diff --git a/pystac/serialization/migrate.py b/pystac/serialization/migrate.py index ed0945a03..79b5be6a6 100644 --- a/pystac/serialization/migrate.py +++ b/pystac/serialization/migrate.py @@ -1,244 +1,179 @@ -import re from copy import deepcopy +from typing import Any, Callable, Dict, List, Optional, Set, TYPE_CHECKING, Tuple -from pystac import STACObjectType +import pystac from pystac.version import STACVersion -from pystac.extensions import Extensions -from pystac.serialization.identify import (STACJSONDescription, STACVersionRange) +from pystac.serialization.identify import ( + OldExtensionShortIDs, + STACJSONDescription, + STACVersionID, +) -# STAC Object Types +if TYPE_CHECKING: + from pystac import STACObjectType as STACObjectType_Type -def _migrate_links(d, version): - if version < '0.6': - if 'links' in d: - if isinstance(d['links'], dict): - d['links'] = list(d['links'].values()) +def _migrate_links(d: Dict[str, Any], version: STACVersionID) -> None: + if version < "0.6": + if "links" in d: + if isinstance(d["links"], dict): + d["links"] = list(d["links"].values()) -def _migrate_catalog(d, version, info): +def _migrate_catalog( + d: Dict[str, Any], version: STACVersionID, info: STACJSONDescription +) -> None: _migrate_links(d, version) - if version < '0.8': - d['stac_extensions'] = info.common_extensions + info.custom_extensions + if version < "0.8": + d["stac_extensions"] = list(info.extensions) -def _migrate_collection(d, version, info): +def _migrate_collection( + d: Dict[str, Any], version: STACVersionID, info: STACJSONDescription +) -> None: _migrate_catalog(d, version, info) -def _migrate_item(d, version, info): +def _migrate_item( + d: Dict[str, Any], version: STACVersionID, info: STACJSONDescription +) -> None: _migrate_links(d, version) - if version < '0.8': - d['stac_extensions'] = info.common_extensions + info.custom_extensions + if version < "0.8": + d["stac_extensions"] = list(info.extensions) -def _migrate_itemcollection(d, version, info): - if version < '0.9.0': - d['stac_extensions'] = info.common_extensions + info.custom_extensions +def _migrate_itemcollection( + d: Dict[str, Any], version: STACVersionID, info: STACJSONDescription +) -> None: + if version < "0.9.0": + d["stac_extensions"] = list(info.extensions) # Extensions -def _migrate_item_assets(d, version, info): - if version < '1.0.0-beta.2': - if info.object_type == STACObjectType.COLLECTION: - if 'assets' in d: - d['item_assets'] = d['assets'] - del d['assets'] +def _migrate_item_assets( + d: Dict[str, Any], version: STACVersionID, info: STACJSONDescription +) -> Optional[Set[str]]: + if version < "1.0.0-beta.2": + if info.object_type == pystac.STACObjectType.COLLECTION: + if "assets" in d: + d["item_assets"] = d["assets"] + del d["assets"] + return None -def _migrate_checksum(d, version, info): - pass - - -def _migrate_datacube(d, version, info): - pass - - -def _migrate_datetime_range(d, version, info): - if version < '0.9': +def _migrate_datetime_range( + d: Dict[str, Any], version: STACVersionID, info: STACJSONDescription +) -> Optional[Set[str]]: + if version < "0.9": # Datetime range was removed - if 'dtr:start_datetime' in d['properties'] and 'start_datetime' not in d['properties']: - d['properties']['start_datetime'] = d['properties']['dtr:start_datetime'] - del d['properties']['dtr:start_datetime'] - - if 'dtr:end_datetime' in d['properties'] and 'end_datetime' not in d['properties']: - d['properties']['end_datetime'] = d['properties']['dtr:end_datetime'] - del d['properties']['dtr:end_datetime'] - - -def _migrate_eo(d, version, info): - added_extensions = set([]) - if version < '0.5': - if 'eo:crs' in d['properties']: - # Try to pull out the EPSG code. - # Otherwise, just leave it alone. - wkt = d['properties']['eo:crs'] - matches = list(re.finditer(r'AUTHORITY\[[^\]]*\"(\d+)"\]', wkt)) - if len(matches) > 0: - epsg_code = matches[-1].group(1) - d['properties'].pop('eo:crs') - d['properties']['eo:epsg'] = int(epsg_code) - - if version < '0.6': - # Change eo:bands from a dict to a list. eo:bands on an asset - # is an index instead of a dict key. eo:bands is in properties. - bands_dict = d['eo:bands'] - keys_to_indices = {} - bands = [] - for i, (k, band) in enumerate(bands_dict.items()): - keys_to_indices[k] = i - bands.append(band) - - d.pop('eo:bands') - d['properties']['eo:bands'] = bands - for k, asset in d['assets'].items(): - if 'eo:bands' in asset: - asset_band_indices = [] - for bk in asset['eo:bands']: - asset_band_indices.append(keys_to_indices[bk]) - asset['eo:bands'] = sorted(asset_band_indices) - - if version < '0.9': - # Some eo fields became common_metadata - if 'eo:platform' in d['properties'] and 'platform' not in d['properties']: - d['properties']['platform'] = d['properties']['eo:platform'] - del d['properties']['eo:platform'] - - if 'eo:instrument' in d['properties'] and 'instruments' not in d['properties']: - d['properties']['instruments'] = [d['properties']['eo:instrument']] - del d['properties']['eo:instrument'] - - if 'eo:constellation' in d['properties'] and 'constellation' not in d['properties']: - d['properties']['constellation'] = d['properties']['eo:constellation'] - del d['properties']['eo:constellation'] - - # Some eo fields became view extension fields - eo_to_view_fields = [ - 'off_nadir', 'azimuth', 'incidence_angle', 'sun_azimuth', 'sun_elevation' - ] - - view_enabled = 'view' in d['stac_extensions'] - for field in eo_to_view_fields: - if 'eo:{}'.format(field) in d['properties']: - if not view_enabled: - added_extensions.add('view') - view_enabled = True - if not 'view:{}'.format(field) in d['properties']: - d['properties']['view:{}'.format(field)] = \ - d['properties']['eo:{}'.format(field)] - del d['properties']['eo:{}'.format(field)] - - if version < '1.0.0-beta.1' and info.object_type == STACObjectType.ITEM: - # gsd moved from eo to common metadata - if 'eo:gsd' in d['properties']: - d['properties']['gsd'] = d['properties']['eo:gsd'] - del d['properties']['eo:gsd'] - - # The way bands were declared in assets changed. - # In 1.0.0-beta.1 they are inlined into assets as - # opposed to having indices back into a property-level array. - if 'eo:bands' in d['properties']: - bands = d['properties']['eo:bands'] - for asset in d['assets'].values(): - if 'eo:bands' in asset: - new_bands = [] - for band_index in asset['eo:bands']: - new_bands.append(bands[band_index]) - asset['eo:bands'] = new_bands - - return added_extensions - - -def _migrate_label(d, version, info): - if info.object_type == STACObjectType.ITEM and version < '1.0.0': - props = d['properties'] - # Migrate 0.8.0-rc1 non-pluralized forms - # As it's a common mistake, convert for any pre-1.0.0 version. - if 'label:property' in props and 'label:properties' not in props: - props['label:properties'] = props['label:property'] - del props['label:property'] - - if 'label:task' in props and 'label:tasks' not in props: - props['label:tasks'] = props['label:task'] - del props['label:task'] - - if 'label:overview' in props and 'label:overviews' not in props: - props['label:overviews'] = props['label:overview'] - del props['label:overview'] - - if 'label:method' in props and 'label:methods' not in props: - props['label:methods'] = props['label:method'] - del props['label:method'] - - -def _migrate_pointcloud(d, version, info): - pass - - -def _migrate_sar(d, version, info): - if version < '0.9': - # Some sar fields became common_metadata - if 'sar:platform' in d['properties'] and 'platform' not in d['properties']: - d['properties']['platform'] = d['properties']['sar:platform'] - del d['properties']['sar:platform'] - - if 'sar:instrument' in d['properties'] and 'instruments' not in d['properties']: - d['properties']['instruments'] = [d['properties']['sar:instrument']] - del d['properties']['sar:instrument'] - - if 'sar:constellation' in d['properties'] and 'constellation' not in d['properties']: - d['properties']['constellation'] = d['properties']['sar:constellation'] - del d['properties']['sar:constellation'] - - -def _migrate_scientific(d, version, info): - pass - - -def _migrate_single_file_stac(d, version, info): - pass - - -_object_migrations = { - STACObjectType.CATALOG: _migrate_catalog, - STACObjectType.COLLECTION: _migrate_collection, - STACObjectType.ITEM: _migrate_item, - STACObjectType.ITEMCOLLECTION: _migrate_itemcollection -} - -_extension_migrations = { - Extensions.CHECKSUM: _migrate_checksum, - Extensions.DATACUBE: _migrate_datacube, - Extensions.EO: _migrate_eo, - Extensions.ITEM_ASSETS: _migrate_item_assets, - Extensions.LABEL: _migrate_label, - Extensions.POINTCLOUD: _migrate_pointcloud, - Extensions.SAR: _migrate_sar, - Extensions.SCIENTIFIC: _migrate_scientific, - Extensions.SINGLE_FILE_STAC: _migrate_single_file_stac -} - -_removed_extension_migrations = { - # Removed in 0.9.0 - 'dtr': _migrate_datetime_range, - 'datetime-range': _migrate_datetime_range, - 'commons': lambda a, b, c: None # No changes needed, just remove the extension_id -} - -_extension_renames = {'asset': 'item-assets'} - - -def migrate_to_latest(json_dict, info): + if ( + "dtr:start_datetime" in d["properties"] + and "start_datetime" not in d["properties"] + ): + d["properties"]["start_datetime"] = d["properties"]["dtr:start_datetime"] + del d["properties"]["dtr:start_datetime"] + + if ( + "dtr:end_datetime" in d["properties"] + and "end_datetime" not in d["properties"] + ): + d["properties"]["end_datetime"] = d["properties"]["dtr:end_datetime"] + del d["properties"]["dtr:end_datetime"] + + return None + + +def _get_object_migrations() -> Dict[ + str, Callable[[Dict[str, Any], STACVersionID, STACJSONDescription], None] +]: + return { + pystac.STACObjectType.CATALOG: _migrate_catalog, + pystac.STACObjectType.COLLECTION: _migrate_collection, + pystac.STACObjectType.ITEM: _migrate_item, + pystac.STACObjectType.ITEMCOLLECTION: _migrate_itemcollection, + } + + +def _get_removed_extension_migrations() -> Dict[ + str, + Tuple[ + Optional[List["STACObjectType_Type"]], + Optional[ + Callable[ + [Dict[str, Any], STACVersionID, STACJSONDescription], Optional[Set[str]] + ] + ], + ], +]: # noqa + """Handles removed extensions. + + This does not handle renamed extension or extensions that were absorbed + by other extensions; for instance the FileExtensions handles the migration of + the since replaced 'checksum' extension. + + Dict of the extension ID to a tuple of optional list of STACObjectType which it was + removed for (or None if removed from all), and an optional migrate function + that can modify the object in case the extension was removed but the properties + were moved. + """ + return { + # -- Removed in 1.0 + # assets in collections became a core property + OldExtensionShortIDs.COLLECTION_ASSETS.value: (None, None), + # Extensions that were placed on Collections that applied to + # the 'commons' properties of their Items, but since the commons + # property merging has went away these extensions are removed + # from the collection. Note that a migrated Collection may still + # have a "properties" in extra_fields with the extension fields. + OldExtensionShortIDs.EO.value: ([pystac.STACObjectType.COLLECTION], None), + OldExtensionShortIDs.FILE.value: ([pystac.STACObjectType.COLLECTION], None), + OldExtensionShortIDs.LABEL.value: ([pystac.STACObjectType.COLLECTION], None), + OldExtensionShortIDs.POINTCLOUD.value: ( + [pystac.STACObjectType.COLLECTION], + None, + ), + OldExtensionShortIDs.PROJECTION.value: ( + [pystac.STACObjectType.COLLECTION], + None, + ), + OldExtensionShortIDs.SAR.value: ([pystac.STACObjectType.COLLECTION], None), + OldExtensionShortIDs.SAT.value: ([pystac.STACObjectType.COLLECTION], None), + OldExtensionShortIDs.TIMESTAMPS.value: ( + [pystac.STACObjectType.COLLECTION], + None, + ), + OldExtensionShortIDs.VIEW.value: ([pystac.STACObjectType.COLLECTION], None), + # tiled-assets was never a fully published extension; + # remove reference to the pre-1.0 RC short ID + OldExtensionShortIDs.TILED_ASSETS.value: (None, None), + # Single File STAC is a removed concept; is being reworked as of + # STAC 1.0.0-RC.3. Remove short ID from PySTAC as it's unsupported + OldExtensionShortIDs.SINGLE_FILE_STAC.value: (None, None), + # -- Removed in 0.9.0 + "dtr": (None, _migrate_datetime_range), + "datetime-range": (None, _migrate_datetime_range), + "commons": (None, None), + } + + +# TODO: Item Assets +def _get_extension_renames() -> Dict[str, str]: + return {"asset": "item-assets"} + + +def migrate_to_latest( + json_dict: Dict[str, Any], info: STACJSONDescription +) -> Dict[str, Any]: """Migrates the STAC JSON to the latest version Args: json_dict (dict): The dict of STAC JSON to identify. info (STACJSONDescription): The info from - :func:`~pystac.serialzation.identify.identify_stac_object` that describes + :func:`~pystac.serialization.identify.identify_stac_object` that describes the STAC object contained in the JSON dict. Returns: @@ -248,39 +183,29 @@ def migrate_to_latest(json_dict, info): result = deepcopy(json_dict) version = info.version_range.latest_valid_version() + object_migrations = _get_object_migrations() + removed_extension_migrations = _get_removed_extension_migrations() + if version != STACVersion.DEFAULT_STAC_VERSION: - _object_migrations[info.object_type](result, version, info) - - extensions_to_add = set([]) - for ext in info.common_extensions: - if ext in _extension_renames: - result['stac_extensions'].remove(ext) - ext = _extension_renames[ext] - extensions_to_add.add(ext) - - if ext in _extension_migrations: - added_extensions = _extension_migrations[ext](result, version, info) - if added_extensions: - extensions_to_add |= added_extensions - - if ext in _removed_extension_migrations: - _removed_extension_migrations[ext](result, version, info) - result['stac_extensions'].remove(ext) - - for ext in extensions_to_add: - result['stac_extensions'].append(ext) - - migrated_extensions = set(info.common_extensions) - migrated_extensions = migrated_extensions | set(extensions_to_add) - migrated_extensions = migrated_extensions - set(_removed_extension_migrations.keys()) - migrated_extensions = migrated_extensions - set(_extension_renames.keys()) - common_extensions = list(migrated_extensions) + object_migrations[info.object_type](result, version, info) + if "stac_extensions" not in result: + # Force stac_extensions property, as it makes + # downstream migration less complex + result["stac_extensions"] = [] + pystac.EXTENSION_HOOKS.migrate(result, version, info) + + for ext in result["stac_extensions"][:]: + if ext in removed_extension_migrations: + object_types, migration_fn = removed_extension_migrations[ext] + if object_types is None or info.object_type in object_types: + if migration_fn: + migration_fn(result, version, info) + result["stac_extensions"].remove(ext) + + result["stac_version"] = STACVersion.DEFAULT_STAC_VERSION else: - common_extensions = info.common_extensions - - result['stac_version'] = STACVersion.DEFAULT_STAC_VERSION + # Ensure stac_extensions property for consistency + if "stac_extensions" not in result: + result["stac_extensions"] = [] - return result, STACJSONDescription( - info.object_type, - STACVersionRange(STACVersion.DEFAULT_STAC_VERSION, STACVersion.DEFAULT_STAC_VERSION), - common_extensions, info.custom_extensions) + return result diff --git a/pystac/stac_io.py b/pystac/stac_io.py index 5e1e5a7ea..94e391875 100644 --- a/pystac/stac_io.py +++ b/pystac/stac_io.py @@ -1,61 +1,297 @@ +from abc import ABC, abstractmethod import os import json +from typing import ( + Any, + Callable, + Dict, + List, + Optional, + TYPE_CHECKING, + Tuple, + Type, + Union, +) +import warnings from urllib.parse import urlparse from urllib.request import urlopen from urllib.error import HTTPError +import pystac +import pystac.serialization -class STAC_IO: - """Methods used to read and save STAC json. - Allows users of the library to set their own methods - (e.g. for reading and writing from cloud storage) - """ - def default_read_text_method(uri): - """Default method for reading text. Only handles local file paths.""" - parsed = urlparse(uri) - if parsed.scheme != '': +# Use orjson if available +try: + import orjson +except ImportError: + orjson = None + +if TYPE_CHECKING: + from pystac.stac_object import STACObject as STACObject_Type + from pystac.catalog import Catalog as Catalog_Type + from pystac.link import Link as Link_Type + + +class StacIO(ABC): + _default_io: Optional[Type["StacIO"]] = None + + @abstractmethod + def read_text( + self, source: Union[str, "Link_Type"], *args: Any, **kwargs: Any + ) -> str: + """Read text from the given URI. + + The source to read from can be specified + as a string or a Link. If it's a string, it's the URL of the HREF from which to + read. When reading links, PySTAC will pass in the entire link body. + This enables implementations to utilize additional link information, + e.g. the "post" information in a pagination link from a STAC API search. + + Args: + source (str or pystac.Link): The source to read from. + + Returns: + str: The text contained in the file at the location specified by the uri. + """ + raise NotImplementedError("read_text not implemented") + + @abstractmethod + def write_text( + self, dest: Union[str, "Link_Type"], txt: str, *args: Any, **kwargs: Any + ) -> None: + """Write the given text to a file at the given URI. + + The destination to write to from can be specified + as a string or a Link. If it's a string, it's the URL of the HREF from which to + read. When writing based on links links, PySTAC will pass in the entire + link body. + + Args: + dest (str or pystac.Link): The destination to write to. + txt (str): The text to write. + """ + raise NotImplementedError("write_text not implemented") + + def _json_loads(self, txt: str, source: Union[str, "Link_Type"]) -> Dict[str, Any]: + if orjson is not None: + return orjson.loads(txt) + else: + return json.loads(self.read_text(txt)) + + def _json_dumps( + self, json_dict: Dict[str, Any], source: Union[str, "Link_Type"] + ) -> str: + if orjson is not None: + return orjson.dumps(json_dict, option=orjson.OPT_INDENT_2).decode("utf-8") + else: + return json.dumps(json_dict, indent=2) + + def stac_object_from_dict( + self, + d: Dict[str, Any], + href: Optional[str] = None, + root: Optional["Catalog_Type"] = None, + ) -> "STACObject_Type": + result = pystac.serialization.stac_object_from_dict(d, href, root) + if isinstance(result, pystac.Catalog): + # Set the stac_io instance for usage by io operations + # where this catalog is the root. + result._stac_io = self + return result + + def read_json(self, source: Union[str, "Link_Type"]) -> Dict[str, Any]: + """Read a dict from the given source. + + See :func:`StacIO.read_text ` for usage of + str vs Link as a parameter. + + Args: + source (str or Link): The source from which to read. + + Returns: + dict: A dict representation of the JSON contained in the file at the + given source. + """ + txt = self.read_text(source) + return self._json_loads(txt, source) + + def read_stac_object( + self, source: Union[str, "Link_Type"], root: Optional["Catalog_Type"] = None + ) -> "STACObject_Type": + """Read a STACObject from a JSON file at the given source. + + See :func:`StacIO.read_text ` for usage of + str vs Link as a parameter. + + Args: + source (str or pystac.Link): The source from which to read. + root (Catalog or Collection): Optional root of the catalog for this object. + If provided, the root's resolved object cache can be used to search for + previously resolved instances of the STAC object. + + Returns: + STACObject: The deserialized STACObject from the serialized JSON + contained in the file at the given uri. + """ + d = self.read_json(source) + href = source if isinstance(source, str) else source.get_absolute_href() + return self.stac_object_from_dict(d, href=href, root=root) + + def save_json( + self, dest: Union[str, "Link_Type"], json_dict: Dict[str, Any] + ) -> None: + """Write a dict to the given URI as JSON. + + See :func:`StacIO.write_text ` for usage of + str vs Link as a parameter. + + Args: + dest (str or pystac.Link): The destination file to write the text to. + json_dict (dict): The JSON dict to write. + """ + txt = self._json_dumps(json_dict, dest) + self.write_text(dest, txt) + + @classmethod + def set_default(cls, stac_io_class: Type["StacIO"]) -> None: + """Set the default StacIO instance to use.""" + cls._default_io = stac_io_class + + @classmethod + def default(cls) -> "StacIO": + if cls._default_io is None: + cls._default_io = DefaultStacIO + + return cls._default_io() + + +class DefaultStacIO(StacIO): + def read_text( + self, source: Union[str, "Link_Type"], *args: Any, **kwargs: Any + ) -> str: + if isinstance(source, str): + href = source + else: + href = source.get_absolute_href() + if href is None: + raise IOError(f"Could not get an absolute HREF from link {source}") + + parsed = urlparse(href) + if parsed.scheme != "": try: - with urlopen(uri) as f: - return f.read().decode('utf-8') + with urlopen(href) as f: + return f.read().decode("utf-8") except HTTPError as e: - raise Exception("Could not read uri {}".format(uri)) from e + raise Exception("Could not read uri {}".format(href)) from e else: - with open(uri) as f: + with open(href) as f: return f.read() - def default_write_text_method(uri, txt): - """Default method for writing text. Only handles local file paths.""" - dirname = os.path.dirname(uri) - if dirname != '' and not os.path.isdir(dirname): + def write_text( + self, dest: Union[str, "Link_Type"], txt: str, *args: Any, **kwargs: Any + ) -> None: + if isinstance(dest, str): + href = dest + else: + href = dest.get_absolute_href() + if href is None: + raise IOError(f"Could not get an absolute HREF from link {dest}") + + dirname = os.path.dirname(href) + if dirname != "" and not os.path.isdir(dirname): os.makedirs(dirname) - with open(uri, 'w') as f: + with open(href, "w") as f: f.write(txt) - read_text_method = default_read_text_method - """Users of PySTAC can replace the read_text_method in order - to expand the ability of PySTAC to read different file systems. - For example, a client of the library might replace this class - member in it's own __init__.py with a method that can read from - cloud storage. + +class DuplicateObjectKeyError(Exception): + pass + + +class DuplicateKeyReportingMixin(StacIO): + """A mixin for StacIO implementations that will report + on duplicate keys in the JSON being read in. + + See https://github.com/stac-utils/pystac/issues/313 """ - write_text_method = default_write_text_method - """Users of PySTAC can replace the write_text_method in order - to expand the ability of PySTAC to write to different file systems. - For example, a client of the library might replace this class - member in it's own __init__.py with a method that can read from - cloud storage. + def _json_loads(self, txt: str, source: Union[str, "Link_Type"]) -> Dict[str, Any]: + return json.loads( + txt, object_pairs_hook=self.duplicate_object_names_report_builder(source) + ) + + @staticmethod + def duplicate_object_names_report_builder( + source: Union[str, "Link_Type"] + ) -> Callable[[List[Tuple[str, Any]]], Dict[str, Any]]: + def report_duplicate_object_names( + object_pairs: List[Tuple[str, Any]] + ) -> Dict[str, Any]: + result: Dict[str, Any] = {} + for key, value in object_pairs: + if key in result: + url = ( + source + if isinstance(source, str) + else source.get_absolute_href() + ) + raise DuplicateObjectKeyError( + f"Found duplicate object name “{key}” in “{url}”" + ) + else: + result[key] = value + return result + + return report_duplicate_object_names + + +class STAC_IO: + """DEPRECATED: Methods used to read and save STAC json. + Allows users of the library to set their own methods + (e.g. for reading and writing from cloud storage) + + Note: The static methods of this class are deprecated. Move to using + instance methods of a specific instance of StacIO. """ - # Replaced in __init__ to account for extension objects. - _stac_object_from_dict = None + @staticmethod + def read_text_method(uri: str) -> str: + warnings.warn( + "STAC_IO is deprecated. " + "Please use instances of StacIO (e.g. StacIO.default()).", + DeprecationWarning, + ) + return StacIO.default().read_text(uri) + + @staticmethod + def write_text_method(uri: str, txt: str) -> None: + """Default method for writing text.""" + warnings.warn( + "STAC_IO is deprecated. " + "Please use instances of StacIO (e.g. StacIO.default()).", + DeprecationWarning, + ) + return StacIO.default().write_text(uri, txt) + + @staticmethod + def stac_object_from_dict( + d: Dict[str, Any], + href: Optional[str] = None, + root: Optional["Catalog_Type"] = None, + ) -> "STACObject_Type": + warnings.warn( + "STAC_IO is deprecated. " + "Please use instances of StacIO (e.g. StacIO.default()).", + DeprecationWarning, + ) + return pystac.serialization.stac_object_from_dict(d, href, root) # This is set in __init__.py _STAC_OBJECT_CLASSES = None @classmethod - def read_text(cls, uri): + def read_text(cls, uri: str) -> str: """Read text from the given URI. Args: @@ -66,14 +302,14 @@ def read_text(cls, uri): Note: This method uses the :func:`STAC_IO.read_text_method - `. If you want to modify the behavior of + `. If you want to modify the behavior of STAC_IO in order to enable additional URI types, replace that member with your own implementation. """ return cls.read_text_method(uri) @classmethod - def write_text(cls, uri, txt): + def write_text(cls, uri: str, txt: str) -> None: """Write the given text to a file at the given URI. Args: @@ -82,14 +318,14 @@ def write_text(cls, uri, txt): Note: This method uses the :func:`STAC_IO.write_text_method - `. If you want to modify the behavior of + `. If you want to modify the behavior of STAC_IO in order to enable additional URI types, replace that member with your own implementation. """ cls.write_text_method(uri, txt) @classmethod - def read_json(cls, uri): + def read_json(cls, uri: str) -> Dict[str, Any]: """Read a dict from the given URI. Args: @@ -101,14 +337,16 @@ def read_json(cls, uri): Note: This method uses the :func:`STAC_IO.read_text_method - `. If you want to modify the behavior of + `. If you want to modify the behavior of STAC_IO in order to enable additional URI types, replace that member with your own implementation. """ return json.loads(STAC_IO.read_text(uri)) @classmethod - def read_stac_object(cls, uri, root=None): + def read_stac_object( + cls, uri: str, root: Optional["Catalog_Type"] = None + ) -> "STACObject_Type": """Read a STACObject from a JSON file at the given URI. Args: @@ -123,15 +361,15 @@ def read_stac_object(cls, uri, root=None): Note: This method uses the :func:`STAC_IO.read_text_method - `. If you want to modify the behavior of + `. If you want to modify the behavior of STAC_IO in order to enable additional URI types, replace that member with your own implementation. """ d = cls.read_json(uri) - return cls.stac_object_from_dict(d, href=uri, root=root) + return cls.stac_object_from_dict(d, uri, root) @classmethod - def save_json(cls, uri, json_dict): + def save_json(cls, uri: str, json_dict: Dict[str, Any]) -> None: """Write a dict to the given URI as JSON. Args: @@ -140,7 +378,7 @@ def save_json(cls, uri, json_dict): Note: This method uses the :func:`STAC_IO.write_text_method - `. If you want to modify the behavior of + `. If you want to modify the behavior of STAC_IO in order to enable additional URI types, replace that member with your own implementation. """ diff --git a/pystac/stac_object.py b/pystac/stac_object.py index 0f5eebaf5..8a303a665 100644 --- a/pystac/stac_object.py +++ b/pystac/stac_object.py @@ -1,113 +1,69 @@ -from abc import (ABC, abstractmethod) +from abc import ABC, abstractmethod from enum import Enum +from typing import Any, Dict, Iterable, List, Optional, cast, TYPE_CHECKING import pystac from pystac import STACError from pystac.link import Link -from pystac.stac_io import STAC_IO -from pystac.utils import (is_absolute_href, make_absolute_href) -from pystac.extensions import ExtensionError +from pystac.utils import is_absolute_href, make_absolute_href + +if TYPE_CHECKING: + from pystac.catalog import Catalog as Catalog_Type class STACObjectType(str, Enum): - def __str__(self): + def __str__(self) -> str: return str(self.value) - CATALOG = 'CATALOG' - COLLECTION = 'COLLECTION' - ITEM = 'ITEM' - ITEMCOLLECTION = 'ITEMCOLLECTION' - + CATALOG = "CATALOG" + COLLECTION = "COLLECTION" + ITEM = "ITEM" + ITEMCOLLECTION = "ITEMCOLLECTION" -class ExtensionIndex: - """Defines methods for accessing extension functionality. - To access a specific extension, use the __getitem__ on this class with the - extension ID:: +class STACObject(ABC): + """A STACObject is the base class for any element of STAC that + has links e.g. (Catalogs, Collections, or Items). A STACObject has + common functionality, can be converted to and from Python ``dicts`` representing + JSON, and can be cloned or copied. - # Access the "bands" property on the eo extension. - item.ext['eo'].bands + Attributes: + links (List[Link]): A list of :class:`~pystac.Link` objects representing + all links associated with this STACObject. """ - def __init__(self, stac_object): - self.stac_object = stac_object - - def __getitem__(self, extension_id): - """Gets the extension object for the given extension. - - Returns: - CatalogExtension or CollectionExtension or ItemExtension: The extension object - through which you can access the extension functionality for the extension represented - by the extension_id. - """ - # Check to make sure this is a registered extension. - if not pystac.STAC_EXTENSIONS.is_registered_extension(extension_id): - raise ExtensionError("'{}' is not an extension " - "registered with PySTAC".format(extension_id)) - - if not self.implements(extension_id): - raise ExtensionError("{} does not implement the {} extension. " - "Use the 'ext.enable' method to enable this extension " - "first.".format(self.stac_object, extension_id)) - - return pystac.STAC_EXTENSIONS.extend_object(extension_id, self.stac_object) - - def __getattr__(self, extension_id): - """Gets an extension based on a dynamic attribute. - - This takes the attribute name and passes it to __getitem__. - - This allows the following two lines to be equivalent:: - - item.ext["label"].label_properties - item.ext.label.label_properties - """ - if extension_id.startswith('__') and hasattr(ExtensionIndex, extension_id): - return self.__getattribute__(extension_id) - return self[extension_id] - def enable(self, extension_id): - """Enables a stac extension for the given object. If the object already - enables the extension, no action is taken. If it does not, the extension ID is - added to the object's stac_extension property. + id: str - Args: - extension_id (str): The extension ID representing the extension - the object should implement + STAC_OBJECT_TYPE: STACObjectType - """ - pystac.STAC_EXTENSIONS.enable_extension(extension_id, self.stac_object) + def __init__(self, stac_extensions: List[str]) -> None: + self.links: List[Link] = [] + self.stac_extensions = stac_extensions - def implements(self, extension_id): - """Returns true if the associated object implements the given extension. + def validate(self) -> List[Any]: + """Validate this STACObject. - Args: - extension_id (str): The extension ID to check + Returns a list of validation results, which depends on the validation + implementation. For JSON Schema validation, this will be a list + of schema URIs that were used during validation. - Returns: - [bool]: True if the object implements the extensions - i.e. if - the extension ID is in the "stac_extensions" property. + Raises: + STACValidationError """ - return (self.stac_object.stac_extensions is not None - and extension_id in self.stac_object.stac_extensions) - + import pystac.validation -class LinkMixin: - """Mixin class for adding and accessing links. + return pystac.validation.validate(self) # type:ignore - Implementing classes must have a `links` attribute that is - a list of links. - """ - def add_link(self, link): + def add_link(self, link: Link) -> None: """Add a link to this object's set of links. Args: link (Link): The link to add. """ - link.set_owner(self) + link.set_owner(cast(STACObject, self)) self.links.append(link) - return self - def add_links(self, links): + def add_links(self, links: List[Link]) -> None: """Add links to this object's set of links. Args: @@ -116,9 +72,8 @@ def add_links(self, links): for link in links: self.add_link(link) - return self - def remove_links(self, rel): + def remove_links(self, rel: str) -> None: """Remove links to this object's set of links that match the given ``rel``. Args: @@ -126,9 +81,8 @@ def remove_links(self, rel): """ self.links = [link for link in self.links if link.rel != rel] - return self - def get_single_link(self, rel): + def get_single_link(self, rel: str) -> Optional[Link]: """Get single link that match the given ``rel``. Args: @@ -137,7 +91,7 @@ def get_single_link(self, rel): return next((link for link in self.links if link.rel == rel), None) - def get_links(self, rel=None): + def get_links(self, rel: Optional[str] = None) -> List[Link]: """Gets the :class:`~pystac.Link` instances associated with this object. Args: @@ -153,7 +107,7 @@ def get_links(self, rel=None): else: return [link for link in self.links if link.rel == rel] - def clear_links(self, rel=None): + def clear_links(self, rel: Optional[str] = None) -> None: """Clears all :class:`~pystac.Link` instances associated with this object. Args: @@ -163,9 +117,8 @@ def clear_links(self, rel=None): self.links = [link for link in self.links if link.rel != rel] else: self.links = [] - return self - def get_root_link(self): + def get_root_link(self) -> Optional[Link]: """Get the :class:`~pystac.Link` representing the root for this object. @@ -173,9 +126,23 @@ def get_root_link(self): :class:`~pystac.Link` or None: The root link for this object, or ``None`` if no root link is set. """ - return self.get_single_link('root') + return self.get_single_link("root") - def get_self_href(self): + @property + def self_href(self) -> str: + """Gets the absolute HREF that is represented by the ``rel == 'self'`` + :class:`~pystac.Link`. + + Raises: + ValueError: If the self_href is not set, this method will throw + a ValueError. Use get_self_href if there may not be an href set. + """ + result = self.get_self_href() + if result is None: + raise ValueError(f"{self} does not have a self_href set.") + return result + + def get_self_href(self) -> Optional[str]: """Gets the absolute HREF that is represented by the ``rel == 'self'`` :class:`~pystac.Link`. @@ -190,13 +157,13 @@ def get_self_href(self): have the HREF the file was read from set as it's self HREF. All self links have absolute (as opposed to relative) HREFs. """ - self_link = self.get_single_link('self') + self_link = self.get_single_link("self") if self_link: - return self_link.target + return cast(str, self_link.target) else: return None - def set_self_href(self, href): + def set_self_href(self, href: Optional[str]) -> None: """Sets the absolute HREF that is represented by the ``rel == 'self'`` :class:`~pystac.Link`. @@ -208,44 +175,20 @@ def set_self_href(self, href): """ root_link = self.get_root_link() if root_link is not None and root_link.is_resolved(): - root_link.target._resolved_objects.remove(self) + cast(pystac.Catalog, root_link.target)._resolved_objects.remove( + cast(STACObject, self) + ) - self.remove_links('self') + self.remove_links("self") if href is not None: self.add_link(Link.self_href(href)) if root_link is not None and root_link.is_resolved(): - root_link.target._resolved_objects.cache(self) - - return self + cast(pystac.Catalog, root_link.target)._resolved_objects.cache( + cast(STACObject, self) + ) - -class STACObject(LinkMixin, ABC): - """A STACObject is the base class for any element of STAC that - has links e.g. (Catalogs, Collections, or Items). A STACObject has - common functionality, can be converted to and from Python ``dicts`` representing - JSON, and can be cloned or copied. - - Attributes: - links (List[Link]): A list of :class:`~pystac.Link` objects representing - all links associated with this STACObject. - """ - - STAC_OBJECT_TYPE = None # Overridden by the child classes with their type. - - def __init__(self, stac_extensions): - self.links = [] - self.stac_extensions = stac_extensions - - def validate(self): - """Validate this STACObject. - - Raises: - STACValidationError - """ - return pystac.validation.validate(self) - - def get_root(self): + def get_root(self) -> Optional["Catalog_Type"]: """Get the :class:`~pystac.Catalog` or :class:`~pystac.Collection` to the root for this object. The root is represented by a :class:`~pystac.Link` with ``rel == 'root'``. @@ -259,12 +202,12 @@ def get_root(self): if not root_link.is_resolved(): root_link.resolve_stac_object() # Use set_root, so Catalogs can merge ResolvedObjectCache instances. - self.set_root(root_link.target) - return root_link.target + self.set_root(cast(pystac.Catalog, root_link.target)) + return cast(pystac.Catalog, root_link.target) else: return None - def set_root(self, root): + def set_root(self, root: Optional["Catalog_Type"]) -> None: """Sets the root :class:`~pystac.Catalog` or :class:`~pystac.Collection` for this object. @@ -272,17 +215,18 @@ def set_root(self, root): root (Catalog, Collection or None): The root object to set. Passing in None will clear the root. """ - root_link_index = next(iter([i for i, link in enumerate(self.links) if link.rel == 'root']), - None) + root_link_index = next( + iter([i for i, link in enumerate(self.links) if link.rel == "root"]), None + ) # Remove from old root resolution cache if root_link_index is not None: root_link = self.links[root_link_index] if root_link.is_resolved(): - root_link.target._resolved_objects.remove(self) + cast(pystac.Catalog, root_link.target)._resolved_objects.remove(self) if root is None: - self.remove_links('root') + self.remove_links("root") else: new_root_link = Link.root(root) if root_link_index is not None: @@ -292,9 +236,7 @@ def set_root(self, root): self.add_link(new_root_link) root._resolved_objects.cache(self) - return self - - def get_parent(self): + def get_parent(self) -> Optional["Catalog_Type"]: """Get the :class:`~pystac.Catalog` or :class:`~pystac.Collection` to the parent for this object. The root is represented by a :class:`~pystac.Link` with ``rel == 'parent'``. @@ -304,13 +246,13 @@ def get_parent(self): The parent object for this object, or ``None`` if no root link is set. """ - parent_link = self.get_single_link('parent') + parent_link = self.get_single_link("parent") if parent_link: - return parent_link.resolve_stac_object().target + return cast(pystac.Catalog, parent_link.resolve_stac_object().target) else: return None - def set_parent(self, parent): + def set_parent(self, parent: Optional["Catalog_Type"]) -> None: """Sets the parent :class:`~pystac.Catalog` or :class:`~pystac.Collection` for this object. @@ -319,12 +261,11 @@ def set_parent(self, parent): object to set. Passing in None will clear the parent. """ - self.remove_links('parent') + self.remove_links("parent") if parent is not None: self.add_link(Link.parent(parent)) - return self - def get_stac_objects(self, rel): + def get_stac_objects(self, rel: str) -> Iterable["STACObject"]: """Gets the :class:`~pystac.STACObject` instances that are linked to by links with their ``rel`` property matching the passed in argument. @@ -333,7 +274,7 @@ def get_stac_objects(self, rel): ``rel`` property against. Returns: - Generator[STACObjects]: A possibly empty generator of STACObjects that are + Iterable[STACObjects]: A possibly empty iterable of STACObjects that are connected to this object through links with the given ``rel``. """ links = self.links[:] @@ -341,35 +282,60 @@ def get_stac_objects(self, rel): link = links[i] if link.rel == rel: link.resolve_stac_object(root=self.get_root()) - yield link.target - - def save_object(self, include_self_link=True, dest_href=None): + yield cast("STACObject", link.target) + + def save_object( + self, + include_self_link: bool = True, + dest_href: Optional[str] = None, + stac_io: Optional[pystac.StacIO] = None, + ) -> None: """Saves this STAC Object to it's 'self' HREF. Args: - include_self_link (bool): If this is true, include the 'self' link with this object. - Otherwise, leave out the self link. - dest_href (str): Optional HREF to save the file to. If None, the object will be saved - to the object's self href. + include_self_link (bool): If this is true, include the 'self' link with + this object. Otherwise, leave out the self link. + dest_href (str): Optional HREF to save the file to. If None, the object + will be saved to the object's self href. + stac_io: Optional instance of StacIO to use. If not provided, will use the + instance set on the object's root if available, otherwise will use the + default instance. + Raises: - :class:`~pystac.STACError`: If no self href is set, this error will be raised. + :class:`~pystac.STACError`: If no self href is set, this error will be + raised. Note: When to include a self link is described in the `Use of Links section of the STAC best practices document `_ """ + if stac_io is None: + root = self.get_root() + if root is not None: + root_stac_io = root._stac_io + if root_stac_io is not None: + stac_io = root_stac_io + + if stac_io is None: + stac_io = pystac.StacIO.default() + if dest_href is None: self_href = self.get_self_href() if self_href is None: raise STACError( - 'Self HREF must be set before saving without an explicit dest_href.') + "Self HREF must be set before saving without an explicit dest_href." + ) dest_href = self_href - STAC_IO.save_json(dest_href, self.to_dict(include_self_link=include_self_link)) + stac_io.save_json(dest_href, self.to_dict(include_self_link=include_self_link)) - def full_copy(self, root=None, parent=None): + def full_copy( + self, + root: Optional["Catalog_Type"] = None, + parent: Optional["Catalog_Type"] = None, + ) -> "STACObject": """Create a full copy of this STAC object and any stac objects linked to by this object. @@ -385,9 +351,10 @@ def full_copy(self, root=None, parent=None): """ clone = self.clone() - if root is None: + if root is None and isinstance(clone, pystac.Catalog): root = clone - clone.set_root(root) + + clone.set_root(cast(pystac.Catalog, root)) if parent: clone.set_parent(parent) @@ -395,45 +362,37 @@ def full_copy(self, root=None, parent=None): for link in clone.links: if link.rel in link_rels: link.resolve_stac_object() - target = link.target - if target in root._resolved_objects: - target = root._resolved_objects.get(target) + target = cast(STACObject, link.target) + if root is not None and target in root._resolved_objects: + cached_target = root._resolved_objects.get(target) + assert cached_target is not None + target = cached_target else: - copied_target = target.full_copy(root=root, parent=clone) - root._resolved_objects.cache(copied_target) + target_parent = None + if link.rel in ["child", "item"] and isinstance( + clone, pystac.Catalog + ): + target_parent = clone + copied_target = target.full_copy(root=root, parent=target_parent) + if root is not None: + root._resolved_objects.cache(copied_target) target = copied_target - if link.rel in ['child', 'item']: + if link.rel in ["child", "item"]: target.set_root(root) - target.set_parent(clone) + if isinstance(clone, pystac.Catalog): + target.set_parent(clone) link.target = target return clone - @property - def ext(self): - """Access extensions for this STACObject. - - Example: - This example shows accessing a Item's EO extension functionality - that gets the band information for an asset:: - - item = pystac.read_file("eo_item.json") - bands = item.ext.eo.get_asset_bands(item.assets["image"]) - - Returns: - ExtensionIndex: The object that can be used to access extension information - and functionality. - """ - return ExtensionIndex(self) - - def resolve_links(self): + def resolve_links(self) -> None: """Ensure all STACObjects linked to by this STACObject are resolved. This is important for operations such as changing HREFs. This method mutates the entire catalog tree. """ - link_rels = set(self._object_links()) | set(['root', 'parent']) + link_rels = set(self._object_links()) | set(["root", "parent"]) for link in self.links: if link.rel in link_rels: @@ -441,7 +400,7 @@ def resolve_links(self): link.resolve_stac_object(root=self.get_root()) @abstractmethod - def _object_links(self): + def _object_links(self) -> List[str]: """Inherited classes return a list of link 'rel' types that represent STACObjects linked to by this object (not including root, parent or self). This can include optional relations (which may not be present). @@ -449,20 +408,19 @@ def _object_links(self): pass @abstractmethod - def to_dict(self, include_self_link=True): + def to_dict(self, include_self_link: bool = True) -> Dict[str, Any]: """Generate a dictionary representing the JSON of this serialized object. Args: include_self_link (bool): If True, the dict will contain a self link to this object. If False, the self link will be omitted. - Returns: - dict: A serializion of the object that can be written out as JSON. + dict: A serialization of the object that can be written out as JSON. """ pass @abstractmethod - def clone(self): + def clone(self) -> "STACObject": """Clones this object. Cloning an object will make a copy of all properties and links of the object; @@ -476,24 +434,27 @@ def clone(self): pass @classmethod - def from_file(cls, href): + def from_file( + cls, href: str, stac_io: Optional[pystac.StacIO] = None + ) -> "STACObject": """Reads a STACObject implementation from a file. Args: href (str): The HREF to read the object from. + stac_io: Optional instance of StacIO to use. If not provided, will use the + default instance. Returns: The specific STACObject implementation class that is represented by the JSON read from the file located at HREF. """ + if stac_io is None: + stac_io = pystac.StacIO.default() + if not is_absolute_href(href): href = make_absolute_href(href) - d = STAC_IO.read_json(href) - if cls == STACObject: - o = STAC_IO.stac_object_from_dict(d, href=href) - else: - o = cls.from_dict(d, href=href) + o = stac_io.read_stac_object(href) # Set the self HREF, if it's not already set to something else. if o.get_self_href() is None: @@ -504,12 +465,18 @@ def from_file(cls, href): if root_link is not None: if not root_link.is_resolved(): if root_link.get_absolute_href() == href: - o.set_root(o) + o.set_root(cast(pystac.Catalog, o)) return o @classmethod @abstractmethod - def from_dict(cls, d, href=None, root=None): + def from_dict( + cls, + d: Dict[str, Any], + href: Optional[str] = None, + root: Optional["Catalog_Type"] = None, + migrate: bool = False, + ) -> "STACObject": """Parses this STACObject from the passed in dictionary. Args: @@ -519,6 +486,8 @@ def from_dict(cls, d, href=None, root=None): root (Catalog or Collection): Optional root of the catalog for this object. If provided, the root's resolved object cache can be used to search for previously resolved instances of the STAC object. + migrate: Use True if this dict represents JSON from an older STAC object, + so that migrations are run against it. Returns: STACObject: The STACObject parsed from this dict. diff --git a/pystac/utils.py b/pystac/utils.py index 534e3bfae..d1c9a78af 100644 --- a/pystac/utils.py +++ b/pystac/utils.py @@ -1,7 +1,9 @@ import os import posixpath -from urllib.parse import (urlparse, ParseResult as URLParseResult) -from datetime import timezone +from pystac.errors import RequiredPropertyMissing +from typing import Any, Callable, Dict, List, Optional, TypeVar, Union +from urllib.parse import urlparse, ParseResult as URLParseResult +from datetime import datetime, timezone import dateutil.parser # Allow for modifying the path library for testability @@ -9,25 +11,27 @@ _pathlib = os.path -def _urlparse(href): +def _urlparse(href: str) -> URLParseResult: """Version of URL parse that takes into account windows paths. A windows absolute path will be parsed with a scheme from urllib.parse.urlparse. This method will take this into account. """ parsed = urlparse(href) - if parsed.scheme != '' and href.lower().startswith('{}:\\'.format(parsed.scheme)): - return URLParseResult(scheme='', - netloc='', - path='{}:{}'.format(parsed.scheme, parsed.path), - params=parsed.params, - query=parsed.query, - fragment=parsed.fragment) + if parsed.scheme != "" and href.lower().startswith("{}:\\".format(parsed.scheme)): + return URLParseResult( + scheme="", + netloc="", + path="{}:{}".format(parsed.scheme, parsed.path), + params=parsed.params, + query=parsed.query, + fragment=parsed.fragment, + ) else: return parsed -def _join(is_path, *args): +def _join(is_path: bool, *args: str) -> str: """Version of os.path.join that takes into account whether or not we are working with a URL. @@ -39,7 +43,9 @@ def _join(is_path, *args): return posixpath.join(*args) -def make_relative_href(source_href, start_href, start_is_dir=False): +def make_relative_href( + source_href: str, start_href: str, start_is_dir: bool = False +) -> str: """Makes a given HREF relative to the given starting HREF. Args: @@ -47,7 +53,8 @@ def make_relative_href(source_href, start_href, start_is_dir=False): start_href (str): The HREF that the resulting HREF will be relative with respect to. start_is_dir (str): If True, the start_href is treated as a directory. - Otherwise, the start_href is considered to be a file HREF. Defaults to False. + Otherwise, the start_href is considered to be a file HREF. + Defaults to False. Returns: str: The relative HREF. If the source_href and start_href do not share a common @@ -56,11 +63,13 @@ def make_relative_href(source_href, start_href, start_is_dir=False): parsed_source = _urlparse(source_href) parsed_start = _urlparse(start_href) - if not (parsed_source.scheme == parsed_start.scheme - and parsed_source.netloc == parsed_start.netloc): + if not ( + parsed_source.scheme == parsed_start.scheme + and parsed_source.netloc == parsed_start.netloc + ): return source_href - is_path = parsed_start.scheme == '' + is_path = parsed_start.scheme == "" if start_is_dir: start_dir = parsed_start.path @@ -68,14 +77,16 @@ def make_relative_href(source_href, start_href, start_is_dir=False): start_dir = _pathlib.dirname(parsed_start.path) relpath = _pathlib.relpath(parsed_source.path, start_dir) if not is_path: - relpath = relpath.replace('\\', '/') - if not relpath.startswith('.'): - relpath = _join(is_path, '.', relpath) + relpath = relpath.replace("\\", "/") + if not relpath.startswith("."): + relpath = _join(is_path, ".", relpath) return relpath -def make_absolute_href(source_href, start_href=None, start_is_dir=False): +def make_absolute_href( + source_href: str, start_href: Optional[str] = None, start_is_dir: bool = False +) -> str: """Makes a given HREF absolute based on the given starting HREF. Args: @@ -84,25 +95,22 @@ def make_absolute_href(source_href, start_href=None, start_is_dir=False): relative paths, if source_href is a relative path. Defaults to the current working directory. start_is_dir (str): If True, the start_href is treated as a directory. - Otherwise, the start_href is considered to be a file HREF. Defaults to False. + Otherwise, the start_href is considered to be a file HREF. + Defaults to False. Returns: str: The absolute HREF. If the source_href is already an absolute href, - then it will be returned unchanged. If the source_href it None, it will - return None. + then it will be returned unchanged. """ - if source_href is None: - return None - if start_href is None: start_href = os.getcwd() start_is_dir = True parsed_source = _urlparse(source_href) - if parsed_source.scheme == '': + if parsed_source.scheme == "": if not _pathlib.isabs(parsed_source.path): parsed_start = _urlparse(start_href) - is_path = parsed_start.scheme == '' + is_path = parsed_start.scheme == "" if start_is_dir: start_dir = parsed_start.path else: @@ -115,11 +123,13 @@ def make_absolute_href(source_href, start_href=None, start_is_dir=False): if not start_dir == _pathlib.abspath(start_dir): abs_path = abs_path.replace(_pathlib.abspath(start_dir), start_dir) - if parsed_start.scheme != '': + if parsed_start.scheme != "": if not is_path: - abs_path = abs_path.replace('\\', '/') + abs_path = abs_path.replace("\\", "/") - return '{}://{}{}'.format(parsed_start.scheme, parsed_start.netloc, abs_path) + return "{}://{}{}".format( + parsed_start.scheme, parsed_start.netloc, abs_path + ) else: return abs_path else: @@ -128,7 +138,7 @@ def make_absolute_href(source_href, start_href=None, start_is_dir=False): return source_href -def is_absolute_href(href): +def is_absolute_href(href: str) -> bool: """Determines if an HREF is absolute or not. Args: @@ -138,10 +148,10 @@ def is_absolute_href(href): bool: True if the given HREF is absolute, False if it is relative. """ parsed = _urlparse(href) - return parsed.scheme != '' or _pathlib.isabs(parsed.path) + return parsed.scheme != "" or _pathlib.isabs(parsed.path) -def datetime_to_str(dt): +def datetime_to_str(dt: datetime) -> str: """Convert a python datetime to an ISO8601 string Args: @@ -154,18 +164,18 @@ def datetime_to_str(dt): dt = dt.replace(tzinfo=timezone.utc) timestamp = dt.isoformat() - zulu = '+00:00' + zulu = "+00:00" if timestamp.endswith(zulu): - timestamp = '{}Z'.format(timestamp[:-len(zulu)]) + timestamp = "{}Z".format(timestamp[: -len(zulu)]) return timestamp -def str_to_datetime(s): +def str_to_datetime(s: str) -> datetime: return dateutil.parser.parse(s) -def geometry_to_bbox(geometry): +def geometry_to_bbox(geometry: Dict[str, Any]) -> List[float]: """Extract the bounding box from a geojson geometry Args: @@ -175,24 +185,24 @@ def geometry_to_bbox(geometry): list: Bounding box of geojson geometry, formatted according to: https://tools.ietf.org/html/rfc7946#section-5 """ - coords = geometry['coordinates'] + coords = geometry["coordinates"] - lats = [] - lons = [] + lats: List[float] = [] + lons: List[float] = [] - def extract_coords(coords): + def extract_coords(coords: List[Union[List[float], List[List[Any]]]]) -> None: for x in coords: # This handles points if isinstance(x, float): - lats.append(coords[0]) - lons.append(coords[1]) + lats.append(coords[0]) # type:ignore + lons.append(coords[1]) # type:ignore return if isinstance(x[0], list): - extract_coords(x) + extract_coords(x) # type:ignore else: lat, lon = x - lats.append(lat) - lons.append(lon) + lats.append(lat) # type:ignore + lons.append(lon) # type:ignore extract_coords(coords) @@ -202,3 +212,41 @@ def extract_coords(coords): bbox = [lats[0], lons[0], lats[-1], lons[-1]] return bbox + + +T = TypeVar("T") +U = TypeVar("U") + + +def map_opt(fn: Callable[[T], U], v: Optional[T]) -> Optional[U]: + """Maps the value of an option to another value, returning + None if the input option is None. + """ + return v if v is None else fn(v) + + +def get_opt(option: Optional[T]) -> T: + """Retrieves the value of the Optional type. + + If the Optional is None, this will raise a value error. + Use this to get a properly typed value from an optional + in contexts where you can be certain the value is not None. + If there is potential for a non-None value, it's best to handle + the None case of the optional instead of using this method. + + Returns: + The value of type T wrapped by the Optional[T] + """ + if option is None: + raise ValueError("Cannot get value from None") + return option + + +def get_required(option: Optional[T], obj: Union[str, Any], prop: str) -> T: + """Retrieves an optional value that comes from a required property. + If the option is None, throws an RequiredPropertyError with + the given obj and property + """ + if option is None: + raise RequiredPropertyMissing(obj, prop) + return option diff --git a/pystac/validation/__init__.py b/pystac/validation/__init__.py index 52166db19..b56e244f1 100644 --- a/pystac/validation/__init__.py +++ b/pystac/validation/__init__.py @@ -1,30 +1,21 @@ # flake8: noqa +from typing import Dict, List, Any, Optional, cast, TYPE_CHECKING + import pystac -from pystac.serialization.identify import identify_stac_object +from pystac.serialization.identify import STACVersionID, identify_stac_object +from pystac.validation.schema_uri_map import OldExtensionSchemaUriMap from pystac.utils import make_absolute_href -from pystac.validation.schema_uri_map import (SchemaUriMap) - - -class STACValidationError(Exception): - """Represents a validation error. Thrown by validation calls if the STAC JSON - is invalid. - - Args: - source (object): Source of the exception. Type will be determined by the - validation implementation. For the default JsonSchemaValidator this will a - the ``jsonschema.ValidationError``. - """ - def __init__(self, message, source=None): - super().__init__(message) - self.source = source +if TYPE_CHECKING: + from pystac.stac_object import STACObject as STACObject_Type + from pystac.stac_object import STACObjectType as STACObjectType_Type # Import after above class definition -from pystac.validation.stac_validator import (STACValidator, JsonSchemaSTACValidator) +from pystac.validation.stac_validator import STACValidator, JsonSchemaSTACValidator -def validate(stac_object): +def validate(stac_object: "STACObject_Type") -> List[Any]: """Validates a :class:`~pystac.STACObject`. Args: @@ -38,14 +29,22 @@ def validate(stac_object): Raises: STACValidationError """ - validate_dict(stac_dict=stac_object.to_dict(), - stac_object_type=stac_object.STAC_OBJECT_TYPE, - stac_version=pystac.get_stac_version(), - extensions=stac_object.stac_extensions, - href=stac_object.get_self_href()) - - -def validate_dict(stac_dict, stac_object_type=None, stac_version=None, extensions=None, href=None): + return validate_dict( + stac_dict=stac_object.to_dict(), + stac_object_type=stac_object.STAC_OBJECT_TYPE, + stac_version=pystac.get_stac_version(), + extensions=stac_object.stac_extensions, + href=stac_object.get_self_href(), + ) + + +def validate_dict( + stac_dict: Dict[str, Any], + stac_object_type: Optional["STACObjectType_Type"] = None, + stac_version: Optional[str] = None, + extensions: Optional[List[str]] = None, + href: Optional[str] = None, +) -> List[Any]: """Validate a stac object serialized as JSON into a dict. This method delegates to the call to :meth:`pystac.validation.STACValidator.validate` @@ -78,17 +77,35 @@ def validate_dict(stac_dict, stac_object_type=None, stac_version=None, extension if stac_version is None: if info is None: info = identify_stac_object(stac_dict) - stac_version = info.version_range.latest_valid_version() + stac_version = str(info.version_range.latest_valid_version()) if extensions is None: if info is None: info = identify_stac_object(stac_dict) - extensions = info.common_extensions + extensions = list(info.extensions) - return RegisteredValidator.get_validator().validate(stac_dict, stac_object_type, stac_version, - extensions, href) + stac_version_id = STACVersionID(stac_version) + # If the version is before 1.0.0-rc.1, substitute extension short IDs for + # their schemas. + if stac_version_id < "1.0.0-rc.1": -def validate_all(stac_dict, href): + def _get_uri(ext: str) -> Optional[str]: + return OldExtensionSchemaUriMap.get_extension_schema_uri( + ext, + stac_object_type, # type:ignore + stac_version_id, + ) + + extensions = [uri for uri in map(_get_uri, extensions) if uri is not None] + + return RegisteredValidator.get_validator().validate( + stac_dict, stac_object_type, stac_version, extensions, href + ) + + +def validate_all( + stac_dict: Dict[str, Any], href: str, stac_io: Optional[pystac.StacIO] = None +) -> None: """Validate STAC JSON and all contained catalogs, collections and items. If this stac_dict represents a catalog or collection, this method will @@ -99,67 +116,75 @@ def validate_all(stac_dict, href): stac_dict (dict): Dictionary that is the STAC json of the object. href (str): HREF of the STAC object being validated. Used for error reporting and resolving relative links. + stac_io: Optional StacIO instance to use for reading hrefs. If None, + the StacIO.default() instance is used. Raises: STACValidationError: This will raise a STACValidationError if this or any contained catalog, collection or item has a validation error. """ + if stac_io is None: + stac_io = pystac.StacIO.default() + info = identify_stac_object(stac_dict) # Validate this object - validate_dict(stac_dict, - stac_object_type=info.object_type, - stac_version=info.version_range.latest_valid_version(), - extensions=info.common_extensions, - href=href) + validate_dict( + stac_dict, + stac_object_type=info.object_type, + stac_version=str(info.version_range.latest_valid_version()), + extensions=list(info.extensions), + href=href, + ) if info.object_type != pystac.STACObjectType.ITEM: - links = stac_dict.get('links') - if links is not None: + if "links" in stac_dict: # Account for 0.6 links - if isinstance(links, dict): - links = list(links.values()) - + if isinstance(stac_dict["links"], dict): + links: List[Dict[str, Any]] = list(stac_dict["links"].values()) + else: + links = cast(List[Dict[str, Any]], stac_dict.get("links")) for link in links: - rel = link.get('rel') - if rel in ['item', 'child']: - link_href = make_absolute_href(link.get('href'), start_href=href) + rel = link.get("rel") + if rel in ["item", "child"]: + link_href = make_absolute_href( + cast(str, link.get("href")), start_href=href + ) if link_href is not None: - d = pystac.STAC_IO.read_json(link_href) + d = stac_io.read_json(link_href) validate_all(d, link_href) class RegisteredValidator: - _validator = None + _validator: Optional[STACValidator] = None @classmethod - def get_validator(cls): + def get_validator(cls) -> STACValidator: if cls._validator is None: try: - import jsonschema + import jsonschema # type:ignore except ImportError: raise Exception( 'Cannot validate with default validator because package "jsonschema" ' - 'is not installed. Install pystac with the validation optional requirements ' - '(e.g. pip install pystac[validation]) to install jsonschema') + "is not installed. Install pystac with the validation optional requirements " + "(e.g. pip install pystac[validation]) to install jsonschema" + ) cls._validator = JsonSchemaSTACValidator() return cls._validator @classmethod - def set_validator(cls, validator): + def set_validator(cls, validator: STACValidator) -> None: if not issubclass(type(validator), STACValidator): - raise Exception('Validator must be a subclass of {}'.format(STACValidator)) + raise Exception("Validator must be a subclass of {}".format(STACValidator)) cls._validator = validator -def set_validator(validator): +def set_validator(validator: STACValidator) -> None: """Sets the STACValidator to use in PySTAC. - TKTK - Args: - validator (STACValidator): The STACVlidator implementation to use for + validator (STACValidator): The STACValidator implementation to use for validation. """ RegisteredValidator.set_validator(validator) diff --git a/pystac/validation/schema_uri_map.py b/pystac/validation/schema_uri_map.py index 27b5d0782..a2d62841b 100644 --- a/pystac/validation/schema_uri_map.py +++ b/pystac/validation/schema_uri_map.py @@ -1,36 +1,28 @@ -from abc import (ABC, abstractmethod) +from abc import ABC, abstractmethod +from functools import lru_cache +from pystac.serialization.identify import OldExtensionShortIDs, STACVersionID +from typing import Any, Callable, Dict, List, Optional, Tuple import pystac -from pystac import (STACObjectType, Extensions) from pystac.serialization import STACVersionRange +from pystac.stac_object import STACObjectType class SchemaUriMap(ABC): - """Abstract class defining schema URIs for STAC core objects and extensions. - """ - def __init__(self): - pass - - @abstractmethod - def get_core_schema_uri(self, object_type, stac_version): - """Get the schema URI for the given object type and stac version. + """Abstract class defining schema URIs for STAC core objects and extensions.""" - Args: - object_type (str): STAC object type. One of :class:`~pystac.STACObjectType` - stac_version (str): The STAC version of the schema to return. - - Returns: - str: The URI of the schema, or None if not found. - """ + def __init__(self) -> None: pass @abstractmethod - def get_extension_schema_uri(self, extension_id, object_type, stac_version): - """Get the extension's schema URI for the given object type, stac version. + def get_object_schema_uri( + self, object_type: STACObjectType, stac_version: str + ) -> Optional[str]: + """Get the schema URI for the given object type and stac version. Args: - extension_id (str): The Extension ID of the extension of the schema. - object_type (str): STAC object type. One of :class:`~pystac.STACObjectType` + object_type (STACObjectType): STAC object type. One of + :class:`~pystac.STACObjectType` stac_version (str): The STAC version of the schema to return. Returns: @@ -40,7 +32,7 @@ def get_extension_schema_uri(self, extension_id, object_type, stac_version): class DefaultSchemaUriMap(SchemaUriMap): - """Implementation of SchemaUriMap that uses schemas hosted by https://schemas.stacspec.org. + """Implementation of SchemaUriMap that uses schemas hosted by stacspec.org For STAC Versions 0.9.0 or earlier this will use the schemas hosted on the radiantearth/stac-spec GitHub repo. @@ -49,155 +41,310 @@ class DefaultSchemaUriMap(SchemaUriMap): # BASE_URIS contains a list of tuples, the first element is a version range and the # second being the base URI for schemas for that range. The schema URI of a STAC # for a particular version uses the base URI associated with the version range which - # contains it. If the version it outside of any VersionRange, there is no URI for the - # schema. - BASE_URIS = [(STACVersionRange(min_version='1.0.0-beta.1'), - lambda version: 'https://schemas.stacspec.org/v{}'.format(version)), - (STACVersionRange(min_version='0.8.0', max_version='0.9.0'), lambda version: - 'https://raw.githubusercontent.com/radiantearth/stac-spec/v{}'.format(version))] - - # DEFAULT_SCHEMA_MAP contains a structure that matches 'core' or 'extension' schema URIs - # based on the stac object type and the stac version, using a similar technique as BASE_URIS. - # Uris are contained in a tuple whose first element represents the URI of the latest - # version, so that a search through version ranges is avoided if the STAC being validated - # is the latest version. If it's a previous version, the stac_version that matches - # the listed version range is used, or else the URI from the latest version is used if - # there are no overrides for previous versions. - DEFAULT_SCHEMA_MAP = { - 'core': { - STACObjectType.CATALOG: ('catalog-spec/json-schema/catalog.json', None), - STACObjectType.COLLECTION: ('collection-spec/json-schema/collection.json', None), - STACObjectType.ITEM: ('item-spec/json-schema/item.json', None), - STACObjectType.ITEMCOLLECTION: (None, [ - STACVersionRange(min_version='v0.8.0-rc1', max_version='0.9.0'), - 'item-spec/json-schema/itemcollection.json' - ]) - }, - 'extension': { - Extensions.CHECKSUM: ({ - STACObjectType.CATALOG: 'extensions/checksum/json-schema/schema.json', - STACObjectType.COLLECTION: 'extensions/checksum/json-schema/schema.json', - STACObjectType.ITEM: 'extensions/checksum/json-schema/schema.json' - }, None), - Extensions.COLLECTION_ASSETS: ({ - STACObjectType.COLLECTION: - 'extensions/collection-assets/json-schema/schema.json' - }, None), - Extensions.DATACUBE: ({ - STACObjectType.COLLECTION: 'extensions/datacube/json-schema/schema.json', - STACObjectType.ITEM: 'extensions/datacube/json-schema/schema.json' - }, [(STACVersionRange(min_version='0.5.0', max_version='0.9.0'), { - STACObjectType.COLLECTION: None, - STACObjectType.ITEM: None - })]), - Extensions.EO: ({ - STACObjectType.ITEM: 'extensions/eo/json-schema/schema.json' - }, None), - Extensions.ITEM_ASSETS: ({ - STACObjectType.COLLECTION: - 'extensions/item-assets/json-schema/schema.json' - }, None), - Extensions.LABEL: ({ - STACObjectType.ITEM: 'extensions/label/json-schema/schema.json' - }, [(STACVersionRange(min_version='0.8.0-rc1', max_version='0.8.1'), { - STACObjectType.ITEM: 'extensions/label/schema.json' - })]), - Extensions.POINTCLOUD: ( - { - STACObjectType.ITEM: None # 'extensions/pointcloud/json-schema/schema.json' - }, - None), - Extensions.PROJECTION: ({ - STACObjectType.ITEM: - 'extensions/projection/json-schema/schema.json' - }, None), - Extensions.SAR: ({ - STACObjectType.ITEM: 'extensions/sar/json-schema/schema.json' - }, None), - Extensions.SAT: ({ - STACObjectType.ITEM: 'extensions/sat/json-schema/schema.json' - }, None), - Extensions.SCIENTIFIC: ({ - STACObjectType.ITEM: - 'extensions/scientific/json-schema/schema.json', - STACObjectType.COLLECTION: - 'extensions/scientific/json-schema/schema.json' - }, None), - Extensions.SINGLE_FILE_STAC: ({ - STACObjectType.CATALOG: - 'extensions/single-file-stac/json-schema/schema.json' - }, None), - Extensions.TILED_ASSETS: ({ - STACObjectType.CATALOG: - 'extensions/tiled-assets/json-schema/schema.json', - STACObjectType.COLLECTION: - 'extensions/tiled-assets/json-schema/schema.json', - STACObjectType.ITEM: - 'extensions/tiled-assets/json-schema/schema.json' - }, None), - Extensions.TIMESTAMPS: ({ - STACObjectType.ITEM: - 'extensions/timestamps/json-schema/schema.json' - }, None), - Extensions.VERSION: ({ - STACObjectType.ITEM: - 'extensions/version/json-schema/schema.json', - STACObjectType.COLLECTION: - 'extensions/version/json-schema/schema.json' - }, None), - Extensions.VIEW: ({ - STACObjectType.ITEM: 'extensions/view/json-schema/schema.json' - }, None), + # contains it. If the version it outside of any VersionRange, there is no URI for + # the schema. + BASE_URIS: List[Tuple[STACVersionRange, Callable[[str], str]]] = [ + ( + STACVersionRange(min_version="1.0.0-beta.1"), + lambda version: "https://schemas.stacspec.org/v{}".format(version), + ), + ( + STACVersionRange(min_version="0.8.0", max_version="0.9.0"), + lambda version: ( + f"https://raw.githubusercontent.com/radiantearth/stac-spec/v{version}" + ), + ), + ] - # Removed or renamed extensions. - 'dtr': (None, None), # Invalid schema - 'asset': (None, [(STACVersionRange(min_version='0.8.0-rc1', max_version='0.9.0'), { - STACObjectType.COLLECTION: 'extensions/asset/json-schema/schema.json' - })]), - } + # DEFAULT_SCHEMA_MAP contains a structure that matches 'core' or 'extension' schema + # URIs based on the stac object type and the stac version, using a similar + # technique as BASE_URIS. Uris are contained in a tuple whose first element + # represents the URI of the latest version, so that a search through version + # ranges is avoided if the STAC being validated + # is the latest version. If it's a previous version, the stac_version that matches + # the listed version range is used, or else the URI from the latest version is used + # if there are no overrides for previous versions. + DEFAULT_SCHEMA_MAP: Dict[str, Any] = { + STACObjectType.CATALOG: ("catalog-spec/json-schema/catalog.json", None), + STACObjectType.COLLECTION: ( + "collection-spec/json-schema/collection.json", + None, + ), + STACObjectType.ITEM: ("item-spec/json-schema/item.json", None), + STACObjectType.ITEMCOLLECTION: ( + None, + [ + STACVersionRange(min_version="v0.8.0-rc1", max_version="0.9.0"), + "item-spec/json-schema/itemcollection.json", + ], + ), } @classmethod - def _append_base_uri_if_needed(cls, uri, stac_version): + def _append_base_uri_if_needed(cls, uri: str, stac_version: str) -> Optional[str]: # Only append the base URI if it's not already an absolute URI - if '://' not in uri: + if "://" not in uri: base_uri = None for version_range, f in cls.BASE_URIS: if version_range.contains(stac_version): base_uri = f(stac_version) - return '{}/{}'.format(base_uri, uri) + return "{}/{}".format(base_uri, uri) # We don't have JSON schema validation for this version of PySTAC return None else: return uri - def get_core_schema_uri(self, object_type, stac_version): + def get_object_schema_uri( + self, object_type: STACObjectType, stac_version: str + ) -> Optional[str]: uri = None is_latest = stac_version == pystac.get_stac_version() - if object_type not in self.DEFAULT_SCHEMA_MAP['core']: - raise KeyError('Unknown STAC object type {}'.format(object_type)) + if object_type not in self.DEFAULT_SCHEMA_MAP: + raise KeyError("Unknown STAC object type {}".format(object_type)) - uri = self.DEFAULT_SCHEMA_MAP['core'][object_type][0] + uri = self.DEFAULT_SCHEMA_MAP[object_type][0] if not is_latest: - if self.DEFAULT_SCHEMA_MAP['core'][object_type][1]: - for version_range, range_uri in self.DEFAULT_SCHEMA_MAP['core'][object_type][1]: + if self.DEFAULT_SCHEMA_MAP[object_type][1]: + for version_range, range_uri in self.DEFAULT_SCHEMA_MAP[object_type][1]: if version_range.contains(stac_version): uri = range_uri break return self._append_base_uri_if_needed(uri, stac_version) - def get_extension_schema_uri(self, extension_id, object_type, stac_version): + +class OldExtensionSchemaUriMap: + """Ties old extension IDs to schemas hosted by https://schemas.stacspec.org. + + For STAC Versions 0.9.0 or earlier this will use the schemas hosted on the + radiantearth/stac-spec GitHub repo. + """ + + # BASE_URIS contains a list of tuples, the first element is a version range and the + # second being the base URI for schemas for that range. The schema URI of a STAC + # for a particular version uses the base URI associated with the version range which + # contains it. If the version it outside of any VersionRange, there is no URI for + # the schema. + @classmethod + @lru_cache() + def get_base_uris( + cls, + ) -> List[Tuple[STACVersionRange, Callable[[STACVersionID], str]]]: + return [ + ( + STACVersionRange(min_version="1.0.0-beta.1"), + lambda version: f"https://schemas.stacspec.org/v{version}", + ), + ( + STACVersionRange(min_version="0.8.0", max_version="0.9.0"), + lambda version: ( + "https://raw.githubusercontent.com/" + f"radiantearth/stac-spec/v{version}" + ), + ), + ] + + # DEFAULT_SCHEMA_MAP contains a structure that matches extension schema URIs + # based on the stac object type, extension ID and the stac version. + # Uris are contained in a tuple whose first element represents the URI of the latest + # version, so that a search through version ranges is avoided if the STAC being + # validated is the latest version. If it's a previous version, the stac_version + # that matches the listed version range is used, or else the URI from the latest + # version is used if there are no overrides for previous versions. + @classmethod + @lru_cache() + def get_schema_map(cls) -> Dict[str, Any]: + return { + OldExtensionShortIDs.CHECKSUM.value: ( + { + pystac.STACObjectType.CATALOG: ( + "extensions/checksum/json-schema/schema.json" + ), + pystac.STACObjectType.COLLECTION: ( + "extensions/checksum/json-schema/schema.json" + ), + pystac.STACObjectType.ITEM: ( + "extensions/checksum/json-schema/schema.json" + ), + }, + None, + ), + OldExtensionShortIDs.COLLECTION_ASSETS.value: ( + { + pystac.STACObjectType.COLLECTION: ( + "extensions/collection-assets/json-schema/schema.json" + ) + }, + None, + ), + OldExtensionShortIDs.DATACUBE.value: ( + { + pystac.STACObjectType.COLLECTION: ( + "extensions/datacube/json-schema/schema.json" + ), + pystac.STACObjectType.ITEM: ( + "extensions/datacube/json-schema/schema.json" + ), + }, + [ + ( + STACVersionRange(min_version="0.5.0", max_version="0.9.0"), + { + pystac.STACObjectType.COLLECTION: None, + pystac.STACObjectType.ITEM: None, + }, + ) + ], + ), + OldExtensionShortIDs.EO.value: ( + {pystac.STACObjectType.ITEM: "extensions/eo/json-schema/schema.json"}, + None, + ), + OldExtensionShortIDs.ITEM_ASSETS.value: ( + { + pystac.STACObjectType.COLLECTION: ( + "extensions/item-assets/json-schema/schema.json" + ) + }, + None, + ), + OldExtensionShortIDs.LABEL.value: ( + { + pystac.STACObjectType.ITEM: ( + "extensions/label/json-schema/schema.json" + ) + }, + [ + ( + STACVersionRange(min_version="0.8.0-rc1", max_version="0.8.1"), + {pystac.STACObjectType.ITEM: "extensions/label/schema.json"}, + ) + ], + ), + OldExtensionShortIDs.POINTCLOUD.value: ( + # Invalid schema + None, + None, + ), + OldExtensionShortIDs.PROJECTION.value: ( + { + pystac.STACObjectType.ITEM: ( + "extensions/projection/json-schema/schema.json" + ) + }, + None, + ), + OldExtensionShortIDs.SAR.value: ( + {pystac.STACObjectType.ITEM: "extensions/sar/json-schema/schema.json"}, + None, + ), + OldExtensionShortIDs.SAT.value: ( + {pystac.STACObjectType.ITEM: "extensions/sat/json-schema/schema.json"}, + None, + ), + OldExtensionShortIDs.SCIENTIFIC.value: ( + { + pystac.STACObjectType.ITEM: ( + "extensions/scientific/json-schema/schema.json" + ), + pystac.STACObjectType.COLLECTION: ( + "extensions/scientific/json-schema/schema.json" + ), + }, + None, + ), + OldExtensionShortIDs.SINGLE_FILE_STAC.value: ( + { + pystac.STACObjectType.CATALOG: ( + "extensions/single-file-stac/json-schema/schema.json" + ) + }, + None, + ), + OldExtensionShortIDs.TILED_ASSETS.value: ( + { + pystac.STACObjectType.CATALOG: ( + "extensions/tiled-assets/json-schema/schema.json" + ), + pystac.STACObjectType.COLLECTION: ( + "extensions/tiled-assets/json-schema/schema.json" + ), + pystac.STACObjectType.ITEM: ( + "extensions/tiled-assets/json-schema/schema.json" + ), + }, + None, + ), + OldExtensionShortIDs.TIMESTAMPS.value: ( + { + pystac.STACObjectType.ITEM: ( + "extensions/timestamps/json-schema/schema.json" + ) + }, + None, + ), + OldExtensionShortIDs.VERSION.value: ( + { + pystac.STACObjectType.ITEM: ( + "extensions/version/json-schema/schema.json" + ), + pystac.STACObjectType.COLLECTION: ( + "extensions/version/json-schema/schema.json" + ), + }, + None, + ), + OldExtensionShortIDs.VIEW.value: ( + {pystac.STACObjectType.ITEM: "extensions/view/json-schema/schema.json"}, + None, + ), + # Removed or renamed extensions. + "dtr": (None, None), # Invalid schema + "asset": ( + None, + [ + ( + STACVersionRange(min_version="0.8.0-rc1", max_version="0.9.0"), + { + pystac.STACObjectType.COLLECTION: ( + "extensions/asset/json-schema/schema.json" + ) + }, + ) + ], + ), + } + + @classmethod + def _append_base_uri_if_needed( + cls, uri: str, stac_version: STACVersionID + ) -> Optional[str]: + # Only append the base URI if it's not already an absolute URI + if "://" not in uri: + base_uri = None + for version_range, f in cls.get_base_uris(): + if version_range.contains(stac_version): + base_uri = f(stac_version) + return "{}/{}".format(base_uri, uri) + + # No JSON Schema for the old extension + return None + else: + return uri + + @classmethod + def get_extension_schema_uri( + cls, extension_id: str, object_type: STACObjectType, stac_version: STACVersionID + ) -> Optional[str]: uri = None is_latest = stac_version == pystac.get_stac_version() - ext_map = self.DEFAULT_SCHEMA_MAP['extension'] + ext_map = cls.get_schema_map() if extension_id in ext_map: - if ext_map[extension_id][0] and \ - object_type in ext_map[extension_id][0]: + if ext_map[extension_id][0] and object_type in ext_map[extension_id][0]: uri = ext_map[extension_id][0][object_type] if not is_latest: @@ -211,4 +358,4 @@ def get_extension_schema_uri(self, extension_id, object_type, stac_version): if uri is None: return uri else: - return self._append_base_uri_if_needed(uri, stac_version) + return cls._append_base_uri_if_needed(uri, stac_version) diff --git a/pystac/validation/stac_validator.py b/pystac/validation/stac_validator.py index 08669a45d..777b4307d 100644 --- a/pystac/validation/stac_validator.py +++ b/pystac/validation/stac_validator.py @@ -1,15 +1,21 @@ +from abc import ABC, abstractmethod +import logging import json -from abc import (ABC, abstractmethod) +from pystac.stac_object import STACObjectType +from typing import Any, Dict, List, Optional, Tuple -from pystac import STAC_IO -from pystac.validation import STACValidationError -from pystac.validation.schema_uri_map import DefaultSchemaUriMap +import pystac +from pystac.validation.schema_uri_map import DefaultSchemaUriMap, SchemaUriMap try: import jsonschema + import jsonschema.validators + import jsonschema.exceptions except ImportError: jsonschema = None +logger = logging.getLogger(__name__) + class STACValidator(ABC): """STACValidator defines methods for validating STAC @@ -18,71 +24,90 @@ class STACValidator(ABC): STACValidator implementation and set that validator to be used by pystac by using the :func:`~pystac.validation.set_validator` method. """ + @abstractmethod - def validate_core(self, stac_dict, stac_object_type, stac_version, href=None): + def validate_core( + self, + stac_dict: Dict[str, Any], + stac_object_type: STACObjectType, + stac_version: str, + href: Optional[str] = None, + ) -> Any: """Validate a core stac object. Return value can be None or specific to the implementation. Args: stac_dict (dict): Dictionary that is the STAC json of the object. - stac_object_type (str): The stac object type of the object encoded in stac_dict. - One of :class:`~pystac.STACObjectType`. + stac_object_type (str): The stac object type of the object encoded + in stac_dict. One of :class:`~pystac.STACObjectType`. stac_version (str): The version of STAC to validate the object against. href (str): Optional HREF of the STAC object being validated. """ pass @abstractmethod - def validate_extension(self, - stac_dict, - stac_object_type, - stac_version, - extension_id, - href=None): + def validate_extension( + self, + stac_dict: Dict[str, Any], + stac_object_type: STACObjectType, + stac_version: str, + extension_id: str, + href: Optional[str] = None, + ) -> Any: """Validate an extension stac object. Return value can be None or specific to the implementation. Args: stac_dict (dict): Dictionary that is the STAC json of the object. - stac_object_type (str): The stac object type of the object encoded in stac_dict. - One of :class:`~pystac.STACObjectType`. + stac_object_type (str): The stac object type of the object encoded in + stac_dict. One of :class:`~pystac.STACObjectType`. stac_version (str): The version of STAC to validate the object against. extension_id (str): The extension ID of the extension to validate against. href (str): Optional HREF of the STAC object being validated. """ pass - def validate(self, stac_dict, stac_object_type, stac_version, extensions, href=None): + def validate( + self, + stac_dict: Dict[str, Any], + stac_object_type: STACObjectType, + stac_version: str, + extensions: List[str], + href: Optional[str] = None, + ) -> List[Any]: """Validate a STAC object JSON. Args: stac_dict (dict): Dictionary that is the STAC json of the object. - stac_object_type (str): The stac object type of the object encoded in stac_dict. - One of :class:`~pystac.STACObjectType`. + stac_object_type (str): The stac object type of the object encoded in + stac_dict. One of :class:`~pystac.STACObjectType`. stac_version (str): The version of STAC to validate the object against. extensions (List[str]): Extension IDs for this stac object. href (str): Optional href of the STAC object being validated. Returns: - List[Object]: List of return values from the validation calls for the + List[Any]: List of return values from the validation calls for the core object and any extensions. Element type is specific to the STACValidator implementation. """ - results = [] + results: List[Any] = [] # Pass the dict through JSON serialization and parsing, otherwise # some valid properties can be marked as invalid (e.g. tuples in # coordinate sequences for geometries). json_dict = json.loads(json.dumps(stac_dict)) - core_result = self.validate_core(json_dict, stac_object_type, stac_version, href) + core_result = self.validate_core( + json_dict, stac_object_type, stac_version, href + ) if core_result is not None: results.append(core_result) for extension_id in extensions: - ext_result = self.validate_extension(json_dict, stac_object_type, stac_version, - extension_id, href) + ext_result = self.validate_extension( + json_dict, stac_object_type, stac_version, extension_id, href + ) if ext_result is not None: results.append(ext_result) @@ -105,58 +130,74 @@ class JsonSchemaSTACValidator(STACValidator): Note: This class requires the ``jsonschema`` library to be installed. """ - def __init__(self, schema_uri_map=None): + + def __init__(self, schema_uri_map: Optional[SchemaUriMap] = None) -> None: if jsonschema is None: - raise Exception('Cannot instantiate, requires jsonschema package') + raise Exception("Cannot instantiate, requires jsonschema package") if schema_uri_map is not None: self.schema_uri_map = schema_uri_map else: self.schema_uri_map = DefaultSchemaUriMap() - self.schema_cache = {} + self.schema_cache: Dict[str, Dict[str, Any]] = {} - def get_schema_from_uri(self, schema_uri): + def get_schema_from_uri(self, schema_uri: str) -> Tuple[Dict[str, Any], Any]: if schema_uri not in self.schema_cache: - s = json.loads(STAC_IO.read_text(schema_uri)) + s = json.loads(pystac.StacIO.default().read_text(schema_uri)) self.schema_cache[schema_uri] = s schema = self.schema_cache[schema_uri] - resolver = jsonschema.validators.RefResolver(base_uri=schema_uri, - referrer=schema, - store=self.schema_cache) + resolver = jsonschema.validators.RefResolver( + base_uri=schema_uri, referrer=schema, store=self.schema_cache + ) return (schema, resolver) - def _validate_from_uri(self, stac_dict, schema_uri): + def _validate_from_uri(self, stac_dict: Dict[str, Any], schema_uri: str) -> None: schema, resolver = self.get_schema_from_uri(schema_uri) - jsonschema.validate(instance=stac_dict, schema=schema, resolver=resolver) + jsonschema.validate( + instance=stac_dict, schema=schema, resolver=resolver + ) # type:ignore for uri in resolver.store: if uri not in self.schema_cache: self.schema_cache[uri] = resolver.store[uri] - def _get_error_message(self, schema_uri, stac_object_type, extension_id, href, stac_id): - s = 'Validation failed for {} '.format(stac_object_type) + def _get_error_message( + self, + schema_uri: str, + stac_object_type: STACObjectType, + extension_id: Optional[str], + href: Optional[str], + stac_id: Optional[str], + ) -> str: + s = "Validation failed for {} ".format(stac_object_type) if href is not None: - s += 'at {} '.format(href) + s += "at {} ".format(href) if stac_id is not None: - s += 'with ID {} '.format(stac_id) - s += 'against schema at {}'.format(schema_uri) + s += "with ID {} ".format(stac_id) + s += "against schema at {}".format(schema_uri) if extension_id is not None: s += " for STAC extension '{}'".format(extension_id) return s - def validate_core(self, stac_dict, stac_object_type, stac_version, href=None): + def validate_core( + self, + stac_dict: Dict[str, Any], + stac_object_type: STACObjectType, + stac_version: str, + href: Optional[str] = None, + ) -> Optional[str]: """Validate a core stac object. Return value can be None or specific to the implementation. Args: stac_dict (dict): Dictionary that is the STAC json of the object. - stac_object_type (str): The stac object type of the object encoded in stac_dict. - One of :class:`~pystac.STACObjectType`. + stac_object_type (str): The stac object type of the object encoded in + stac_dict. One of :class:`~pystac.STACObjectType`. stac_version (str): The version of STAC to validate the object against. href (str): Optional HREF of the STAC object being validated. @@ -164,7 +205,9 @@ def validate_core(self, stac_dict, stac_object_type, stac_version, href=None): str: URI for the JSON schema that was validated against, or None if no validation occurred. """ - schema_uri = self.schema_uri_map.get_core_schema_uri(stac_object_type, stac_version) + schema_uri = self.schema_uri_map.get_object_schema_uri( + stac_object_type, stac_version + ) if schema_uri is None: return None @@ -173,24 +216,27 @@ def validate_core(self, stac_dict, stac_object_type, stac_version, href=None): self._validate_from_uri(stac_dict, schema_uri) return schema_uri except jsonschema.exceptions.ValidationError as e: - msg = self._get_error_message(schema_uri, stac_object_type, None, href, - stac_dict.get('id')) - raise STACValidationError(msg, source=e) from e - - def validate_extension(self, - stac_dict, - stac_object_type, - stac_version, - extension_id, - href=None): + msg = self._get_error_message( + schema_uri, stac_object_type, None, href, stac_dict.get("id") + ) + raise pystac.STACValidationError(msg, source=e) from e + + def validate_extension( + self, + stac_dict: Dict[str, Any], + stac_object_type: STACObjectType, + stac_version: str, + extension_id: str, + href: Optional[str] = None, + ) -> Optional[str]: """Validate an extension stac object. Return value can be None or specific to the implementation. Args: stac_dict (dict): Dictionary that is the STAC json of the object. - stac_object_type (str): The stac object type of the object encoded in stac_dict. - One of :class:`~pystac.STACObjectType`. + stac_object_type (str): The stac object type of the object encoded in + stac_dict. One of :class:`~pystac.STACObjectType`. stac_version (str): The version of STAC to validate the object against. extension_id (str): The extension ID to validate against. href (str): Optional HREF of the STAC object being validated. @@ -199,8 +245,7 @@ def validate_extension(self, str: URI for the JSON schema that was validated against, or None if no validation occurred. """ - schema_uri = self.schema_uri_map.get_extension_schema_uri(extension_id, stac_object_type, - stac_version) + schema_uri = extension_id if schema_uri is None: return None @@ -209,6 +254,11 @@ def validate_extension(self, self._validate_from_uri(stac_dict, schema_uri) return schema_uri except jsonschema.exceptions.ValidationError as e: - msg = self._get_error_message(schema_uri, stac_object_type, extension_id, href, - stac_dict.get('id')) - raise STACValidationError(msg, source=e) from e + msg = self._get_error_message( + schema_uri, stac_object_type, extension_id, href, stac_dict.get("id") + ) + raise pystac.STACValidationError(msg, source=e) from e + except Exception as e: + logger.error(f"Exception while validating {stac_object_type} href: {href}") + logger.exception(e) + raise diff --git a/pystac/version.py b/pystac/version.py index 096f0ebc7..4176f0428 100644 --- a/pystac/version.py +++ b/pystac/version.py @@ -1,20 +1,21 @@ import os +from typing import Optional -__version__ = '0.5.6' +__version__ = "0.5.6" """Library version""" class STACVersion: - DEFAULT_STAC_VERSION = '1.0.0-beta.2' + DEFAULT_STAC_VERSION = "1.0.0-rc.3" """Latest STAC version supported by PySTAC""" # Version that holds a user-set STAC version to use. - _override_version = None + _override_version: Optional[str] = None - OVERRIDE_VERSION_ENV_VAR = 'PYSTAC_STAC_VERSION_OVERRIDE' + OVERRIDE_VERSION_ENV_VAR = "PYSTAC_STAC_VERSION_OVERRIDE" @classmethod - def get_stac_version(cls): + def get_stac_version(cls) -> str: if cls._override_version is not None: return cls._override_version @@ -25,17 +26,18 @@ def get_stac_version(cls): return cls.DEFAULT_STAC_VERSION @classmethod - def set_stac_version(cls, stac_version): + def set_stac_version(cls, stac_version: Optional[str]) -> None: cls._override_version = stac_version -def get_stac_version(): +def get_stac_version() -> str: """Returns the STAC version PySTAC writes as the "stac_version" property for any object it serializes into JSON. - If a call to ``set_stac_version`` was made, this will return the value it was called with. - Next it will check the environment for a PYSTAC_STAC_VERSION_OVERRIDE variable. Otherwise - it will return the latest STAC version that this version of PySTAC supports. + If a call to ``set_stac_version`` was made, this will return the value it was + called with. Next it will check the environment for a PYSTAC_STAC_VERSION_OVERRIDE + variable. Otherwise it will return the latest STAC version that this version of + PySTAC supports. Returns: str: The STAC Version PySTAC is set up to use. @@ -43,7 +45,7 @@ def get_stac_version(): return STACVersion.get_stac_version() -def set_stac_version(stac_version): +def set_stac_version(stac_version: Optional[str]) -> None: """Sets the STAC version that PySTAC should use. This is the version that will be set as the "stac_version" property @@ -55,12 +57,14 @@ def set_stac_version(stac_version): the version. Args: - stac_version (str): The STAC version to use instead of the latest STAC version that - PySTAC supports (described in STACVersion.DEFAULT_STAC_VERSION) + stac_version (str): The STAC version to use instead of the latest STAC version + that PySTAC supports (described in STACVersion.DEFAULT_STAC_VERSION). + If None, clear to use the default for this version of PySTAC. Note: - Setting the STAC version to something besides the default version will not effect - the format of STAC read or written; it will only override the ``stac_version`` property - of the objects being written. Setting this incorrectly can produce invalid STAC. + Setting the STAC version to something besides the default version will not + effect the format of STAC read or written; it will only override the + ``stac_version`` property of the objects being written. Setting this + incorrectly can produce invalid STAC. """ STACVersion.set_stac_version(stac_version) diff --git a/requirements-dev.txt b/requirements-dev.txt index 03a4f079e..3b00ec452 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,12 +1,16 @@ +mypy==0.790 +flake8==3.8.* +black==21.4b2 + codespell==1.17.1 ipython==7.16.1 jsonschema==3.2.0 pylint==1.9.1 -Sphinx==1.8.0 +Sphinx==3.5.4 sphinx-autobuild==0.7.1 sphinxcontrib-fulltoc==1.2.0 -sphinxcontrib-napoleon==0.7 -flake8==3.8.* -yapf==0.30.* nbsphinx==0.7.1 coverage==5.2.* + +# optional dependencies +orjson==3.5.2 diff --git a/scripts/format b/scripts/format index a7e68fd4f..640929c39 100755 --- a/scripts/format +++ b/scripts/format @@ -17,6 +17,7 @@ if [ "${BASH_SOURCE[0]}" = "${0}" ]; then if [ "${1:-}" = "--help" ]; then usage else - yapf -ipr pystac tests + black pystac + black tests fi fi diff --git a/scripts/pyright b/scripts/pyright new file mode 100755 index 000000000..e50f0ac2c --- /dev/null +++ b/scripts/pyright @@ -0,0 +1,73 @@ +#!/bin/bash +PATH_TO_PYRIGHT=`which pyright` + +vercomp () { + if [[ $1 == $2 ]] + then + return 0 + fi + local IFS=. + local i ver1=($1) ver2=($2) + # fill empty fields in ver1 with zeros + for ((i=${#ver1[@]}; i<${#ver2[@]}; i++)) + do + ver1[i]=0 + done + for ((i=0; i<${#ver1[@]}; i++)) + do + if [[ -z ${ver2[i]} ]] + then + # fill empty fields in ver2 with zeros + ver2[i]=0 + fi + if ((10#${ver1[i]} > 10#${ver2[i]})) + then + return 1 + fi + if ((10#${ver1[i]} < 10#${ver2[i]})) + then + return 2 + fi + done + return 0 +} + +# Node version check +echo "Checking node version..." +NODE_VERSION=`node -v | cut -d'v' -f2` +MIN_NODE_VERSION="10.15.2" +vercomp $MIN_NODE_VERSION $NODE_VERSION +# 1 == gt +if [[ $? -eq 1 ]]; then + echo "Node version ${NODE_VERSION} too old, min expected is ${MIN_NODE_VERSION}, run:" + echo " npm -g upgrade node" + exit -1 +fi + +# Do we need to sudo? +echo "Checking node_modules dir..." +NODE_MODULES=`npm -g root` +SUDO="sudo" +if [ -w "$NODE_MODULES" ]; then + SUDO="" #nop +fi + +# If we can't find pyright, install it. +echo "Checking pyright exists..." +if [ -z "$PATH_TO_PYRIGHT" ]; then + echo "...installing pyright" + ${SUDO} npm install -g pyright +else + # already installed, upgrade to make sure it's current + # this avoids a sudo on launch if we're already current + echo "Checking pyright version..." + CURRENT=`pyright --version | cut -d' ' -f2` + REMOTE=`npm info pyright version` + if [ "$CURRENT" != "$REMOTE" ]; then + echo "...new version of pyright found, upgrading." + ${SUDO} npm upgrade -g pyright + fi +fi + +echo "done." +pyright "$@" \ No newline at end of file diff --git a/scripts/test b/scripts/test index 93df987d6..2cfc070b3 100755 --- a/scripts/test +++ b/scripts/test @@ -17,11 +17,28 @@ if [ "${BASH_SOURCE[0]}" = "${0}" ]; then if [ "${1:-}" = "--help" ]; then usage else - # Lint + echo + echo " -- CHECKING TYPES WITH PYRIGHT --" + echo + + scripts/pyright pystac tests + + echo + echo " -- LINTING WITH FLAKE8 --" + echo + flake8 pystac tests - # Code formatting - yapf -dpr pystac tests + echo + echo " -- CHECKING FORMAT WITH BLACK --" + echo + + black --check pystac + black --check tests + + echo + echo " -- CHECKING SPELLING WITH CODESPELL --" + echo # Code spelling codespell -I .codespellignore -f \ @@ -33,6 +50,10 @@ if [ "${BASH_SOURCE[0]}" = "${0}" ]; then *.py \ *.md + echo + echo " -- RUNNING UNIT TESTS --" + echo + # Test suite with coverage enabled coverage run --source=pystac/ -m unittest discover tests/ coverage xml diff --git a/setup.py b/setup.py index 597d6bb05..6851f848a 100644 --- a/setup.py +++ b/setup.py @@ -29,7 +29,8 @@ include_package_data=False, install_requires=["python-dateutil>=2.7.0"], extras_require={ - "validation": ["jsonschema==3.2.0"] + "validation": ["jsonschema>=3.0"], + "orjson": ["orjson>=3.5"] }, license="Apache Software License 2.0", zip_safe=False, diff --git a/tests/__init__.py b/tests/__init__.py index e69de29bb..4c566cbae 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -0,0 +1,18 @@ +import logging +import sys + + +def setup_logging(level: int) -> None: + for package in ["pystac", "tests"]: + logger = logging.getLogger(package) + logger.setLevel(level) + + formatter = logging.Formatter("[%(levelname)s] %(asctime)s - %(message)s") + + ch = logging.StreamHandler(sys.stdout) + ch.setLevel(level) + ch.setFormatter(formatter) + logger.addHandler(ch) + + +setup_logging(logging.INFO) diff --git a/tests/data-files/catalogs/cbers-partial/CBERS4AWFI/collection.json b/tests/data-files/catalogs/cbers-partial/CBERS4AWFI/collection.json index 3c7a38068..5afab0a5b 100644 --- a/tests/data-files/catalogs/cbers-partial/CBERS4AWFI/collection.json +++ b/tests/data-files/catalogs/cbers-partial/CBERS4AWFI/collection.json @@ -1,119 +1,120 @@ { - "id": "CBERS4AWFI", - "stac_version": "1.0.0-beta.2", - "description": "CBERS4 AWFI camera catalog", - "links": [ - { - "rel": "root", - "href": "../catalog.json", - "type": "application/json" - }, + "type": "Collection", + "id": "CBERS4AWFI", + "stac_version": "1.0.0-rc.3", + "description": "CBERS4 AWFI camera catalog", + "links": [ + { + "rel": "root", + "href": "../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../catalog.json", + "type": "application/json" + } + ], + "stac_extensions": [ + "https://stac-extensions.github.io/eo/v1.0.0/schema.json", + "https://schemas.stacspec.org/v1.0.0-beta.2/extensions/item-assets/json-schema/schema.json" + ], + "providers": [ + { + "name": "Instituto Nacional de Pesquisas Espaciais, INPE", + "roles": [ + "producer" + ], + "url": "http://www.cbers.inpe.br" + }, + { + "name": "AMS Kepler", + "description": "Convert INPE's original TIFF to COG and copy to Amazon Web Services", + "roles": [ + "processor" + ], + "url": "https://github.com/fredliporace/cbers-on-aws" + }, + { + "name": "Amazon Web Services", + "roles": [ + "host" + ], + "url": "https://registry.opendata.aws/cbers/" + } + ], + "properties": { + "gsd": 64.0, + "platform": "CBERS-4", + "instruments": [ + "AWFI" + ] + }, + "item_assets": { + "thumbnail": { + "title": "Thumbnail", + "type": "image/jpeg" + }, + "metadata": { + "title": "INPE original metadata", + "type": "text/xml" + }, + "B13": { + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "eo:bands": [ { - "rel": "parent", - "href": "../catalog.json", - "type": "application/json" + "name": "B13", + "common_name": "blue" } - ], - "stac_extensions": [ - "eo", - "item-assets" - ], - "providers": [ - { - "name": "Instituto Nacional de Pesquisas Espaciais, INPE", - "roles": [ - "producer" - ], - "url": "http://www.cbers.inpe.br" - }, - { - "name": "AMS Kepler", - "description": "Convert INPE's original TIFF to COG and copy to Amazon Web Services", - "roles": [ - "processor" - ], - "url": "https://github.com/fredliporace/cbers-on-aws" - }, + ] + }, + "B14": { + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "eo:bands": [ { - "name": "Amazon Web Services", - "roles": [ - "host" - ], - "url": "https://registry.opendata.aws/cbers/" + "name": "B14", + "common_name": "green" } - ], - "properties": { - "gsd": 64.0, - "platform": "CBERS-4", - "instruments": [ - "AWFI" - ] + ] }, - "item_assets": { - "thumbnail": { - "title": "Thumbnail", - "type": "image/jpeg" - }, - "metadata": { - "title": "INPE original metadata", - "type": "text/xml" - }, - "B13": { - "type": "image/tiff; application=geotiff; profile=cloud-optimized", - "eo:bands": [ - { - "name": "B13", - "common_name": "blue" - } - ] - }, - "B14": { - "type": "image/tiff; application=geotiff; profile=cloud-optimized", - "eo:bands": [ - { - "name": "B14", - "common_name": "green" - } - ] - }, - "B15": { - "type": "image/tiff; application=geotiff; profile=cloud-optimized", - "eo:bands": [ - { - "name": "B15", - "common_name": "red" - } - ] - }, - "B16": { - "type": "image/tiff; application=geotiff; profile=cloud-optimized", - "eo:bands": [ - { - "name": "B16", - "common_name": "nir" - } - ] + "B15": { + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "eo:bands": [ + { + "name": "B15", + "common_name": "red" } + ] }, - "extent": { - "spatial": { - "bbox": [ - [ - -180.0, - -83.0, - 180.0, - 83.0 - ] - ] - }, - "temporal": { - "interval": [ - [ - "2014-12-08T00:00:00Z", - null - ] - ] + "B16": { + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "eo:bands": [ + { + "name": "B16", + "common_name": "nir" } + ] + } + }, + "extent": { + "spatial": { + "bbox": [ + [ + -180.0, + -83.0, + 180.0, + 83.0 + ] + ] }, - "license": "CC-BY-SA-3.0" -} + "temporal": { + "interval": [ + [ + "2014-12-08T00:00:00Z", + null + ] + ] + } + }, + "license": "CC-BY-SA-3.0" +} \ No newline at end of file diff --git a/tests/data-files/catalogs/cbers-partial/CBERS4MUX/collection.json b/tests/data-files/catalogs/cbers-partial/CBERS4MUX/collection.json index 06ba1205d..7ba7f8f51 100644 --- a/tests/data-files/catalogs/cbers-partial/CBERS4MUX/collection.json +++ b/tests/data-files/catalogs/cbers-partial/CBERS4MUX/collection.json @@ -1,119 +1,120 @@ { - "id": "CBERS4MUX", - "stac_version": "1.0.0-beta.2", - "description": "CBERS4 MUX camera catalog", - "links": [ - { - "rel": "root", - "href": "../catalog.json", - "type": "application/json" - }, + "type": "Collection", + "id": "CBERS4MUX", + "stac_version": "1.0.0-rc.3", + "description": "CBERS4 MUX camera catalog", + "links": [ + { + "rel": "root", + "href": "../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../catalog.json", + "type": "application/json" + } + ], + "stac_extensions": [ + "eo", + "item-assets" + ], + "providers": [ + { + "name": "Instituto Nacional de Pesquisas Espaciais, INPE", + "roles": [ + "producer" + ], + "url": "http://www.cbers.inpe.br" + }, + { + "name": "AMS Kepler", + "description": "Convert INPE's original TIFF to COG and copy to Amazon Web Services", + "roles": [ + "processor" + ], + "url": "https://github.com/fredliporace/cbers-on-aws" + }, + { + "name": "Amazon Web Services", + "roles": [ + "host" + ], + "url": "https://registry.opendata.aws/cbers/" + } + ], + "properties": { + "gsd": 20.0, + "platform": "CBERS-4", + "instruments": [ + "MUX" + ] + }, + "item_assets": { + "thumbnail": { + "title": "Thumbnail", + "type": "image/jpeg" + }, + "metadata": { + "title": "INPE original metadata", + "type": "text/xml" + }, + "B5": { + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "eo:bands": [ { - "rel": "parent", - "href": "../catalog.json", - "type": "application/json" + "name": "B5", + "common_name": "blue" } - ], - "stac_extensions": [ - "eo", - "item-assets" - ], - "providers": [ - { - "name": "Instituto Nacional de Pesquisas Espaciais, INPE", - "roles": [ - "producer" - ], - "url": "http://www.cbers.inpe.br" - }, - { - "name": "AMS Kepler", - "description": "Convert INPE's original TIFF to COG and copy to Amazon Web Services", - "roles": [ - "processor" - ], - "url": "https://github.com/fredliporace/cbers-on-aws" - }, + ] + }, + "B6": { + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "eo:bands": [ { - "name": "Amazon Web Services", - "roles": [ - "host" - ], - "url": "https://registry.opendata.aws/cbers/" + "name": "B6", + "common_name": "green" } - ], - "properties": { - "gsd": 20.0, - "platform": "CBERS-4", - "instruments": [ - "MUX" - ] + ] }, - "item_assets": { - "thumbnail": { - "title": "Thumbnail", - "type": "image/jpeg" - }, - "metadata": { - "title": "INPE original metadata", - "type": "text/xml" - }, - "B5": { - "type": "image/tiff; application=geotiff; profile=cloud-optimized", - "eo:bands": [ - { - "name": "B5", - "common_name": "blue" - } - ] - }, - "B6": { - "type": "image/tiff; application=geotiff; profile=cloud-optimized", - "eo:bands": [ - { - "name": "B6", - "common_name": "green" - } - ] - }, - "B7": { - "type": "image/tiff; application=geotiff; profile=cloud-optimized", - "eo:bands": [ - { - "name": "B7", - "common_name": "red" - } - ] - }, - "B8": { - "type": "image/tiff; application=geotiff; profile=cloud-optimized", - "eo:bands": [ - { - "name": "B8", - "common_name": "nir" - } - ] + "B7": { + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "eo:bands": [ + { + "name": "B7", + "common_name": "red" } + ] }, - "extent": { - "spatial": { - "bbox": [ - [ - -180.0, - -83.0, - 180.0, - 83.0 - ] - ] - }, - "temporal": { - "interval": [ - [ - "2014-12-08T00:00:00Z", - null - ] - ] + "B8": { + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "eo:bands": [ + { + "name": "B8", + "common_name": "nir" } + ] + } + }, + "extent": { + "spatial": { + "bbox": [ + [ + -180.0, + -83.0, + 180.0, + 83.0 + ] + ] }, - "license": "CC-BY-SA-3.0" -} + "temporal": { + "interval": [ + [ + "2014-12-08T00:00:00Z", + null + ] + ] + } + }, + "license": "CC-BY-SA-3.0" +} \ No newline at end of file diff --git a/tests/data-files/catalogs/cbers-partial/CBERS4PAN10M/collection.json b/tests/data-files/catalogs/cbers-partial/CBERS4PAN10M/collection.json index f1d53143f..7e267e87b 100644 --- a/tests/data-files/catalogs/cbers-partial/CBERS4PAN10M/collection.json +++ b/tests/data-files/catalogs/cbers-partial/CBERS4PAN10M/collection.json @@ -1,110 +1,111 @@ { - "id": "CBERS4PAN10M", - "stac_version": "1.0.0-beta.2", - "description": "CBERS4 PAN10M camera catalog", - "links": [ - { - "rel": "root", - "href": "../catalog.json", - "type": "application/json" - }, - { - "rel": "parent", - "href": "../catalog.json", - "type": "application/json" - } - ], - "stac_extensions": [ - "eo", - "item-assets" - ], - "providers": [ - { - "name": "Instituto Nacional de Pesquisas Espaciais, INPE", - "roles": [ - "producer" - ], - "url": "http://www.cbers.inpe.br" - }, - { - "name": "AMS Kepler", - "description": "Convert INPE's original TIFF to COG and copy to Amazon Web Services", - "roles": [ - "processor" - ], - "url": "https://github.com/fredliporace/cbers-on-aws" - }, + "type": "Collection", + "id": "CBERS4PAN10M", + "stac_version": "1.0.0-rc.3", + "description": "CBERS4 PAN10M camera catalog", + "links": [ + { + "rel": "root", + "href": "../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../catalog.json", + "type": "application/json" + } + ], + "stac_extensions": [ + "eo", + "item-assets" + ], + "providers": [ + { + "name": "Instituto Nacional de Pesquisas Espaciais, INPE", + "roles": [ + "producer" + ], + "url": "http://www.cbers.inpe.br" + }, + { + "name": "AMS Kepler", + "description": "Convert INPE's original TIFF to COG and copy to Amazon Web Services", + "roles": [ + "processor" + ], + "url": "https://github.com/fredliporace/cbers-on-aws" + }, + { + "name": "Amazon Web Services", + "roles": [ + "host" + ], + "url": "https://registry.opendata.aws/cbers/" + } + ], + "properties": { + "gsd": 10.0, + "platform": "CBERS-4", + "instruments": [ + "PAN10M" + ] + }, + "item_assets": { + "thumbnail": { + "title": "Thumbnail", + "type": "image/jpeg" + }, + "metadata": { + "title": "INPE original metadata", + "type": "text/xml" + }, + "B2": { + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "eo:bands": [ { - "name": "Amazon Web Services", - "roles": [ - "host" - ], - "url": "https://registry.opendata.aws/cbers/" + "name": "B2", + "common_name": "green" } - ], - "properties": { - "gsd": 10.0, - "platform": "CBERS-4", - "instruments": [ - "PAN10M" - ] + ] }, - "item_assets": { - "thumbnail": { - "title": "Thumbnail", - "type": "image/jpeg" - }, - "metadata": { - "title": "INPE original metadata", - "type": "text/xml" - }, - "B2": { - "type": "image/tiff; application=geotiff; profile=cloud-optimized", - "eo:bands": [ - { - "name": "B2", - "common_name": "green" - } - ] - }, - "B3": { - "type": "image/tiff; application=geotiff; profile=cloud-optimized", - "eo:bands": [ - { - "name": "B3", - "common_name": "red" - } - ] - }, - "B4": { - "type": "image/tiff; application=geotiff; profile=cloud-optimized", - "eo:bands": [ - { - "name": "B4", - "common_name": "nir" - } - ] + "B3": { + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "eo:bands": [ + { + "name": "B3", + "common_name": "red" } + ] }, - "extent": { - "spatial": { - "bbox": [ - [ - -180.0, - -83.0, - 180.0, - 83.0 - ] - ] - }, - "temporal": { - "interval": [ - [ - "2014-12-08T00:00:00Z", - null - ] - ] + "B4": { + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "eo:bands": [ + { + "name": "B4", + "common_name": "nir" } + ] + } + }, + "extent": { + "spatial": { + "bbox": [ + [ + -180.0, + -83.0, + 180.0, + 83.0 + ] + ] }, - "license": "CC-BY-SA-3.0" -} + "temporal": { + "interval": [ + [ + "2014-12-08T00:00:00Z", + null + ] + ] + } + }, + "license": "CC-BY-SA-3.0" +} \ No newline at end of file diff --git a/tests/data-files/catalogs/cbers-partial/CBERS4PAN5M/collection.json b/tests/data-files/catalogs/cbers-partial/CBERS4PAN5M/collection.json index 2ac16b9f4..c85a652fb 100644 --- a/tests/data-files/catalogs/cbers-partial/CBERS4PAN5M/collection.json +++ b/tests/data-files/catalogs/cbers-partial/CBERS4PAN5M/collection.json @@ -1,92 +1,93 @@ { - "id": "CBERS4PAN5M", - "stac_version": "1.0.0-beta.2", - "description": "CBERS4 PAN5M camera catalog", - "links": [ - { - "rel": "root", - "href": "../catalog.json", - "type": "application/json" - }, - { - "rel": "parent", - "href": "../catalog.json", - "type": "application/json" - } - ], - "stac_extensions": [ - "eo", - "item-assets" - ], - "providers": [ - { - "name": "Instituto Nacional de Pesquisas Espaciais, INPE", - "roles": [ - "producer" - ], - "url": "http://www.cbers.inpe.br" - }, - { - "name": "AMS Kepler", - "description": "Convert INPE's original TIFF to COG and copy to Amazon Web Services", - "roles": [ - "processor" - ], - "url": "https://github.com/fredliporace/cbers-on-aws" - }, - { - "name": "Amazon Web Services", - "roles": [ - "host" - ], - "url": "https://registry.opendata.aws/cbers/" - } - ], - "properties": { - "gsd": 5.0, - "platform": "CBERS-4", - "instruments": [ - "PAN5M" - ] + "type": "Collection", + "id": "CBERS4PAN5M", + "stac_version": "1.0.0-rc.3", + "description": "CBERS4 PAN5M camera catalog", + "links": [ + { + "rel": "root", + "href": "../catalog.json", + "type": "application/json" }, - "item_assets": { - "thumbnail": { - "title": "Thumbnail", - "type": "image/jpeg" - }, - "metadata": { - "title": "INPE original metadata", - "type": "text/xml" - }, - "B1": { - "type": "image/tiff; application=geotiff; profile=cloud-optimized", - "eo:bands": [ - { - "name": "B1", - "common_name": "pan" - } - ] - } + { + "rel": "parent", + "href": "../catalog.json", + "type": "application/json" + } + ], + "stac_extensions": [ + "eo", + "item-assets" + ], + "providers": [ + { + "name": "Instituto Nacional de Pesquisas Espaciais, INPE", + "roles": [ + "producer" + ], + "url": "http://www.cbers.inpe.br" + }, + { + "name": "AMS Kepler", + "description": "Convert INPE's original TIFF to COG and copy to Amazon Web Services", + "roles": [ + "processor" + ], + "url": "https://github.com/fredliporace/cbers-on-aws" + }, + { + "name": "Amazon Web Services", + "roles": [ + "host" + ], + "url": "https://registry.opendata.aws/cbers/" + } + ], + "properties": { + "gsd": 5.0, + "platform": "CBERS-4", + "instruments": [ + "PAN5M" + ] + }, + "item_assets": { + "thumbnail": { + "title": "Thumbnail", + "type": "image/jpeg" + }, + "metadata": { + "title": "INPE original metadata", + "type": "text/xml" }, - "extent": { - "spatial": { - "bbox": [ - [ - -180.0, - -83.0, - 180.0, - 83.0 - ] - ] - }, - "temporal": { - "interval": [ - [ - "2014-12-08T00:00:00Z", - null - ] - ] + "B1": { + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "eo:bands": [ + { + "name": "B1", + "common_name": "pan" } + ] + } + }, + "extent": { + "spatial": { + "bbox": [ + [ + -180.0, + -83.0, + 180.0, + 83.0 + ] + ] }, - "license": "CC-BY-SA-3.0" -} + "temporal": { + "interval": [ + [ + "2014-12-08T00:00:00Z", + null + ] + ] + } + }, + "license": "CC-BY-SA-3.0" +} \ No newline at end of file diff --git a/tests/data-files/catalogs/cbers-partial/catalog.json b/tests/data-files/catalogs/cbers-partial/catalog.json index 4ac54b6fd..d5ee92404 100644 --- a/tests/data-files/catalogs/cbers-partial/catalog.json +++ b/tests/data-files/catalogs/cbers-partial/catalog.json @@ -1,28 +1,30 @@ { - "id": "CBERS4", - "stac_version": "1.0.0-beta.2", - "description": "Catalogs of CBERS-4 mission's imagery on AWS", - "links": [ - { - "rel": "root", - "href": "https://cbers-stac-1-0.s3.amazonaws.com/catalog.json", - "type": "application/json" - }, - { - "rel": "child", - "href": "./CBERS4MUX/collection.json" - }, - { - "rel": "child", - "href": "./CBERS4AWFI/collection.json" - }, - { - "rel": "child", - "href": "./CBERS4PAN10M/collection.json" - }, - { - "rel": "child", - "href": "./CBERS4PAN5M/collection.json" - } - ] -} + "type": "Catalog", + "id": "CBERS4", + "stac_version": "1.0.0-rc.3", + "description": "Catalogs of CBERS-4 mission's imagery on AWS", + "links": [ + { + "rel": "root", + "href": "https://cbers-stac-1-0.s3.amazonaws.com/catalog.json", + "type": "application/json" + }, + { + "rel": "child", + "href": "./CBERS4MUX/collection.json" + }, + { + "rel": "child", + "href": "./CBERS4AWFI/collection.json" + }, + { + "rel": "child", + "href": "./CBERS4PAN10M/collection.json" + }, + { + "rel": "child", + "href": "./CBERS4PAN5M/collection.json" + } + ], + "stac_extensions": [] +} \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/acc/665946-labels/665946-labels.json b/tests/data-files/catalogs/label_catalog-v0.8.1/acc/665946-labels/665946-labels.json similarity index 98% rename from tests/data-files/catalogs/label_catalog_0_8_1/acc/665946-labels/665946-labels.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/acc/665946-labels/665946-labels.json index 429604d14..0f825fb88 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/acc/665946-labels/665946-labels.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/acc/665946-labels/665946-labels.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "665946-labels", "properties": { "label:description": "Geojson building labels for scene 665946", @@ -258,12 +258,6 @@ ], "type": "Polygon" }, - "bbox": [ - -0.24297113100354567, - 5.620077394512653, - -0.22777618020007248, - 5.647261088925513 - ], "links": [ { "rel": "collection", @@ -287,7 +281,14 @@ "type": "application/geo+json" } }, + "bbox": [ + -0.24297113100354567, + 5.620077394512653, + -0.22777618020007248, + 5.647261088925513 + ], "stac_extensions": [ - "label" - ] + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "acc" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/acc/665946/665946.json b/tests/data-files/catalogs/label_catalog-v0.8.1/acc/665946/665946.json similarity index 99% rename from tests/data-files/catalogs/label_catalog_0_8_1/acc/665946/665946.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/acc/665946/665946.json index eeb106f92..bd4c9dd4f 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/acc/665946/665946.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/acc/665946/665946.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "665946", "properties": { "area": "acc", @@ -234,12 +234,6 @@ ], "type": "Polygon" }, - "bbox": [ - -0.24297113100354567, - 5.620077394512653, - -0.22777618020007248, - 5.647261088925513 - ], "links": [ { "rel": "collection", @@ -264,5 +258,12 @@ "title": "GeoTIFF" } }, + "bbox": [ + -0.24297113100354567, + 5.620077394512653, + -0.22777618020007248, + 5.647261088925513 + ], + "stac_extensions": [], "collection": "acc" -} +} \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/acc/a42435-labels/a42435-labels.json b/tests/data-files/catalogs/label_catalog-v0.8.1/acc/a42435-labels/a42435-labels.json similarity index 97% rename from tests/data-files/catalogs/label_catalog_0_8_1/acc/a42435-labels/a42435-labels.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/acc/a42435-labels/a42435-labels.json index bb4580866..52a1042e2 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/acc/a42435-labels/a42435-labels.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/acc/a42435-labels/a42435-labels.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "a42435-labels", "properties": { "label:description": "Geojson building labels for scene a42435", @@ -174,12 +174,6 @@ ], "type": "Polygon" }, - "bbox": [ - -0.2498678517428029, - 5.607877073189545, - -0.23326449513459932, - 5.619166711344742 - ], "links": [ { "rel": "collection", @@ -203,7 +197,14 @@ "type": "application/geo+json" } }, + "bbox": [ + -0.2498678517428029, + 5.607877073189545, + -0.23326449513459932, + 5.619166711344742 + ], "stac_extensions": [ - "label" - ] + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "acc" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/acc/a42435/a42435.json b/tests/data-files/catalogs/label_catalog-v0.8.1/acc/a42435/a42435.json similarity index 98% rename from tests/data-files/catalogs/label_catalog_0_8_1/acc/a42435/a42435.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/acc/a42435/a42435.json index a1c96212c..df352a839 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/acc/a42435/a42435.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/acc/a42435/a42435.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "a42435", "properties": { "area": "acc", @@ -150,12 +150,6 @@ ], "type": "Polygon" }, - "bbox": [ - -0.2498678517428029, - 5.607877073189545, - -0.23326449513459932, - 5.619166711344742 - ], "links": [ { "rel": "collection", @@ -180,5 +174,12 @@ "title": "GeoTIFF" } }, + "bbox": [ + -0.2498678517428029, + 5.607877073189545, + -0.23326449513459932, + 5.619166711344742 + ], + "stac_extensions": [], "collection": "acc" -} +} \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/acc/ca041a-labels/ca041a-labels.json b/tests/data-files/catalogs/label_catalog-v0.8.1/acc/ca041a-labels/ca041a-labels.json similarity index 97% rename from tests/data-files/catalogs/label_catalog_0_8_1/acc/ca041a-labels/ca041a-labels.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/acc/ca041a-labels/ca041a-labels.json index ae1f6c44c..41b4279a4 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/acc/ca041a-labels/ca041a-labels.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/acc/ca041a-labels/ca041a-labels.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "ca041a-labels", "properties": { "label:description": "Geojson building labels for scene ca041a", @@ -170,12 +170,6 @@ ], "type": "Polygon" }, - "bbox": [ - -0.22707525357332697, - 5.585527399115482, - -0.20581415249279408, - 5.610742610987594 - ], "links": [ { "rel": "collection", @@ -199,7 +193,14 @@ "type": "application/geo+json" } }, + "bbox": [ + -0.22707525357332697, + 5.585527399115482, + -0.20581415249279408, + 5.610742610987594 + ], "stac_extensions": [ - "label" - ] + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "acc" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/acc/ca041a/ca041a.json b/tests/data-files/catalogs/label_catalog-v0.8.1/acc/ca041a/ca041a.json similarity index 98% rename from tests/data-files/catalogs/label_catalog_0_8_1/acc/ca041a/ca041a.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/acc/ca041a/ca041a.json index bcd9428ed..d2abc4c05 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/acc/ca041a/ca041a.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/acc/ca041a/ca041a.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "ca041a", "properties": { "area": "acc", @@ -146,12 +146,6 @@ ], "type": "Polygon" }, - "bbox": [ - -0.22707525357332697, - 5.585527399115482, - -0.20581415249279408, - 5.610742610987594 - ], "links": [ { "rel": "collection", @@ -176,5 +170,12 @@ "title": "GeoTIFF" } }, + "bbox": [ + -0.22707525357332697, + 5.585527399115482, + -0.20581415249279408, + 5.610742610987594 + ], + "stac_extensions": [], "collection": "acc" -} +} \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/acc/collection.json b/tests/data-files/catalogs/label_catalog-v0.8.1/acc/collection.json similarity index 96% rename from tests/data-files/catalogs/label_catalog_0_8_1/acc/collection.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/acc/collection.json index baf12f11a..0de579cda 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/acc/collection.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/acc/collection.json @@ -74,8 +74,5 @@ ] } }, - "license": "various", - "stac_extensions": [ - "label" - ] + "license": "various" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/acc/d41d81-labels/d41d81-labels.json b/tests/data-files/catalogs/label_catalog-v0.8.1/acc/d41d81-labels/d41d81-labels.json similarity index 97% rename from tests/data-files/catalogs/label_catalog_0_8_1/acc/d41d81-labels/d41d81-labels.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/acc/d41d81-labels/d41d81-labels.json index e3cdba650..799c1d6b0 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/acc/d41d81-labels/d41d81-labels.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/acc/d41d81-labels/d41d81-labels.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "d41d81-labels", "properties": { "label:description": "Geojson building labels for scene d41d81", @@ -202,12 +202,6 @@ ], "type": "Polygon" }, - "bbox": [ - -0.20863145179911316, - 5.573262528211078, - -0.18948660187120017, - 5.593203677296213 - ], "links": [ { "rel": "collection", @@ -231,7 +225,14 @@ "type": "application/geo+json" } }, + "bbox": [ + -0.20863145179911316, + 5.573262528211078, + -0.18948660187120017, + 5.593203677296213 + ], "stac_extensions": [ - "label" - ] + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "acc" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/acc/d41d81/d41d81.json b/tests/data-files/catalogs/label_catalog-v0.8.1/acc/d41d81/d41d81.json similarity index 98% rename from tests/data-files/catalogs/label_catalog_0_8_1/acc/d41d81/d41d81.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/acc/d41d81/d41d81.json index 53bc3a41c..7649f0f2e 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/acc/d41d81/d41d81.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/acc/d41d81/d41d81.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "d41d81", "properties": { "area": "acc", @@ -178,12 +178,6 @@ ], "type": "Polygon" }, - "bbox": [ - -0.20863145179911316, - 5.573262528211078, - -0.18948660187120017, - 5.593203677296213 - ], "links": [ { "rel": "collection", @@ -208,5 +202,12 @@ "title": "GeoTIFF" } }, + "bbox": [ + -0.20863145179911316, + 5.573262528211078, + -0.18948660187120017, + 5.593203677296213 + ], + "stac_extensions": [], "collection": "acc" -} +} \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/catalog.json b/tests/data-files/catalogs/label_catalog-v0.8.1/catalog.json similarity index 100% rename from tests/data-files/catalogs/label_catalog_0_8_1/catalog.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/catalog.json diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/dar/0a4c40-labels/0a4c40-labels.json b/tests/data-files/catalogs/label_catalog-v0.8.1/dar/0a4c40-labels/0a4c40-labels.json similarity index 99% rename from tests/data-files/catalogs/label_catalog_0_8_1/dar/0a4c40-labels/0a4c40-labels.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/dar/0a4c40-labels/0a4c40-labels.json index a39a234e3..f69f203cf 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/dar/0a4c40-labels/0a4c40-labels.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/dar/0a4c40-labels/0a4c40-labels.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "0a4c40-labels", "properties": { "label:description": "Geojson building labels for scene 0a4c40", @@ -578,12 +578,6 @@ ] ] }, - "bbox": [ - 39.276084515013736, - -6.831966577377629, - 39.304456754694705, - -6.801144663537702 - ], "links": [ { "rel": "collection", @@ -607,7 +601,14 @@ "type": "application/geo+json" } }, + "bbox": [ + 39.276084515013736, + -6.831966577377629, + 39.304456754694705, + -6.801144663537702 + ], "stac_extensions": [ - "label" - ] + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "dar" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/dar/0a4c40/0a4c40.json b/tests/data-files/catalogs/label_catalog-v0.8.1/dar/0a4c40/0a4c40.json similarity index 99% rename from tests/data-files/catalogs/label_catalog_0_8_1/dar/0a4c40/0a4c40.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/dar/0a4c40/0a4c40.json index 1fc513512..20eb50e69 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/dar/0a4c40/0a4c40.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/dar/0a4c40/0a4c40.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "0a4c40", "properties": { "area": "dar", @@ -554,12 +554,6 @@ ] ] }, - "bbox": [ - 39.276084515013736, - -6.831966577377629, - 39.304456754694705, - -6.801144663537702 - ], "links": [ { "rel": "collection", @@ -584,5 +578,12 @@ "title": "GeoTIFF" } }, + "bbox": [ + 39.276084515013736, + -6.831966577377629, + 39.304456754694705, + -6.801144663537702 + ], + "stac_extensions": [], "collection": "dar" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/dar/353093-labels/353093-labels.json b/tests/data-files/catalogs/label_catalog-v0.8.1/dar/353093-labels/353093-labels.json similarity index 97% rename from tests/data-files/catalogs/label_catalog_0_8_1/dar/353093-labels/353093-labels.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/dar/353093-labels/353093-labels.json index ef1bfd2b7..63e7bcb9c 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/dar/353093-labels/353093-labels.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/dar/353093-labels/353093-labels.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "353093-labels", "properties": { "label:description": "Geojson building labels for scene 353093", @@ -194,12 +194,6 @@ ], "type": "Polygon" }, - "bbox": [ - 39.20390891675323, - -6.809511989589884, - 39.2270869431941, - -6.783684392169557 - ], "links": [ { "rel": "collection", @@ -223,7 +217,14 @@ "type": "application/geo+json" } }, + "bbox": [ + 39.20390891675323, + -6.809511989589884, + 39.2270869431941, + -6.783684392169557 + ], "stac_extensions": [ - "label" - ] + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "dar" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/dar/353093/353093.json b/tests/data-files/catalogs/label_catalog-v0.8.1/dar/353093/353093.json similarity index 98% rename from tests/data-files/catalogs/label_catalog_0_8_1/dar/353093/353093.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/dar/353093/353093.json index ca670a9c0..b24d05651 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/dar/353093/353093.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/dar/353093/353093.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "353093", "properties": { "area": "dar", @@ -170,12 +170,6 @@ ], "type": "Polygon" }, - "bbox": [ - 39.20390891675323, - -6.809511989589884, - 39.2270869431941, - -6.783684392169557 - ], "links": [ { "rel": "collection", @@ -200,5 +194,12 @@ "title": "GeoTIFF" } }, + "bbox": [ + 39.20390891675323, + -6.809511989589884, + 39.2270869431941, + -6.783684392169557 + ], + "stac_extensions": [], "collection": "dar" -} +} \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/dar/42f235-labels/42f235-labels.json b/tests/data-files/catalogs/label_catalog-v0.8.1/dar/42f235-labels/42f235-labels.json similarity index 99% rename from tests/data-files/catalogs/label_catalog_0_8_1/dar/42f235-labels/42f235-labels.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/dar/42f235-labels/42f235-labels.json index 00895b300..670590586 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/dar/42f235-labels/42f235-labels.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/dar/42f235-labels/42f235-labels.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "42f235-labels", "properties": { "label:description": "Geojson building labels for scene 42f235", @@ -820,12 +820,6 @@ ] ] }, - "bbox": [ - 39.2484489815814, - -6.832170132981521, - 39.28214024571535, - -6.800774407651622 - ], "links": [ { "rel": "collection", @@ -849,7 +843,14 @@ "type": "application/geo+json" } }, + "bbox": [ + 39.2484489815814, + -6.832170132981521, + 39.28214024571535, + -6.800774407651622 + ], "stac_extensions": [ - "label" - ] + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "dar" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/dar/42f235/42f235.json b/tests/data-files/catalogs/label_catalog-v0.8.1/dar/42f235/42f235.json similarity index 99% rename from tests/data-files/catalogs/label_catalog_0_8_1/dar/42f235/42f235.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/dar/42f235/42f235.json index 3bfc184a7..18ffed606 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/dar/42f235/42f235.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/dar/42f235/42f235.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "42f235", "properties": { "area": "dar", @@ -796,12 +796,6 @@ ] ] }, - "bbox": [ - 39.2484489815814, - -6.832170132981521, - 39.28214024571535, - -6.800774407651622 - ], "links": [ { "rel": "collection", @@ -826,5 +820,12 @@ "title": "GeoTIFF" } }, + "bbox": [ + 39.2484489815814, + -6.832170132981521, + 39.28214024571535, + -6.800774407651622 + ], + "stac_extensions": [], "collection": "dar" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/dar/a017f9-labels/a017f9-labels.json b/tests/data-files/catalogs/label_catalog-v0.8.1/dar/a017f9-labels/a017f9-labels.json similarity index 99% rename from tests/data-files/catalogs/label_catalog_0_8_1/dar/a017f9-labels/a017f9-labels.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/dar/a017f9-labels/a017f9-labels.json index 7666a78d1..1025e7bf8 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/dar/a017f9-labels/a017f9-labels.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/dar/a017f9-labels/a017f9-labels.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "a017f9-labels", "properties": { "label:description": "Geojson building labels for scene a017f9", @@ -790,12 +790,6 @@ ], "type": "Polygon" }, - "bbox": [ - 39.25403029430106, - -6.779784892393674, - 39.2731659202684, - -6.759102343973786 - ], "links": [ { "rel": "collection", @@ -819,7 +813,14 @@ "type": "application/geo+json" } }, + "bbox": [ + 39.25403029430106, + -6.779784892393674, + 39.2731659202684, + -6.759102343973786 + ], "stac_extensions": [ - "label" - ] + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "dar" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/dar/a017f9/a017f9.json b/tests/data-files/catalogs/label_catalog-v0.8.1/dar/a017f9/a017f9.json similarity index 99% rename from tests/data-files/catalogs/label_catalog_0_8_1/dar/a017f9/a017f9.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/dar/a017f9/a017f9.json index b66ecbc72..be22c5b66 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/dar/a017f9/a017f9.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/dar/a017f9/a017f9.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "a017f9", "properties": { "area": "dar", @@ -766,12 +766,6 @@ ], "type": "Polygon" }, - "bbox": [ - 39.25403029430106, - -6.779784892393674, - 39.2731659202684, - -6.759102343973786 - ], "links": [ { "rel": "collection", @@ -796,5 +790,12 @@ "title": "GeoTIFF" } }, + "bbox": [ + 39.25403029430106, + -6.779784892393674, + 39.2731659202684, + -6.759102343973786 + ], + "stac_extensions": [], "collection": "dar" -} +} \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/dar/b15fce-labels/b15fce-labels.json b/tests/data-files/catalogs/label_catalog-v0.8.1/dar/b15fce-labels/b15fce-labels.json similarity index 97% rename from tests/data-files/catalogs/label_catalog_0_8_1/dar/b15fce-labels/b15fce-labels.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/dar/b15fce-labels/b15fce-labels.json index b91a33414..80c95e106 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/dar/b15fce-labels/b15fce-labels.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/dar/b15fce-labels/b15fce-labels.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "b15fce-labels", "properties": { "label:description": "Geojson building labels for scene b15fce", @@ -146,12 +146,6 @@ ] ] }, - "bbox": [ - 39.231583919750726, - -6.806085900208043, - 39.25215435443532, - -6.786630132161881 - ], "links": [ { "rel": "collection", @@ -175,7 +169,14 @@ "type": "application/geo+json" } }, + "bbox": [ + 39.231583919750726, + -6.806085900208043, + 39.25215435443532, + -6.786630132161881 + ], "stac_extensions": [ - "label" - ] + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "dar" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/dar/b15fce/b15fce.json b/tests/data-files/catalogs/label_catalog-v0.8.1/dar/b15fce/b15fce.json similarity index 98% rename from tests/data-files/catalogs/label_catalog_0_8_1/dar/b15fce/b15fce.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/dar/b15fce/b15fce.json index 46d5eb70a..9920d57d4 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/dar/b15fce/b15fce.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/dar/b15fce/b15fce.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "b15fce", "properties": { "area": "dar", @@ -122,12 +122,6 @@ ] ] }, - "bbox": [ - 39.231583919750726, - -6.806085900208043, - 39.25215435443532, - -6.786630132161881 - ], "links": [ { "rel": "collection", @@ -152,5 +146,12 @@ "title": "GeoTIFF" } }, + "bbox": [ + 39.231583919750726, + -6.806085900208043, + 39.25215435443532, + -6.786630132161881 + ], + "stac_extensions": [], "collection": "dar" -} +} \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/dar/collection.json b/tests/data-files/catalogs/label_catalog-v0.8.1/dar/collection.json similarity index 97% rename from tests/data-files/catalogs/label_catalog_0_8_1/dar/collection.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/dar/collection.json index a04b1d5db..651125b70 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/dar/collection.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/dar/collection.json @@ -94,8 +94,5 @@ ] } }, - "license": "various", - "stac_extensions": [ - "label" - ] + "license": "various" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/dar/f883a0-labels/f883a0-labels.json b/tests/data-files/catalogs/label_catalog-v0.8.1/dar/f883a0-labels/f883a0-labels.json similarity index 99% rename from tests/data-files/catalogs/label_catalog_0_8_1/dar/f883a0-labels/f883a0-labels.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/dar/f883a0-labels/f883a0-labels.json index 03223cfe9..1bb93fb69 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/dar/f883a0-labels/f883a0-labels.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/dar/f883a0-labels/f883a0-labels.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "f883a0-labels", "properties": { "label:description": "Geojson building labels for scene f883a0", @@ -1256,12 +1256,6 @@ ] ] }, - "bbox": [ - 39.24966102436161, - -6.804292908938633, - 39.28114400293776, - -6.773980646345491 - ], "links": [ { "rel": "collection", @@ -1285,7 +1279,14 @@ "type": "application/geo+json" } }, + "bbox": [ + 39.24966102436161, + -6.804292908938633, + 39.28114400293776, + -6.773980646345491 + ], "stac_extensions": [ - "label" - ] + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "dar" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/dar/f883a0/f883a0.json b/tests/data-files/catalogs/label_catalog-v0.8.1/dar/f883a0/f883a0.json similarity index 99% rename from tests/data-files/catalogs/label_catalog_0_8_1/dar/f883a0/f883a0.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/dar/f883a0/f883a0.json index 76379599f..817441517 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/dar/f883a0/f883a0.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/dar/f883a0/f883a0.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "f883a0", "properties": { "area": "dar", @@ -1232,12 +1232,6 @@ ] ] }, - "bbox": [ - 39.24966102436161, - -6.804292908938633, - 39.28114400293776, - -6.773980646345491 - ], "links": [ { "rel": "collection", @@ -1262,5 +1256,12 @@ "title": "GeoTIFF" } }, + "bbox": [ + 39.24966102436161, + -6.804292908938633, + 39.28114400293776, + -6.773980646345491 + ], + "stac_extensions": [], "collection": "dar" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/kam/4e7c7f-labels/4e7c7f-labels.json b/tests/data-files/catalogs/label_catalog-v0.8.1/kam/4e7c7f-labels/4e7c7f-labels.json similarity index 98% rename from tests/data-files/catalogs/label_catalog_0_8_1/kam/4e7c7f-labels/4e7c7f-labels.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/kam/4e7c7f-labels/4e7c7f-labels.json index ea534e7fd..38250e5ff 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/kam/4e7c7f-labels/4e7c7f-labels.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/kam/4e7c7f-labels/4e7c7f-labels.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "4e7c7f-labels", "properties": { "label:description": "Geojson building labels for scene 4e7c7f", @@ -390,12 +390,6 @@ ], "type": "Polygon" }, - "bbox": [ - 32.626179443806286, - 0.24927592951780594, - 32.638649276300896, - 0.26207074609958386 - ], "links": [ { "rel": "collection", @@ -419,7 +413,14 @@ "type": "application/geo+json" } }, + "bbox": [ + 32.626179443806286, + 0.24927592951780594, + 32.638649276300896, + 0.26207074609958386 + ], "stac_extensions": [ - "label" - ] + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "kam" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/kam/4e7c7f/4e7c7f.json b/tests/data-files/catalogs/label_catalog-v0.8.1/kam/4e7c7f/4e7c7f.json similarity index 99% rename from tests/data-files/catalogs/label_catalog_0_8_1/kam/4e7c7f/4e7c7f.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/kam/4e7c7f/4e7c7f.json index 83e039500..a49d7626f 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/kam/4e7c7f/4e7c7f.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/kam/4e7c7f/4e7c7f.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "4e7c7f", "properties": { "area": "kam", @@ -366,12 +366,6 @@ ], "type": "Polygon" }, - "bbox": [ - 32.626179443806286, - 0.24927592951780594, - 32.638649276300896, - 0.26207074609958386 - ], "links": [ { "rel": "collection", @@ -396,5 +390,12 @@ "title": "GeoTIFF" } }, + "bbox": [ + 32.626179443806286, + 0.24927592951780594, + 32.638649276300896, + 0.26207074609958386 + ], + "stac_extensions": [], "collection": "kam" -} +} \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/kam/collection.json b/tests/data-files/catalogs/label_catalog-v0.8.1/kam/collection.json similarity index 93% rename from tests/data-files/catalogs/label_catalog_0_8_1/kam/collection.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/kam/collection.json index d3b1207af..45b550a46 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/kam/collection.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/kam/collection.json @@ -44,8 +44,5 @@ ] } }, - "license": "various", - "stac_extensions": [ - "label" - ] + "license": "various" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/mon/207cc7-labels/207cc7-labels.json b/tests/data-files/catalogs/label_catalog-v0.8.1/mon/207cc7-labels/207cc7-labels.json similarity index 98% rename from tests/data-files/catalogs/label_catalog_0_8_1/mon/207cc7-labels/207cc7-labels.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/mon/207cc7-labels/207cc7-labels.json index f596cd68c..55fc79920 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/mon/207cc7-labels/207cc7-labels.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/mon/207cc7-labels/207cc7-labels.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "207cc7-labels", "properties": { "label:description": "Geojson building labels for scene 207cc7", @@ -206,12 +206,6 @@ ], "type": "Polygon" }, - "bbox": [ - -10.798182715496184, - 6.325934341609507, - -10.788359662453985, - 6.333146686841442 - ], "links": [ { "rel": "collection", @@ -235,7 +229,14 @@ "type": "application/geo+json" } }, + "bbox": [ + -10.798182715496184, + 6.325934341609507, + -10.788359662453985, + 6.333146686841442 + ], "stac_extensions": [ - "label" - ] + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "mon" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/mon/207cc7/207cc7.json b/tests/data-files/catalogs/label_catalog-v0.8.1/mon/207cc7/207cc7.json similarity index 98% rename from tests/data-files/catalogs/label_catalog_0_8_1/mon/207cc7/207cc7.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/mon/207cc7/207cc7.json index 4d1e7f29d..e5ec355f9 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/mon/207cc7/207cc7.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/mon/207cc7/207cc7.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "207cc7", "properties": { "area": "mon", @@ -182,12 +182,6 @@ ], "type": "Polygon" }, - "bbox": [ - -10.798182715496184, - 6.325934341609507, - -10.788359662453985, - 6.333146686841442 - ], "links": [ { "rel": "collection", @@ -212,5 +206,12 @@ "title": "GeoTIFF" } }, + "bbox": [ + -10.798182715496184, + 6.325934341609507, + -10.788359662453985, + 6.333146686841442 + ], + "stac_extensions": [], "collection": "mon" -} +} \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/mon/401175-labels/401175-labels.json b/tests/data-files/catalogs/label_catalog-v0.8.1/mon/401175-labels/401175-labels.json similarity index 97% rename from tests/data-files/catalogs/label_catalog_0_8_1/mon/401175-labels/401175-labels.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/mon/401175-labels/401175-labels.json index 76dd87f00..3bfc716aa 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/mon/401175-labels/401175-labels.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/mon/401175-labels/401175-labels.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "401175-labels", "properties": { "label:description": "Geojson building labels for scene 401175", @@ -198,12 +198,6 @@ ], "type": "Polygon" }, - "bbox": [ - -10.793204246358947, - 6.330781306914856, - -10.783947405680633, - 6.339080445680323 - ], "links": [ { "rel": "collection", @@ -227,7 +221,14 @@ "type": "application/geo+json" } }, + "bbox": [ + -10.793204246358947, + 6.330781306914856, + -10.783947405680633, + 6.339080445680323 + ], "stac_extensions": [ - "label" - ] + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "mon" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/mon/401175/401175.json b/tests/data-files/catalogs/label_catalog-v0.8.1/mon/401175/401175.json similarity index 98% rename from tests/data-files/catalogs/label_catalog_0_8_1/mon/401175/401175.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/mon/401175/401175.json index ea51ca04b..26a75cca8 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/mon/401175/401175.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/mon/401175/401175.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "401175", "properties": { "area": "mon", @@ -174,12 +174,6 @@ ], "type": "Polygon" }, - "bbox": [ - -10.793204246358947, - 6.330781306914856, - -10.783947405680633, - 6.339080445680323 - ], "links": [ { "rel": "collection", @@ -204,5 +198,12 @@ "title": "GeoTIFF" } }, + "bbox": [ + -10.793204246358947, + 6.330781306914856, + -10.783947405680633, + 6.339080445680323 + ], + "stac_extensions": [], "collection": "mon" -} +} \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/mon/493701-labels/493701-labels.json b/tests/data-files/catalogs/label_catalog-v0.8.1/mon/493701-labels/493701-labels.json similarity index 97% rename from tests/data-files/catalogs/label_catalog_0_8_1/mon/493701-labels/493701-labels.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/mon/493701-labels/493701-labels.json index 15688928c..691d1632f 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/mon/493701-labels/493701-labels.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/mon/493701-labels/493701-labels.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "493701-labels", "properties": { "label:description": "Geojson building labels for scene 493701", @@ -166,12 +166,6 @@ ], "type": "Polygon" }, - "bbox": [ - -10.789750111567438, - 6.326344897772844, - -10.7812814574604, - 6.334626743333399 - ], "links": [ { "rel": "collection", @@ -195,7 +189,14 @@ "type": "application/geo+json" } }, + "bbox": [ + -10.789750111567438, + 6.326344897772844, + -10.7812814574604, + 6.334626743333399 + ], "stac_extensions": [ - "label" - ] + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "mon" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/mon/493701/493701.json b/tests/data-files/catalogs/label_catalog-v0.8.1/mon/493701/493701.json similarity index 98% rename from tests/data-files/catalogs/label_catalog_0_8_1/mon/493701/493701.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/mon/493701/493701.json index 34646bdab..951db2aab 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/mon/493701/493701.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/mon/493701/493701.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "493701", "properties": { "area": "mon", @@ -142,12 +142,6 @@ ], "type": "Polygon" }, - "bbox": [ - -10.789750111567438, - 6.326344897772844, - -10.7812814574604, - 6.334626743333399 - ], "links": [ { "rel": "collection", @@ -172,5 +166,12 @@ "title": "GeoTIFF" } }, + "bbox": [ + -10.789750111567438, + 6.326344897772844, + -10.7812814574604, + 6.334626743333399 + ], + "stac_extensions": [], "collection": "mon" -} +} \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/mon/collection.json b/tests/data-files/catalogs/label_catalog-v0.8.1/mon/collection.json similarity index 96% rename from tests/data-files/catalogs/label_catalog_0_8_1/mon/collection.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/mon/collection.json index 821f5e8b1..c3026539c 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/mon/collection.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/mon/collection.json @@ -74,8 +74,5 @@ ] } }, - "license": "various", - "stac_extensions": [ - "label" - ] + "license": "various" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/mon/f15272-labels/f15272-labels.json b/tests/data-files/catalogs/label_catalog-v0.8.1/mon/f15272-labels/f15272-labels.json similarity index 97% rename from tests/data-files/catalogs/label_catalog_0_8_1/mon/f15272-labels/f15272-labels.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/mon/f15272-labels/f15272-labels.json index 30353de35..ac04f9b15 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/mon/f15272-labels/f15272-labels.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/mon/f15272-labels/f15272-labels.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "f15272-labels", "properties": { "label:description": "Geojson building labels for scene f15272", @@ -154,12 +154,6 @@ ], "type": "Polygon" }, - "bbox": [ - -10.801045209329727, - 6.32481451523328, - -10.793669675961551, - 6.331302091125989 - ], "links": [ { "rel": "collection", @@ -183,7 +177,14 @@ "type": "application/geo+json" } }, + "bbox": [ + -10.801045209329727, + 6.32481451523328, + -10.793669675961551, + 6.331302091125989 + ], "stac_extensions": [ - "label" - ] + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "mon" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/mon/f15272/f15272.json b/tests/data-files/catalogs/label_catalog-v0.8.1/mon/f15272/f15272.json similarity index 98% rename from tests/data-files/catalogs/label_catalog_0_8_1/mon/f15272/f15272.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/mon/f15272/f15272.json index 81f17576a..1d5f9fbb3 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/mon/f15272/f15272.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/mon/f15272/f15272.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "f15272", "properties": { "area": "mon", @@ -130,12 +130,6 @@ ], "type": "Polygon" }, - "bbox": [ - -10.801045209329727, - 6.32481451523328, - -10.793669675961551, - 6.331302091125989 - ], "links": [ { "rel": "collection", @@ -160,5 +154,12 @@ "title": "GeoTIFF" } }, + "bbox": [ + -10.801045209329727, + 6.32481451523328, + -10.793669675961551, + 6.331302091125989 + ], + "stac_extensions": [], "collection": "mon" -} +} \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/nia/825a50-labels/825a50-labels.json b/tests/data-files/catalogs/label_catalog-v0.8.1/nia/825a50-labels/825a50-labels.json similarity index 96% rename from tests/data-files/catalogs/label_catalog_0_8_1/nia/825a50-labels/825a50-labels.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/nia/825a50-labels/825a50-labels.json index 75754c985..a14743923 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/nia/825a50-labels/825a50-labels.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/nia/825a50-labels/825a50-labels.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "825a50-labels", "properties": { "label:description": "Geojson building labels for scene 825a50", @@ -94,12 +94,6 @@ ], "type": "Polygon" }, - "bbox": [ - 2.000607112710697, - 13.570445755015827, - 2.0089069498293726, - 13.583969811536608 - ], "links": [ { "rel": "collection", @@ -123,7 +117,14 @@ "type": "application/geo+json" } }, + "bbox": [ + 2.000607112710697, + 13.570445755015827, + 2.0089069498293726, + 13.583969811536608 + ], "stac_extensions": [ - "label" - ] + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "nia" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/nia/825a50/825a50.json b/tests/data-files/catalogs/label_catalog-v0.8.1/nia/825a50/825a50.json similarity index 97% rename from tests/data-files/catalogs/label_catalog_0_8_1/nia/825a50/825a50.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/nia/825a50/825a50.json index 2383367ca..506945f9c 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/nia/825a50/825a50.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/nia/825a50/825a50.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "825a50", "properties": { "area": "nia", @@ -70,12 +70,6 @@ ], "type": "Polygon" }, - "bbox": [ - 2.000607112710697, - 13.570445755015827, - 2.0089069498293726, - 13.583969811536608 - ], "links": [ { "rel": "collection", @@ -100,5 +94,12 @@ "title": "GeoTIFF" } }, + "bbox": [ + 2.000607112710697, + 13.570445755015827, + 2.0089069498293726, + 13.583969811536608 + ], + "stac_extensions": [], "collection": "nia" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/nia/collection.json b/tests/data-files/catalogs/label_catalog-v0.8.1/nia/collection.json similarity index 93% rename from tests/data-files/catalogs/label_catalog_0_8_1/nia/collection.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/nia/collection.json index 31df4ab11..f3dbfa603 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/nia/collection.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/nia/collection.json @@ -44,8 +44,5 @@ ] } }, - "license": "various", - "stac_extensions": [ - "label" - ] + "license": "various" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/ptn/abe1a3-labels/abe1a3-labels.json b/tests/data-files/catalogs/label_catalog-v0.8.1/ptn/abe1a3-labels/abe1a3-labels.json similarity index 97% rename from tests/data-files/catalogs/label_catalog_0_8_1/ptn/abe1a3-labels/abe1a3-labels.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/ptn/abe1a3-labels/abe1a3-labels.json index 7eaa50740..3896ab604 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/ptn/abe1a3-labels/abe1a3-labels.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/ptn/abe1a3-labels/abe1a3-labels.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "abe1a3-labels", "properties": { "label:description": "Geojson building labels for scene abe1a3", @@ -130,12 +130,6 @@ ], "type": "Polygon" }, - "bbox": [ - 11.879921982584099, - -4.780589144725401, - 11.894047213717943, - -4.7665107950056145 - ], "links": [ { "rel": "collection", @@ -159,7 +153,14 @@ "type": "application/geo+json" } }, + "bbox": [ + 11.879921982584099, + -4.780589144725401, + 11.894047213717943, + -4.7665107950056145 + ], "stac_extensions": [ - "label" - ] + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "ptn" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/ptn/abe1a3/abe1a3.json b/tests/data-files/catalogs/label_catalog-v0.8.1/ptn/abe1a3/abe1a3.json similarity index 98% rename from tests/data-files/catalogs/label_catalog_0_8_1/ptn/abe1a3/abe1a3.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/ptn/abe1a3/abe1a3.json index 8f4d3787f..b8deb4c6a 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/ptn/abe1a3/abe1a3.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/ptn/abe1a3/abe1a3.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "abe1a3", "properties": { "area": "ptn", @@ -106,12 +106,6 @@ ], "type": "Polygon" }, - "bbox": [ - 11.879921982584099, - -4.780589144725401, - 11.894047213717943, - -4.7665107950056145 - ], "links": [ { "rel": "collection", @@ -136,5 +130,12 @@ "title": "GeoTIFF" } }, + "bbox": [ + 11.879921982584099, + -4.780589144725401, + 11.894047213717943, + -4.7665107950056145 + ], + "stac_extensions": [], "collection": "ptn" -} +} \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/ptn/collection.json b/tests/data-files/catalogs/label_catalog-v0.8.1/ptn/collection.json similarity index 95% rename from tests/data-files/catalogs/label_catalog_0_8_1/ptn/collection.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/ptn/collection.json index a630ec58c..c721cc9f8 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/ptn/collection.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/ptn/collection.json @@ -54,8 +54,5 @@ ] } }, - "license": "various", - "stac_extensions": [ - "label" - ] + "license": "various" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/ptn/f49f31-labels/f49f31-labels.json b/tests/data-files/catalogs/label_catalog-v0.8.1/ptn/f49f31-labels/f49f31-labels.json similarity index 95% rename from tests/data-files/catalogs/label_catalog_0_8_1/ptn/f49f31-labels/f49f31-labels.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/ptn/f49f31-labels/f49f31-labels.json index 3aa4aec06..b29df6e49 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/ptn/f49f31-labels/f49f31-labels.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/ptn/f49f31-labels/f49f31-labels.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "f49f31-labels", "properties": { "label:description": "Geojson building labels for scene f49f31", @@ -86,12 +86,6 @@ ], "type": "Polygon" }, - "bbox": [ - 11.885939170933694, - -4.805243717903951, - 11.897849273966862, - -4.797722543259397 - ], "links": [ { "rel": "collection", @@ -115,7 +109,14 @@ "type": "application/geo+json" } }, + "bbox": [ + 11.885939170933694, + -4.805243717903951, + 11.897849273966862, + -4.797722543259397 + ], "stac_extensions": [ - "label" - ] + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "ptn" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/ptn/f49f31/f49f31.json b/tests/data-files/catalogs/label_catalog-v0.8.1/ptn/f49f31/f49f31.json similarity index 97% rename from tests/data-files/catalogs/label_catalog_0_8_1/ptn/f49f31/f49f31.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/ptn/f49f31/f49f31.json index 4c06b33ac..777c31a96 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/ptn/f49f31/f49f31.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/ptn/f49f31/f49f31.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "f49f31", "properties": { "area": "ptn", @@ -62,12 +62,6 @@ ], "type": "Polygon" }, - "bbox": [ - 11.885939170933694, - -4.805243717903951, - 11.897849273966862, - -4.797722543259397 - ], "links": [ { "rel": "collection", @@ -92,5 +86,12 @@ "title": "GeoTIFF" } }, + "bbox": [ + 11.885939170933694, + -4.805243717903951, + 11.897849273966862, + -4.797722543259397 + ], + "stac_extensions": [], "collection": "ptn" -} +} \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/znz/06f252-labels/06f252-labels.json b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/06f252-labels/06f252-labels.json similarity index 94% rename from tests/data-files/catalogs/label_catalog_0_8_1/znz/06f252-labels/06f252-labels.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/znz/06f252-labels/06f252-labels.json index bf5e9f682..2c8ea9eef 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/znz/06f252-labels/06f252-labels.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/06f252-labels/06f252-labels.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "06f252-labels", "properties": { "label:description": "Geojson building labels for scene 06f252", @@ -61,12 +61,6 @@ ], "type": "Polygon" }, - "bbox": [ - 39.31367952293228, - -5.905851570308218, - 39.340797007857546, - -5.878724233277496 - ], "links": [ { "rel": "collection", @@ -90,7 +84,14 @@ "type": "application/geo+json" } }, + "bbox": [ + 39.31367952293228, + -5.905851570308218, + 39.340797007857546, + -5.878724233277496 + ], "stac_extensions": [ - "label" - ] + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "znz" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/znz/06f252/06f252.json b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/06f252/06f252.json similarity index 96% rename from tests/data-files/catalogs/label_catalog_0_8_1/znz/06f252/06f252.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/znz/06f252/06f252.json index a1b17c7d7..0650d7bec 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/znz/06f252/06f252.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/06f252/06f252.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "06f252", "properties": { "area": "znz", @@ -37,12 +37,6 @@ ], "type": "Polygon" }, - "bbox": [ - 39.31367952293228, - -5.905851570308218, - 39.340797007857546, - -5.878724233277496 - ], "links": [ { "rel": "collection", @@ -67,5 +61,12 @@ "title": "GeoTIFF" } }, + "bbox": [ + 39.31367952293228, + -5.905851570308218, + 39.340797007857546, + -5.878724233277496 + ], + "stac_extensions": [], "collection": "znz" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/znz/076995-labels/076995-labels.json b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/076995-labels/076995-labels.json similarity index 95% rename from tests/data-files/catalogs/label_catalog_0_8_1/znz/076995-labels/076995-labels.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/znz/076995-labels/076995-labels.json index fb4052842..366e5f7f0 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/znz/076995-labels/076995-labels.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/076995-labels/076995-labels.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "076995-labels", "properties": { "label:description": "Geojson building labels for scene 076995", @@ -73,12 +73,6 @@ ] ] }, - "bbox": [ - 39.34073844240503, - -5.851576358919395, - 39.36335800442592, - -5.824424385662977 - ], "links": [ { "rel": "collection", @@ -102,7 +96,14 @@ "type": "application/geo+json" } }, + "bbox": [ + 39.34073844240503, + -5.851576358919395, + 39.36335800442592, + -5.824424385662977 + ], "stac_extensions": [ - "label" - ] + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "znz" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/znz/076995/076995.json b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/076995/076995.json similarity index 97% rename from tests/data-files/catalogs/label_catalog_0_8_1/znz/076995/076995.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/znz/076995/076995.json index 2608615d6..b411ef394 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/znz/076995/076995.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/076995/076995.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "076995", "properties": { "area": "znz", @@ -49,12 +49,6 @@ ] ] }, - "bbox": [ - 39.34073844240503, - -5.851576358919395, - 39.36335800442592, - -5.824424385662977 - ], "links": [ { "rel": "collection", @@ -79,5 +73,12 @@ "title": "GeoTIFF" } }, + "bbox": [ + 39.34073844240503, + -5.851576358919395, + 39.36335800442592, + -5.824424385662977 + ], + "stac_extensions": [], "collection": "znz" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/znz/33cae6-labels/33cae6-labels.json b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/33cae6-labels/33cae6-labels.json similarity index 99% rename from tests/data-files/catalogs/label_catalog_0_8_1/znz/33cae6-labels/33cae6-labels.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/znz/33cae6-labels/33cae6-labels.json index 3934a2bb1..c7e40d47f 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/znz/33cae6-labels/33cae6-labels.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/33cae6-labels/33cae6-labels.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "33cae6-labels", "properties": { "label:description": "Geojson building labels for scene 33cae6", @@ -1129,12 +1129,6 @@ ], "type": "Polygon" }, - "bbox": [ - 39.287711527683925, - -5.743060299502631, - 39.31360456846548, - -5.719012276837555 - ], "links": [ { "rel": "collection", @@ -1158,7 +1152,14 @@ "type": "application/geo+json" } }, + "bbox": [ + 39.287711527683925, + -5.743060299502631, + 39.31360456846548, + -5.719012276837555 + ], "stac_extensions": [ - "label" - ] + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "znz" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/znz/33cae6/33cae6.json b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/33cae6/33cae6.json similarity index 99% rename from tests/data-files/catalogs/label_catalog_0_8_1/znz/33cae6/33cae6.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/znz/33cae6/33cae6.json index bed2ece41..f1928cb44 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/znz/33cae6/33cae6.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/33cae6/33cae6.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "33cae6", "properties": { "area": "znz", @@ -1105,12 +1105,6 @@ ], "type": "Polygon" }, - "bbox": [ - 39.287711527683925, - -5.743060299502631, - 39.31360456846548, - -5.719012276837555 - ], "links": [ { "rel": "collection", @@ -1135,5 +1129,12 @@ "title": "GeoTIFF" } }, + "bbox": [ + 39.287711527683925, + -5.743060299502631, + 39.31360456846548, + -5.719012276837555 + ], + "stac_extensions": [], "collection": "znz" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/znz/3b20d4-labels/3b20d4-labels.json b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/3b20d4-labels/3b20d4-labels.json similarity index 94% rename from tests/data-files/catalogs/label_catalog_0_8_1/znz/3b20d4-labels/3b20d4-labels.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/znz/3b20d4-labels/3b20d4-labels.json index 882ec3f02..32b53802c 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/znz/3b20d4-labels/3b20d4-labels.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/3b20d4-labels/3b20d4-labels.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "3b20d4-labels", "properties": { "label:description": "Geojson building labels for scene 3b20d4", @@ -57,12 +57,6 @@ ] ] }, - "bbox": [ - 39.31347857904143, - -5.851778449857214, - 39.34092291979187, - -5.824334109106769 - ], "links": [ { "rel": "collection", @@ -86,7 +80,14 @@ "type": "application/geo+json" } }, + "bbox": [ + 39.31347857904143, + -5.851778449857214, + 39.34092291979187, + -5.824334109106769 + ], "stac_extensions": [ - "label" - ] + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "znz" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/znz/3b20d4/3b20d4.json b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/3b20d4/3b20d4.json similarity index 96% rename from tests/data-files/catalogs/label_catalog_0_8_1/znz/3b20d4/3b20d4.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/znz/3b20d4/3b20d4.json index 37ebb8aac..9a385cf3c 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/znz/3b20d4/3b20d4.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/3b20d4/3b20d4.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "3b20d4", "properties": { "area": "znz", @@ -33,12 +33,6 @@ ] ] }, - "bbox": [ - 39.31347857904143, - -5.851778449857214, - 39.34092291979187, - -5.824334109106769 - ], "links": [ { "rel": "collection", @@ -63,5 +57,12 @@ "title": "GeoTIFF" } }, + "bbox": [ + 39.31347857904143, + -5.851778449857214, + 39.34092291979187, + -5.824334109106769 + ], + "stac_extensions": [], "collection": "znz" -} +} \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/znz/3f8360-labels/3f8360-labels.json b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/3f8360-labels/3f8360-labels.json similarity index 94% rename from tests/data-files/catalogs/label_catalog_0_8_1/znz/3f8360-labels/3f8360-labels.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/znz/3f8360-labels/3f8360-labels.json index 6a8b72d52..4a0d84832 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/znz/3f8360-labels/3f8360-labels.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/3f8360-labels/3f8360-labels.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "3f8360-labels", "properties": { "label:description": "Geojson building labels for scene 3f8360", @@ -61,12 +61,6 @@ ], "type": "Polygon" }, - "bbox": [ - 39.34079687232617, - -5.933001162750248, - 39.36446684258708, - -5.905820682536527 - ], "links": [ { "rel": "collection", @@ -90,7 +84,14 @@ "type": "application/geo+json" } }, + "bbox": [ + 39.34079687232617, + -5.933001162750248, + 39.36446684258708, + -5.905820682536527 + ], "stac_extensions": [ - "label" - ] + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "znz" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/znz/3f8360/3f8360.json b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/3f8360/3f8360.json similarity index 96% rename from tests/data-files/catalogs/label_catalog_0_8_1/znz/3f8360/3f8360.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/znz/3f8360/3f8360.json index f389c8db4..e002c85c8 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/znz/3f8360/3f8360.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/3f8360/3f8360.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "3f8360", "properties": { "area": "znz", @@ -37,12 +37,6 @@ ], "type": "Polygon" }, - "bbox": [ - 39.34079687232617, - -5.933001162750248, - 39.36446684258708, - -5.905820682536527 - ], "links": [ { "rel": "collection", @@ -67,5 +61,12 @@ "title": "GeoTIFF" } }, + "bbox": [ + 39.34079687232617, + -5.933001162750248, + 39.36446684258708, + -5.905820682536527 + ], + "stac_extensions": [], "collection": "znz" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/znz/425403-labels/425403-labels.json b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/425403-labels/425403-labels.json similarity index 94% rename from tests/data-files/catalogs/label_catalog_0_8_1/znz/425403-labels/425403-labels.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/znz/425403-labels/425403-labels.json index b3281171a..336ba134f 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/znz/425403-labels/425403-labels.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/425403-labels/425403-labels.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "425403-labels", "properties": { "label:description": "Geojson building labels for scene 425403", @@ -57,12 +57,6 @@ ], "type": "Polygon" }, - "bbox": [ - 39.31371005982263, - -5.960174243786799, - 39.34082996500427, - -5.933001378219889 - ], "links": [ { "rel": "collection", @@ -86,7 +80,14 @@ "type": "application/geo+json" } }, + "bbox": [ + 39.31371005982263, + -5.960174243786799, + 39.34082996500427, + -5.933001378219889 + ], "stac_extensions": [ - "label" - ] + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "znz" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/znz/425403/425403.json b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/425403/425403.json similarity index 96% rename from tests/data-files/catalogs/label_catalog_0_8_1/znz/425403/425403.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/znz/425403/425403.json index f4037a1f1..d15a6f17c 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/znz/425403/425403.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/425403/425403.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "425403", "properties": { "area": "znz", @@ -33,12 +33,6 @@ ], "type": "Polygon" }, - "bbox": [ - 39.31371005982263, - -5.960174243786799, - 39.34082996500427, - -5.933001378219889 - ], "links": [ { "rel": "collection", @@ -63,5 +57,12 @@ "title": "GeoTIFF" } }, + "bbox": [ + 39.31371005982263, + -5.960174243786799, + 39.34082996500427, + -5.933001378219889 + ], + "stac_extensions": [], "collection": "znz" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/znz/75cdfa-labels/75cdfa-labels.json b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/75cdfa-labels/75cdfa-labels.json similarity index 94% rename from tests/data-files/catalogs/label_catalog_0_8_1/znz/75cdfa-labels/75cdfa-labels.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/znz/75cdfa-labels/75cdfa-labels.json index bc9cd83c8..967f03394 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/znz/75cdfa-labels/75cdfa-labels.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/75cdfa-labels/75cdfa-labels.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "75cdfa-labels", "properties": { "label:description": "Geojson building labels for scene 75cdfa", @@ -61,12 +61,6 @@ ], "type": "Polygon" }, - "bbox": [ - 39.31366435148484, - -5.8787400187081476, - 39.34078034637437, - -5.851567529006198 - ], "links": [ { "rel": "collection", @@ -90,7 +84,14 @@ "type": "application/geo+json" } }, + "bbox": [ + 39.31366435148484, + -5.8787400187081476, + 39.34078034637437, + -5.851567529006198 + ], "stac_extensions": [ - "label" - ] + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "znz" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/znz/75cdfa/75cdfa.json b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/75cdfa/75cdfa.json similarity index 96% rename from tests/data-files/catalogs/label_catalog_0_8_1/znz/75cdfa/75cdfa.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/znz/75cdfa/75cdfa.json index f3c60dd14..567f22d8d 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/znz/75cdfa/75cdfa.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/75cdfa/75cdfa.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "75cdfa", "properties": { "area": "znz", @@ -37,12 +37,6 @@ ], "type": "Polygon" }, - "bbox": [ - 39.31366435148484, - -5.8787400187081476, - 39.34078034637437, - -5.851567529006198 - ], "links": [ { "rel": "collection", @@ -67,5 +61,12 @@ "title": "GeoTIFF" } }, + "bbox": [ + 39.31366435148484, + -5.8787400187081476, + 39.34078034637437, + -5.851567529006198 + ], + "stac_extensions": [], "collection": "znz" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/znz/9b8638-labels/9b8638-labels.json b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/9b8638-labels/9b8638-labels.json similarity index 96% rename from tests/data-files/catalogs/label_catalog_0_8_1/znz/9b8638-labels/9b8638-labels.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/znz/9b8638-labels/9b8638-labels.json index cfc7a0981..2483ad14e 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/znz/9b8638-labels/9b8638-labels.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/9b8638-labels/9b8638-labels.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "9b8638-labels", "properties": { "label:description": "Geojson building labels for scene 9b8638", @@ -113,12 +113,6 @@ ], "type": "Polygon" }, - "bbox": [ - 39.34076385802326, - -5.878724092981988, - 39.362419204085, - -5.8515539621204695 - ], "links": [ { "rel": "collection", @@ -142,7 +136,14 @@ "type": "application/geo+json" } }, + "bbox": [ + 39.34076385802326, + -5.878724092981988, + 39.362419204085, + -5.8515539621204695 + ], "stac_extensions": [ - "label" - ] + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "znz" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/znz/9b8638/9b8638.json b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/9b8638/9b8638.json similarity index 98% rename from tests/data-files/catalogs/label_catalog_0_8_1/znz/9b8638/9b8638.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/znz/9b8638/9b8638.json index 810e0332a..421b75f92 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/znz/9b8638/9b8638.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/9b8638/9b8638.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "9b8638", "properties": { "area": "znz", @@ -89,12 +89,6 @@ ], "type": "Polygon" }, - "bbox": [ - 39.34076385802326, - -5.878724092981988, - 39.362419204085, - -5.8515539621204695 - ], "links": [ { "rel": "collection", @@ -119,5 +113,12 @@ "title": "GeoTIFF" } }, + "bbox": [ + 39.34076385802326, + -5.878724092981988, + 39.362419204085, + -5.8515539621204695 + ], + "stac_extensions": [], "collection": "znz" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/znz/aee7fd-labels/aee7fd-labels.json b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/aee7fd-labels/aee7fd-labels.json similarity index 94% rename from tests/data-files/catalogs/label_catalog_0_8_1/znz/aee7fd-labels/aee7fd-labels.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/znz/aee7fd-labels/aee7fd-labels.json index 106a7f1c0..4db538c37 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/znz/aee7fd-labels/aee7fd-labels.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/aee7fd-labels/aee7fd-labels.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "aee7fd-labels", "properties": { "label:description": "Geojson building labels for scene aee7fd", @@ -61,12 +61,6 @@ ], "type": "Polygon" }, - "bbox": [ - 39.31369530504979, - -5.933017366868187, - 39.340814311389366, - -5.905835679883141 - ], "links": [ { "rel": "collection", @@ -90,7 +84,14 @@ "type": "application/geo+json" } }, + "bbox": [ + 39.31369530504979, + -5.933017366868187, + 39.340814311389366, + -5.905835679883141 + ], "stac_extensions": [ - "label" - ] + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "znz" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/znz/aee7fd/aee7fd.json b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/aee7fd/aee7fd.json similarity index 96% rename from tests/data-files/catalogs/label_catalog_0_8_1/znz/aee7fd/aee7fd.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/znz/aee7fd/aee7fd.json index d8eda463b..fc130af26 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/znz/aee7fd/aee7fd.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/aee7fd/aee7fd.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "aee7fd", "properties": { "area": "znz", @@ -37,12 +37,6 @@ ], "type": "Polygon" }, - "bbox": [ - 39.31369530504979, - -5.933017366868187, - 39.340814311389366, - -5.905835679883141 - ], "links": [ { "rel": "collection", @@ -67,5 +61,12 @@ "title": "GeoTIFF" } }, + "bbox": [ + 39.31369530504979, + -5.933017366868187, + 39.340814311389366, + -5.905835679883141 + ], + "stac_extensions": [], "collection": "znz" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/znz/bc32f1-labels/bc32f1-labels.json b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/bc32f1-labels/bc32f1-labels.json similarity index 94% rename from tests/data-files/catalogs/label_catalog_0_8_1/znz/bc32f1-labels/bc32f1-labels.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/znz/bc32f1-labels/bc32f1-labels.json index fa4bcd9c8..44efd7d87 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/znz/bc32f1-labels/bc32f1-labels.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/bc32f1-labels/bc32f1-labels.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "bc32f1-labels", "properties": { "label:description": "Geojson building labels for scene bc32f1", @@ -61,12 +61,6 @@ ], "type": "Polygon" }, - "bbox": [ - 39.34083023028068, - -5.987278166971163, - 39.36795215042373, - -5.960140574104503 - ], "links": [ { "rel": "collection", @@ -90,7 +84,14 @@ "type": "application/geo+json" } }, + "bbox": [ + 39.34083023028068, + -5.987278166971163, + 39.36795215042373, + -5.960140574104503 + ], "stac_extensions": [ - "label" - ] + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "znz" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/znz/bc32f1/bc32f1.json b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/bc32f1/bc32f1.json similarity index 96% rename from tests/data-files/catalogs/label_catalog_0_8_1/znz/bc32f1/bc32f1.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/znz/bc32f1/bc32f1.json index bd5c2ccb5..1d2709183 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/znz/bc32f1/bc32f1.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/bc32f1/bc32f1.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "bc32f1", "properties": { "area": "znz", @@ -37,12 +37,6 @@ ], "type": "Polygon" }, - "bbox": [ - 39.34083023028068, - -5.987278166971163, - 39.36795215042373, - -5.960140574104503 - ], "links": [ { "rel": "collection", @@ -67,5 +61,12 @@ "title": "GeoTIFF" } }, + "bbox": [ + 39.34083023028068, + -5.987278166971163, + 39.36795215042373, + -5.960140574104503 + ], + "stac_extensions": [], "collection": "znz" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/znz/bd5c14-labels/bd5c14-labels.json b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/bd5c14-labels/bd5c14-labels.json similarity index 94% rename from tests/data-files/catalogs/label_catalog_0_8_1/znz/bd5c14-labels/bd5c14-labels.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/znz/bd5c14-labels/bd5c14-labels.json index d1f4ed19a..766476c23 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/znz/bd5c14-labels/bd5c14-labels.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/bd5c14-labels/bd5c14-labels.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "bd5c14-labels", "properties": { "label:description": "Geojson building labels for scene bd5c14", @@ -61,12 +61,6 @@ ], "type": "Polygon" }, - "bbox": [ - 39.34081295055692, - -5.960157881729879, - 39.367933753210345, - -5.932984029391401 - ], "links": [ { "rel": "collection", @@ -90,7 +84,14 @@ "type": "application/geo+json" } }, + "bbox": [ + 39.34081295055692, + -5.960157881729879, + 39.367933753210345, + -5.932984029391401 + ], "stac_extensions": [ - "label" - ] + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "znz" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/znz/bd5c14/bd5c14.json b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/bd5c14/bd5c14.json similarity index 96% rename from tests/data-files/catalogs/label_catalog_0_8_1/znz/bd5c14/bd5c14.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/znz/bd5c14/bd5c14.json index 063e13f72..19cad7c97 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/znz/bd5c14/bd5c14.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/bd5c14/bd5c14.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "bd5c14", "properties": { "area": "znz", @@ -37,12 +37,6 @@ ], "type": "Polygon" }, - "bbox": [ - 39.34081295055692, - -5.960157881729879, - 39.367933753210345, - -5.932984029391401 - ], "links": [ { "rel": "collection", @@ -67,5 +61,12 @@ "title": "GeoTIFF" } }, + "bbox": [ + 39.34081295055692, + -5.960157881729879, + 39.367933753210345, + -5.932984029391401 + ], + "stac_extensions": [], "collection": "znz" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/znz/c7415c-labels/c7415c-labels.json b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/c7415c-labels/c7415c-labels.json similarity index 94% rename from tests/data-files/catalogs/label_catalog_0_8_1/znz/c7415c-labels/c7415c-labels.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/znz/c7415c-labels/c7415c-labels.json index 963065505..08497f0e7 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/znz/c7415c-labels/c7415c-labels.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/c7415c-labels/c7415c-labels.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "c7415c-labels", "properties": { "label:description": "Geojson building labels for scene c7415c", @@ -61,12 +61,6 @@ ], "type": "Polygon" }, - "bbox": [ - 39.340780340171506, - -5.9058357319970805, - 39.360290846530575, - -5.878712001912929 - ], "links": [ { "rel": "collection", @@ -90,7 +84,14 @@ "type": "application/geo+json" } }, + "bbox": [ + 39.340780340171506, + -5.9058357319970805, + 39.360290846530575, + -5.878712001912929 + ], "stac_extensions": [ - "label" - ] + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "znz" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/znz/c7415c/c7415c.json b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/c7415c/c7415c.json similarity index 96% rename from tests/data-files/catalogs/label_catalog_0_8_1/znz/c7415c/c7415c.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/znz/c7415c/c7415c.json index 8beaebe91..9c7991b75 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/znz/c7415c/c7415c.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/c7415c/c7415c.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "c7415c", "properties": { "area": "znz", @@ -37,12 +37,6 @@ ], "type": "Polygon" }, - "bbox": [ - 39.340780340171506, - -5.9058357319970805, - 39.360290846530575, - -5.878712001912929 - ], "links": [ { "rel": "collection", @@ -67,5 +61,12 @@ "title": "GeoTIFF" } }, + "bbox": [ + 39.340780340171506, + -5.9058357319970805, + 39.360290846530575, + -5.878712001912929 + ], + "stac_extensions": [], "collection": "znz" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/znz/collection.json b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/collection.json similarity index 98% rename from tests/data-files/catalogs/label_catalog_0_8_1/znz/collection.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/znz/collection.json index 214a95f2d..bd245e151 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/znz/collection.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/collection.json @@ -164,8 +164,5 @@ ] } }, - "license": "CC-BY-4.0", - "stac_extensions": [ - "label" - ] + "license": "CC-BY-4.0" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/znz/e52478-labels/e52478-labels.json b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/e52478-labels/e52478-labels.json similarity index 94% rename from tests/data-files/catalogs/label_catalog_0_8_1/znz/e52478-labels/e52478-labels.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/znz/e52478-labels/e52478-labels.json index 8635cddcf..a8437dbc7 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/znz/e52478-labels/e52478-labels.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/e52478-labels/e52478-labels.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "e52478-labels", "properties": { "label:description": "Geojson building labels for scene e52478", @@ -61,12 +61,6 @@ ], "type": "Polygon" }, - "bbox": [ - 39.36791576371174, - -5.9601408243123455, - 39.378914288970435, - -5.9329766232129995 - ], "links": [ { "rel": "collection", @@ -90,7 +84,14 @@ "type": "application/geo+json" } }, + "bbox": [ + 39.36791576371174, + -5.9601408243123455, + 39.378914288970435, + -5.9329766232129995 + ], "stac_extensions": [ - "label" - ] + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "znz" } \ No newline at end of file diff --git a/tests/data-files/catalogs/label_catalog_0_8_1/znz/e52478/e52478.json b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/e52478/e52478.json similarity index 96% rename from tests/data-files/catalogs/label_catalog_0_8_1/znz/e52478/e52478.json rename to tests/data-files/catalogs/label_catalog-v0.8.1/znz/e52478/e52478.json index 8e6863629..1632da701 100644 --- a/tests/data-files/catalogs/label_catalog_0_8_1/znz/e52478/e52478.json +++ b/tests/data-files/catalogs/label_catalog-v0.8.1/znz/e52478/e52478.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "0.8.1", + "stac_version": "1.0.0-rc.3", "id": "e52478", "properties": { "area": "znz", @@ -37,12 +37,6 @@ ], "type": "Polygon" }, - "bbox": [ - 39.36791576371174, - -5.9601408243123455, - 39.378914288970435, - -5.9329766232129995 - ], "links": [ { "rel": "collection", @@ -67,5 +61,12 @@ "title": "GeoTIFF" } }, + "bbox": [ + 39.36791576371174, + -5.9601408243123455, + 39.378914288970435, + -5.9329766232129995 + ], + "stac_extensions": [], "collection": "znz" } \ No newline at end of file diff --git a/tests/data-files/catalogs/planet-example-1.0.0-beta.2/collection.json b/tests/data-files/catalogs/planet-example-v1.0.0-beta.2/collection.json similarity index 98% rename from tests/data-files/catalogs/planet-example-1.0.0-beta.2/collection.json rename to tests/data-files/catalogs/planet-example-v1.0.0-beta.2/collection.json index 6722373f3..eb4923d4c 100644 --- a/tests/data-files/catalogs/planet-example-1.0.0-beta.2/collection.json +++ b/tests/data-files/catalogs/planet-example-v1.0.0-beta.2/collection.json @@ -91,7 +91,7 @@ "temporal": { "interval": [ [ - "2017-08-28T10:00:00-08:00", + "2017-08-28T10:00:00+00:00", null ] ] diff --git a/tests/data-files/catalogs/planet-example-1.0.0-beta.2/hurricane-harvey/catalog.json b/tests/data-files/catalogs/planet-example-v1.0.0-beta.2/hurricane-harvey/catalog.json similarity index 100% rename from tests/data-files/catalogs/planet-example-1.0.0-beta.2/hurricane-harvey/catalog.json rename to tests/data-files/catalogs/planet-example-v1.0.0-beta.2/hurricane-harvey/catalog.json diff --git a/tests/data-files/catalogs/planet-example-1.0.0-beta.2/hurricane-harvey/hurricane-harvey-0831/20170831_162740_ssc1d1/20170831_162740_ssc1d1.json b/tests/data-files/catalogs/planet-example-v1.0.0-beta.2/hurricane-harvey/hurricane-harvey-0831/20170831_162740_ssc1d1/20170831_162740_ssc1d1.json similarity index 96% rename from tests/data-files/catalogs/planet-example-1.0.0-beta.2/hurricane-harvey/hurricane-harvey-0831/20170831_162740_ssc1d1/20170831_162740_ssc1d1.json rename to tests/data-files/catalogs/planet-example-v1.0.0-beta.2/hurricane-harvey/hurricane-harvey-0831/20170831_162740_ssc1d1/20170831_162740_ssc1d1.json index d9c9b526c..a1ded9213 100644 --- a/tests/data-files/catalogs/planet-example-1.0.0-beta.2/hurricane-harvey/hurricane-harvey-0831/20170831_162740_ssc1d1/20170831_162740_ssc1d1.json +++ b/tests/data-files/catalogs/planet-example-v1.0.0-beta.2/hurricane-harvey/hurricane-harvey-0831/20170831_162740_ssc1d1/20170831_162740_ssc1d1.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "1.0.0-beta.2", + "stac_version": "1.0.0-rc.3", "id": "20170831_162740_ssc1d1", "properties": { "datetime": "2017-08-31T16:27:42.176605Z", @@ -156,8 +156,8 @@ 29.064872627755797 ], "stac_extensions": [ - "eo", - "view" + "https://stac-extensions.github.io/eo/v1.0.0/schema.json", + "https://stac-extensions.github.io/view/v1.0.0/schema.json" ], "collection": "planet-disaster-data" } \ No newline at end of file diff --git a/tests/data-files/catalogs/planet-example-1.0.0-beta.2/hurricane-harvey/hurricane-harvey-0831/20170831_172754_101c/20170831_172754_101c.json b/tests/data-files/catalogs/planet-example-v1.0.0-beta.2/hurricane-harvey/hurricane-harvey-0831/20170831_172754_101c/20170831_172754_101c.json similarity index 94% rename from tests/data-files/catalogs/planet-example-1.0.0-beta.2/hurricane-harvey/hurricane-harvey-0831/20170831_172754_101c/20170831_172754_101c.json rename to tests/data-files/catalogs/planet-example-v1.0.0-beta.2/hurricane-harvey/hurricane-harvey-0831/20170831_172754_101c/20170831_172754_101c.json index e4120efdc..701f76ce0 100644 --- a/tests/data-files/catalogs/planet-example-1.0.0-beta.2/hurricane-harvey/hurricane-harvey-0831/20170831_172754_101c/20170831_172754_101c.json +++ b/tests/data-files/catalogs/planet-example-v1.0.0-beta.2/hurricane-harvey/hurricane-harvey-0831/20170831_172754_101c/20170831_172754_101c.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "1.0.0-beta.2", + "stac_version": "1.0.0-rc.3", "id": "20170831_172754_101c", "properties": { "datetime": "2017-08-31T17:27:54.960530Z", @@ -141,9 +141,9 @@ 29.62330817060518 ], "stac_extensions": [ - "eo", - "view", - "proj" + "https://stac-extensions.github.io/eo/v1.0.0/schema.json", + "https://stac-extensions.github.io/view/v1.0.0/schema.json", + "https://stac-extensions.github.io/projection/v1.0.0/schema.json" ], "collection": "planet-disaster-data" } \ No newline at end of file diff --git a/tests/data-files/catalogs/planet-example-1.0.0-beta.2/hurricane-harvey/hurricane-harvey-0831/20170831_195425_SS02/20170831_195425_SS02.json b/tests/data-files/catalogs/planet-example-v1.0.0-beta.2/hurricane-harvey/hurricane-harvey-0831/20170831_195425_SS02/20170831_195425_SS02.json similarity index 95% rename from tests/data-files/catalogs/planet-example-1.0.0-beta.2/hurricane-harvey/hurricane-harvey-0831/20170831_195425_SS02/20170831_195425_SS02.json rename to tests/data-files/catalogs/planet-example-v1.0.0-beta.2/hurricane-harvey/hurricane-harvey-0831/20170831_195425_SS02/20170831_195425_SS02.json index 96e295d5c..91b6fdd7e 100644 --- a/tests/data-files/catalogs/planet-example-1.0.0-beta.2/hurricane-harvey/hurricane-harvey-0831/20170831_195425_SS02/20170831_195425_SS02.json +++ b/tests/data-files/catalogs/planet-example-v1.0.0-beta.2/hurricane-harvey/hurricane-harvey-0831/20170831_195425_SS02/20170831_195425_SS02.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "1.0.0-beta.2", + "stac_version": "1.0.0-rc.3", "id": "20170831_195425_SS02", "properties": { "datetime": "2017-08-31T19:54:26.532800Z", @@ -121,8 +121,8 @@ 30.052156732418428 ], "stac_extensions": [ - "eo", - "view" + "https://stac-extensions.github.io/eo/v1.0.0/schema.json", + "https://stac-extensions.github.io/view/v1.0.0/schema.json" ], "collection": "planet-disaster-data" } \ No newline at end of file diff --git a/tests/data-files/catalogs/planet-example-1.0.0-beta.2/hurricane-harvey/hurricane-harvey-0831/2017831_195552_SS02/2017831_195552_SS02.json b/tests/data-files/catalogs/planet-example-v1.0.0-beta.2/hurricane-harvey/hurricane-harvey-0831/2017831_195552_SS02/2017831_195552_SS02.json similarity index 96% rename from tests/data-files/catalogs/planet-example-1.0.0-beta.2/hurricane-harvey/hurricane-harvey-0831/2017831_195552_SS02/2017831_195552_SS02.json rename to tests/data-files/catalogs/planet-example-v1.0.0-beta.2/hurricane-harvey/hurricane-harvey-0831/2017831_195552_SS02/2017831_195552_SS02.json index 29005fb9a..abee6ece5 100644 --- a/tests/data-files/catalogs/planet-example-1.0.0-beta.2/hurricane-harvey/hurricane-harvey-0831/2017831_195552_SS02/2017831_195552_SS02.json +++ b/tests/data-files/catalogs/planet-example-v1.0.0-beta.2/hurricane-harvey/hurricane-harvey-0831/2017831_195552_SS02/2017831_195552_SS02.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "1.0.0-beta.2", + "stac_version": "1.0.0-rc.3", "id": "2017831_195552_SS02", "properties": { "datetime": "2017-08-31T19:55:53.513448Z", @@ -140,8 +140,8 @@ 29.834836581964858 ], "stac_extensions": [ - "eo", - "view" + "https://stac-extensions.github.io/eo/v1.0.0/schema.json", + "https://stac-extensions.github.io/view/v1.0.0/schema.json" ], "collection": "planet-disaster-data" } \ No newline at end of file diff --git a/tests/data-files/catalogs/planet-example-1.0.0-beta.2/hurricane-harvey/hurricane-harvey-0831/Houston-East-20170831-103f-100d-0f4f-RGB/Houston-East-20170831-103f-100d-0f4f-RGB.json b/tests/data-files/catalogs/planet-example-v1.0.0-beta.2/hurricane-harvey/hurricane-harvey-0831/Houston-East-20170831-103f-100d-0f4f-RGB/Houston-East-20170831-103f-100d-0f4f-RGB.json similarity index 89% rename from tests/data-files/catalogs/planet-example-1.0.0-beta.2/hurricane-harvey/hurricane-harvey-0831/Houston-East-20170831-103f-100d-0f4f-RGB/Houston-East-20170831-103f-100d-0f4f-RGB.json rename to tests/data-files/catalogs/planet-example-v1.0.0-beta.2/hurricane-harvey/hurricane-harvey-0831/Houston-East-20170831-103f-100d-0f4f-RGB/Houston-East-20170831-103f-100d-0f4f-RGB.json index 693c4b0b8..a39c7aa6f 100644 --- a/tests/data-files/catalogs/planet-example-1.0.0-beta.2/hurricane-harvey/hurricane-harvey-0831/Houston-East-20170831-103f-100d-0f4f-RGB/Houston-East-20170831-103f-100d-0f4f-RGB.json +++ b/tests/data-files/catalogs/planet-example-v1.0.0-beta.2/hurricane-harvey/hurricane-harvey-0831/Houston-East-20170831-103f-100d-0f4f-RGB/Houston-East-20170831-103f-100d-0f4f-RGB.json @@ -1,6 +1,6 @@ { "type": "Feature", - "stac_version": "1.0.0-beta.2", + "stac_version": "1.0.0-rc.3", "id": "Houston-East-20170831-103f-100d-0f4f-RGB", "properties": { "datetime": "2017-08-31T17:24:57.555491Z", @@ -13,7 +13,7 @@ "view:sun_azimuth": 145.5, "view:sun_elevation": 64.9, "view:off_nadir": 0.2, - "proj:epsg_code": 32615, + "proj:epsg": 32615, "pl:ground_control": true }, "geometry": { @@ -84,9 +84,9 @@ 30.157560439570304 ], "stac_extensions": [ - "eo", - "view", - "proj" + "https://stac-extensions.github.io/eo/v1.0.0/schema.json", + "https://stac-extensions.github.io/view/v1.0.0/schema.json", + "https://stac-extensions.github.io/projection/v1.0.0/schema.json" ], "collection": "planet-disaster-data" } \ No newline at end of file diff --git a/tests/data-files/catalogs/planet-example-1.0.0-beta.2/hurricane-harvey/hurricane-harvey-0831/catalog.json b/tests/data-files/catalogs/planet-example-v1.0.0-beta.2/hurricane-harvey/hurricane-harvey-0831/catalog.json similarity index 100% rename from tests/data-files/catalogs/planet-example-1.0.0-beta.2/hurricane-harvey/hurricane-harvey-0831/catalog.json rename to tests/data-files/catalogs/planet-example-v1.0.0-beta.2/hurricane-harvey/hurricane-harvey-0831/catalog.json diff --git a/tests/data-files/catalogs/test-case-1/catalog.json b/tests/data-files/catalogs/test-case-1/catalog.json index 56f92411d..d2d07610d 100644 --- a/tests/data-files/catalogs/test-case-1/catalog.json +++ b/tests/data-files/catalogs/test-case-1/catalog.json @@ -1,6 +1,7 @@ { + "type": "Catalog", "id": "test", - "stac_version": "1.0.0-beta.2", + "stac_version": "1.0.0-rc.3", "description": "test catalog", "links": [ { @@ -18,5 +19,6 @@ "href": "./catalog.json", "type": "application/json" } - ] + ], + "stac_extensions": [] } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-1/country-1/area-1-1/area-1-1-imagery/area-1-1-imagery.json b/tests/data-files/catalogs/test-case-1/country-1/area-1-1/area-1-1-imagery/area-1-1-imagery.json index c78c81b26..3c43c3581 100644 --- a/tests/data-files/catalogs/test-case-1/country-1/area-1-1/area-1-1-imagery/area-1-1-imagery.json +++ b/tests/data-files/catalogs/test-case-1/country-1/area-1-1/area-1-1-imagery/area-1-1-imagery.json @@ -1,69 +1,70 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "area-1-1-imagery", - "properties": { - "datetime": "2019-10-04 18:55:37Z" - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [ - -2.5048828125, - 3.8916575492899987 - ], - [ - -1.9610595703125, - 3.8916575492899987 - ], - [ - -1.9610595703125, - 4.275202171119132 - ], - [ - -2.5048828125, - 4.275202171119132 - ], - [ - -2.5048828125, - 3.8916575492899987 - ] - ] - ] - }, - "bbox": [ - -2.5048828125, - 3.8916575492899987, - -1.9610595703125, - 3.8916575492899987 - ], - "collection": "area-1-1", - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "area-1-1-imagery", + "properties": { + "datetime": "2019-10-04T18:55:37Z" }, - { - "rel": "root", - "href": "../../../catalog.json", - "type": "application/json" + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + -2.5048828125, + 3.8916575492899987 + ], + [ + -1.9610595703125, + 3.8916575492899987 + ], + [ + -1.9610595703125, + 4.275202171119132 + ], + [ + -2.5048828125, + 4.275202171119132 + ], + [ + -2.5048828125, + 3.8916575492899987 + ] + ] + ] }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "ortho": { - "href": "http://example.com/area-1-1_ortho.tif", - "type": "image/vnd.stac.geotiff" + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "ortho": { + "href": "http://example.com/area-1-1_ortho.tif", + "type": "image/vnd.stac.geotiff" + }, + "dsm": { + "href": "http://example.com/area-1-1_dsm.tif", + "type": "image/vnd.stac.geotiff" + } }, - "dsm": { - "href": "http://example.com/area-1-1_dsm.tif", - "type": "image/vnd.stac.geotiff" - } - } -} + "bbox": [ + -2.5048828125, + 3.8916575492899987, + -1.9610595703125, + 3.8916575492899987 + ], + "stac_extensions": [], + "collection": "area-1-1" +} \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-1/country-1/area-1-1/area-1-1-labels/area-1-1-labels.json b/tests/data-files/catalogs/test-case-1/country-1/area-1-1/area-1-1-labels/area-1-1-labels.json index a2c203a52..d6204f9e6 100644 --- a/tests/data-files/catalogs/test-case-1/country-1/area-1-1/area-1-1-labels/area-1-1-labels.json +++ b/tests/data-files/catalogs/test-case-1/country-1/area-1-1/area-1-1-labels/area-1-1-labels.json @@ -1,93 +1,93 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "area-1-1-labels", - "properties": { - "datetime": "2019-10-04 18:55:37Z", - "label:description": "labels for area-1-1", - "label:type": "vector", - "label:properties": [ - "label" - ], - "label:classes": [ - { - "name": "label", - "classes": [ - "one", - "two" - ] - } - ], - "label:task": [ - "classification" - ], - "label:method": [ - "manual" - ] - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [ - -2.5048828125, - 3.8916575492899987 - ], - [ - -1.9610595703125, - 3.8916575492899987 + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "area-1-1-labels", + "properties": { + "datetime": "2019-10-04T18:55:37Z", + "label:description": "labels for area-1-1", + "label:type": "vector", + "label:properties": [ + "label" ], - [ - -1.9610595703125, - 4.275202171119132 + "label:classes": [ + { + "name": "label", + "classes": [ + "one", + "two" + ] + } ], - [ - -2.5048828125, - 4.275202171119132 + "label:tasks": [ + "classification" ], - [ - -2.5048828125, - 3.8916575492899987 + "label:methods": [ + "manual" ] - ] - ] - }, - "bbox": [ - -2.5048828125, - 3.8916575492899987, - -1.9610595703125, - 3.8916575492899987 - ], - "collection": "area-1-1", - "links": [ - { - "rel": "source", - "href": "../area-1-1-imagery/area-1-1-imagery.json", - "type": "application/json" }, - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + -2.5048828125, + 3.8916575492899987 + ], + [ + -1.9610595703125, + 3.8916575492899987 + ], + [ + -1.9610595703125, + 4.275202171119132 + ], + [ + -2.5048828125, + 4.275202171119132 + ], + [ + -2.5048828125, + 3.8916575492899987 + ] + ] + ] }, - { - "rel": "root", - "href": "../../../catalog.json", - "type": "application/json" + "links": [ + { + "rel": "source", + "href": "../area-1-1-imagery/area-1-1-imagery.json", + "type": "application/json" + }, + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "labels": { + "href": "http://example.com/area-1-1-labels.geojson", + "type": "application/geo+json" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "labels": { - "href": "http://example.com/area-1-1-labels.geojson", - "type": "application/geo+json" - } - }, - "stac_extensions": [ - "label" - ] -} + "bbox": [ + -2.5048828125, + 3.8916575492899987, + -1.9610595703125, + 3.8916575492899987 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "area-1-1" +} \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-1/country-1/area-1-1/collection.json b/tests/data-files/catalogs/test-case-1/country-1/area-1-1/collection.json index 8e1c7f953..51e3950e1 100644 --- a/tests/data-files/catalogs/test-case-1/country-1/area-1-1/collection.json +++ b/tests/data-files/catalogs/test-case-1/country-1/area-1-1/collection.json @@ -1,6 +1,7 @@ { + "type": "Collection", "id": "area-1-1", - "stac_version": "1.0.0-beta.2", + "stac_version": "1.0.0-rc.3", "description": "test collection country-1", "links": [ { @@ -24,6 +25,7 @@ "type": "application/json" } ], + "stac_extensions": [], "extent": { "spatial": { "bbox": [ diff --git a/tests/data-files/catalogs/test-case-1/country-1/area-1-2/area-1-2-imagery/area-1-2-imagery.json b/tests/data-files/catalogs/test-case-1/country-1/area-1-2/area-1-2-imagery/area-1-2-imagery.json index a8535f7ff..7cf5dbfd5 100644 --- a/tests/data-files/catalogs/test-case-1/country-1/area-1-2/area-1-2-imagery/area-1-2-imagery.json +++ b/tests/data-files/catalogs/test-case-1/country-1/area-1-2/area-1-2-imagery/area-1-2-imagery.json @@ -1,69 +1,70 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "area-1-2-imagery", - "properties": { - "datetime": "2019-10-04 18:55:37Z" - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [ - -2.5048828125, - 3.8916575492899987 - ], - [ - -1.9610595703125, - 3.8916575492899987 - ], - [ - -1.9610595703125, - 4.275202171119132 - ], - [ - -2.5048828125, - 4.275202171119132 - ], - [ - -2.5048828125, - 3.8916575492899987 - ] - ] - ] - }, - "bbox": [ - -2.5048828125, - 3.8916575492899987, - -1.9610595703125, - 3.8916575492899987 - ], - "collection": "area-1-2", - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "area-1-2-imagery", + "properties": { + "datetime": "2019-10-04T18:55:37Z" }, - { - "rel": "root", - "href": "../../../catalog.json", - "type": "application/json" + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + -2.5048828125, + 3.8916575492899987 + ], + [ + -1.9610595703125, + 3.8916575492899987 + ], + [ + -1.9610595703125, + 4.275202171119132 + ], + [ + -2.5048828125, + 4.275202171119132 + ], + [ + -2.5048828125, + 3.8916575492899987 + ] + ] + ] }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "ortho": { - "href": "http://example.com/area-1-2_ortho.tif", - "type": "image/vnd.stac.geotiff" + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "ortho": { + "href": "http://example.com/area-1-2_ortho.tif", + "type": "image/vnd.stac.geotiff" + }, + "dsm": { + "href": "http://example.com/area-1-2_dsm.tif", + "type": "image/vnd.stac.geotiff" + } }, - "dsm": { - "href": "http://example.com/area-1-2_dsm.tif", - "type": "image/vnd.stac.geotiff" - } - } -} + "bbox": [ + -2.5048828125, + 3.8916575492899987, + -1.9610595703125, + 3.8916575492899987 + ], + "stac_extensions": [], + "collection": "area-1-2" +} \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-1/country-1/area-1-2/area-1-2-labels/area-1-2-labels.json b/tests/data-files/catalogs/test-case-1/country-1/area-1-2/area-1-2-labels/area-1-2-labels.json index 9e3c4517b..0b3b4ae9f 100644 --- a/tests/data-files/catalogs/test-case-1/country-1/area-1-2/area-1-2-labels/area-1-2-labels.json +++ b/tests/data-files/catalogs/test-case-1/country-1/area-1-2/area-1-2-labels/area-1-2-labels.json @@ -1,93 +1,93 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "area-1-2-labels", - "properties": { - "datetime": "2019-10-04 18:55:37Z", - "label:description": "labels for area-1-2", - "label:type": "vector", - "label:properties": [ - "label" - ], - "label:classes": [ - { - "name": "label", - "classes": [ - "one", - "two" - ] - } - ], - "label:task": [ - "classification" - ], - "label:method": [ - "manual" - ] - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [ - -2.5048828125, - 3.8916575492899987 - ], - [ - -1.9610595703125, - 3.8916575492899987 + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "area-1-2-labels", + "properties": { + "datetime": "2019-10-04T18:55:37Z", + "label:description": "labels for area-1-2", + "label:type": "vector", + "label:properties": [ + "label" ], - [ - -1.9610595703125, - 4.275202171119132 + "label:classes": [ + { + "name": "label", + "classes": [ + "one", + "two" + ] + } ], - [ - -2.5048828125, - 4.275202171119132 + "label:tasks": [ + "classification" ], - [ - -2.5048828125, - 3.8916575492899987 + "label:methods": [ + "manual" ] - ] - ] - }, - "bbox": [ - -2.5048828125, - 3.8916575492899987, - -1.9610595703125, - 3.8916575492899987 - ], - "collection": "area-1-2", - "links": [ - { - "rel": "source", - "href": "../area-1-2-imagery/area-1-2-imagery.json", - "type": "application/json" }, - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + -2.5048828125, + 3.8916575492899987 + ], + [ + -1.9610595703125, + 3.8916575492899987 + ], + [ + -1.9610595703125, + 4.275202171119132 + ], + [ + -2.5048828125, + 4.275202171119132 + ], + [ + -2.5048828125, + 3.8916575492899987 + ] + ] + ] }, - { - "rel": "root", - "href": "../../../catalog.json", - "type": "application/json" + "links": [ + { + "rel": "source", + "href": "../area-1-2-imagery/area-1-2-imagery.json", + "type": "application/json" + }, + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "labels": { + "href": "http://example.com/area-1-2-labels.geojson", + "type": "application/geo+json" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "labels": { - "href": "http://example.com/area-1-2-labels.geojson", - "type": "application/geo+json" - } - }, - "stac_extensions": [ - "label" - ] -} + "bbox": [ + -2.5048828125, + 3.8916575492899987, + -1.9610595703125, + 3.8916575492899987 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "area-1-2" +} \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-1/country-1/area-1-2/collection.json b/tests/data-files/catalogs/test-case-1/country-1/area-1-2/collection.json index 0f1743608..580ab0fa0 100644 --- a/tests/data-files/catalogs/test-case-1/country-1/area-1-2/collection.json +++ b/tests/data-files/catalogs/test-case-1/country-1/area-1-2/collection.json @@ -1,6 +1,7 @@ { + "type": "Collection", "id": "area-1-2", - "stac_version": "1.0.0-beta.2", + "stac_version": "1.0.0-rc.3", "description": "test collection country-1", "links": [ { @@ -24,6 +25,7 @@ "type": "application/json" } ], + "stac_extensions": [], "extent": { "spatial": { "bbox": [ diff --git a/tests/data-files/catalogs/test-case-1/country-1/catalog.json b/tests/data-files/catalogs/test-case-1/country-1/catalog.json index 7fa89aead..f1c0e3108 100644 --- a/tests/data-files/catalogs/test-case-1/country-1/catalog.json +++ b/tests/data-files/catalogs/test-case-1/country-1/catalog.json @@ -1,6 +1,7 @@ { + "type": "Catalog", "id": "country-1", - "stac_version": "1.0.0-beta.2", + "stac_version": "1.0.0-rc.3", "description": "test catalog country-1", "links": [ { @@ -23,5 +24,6 @@ "href": "../catalog.json", "type": "application/json" } - ] + ], + "stac_extensions": [] } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-1/country-2/area-2-1/area-2-1-imagery/area-2-1-imagery.json b/tests/data-files/catalogs/test-case-1/country-2/area-2-1/area-2-1-imagery/area-2-1-imagery.json index b13143c40..32ed274a0 100644 --- a/tests/data-files/catalogs/test-case-1/country-2/area-2-1/area-2-1-imagery/area-2-1-imagery.json +++ b/tests/data-files/catalogs/test-case-1/country-2/area-2-1/area-2-1-imagery/area-2-1-imagery.json @@ -1,69 +1,70 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "area-2-1-imagery", - "properties": { - "datetime": "2019-10-04 18:55:37Z" - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [ - -2.5048828125, - 3.8916575492899987 - ], - [ - -1.9610595703125, - 3.8916575492899987 - ], - [ - -1.9610595703125, - 4.275202171119132 - ], - [ - -2.5048828125, - 4.275202171119132 - ], - [ - -2.5048828125, - 3.8916575492899987 - ] - ] - ] - }, - "bbox": [ - -2.5048828125, - 3.8916575492899987, - -1.9610595703125, - 3.8916575492899987 - ], - "collection": "area-2-1", - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "area-2-1-imagery", + "properties": { + "datetime": "2019-10-04T18:55:37Z" }, - { - "rel": "root", - "href": "../../../catalog.json", - "type": "application/json" + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + -2.5048828125, + 3.8916575492899987 + ], + [ + -1.9610595703125, + 3.8916575492899987 + ], + [ + -1.9610595703125, + 4.275202171119132 + ], + [ + -2.5048828125, + 4.275202171119132 + ], + [ + -2.5048828125, + 3.8916575492899987 + ] + ] + ] }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "ortho": { - "href": "http://example.com/area-2-1_ortho.tif", - "type": "image/vnd.stac.geotiff" + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "ortho": { + "href": "http://example.com/area-2-1_ortho.tif", + "type": "image/vnd.stac.geotiff" + }, + "dsm": { + "href": "http://example.com/area-2-1_dsm.tif", + "type": "image/vnd.stac.geotiff" + } }, - "dsm": { - "href": "http://example.com/area-2-1_dsm.tif", - "type": "image/vnd.stac.geotiff" - } - } -} + "bbox": [ + -2.5048828125, + 3.8916575492899987, + -1.9610595703125, + 3.8916575492899987 + ], + "stac_extensions": [], + "collection": "area-2-1" +} \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-1/country-2/area-2-1/area-2-1-labels/area-2-1-labels.json b/tests/data-files/catalogs/test-case-1/country-2/area-2-1/area-2-1-labels/area-2-1-labels.json index 267467a6f..d05be47fb 100644 --- a/tests/data-files/catalogs/test-case-1/country-2/area-2-1/area-2-1-labels/area-2-1-labels.json +++ b/tests/data-files/catalogs/test-case-1/country-2/area-2-1/area-2-1-labels/area-2-1-labels.json @@ -1,93 +1,93 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "area-2-1-labels", - "properties": { - "datetime": "2019-10-04 18:55:37Z", - "label:description": "labels for area-2-1", - "label:type": "vector", - "label:properties": [ - "label" - ], - "label:classes": [ - { - "name": "label", - "classes": [ - "one", - "two" - ] - } - ], - "label:task": [ - "classification" - ], - "label:method": [ - "manual" - ] - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [ - -2.5048828125, - 3.8916575492899987 - ], - [ - -1.9610595703125, - 3.8916575492899987 + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "area-2-1-labels", + "properties": { + "datetime": "2019-10-04T18:55:37Z", + "label:description": "labels for area-2-1", + "label:type": "vector", + "label:properties": [ + "label" ], - [ - -1.9610595703125, - 4.275202171119132 + "label:classes": [ + { + "name": "label", + "classes": [ + "one", + "two" + ] + } ], - [ - -2.5048828125, - 4.275202171119132 + "label:tasks": [ + "classification" ], - [ - -2.5048828125, - 3.8916575492899987 + "label:methods": [ + "manual" ] - ] - ] - }, - "bbox": [ - -2.5048828125, - 3.8916575492899987, - -1.9610595703125, - 3.8916575492899987 - ], - "collection": "area-2-1", - "links": [ - { - "rel": "source", - "href": "../area-2-1-imagery/area-2-1-imagery.json", - "type": "application/json" }, - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + -2.5048828125, + 3.8916575492899987 + ], + [ + -1.9610595703125, + 3.8916575492899987 + ], + [ + -1.9610595703125, + 4.275202171119132 + ], + [ + -2.5048828125, + 4.275202171119132 + ], + [ + -2.5048828125, + 3.8916575492899987 + ] + ] + ] }, - { - "rel": "root", - "href": "../../../catalog.json", - "type": "application/json" + "links": [ + { + "rel": "source", + "href": "../area-2-1-imagery/area-2-1-imagery.json", + "type": "application/json" + }, + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "labels": { + "href": "http://example.com/area-2-1-labels.geojson", + "type": "application/geo+json" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "labels": { - "href": "http://example.com/area-2-1-labels.geojson", - "type": "application/geo+json" - } - }, - "stac_extensions": [ - "label" - ] -} + "bbox": [ + -2.5048828125, + 3.8916575492899987, + -1.9610595703125, + 3.8916575492899987 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "area-2-1" +} \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-1/country-2/area-2-1/collection.json b/tests/data-files/catalogs/test-case-1/country-2/area-2-1/collection.json index 417afd754..4865aaf50 100644 --- a/tests/data-files/catalogs/test-case-1/country-2/area-2-1/collection.json +++ b/tests/data-files/catalogs/test-case-1/country-2/area-2-1/collection.json @@ -1,6 +1,7 @@ { + "type": "Collection", "id": "area-2-1", - "stac_version": "1.0.0-beta.2", + "stac_version": "1.0.0-rc.3", "description": "test collection country-2", "links": [ { @@ -24,6 +25,7 @@ "type": "application/json" } ], + "stac_extensions": [], "extent": { "spatial": { "bbox": [ diff --git a/tests/data-files/catalogs/test-case-1/country-2/area-2-2/area-2-2-imagery/area-2-2-imagery.json b/tests/data-files/catalogs/test-case-1/country-2/area-2-2/area-2-2-imagery/area-2-2-imagery.json index 3ed5c71f3..de99f978b 100644 --- a/tests/data-files/catalogs/test-case-1/country-2/area-2-2/area-2-2-imagery/area-2-2-imagery.json +++ b/tests/data-files/catalogs/test-case-1/country-2/area-2-2/area-2-2-imagery/area-2-2-imagery.json @@ -1,69 +1,70 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "area-2-2-imagery", - "properties": { - "datetime": "2019-10-04 18:55:37Z" - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [ - -2.5048828125, - 3.8916575492899987 - ], - [ - -1.9610595703125, - 3.8916575492899987 - ], - [ - -1.9610595703125, - 4.275202171119132 - ], - [ - -2.5048828125, - 4.275202171119132 - ], - [ - -2.5048828125, - 3.8916575492899987 - ] - ] - ] - }, - "bbox": [ - -2.5048828125, - 3.8916575492899987, - -1.9610595703125, - 3.8916575492899987 - ], - "collection": "area-2-2", - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "area-2-2-imagery", + "properties": { + "datetime": "2019-10-04T18:55:37Z" }, - { - "rel": "root", - "href": "../../../catalog.json", - "type": "application/json" + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + -2.5048828125, + 3.8916575492899987 + ], + [ + -1.9610595703125, + 3.8916575492899987 + ], + [ + -1.9610595703125, + 4.275202171119132 + ], + [ + -2.5048828125, + 4.275202171119132 + ], + [ + -2.5048828125, + 3.8916575492899987 + ] + ] + ] }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "ortho": { - "href": "http://example.com/area-2-2_ortho.tif", - "type": "image/vnd.stac.geotiff" + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "ortho": { + "href": "http://example.com/area-2-2_ortho.tif", + "type": "image/vnd.stac.geotiff" + }, + "dsm": { + "href": "http://example.com/area-2-2_dsm.tif", + "type": "image/vnd.stac.geotiff" + } }, - "dsm": { - "href": "http://example.com/area-2-2_dsm.tif", - "type": "image/vnd.stac.geotiff" - } - } -} + "bbox": [ + -2.5048828125, + 3.8916575492899987, + -1.9610595703125, + 3.8916575492899987 + ], + "stac_extensions": [], + "collection": "area-2-2" +} \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-1/country-2/area-2-2/area-2-2-labels/area-2-2-labels.json b/tests/data-files/catalogs/test-case-1/country-2/area-2-2/area-2-2-labels/area-2-2-labels.json index 8ce9a7d5b..50bddf151 100644 --- a/tests/data-files/catalogs/test-case-1/country-2/area-2-2/area-2-2-labels/area-2-2-labels.json +++ b/tests/data-files/catalogs/test-case-1/country-2/area-2-2/area-2-2-labels/area-2-2-labels.json @@ -1,93 +1,93 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "area-2-2-labels", - "properties": { - "datetime": "2019-10-04 18:55:37Z", - "label:description": "labels for area-2-2", - "label:type": "vector", - "label:properties": [ - "label" - ], - "label:classes": [ - { - "name": "label", - "classes": [ - "one", - "two" - ] - } - ], - "label:task": [ - "classification" - ], - "label:method": [ - "manual" - ] - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [ - -2.5048828125, - 3.8916575492899987 - ], - [ - -1.9610595703125, - 3.8916575492899987 + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "area-2-2-labels", + "properties": { + "datetime": "2019-10-04T18:55:37Z", + "label:description": "labels for area-2-2", + "label:type": "vector", + "label:properties": [ + "label" ], - [ - -1.9610595703125, - 4.275202171119132 + "label:classes": [ + { + "name": "label", + "classes": [ + "one", + "two" + ] + } ], - [ - -2.5048828125, - 4.275202171119132 + "label:tasks": [ + "classification" ], - [ - -2.5048828125, - 3.8916575492899987 + "label:methods": [ + "manual" ] - ] - ] - }, - "bbox": [ - -2.5048828125, - 3.8916575492899987, - -1.9610595703125, - 3.8916575492899987 - ], - "collection": "area-2-2", - "links": [ - { - "rel": "source", - "href": "../area-2-2-imagery/area-2-2-imagery.json", - "type": "application/json" }, - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + -2.5048828125, + 3.8916575492899987 + ], + [ + -1.9610595703125, + 3.8916575492899987 + ], + [ + -1.9610595703125, + 4.275202171119132 + ], + [ + -2.5048828125, + 4.275202171119132 + ], + [ + -2.5048828125, + 3.8916575492899987 + ] + ] + ] }, - { - "rel": "root", - "href": "../../../catalog.json", - "type": "application/json" + "links": [ + { + "rel": "source", + "href": "../area-2-2-imagery/area-2-2-imagery.json", + "type": "application/json" + }, + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "labels": { + "href": "http://example.com/area-2-2-labels.geojson", + "type": "application/geo+json" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "labels": { - "href": "http://example.com/area-2-2-labels.geojson", - "type": "application/geo+json" - } - }, - "stac_extensions": [ - "label" - ] -} + "bbox": [ + -2.5048828125, + 3.8916575492899987, + -1.9610595703125, + 3.8916575492899987 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "area-2-2" +} \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-1/country-2/area-2-2/collection.json b/tests/data-files/catalogs/test-case-1/country-2/area-2-2/collection.json index d0cd0cf5a..6274a9d9d 100644 --- a/tests/data-files/catalogs/test-case-1/country-2/area-2-2/collection.json +++ b/tests/data-files/catalogs/test-case-1/country-2/area-2-2/collection.json @@ -1,6 +1,7 @@ { + "type": "Collection", "id": "area-2-2", - "stac_version": "1.0.0-beta.2", + "stac_version": "1.0.0-rc.3", "description": "test collection country-2", "links": [ { @@ -24,6 +25,7 @@ "type": "application/json" } ], + "stac_extensions": [], "extent": { "spatial": { "bbox": [ diff --git a/tests/data-files/catalogs/test-case-1/country-2/catalog.json b/tests/data-files/catalogs/test-case-1/country-2/catalog.json index d7696d8fb..7441b2a77 100644 --- a/tests/data-files/catalogs/test-case-1/country-2/catalog.json +++ b/tests/data-files/catalogs/test-case-1/country-2/catalog.json @@ -1,6 +1,7 @@ { + "type": "Catalog", "id": "country-2", - "stac_version": "1.0.0-beta.2", + "stac_version": "1.0.0-rc.3", "description": "test catalog country-2", "links": [ { @@ -23,5 +24,6 @@ "href": "../catalog.json", "type": "application/json" } - ] + ], + "stac_extensions": [] } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-2/1a8c1632-fa91-4a62-b33e-3a87c2ebdf16/5b922d42-9a77-4f79-a672-86096f7f849e/cf73ec1a-d790-4b59-b077-e101738571ed/cf73ec1a-d790-4b59-b077-e101738571ed.json b/tests/data-files/catalogs/test-case-2/1a8c1632-fa91-4a62-b33e-3a87c2ebdf16/5b922d42-9a77-4f79-a672-86096f7f849e/cf73ec1a-d790-4b59-b077-e101738571ed/cf73ec1a-d790-4b59-b077-e101738571ed.json index 714c0b535..27a7066fa 100644 --- a/tests/data-files/catalogs/test-case-2/1a8c1632-fa91-4a62-b33e-3a87c2ebdf16/5b922d42-9a77-4f79-a672-86096f7f849e/cf73ec1a-d790-4b59-b077-e101738571ed/cf73ec1a-d790-4b59-b077-e101738571ed.json +++ b/tests/data-files/catalogs/test-case-2/1a8c1632-fa91-4a62-b33e-3a87c2ebdf16/5b922d42-9a77-4f79-a672-86096f7f849e/cf73ec1a-d790-4b59-b077-e101738571ed/cf73ec1a-d790-4b59-b077-e101738571ed.json @@ -1,914 +1,914 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "cf73ec1a-d790-4b59-b077-e101738571ed", - "properties": { - "label:description": "Labels in layer", - "label:type": "vector", - "datetime": "2019-08-07 20:37:10Z", - "label:method": [ - "manual" - ], - "label:classes": [ - { - "name": "label", - "classes": [ - "Passenger Vehicle", - "Bus", - "Truck" + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "cf73ec1a-d790-4b59-b077-e101738571ed", + "properties": { + "label:description": "Labels in layer", + "label:type": "vector", + "datetime": "2019-08-07T20:37:10Z", + "label:classes": [ + { + "name": "label", + "classes": [ + "Passenger Vehicle", + "Bus", + "Truck" + ] + } + ], + "label:properties": [ + "label" + ], + "label:tasks": [ + "detection" + ], + "label:methods": [ + "manual" ] - } - ], - "label:task": [ - "detection" - ], - "label:properties": [ - "label" - ] - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [ - -86.75155098633836, - 35.686645216009545 - ], - [ - -86.75155102590682, - 35.68664554635556 - ], - [ - -86.75155102590682, - 35.90922661159095 - ], - [ - -86.75155098633836, - 35.90922694104629 - ], - [ - -86.75155058459285, - 35.90922697349481 - ], - [ - -86.62304646828477, - 35.90922697349481 - ], - [ - -86.62304606653927, - 35.90922694104629 - ], - [ - -86.6230460269708, - 35.90922661159095 - ], - [ - -86.6230460269708, - 35.87775813030909 - ], - [ - -86.62304585436203, - 35.87775669258231 - ], - [ - -86.623045343169, - 35.87775531010654 - ], - [ - -86.62304451303658, - 35.87775403600955 - ], - [ - -86.62304339586625, - 35.877752919254185 - ], - [ - -86.62304203459027, - 35.87775200275673 - ], - [ - -86.62304048152171, - 35.87775132173768 - ], - [ - -86.62303879634413, - 35.877750902368206 - ], - [ - -86.62303704381796, - 35.87775076076447 - ], - [ - -86.43439019325102, - 35.87775076076447 - ], - [ - -86.43438979150552, - 35.87775072830352 - ], - [ - -86.43438975193705, - 35.87775039872192 - ], - [ - -86.43438975193705, - 35.810302095824625 - ], - [ - -86.43438979150552, - 35.81030176597282 - ], - [ - -86.43439019325102, - 35.810301733485254 - ], - [ - -86.56561991663378, - 35.810301733485254 - ], - [ - -86.56562166915995, - 35.81030159176542 - ], - [ - -86.56562335433752, - 35.81030117205213 - ], - [ - -86.56562490740609, - 35.81030049047472 - ], - [ - -86.56562626868205, - 35.81029957322583 - ], - [ - -86.56562738585238, - 35.8102984555548 - ], - [ - -86.56562821598482, - 35.810297180413116 - ], - [ - -86.56562872717785, - 35.810295796803736 - ], - [ - -86.56562889978662, - 35.81029435789799 - ], - [ - -86.56562889978662, - 35.80805379492521 - ], - [ - -86.56562893935508, - 35.8080534650644 - ], - [ - -86.56562934110059, - 35.808053432575946 - ], - [ - -86.5929614057691, - 35.808053432575946 - ], - [ - -86.59296315829528, - 35.80805329085224 - ], - [ - -86.59296484347286, - 35.8080528711275 - ], - [ - -86.59296639654143, - 35.808052189531494 - ], - [ - -86.59296775781738, - 35.80805127225758 - ], - [ - -86.5929688749877, - 35.808050154556064 - ], - [ - -86.59296970512014, - 35.80804887937959 - ], - [ - -86.59297021631318, - 35.80804749573245 - ], - [ - -86.59297038892194, - 35.80804605678745 - ], - [ - -86.59297038892194, - 35.72487368215667 - ], - [ - -86.59297021631318, - 35.72487224176095 - ], - [ - -86.59296970512014, - 35.72487085671881 - ], - [ - -86.5929688749877, - 35.72486958025665 - ], - [ - -86.59296775781738, - 35.72486846142819 - ], - [ - -86.59296639654143, - 35.724867543229394 - ], - [ - -86.59296484347286, - 35.72486686094612 - ], - [ - -86.59296315829528, - 35.72486644079816 - ], - [ - -86.5929614057691, - 35.72486629893155 - ], - [ - -86.59023668132238, - 35.72486629893155 - ], - [ - -86.59023627957687, - 35.72486626641034 - ], - [ - -86.59023624000841, - 35.72486593621692 - ], - [ - -86.59023624000841, - 35.68664554635556 - ], - [ - -86.59023627957687, - 35.686645216009545 - ], - [ - -86.59023668132238, - 35.68664518347332 - ], - [ - -86.75155058459285, - 35.68664518347332 - ], - [ - -86.75155098633836, - 35.686645216009545 - ] - ], - [ - [ - -86.57382236337436, - 35.857516052580706 - ], - [ - -86.57382411590054, - 35.857515910942126 - ], - [ - -86.57382580107813, - 35.85751549146944 - ], - [ - -86.57382735414667, - 35.85751481028278 - ], - [ - -86.57382871542264, - 35.857513893559734 - ], - [ - -86.57382983259296, - 35.85751277652946 - ], - [ - -86.5738306627254, - 35.85751150211878 - ], - [ - -86.57383117391844, - 35.85751011930261 - ], - [ - -86.5738313465272, - 35.857508681221766 - ], - [ - -86.5738313465272, - 35.85527512323118 - ], - [ - -86.57383117391844, - 35.855273685111264 - ], - [ - -86.5738306627254, - 35.85527230225746 - ], - [ - -86.57382983259296, - 35.85527102781209 - ], - [ - -86.57382871542264, - 35.85526991075136 - ], - [ - -86.57382735414667, - 35.8552689940033 - ], - [ - -86.57382580107813, - 35.85526831279802 - ], - [ - -86.57382411590054, - 35.855267893313886 - ], - [ - -86.57382236337436, - 35.85526775167143 - ], - [ - -86.57110618076653, - 35.85526775167143 - ], - [ - -86.57110442824035, - 35.855267893313886 - ], - [ - -86.57110274306277, - 35.85526831279802 - ], - [ - -86.57110118999421, - 35.8552689940033 - ], - [ - -86.57109982871825, - 35.85526991075136 - ], - [ - -86.57109871154792, - 35.85527102781209 - ], - [ - -86.57109788141548, - 35.85527230225746 - ], - [ - -86.57109737022245, - 35.855273685111264 - ], - [ - -86.57109719761368, - 35.85527512323118 - ], - [ - -86.57109719761368, - 35.857508681221766 - ], - [ - -86.57109737022245, - 35.85751011930261 - ], - [ - -86.57109788141548, - 35.85751150211878 - ], - [ - -86.57109871154792, - 35.85751277652946 - ], - [ - -86.57109982871825, - 35.857513893559734 - ], - [ - -86.57110118999421, - 35.85751481028278 - ], - [ - -86.57110274306277, - 35.85751549146944 - ], - [ - -86.57110442824035, - 35.857515910942126 - ], - [ - -86.57110618076653, - 35.857516052580706 - ], - [ - -86.57382236337436, - 35.857516052580706 - ] - ], - [ - [ - -86.6312484737114, - 35.742860087824354 - ], - [ - -86.63124830110263, - 35.7428586477421 - ], - [ - -86.6312477899096, - 35.742857263001376 - ], - [ - -86.63124695977717, - 35.742855986817 - ], - [ - -86.63124584260684, - 35.742854868232016 - ], - [ - -86.63124448133088, - 35.742853950233034 - ], - [ - -86.63124292826232, - 35.742853268098244 - ], - [ - -86.63124124308473, - 35.742852848041714 - ], - [ - -86.63123949055856, - 35.74285270620598 - ], - [ - -86.6285233079507, - 35.74285270620598 - ], - [ - -86.62852155542451, - 35.742852848041714 - ], - [ - -86.62851987024693, - 35.742853268098244 - ], - [ - -86.62851831717838, - 35.742853950233034 - ], - [ - -86.62851695590241, - 35.742854868232016 - ], - [ - -86.62851583873208, - 35.742855986817 - ], - [ - -86.62851500859965, - 35.742857263001376 - ], - [ - -86.62851449740661, - 35.7428586477421 - ], - [ - -86.62851432479786, - 35.742860087824354 - ], - [ - -86.62851432479786, - 35.74509362569718 - ], - [ - -86.62851449740661, - 35.74509506574047 - ], - [ - -86.62851500859965, - 35.74509645044369 - ], - [ - -86.62851583873208, - 35.74509772659346 - ], - [ - -86.62851695590241, - 35.745098845148064 - ], - [ - -86.62851831717838, - 35.7450997631221 - ], - [ - -86.62851987024693, - 35.74510044523834 - ], - [ - -86.62852155542451, - 35.74510086528344 - ], - [ - -86.6285233079507, - 35.74510100711532 - ], - [ - -86.63123949055856, - 35.74510100711532 - ], - [ - -86.63124124308473, - 35.74510086528344 - ], - [ - -86.63124292826232, - 35.74510044523834 - ], - [ - -86.63124448133088, - 35.7450997631221 - ], - [ - -86.63124584260684, - 35.745098845148064 - ], - [ - -86.63124695977717, - 35.74509772659346 - ], - [ - -86.6312477899096, - 35.74509645044369 - ], - [ - -86.63124830110263, - 35.74509506574047 - ], - [ - -86.6312484737114, - 35.74509362569718 - ], - [ - -86.6312484737114, - 35.742860087824354 - ] - ], - [ - [ - -86.6640582606738, - 35.84178531898385 - ], - [ - -86.66405808806503, - 35.84178388062817 - ], - [ - -86.664057576872, - 35.84178249754766 - ], - [ - -86.66405674673958, - 35.84178122289334 - ], - [ - -86.66405562956925, - 35.84178010564947 - ], - [ - -86.66405426829328, - 35.84177918875111 - ], - [ - -86.66405271522473, - 35.84177850743416 - ], - [ - -86.66405103004713, - 35.841778087881245 - ], - [ - -86.66404927752096, - 35.84177794621557 - ], - [ - -86.66133309491308, - 35.84177794621557 - ], - [ - -86.6613313423869, - 35.841778087881245 - ], - [ - -86.66132965720934, - 35.84177850743416 - ], - [ - -86.66132810414076, - 35.84177918875111 - ], - [ - -86.6613267428648, - 35.84178010564947 - ], - [ - -86.66132562569447, - 35.84178122289334 - ], - [ - -86.66132479556204, - 35.84178249754766 - ], - [ - -86.661324284369, - 35.84178388062817 - ], - [ - -86.66132411176024, - 35.84178531898385 - ], - [ - -86.66132411176024, - 35.84401887455732 - ], - [ - -86.661324284369, - 35.84402031287395 - ], - [ - -86.66132479556204, - 35.84402169591686 - ], - [ - -86.66132562569447, - 35.84402297053648 - ], - [ - -86.6613267428648, - 35.84402408774991 - ], - [ - -86.66132810414076, - 35.844025004623255 - ], - [ - -86.66132965720934, - 35.84402568592161 - ], - [ - -86.6613313423869, - 35.84402610546306 - ], - [ - -86.66133309491308, - 35.844026247124866 - ], - [ - -86.66404927752096, - 35.844026247124866 - ], - [ - -86.66405103004713, - 35.84402610546306 - ], - [ - -86.66405271522473, - 35.84402568592161 - ], - [ - -86.66405426829328, - 35.844025004623255 - ], - [ - -86.66405562956925, - 35.84402408774991 - ], - [ - -86.66405674673958, - 35.84402297053648 - ], - [ - -86.664057576872, - 35.84402169591686 - ], - [ - -86.66405808806503, - 35.84402031287395 - ], - [ - -86.6640582606738, - 35.84401887455732 - ], - [ - -86.6640582606738, - 35.84178531898385 - ] - ], - [ - [ - -86.67226070741438, - 35.7675913956163 - ], - [ - -86.67226053480562, - 35.76758995596529 - ], - [ - -86.67226002361258, - 35.76758857163924 - ], - [ - -86.67225919348014, - 35.767587295837004 - ], - [ - -86.67225807630982, - 35.767586177586985 - ], - [ - -86.67225671503387, - 35.76758525986291 - ], - [ - -86.6722551619653, - 35.76758457793238 - ], - [ - -86.67225347678772, - 35.767584158001654 - ], - [ - -86.67225172426154, - 35.767584016208396 - ], - [ - -86.66953554165369, - 35.767584016208396 - ], - [ - -86.66953378912751, - 35.767584158001654 - ], - [ - -86.66953210394993, - 35.76758457793238 - ], - [ - -86.66953055088136, - 35.76758525986291 - ], - [ - -86.66952918960541, - 35.767586177586985 - ], - [ - -86.66952807243509, - 35.767587295837004 - ], - [ - -86.66952724230264, - 35.76758857163924 - ], - [ - -86.66952673110961, - 35.76758995596529 - ], - [ - -86.66952655850085, - 35.7675913956163 - ], - [ - -86.66952655850085, - 35.76982493791015 - ], - [ - -86.66952673110961, - 35.76982637752218 - ], - [ - -86.66952724230264, - 35.7698277618107 - ], - [ - -86.66952807243509, - 35.7698290375783 - ], - [ - -86.66952918960541, - 35.76983015579792 - ], - [ - -86.66953055088136, - 35.76983107349703 - ], - [ - -86.66953210394993, - 35.769831755409 - ], - [ - -86.66953378912751, - 35.769832175328304 - ], - [ - -86.66953554165369, - 35.76983231711771 - ], - [ - -86.67225172426154, - 35.76983231711771 - ], - [ - -86.67225347678772, - 35.769832175328304 - ], - [ - -86.6722551619653, - 35.769831755409 - ], - [ - -86.67225671503387, - 35.76983107349703 - ], - [ - -86.67225807630982, - 35.76983015579792 - ], - [ - -86.67225919348014, - 35.7698290375783 - ], - [ - -86.67226002361258, - 35.7698277618107 - ], - [ - -86.67226053480562, - 35.76982637752218 - ], - [ - -86.67226070741438, - 35.76982493791015 - ], - [ - -86.67226070741438, - 35.7675913956163 + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + -86.75155098633836, + 35.686645216009545 + ], + [ + -86.75155102590682, + 35.68664554635556 + ], + [ + -86.75155102590682, + 35.90922661159095 + ], + [ + -86.75155098633836, + 35.90922694104629 + ], + [ + -86.75155058459285, + 35.90922697349481 + ], + [ + -86.62304646828477, + 35.90922697349481 + ], + [ + -86.62304606653927, + 35.90922694104629 + ], + [ + -86.6230460269708, + 35.90922661159095 + ], + [ + -86.6230460269708, + 35.87775813030909 + ], + [ + -86.62304585436203, + 35.87775669258231 + ], + [ + -86.623045343169, + 35.87775531010654 + ], + [ + -86.62304451303658, + 35.87775403600955 + ], + [ + -86.62304339586625, + 35.877752919254185 + ], + [ + -86.62304203459027, + 35.87775200275673 + ], + [ + -86.62304048152171, + 35.87775132173768 + ], + [ + -86.62303879634413, + 35.877750902368206 + ], + [ + -86.62303704381796, + 35.87775076076447 + ], + [ + -86.43439019325102, + 35.87775076076447 + ], + [ + -86.43438979150552, + 35.87775072830352 + ], + [ + -86.43438975193705, + 35.87775039872192 + ], + [ + -86.43438975193705, + 35.810302095824625 + ], + [ + -86.43438979150552, + 35.81030176597282 + ], + [ + -86.43439019325102, + 35.810301733485254 + ], + [ + -86.56561991663378, + 35.810301733485254 + ], + [ + -86.56562166915995, + 35.81030159176542 + ], + [ + -86.56562335433752, + 35.81030117205213 + ], + [ + -86.56562490740609, + 35.81030049047472 + ], + [ + -86.56562626868205, + 35.81029957322583 + ], + [ + -86.56562738585238, + 35.8102984555548 + ], + [ + -86.56562821598482, + 35.810297180413116 + ], + [ + -86.56562872717785, + 35.810295796803736 + ], + [ + -86.56562889978662, + 35.81029435789799 + ], + [ + -86.56562889978662, + 35.80805379492521 + ], + [ + -86.56562893935508, + 35.8080534650644 + ], + [ + -86.56562934110059, + 35.808053432575946 + ], + [ + -86.5929614057691, + 35.808053432575946 + ], + [ + -86.59296315829528, + 35.80805329085224 + ], + [ + -86.59296484347286, + 35.8080528711275 + ], + [ + -86.59296639654143, + 35.808052189531494 + ], + [ + -86.59296775781738, + 35.80805127225758 + ], + [ + -86.5929688749877, + 35.808050154556064 + ], + [ + -86.59296970512014, + 35.80804887937959 + ], + [ + -86.59297021631318, + 35.80804749573245 + ], + [ + -86.59297038892194, + 35.80804605678745 + ], + [ + -86.59297038892194, + 35.72487368215667 + ], + [ + -86.59297021631318, + 35.72487224176095 + ], + [ + -86.59296970512014, + 35.72487085671881 + ], + [ + -86.5929688749877, + 35.72486958025665 + ], + [ + -86.59296775781738, + 35.72486846142819 + ], + [ + -86.59296639654143, + 35.724867543229394 + ], + [ + -86.59296484347286, + 35.72486686094612 + ], + [ + -86.59296315829528, + 35.72486644079816 + ], + [ + -86.5929614057691, + 35.72486629893155 + ], + [ + -86.59023668132238, + 35.72486629893155 + ], + [ + -86.59023627957687, + 35.72486626641034 + ], + [ + -86.59023624000841, + 35.72486593621692 + ], + [ + -86.59023624000841, + 35.68664554635556 + ], + [ + -86.59023627957687, + 35.686645216009545 + ], + [ + -86.59023668132238, + 35.68664518347332 + ], + [ + -86.75155058459285, + 35.68664518347332 + ], + [ + -86.75155098633836, + 35.686645216009545 + ] + ], + [ + [ + -86.57382236337436, + 35.857516052580706 + ], + [ + -86.57382411590054, + 35.857515910942126 + ], + [ + -86.57382580107813, + 35.85751549146944 + ], + [ + -86.57382735414667, + 35.85751481028278 + ], + [ + -86.57382871542264, + 35.857513893559734 + ], + [ + -86.57382983259296, + 35.85751277652946 + ], + [ + -86.5738306627254, + 35.85751150211878 + ], + [ + -86.57383117391844, + 35.85751011930261 + ], + [ + -86.5738313465272, + 35.857508681221766 + ], + [ + -86.5738313465272, + 35.85527512323118 + ], + [ + -86.57383117391844, + 35.855273685111264 + ], + [ + -86.5738306627254, + 35.85527230225746 + ], + [ + -86.57382983259296, + 35.85527102781209 + ], + [ + -86.57382871542264, + 35.85526991075136 + ], + [ + -86.57382735414667, + 35.8552689940033 + ], + [ + -86.57382580107813, + 35.85526831279802 + ], + [ + -86.57382411590054, + 35.855267893313886 + ], + [ + -86.57382236337436, + 35.85526775167143 + ], + [ + -86.57110618076653, + 35.85526775167143 + ], + [ + -86.57110442824035, + 35.855267893313886 + ], + [ + -86.57110274306277, + 35.85526831279802 + ], + [ + -86.57110118999421, + 35.8552689940033 + ], + [ + -86.57109982871825, + 35.85526991075136 + ], + [ + -86.57109871154792, + 35.85527102781209 + ], + [ + -86.57109788141548, + 35.85527230225746 + ], + [ + -86.57109737022245, + 35.855273685111264 + ], + [ + -86.57109719761368, + 35.85527512323118 + ], + [ + -86.57109719761368, + 35.857508681221766 + ], + [ + -86.57109737022245, + 35.85751011930261 + ], + [ + -86.57109788141548, + 35.85751150211878 + ], + [ + -86.57109871154792, + 35.85751277652946 + ], + [ + -86.57109982871825, + 35.857513893559734 + ], + [ + -86.57110118999421, + 35.85751481028278 + ], + [ + -86.57110274306277, + 35.85751549146944 + ], + [ + -86.57110442824035, + 35.857515910942126 + ], + [ + -86.57110618076653, + 35.857516052580706 + ], + [ + -86.57382236337436, + 35.857516052580706 + ] + ], + [ + [ + -86.6312484737114, + 35.742860087824354 + ], + [ + -86.63124830110263, + 35.7428586477421 + ], + [ + -86.6312477899096, + 35.742857263001376 + ], + [ + -86.63124695977717, + 35.742855986817 + ], + [ + -86.63124584260684, + 35.742854868232016 + ], + [ + -86.63124448133088, + 35.742853950233034 + ], + [ + -86.63124292826232, + 35.742853268098244 + ], + [ + -86.63124124308473, + 35.742852848041714 + ], + [ + -86.63123949055856, + 35.74285270620598 + ], + [ + -86.6285233079507, + 35.74285270620598 + ], + [ + -86.62852155542451, + 35.742852848041714 + ], + [ + -86.62851987024693, + 35.742853268098244 + ], + [ + -86.62851831717838, + 35.742853950233034 + ], + [ + -86.62851695590241, + 35.742854868232016 + ], + [ + -86.62851583873208, + 35.742855986817 + ], + [ + -86.62851500859965, + 35.742857263001376 + ], + [ + -86.62851449740661, + 35.7428586477421 + ], + [ + -86.62851432479786, + 35.742860087824354 + ], + [ + -86.62851432479786, + 35.74509362569718 + ], + [ + -86.62851449740661, + 35.74509506574047 + ], + [ + -86.62851500859965, + 35.74509645044369 + ], + [ + -86.62851583873208, + 35.74509772659346 + ], + [ + -86.62851695590241, + 35.745098845148064 + ], + [ + -86.62851831717838, + 35.7450997631221 + ], + [ + -86.62851987024693, + 35.74510044523834 + ], + [ + -86.62852155542451, + 35.74510086528344 + ], + [ + -86.6285233079507, + 35.74510100711532 + ], + [ + -86.63123949055856, + 35.74510100711532 + ], + [ + -86.63124124308473, + 35.74510086528344 + ], + [ + -86.63124292826232, + 35.74510044523834 + ], + [ + -86.63124448133088, + 35.7450997631221 + ], + [ + -86.63124584260684, + 35.745098845148064 + ], + [ + -86.63124695977717, + 35.74509772659346 + ], + [ + -86.6312477899096, + 35.74509645044369 + ], + [ + -86.63124830110263, + 35.74509506574047 + ], + [ + -86.6312484737114, + 35.74509362569718 + ], + [ + -86.6312484737114, + 35.742860087824354 + ] + ], + [ + [ + -86.6640582606738, + 35.84178531898385 + ], + [ + -86.66405808806503, + 35.84178388062817 + ], + [ + -86.664057576872, + 35.84178249754766 + ], + [ + -86.66405674673958, + 35.84178122289334 + ], + [ + -86.66405562956925, + 35.84178010564947 + ], + [ + -86.66405426829328, + 35.84177918875111 + ], + [ + -86.66405271522473, + 35.84177850743416 + ], + [ + -86.66405103004713, + 35.841778087881245 + ], + [ + -86.66404927752096, + 35.84177794621557 + ], + [ + -86.66133309491308, + 35.84177794621557 + ], + [ + -86.6613313423869, + 35.841778087881245 + ], + [ + -86.66132965720934, + 35.84177850743416 + ], + [ + -86.66132810414076, + 35.84177918875111 + ], + [ + -86.6613267428648, + 35.84178010564947 + ], + [ + -86.66132562569447, + 35.84178122289334 + ], + [ + -86.66132479556204, + 35.84178249754766 + ], + [ + -86.661324284369, + 35.84178388062817 + ], + [ + -86.66132411176024, + 35.84178531898385 + ], + [ + -86.66132411176024, + 35.84401887455732 + ], + [ + -86.661324284369, + 35.84402031287395 + ], + [ + -86.66132479556204, + 35.84402169591686 + ], + [ + -86.66132562569447, + 35.84402297053648 + ], + [ + -86.6613267428648, + 35.84402408774991 + ], + [ + -86.66132810414076, + 35.844025004623255 + ], + [ + -86.66132965720934, + 35.84402568592161 + ], + [ + -86.6613313423869, + 35.84402610546306 + ], + [ + -86.66133309491308, + 35.844026247124866 + ], + [ + -86.66404927752096, + 35.844026247124866 + ], + [ + -86.66405103004713, + 35.84402610546306 + ], + [ + -86.66405271522473, + 35.84402568592161 + ], + [ + -86.66405426829328, + 35.844025004623255 + ], + [ + -86.66405562956925, + 35.84402408774991 + ], + [ + -86.66405674673958, + 35.84402297053648 + ], + [ + -86.664057576872, + 35.84402169591686 + ], + [ + -86.66405808806503, + 35.84402031287395 + ], + [ + -86.6640582606738, + 35.84401887455732 + ], + [ + -86.6640582606738, + 35.84178531898385 + ] + ], + [ + [ + -86.67226070741438, + 35.7675913956163 + ], + [ + -86.67226053480562, + 35.76758995596529 + ], + [ + -86.67226002361258, + 35.76758857163924 + ], + [ + -86.67225919348014, + 35.767587295837004 + ], + [ + -86.67225807630982, + 35.767586177586985 + ], + [ + -86.67225671503387, + 35.76758525986291 + ], + [ + -86.6722551619653, + 35.76758457793238 + ], + [ + -86.67225347678772, + 35.767584158001654 + ], + [ + -86.67225172426154, + 35.767584016208396 + ], + [ + -86.66953554165369, + 35.767584016208396 + ], + [ + -86.66953378912751, + 35.767584158001654 + ], + [ + -86.66953210394993, + 35.76758457793238 + ], + [ + -86.66953055088136, + 35.76758525986291 + ], + [ + -86.66952918960541, + 35.767586177586985 + ], + [ + -86.66952807243509, + 35.767587295837004 + ], + [ + -86.66952724230264, + 35.76758857163924 + ], + [ + -86.66952673110961, + 35.76758995596529 + ], + [ + -86.66952655850085, + 35.7675913956163 + ], + [ + -86.66952655850085, + 35.76982493791015 + ], + [ + -86.66952673110961, + 35.76982637752218 + ], + [ + -86.66952724230264, + 35.7698277618107 + ], + [ + -86.66952807243509, + 35.7698290375783 + ], + [ + -86.66952918960541, + 35.76983015579792 + ], + [ + -86.66953055088136, + 35.76983107349703 + ], + [ + -86.66953210394993, + 35.769831755409 + ], + [ + -86.66953378912751, + 35.769832175328304 + ], + [ + -86.66953554165369, + 35.76983231711771 + ], + [ + -86.67225172426154, + 35.76983231711771 + ], + [ + -86.67225347678772, + 35.769832175328304 + ], + [ + -86.6722551619653, + 35.769831755409 + ], + [ + -86.67225671503387, + 35.76983107349703 + ], + [ + -86.67225807630982, + 35.76983015579792 + ], + [ + -86.67225919348014, + 35.7698290375783 + ], + [ + -86.67226002361258, + 35.7698277618107 + ], + [ + -86.67226053480562, + 35.76982637752218 + ], + [ + -86.67226070741438, + 35.76982493791015 + ], + [ + -86.67226070741438, + 35.7675913956163 + ] + ] ] - ] - ] - }, - "bbox": [ - -86.75155102590682, - 35.68664518347332, - -86.43438975193705, - 35.90922697349481 - ], - "links": [ - { - "rel": "source", - "href": "../../f433578c-f879-414d-8101-83142a0a13c3/d43bead8-e3f8-4c51-95d6-e24e750a402b/d43bead8-e3f8-4c51-95d6-e24e750a402b.json", - "type": "image/vnd.stac.geotiff; cloud-optimized=true", - "title": "Source image STAC item for the label item" }, - { - "rel": "root", - "href": "../../../catalog.json", - "type": "application/json" + "links": [ + { + "rel": "source", + "href": "../../f433578c-f879-414d-8101-83142a0a13c3/d43bead8-e3f8-4c51-95d6-e24e750a402b/d43bead8-e3f8-4c51-95d6-e24e750a402b.json", + "type": "image/vnd.stac.geotiff; cloud-optimized=true", + "title": "Source image STAC item for the label item" + }, + { + "rel": "root", + "href": "../../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "cf73ec1a-d790-4b59-b077-e101738571ed": { + "href": "./data.geojson", + "type": "application/geo+json", + "title": "Label Data Feature Collection" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "cf73ec1a-d790-4b59-b077-e101738571ed": { - "href": "./data.geojson", - "type": "application/geo+json", - "title": "Label Data Feature Collection" - } - }, - "stac_extensions": [ - "label" - ] + "bbox": [ + -86.75155102590682, + 35.68664518347332, + -86.43438975193705, + 35.90922697349481 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ] } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-2/1a8c1632-fa91-4a62-b33e-3a87c2ebdf16/5b922d42-9a77-4f79-a672-86096f7f849e/collection.json b/tests/data-files/catalogs/test-case-2/1a8c1632-fa91-4a62-b33e-3a87c2ebdf16/5b922d42-9a77-4f79-a672-86096f7f849e/collection.json index 263b1f8a2..dbad0e5dc 100644 --- a/tests/data-files/catalogs/test-case-2/1a8c1632-fa91-4a62-b33e-3a87c2ebdf16/5b922d42-9a77-4f79-a672-86096f7f849e/collection.json +++ b/tests/data-files/catalogs/test-case-2/1a8c1632-fa91-4a62-b33e-3a87c2ebdf16/5b922d42-9a77-4f79-a672-86096f7f849e/collection.json @@ -1,6 +1,7 @@ { + "type": "Collection", "id": "5b922d42-9a77-4f79-a672-86096f7f849e", - "stac_version": "1.0.0-beta.2", + "stac_version": "1.0.0-rc.3", "description": "Label collection in layer 1a8c1632-fa91-4a62-b33e-3a87c2ebdf16", "links": [ { @@ -20,7 +21,12 @@ "type": "application/json" } ], + "stac_extensions": [], "title": "Label collection", + "keywords": [], + "version": "1", + "providers": [], + "properties": {}, "extent": { "spatial": { "bbox": [ @@ -41,9 +47,5 @@ ] } }, - "license": "proprietary", - "keywords": [], - "version": "1", - "providers": [], - "properties": {} + "license": "proprietary" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-2/1a8c1632-fa91-4a62-b33e-3a87c2ebdf16/collection.json b/tests/data-files/catalogs/test-case-2/1a8c1632-fa91-4a62-b33e-3a87c2ebdf16/collection.json index c8d614c88..1cea4cec1 100644 --- a/tests/data-files/catalogs/test-case-2/1a8c1632-fa91-4a62-b33e-3a87c2ebdf16/collection.json +++ b/tests/data-files/catalogs/test-case-2/1a8c1632-fa91-4a62-b33e-3a87c2ebdf16/collection.json @@ -1,6 +1,7 @@ { + "type": "Collection", "id": "1a8c1632-fa91-4a62-b33e-3a87c2ebdf16", - "stac_version": "1.0.0-beta.2", + "stac_version": "1.0.0-rc.3", "description": "Project layer collection", "links": [ { @@ -26,7 +27,12 @@ "type": "application/json" } ], + "stac_extensions": [], "title": "Layers", + "keywords": [], + "version": "1", + "providers": [], + "properties": {}, "extent": { "spatial": { "bbox": [ @@ -47,9 +53,5 @@ ] } }, - "license": "proprietary", - "keywords": [], - "version": "1", - "providers": [], - "properties": {} + "license": "proprietary" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-2/1a8c1632-fa91-4a62-b33e-3a87c2ebdf16/f433578c-f879-414d-8101-83142a0a13c3/collection.json b/tests/data-files/catalogs/test-case-2/1a8c1632-fa91-4a62-b33e-3a87c2ebdf16/f433578c-f879-414d-8101-83142a0a13c3/collection.json index 6f431f9cc..9f7105872 100644 --- a/tests/data-files/catalogs/test-case-2/1a8c1632-fa91-4a62-b33e-3a87c2ebdf16/f433578c-f879-414d-8101-83142a0a13c3/collection.json +++ b/tests/data-files/catalogs/test-case-2/1a8c1632-fa91-4a62-b33e-3a87c2ebdf16/f433578c-f879-414d-8101-83142a0a13c3/collection.json @@ -1,6 +1,7 @@ { + "type": "Collection", "id": "f433578c-f879-414d-8101-83142a0a13c3", - "stac_version": "1.0.0-beta.2", + "stac_version": "1.0.0-rc.3", "description": "Scene collection in layer 1a8c1632-fa91-4a62-b33e-3a87c2ebdf16", "links": [ { @@ -20,7 +21,12 @@ "type": "application/json" } ], + "stac_extensions": [], "title": "Scene collection", + "keywords": [], + "version": "1", + "providers": [], + "properties": {}, "extent": { "spatial": { "bbox": [ @@ -41,9 +47,5 @@ ] } }, - "license": "proprietary", - "keywords": [], - "version": "1", - "providers": [], - "properties": {} + "license": "proprietary" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-2/1a8c1632-fa91-4a62-b33e-3a87c2ebdf16/f433578c-f879-414d-8101-83142a0a13c3/d43bead8-e3f8-4c51-95d6-e24e750a402b/d43bead8-e3f8-4c51-95d6-e24e750a402b.json b/tests/data-files/catalogs/test-case-2/1a8c1632-fa91-4a62-b33e-3a87c2ebdf16/f433578c-f879-414d-8101-83142a0a13c3/d43bead8-e3f8-4c51-95d6-e24e750a402b/d43bead8-e3f8-4c51-95d6-e24e750a402b.json index 9c6ade178..b2e249c36 100644 --- a/tests/data-files/catalogs/test-case-2/1a8c1632-fa91-4a62-b33e-3a87c2ebdf16/f433578c-f879-414d-8101-83142a0a13c3/d43bead8-e3f8-4c51-95d6-e24e750a402b/d43bead8-e3f8-4c51-95d6-e24e750a402b.json +++ b/tests/data-files/catalogs/test-case-2/1a8c1632-fa91-4a62-b33e-3a87c2ebdf16/f433578c-f879-414d-8101-83142a0a13c3/d43bead8-e3f8-4c51-95d6-e24e750a402b/d43bead8-e3f8-4c51-95d6-e24e750a402b.json @@ -1,63 +1,63 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "d43bead8-e3f8-4c51-95d6-e24e750a402b", - "properties": { - "datetime": "2019-08-07 20:37:10Z" - }, - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - -86.75260925292969, - 35.685734110176064 - ], - [ - -86.75260925292969, - 35.9078947564485 - ], - [ - -86.43606567382814, - 35.9078947564485 - ], - [ - -86.43606567382814, - 35.685734110176064 - ], - [ - -86.75260925292969, - 35.685734110176064 - ] + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "d43bead8-e3f8-4c51-95d6-e24e750a402b", + "properties": { + "datetime": "2019-08-07T20:37:10Z" + }, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [ + -86.75260925292969, + 35.685734110176064 + ], + [ + -86.75260925292969, + 35.9078947564485 + ], + [ + -86.43606567382814, + 35.9078947564485 + ], + [ + -86.43606567382814, + 35.685734110176064 + ], + [ + -86.75260925292969, + 35.685734110176064 + ] + ] + ] ] - ] - ] - }, - "bbox": [ - -86.75260925292969, - 35.685734110176064, - -86.43606567382814, - 35.9078947564485 - ], - "links": [ - { - "rel": "root", - "href": "../../../catalog.json", - "type": "application/json" }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "d43bead8-e3f8-4c51-95d6-e24e750a402b": { - "href": "s3://somebucket/some/sort/of/COG.tif", - "type": "image/vnd.stac.geotiff; cloud-optimized=true", - "title": "scene" - } - }, - "stac_extensions": [] + "links": [ + { + "rel": "root", + "href": "../../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "d43bead8-e3f8-4c51-95d6-e24e750a402b": { + "href": "s3://somebucket/some/sort/of/COG.tif", + "type": "image/vnd.stac.geotiff; cloud-optimized=true", + "title": "scene" + } + }, + "bbox": [ + -86.75260925292969, + 35.685734110176064, + -86.43606567382814, + 35.9078947564485 + ], + "stac_extensions": [] } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-2/catalog.json b/tests/data-files/catalogs/test-case-2/catalog.json index 73cea685d..8d3626f02 100644 --- a/tests/data-files/catalogs/test-case-2/catalog.json +++ b/tests/data-files/catalogs/test-case-2/catalog.json @@ -1,6 +1,7 @@ { + "type": "Catalog", "id": "01749366-9e25-4b42-a4d1-5aae9f8c9eec", - "stac_version": "1.0.0-beta.2", + "stac_version": "1.0.0-rc.3", "description": "Exported from Raster Foundry 2019-10-04 15:55:13.759", "links": [ { @@ -15,5 +16,6 @@ "title": "Layer Collection" } ], + "stac_extensions": [], "title": "Test Case 2" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/acc/665946-labels/665946-labels.json b/tests/data-files/catalogs/test-case-4/acc/665946-labels/665946-labels.json index 1bb21dcfc..0f825fb88 100644 --- a/tests/data-files/catalogs/test-case-4/acc/665946-labels/665946-labels.json +++ b/tests/data-files/catalogs/test-case-4/acc/665946-labels/665946-labels.json @@ -1,293 +1,294 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "665946-labels", - "properties": { - "label:description": "Geojson building labels for scene 665946", - "area": "acc", - "label:type": "vector", - "label:properties": [ - "building" - ], - "label:overviews": [ - { - "property_key": "building", - "counts": [ - { - "name": "yes", - "count": 7308 - } - ] - } - ], - "license": "ODbL-1.0", - "datetime": "2018-08-05T00:00:00Z", - "label:classes": [ - { - "name": "building", - "classes": [ - "yes" + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "665946-labels", + "properties": { + "label:description": "Geojson building labels for scene 665946", + "area": "acc", + "label:type": "vector", + "label:properties": [ + "building" + ], + "label:overviews": [ + { + "property_key": "building", + "counts": [ + { + "name": "yes", + "count": 7308 + } + ] + } + ], + "license": "ODbL-1.0", + "datetime": "2018-08-05T00:00:00Z", + "label:classes": [ + { + "name": "building", + "classes": [ + "yes" + ] + } ] - } - ] - }, - "geometry": { - "coordinates": [ - [ - [ - -0.24297113100354567, - 5.639021431491198 - ], - [ - -0.23897453489157597, - 5.641691785417461 - ], - [ - -0.23850428635941076, - 5.642250323405412 - ], - [ - -0.2366780918775795, - 5.646581694873462 - ], - [ - -0.2365678982420534, - 5.647261088925513 - ], - [ - -0.23628962908589524, - 5.6470592605205 - ], - [ - -0.23574709855965523, - 5.646250384519349 - ], - [ - -0.23549999005573774, - 5.646062606522559 - ], - [ - -0.2352479883141164, - 5.645837517588297 - ], - [ - -0.2351489002506633, - 5.645826507803469 - ], - [ - -0.23489078196191707, - 5.645643011389668 - ], - [ - -0.23501342114346913, - 5.645366016963376 - ], - [ - -0.23498470193337662, - 5.645184128632788 - ], - [ - -0.23469272329743152, - 5.644748553946379 - ], - [ - -0.23452040803687635, - 5.644241181234739 - ], - [ - -0.23438159852142515, - 5.644073652509197 - ], - [ - -0.23389815848486362, - 5.643677566736666 - ], - [ - -0.23365883173408977, - 5.643060103719671 - ], - [ - -0.23308923406724827, - 5.642587433386895 - ], - [ - -0.2330078629719845, - 5.642391185451258 - ], - [ - -0.23287862652656693, - 5.641023433070588 - ], - [ - -0.2325962209606543, - 5.640494520951376 - ], - [ - -0.23233774806981916, - 5.639542000483295 - ], - [ - -0.231619767817498, - 5.638628968929094 - ], - [ - -0.2313230026465391, - 5.637736280148708 - ], - [ - -0.23095443945034647, - 5.637243267042115 - ], - [ - -0.23061459546424917, - 5.63661742758884 - ], - [ - -0.2303513360383966, - 5.635274804516999 - ], - [ - -0.23008329007752945, - 5.634768628439113 - ], - [ - -0.2294179617103787, - 5.63434741335775 - ], - [ - -0.22888186978864675, - 5.633672511920566 - ], - [ - -0.22813038379121683, - 5.632798969280243 - ], - [ - -0.22817824914137264, - 5.632402883507711 - ], - [ - -0.22802029348586056, - 5.630963333101811 - ], - [ - -0.2282117548864802, - 5.630476303163984 - ], - [ - -0.22777618020007248, - 5.630079020757702 - ], - [ - -0.2282117548864806, - 5.6293371078303025 - ], - [ - -0.22854202580254826, - 5.628882387003831 - ], - [ - -0.22852628100057304, - 5.628226174025203 - ], - [ - -0.22799593868162446, - 5.627172467575712 - ], - [ - -0.22778055649501683, - 5.626682654237342 - ], - [ - -0.2278709467984373, - 5.626501873630503 - ], - [ - -0.22845649911650084, - 5.62644673598136 - ], - [ - -0.22858210650783073, - 5.625651222502934 - ], - [ - -0.22899381962385806, - 5.62461496152446 - ], - [ - -0.22936723044334495, - 5.623408328310911 - ], - [ - -0.2292520125949269, - 5.621492222212219 - ], - [ - -0.22909151426155971, - 5.620375712067064 - ], - [ - -0.23060578114592858, - 5.620077394512653 - ], - [ - -0.23103842882717712, - 5.620844995237451 - ], - [ - -0.23218982991437007, - 5.622524994096494 - ], - [ - -0.23385761694369905, - 5.62503016373469 - ], - [ - -0.23535094926284753, - 5.627118386615555 - ], - [ - -0.24008913919135902, - 5.634579814569995 - ], - [ - -0.24297113100354567, - 5.639021431491198 - ] - ] - ], - "type": "Polygon" - }, - "bbox": [ - -0.24297113100354567, - 5.620077394512653, - -0.22777618020007248, - 5.647261088925513 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "geometry": { + "coordinates": [ + [ + [ + -0.24297113100354567, + 5.639021431491198 + ], + [ + -0.23897453489157597, + 5.641691785417461 + ], + [ + -0.23850428635941076, + 5.642250323405412 + ], + [ + -0.2366780918775795, + 5.646581694873462 + ], + [ + -0.2365678982420534, + 5.647261088925513 + ], + [ + -0.23628962908589524, + 5.6470592605205 + ], + [ + -0.23574709855965523, + 5.646250384519349 + ], + [ + -0.23549999005573774, + 5.646062606522559 + ], + [ + -0.2352479883141164, + 5.645837517588297 + ], + [ + -0.2351489002506633, + 5.645826507803469 + ], + [ + -0.23489078196191707, + 5.645643011389668 + ], + [ + -0.23501342114346913, + 5.645366016963376 + ], + [ + -0.23498470193337662, + 5.645184128632788 + ], + [ + -0.23469272329743152, + 5.644748553946379 + ], + [ + -0.23452040803687635, + 5.644241181234739 + ], + [ + -0.23438159852142515, + 5.644073652509197 + ], + [ + -0.23389815848486362, + 5.643677566736666 + ], + [ + -0.23365883173408977, + 5.643060103719671 + ], + [ + -0.23308923406724827, + 5.642587433386895 + ], + [ + -0.2330078629719845, + 5.642391185451258 + ], + [ + -0.23287862652656693, + 5.641023433070588 + ], + [ + -0.2325962209606543, + 5.640494520951376 + ], + [ + -0.23233774806981916, + 5.639542000483295 + ], + [ + -0.231619767817498, + 5.638628968929094 + ], + [ + -0.2313230026465391, + 5.637736280148708 + ], + [ + -0.23095443945034647, + 5.637243267042115 + ], + [ + -0.23061459546424917, + 5.63661742758884 + ], + [ + -0.2303513360383966, + 5.635274804516999 + ], + [ + -0.23008329007752945, + 5.634768628439113 + ], + [ + -0.2294179617103787, + 5.63434741335775 + ], + [ + -0.22888186978864675, + 5.633672511920566 + ], + [ + -0.22813038379121683, + 5.632798969280243 + ], + [ + -0.22817824914137264, + 5.632402883507711 + ], + [ + -0.22802029348586056, + 5.630963333101811 + ], + [ + -0.2282117548864802, + 5.630476303163984 + ], + [ + -0.22777618020007248, + 5.630079020757702 + ], + [ + -0.2282117548864806, + 5.6293371078303025 + ], + [ + -0.22854202580254826, + 5.628882387003831 + ], + [ + -0.22852628100057304, + 5.628226174025203 + ], + [ + -0.22799593868162446, + 5.627172467575712 + ], + [ + -0.22778055649501683, + 5.626682654237342 + ], + [ + -0.2278709467984373, + 5.626501873630503 + ], + [ + -0.22845649911650084, + 5.62644673598136 + ], + [ + -0.22858210650783073, + 5.625651222502934 + ], + [ + -0.22899381962385806, + 5.62461496152446 + ], + [ + -0.22936723044334495, + 5.623408328310911 + ], + [ + -0.2292520125949269, + 5.621492222212219 + ], + [ + -0.22909151426155971, + 5.620375712067064 + ], + [ + -0.23060578114592858, + 5.620077394512653 + ], + [ + -0.23103842882717712, + 5.620844995237451 + ], + [ + -0.23218982991437007, + 5.622524994096494 + ], + [ + -0.23385761694369905, + 5.62503016373469 + ], + [ + -0.23535094926284753, + 5.627118386615555 + ], + [ + -0.24008913919135902, + 5.634579814569995 + ], + [ + -0.24297113100354567, + 5.639021431491198 + ] + ] + ], + "type": "Polygon" }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "labels": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/acc/665946-labels/665946.geojson", - "type": "application/geo+json" - } - }, - "stac_extensions": [ - "label" - ] + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "labels": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/acc/665946-labels/665946.geojson", + "type": "application/geo+json" + } + }, + "bbox": [ + -0.24297113100354567, + 5.620077394512653, + -0.22777618020007248, + 5.647261088925513 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "acc" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/acc/665946/665946.json b/tests/data-files/catalogs/test-case-4/acc/665946/665946.json index 6cc411832..bd4c9dd4f 100644 --- a/tests/data-files/catalogs/test-case-4/acc/665946/665946.json +++ b/tests/data-files/catalogs/test-case-4/acc/665946/665946.json @@ -1,268 +1,269 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "665946", - "properties": { - "area": "acc", - "license": "CC-BY-4.0", - "datetime": "2018-08-05T00:00:00Z" - }, - "geometry": { - "coordinates": [ - [ - [ - -0.24297113100354567, - 5.639021431491198 - ], - [ - -0.23897453489157597, - 5.641691785417461 - ], - [ - -0.23850428635941076, - 5.642250323405412 - ], - [ - -0.2366780918775795, - 5.646581694873462 - ], - [ - -0.2365678982420534, - 5.647261088925513 - ], - [ - -0.23628962908589524, - 5.6470592605205 - ], - [ - -0.23574709855965523, - 5.646250384519349 - ], - [ - -0.23549999005573774, - 5.646062606522559 - ], - [ - -0.2352479883141164, - 5.645837517588297 - ], - [ - -0.2351489002506633, - 5.645826507803469 - ], - [ - -0.23489078196191707, - 5.645643011389668 - ], - [ - -0.23501342114346913, - 5.645366016963376 - ], - [ - -0.23498470193337662, - 5.645184128632788 - ], - [ - -0.23469272329743152, - 5.644748553946379 - ], - [ - -0.23452040803687635, - 5.644241181234739 - ], - [ - -0.23438159852142515, - 5.644073652509197 - ], - [ - -0.23389815848486362, - 5.643677566736666 - ], - [ - -0.23365883173408977, - 5.643060103719671 - ], - [ - -0.23308923406724827, - 5.642587433386895 - ], - [ - -0.2330078629719845, - 5.642391185451258 - ], - [ - -0.23287862652656693, - 5.641023433070588 - ], - [ - -0.2325962209606543, - 5.640494520951376 - ], - [ - -0.23233774806981916, - 5.639542000483295 - ], - [ - -0.231619767817498, - 5.638628968929094 - ], - [ - -0.2313230026465391, - 5.637736280148708 - ], - [ - -0.23095443945034647, - 5.637243267042115 - ], - [ - -0.23061459546424917, - 5.63661742758884 - ], - [ - -0.2303513360383966, - 5.635274804516999 - ], - [ - -0.23008329007752945, - 5.634768628439113 - ], - [ - -0.2294179617103787, - 5.63434741335775 - ], - [ - -0.22888186978864675, - 5.633672511920566 - ], - [ - -0.22813038379121683, - 5.632798969280243 - ], - [ - -0.22817824914137264, - 5.632402883507711 - ], - [ - -0.22802029348586056, - 5.630963333101811 - ], - [ - -0.2282117548864802, - 5.630476303163984 - ], - [ - -0.22777618020007248, - 5.630079020757702 - ], - [ - -0.2282117548864806, - 5.6293371078303025 - ], - [ - -0.22854202580254826, - 5.628882387003831 - ], - [ - -0.22852628100057304, - 5.628226174025203 - ], - [ - -0.22799593868162446, - 5.627172467575712 - ], - [ - -0.22778055649501683, - 5.626682654237342 - ], - [ - -0.2278709467984373, - 5.626501873630503 - ], - [ - -0.22845649911650084, - 5.62644673598136 - ], - [ - -0.22858210650783073, - 5.625651222502934 - ], - [ - -0.22899381962385806, - 5.62461496152446 - ], - [ - -0.22936723044334495, - 5.623408328310911 - ], - [ - -0.2292520125949269, - 5.621492222212219 - ], - [ - -0.22909151426155971, - 5.620375712067064 - ], - [ - -0.23060578114592858, - 5.620077394512653 - ], - [ - -0.23103842882717712, - 5.620844995237451 - ], - [ - -0.23218982991437007, - 5.622524994096494 - ], - [ - -0.23385761694369905, - 5.62503016373469 - ], - [ - -0.23535094926284753, - 5.627118386615555 - ], - [ - -0.24008913919135902, - 5.634579814569995 - ], - [ - -0.24297113100354567, - 5.639021431491198 - ] - ] - ], - "type": "Polygon" - }, - "bbox": [ - -0.24297113100354567, - 5.620077394512653, - -0.22777618020007248, - 5.647261088925513 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "665946", + "properties": { + "area": "acc", + "license": "CC-BY-4.0", + "datetime": "2018-08-05T00:00:00Z" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "geometry": { + "coordinates": [ + [ + [ + -0.24297113100354567, + 5.639021431491198 + ], + [ + -0.23897453489157597, + 5.641691785417461 + ], + [ + -0.23850428635941076, + 5.642250323405412 + ], + [ + -0.2366780918775795, + 5.646581694873462 + ], + [ + -0.2365678982420534, + 5.647261088925513 + ], + [ + -0.23628962908589524, + 5.6470592605205 + ], + [ + -0.23574709855965523, + 5.646250384519349 + ], + [ + -0.23549999005573774, + 5.646062606522559 + ], + [ + -0.2352479883141164, + 5.645837517588297 + ], + [ + -0.2351489002506633, + 5.645826507803469 + ], + [ + -0.23489078196191707, + 5.645643011389668 + ], + [ + -0.23501342114346913, + 5.645366016963376 + ], + [ + -0.23498470193337662, + 5.645184128632788 + ], + [ + -0.23469272329743152, + 5.644748553946379 + ], + [ + -0.23452040803687635, + 5.644241181234739 + ], + [ + -0.23438159852142515, + 5.644073652509197 + ], + [ + -0.23389815848486362, + 5.643677566736666 + ], + [ + -0.23365883173408977, + 5.643060103719671 + ], + [ + -0.23308923406724827, + 5.642587433386895 + ], + [ + -0.2330078629719845, + 5.642391185451258 + ], + [ + -0.23287862652656693, + 5.641023433070588 + ], + [ + -0.2325962209606543, + 5.640494520951376 + ], + [ + -0.23233774806981916, + 5.639542000483295 + ], + [ + -0.231619767817498, + 5.638628968929094 + ], + [ + -0.2313230026465391, + 5.637736280148708 + ], + [ + -0.23095443945034647, + 5.637243267042115 + ], + [ + -0.23061459546424917, + 5.63661742758884 + ], + [ + -0.2303513360383966, + 5.635274804516999 + ], + [ + -0.23008329007752945, + 5.634768628439113 + ], + [ + -0.2294179617103787, + 5.63434741335775 + ], + [ + -0.22888186978864675, + 5.633672511920566 + ], + [ + -0.22813038379121683, + 5.632798969280243 + ], + [ + -0.22817824914137264, + 5.632402883507711 + ], + [ + -0.22802029348586056, + 5.630963333101811 + ], + [ + -0.2282117548864802, + 5.630476303163984 + ], + [ + -0.22777618020007248, + 5.630079020757702 + ], + [ + -0.2282117548864806, + 5.6293371078303025 + ], + [ + -0.22854202580254826, + 5.628882387003831 + ], + [ + -0.22852628100057304, + 5.628226174025203 + ], + [ + -0.22799593868162446, + 5.627172467575712 + ], + [ + -0.22778055649501683, + 5.626682654237342 + ], + [ + -0.2278709467984373, + 5.626501873630503 + ], + [ + -0.22845649911650084, + 5.62644673598136 + ], + [ + -0.22858210650783073, + 5.625651222502934 + ], + [ + -0.22899381962385806, + 5.62461496152446 + ], + [ + -0.22936723044334495, + 5.623408328310911 + ], + [ + -0.2292520125949269, + 5.621492222212219 + ], + [ + -0.22909151426155971, + 5.620375712067064 + ], + [ + -0.23060578114592858, + 5.620077394512653 + ], + [ + -0.23103842882717712, + 5.620844995237451 + ], + [ + -0.23218982991437007, + 5.622524994096494 + ], + [ + -0.23385761694369905, + 5.62503016373469 + ], + [ + -0.23535094926284753, + 5.627118386615555 + ], + [ + -0.24008913919135902, + 5.634579814569995 + ], + [ + -0.24297113100354567, + 5.639021431491198 + ] + ] + ], + "type": "Polygon" }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "image": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/acc/665946/665946.tif", - "type": "image/tiff; application=geotiff; profile=cloud-optimized", - "title": "GeoTIFF" - } - }, - "collection": "acc" + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "image": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/acc/665946/665946.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "GeoTIFF" + } + }, + "bbox": [ + -0.24297113100354567, + 5.620077394512653, + -0.22777618020007248, + 5.647261088925513 + ], + "stac_extensions": [], + "collection": "acc" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/acc/a42435-labels/a42435-labels.json b/tests/data-files/catalogs/test-case-4/acc/a42435-labels/a42435-labels.json index 955df0cd7..52a1042e2 100644 --- a/tests/data-files/catalogs/test-case-4/acc/a42435-labels/a42435-labels.json +++ b/tests/data-files/catalogs/test-case-4/acc/a42435-labels/a42435-labels.json @@ -1,209 +1,210 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "a42435-labels", - "properties": { - "label:description": "Geojson building labels for scene a42435", - "area": "acc", - "label:type": "vector", - "label:properties": [ - "building" - ], - "label:overviews": [ - { - "property_key": "building", - "counts": [ - { - "name": "yes", - "count": 6647 - } - ] - } - ], - "license": "ODbL-1.0", - "datetime": "2018-10-06T00:00:00Z", - "label:classes": [ - { - "name": "building", - "classes": [ - "yes" - ] - } - ] - }, - "geometry": { - "coordinates": [ - [ - [ - -0.2498678517428029, - 5.617970541565606 - ], - [ - -0.2483206321371833, - 5.618380099696508 - ], - [ - -0.24612982118300658, - 5.61867914214129 - ], - [ - -0.2449076477130216, - 5.618425606155497 - ], - [ - -0.24292486628565255, - 5.618295587701242 - ], - [ - -0.24057803318637266, - 5.61884816613182 - ], - [ - -0.23918683572585742, - 5.618893672590809 - ], - [ - -0.23845873238203655, - 5.619088700272191 - ], - [ - -0.2367164850950368, - 5.619166711344742 - ], - [ - -0.2367164850950352, - 5.6187116467548535 - ], - [ - -0.23648895280009183, - 5.617144924381095 - ], - [ - -0.23618991035530826, - 5.61604951890401 - ], - [ - -0.23606639282376832, - 5.615178395260507 - ], - [ - -0.2358128568379735, - 5.6150613786516805 - ], - [ - -0.23484421935378336, - 5.614905356506578 - ], - [ - -0.23409011231911103, - 5.614809467896564 - ], - [ - -0.23370005695634877, - 5.614633942983321 - ], - [ - -0.23344002004784176, - 5.614284518387513 - ], - [ - -0.23326449513459932, - 5.613874960256616 - ], - [ - -0.2332904988254504, - 5.612933951693955 - ], - [ - -0.23357958657882866, - 5.610610569931325 - ], - [ - -0.23818182071090357, - 5.609166251772857 - ], - [ - -0.23942120427966462, - 5.608949984373012 - ], - [ - -0.24480177379675747, - 5.608165317985103 - ], - [ - -0.24616292977578505, - 5.607877073189545 - ], - [ - -0.2453887159937594, - 5.610507482291447 - ], - [ - -0.24500926881889307, - 5.612188394844965 - ], - [ - -0.244985658785574, - 5.612914448925815 - ], - [ - -0.24537571414833664, - 5.614219509160388 - ], - [ - -0.2465653830047576, - 5.614698952210449 - ], - [ - -0.24663689315459741, - 5.615028874038114 - ], - [ - -0.24762503340692765, - 5.615730973691088 - ], - [ - -0.24860017181382998, - 5.616101526285711 - ], - [ - -0.2498678517428029, - 5.617970541565606 + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "a42435-labels", + "properties": { + "label:description": "Geojson building labels for scene a42435", + "area": "acc", + "label:type": "vector", + "label:properties": [ + "building" + ], + "label:overviews": [ + { + "property_key": "building", + "counts": [ + { + "name": "yes", + "count": 6647 + } + ] + } + ], + "license": "ODbL-1.0", + "datetime": "2018-10-06T00:00:00Z", + "label:classes": [ + { + "name": "building", + "classes": [ + "yes" + ] + } ] - ] - ], - "type": "Polygon" - }, - "bbox": [ - -0.2498678517428029, - 5.607877073189545, - -0.23326449513459932, - 5.619166711344742 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "geometry": { + "coordinates": [ + [ + [ + -0.2498678517428029, + 5.617970541565606 + ], + [ + -0.2483206321371833, + 5.618380099696508 + ], + [ + -0.24612982118300658, + 5.61867914214129 + ], + [ + -0.2449076477130216, + 5.618425606155497 + ], + [ + -0.24292486628565255, + 5.618295587701242 + ], + [ + -0.24057803318637266, + 5.61884816613182 + ], + [ + -0.23918683572585742, + 5.618893672590809 + ], + [ + -0.23845873238203655, + 5.619088700272191 + ], + [ + -0.2367164850950368, + 5.619166711344742 + ], + [ + -0.2367164850950352, + 5.6187116467548535 + ], + [ + -0.23648895280009183, + 5.617144924381095 + ], + [ + -0.23618991035530826, + 5.61604951890401 + ], + [ + -0.23606639282376832, + 5.615178395260507 + ], + [ + -0.2358128568379735, + 5.6150613786516805 + ], + [ + -0.23484421935378336, + 5.614905356506578 + ], + [ + -0.23409011231911103, + 5.614809467896564 + ], + [ + -0.23370005695634877, + 5.614633942983321 + ], + [ + -0.23344002004784176, + 5.614284518387513 + ], + [ + -0.23326449513459932, + 5.613874960256616 + ], + [ + -0.2332904988254504, + 5.612933951693955 + ], + [ + -0.23357958657882866, + 5.610610569931325 + ], + [ + -0.23818182071090357, + 5.609166251772857 + ], + [ + -0.23942120427966462, + 5.608949984373012 + ], + [ + -0.24480177379675747, + 5.608165317985103 + ], + [ + -0.24616292977578505, + 5.607877073189545 + ], + [ + -0.2453887159937594, + 5.610507482291447 + ], + [ + -0.24500926881889307, + 5.612188394844965 + ], + [ + -0.244985658785574, + 5.612914448925815 + ], + [ + -0.24537571414833664, + 5.614219509160388 + ], + [ + -0.2465653830047576, + 5.614698952210449 + ], + [ + -0.24663689315459741, + 5.615028874038114 + ], + [ + -0.24762503340692765, + 5.615730973691088 + ], + [ + -0.24860017181382998, + 5.616101526285711 + ], + [ + -0.2498678517428029, + 5.617970541565606 + ] + ] + ], + "type": "Polygon" + }, + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "labels": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/acc/a42435-labels/a42435.geojson", + "type": "application/geo+json" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "labels": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/acc/a42435-labels/a42435.geojson", - "type": "application/geo+json" - } - }, - "stac_extensions": [ - "label" - ] + "bbox": [ + -0.2498678517428029, + 5.607877073189545, + -0.23326449513459932, + 5.619166711344742 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "acc" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/acc/a42435/a42435.json b/tests/data-files/catalogs/test-case-4/acc/a42435/a42435.json index 684a405c7..df352a839 100644 --- a/tests/data-files/catalogs/test-case-4/acc/a42435/a42435.json +++ b/tests/data-files/catalogs/test-case-4/acc/a42435/a42435.json @@ -1,184 +1,185 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "a42435", - "properties": { - "area": "acc", - "license": "CC-BY-4.0", - "datetime": "2018-10-06T00:00:00Z" - }, - "geometry": { - "coordinates": [ - [ - [ - -0.2498678517428029, - 5.617970541565606 - ], - [ - -0.2483206321371833, - 5.618380099696508 - ], - [ - -0.24612982118300658, - 5.61867914214129 - ], - [ - -0.2449076477130216, - 5.618425606155497 - ], - [ - -0.24292486628565255, - 5.618295587701242 - ], - [ - -0.24057803318637266, - 5.61884816613182 - ], - [ - -0.23918683572585742, - 5.618893672590809 - ], - [ - -0.23845873238203655, - 5.619088700272191 - ], - [ - -0.2367164850950368, - 5.619166711344742 - ], - [ - -0.2367164850950352, - 5.6187116467548535 - ], - [ - -0.23648895280009183, - 5.617144924381095 - ], - [ - -0.23618991035530826, - 5.61604951890401 - ], - [ - -0.23606639282376832, - 5.615178395260507 - ], - [ - -0.2358128568379735, - 5.6150613786516805 - ], - [ - -0.23484421935378336, - 5.614905356506578 - ], - [ - -0.23409011231911103, - 5.614809467896564 - ], - [ - -0.23370005695634877, - 5.614633942983321 - ], - [ - -0.23344002004784176, - 5.614284518387513 - ], - [ - -0.23326449513459932, - 5.613874960256616 - ], - [ - -0.2332904988254504, - 5.612933951693955 - ], - [ - -0.23357958657882866, - 5.610610569931325 - ], - [ - -0.23818182071090357, - 5.609166251772857 - ], - [ - -0.23942120427966462, - 5.608949984373012 - ], - [ - -0.24480177379675747, - 5.608165317985103 - ], - [ - -0.24616292977578505, - 5.607877073189545 - ], - [ - -0.2453887159937594, - 5.610507482291447 - ], - [ - -0.24500926881889307, - 5.612188394844965 - ], - [ - -0.244985658785574, - 5.612914448925815 - ], - [ - -0.24537571414833664, - 5.614219509160388 - ], - [ - -0.2465653830047576, - 5.614698952210449 - ], - [ - -0.24663689315459741, - 5.615028874038114 - ], - [ - -0.24762503340692765, - 5.615730973691088 - ], - [ - -0.24860017181382998, - 5.616101526285711 - ], - [ - -0.2498678517428029, - 5.617970541565606 - ] - ] - ], - "type": "Polygon" - }, - "bbox": [ - -0.2498678517428029, - 5.607877073189545, - -0.23326449513459932, - 5.619166711344742 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "a42435", + "properties": { + "area": "acc", + "license": "CC-BY-4.0", + "datetime": "2018-10-06T00:00:00Z" + }, + "geometry": { + "coordinates": [ + [ + [ + -0.2498678517428029, + 5.617970541565606 + ], + [ + -0.2483206321371833, + 5.618380099696508 + ], + [ + -0.24612982118300658, + 5.61867914214129 + ], + [ + -0.2449076477130216, + 5.618425606155497 + ], + [ + -0.24292486628565255, + 5.618295587701242 + ], + [ + -0.24057803318637266, + 5.61884816613182 + ], + [ + -0.23918683572585742, + 5.618893672590809 + ], + [ + -0.23845873238203655, + 5.619088700272191 + ], + [ + -0.2367164850950368, + 5.619166711344742 + ], + [ + -0.2367164850950352, + 5.6187116467548535 + ], + [ + -0.23648895280009183, + 5.617144924381095 + ], + [ + -0.23618991035530826, + 5.61604951890401 + ], + [ + -0.23606639282376832, + 5.615178395260507 + ], + [ + -0.2358128568379735, + 5.6150613786516805 + ], + [ + -0.23484421935378336, + 5.614905356506578 + ], + [ + -0.23409011231911103, + 5.614809467896564 + ], + [ + -0.23370005695634877, + 5.614633942983321 + ], + [ + -0.23344002004784176, + 5.614284518387513 + ], + [ + -0.23326449513459932, + 5.613874960256616 + ], + [ + -0.2332904988254504, + 5.612933951693955 + ], + [ + -0.23357958657882866, + 5.610610569931325 + ], + [ + -0.23818182071090357, + 5.609166251772857 + ], + [ + -0.23942120427966462, + 5.608949984373012 + ], + [ + -0.24480177379675747, + 5.608165317985103 + ], + [ + -0.24616292977578505, + 5.607877073189545 + ], + [ + -0.2453887159937594, + 5.610507482291447 + ], + [ + -0.24500926881889307, + 5.612188394844965 + ], + [ + -0.244985658785574, + 5.612914448925815 + ], + [ + -0.24537571414833664, + 5.614219509160388 + ], + [ + -0.2465653830047576, + 5.614698952210449 + ], + [ + -0.24663689315459741, + 5.615028874038114 + ], + [ + -0.24762503340692765, + 5.615730973691088 + ], + [ + -0.24860017181382998, + 5.616101526285711 + ], + [ + -0.2498678517428029, + 5.617970541565606 + ] + ] + ], + "type": "Polygon" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "image": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/acc/a42435/a42435.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "GeoTIFF" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "image": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/acc/a42435/a42435.tif", - "type": "image/tiff; application=geotiff; profile=cloud-optimized", - "title": "GeoTIFF" - } - }, - "collection": "acc" + "bbox": [ + -0.2498678517428029, + 5.607877073189545, + -0.23326449513459932, + 5.619166711344742 + ], + "stac_extensions": [], + "collection": "acc" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/acc/ca041a-labels/ca041a-labels.json b/tests/data-files/catalogs/test-case-4/acc/ca041a-labels/ca041a-labels.json index ff8bd2dcb..41b4279a4 100644 --- a/tests/data-files/catalogs/test-case-4/acc/ca041a-labels/ca041a-labels.json +++ b/tests/data-files/catalogs/test-case-4/acc/ca041a-labels/ca041a-labels.json @@ -1,205 +1,206 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "ca041a-labels", - "properties": { - "label:description": "Geojson building labels for scene ca041a", - "area": "acc", - "label:type": "vector", - "label:properties": [ - "building" - ], - "label:overviews": [ - { - "property_key": "building", - "counts": [ - { - "name": "yes", - "count": 10194 - } - ] - } - ], - "license": "ODbL-1.0", - "datetime": "2018-11-12T00:00:00Z", - "label:classes": [ - { - "name": "building", - "classes": [ - "yes" + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "ca041a-labels", + "properties": { + "label:description": "Geojson building labels for scene ca041a", + "area": "acc", + "label:type": "vector", + "label:properties": [ + "building" + ], + "label:overviews": [ + { + "property_key": "building", + "counts": [ + { + "name": "yes", + "count": 10194 + } + ] + } + ], + "license": "ODbL-1.0", + "datetime": "2018-11-12T00:00:00Z", + "label:classes": [ + { + "name": "building", + "classes": [ + "yes" + ] + } ] - } - ] - }, - "geometry": { - "coordinates": [ - [ - [ - -0.2260939759101167, - 5.607821019807083 - ], - [ - -0.22707525357332697, - 5.609567361411101 - ], - [ - -0.2257626190986551, - 5.610742610987594 - ], - [ - -0.2209214783972656, - 5.60396659440964 - ], - [ - -0.2209297943096631, - 5.603475955578037 - ], - [ - -0.21938590601191368, - 5.601711342600872 - ], - [ - -0.21863322644066166, - 5.601370284670147 - ], - [ - -0.2171984310079642, - 5.60126443910544 - ], - [ - -0.2150344772406196, - 5.602172946869177 - ], - [ - -0.21221192884842804, - 5.603687126475405 - ], - [ - -0.2071666235973881, - 5.60628622311988 - ], - [ - -0.20581415249279408, - 5.604666197948947 - ], - [ - -0.2074253572000044, - 5.603584221065274 - ], - [ - -0.2083544460457665, - 5.6019965375946645 - ], - [ - -0.20906008314381597, - 5.600996885039098 - ], - [ - -0.21070656970592522, - 5.599526807751497 - ], - [ - -0.2114122068039735, - 5.597897962116837 - ], - [ - -0.212416616071534, - 5.595984932725826 - ], - [ - -0.2138692108714978, - 5.593295072530488 - ], - [ - -0.21395275670010877, - 5.593002662130355 - ], - [ - -0.21397782044869207, - 5.590391854986293 - ], - [ - -0.2141449121059085, - 5.590032607923272 - ], - [ - -0.21550670911225214, - 5.588150738133833 - ], - [ - -0.21721104401589492, - 5.585527399115482 - ], - [ - -0.21795907856051402, - 5.590627248068187 - ], - [ - -0.21855973661963968, - 5.59108215821591 - ], - [ - -0.2203440443835102, - 5.593219794249854 - ], - [ - -0.22225201704190803, - 5.59588742268891 - ], - [ - -0.2234356667466541, - 5.598325387752418 - ], - [ - -0.22523764092403067, - 5.601536258406711 - ], - [ - -0.22571463408862905, - 5.6031880680693025 - ], - [ - -0.2259010426101557, - 5.606526622234949 - ], - [ - -0.2260939759101167, - 5.607821019807083 - ] - ] - ], - "type": "Polygon" - }, - "bbox": [ - -0.22707525357332697, - 5.585527399115482, - -0.20581415249279408, - 5.610742610987594 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "geometry": { + "coordinates": [ + [ + [ + -0.2260939759101167, + 5.607821019807083 + ], + [ + -0.22707525357332697, + 5.609567361411101 + ], + [ + -0.2257626190986551, + 5.610742610987594 + ], + [ + -0.2209214783972656, + 5.60396659440964 + ], + [ + -0.2209297943096631, + 5.603475955578037 + ], + [ + -0.21938590601191368, + 5.601711342600872 + ], + [ + -0.21863322644066166, + 5.601370284670147 + ], + [ + -0.2171984310079642, + 5.60126443910544 + ], + [ + -0.2150344772406196, + 5.602172946869177 + ], + [ + -0.21221192884842804, + 5.603687126475405 + ], + [ + -0.2071666235973881, + 5.60628622311988 + ], + [ + -0.20581415249279408, + 5.604666197948947 + ], + [ + -0.2074253572000044, + 5.603584221065274 + ], + [ + -0.2083544460457665, + 5.6019965375946645 + ], + [ + -0.20906008314381597, + 5.600996885039098 + ], + [ + -0.21070656970592522, + 5.599526807751497 + ], + [ + -0.2114122068039735, + 5.597897962116837 + ], + [ + -0.212416616071534, + 5.595984932725826 + ], + [ + -0.2138692108714978, + 5.593295072530488 + ], + [ + -0.21395275670010877, + 5.593002662130355 + ], + [ + -0.21397782044869207, + 5.590391854986293 + ], + [ + -0.2141449121059085, + 5.590032607923272 + ], + [ + -0.21550670911225214, + 5.588150738133833 + ], + [ + -0.21721104401589492, + 5.585527399115482 + ], + [ + -0.21795907856051402, + 5.590627248068187 + ], + [ + -0.21855973661963968, + 5.59108215821591 + ], + [ + -0.2203440443835102, + 5.593219794249854 + ], + [ + -0.22225201704190803, + 5.59588742268891 + ], + [ + -0.2234356667466541, + 5.598325387752418 + ], + [ + -0.22523764092403067, + 5.601536258406711 + ], + [ + -0.22571463408862905, + 5.6031880680693025 + ], + [ + -0.2259010426101557, + 5.606526622234949 + ], + [ + -0.2260939759101167, + 5.607821019807083 + ] + ] + ], + "type": "Polygon" + }, + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "labels": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/acc/ca041a-labels/ca041a.geojson", + "type": "application/geo+json" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "labels": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/acc/ca041a-labels/ca041a.geojson", - "type": "application/geo+json" - } - }, - "stac_extensions": [ - "label" - ] + "bbox": [ + -0.22707525357332697, + 5.585527399115482, + -0.20581415249279408, + 5.610742610987594 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "acc" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/acc/ca041a/ca041a.json b/tests/data-files/catalogs/test-case-4/acc/ca041a/ca041a.json index 1f0870f42..d2abc4c05 100644 --- a/tests/data-files/catalogs/test-case-4/acc/ca041a/ca041a.json +++ b/tests/data-files/catalogs/test-case-4/acc/ca041a/ca041a.json @@ -1,180 +1,181 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "ca041a", - "properties": { - "area": "acc", - "license": "CC-BY-4.0", - "datetime": "2018-11-12T00:00:00Z" - }, - "geometry": { - "coordinates": [ - [ - [ - -0.2260939759101167, - 5.607821019807083 - ], - [ - -0.22707525357332697, - 5.609567361411101 - ], - [ - -0.2257626190986551, - 5.610742610987594 - ], - [ - -0.2209214783972656, - 5.60396659440964 - ], - [ - -0.2209297943096631, - 5.603475955578037 - ], - [ - -0.21938590601191368, - 5.601711342600872 - ], - [ - -0.21863322644066166, - 5.601370284670147 - ], - [ - -0.2171984310079642, - 5.60126443910544 - ], - [ - -0.2150344772406196, - 5.602172946869177 - ], - [ - -0.21221192884842804, - 5.603687126475405 - ], - [ - -0.2071666235973881, - 5.60628622311988 - ], - [ - -0.20581415249279408, - 5.604666197948947 - ], - [ - -0.2074253572000044, - 5.603584221065274 - ], - [ - -0.2083544460457665, - 5.6019965375946645 - ], - [ - -0.20906008314381597, - 5.600996885039098 - ], - [ - -0.21070656970592522, - 5.599526807751497 - ], - [ - -0.2114122068039735, - 5.597897962116837 - ], - [ - -0.212416616071534, - 5.595984932725826 - ], - [ - -0.2138692108714978, - 5.593295072530488 - ], - [ - -0.21395275670010877, - 5.593002662130355 - ], - [ - -0.21397782044869207, - 5.590391854986293 - ], - [ - -0.2141449121059085, - 5.590032607923272 - ], - [ - -0.21550670911225214, - 5.588150738133833 - ], - [ - -0.21721104401589492, - 5.585527399115482 - ], - [ - -0.21795907856051402, - 5.590627248068187 - ], - [ - -0.21855973661963968, - 5.59108215821591 - ], - [ - -0.2203440443835102, - 5.593219794249854 - ], - [ - -0.22225201704190803, - 5.59588742268891 - ], - [ - -0.2234356667466541, - 5.598325387752418 - ], - [ - -0.22523764092403067, - 5.601536258406711 - ], - [ - -0.22571463408862905, - 5.6031880680693025 - ], - [ - -0.2259010426101557, - 5.606526622234949 - ], - [ - -0.2260939759101167, - 5.607821019807083 - ] - ] - ], - "type": "Polygon" - }, - "bbox": [ - -0.22707525357332697, - 5.585527399115482, - -0.20581415249279408, - 5.610742610987594 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "ca041a", + "properties": { + "area": "acc", + "license": "CC-BY-4.0", + "datetime": "2018-11-12T00:00:00Z" + }, + "geometry": { + "coordinates": [ + [ + [ + -0.2260939759101167, + 5.607821019807083 + ], + [ + -0.22707525357332697, + 5.609567361411101 + ], + [ + -0.2257626190986551, + 5.610742610987594 + ], + [ + -0.2209214783972656, + 5.60396659440964 + ], + [ + -0.2209297943096631, + 5.603475955578037 + ], + [ + -0.21938590601191368, + 5.601711342600872 + ], + [ + -0.21863322644066166, + 5.601370284670147 + ], + [ + -0.2171984310079642, + 5.60126443910544 + ], + [ + -0.2150344772406196, + 5.602172946869177 + ], + [ + -0.21221192884842804, + 5.603687126475405 + ], + [ + -0.2071666235973881, + 5.60628622311988 + ], + [ + -0.20581415249279408, + 5.604666197948947 + ], + [ + -0.2074253572000044, + 5.603584221065274 + ], + [ + -0.2083544460457665, + 5.6019965375946645 + ], + [ + -0.20906008314381597, + 5.600996885039098 + ], + [ + -0.21070656970592522, + 5.599526807751497 + ], + [ + -0.2114122068039735, + 5.597897962116837 + ], + [ + -0.212416616071534, + 5.595984932725826 + ], + [ + -0.2138692108714978, + 5.593295072530488 + ], + [ + -0.21395275670010877, + 5.593002662130355 + ], + [ + -0.21397782044869207, + 5.590391854986293 + ], + [ + -0.2141449121059085, + 5.590032607923272 + ], + [ + -0.21550670911225214, + 5.588150738133833 + ], + [ + -0.21721104401589492, + 5.585527399115482 + ], + [ + -0.21795907856051402, + 5.590627248068187 + ], + [ + -0.21855973661963968, + 5.59108215821591 + ], + [ + -0.2203440443835102, + 5.593219794249854 + ], + [ + -0.22225201704190803, + 5.59588742268891 + ], + [ + -0.2234356667466541, + 5.598325387752418 + ], + [ + -0.22523764092403067, + 5.601536258406711 + ], + [ + -0.22571463408862905, + 5.6031880680693025 + ], + [ + -0.2259010426101557, + 5.606526622234949 + ], + [ + -0.2260939759101167, + 5.607821019807083 + ] + ] + ], + "type": "Polygon" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "image": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/acc/ca041a/ca041a.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "GeoTIFF" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "image": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/acc/ca041a/ca041a.tif", - "type": "image/tiff; application=geotiff; profile=cloud-optimized", - "title": "GeoTIFF" - } - }, - "collection": "acc" + "bbox": [ + -0.22707525357332697, + 5.585527399115482, + -0.20581415249279408, + 5.610742610987594 + ], + "stac_extensions": [], + "collection": "acc" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/acc/collection.json b/tests/data-files/catalogs/test-case-4/acc/collection.json index f9ab1e736..8c720cd37 100644 --- a/tests/data-files/catalogs/test-case-4/acc/collection.json +++ b/tests/data-files/catalogs/test-case-4/acc/collection.json @@ -1,6 +1,7 @@ { + "type": "Collection", "id": "acc", - "stac_version": "1.0.0-beta.2", + "stac_version": "1.0.0-rc.3", "description": "Tier 1 training data from acc", "links": [ { @@ -54,6 +55,7 @@ "type": "application/json" } ], + "stac_extensions": [], "extent": { "spatial": { "bbox": [ @@ -74,8 +76,5 @@ ] } }, - "license": "various", - "stac_extensions": [ - "label" - ] + "license": "various" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/acc/d41d81-labels/d41d81-labels.json b/tests/data-files/catalogs/test-case-4/acc/d41d81-labels/d41d81-labels.json index 842a98353..799c1d6b0 100644 --- a/tests/data-files/catalogs/test-case-4/acc/d41d81-labels/d41d81-labels.json +++ b/tests/data-files/catalogs/test-case-4/acc/d41d81-labels/d41d81-labels.json @@ -1,237 +1,238 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "d41d81-labels", - "properties": { - "label:description": "Geojson building labels for scene d41d81", - "area": "acc", - "label:type": "vector", - "label:properties": [ - "building" - ], - "label:overviews": [ - { - "property_key": "building", - "counts": [ - { - "name": "yes", - "count": 9436 - } - ] - } - ], - "license": "ODbL-1.0", - "datetime": "2019-07-07T00:00:00Z", - "label:classes": [ - { - "name": "building", - "classes": [ - "yes" + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "d41d81-labels", + "properties": { + "label:description": "Geojson building labels for scene d41d81", + "area": "acc", + "label:type": "vector", + "label:properties": [ + "building" + ], + "label:overviews": [ + { + "property_key": "building", + "counts": [ + { + "name": "yes", + "count": 9436 + } + ] + } + ], + "license": "ODbL-1.0", + "datetime": "2019-07-07T00:00:00Z", + "label:classes": [ + { + "name": "building", + "classes": [ + "yes" + ] + } ] - } - ] - }, - "geometry": { - "coordinates": [ - [ - [ - -0.20863145179911316, - 5.582119462388951 - ], - [ - -0.20385702387126087, - 5.579536961528113 - ], - [ - -0.2009950607269171, - 5.577949413736869 - ], - [ - -0.20077283770629886, - 5.577641331821918 - ], - [ - -0.20073243352073175, - 5.573262528211078 - ], - [ - -0.19864488393309448, - 5.573787782623451 - ], - [ - -0.19734521596401766, - 5.57635681542243 - ], - [ - -0.1960320799330845, - 5.578885444035844 - ], - [ - -0.19481995436606828, - 5.58174404016472 - ], - [ - -0.193715573293899, - 5.5842996049018465 - ], - [ - -0.1928132131495656, - 5.586195234608039 - ], - [ - -0.19234183098461477, - 5.587727226644127 - ], - [ - -0.19077280177842343, - 5.590675048682799 - ], - [ - -0.18995125000522423, - 5.5918703391724955 - ], - [ - -0.18948660187120017, - 5.593203677296213 - ], - [ - -0.1896814210311117, - 5.593146040802338 - ], - [ - -0.19064648860775885, - 5.592399387837963 - ], - [ - -0.19145578395016197, - 5.591683735622175 - ], - [ - -0.191767472021221, - 5.591533359798418 - ], - [ - -0.19283650742283956, - 5.590449970340895 - ], - [ - -0.19318542830603494, - 5.590043519585699 - ], - [ - -0.193702305535994, - 5.589716881891764 - ], - [ - -0.19418464068091668, - 5.589560941307724 - ], - [ - -0.19516869974401801, - 5.589357695039237 - ], - [ - -0.1953956305325968, - 5.589357695039239 - ], - [ - -0.1961839592598401, - 5.5896504069411765 - ], - [ - -0.1965797482249876, - 5.588349850542593 - ], - [ - -0.19764163737530274, - 5.5883155603721155 - ], - [ - -0.19867982389932817, - 5.587968505169294 - ], - [ - -0.19978796845742514, - 5.5877988416473 - ], - [ - -0.20026909700296197, - 5.588264378064047 - ], - [ - -0.2011782799777639, - 5.588967803092853 - ], - [ - -0.20205926441255548, - 5.5896240281790135 - ], - [ - -0.20252257279431515, - 5.589941270993319 - ], - [ - -0.20519554383017538, - 5.592316146871745 - ], - [ - -0.20705628845757923, - 5.590243111157246 - ], - [ - -0.20726746402099225, - 5.589590166024398 - ], - [ - -0.2075150491643001, - 5.587866779242541 - ], - [ - -0.20796945601763953, - 5.5852380825945485 - ], - [ - -0.2084801191101917, - 5.582507241723167 - ], - [ - -0.20863145179911316, - 5.582119462388951 - ] - ] - ], - "type": "Polygon" - }, - "bbox": [ - -0.20863145179911316, - 5.573262528211078, - -0.18948660187120017, - 5.593203677296213 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "geometry": { + "coordinates": [ + [ + [ + -0.20863145179911316, + 5.582119462388951 + ], + [ + -0.20385702387126087, + 5.579536961528113 + ], + [ + -0.2009950607269171, + 5.577949413736869 + ], + [ + -0.20077283770629886, + 5.577641331821918 + ], + [ + -0.20073243352073175, + 5.573262528211078 + ], + [ + -0.19864488393309448, + 5.573787782623451 + ], + [ + -0.19734521596401766, + 5.57635681542243 + ], + [ + -0.1960320799330845, + 5.578885444035844 + ], + [ + -0.19481995436606828, + 5.58174404016472 + ], + [ + -0.193715573293899, + 5.5842996049018465 + ], + [ + -0.1928132131495656, + 5.586195234608039 + ], + [ + -0.19234183098461477, + 5.587727226644127 + ], + [ + -0.19077280177842343, + 5.590675048682799 + ], + [ + -0.18995125000522423, + 5.5918703391724955 + ], + [ + -0.18948660187120017, + 5.593203677296213 + ], + [ + -0.1896814210311117, + 5.593146040802338 + ], + [ + -0.19064648860775885, + 5.592399387837963 + ], + [ + -0.19145578395016197, + 5.591683735622175 + ], + [ + -0.191767472021221, + 5.591533359798418 + ], + [ + -0.19283650742283956, + 5.590449970340895 + ], + [ + -0.19318542830603494, + 5.590043519585699 + ], + [ + -0.193702305535994, + 5.589716881891764 + ], + [ + -0.19418464068091668, + 5.589560941307724 + ], + [ + -0.19516869974401801, + 5.589357695039237 + ], + [ + -0.1953956305325968, + 5.589357695039239 + ], + [ + -0.1961839592598401, + 5.5896504069411765 + ], + [ + -0.1965797482249876, + 5.588349850542593 + ], + [ + -0.19764163737530274, + 5.5883155603721155 + ], + [ + -0.19867982389932817, + 5.587968505169294 + ], + [ + -0.19978796845742514, + 5.5877988416473 + ], + [ + -0.20026909700296197, + 5.588264378064047 + ], + [ + -0.2011782799777639, + 5.588967803092853 + ], + [ + -0.20205926441255548, + 5.5896240281790135 + ], + [ + -0.20252257279431515, + 5.589941270993319 + ], + [ + -0.20519554383017538, + 5.592316146871745 + ], + [ + -0.20705628845757923, + 5.590243111157246 + ], + [ + -0.20726746402099225, + 5.589590166024398 + ], + [ + -0.2075150491643001, + 5.587866779242541 + ], + [ + -0.20796945601763953, + 5.5852380825945485 + ], + [ + -0.2084801191101917, + 5.582507241723167 + ], + [ + -0.20863145179911316, + 5.582119462388951 + ] + ] + ], + "type": "Polygon" + }, + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "labels": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/acc/d41d81-labels/d41d81.geojson", + "type": "application/geo+json" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "labels": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/acc/d41d81-labels/d41d81.geojson", - "type": "application/geo+json" - } - }, - "stac_extensions": [ - "label" - ] + "bbox": [ + -0.20863145179911316, + 5.573262528211078, + -0.18948660187120017, + 5.593203677296213 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "acc" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/acc/d41d81/d41d81.json b/tests/data-files/catalogs/test-case-4/acc/d41d81/d41d81.json index dc1391c92..7649f0f2e 100644 --- a/tests/data-files/catalogs/test-case-4/acc/d41d81/d41d81.json +++ b/tests/data-files/catalogs/test-case-4/acc/d41d81/d41d81.json @@ -1,212 +1,213 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "d41d81", - "properties": { - "area": "acc", - "license": "CC-BY-4.0", - "datetime": "2019-07-07T00:00:00Z" - }, - "geometry": { - "coordinates": [ - [ - [ - -0.20863145179911316, - 5.582119462388951 - ], - [ - -0.20385702387126087, - 5.579536961528113 - ], - [ - -0.2009950607269171, - 5.577949413736869 - ], - [ - -0.20077283770629886, - 5.577641331821918 - ], - [ - -0.20073243352073175, - 5.573262528211078 - ], - [ - -0.19864488393309448, - 5.573787782623451 - ], - [ - -0.19734521596401766, - 5.57635681542243 - ], - [ - -0.1960320799330845, - 5.578885444035844 - ], - [ - -0.19481995436606828, - 5.58174404016472 - ], - [ - -0.193715573293899, - 5.5842996049018465 - ], - [ - -0.1928132131495656, - 5.586195234608039 - ], - [ - -0.19234183098461477, - 5.587727226644127 - ], - [ - -0.19077280177842343, - 5.590675048682799 - ], - [ - -0.18995125000522423, - 5.5918703391724955 - ], - [ - -0.18948660187120017, - 5.593203677296213 - ], - [ - -0.1896814210311117, - 5.593146040802338 - ], - [ - -0.19064648860775885, - 5.592399387837963 - ], - [ - -0.19145578395016197, - 5.591683735622175 - ], - [ - -0.191767472021221, - 5.591533359798418 - ], - [ - -0.19283650742283956, - 5.590449970340895 - ], - [ - -0.19318542830603494, - 5.590043519585699 - ], - [ - -0.193702305535994, - 5.589716881891764 - ], - [ - -0.19418464068091668, - 5.589560941307724 - ], - [ - -0.19516869974401801, - 5.589357695039237 - ], - [ - -0.1953956305325968, - 5.589357695039239 - ], - [ - -0.1961839592598401, - 5.5896504069411765 - ], - [ - -0.1965797482249876, - 5.588349850542593 - ], - [ - -0.19764163737530274, - 5.5883155603721155 - ], - [ - -0.19867982389932817, - 5.587968505169294 - ], - [ - -0.19978796845742514, - 5.5877988416473 - ], - [ - -0.20026909700296197, - 5.588264378064047 - ], - [ - -0.2011782799777639, - 5.588967803092853 - ], - [ - -0.20205926441255548, - 5.5896240281790135 - ], - [ - -0.20252257279431515, - 5.589941270993319 - ], - [ - -0.20519554383017538, - 5.592316146871745 - ], - [ - -0.20705628845757923, - 5.590243111157246 - ], - [ - -0.20726746402099225, - 5.589590166024398 - ], - [ - -0.2075150491643001, - 5.587866779242541 - ], - [ - -0.20796945601763953, - 5.5852380825945485 - ], - [ - -0.2084801191101917, - 5.582507241723167 - ], - [ - -0.20863145179911316, - 5.582119462388951 - ] - ] - ], - "type": "Polygon" - }, - "bbox": [ - -0.20863145179911316, - 5.573262528211078, - -0.18948660187120017, - 5.593203677296213 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "d41d81", + "properties": { + "area": "acc", + "license": "CC-BY-4.0", + "datetime": "2019-07-07T00:00:00Z" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "geometry": { + "coordinates": [ + [ + [ + -0.20863145179911316, + 5.582119462388951 + ], + [ + -0.20385702387126087, + 5.579536961528113 + ], + [ + -0.2009950607269171, + 5.577949413736869 + ], + [ + -0.20077283770629886, + 5.577641331821918 + ], + [ + -0.20073243352073175, + 5.573262528211078 + ], + [ + -0.19864488393309448, + 5.573787782623451 + ], + [ + -0.19734521596401766, + 5.57635681542243 + ], + [ + -0.1960320799330845, + 5.578885444035844 + ], + [ + -0.19481995436606828, + 5.58174404016472 + ], + [ + -0.193715573293899, + 5.5842996049018465 + ], + [ + -0.1928132131495656, + 5.586195234608039 + ], + [ + -0.19234183098461477, + 5.587727226644127 + ], + [ + -0.19077280177842343, + 5.590675048682799 + ], + [ + -0.18995125000522423, + 5.5918703391724955 + ], + [ + -0.18948660187120017, + 5.593203677296213 + ], + [ + -0.1896814210311117, + 5.593146040802338 + ], + [ + -0.19064648860775885, + 5.592399387837963 + ], + [ + -0.19145578395016197, + 5.591683735622175 + ], + [ + -0.191767472021221, + 5.591533359798418 + ], + [ + -0.19283650742283956, + 5.590449970340895 + ], + [ + -0.19318542830603494, + 5.590043519585699 + ], + [ + -0.193702305535994, + 5.589716881891764 + ], + [ + -0.19418464068091668, + 5.589560941307724 + ], + [ + -0.19516869974401801, + 5.589357695039237 + ], + [ + -0.1953956305325968, + 5.589357695039239 + ], + [ + -0.1961839592598401, + 5.5896504069411765 + ], + [ + -0.1965797482249876, + 5.588349850542593 + ], + [ + -0.19764163737530274, + 5.5883155603721155 + ], + [ + -0.19867982389932817, + 5.587968505169294 + ], + [ + -0.19978796845742514, + 5.5877988416473 + ], + [ + -0.20026909700296197, + 5.588264378064047 + ], + [ + -0.2011782799777639, + 5.588967803092853 + ], + [ + -0.20205926441255548, + 5.5896240281790135 + ], + [ + -0.20252257279431515, + 5.589941270993319 + ], + [ + -0.20519554383017538, + 5.592316146871745 + ], + [ + -0.20705628845757923, + 5.590243111157246 + ], + [ + -0.20726746402099225, + 5.589590166024398 + ], + [ + -0.2075150491643001, + 5.587866779242541 + ], + [ + -0.20796945601763953, + 5.5852380825945485 + ], + [ + -0.2084801191101917, + 5.582507241723167 + ], + [ + -0.20863145179911316, + 5.582119462388951 + ] + ] + ], + "type": "Polygon" }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "image": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/acc/d41d81/d41d81.tif", - "type": "image/tiff; application=geotiff; profile=cloud-optimized", - "title": "GeoTIFF" - } - }, - "collection": "acc" + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "image": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/acc/d41d81/d41d81.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "GeoTIFF" + } + }, + "bbox": [ + -0.20863145179911316, + 5.573262528211078, + -0.18948660187120017, + 5.593203677296213 + ], + "stac_extensions": [], + "collection": "acc" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/catalog.json b/tests/data-files/catalogs/test-case-4/catalog.json index 98231c5d2..dbb196930 100644 --- a/tests/data-files/catalogs/test-case-4/catalog.json +++ b/tests/data-files/catalogs/test-case-4/catalog.json @@ -1,6 +1,7 @@ { + "type": "Catalog", "id": "train_tier_1", - "stac_version": "1.0.0-beta.2", + "stac_version": "1.0.0-rc.3", "description": "Tier 1 training data and labels", "links": [ { @@ -43,5 +44,6 @@ "href": "./catalog.json", "type": "application/json" } - ] + ], + "stac_extensions": [] } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/dar/0a4c40-labels/0a4c40-labels.json b/tests/data-files/catalogs/test-case-4/dar/0a4c40-labels/0a4c40-labels.json index a3f1dff59..f69f203cf 100644 --- a/tests/data-files/catalogs/test-case-4/dar/0a4c40-labels/0a4c40-labels.json +++ b/tests/data-files/catalogs/test-case-4/dar/0a4c40-labels/0a4c40-labels.json @@ -1,613 +1,614 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "0a4c40-labels", - "properties": { - "label:description": "Geojson building labels for scene 0a4c40", - "area": "dar", - "label:type": "vector", - "label:properties": [ - "building" - ], - "label:overviews": [ - { - "property_key": "building", - "counts": [ - { - "name": "yes", - "count": 8286 - } - ] - } - ], - "license": "ODbL-1.0", - "datetime": "2017-11-01T00:00:00Z", - "label:classes": [ - { - "name": "building", - "classes": [ - "yes" + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "0a4c40-labels", + "properties": { + "label:description": "Geojson building labels for scene 0a4c40", + "area": "dar", + "label:type": "vector", + "label:properties": [ + "building" + ], + "label:overviews": [ + { + "property_key": "building", + "counts": [ + { + "name": "yes", + "count": 8286 + } + ] + } + ], + "license": "ODbL-1.0", + "datetime": "2017-11-01T00:00:00Z", + "label:classes": [ + { + "name": "building", + "classes": [ + "yes" + ] + } ] - } - ] - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [ - 39.276113972191155, - -6.810947356781285 - ], - [ - 39.27608768801011, - -6.810947371883635 - ], - [ - 39.276084515013736, - -6.808826770575084 - ], - [ - 39.27627895492949, - -6.80710456764605 - ], - [ - 39.276594556504065, - -6.806958701930941 - ], - [ - 39.276510741596354, - -6.806687631444213 - ], - [ - 39.27652119569571, - -6.806681745790719 - ], - [ - 39.276375849532066, - -6.806246732800051 - ], - [ - 39.27676148940767, - -6.802859165095991 - ], - [ - 39.27799210415278, - -6.801568197283092 - ], - [ - 39.27889256685514, - -6.801261282769122 - ], - [ - 39.28093888743356, - -6.801172557514979 - ], - [ - 39.28284276122209, - -6.801144663537702 - ], - [ - 39.287098934034255, - -6.801204220933001 - ], - [ - 39.28786172777648, - -6.801307642089444 - ], - [ - 39.29241967438444, - -6.803227561830162 - ], - [ - 39.29242104009511, - -6.804404801451413 - ], - [ - 39.2952098976496, - -6.804403107757896 - ], - [ - 39.29653702336342, - -6.804962171090828 - ], - [ - 39.29661761435555, - -6.805287463245364 - ], - [ - 39.29669874755685, - -6.805431138675158 - ], - [ - 39.29708487226545, - -6.805193101843461 - ], - [ - 39.29805570346486, - -6.805602121377039 - ], - [ - 39.29895841215751, - -6.806823881391469 - ], - [ - 39.298958934014394, - -6.807667286355446 - ], - [ - 39.29958246153687, - -6.807668860358516 - ], - [ - 39.30200149149115, - -6.810944287822992 - ], - [ - 39.30267181005435, - -6.812597360144989 - ], - [ - 39.302944057686055, - -6.814197764053667 - ], - [ - 39.30223097991555, - -6.814198210670114 - ], - [ - 39.30223302578063, - -6.817464687860646 - ], - [ - 39.30350167306014, - -6.817465198761061 - ], - [ - 39.30428300792764, - -6.822048228051391 - ], - [ - 39.30439216680433, - -6.825162418177655 - ], - [ - 39.30421322355657, - -6.825395757497203 - ], - [ - 39.3043884650693, - -6.825510626914298 - ], - [ - 39.304361679630816, - -6.825530895971746 - ], - [ - 39.304406143224945, - -6.825558959610252 - ], - [ - 39.30445672661969, - -6.826996830597941 - ], - [ - 39.30444382230467, - -6.827262729915446 - ], - [ - 39.29243489660985, - -6.827270162213488 - ], - [ - 39.29243291419468, - -6.824003683429136 - ], - [ - 39.29570098395584, - -6.824001691395822 - ], - [ - 39.295698980368996, - -6.820735213131869 - ], - [ - 39.292430932750584, - -6.820737204202933 - ], - [ - 39.29243203391734, - -6.822552713411381 - ], - [ - 39.291886091399185, - -6.822261673892082 - ], - [ - 39.291331712185126, - -6.822069286537019 - ], - [ - 39.29079159396925, - -6.822763412848062 - ], - [ - 39.290916634631486, - -6.823095865220003 - ], - [ - 39.290887286706145, - -6.823203023482961 - ], - [ - 39.29032132310435, - -6.823311811527542 - ], - [ - 39.290350214705896, - -6.823531954953058 - ], - [ - 39.29052497169452, - -6.823933626889247 - ], - [ - 39.2905158640202, - -6.824004841654237 - ], - [ - 39.28916484346245, - -6.824005653325033 - ], - [ - 39.28916680372398, - -6.827272133060951 - ], - [ - 39.27936251403853, - -6.827277912717446 - ], - [ - 39.28589870987786, - -6.827274081760294 - ], - [ - 39.28916680372398, - -6.827272133060967 - ], - [ - 39.29243489660985, - -6.827270162213504 - ], - [ - 39.29243687999612, - -6.830536640555797 - ], - [ - 39.29570499407533, - -6.830534646597951 - ], - [ - 39.29570298852461, - -6.82726816921793 - ], - [ - 39.302239169397396, - -6.827264116782583 - ], - [ - 39.302241357885, - -6.830751405928632 - ], - [ - 39.30042734934312, - -6.831470511704737 - ], - [ - 39.285901405812794, - -6.831815142462718 - ], - [ - 39.28590064893513, - -6.830540561995053 - ], - [ - 39.28590140581279, - -6.831815142462718 - ], - [ - 39.28432030798075, - -6.831852009204463 - ], - [ - 39.28420651086406, - -6.831739709369598 - ], - [ - 39.28417828929836, - -6.831543737123127 - ], - [ - 39.28342419476295, - -6.831864296417407 - ], - [ - 39.283227357093445, - -6.831700434763547 - ], - [ - 39.28316646237391, - -6.831517547569526 - ], - [ - 39.283127252955246, - -6.831531289830293 - ], - [ - 39.28263380917574, - -6.831604748672614 - ], - [ - 39.282631875915335, - -6.831651787146114 - ], - [ - 39.282491354591365, - -6.831665588763534 - ], - [ - 39.28195217439128, - -6.831769125360806 - ], - [ - 39.281322169788, - -6.831923671517303 - ], - [ - 39.27951165146522, - -6.831966536058077 - ], - [ - 39.278917481559084, - -6.831925069351034 - ], - [ - 39.277115771956005, - -6.831374726411127 - ], - [ - 39.276947089372904, - -6.831292507992302 - ], - [ - 39.27656238533688, - -6.830644005256977 - ], - [ - 39.276191770934496, - -6.829487882480712 - ], - [ - 39.27617850435042, - -6.828009479393501 - ], - [ - 39.27629548853805, - -6.827985240388855 - ], - [ - 39.276252256300765, - -6.827822594249342 - ], - [ - 39.276298667078755, - -6.827829100625223 - ], - [ - 39.27627245745106, - -6.827716095291023 - ], - [ - 39.276320740638376, - -6.827568422539262 - ], - [ - 39.27629900556454, - -6.827279677789797 - ], - [ - 39.279327705491625, - -6.827277932772754 - ], - [ - 39.27624148705606, - -6.827279710743532 - ], - [ - 39.27621387584599, - -6.827002075397047 - ], - [ - 39.27616943986283, - -6.827019739862473 - ], - [ - 39.27612683468972, - -6.822247430209742 - ], - [ - 39.27646012316207, - -6.822153164618359 - ], - [ - 39.27643255943666, - -6.821957844611729 - ], - [ - 39.27643188409867, - -6.82191995377355 - ], - [ - 39.276448873893564, - -6.821912757774376 - ], - [ - 39.27641345973164, - -6.821705029618133 - ], - [ - 39.27636576816117, - -6.821743601454265 - ], - [ - 39.276296925889824, - -6.821371914879673 - ], - [ - 39.27622372478111, - -6.821377836454363 - ], - [ - 39.27620996114228, - -6.821311861333559 - ], - [ - 39.27624850961271, - -6.821286360687025 - ], - [ - 39.27621640032443, - -6.821142653721728 - ], - [ - 39.276236665262545, - -6.821147868499644 - ], - [ - 39.2762373181251, - -6.821146561531956 - ], - [ - 39.27614885165009, - -6.820746794378429 - ], - [ - 39.27611290306914, - -6.820746814944531 - ], - [ - 39.27609678846316, - -6.81657356235559 - ], - [ - 39.27641899996001, - -6.816545939565581 - ], - [ - 39.276407184174914, - -6.81645709791839 - ], - [ - 39.276266686088135, - -6.816504215701405 - ], - [ - 39.276095987198005, - -6.816315510439744 - ], - [ - 39.27609576029834, - -6.815918959194581 - ], - [ - 39.27610621422462, - -6.815912420247079 - ], - [ - 39.276095021844235, - -6.815770661160172 - ], - [ - 39.276088593360576, - -6.811387693741025 - ], - [ - 39.276564395401294, - -6.811357370035534 - ], - [ - 39.27650879806149, - -6.811284885849981 - ], - [ - 39.27645123321342, - -6.811200643431646 - ], - [ - 39.27644727422708, - -6.811135315968837 - ], - [ - 39.27646231033641, - -6.811141187043987 - ], - [ - 39.27646032560643, - -6.81109937715377 - ], - [ - 39.27641589593634, - -6.811125534455874 - ], - [ - 39.27643093129704, - -6.8111300989379 - ], - [ - 39.276088566839796, - -6.811341309648862 - ], - [ - 39.27608768801011, - -6.810947371883652 - ], - [ - 39.276113972191155, - -6.810947356781285 + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + 39.276113972191155, + -6.810947356781285 + ], + [ + 39.27608768801011, + -6.810947371883635 + ], + [ + 39.276084515013736, + -6.808826770575084 + ], + [ + 39.27627895492949, + -6.80710456764605 + ], + [ + 39.276594556504065, + -6.806958701930941 + ], + [ + 39.276510741596354, + -6.806687631444213 + ], + [ + 39.27652119569571, + -6.806681745790719 + ], + [ + 39.276375849532066, + -6.806246732800051 + ], + [ + 39.27676148940767, + -6.802859165095991 + ], + [ + 39.27799210415278, + -6.801568197283092 + ], + [ + 39.27889256685514, + -6.801261282769122 + ], + [ + 39.28093888743356, + -6.801172557514979 + ], + [ + 39.28284276122209, + -6.801144663537702 + ], + [ + 39.287098934034255, + -6.801204220933001 + ], + [ + 39.28786172777648, + -6.801307642089444 + ], + [ + 39.29241967438444, + -6.803227561830162 + ], + [ + 39.29242104009511, + -6.804404801451413 + ], + [ + 39.2952098976496, + -6.804403107757896 + ], + [ + 39.29653702336342, + -6.804962171090828 + ], + [ + 39.29661761435555, + -6.805287463245364 + ], + [ + 39.29669874755685, + -6.805431138675158 + ], + [ + 39.29708487226545, + -6.805193101843461 + ], + [ + 39.29805570346486, + -6.805602121377039 + ], + [ + 39.29895841215751, + -6.806823881391469 + ], + [ + 39.298958934014394, + -6.807667286355446 + ], + [ + 39.29958246153687, + -6.807668860358516 + ], + [ + 39.30200149149115, + -6.810944287822992 + ], + [ + 39.30267181005435, + -6.812597360144989 + ], + [ + 39.302944057686055, + -6.814197764053667 + ], + [ + 39.30223097991555, + -6.814198210670114 + ], + [ + 39.30223302578063, + -6.817464687860646 + ], + [ + 39.30350167306014, + -6.817465198761061 + ], + [ + 39.30428300792764, + -6.822048228051391 + ], + [ + 39.30439216680433, + -6.825162418177655 + ], + [ + 39.30421322355657, + -6.825395757497203 + ], + [ + 39.3043884650693, + -6.825510626914298 + ], + [ + 39.304361679630816, + -6.825530895971746 + ], + [ + 39.304406143224945, + -6.825558959610252 + ], + [ + 39.30445672661969, + -6.826996830597941 + ], + [ + 39.30444382230467, + -6.827262729915446 + ], + [ + 39.29243489660985, + -6.827270162213488 + ], + [ + 39.29243291419468, + -6.824003683429136 + ], + [ + 39.29570098395584, + -6.824001691395822 + ], + [ + 39.295698980368996, + -6.820735213131869 + ], + [ + 39.292430932750584, + -6.820737204202933 + ], + [ + 39.29243203391734, + -6.822552713411381 + ], + [ + 39.291886091399185, + -6.822261673892082 + ], + [ + 39.291331712185126, + -6.822069286537019 + ], + [ + 39.29079159396925, + -6.822763412848062 + ], + [ + 39.290916634631486, + -6.823095865220003 + ], + [ + 39.290887286706145, + -6.823203023482961 + ], + [ + 39.29032132310435, + -6.823311811527542 + ], + [ + 39.290350214705896, + -6.823531954953058 + ], + [ + 39.29052497169452, + -6.823933626889247 + ], + [ + 39.2905158640202, + -6.824004841654237 + ], + [ + 39.28916484346245, + -6.824005653325033 + ], + [ + 39.28916680372398, + -6.827272133060951 + ], + [ + 39.27936251403853, + -6.827277912717446 + ], + [ + 39.28589870987786, + -6.827274081760294 + ], + [ + 39.28916680372398, + -6.827272133060967 + ], + [ + 39.29243489660985, + -6.827270162213504 + ], + [ + 39.29243687999612, + -6.830536640555797 + ], + [ + 39.29570499407533, + -6.830534646597951 + ], + [ + 39.29570298852461, + -6.82726816921793 + ], + [ + 39.302239169397396, + -6.827264116782583 + ], + [ + 39.302241357885, + -6.830751405928632 + ], + [ + 39.30042734934312, + -6.831470511704737 + ], + [ + 39.285901405812794, + -6.831815142462718 + ], + [ + 39.28590064893513, + -6.830540561995053 + ], + [ + 39.28590140581279, + -6.831815142462718 + ], + [ + 39.28432030798075, + -6.831852009204463 + ], + [ + 39.28420651086406, + -6.831739709369598 + ], + [ + 39.28417828929836, + -6.831543737123127 + ], + [ + 39.28342419476295, + -6.831864296417407 + ], + [ + 39.283227357093445, + -6.831700434763547 + ], + [ + 39.28316646237391, + -6.831517547569526 + ], + [ + 39.283127252955246, + -6.831531289830293 + ], + [ + 39.28263380917574, + -6.831604748672614 + ], + [ + 39.282631875915335, + -6.831651787146114 + ], + [ + 39.282491354591365, + -6.831665588763534 + ], + [ + 39.28195217439128, + -6.831769125360806 + ], + [ + 39.281322169788, + -6.831923671517303 + ], + [ + 39.27951165146522, + -6.831966536058077 + ], + [ + 39.278917481559084, + -6.831925069351034 + ], + [ + 39.277115771956005, + -6.831374726411127 + ], + [ + 39.276947089372904, + -6.831292507992302 + ], + [ + 39.27656238533688, + -6.830644005256977 + ], + [ + 39.276191770934496, + -6.829487882480712 + ], + [ + 39.27617850435042, + -6.828009479393501 + ], + [ + 39.27629548853805, + -6.827985240388855 + ], + [ + 39.276252256300765, + -6.827822594249342 + ], + [ + 39.276298667078755, + -6.827829100625223 + ], + [ + 39.27627245745106, + -6.827716095291023 + ], + [ + 39.276320740638376, + -6.827568422539262 + ], + [ + 39.27629900556454, + -6.827279677789797 + ], + [ + 39.279327705491625, + -6.827277932772754 + ], + [ + 39.27624148705606, + -6.827279710743532 + ], + [ + 39.27621387584599, + -6.827002075397047 + ], + [ + 39.27616943986283, + -6.827019739862473 + ], + [ + 39.27612683468972, + -6.822247430209742 + ], + [ + 39.27646012316207, + -6.822153164618359 + ], + [ + 39.27643255943666, + -6.821957844611729 + ], + [ + 39.27643188409867, + -6.82191995377355 + ], + [ + 39.276448873893564, + -6.821912757774376 + ], + [ + 39.27641345973164, + -6.821705029618133 + ], + [ + 39.27636576816117, + -6.821743601454265 + ], + [ + 39.276296925889824, + -6.821371914879673 + ], + [ + 39.27622372478111, + -6.821377836454363 + ], + [ + 39.27620996114228, + -6.821311861333559 + ], + [ + 39.27624850961271, + -6.821286360687025 + ], + [ + 39.27621640032443, + -6.821142653721728 + ], + [ + 39.276236665262545, + -6.821147868499644 + ], + [ + 39.2762373181251, + -6.821146561531956 + ], + [ + 39.27614885165009, + -6.820746794378429 + ], + [ + 39.27611290306914, + -6.820746814944531 + ], + [ + 39.27609678846316, + -6.81657356235559 + ], + [ + 39.27641899996001, + -6.816545939565581 + ], + [ + 39.276407184174914, + -6.81645709791839 + ], + [ + 39.276266686088135, + -6.816504215701405 + ], + [ + 39.276095987198005, + -6.816315510439744 + ], + [ + 39.27609576029834, + -6.815918959194581 + ], + [ + 39.27610621422462, + -6.815912420247079 + ], + [ + 39.276095021844235, + -6.815770661160172 + ], + [ + 39.276088593360576, + -6.811387693741025 + ], + [ + 39.276564395401294, + -6.811357370035534 + ], + [ + 39.27650879806149, + -6.811284885849981 + ], + [ + 39.27645123321342, + -6.811200643431646 + ], + [ + 39.27644727422708, + -6.811135315968837 + ], + [ + 39.27646231033641, + -6.811141187043987 + ], + [ + 39.27646032560643, + -6.81109937715377 + ], + [ + 39.27641589593634, + -6.811125534455874 + ], + [ + 39.27643093129704, + -6.8111300989379 + ], + [ + 39.276088566839796, + -6.811341309648862 + ], + [ + 39.27608768801011, + -6.810947371883652 + ], + [ + 39.276113972191155, + -6.810947356781285 + ] + ] ] - ] - ] - }, - "bbox": [ - 39.276084515013736, - -6.831966577377629, - 39.304456754694705, - -6.801144663537702 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "labels": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/dar/0a4c40-labels/0a4c40.geojson", + "type": "application/geo+json" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "labels": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/dar/0a4c40-labels/0a4c40.geojson", - "type": "application/geo+json" - } - }, - "stac_extensions": [ - "label" - ] + "bbox": [ + 39.276084515013736, + -6.831966577377629, + 39.304456754694705, + -6.801144663537702 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "dar" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/dar/0a4c40/0a4c40.json b/tests/data-files/catalogs/test-case-4/dar/0a4c40/0a4c40.json index af75d448b..20eb50e69 100644 --- a/tests/data-files/catalogs/test-case-4/dar/0a4c40/0a4c40.json +++ b/tests/data-files/catalogs/test-case-4/dar/0a4c40/0a4c40.json @@ -1,588 +1,589 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "0a4c40", - "properties": { - "area": "dar", - "license": "ODbL-1.0", - "datetime": "2017-11-01T00:00:00Z" - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [ - 39.276113972191155, - -6.810947356781285 - ], - [ - 39.27608768801011, - -6.810947371883635 - ], - [ - 39.276084515013736, - -6.808826770575084 - ], - [ - 39.27627895492949, - -6.80710456764605 - ], - [ - 39.276594556504065, - -6.806958701930941 - ], - [ - 39.276510741596354, - -6.806687631444213 - ], - [ - 39.27652119569571, - -6.806681745790719 - ], - [ - 39.276375849532066, - -6.806246732800051 - ], - [ - 39.27676148940767, - -6.802859165095991 - ], - [ - 39.27799210415278, - -6.801568197283092 - ], - [ - 39.27889256685514, - -6.801261282769122 - ], - [ - 39.28093888743356, - -6.801172557514979 - ], - [ - 39.28284276122209, - -6.801144663537702 - ], - [ - 39.287098934034255, - -6.801204220933001 - ], - [ - 39.28786172777648, - -6.801307642089444 - ], - [ - 39.29241967438444, - -6.803227561830162 - ], - [ - 39.29242104009511, - -6.804404801451413 - ], - [ - 39.2952098976496, - -6.804403107757896 - ], - [ - 39.29653702336342, - -6.804962171090828 - ], - [ - 39.29661761435555, - -6.805287463245364 - ], - [ - 39.29669874755685, - -6.805431138675158 - ], - [ - 39.29708487226545, - -6.805193101843461 - ], - [ - 39.29805570346486, - -6.805602121377039 - ], - [ - 39.29895841215751, - -6.806823881391469 - ], - [ - 39.298958934014394, - -6.807667286355446 - ], - [ - 39.29958246153687, - -6.807668860358516 - ], - [ - 39.30200149149115, - -6.810944287822992 - ], - [ - 39.30267181005435, - -6.812597360144989 - ], - [ - 39.302944057686055, - -6.814197764053667 - ], - [ - 39.30223097991555, - -6.814198210670114 - ], - [ - 39.30223302578063, - -6.817464687860646 - ], - [ - 39.30350167306014, - -6.817465198761061 - ], - [ - 39.30428300792764, - -6.822048228051391 - ], - [ - 39.30439216680433, - -6.825162418177655 - ], - [ - 39.30421322355657, - -6.825395757497203 - ], - [ - 39.3043884650693, - -6.825510626914298 - ], - [ - 39.304361679630816, - -6.825530895971746 - ], - [ - 39.304406143224945, - -6.825558959610252 - ], - [ - 39.30445672661969, - -6.826996830597941 - ], - [ - 39.30444382230467, - -6.827262729915446 - ], - [ - 39.29243489660985, - -6.827270162213488 - ], - [ - 39.29243291419468, - -6.824003683429136 - ], - [ - 39.29570098395584, - -6.824001691395822 - ], - [ - 39.295698980368996, - -6.820735213131869 - ], - [ - 39.292430932750584, - -6.820737204202933 - ], - [ - 39.29243203391734, - -6.822552713411381 - ], - [ - 39.291886091399185, - -6.822261673892082 - ], - [ - 39.291331712185126, - -6.822069286537019 - ], - [ - 39.29079159396925, - -6.822763412848062 - ], - [ - 39.290916634631486, - -6.823095865220003 - ], - [ - 39.290887286706145, - -6.823203023482961 - ], - [ - 39.29032132310435, - -6.823311811527542 - ], - [ - 39.290350214705896, - -6.823531954953058 - ], - [ - 39.29052497169452, - -6.823933626889247 - ], - [ - 39.2905158640202, - -6.824004841654237 - ], - [ - 39.28916484346245, - -6.824005653325033 - ], - [ - 39.28916680372398, - -6.827272133060951 - ], - [ - 39.27936251403853, - -6.827277912717446 - ], - [ - 39.28589870987786, - -6.827274081760294 - ], - [ - 39.28916680372398, - -6.827272133060967 - ], - [ - 39.29243489660985, - -6.827270162213504 - ], - [ - 39.29243687999612, - -6.830536640555797 - ], - [ - 39.29570499407533, - -6.830534646597951 - ], - [ - 39.29570298852461, - -6.82726816921793 - ], - [ - 39.302239169397396, - -6.827264116782583 - ], - [ - 39.302241357885, - -6.830751405928632 - ], - [ - 39.30042734934312, - -6.831470511704737 - ], - [ - 39.285901405812794, - -6.831815142462718 - ], - [ - 39.28590064893513, - -6.830540561995053 - ], - [ - 39.28590140581279, - -6.831815142462718 - ], - [ - 39.28432030798075, - -6.831852009204463 - ], - [ - 39.28420651086406, - -6.831739709369598 - ], - [ - 39.28417828929836, - -6.831543737123127 - ], - [ - 39.28342419476295, - -6.831864296417407 - ], - [ - 39.283227357093445, - -6.831700434763547 - ], - [ - 39.28316646237391, - -6.831517547569526 - ], - [ - 39.283127252955246, - -6.831531289830293 - ], - [ - 39.28263380917574, - -6.831604748672614 - ], - [ - 39.282631875915335, - -6.831651787146114 - ], - [ - 39.282491354591365, - -6.831665588763534 - ], - [ - 39.28195217439128, - -6.831769125360806 - ], - [ - 39.281322169788, - -6.831923671517303 - ], - [ - 39.27951165146522, - -6.831966536058077 - ], - [ - 39.278917481559084, - -6.831925069351034 - ], - [ - 39.277115771956005, - -6.831374726411127 - ], - [ - 39.276947089372904, - -6.831292507992302 - ], - [ - 39.27656238533688, - -6.830644005256977 - ], - [ - 39.276191770934496, - -6.829487882480712 - ], - [ - 39.27617850435042, - -6.828009479393501 - ], - [ - 39.27629548853805, - -6.827985240388855 - ], - [ - 39.276252256300765, - -6.827822594249342 - ], - [ - 39.276298667078755, - -6.827829100625223 - ], - [ - 39.27627245745106, - -6.827716095291023 - ], - [ - 39.276320740638376, - -6.827568422539262 - ], - [ - 39.27629900556454, - -6.827279677789797 - ], - [ - 39.279327705491625, - -6.827277932772754 - ], - [ - 39.27624148705606, - -6.827279710743532 - ], - [ - 39.27621387584599, - -6.827002075397047 - ], - [ - 39.27616943986283, - -6.827019739862473 - ], - [ - 39.27612683468972, - -6.822247430209742 - ], - [ - 39.27646012316207, - -6.822153164618359 - ], - [ - 39.27643255943666, - -6.821957844611729 - ], - [ - 39.27643188409867, - -6.82191995377355 - ], - [ - 39.276448873893564, - -6.821912757774376 - ], - [ - 39.27641345973164, - -6.821705029618133 - ], - [ - 39.27636576816117, - -6.821743601454265 - ], - [ - 39.276296925889824, - -6.821371914879673 - ], - [ - 39.27622372478111, - -6.821377836454363 - ], - [ - 39.27620996114228, - -6.821311861333559 - ], - [ - 39.27624850961271, - -6.821286360687025 - ], - [ - 39.27621640032443, - -6.821142653721728 - ], - [ - 39.276236665262545, - -6.821147868499644 - ], - [ - 39.2762373181251, - -6.821146561531956 - ], - [ - 39.27614885165009, - -6.820746794378429 - ], - [ - 39.27611290306914, - -6.820746814944531 - ], - [ - 39.27609678846316, - -6.81657356235559 - ], - [ - 39.27641899996001, - -6.816545939565581 - ], - [ - 39.276407184174914, - -6.81645709791839 - ], - [ - 39.276266686088135, - -6.816504215701405 - ], - [ - 39.276095987198005, - -6.816315510439744 - ], - [ - 39.27609576029834, - -6.815918959194581 - ], - [ - 39.27610621422462, - -6.815912420247079 - ], - [ - 39.276095021844235, - -6.815770661160172 - ], - [ - 39.276088593360576, - -6.811387693741025 - ], - [ - 39.276564395401294, - -6.811357370035534 - ], - [ - 39.27650879806149, - -6.811284885849981 - ], - [ - 39.27645123321342, - -6.811200643431646 - ], - [ - 39.27644727422708, - -6.811135315968837 - ], - [ - 39.27646231033641, - -6.811141187043987 - ], - [ - 39.27646032560643, - -6.81109937715377 - ], - [ - 39.27641589593634, - -6.811125534455874 - ], - [ - 39.27643093129704, - -6.8111300989379 - ], - [ - 39.276088566839796, - -6.811341309648862 - ], - [ - 39.27608768801011, - -6.810947371883652 - ], - [ - 39.276113972191155, - -6.810947356781285 + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "0a4c40", + "properties": { + "area": "dar", + "license": "ODbL-1.0", + "datetime": "2017-11-01T00:00:00Z" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + 39.276113972191155, + -6.810947356781285 + ], + [ + 39.27608768801011, + -6.810947371883635 + ], + [ + 39.276084515013736, + -6.808826770575084 + ], + [ + 39.27627895492949, + -6.80710456764605 + ], + [ + 39.276594556504065, + -6.806958701930941 + ], + [ + 39.276510741596354, + -6.806687631444213 + ], + [ + 39.27652119569571, + -6.806681745790719 + ], + [ + 39.276375849532066, + -6.806246732800051 + ], + [ + 39.27676148940767, + -6.802859165095991 + ], + [ + 39.27799210415278, + -6.801568197283092 + ], + [ + 39.27889256685514, + -6.801261282769122 + ], + [ + 39.28093888743356, + -6.801172557514979 + ], + [ + 39.28284276122209, + -6.801144663537702 + ], + [ + 39.287098934034255, + -6.801204220933001 + ], + [ + 39.28786172777648, + -6.801307642089444 + ], + [ + 39.29241967438444, + -6.803227561830162 + ], + [ + 39.29242104009511, + -6.804404801451413 + ], + [ + 39.2952098976496, + -6.804403107757896 + ], + [ + 39.29653702336342, + -6.804962171090828 + ], + [ + 39.29661761435555, + -6.805287463245364 + ], + [ + 39.29669874755685, + -6.805431138675158 + ], + [ + 39.29708487226545, + -6.805193101843461 + ], + [ + 39.29805570346486, + -6.805602121377039 + ], + [ + 39.29895841215751, + -6.806823881391469 + ], + [ + 39.298958934014394, + -6.807667286355446 + ], + [ + 39.29958246153687, + -6.807668860358516 + ], + [ + 39.30200149149115, + -6.810944287822992 + ], + [ + 39.30267181005435, + -6.812597360144989 + ], + [ + 39.302944057686055, + -6.814197764053667 + ], + [ + 39.30223097991555, + -6.814198210670114 + ], + [ + 39.30223302578063, + -6.817464687860646 + ], + [ + 39.30350167306014, + -6.817465198761061 + ], + [ + 39.30428300792764, + -6.822048228051391 + ], + [ + 39.30439216680433, + -6.825162418177655 + ], + [ + 39.30421322355657, + -6.825395757497203 + ], + [ + 39.3043884650693, + -6.825510626914298 + ], + [ + 39.304361679630816, + -6.825530895971746 + ], + [ + 39.304406143224945, + -6.825558959610252 + ], + [ + 39.30445672661969, + -6.826996830597941 + ], + [ + 39.30444382230467, + -6.827262729915446 + ], + [ + 39.29243489660985, + -6.827270162213488 + ], + [ + 39.29243291419468, + -6.824003683429136 + ], + [ + 39.29570098395584, + -6.824001691395822 + ], + [ + 39.295698980368996, + -6.820735213131869 + ], + [ + 39.292430932750584, + -6.820737204202933 + ], + [ + 39.29243203391734, + -6.822552713411381 + ], + [ + 39.291886091399185, + -6.822261673892082 + ], + [ + 39.291331712185126, + -6.822069286537019 + ], + [ + 39.29079159396925, + -6.822763412848062 + ], + [ + 39.290916634631486, + -6.823095865220003 + ], + [ + 39.290887286706145, + -6.823203023482961 + ], + [ + 39.29032132310435, + -6.823311811527542 + ], + [ + 39.290350214705896, + -6.823531954953058 + ], + [ + 39.29052497169452, + -6.823933626889247 + ], + [ + 39.2905158640202, + -6.824004841654237 + ], + [ + 39.28916484346245, + -6.824005653325033 + ], + [ + 39.28916680372398, + -6.827272133060951 + ], + [ + 39.27936251403853, + -6.827277912717446 + ], + [ + 39.28589870987786, + -6.827274081760294 + ], + [ + 39.28916680372398, + -6.827272133060967 + ], + [ + 39.29243489660985, + -6.827270162213504 + ], + [ + 39.29243687999612, + -6.830536640555797 + ], + [ + 39.29570499407533, + -6.830534646597951 + ], + [ + 39.29570298852461, + -6.82726816921793 + ], + [ + 39.302239169397396, + -6.827264116782583 + ], + [ + 39.302241357885, + -6.830751405928632 + ], + [ + 39.30042734934312, + -6.831470511704737 + ], + [ + 39.285901405812794, + -6.831815142462718 + ], + [ + 39.28590064893513, + -6.830540561995053 + ], + [ + 39.28590140581279, + -6.831815142462718 + ], + [ + 39.28432030798075, + -6.831852009204463 + ], + [ + 39.28420651086406, + -6.831739709369598 + ], + [ + 39.28417828929836, + -6.831543737123127 + ], + [ + 39.28342419476295, + -6.831864296417407 + ], + [ + 39.283227357093445, + -6.831700434763547 + ], + [ + 39.28316646237391, + -6.831517547569526 + ], + [ + 39.283127252955246, + -6.831531289830293 + ], + [ + 39.28263380917574, + -6.831604748672614 + ], + [ + 39.282631875915335, + -6.831651787146114 + ], + [ + 39.282491354591365, + -6.831665588763534 + ], + [ + 39.28195217439128, + -6.831769125360806 + ], + [ + 39.281322169788, + -6.831923671517303 + ], + [ + 39.27951165146522, + -6.831966536058077 + ], + [ + 39.278917481559084, + -6.831925069351034 + ], + [ + 39.277115771956005, + -6.831374726411127 + ], + [ + 39.276947089372904, + -6.831292507992302 + ], + [ + 39.27656238533688, + -6.830644005256977 + ], + [ + 39.276191770934496, + -6.829487882480712 + ], + [ + 39.27617850435042, + -6.828009479393501 + ], + [ + 39.27629548853805, + -6.827985240388855 + ], + [ + 39.276252256300765, + -6.827822594249342 + ], + [ + 39.276298667078755, + -6.827829100625223 + ], + [ + 39.27627245745106, + -6.827716095291023 + ], + [ + 39.276320740638376, + -6.827568422539262 + ], + [ + 39.27629900556454, + -6.827279677789797 + ], + [ + 39.279327705491625, + -6.827277932772754 + ], + [ + 39.27624148705606, + -6.827279710743532 + ], + [ + 39.27621387584599, + -6.827002075397047 + ], + [ + 39.27616943986283, + -6.827019739862473 + ], + [ + 39.27612683468972, + -6.822247430209742 + ], + [ + 39.27646012316207, + -6.822153164618359 + ], + [ + 39.27643255943666, + -6.821957844611729 + ], + [ + 39.27643188409867, + -6.82191995377355 + ], + [ + 39.276448873893564, + -6.821912757774376 + ], + [ + 39.27641345973164, + -6.821705029618133 + ], + [ + 39.27636576816117, + -6.821743601454265 + ], + [ + 39.276296925889824, + -6.821371914879673 + ], + [ + 39.27622372478111, + -6.821377836454363 + ], + [ + 39.27620996114228, + -6.821311861333559 + ], + [ + 39.27624850961271, + -6.821286360687025 + ], + [ + 39.27621640032443, + -6.821142653721728 + ], + [ + 39.276236665262545, + -6.821147868499644 + ], + [ + 39.2762373181251, + -6.821146561531956 + ], + [ + 39.27614885165009, + -6.820746794378429 + ], + [ + 39.27611290306914, + -6.820746814944531 + ], + [ + 39.27609678846316, + -6.81657356235559 + ], + [ + 39.27641899996001, + -6.816545939565581 + ], + [ + 39.276407184174914, + -6.81645709791839 + ], + [ + 39.276266686088135, + -6.816504215701405 + ], + [ + 39.276095987198005, + -6.816315510439744 + ], + [ + 39.27609576029834, + -6.815918959194581 + ], + [ + 39.27610621422462, + -6.815912420247079 + ], + [ + 39.276095021844235, + -6.815770661160172 + ], + [ + 39.276088593360576, + -6.811387693741025 + ], + [ + 39.276564395401294, + -6.811357370035534 + ], + [ + 39.27650879806149, + -6.811284885849981 + ], + [ + 39.27645123321342, + -6.811200643431646 + ], + [ + 39.27644727422708, + -6.811135315968837 + ], + [ + 39.27646231033641, + -6.811141187043987 + ], + [ + 39.27646032560643, + -6.81109937715377 + ], + [ + 39.27641589593634, + -6.811125534455874 + ], + [ + 39.27643093129704, + -6.8111300989379 + ], + [ + 39.276088566839796, + -6.811341309648862 + ], + [ + 39.27608768801011, + -6.810947371883652 + ], + [ + 39.276113972191155, + -6.810947356781285 + ] + ] ] - ] - ] - }, - "bbox": [ - 39.276084515013736, - -6.831966577377629, - 39.304456754694705, - -6.801144663537702 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "image": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/dar/0a4c40/0a4c40.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "GeoTIFF" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "image": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/dar/0a4c40/0a4c40.tif", - "type": "image/tiff; application=geotiff; profile=cloud-optimized", - "title": "GeoTIFF" - } - }, - "collection": "dar" + "bbox": [ + 39.276084515013736, + -6.831966577377629, + 39.304456754694705, + -6.801144663537702 + ], + "stac_extensions": [], + "collection": "dar" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/dar/353093-labels/353093-labels.json b/tests/data-files/catalogs/test-case-4/dar/353093-labels/353093-labels.json index 6750ec422..63e7bcb9c 100644 --- a/tests/data-files/catalogs/test-case-4/dar/353093-labels/353093-labels.json +++ b/tests/data-files/catalogs/test-case-4/dar/353093-labels/353093-labels.json @@ -1,229 +1,230 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "353093-labels", - "properties": { - "label:description": "Geojson building labels for scene 353093", - "area": "dar", - "label:type": "vector", - "label:properties": [ - "building" - ], - "label:overviews": [ - { - "property_key": "building", - "counts": [ - { - "name": "yes", - "count": 6998 - } - ] - } - ], - "license": "ODbL-1.0", - "datetime": "2015-04-20T00:00:00Z", - "label:classes": [ - { - "name": "building", - "classes": [ - "yes" + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "353093-labels", + "properties": { + "label:description": "Geojson building labels for scene 353093", + "area": "dar", + "label:type": "vector", + "label:properties": [ + "building" + ], + "label:overviews": [ + { + "property_key": "building", + "counts": [ + { + "name": "yes", + "count": 6998 + } + ] + } + ], + "license": "ODbL-1.0", + "datetime": "2015-04-20T00:00:00Z", + "label:classes": [ + { + "name": "building", + "classes": [ + "yes" + ] + } ] - } - ] - }, - "geometry": { - "coordinates": [ - [ - [ - 39.21152919667973, - -6.808359253694025 - ], - [ - 39.21101071619515, - -6.80780969783032 - ], - [ - 39.2108730885634, - -6.806774452292519 - ], - [ - 39.20942360688795, - -6.80495789295139 - ], - [ - 39.20849433161743, - -6.804654136577633 - ], - [ - 39.20787596866212, - -6.803293387986344 - ], - [ - 39.20635028282986, - -6.80279870007748 - ], - [ - 39.2046107249861, - -6.795381424410041 - ], - [ - 39.20391600733412, - -6.79149776634182 - ], - [ - 39.20390908985627, - -6.791383173329291 - ], - [ - 39.20496051556537, - -6.7866740661368175 - ], - [ - 39.20505620172756, - -6.786303447012387 - ], - [ - 39.20621306671285, - -6.785058576896908 - ], - [ - 39.20929283360648, - -6.783684457665884 - ], - [ - 39.209550980241275, - -6.783726455597161 - ], - [ - 39.213536684353556, - -6.784551417830786 - ], - [ - 39.21258418889021, - -6.789322183261566 - ], - [ - 39.2163274162412, - -6.790171293774371 - ], - [ - 39.21759522944233, - -6.791810729353808 - ], - [ - 39.22088166017734, - -6.7926145242067575 - ], - [ - 39.22094061195484, - -6.792658437353369 - ], - [ - 39.22238742900873, - -6.794159377815079 - ], - [ - 39.22616044436698, - -6.795158821931178 - ], - [ - 39.22707373283919, - -6.796048913257977 - ], - [ - 39.22708687129574, - -6.796117385555728 - ], - [ - 39.227083424855664, - -6.796231104782896 - ], - [ - 39.22701001344086, - -6.79668679086265 - ], - [ - 39.22681107485247, - -6.797855302295221 - ], - [ - 39.22679477506837, - -6.797883580670773 - ], - [ - 39.21886584724193, - -6.796354991252584 - ], - [ - 39.21789760196279, - -6.800821422455203 - ], - [ - 39.21585912856685, - -6.802696774914448 - ], - [ - 39.2146774574239, - -6.808974568223004 - ], - [ - 39.21453136175979, - -6.809102537362755 - ], - [ - 39.21433909072671, - -6.809236085323197 - ], - [ - 39.213911464788005, - -6.809502598801659 - ], - [ - 39.21384943878973, - -6.809510517136742 - ], - [ - 39.212327864627525, - -6.809201572001297 - ], - [ - 39.21152919667973, - -6.808359253694025 - ] - ] - ], - "type": "Polygon" - }, - "bbox": [ - 39.20390891675323, - -6.809511989589884, - 39.2270869431941, - -6.783684392169557 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "geometry": { + "coordinates": [ + [ + [ + 39.21152919667973, + -6.808359253694025 + ], + [ + 39.21101071619515, + -6.80780969783032 + ], + [ + 39.2108730885634, + -6.806774452292519 + ], + [ + 39.20942360688795, + -6.80495789295139 + ], + [ + 39.20849433161743, + -6.804654136577633 + ], + [ + 39.20787596866212, + -6.803293387986344 + ], + [ + 39.20635028282986, + -6.80279870007748 + ], + [ + 39.2046107249861, + -6.795381424410041 + ], + [ + 39.20391600733412, + -6.79149776634182 + ], + [ + 39.20390908985627, + -6.791383173329291 + ], + [ + 39.20496051556537, + -6.7866740661368175 + ], + [ + 39.20505620172756, + -6.786303447012387 + ], + [ + 39.20621306671285, + -6.785058576896908 + ], + [ + 39.20929283360648, + -6.783684457665884 + ], + [ + 39.209550980241275, + -6.783726455597161 + ], + [ + 39.213536684353556, + -6.784551417830786 + ], + [ + 39.21258418889021, + -6.789322183261566 + ], + [ + 39.2163274162412, + -6.790171293774371 + ], + [ + 39.21759522944233, + -6.791810729353808 + ], + [ + 39.22088166017734, + -6.7926145242067575 + ], + [ + 39.22094061195484, + -6.792658437353369 + ], + [ + 39.22238742900873, + -6.794159377815079 + ], + [ + 39.22616044436698, + -6.795158821931178 + ], + [ + 39.22707373283919, + -6.796048913257977 + ], + [ + 39.22708687129574, + -6.796117385555728 + ], + [ + 39.227083424855664, + -6.796231104782896 + ], + [ + 39.22701001344086, + -6.79668679086265 + ], + [ + 39.22681107485247, + -6.797855302295221 + ], + [ + 39.22679477506837, + -6.797883580670773 + ], + [ + 39.21886584724193, + -6.796354991252584 + ], + [ + 39.21789760196279, + -6.800821422455203 + ], + [ + 39.21585912856685, + -6.802696774914448 + ], + [ + 39.2146774574239, + -6.808974568223004 + ], + [ + 39.21453136175979, + -6.809102537362755 + ], + [ + 39.21433909072671, + -6.809236085323197 + ], + [ + 39.213911464788005, + -6.809502598801659 + ], + [ + 39.21384943878973, + -6.809510517136742 + ], + [ + 39.212327864627525, + -6.809201572001297 + ], + [ + 39.21152919667973, + -6.808359253694025 + ] + ] + ], + "type": "Polygon" + }, + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "labels": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/dar/353093-labels/353093.geojson", + "type": "application/geo+json" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "labels": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/dar/353093-labels/353093.geojson", - "type": "application/geo+json" - } - }, - "stac_extensions": [ - "label" - ] + "bbox": [ + 39.20390891675323, + -6.809511989589884, + 39.2270869431941, + -6.783684392169557 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "dar" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/dar/353093/353093.json b/tests/data-files/catalogs/test-case-4/dar/353093/353093.json index 5e1785da7..b24d05651 100644 --- a/tests/data-files/catalogs/test-case-4/dar/353093/353093.json +++ b/tests/data-files/catalogs/test-case-4/dar/353093/353093.json @@ -1,204 +1,205 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "353093", - "properties": { - "area": "dar", - "license": "CC-BY-4.0", - "datetime": "2015-04-20T00:00:00Z" - }, - "geometry": { - "coordinates": [ - [ - [ - 39.21152919667973, - -6.808359253694025 - ], - [ - 39.21101071619515, - -6.80780969783032 - ], - [ - 39.2108730885634, - -6.806774452292519 - ], - [ - 39.20942360688795, - -6.80495789295139 - ], - [ - 39.20849433161743, - -6.804654136577633 - ], - [ - 39.20787596866212, - -6.803293387986344 - ], - [ - 39.20635028282986, - -6.80279870007748 - ], - [ - 39.2046107249861, - -6.795381424410041 - ], - [ - 39.20391600733412, - -6.79149776634182 - ], - [ - 39.20390908985627, - -6.791383173329291 - ], - [ - 39.20496051556537, - -6.7866740661368175 - ], - [ - 39.20505620172756, - -6.786303447012387 - ], - [ - 39.20621306671285, - -6.785058576896908 - ], - [ - 39.20929283360648, - -6.783684457665884 - ], - [ - 39.209550980241275, - -6.783726455597161 - ], - [ - 39.213536684353556, - -6.784551417830786 - ], - [ - 39.21258418889021, - -6.789322183261566 - ], - [ - 39.2163274162412, - -6.790171293774371 - ], - [ - 39.21759522944233, - -6.791810729353808 - ], - [ - 39.22088166017734, - -6.7926145242067575 - ], - [ - 39.22094061195484, - -6.792658437353369 - ], - [ - 39.22238742900873, - -6.794159377815079 - ], - [ - 39.22616044436698, - -6.795158821931178 - ], - [ - 39.22707373283919, - -6.796048913257977 - ], - [ - 39.22708687129574, - -6.796117385555728 - ], - [ - 39.227083424855664, - -6.796231104782896 - ], - [ - 39.22701001344086, - -6.79668679086265 - ], - [ - 39.22681107485247, - -6.797855302295221 - ], - [ - 39.22679477506837, - -6.797883580670773 - ], - [ - 39.21886584724193, - -6.796354991252584 - ], - [ - 39.21789760196279, - -6.800821422455203 - ], - [ - 39.21585912856685, - -6.802696774914448 - ], - [ - 39.2146774574239, - -6.808974568223004 - ], - [ - 39.21453136175979, - -6.809102537362755 - ], - [ - 39.21433909072671, - -6.809236085323197 - ], - [ - 39.213911464788005, - -6.809502598801659 - ], - [ - 39.21384943878973, - -6.809510517136742 - ], - [ - 39.212327864627525, - -6.809201572001297 - ], - [ - 39.21152919667973, - -6.808359253694025 - ] - ] - ], - "type": "Polygon" - }, - "bbox": [ - 39.20390891675323, - -6.809511989589884, - 39.2270869431941, - -6.783684392169557 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "353093", + "properties": { + "area": "dar", + "license": "CC-BY-4.0", + "datetime": "2015-04-20T00:00:00Z" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "geometry": { + "coordinates": [ + [ + [ + 39.21152919667973, + -6.808359253694025 + ], + [ + 39.21101071619515, + -6.80780969783032 + ], + [ + 39.2108730885634, + -6.806774452292519 + ], + [ + 39.20942360688795, + -6.80495789295139 + ], + [ + 39.20849433161743, + -6.804654136577633 + ], + [ + 39.20787596866212, + -6.803293387986344 + ], + [ + 39.20635028282986, + -6.80279870007748 + ], + [ + 39.2046107249861, + -6.795381424410041 + ], + [ + 39.20391600733412, + -6.79149776634182 + ], + [ + 39.20390908985627, + -6.791383173329291 + ], + [ + 39.20496051556537, + -6.7866740661368175 + ], + [ + 39.20505620172756, + -6.786303447012387 + ], + [ + 39.20621306671285, + -6.785058576896908 + ], + [ + 39.20929283360648, + -6.783684457665884 + ], + [ + 39.209550980241275, + -6.783726455597161 + ], + [ + 39.213536684353556, + -6.784551417830786 + ], + [ + 39.21258418889021, + -6.789322183261566 + ], + [ + 39.2163274162412, + -6.790171293774371 + ], + [ + 39.21759522944233, + -6.791810729353808 + ], + [ + 39.22088166017734, + -6.7926145242067575 + ], + [ + 39.22094061195484, + -6.792658437353369 + ], + [ + 39.22238742900873, + -6.794159377815079 + ], + [ + 39.22616044436698, + -6.795158821931178 + ], + [ + 39.22707373283919, + -6.796048913257977 + ], + [ + 39.22708687129574, + -6.796117385555728 + ], + [ + 39.227083424855664, + -6.796231104782896 + ], + [ + 39.22701001344086, + -6.79668679086265 + ], + [ + 39.22681107485247, + -6.797855302295221 + ], + [ + 39.22679477506837, + -6.797883580670773 + ], + [ + 39.21886584724193, + -6.796354991252584 + ], + [ + 39.21789760196279, + -6.800821422455203 + ], + [ + 39.21585912856685, + -6.802696774914448 + ], + [ + 39.2146774574239, + -6.808974568223004 + ], + [ + 39.21453136175979, + -6.809102537362755 + ], + [ + 39.21433909072671, + -6.809236085323197 + ], + [ + 39.213911464788005, + -6.809502598801659 + ], + [ + 39.21384943878973, + -6.809510517136742 + ], + [ + 39.212327864627525, + -6.809201572001297 + ], + [ + 39.21152919667973, + -6.808359253694025 + ] + ] + ], + "type": "Polygon" }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "image": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/dar/353093/353093.tif", - "type": "image/tiff; application=geotiff; profile=cloud-optimized", - "title": "GeoTIFF" - } - }, - "collection": "dar" + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "image": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/dar/353093/353093.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "GeoTIFF" + } + }, + "bbox": [ + 39.20390891675323, + -6.809511989589884, + 39.2270869431941, + -6.783684392169557 + ], + "stac_extensions": [], + "collection": "dar" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/dar/42f235-labels/42f235-labels.json b/tests/data-files/catalogs/test-case-4/dar/42f235-labels/42f235-labels.json index 7ea037593..670590586 100644 --- a/tests/data-files/catalogs/test-case-4/dar/42f235-labels/42f235-labels.json +++ b/tests/data-files/catalogs/test-case-4/dar/42f235-labels/42f235-labels.json @@ -1,855 +1,856 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "42f235-labels", - "properties": { - "label:description": "Geojson building labels for scene 42f235", - "area": "dar", - "label:type": "vector", - "label:properties": [ - "building" - ], - "label:overviews": [ - { - "property_key": "building", - "counts": [ - { - "name": "yes", - "count": 38011 - } - ] - } - ], - "license": "ODbL-1.0", - "datetime": "2017-11-01T00:00:00Z", - "label:classes": [ - { - "name": "building", - "classes": [ - "yes" - ] - } - ] - }, - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 39.249113885000924, - -6.830281768837318 - ], - [ - 39.24884161123377, - -6.828887292275093 - ], - [ - 39.24871852862772, - -6.826210688475486 - ], - [ - 39.24873780887967, - -6.826104043462706 - ], - [ - 39.24871518124407, - -6.826095666463732 - ], - [ - 39.24876108061556, - -6.825838559040912 - ], - [ - 39.248745334613886, - -6.825824622762926 - ], - [ - 39.24883372959313, - -6.825108372989363 - ], - [ - 39.24881466651106, - -6.825100724860026 - ], - [ - 39.248823648081135, - -6.825021263999036 - ], - [ - 39.24878829196981, - -6.824964024555612 - ], - [ - 39.24875880383777, - -6.823975764750708 - ], - [ - 39.248614822687124, - -6.823955191386981 - ], - [ - 39.24852566077328, - -6.822015378803604 - ], - [ - 39.24847267302938, - -6.817448633758215 - ], - [ - 39.24852805358732, - -6.817447536777786 - ], - [ - 39.24852785202801, - -6.817334983971412 - ], - [ - 39.24851981536032, - -6.817052344829385 - ], - [ - 39.24850867395349, - -6.817040674531265 - ], - [ - 39.248462246290046, - -6.816355584534947 - ], - [ - 39.2484489815814, - -6.814858967526715 - ], - [ - 39.24857555480819, - -6.812582295545642 - ], - [ - 39.249003427800226, - -6.81250520642257 - ], - [ - 39.24898887783278, - -6.81234399560838 - ], - [ - 39.24896866449714, - -6.812339800430215 - ], - [ - 39.248924971349844, - -6.812068805181685 - ], - [ - 39.24880864683033, - -6.812098011765998 - ], - [ - 39.248778859104355, - -6.812074785411178 - ], - [ - 39.248719320462236, - -6.812093089498146 - ], - [ - 39.24861449191581, - -6.811914273108745 - ], - [ - 39.24889679656208, - -6.807117076678235 - ], - [ - 39.24890514165142, - -6.807103387095611 - ], - [ - 39.24895350334043, - -6.807098209917111 - ], - [ - 39.24890327231322, - -6.80700753713003 - ], - [ - 39.24907475678098, - -6.804094158740673 - ], - [ - 39.24930614048839, - -6.802705018401825 - ], - [ - 39.25081787969558, - -6.801411369325037 - ], - [ - 39.251008675447466, - -6.801297890493637 - ], - [ - 39.25320499806219, - -6.800774456159943 - ], - [ - 39.25874764808896, - -6.800811619113268 - ], - [ - 39.258786073608775, - -6.800825135486226 - ], - [ - 39.25879893597007, - -6.800813295767783 - ], - [ - 39.25895579718065, - -6.800866120225621 - ], - [ - 39.258974085499354, - -6.800814994369178 - ], - [ - 39.25902908759272, - -6.800813440425365 - ], - [ - 39.260730218645, - -6.800825015408699 - ], - [ - 39.260776088828045, - -6.800843742362178 - ], - [ - 39.26079119762641, - -6.800826328419392 - ], - [ - 39.26081964802796, - -6.80082562450859 - ], - [ - 39.26279103974784, - -6.800839018382041 - ], - [ - 39.26282408195466, - -6.800853484934448 - ], - [ - 39.26283135889312, - -6.800839827584873 - ], - [ - 39.262880469121384, - -6.800839627101004 - ], - [ - 39.2674255850371, - -6.800870658566417 - ], - [ - 39.27802431978168, - -6.801019804497031 - ], - [ - 39.28109921288827, - -6.801626688409457 - ], - [ - 39.28154897125957, - -6.802640253929808 - ], - [ - 39.281838163359225, - -6.803552989812799 - ], - [ - 39.28188220517211, - -6.804654362572848 - ], - [ - 39.28174842361446, - -6.804677677457344 - ], - [ - 39.2818422399688, - -6.804884685465061 - ], - [ - 39.28184158489463, - -6.804910067132295 - ], - [ - 39.281821768102056, - -6.805041729452175 - ], - [ - 39.28176132590204, - -6.805084810716516 - ], - [ - 39.28170218244199, - -6.805103501195034 - ], - [ - 39.28169704386786, - -6.805132894893024 - ], - [ - 39.28180979330479, - -6.805157268210907 - ], - [ - 39.2818006803067, - -6.805121275486576 - ], - [ - 39.28181210517936, - -6.80511328337132 - ], - [ - 39.28183808958605, - -6.805147777380223 - ], - [ - 39.28182612681898, - -6.805160810113123 - ], - [ - 39.281869847721794, - -6.805173622049742 - ], - [ - 39.28190633249704, - -6.805434077918824 - ], - [ - 39.281867601400805, - -6.805514017050015 - ], - [ - 39.28192556234148, - -6.805708808637539 - ], - [ - 39.282005671645834, - -6.807691339680273 - ], - [ - 39.28199943605757, - -6.807706273438956 - ], - [ - 39.28195533204774, - -6.807710185868851 - ], - [ - 39.28197796547748, - -6.807757364213221 - ], - [ - 39.28200883331969, - -6.807773047276546 - ], - [ - 39.282023019900635, - -6.808121846172164 - ], - [ - 39.282018245286956, - -6.808137714081887 - ], - [ - 39.28195634628146, - -6.808155853630331 - ], - [ - 39.28199944963618, - -6.808297352946989 - ], - [ - 39.28195181634511, - -6.80831680607628 - ], - [ - 39.28198882234564, - -6.808428329895218 - ], - [ - 39.282024499646646, - -6.808439547675201 - ], - [ - 39.2820369889843, - -6.808470622842016 - ], - [ - 39.282085070245415, - -6.80965589504642 - ], - [ - 39.28206930768178, - -6.809724680899688 - ], - [ - 39.28197604437582, - -6.809748107963618 - ], - [ - 39.28203658454973, - -6.809955641744993 - ], - [ - 39.28196678950842, - -6.809989174710164 - ], - [ - 39.28200076660283, - -6.809985427370294 - ], - [ - 39.282019456410715, - -6.810031452338205 - ], - [ - 39.28204972047887, - -6.810016433350921 - ], - [ - 39.28210025147508, - -6.810051116848933 - ], - [ - 39.28208152179033, - -6.810068511252877 - ], - [ - 39.28205676485107, - -6.810065686630296 - ], - [ - 39.28204318497603, - -6.810045394638353 - ], - [ - 39.28202652462141, - -6.810054127516999 - ], - [ - 39.28211105481988, - -6.810310955878061 - ], - [ - 39.28213177566899, - -6.810811361103773 - ], - [ - 39.2821320509615, - -6.811580168174703 - ], - [ - 39.28196212984445, - -6.81161380520041 - ], - [ - 39.28196324177067, - -6.811640766913107 - ], - [ - 39.28192745818485, - -6.811648558462478 - ], - [ - 39.28212985550575, - -6.812080389087699 - ], - [ - 39.282133235128924, - -6.812183754967635 - ], - [ - 39.28213536630495, - -6.814779570405246 - ], - [ - 39.28197188899595, - -6.814791111511188 - ], - [ - 39.28197562893217, - -6.814835126510185 - ], - [ - 39.28191559123218, - -6.814843893517796 - ], - [ - 39.28193291303407, - -6.814921201695186 - ], - [ - 39.2819237543314, - -6.81493645195515 - ], - [ - 39.28204752072457, - -6.815465796642168 - ], - [ - 39.28203191583694, - -6.81547995693839 - ], - [ - 39.28213668715259, - -6.815839528151637 - ], - [ - 39.282139961134924, - -6.82031295339354 - ], - [ - 39.28212156668364, - -6.820323535094702 - ], - [ - 39.282083452011165, - -6.820429480387951 - ], - [ - 39.2820979897894, - -6.820427505393686 - ], - [ - 39.28210159597546, - -6.820388271297486 - ], - [ - 39.28213848063579, - -6.820389430950556 - ], - [ - 39.28214024571535, - -6.820799338145754 - ], - [ - 39.28210969828819, - -6.82171079200005 - ], - [ - 39.28195130955397, - -6.821742318527214 - ], - [ - 39.2819621025051, - -6.821764513094872 - ], - [ - 39.2820301392614, - -6.821789494080819 - ], - [ - 39.28210146084555, - -6.821945651724311 - ], - [ - 39.28207040706704, - -6.822893035225293 - ], - [ - 39.28202470254904, - -6.822934919676698 - ], - [ - 39.28202109729184, - -6.822974817458986 - ], - [ - 39.28200660408125, - -6.822974998241254 - ], - [ - 39.28206129036098, - -6.823007414800348 - ], - [ - 39.28206592657398, - -6.82302820749804 - ], - [ - 39.28202064253523, - -6.824380481803342 - ], - [ - 39.281981544474924, - -6.824398479223031 - ], - [ - 39.28198457446479, - -6.824409215900801 - ], - [ - 39.282007489634466, - -6.824391763586223 - ], - [ - 39.28202004299919, - -6.824405229294226 - ], - [ - 39.28201771588613, - -6.824465696907729 - ], - [ - 39.2819989849681, - -6.824470675281921 - ], - [ - 39.28201551904975, - -6.82454063096336 - ], - [ - 39.281970927484814, - -6.82587821531825 - ], - [ - 39.28195816743914, - -6.825889196972958 - ], - [ - 39.281549414229346, - -6.825907201573767 - ], - [ - 39.281536280695086, - -6.825977236091125 - ], - [ - 39.28151348717576, - -6.825989987664138 - ], - [ - 39.281654833408055, - -6.826537198414719 - ], - [ - 39.281616883627095, - -6.826665413771542 - ], - [ - 39.28166851162509, - -6.826681587515675 - ], - [ - 39.28170780397164, - -6.826934383460437 - ], - [ - 39.28164411603734, - -6.827064614531757 - ], - [ - 39.28157087941187, - -6.827067306789635 - ], - [ - 39.28158180421901, - -6.827250179303952 - ], - [ - 39.281652062880944, - -6.827212345943851 - ], - [ - 39.281661122188204, - -6.827254722874545 - ], - [ - 39.28186998371223, - -6.827299194884757 - ], - [ - 39.281879687390074, - -6.827327728734536 - ], - [ - 39.28192180185399, - -6.827334112070436 - ], - [ - 39.28182547653564, - -6.830240875372596 - ], - [ - 39.281807154293304, - -6.830374916457267 - ], - [ - 39.28171581577605, - -6.830474463144125 - ], - [ - 39.280358440001955, - -6.831172974478872 - ], - [ - 39.27736178031955, - -6.832006509610587 - ], - [ - 39.27676315251181, - -6.832050277630079 - ], - [ - 39.26584625859982, - -6.832170132981521 - ], - [ - 39.249536580127696, - -6.832021721810229 - ], - [ - 39.24950165016739, - -6.831993443914228 - ], - [ - 39.24941999314367, - -6.831844309519701 - ], - [ - 39.249113885000924, - -6.830281768837318 - ] + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "42f235-labels", + "properties": { + "label:description": "Geojson building labels for scene 42f235", + "area": "dar", + "label:type": "vector", + "label:properties": [ + "building" ], - [ - [ - 39.282098666051674, - -6.82047613815803 - ], - [ - 39.28209567183957, - -6.820469231737571 - ], - [ - 39.2820671143494, - -6.820462273624464 - ], - [ - 39.28207043911302, - -6.820476154654143 - ], - [ - 39.282098666051674, - -6.82047613815803 - ] + "label:overviews": [ + { + "property_key": "building", + "counts": [ + { + "name": "yes", + "count": 38011 + } + ] + } ], - [ - [ - 39.28167616089308, - -6.805130308068077 - ], - [ - 39.28167391746429, - -6.805111703716632 - ], - [ - 39.28164656952175, - -6.805120400817218 - ], - [ - 39.28164943969814, - -6.805125077344592 - ], - [ - 39.28167616089308, - -6.805130308068077 - ] - ] - ], - [ - [ - [ - 39.281860334465605, - -6.805146602602473 - ], - [ - 39.281870004608614, - -6.80515718683268 - ], - [ - 39.28185880151722, - -6.805166623631171 - ], - [ - 39.28185067602336, - -6.805156082059399 - ], - [ - 39.281860334465605, - -6.805146602602473 - ] + "license": "ODbL-1.0", + "datetime": "2017-11-01T00:00:00Z", + "label:classes": [ + { + "name": "building", + "classes": [ + "yes" + ] + } ] - ], - [ - [ - [ - 39.281777446400945, - -6.805088153206213 - ], - [ - 39.281790280725005, - -6.805110130150037 - ], - [ - 39.28177175352243, - -6.805119220116509 - ], - [ - 39.28176463641958, - -6.805107930094916 - ], - [ - 39.281777446400945, - -6.805088153206213 - ] + }, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [ + 39.249113885000924, + -6.830281768837318 + ], + [ + 39.24884161123377, + -6.828887292275093 + ], + [ + 39.24871852862772, + -6.826210688475486 + ], + [ + 39.24873780887967, + -6.826104043462706 + ], + [ + 39.24871518124407, + -6.826095666463732 + ], + [ + 39.24876108061556, + -6.825838559040912 + ], + [ + 39.248745334613886, + -6.825824622762926 + ], + [ + 39.24883372959313, + -6.825108372989363 + ], + [ + 39.24881466651106, + -6.825100724860026 + ], + [ + 39.248823648081135, + -6.825021263999036 + ], + [ + 39.24878829196981, + -6.824964024555612 + ], + [ + 39.24875880383777, + -6.823975764750708 + ], + [ + 39.248614822687124, + -6.823955191386981 + ], + [ + 39.24852566077328, + -6.822015378803604 + ], + [ + 39.24847267302938, + -6.817448633758215 + ], + [ + 39.24852805358732, + -6.817447536777786 + ], + [ + 39.24852785202801, + -6.817334983971412 + ], + [ + 39.24851981536032, + -6.817052344829385 + ], + [ + 39.24850867395349, + -6.817040674531265 + ], + [ + 39.248462246290046, + -6.816355584534947 + ], + [ + 39.2484489815814, + -6.814858967526715 + ], + [ + 39.24857555480819, + -6.812582295545642 + ], + [ + 39.249003427800226, + -6.81250520642257 + ], + [ + 39.24898887783278, + -6.81234399560838 + ], + [ + 39.24896866449714, + -6.812339800430215 + ], + [ + 39.248924971349844, + -6.812068805181685 + ], + [ + 39.24880864683033, + -6.812098011765998 + ], + [ + 39.248778859104355, + -6.812074785411178 + ], + [ + 39.248719320462236, + -6.812093089498146 + ], + [ + 39.24861449191581, + -6.811914273108745 + ], + [ + 39.24889679656208, + -6.807117076678235 + ], + [ + 39.24890514165142, + -6.807103387095611 + ], + [ + 39.24895350334043, + -6.807098209917111 + ], + [ + 39.24890327231322, + -6.80700753713003 + ], + [ + 39.24907475678098, + -6.804094158740673 + ], + [ + 39.24930614048839, + -6.802705018401825 + ], + [ + 39.25081787969558, + -6.801411369325037 + ], + [ + 39.251008675447466, + -6.801297890493637 + ], + [ + 39.25320499806219, + -6.800774456159943 + ], + [ + 39.25874764808896, + -6.800811619113268 + ], + [ + 39.258786073608775, + -6.800825135486226 + ], + [ + 39.25879893597007, + -6.800813295767783 + ], + [ + 39.25895579718065, + -6.800866120225621 + ], + [ + 39.258974085499354, + -6.800814994369178 + ], + [ + 39.25902908759272, + -6.800813440425365 + ], + [ + 39.260730218645, + -6.800825015408699 + ], + [ + 39.260776088828045, + -6.800843742362178 + ], + [ + 39.26079119762641, + -6.800826328419392 + ], + [ + 39.26081964802796, + -6.80082562450859 + ], + [ + 39.26279103974784, + -6.800839018382041 + ], + [ + 39.26282408195466, + -6.800853484934448 + ], + [ + 39.26283135889312, + -6.800839827584873 + ], + [ + 39.262880469121384, + -6.800839627101004 + ], + [ + 39.2674255850371, + -6.800870658566417 + ], + [ + 39.27802431978168, + -6.801019804497031 + ], + [ + 39.28109921288827, + -6.801626688409457 + ], + [ + 39.28154897125957, + -6.802640253929808 + ], + [ + 39.281838163359225, + -6.803552989812799 + ], + [ + 39.28188220517211, + -6.804654362572848 + ], + [ + 39.28174842361446, + -6.804677677457344 + ], + [ + 39.2818422399688, + -6.804884685465061 + ], + [ + 39.28184158489463, + -6.804910067132295 + ], + [ + 39.281821768102056, + -6.805041729452175 + ], + [ + 39.28176132590204, + -6.805084810716516 + ], + [ + 39.28170218244199, + -6.805103501195034 + ], + [ + 39.28169704386786, + -6.805132894893024 + ], + [ + 39.28180979330479, + -6.805157268210907 + ], + [ + 39.2818006803067, + -6.805121275486576 + ], + [ + 39.28181210517936, + -6.80511328337132 + ], + [ + 39.28183808958605, + -6.805147777380223 + ], + [ + 39.28182612681898, + -6.805160810113123 + ], + [ + 39.281869847721794, + -6.805173622049742 + ], + [ + 39.28190633249704, + -6.805434077918824 + ], + [ + 39.281867601400805, + -6.805514017050015 + ], + [ + 39.28192556234148, + -6.805708808637539 + ], + [ + 39.282005671645834, + -6.807691339680273 + ], + [ + 39.28199943605757, + -6.807706273438956 + ], + [ + 39.28195533204774, + -6.807710185868851 + ], + [ + 39.28197796547748, + -6.807757364213221 + ], + [ + 39.28200883331969, + -6.807773047276546 + ], + [ + 39.282023019900635, + -6.808121846172164 + ], + [ + 39.282018245286956, + -6.808137714081887 + ], + [ + 39.28195634628146, + -6.808155853630331 + ], + [ + 39.28199944963618, + -6.808297352946989 + ], + [ + 39.28195181634511, + -6.80831680607628 + ], + [ + 39.28198882234564, + -6.808428329895218 + ], + [ + 39.282024499646646, + -6.808439547675201 + ], + [ + 39.2820369889843, + -6.808470622842016 + ], + [ + 39.282085070245415, + -6.80965589504642 + ], + [ + 39.28206930768178, + -6.809724680899688 + ], + [ + 39.28197604437582, + -6.809748107963618 + ], + [ + 39.28203658454973, + -6.809955641744993 + ], + [ + 39.28196678950842, + -6.809989174710164 + ], + [ + 39.28200076660283, + -6.809985427370294 + ], + [ + 39.282019456410715, + -6.810031452338205 + ], + [ + 39.28204972047887, + -6.810016433350921 + ], + [ + 39.28210025147508, + -6.810051116848933 + ], + [ + 39.28208152179033, + -6.810068511252877 + ], + [ + 39.28205676485107, + -6.810065686630296 + ], + [ + 39.28204318497603, + -6.810045394638353 + ], + [ + 39.28202652462141, + -6.810054127516999 + ], + [ + 39.28211105481988, + -6.810310955878061 + ], + [ + 39.28213177566899, + -6.810811361103773 + ], + [ + 39.2821320509615, + -6.811580168174703 + ], + [ + 39.28196212984445, + -6.81161380520041 + ], + [ + 39.28196324177067, + -6.811640766913107 + ], + [ + 39.28192745818485, + -6.811648558462478 + ], + [ + 39.28212985550575, + -6.812080389087699 + ], + [ + 39.282133235128924, + -6.812183754967635 + ], + [ + 39.28213536630495, + -6.814779570405246 + ], + [ + 39.28197188899595, + -6.814791111511188 + ], + [ + 39.28197562893217, + -6.814835126510185 + ], + [ + 39.28191559123218, + -6.814843893517796 + ], + [ + 39.28193291303407, + -6.814921201695186 + ], + [ + 39.2819237543314, + -6.81493645195515 + ], + [ + 39.28204752072457, + -6.815465796642168 + ], + [ + 39.28203191583694, + -6.81547995693839 + ], + [ + 39.28213668715259, + -6.815839528151637 + ], + [ + 39.282139961134924, + -6.82031295339354 + ], + [ + 39.28212156668364, + -6.820323535094702 + ], + [ + 39.282083452011165, + -6.820429480387951 + ], + [ + 39.2820979897894, + -6.820427505393686 + ], + [ + 39.28210159597546, + -6.820388271297486 + ], + [ + 39.28213848063579, + -6.820389430950556 + ], + [ + 39.28214024571535, + -6.820799338145754 + ], + [ + 39.28210969828819, + -6.82171079200005 + ], + [ + 39.28195130955397, + -6.821742318527214 + ], + [ + 39.2819621025051, + -6.821764513094872 + ], + [ + 39.2820301392614, + -6.821789494080819 + ], + [ + 39.28210146084555, + -6.821945651724311 + ], + [ + 39.28207040706704, + -6.822893035225293 + ], + [ + 39.28202470254904, + -6.822934919676698 + ], + [ + 39.28202109729184, + -6.822974817458986 + ], + [ + 39.28200660408125, + -6.822974998241254 + ], + [ + 39.28206129036098, + -6.823007414800348 + ], + [ + 39.28206592657398, + -6.82302820749804 + ], + [ + 39.28202064253523, + -6.824380481803342 + ], + [ + 39.281981544474924, + -6.824398479223031 + ], + [ + 39.28198457446479, + -6.824409215900801 + ], + [ + 39.282007489634466, + -6.824391763586223 + ], + [ + 39.28202004299919, + -6.824405229294226 + ], + [ + 39.28201771588613, + -6.824465696907729 + ], + [ + 39.2819989849681, + -6.824470675281921 + ], + [ + 39.28201551904975, + -6.82454063096336 + ], + [ + 39.281970927484814, + -6.82587821531825 + ], + [ + 39.28195816743914, + -6.825889196972958 + ], + [ + 39.281549414229346, + -6.825907201573767 + ], + [ + 39.281536280695086, + -6.825977236091125 + ], + [ + 39.28151348717576, + -6.825989987664138 + ], + [ + 39.281654833408055, + -6.826537198414719 + ], + [ + 39.281616883627095, + -6.826665413771542 + ], + [ + 39.28166851162509, + -6.826681587515675 + ], + [ + 39.28170780397164, + -6.826934383460437 + ], + [ + 39.28164411603734, + -6.827064614531757 + ], + [ + 39.28157087941187, + -6.827067306789635 + ], + [ + 39.28158180421901, + -6.827250179303952 + ], + [ + 39.281652062880944, + -6.827212345943851 + ], + [ + 39.281661122188204, + -6.827254722874545 + ], + [ + 39.28186998371223, + -6.827299194884757 + ], + [ + 39.281879687390074, + -6.827327728734536 + ], + [ + 39.28192180185399, + -6.827334112070436 + ], + [ + 39.28182547653564, + -6.830240875372596 + ], + [ + 39.281807154293304, + -6.830374916457267 + ], + [ + 39.28171581577605, + -6.830474463144125 + ], + [ + 39.280358440001955, + -6.831172974478872 + ], + [ + 39.27736178031955, + -6.832006509610587 + ], + [ + 39.27676315251181, + -6.832050277630079 + ], + [ + 39.26584625859982, + -6.832170132981521 + ], + [ + 39.249536580127696, + -6.832021721810229 + ], + [ + 39.24950165016739, + -6.831993443914228 + ], + [ + 39.24941999314367, + -6.831844309519701 + ], + [ + 39.249113885000924, + -6.830281768837318 + ] + ], + [ + [ + 39.282098666051674, + -6.82047613815803 + ], + [ + 39.28209567183957, + -6.820469231737571 + ], + [ + 39.2820671143494, + -6.820462273624464 + ], + [ + 39.28207043911302, + -6.820476154654143 + ], + [ + 39.282098666051674, + -6.82047613815803 + ] + ], + [ + [ + 39.28167616089308, + -6.805130308068077 + ], + [ + 39.28167391746429, + -6.805111703716632 + ], + [ + 39.28164656952175, + -6.805120400817218 + ], + [ + 39.28164943969814, + -6.805125077344592 + ], + [ + 39.28167616089308, + -6.805130308068077 + ] + ] + ], + [ + [ + [ + 39.281860334465605, + -6.805146602602473 + ], + [ + 39.281870004608614, + -6.80515718683268 + ], + [ + 39.28185880151722, + -6.805166623631171 + ], + [ + 39.28185067602336, + -6.805156082059399 + ], + [ + 39.281860334465605, + -6.805146602602473 + ] + ] + ], + [ + [ + [ + 39.281777446400945, + -6.805088153206213 + ], + [ + 39.281790280725005, + -6.805110130150037 + ], + [ + 39.28177175352243, + -6.805119220116509 + ], + [ + 39.28176463641958, + -6.805107930094916 + ], + [ + 39.281777446400945, + -6.805088153206213 + ] + ] + ] ] - ] - ] - }, - "bbox": [ - 39.2484489815814, - -6.832170132981521, - 39.28214024571535, - -6.800774407651622 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "labels": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/dar/42f235-labels/42f235.geojson", + "type": "application/geo+json" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "labels": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/dar/42f235-labels/42f235.geojson", - "type": "application/geo+json" - } - }, - "stac_extensions": [ - "label" - ] + "bbox": [ + 39.2484489815814, + -6.832170132981521, + 39.28214024571535, + -6.800774407651622 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "dar" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/dar/42f235/42f235.json b/tests/data-files/catalogs/test-case-4/dar/42f235/42f235.json index 6c2e4997b..18ffed606 100644 --- a/tests/data-files/catalogs/test-case-4/dar/42f235/42f235.json +++ b/tests/data-files/catalogs/test-case-4/dar/42f235/42f235.json @@ -1,830 +1,831 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "42f235", - "properties": { - "area": "dar", - "license": "ODbL-1.0", - "datetime": "2017-11-01T00:00:00Z" - }, - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 39.249113885000924, - -6.830281768837318 - ], - [ - 39.24884161123377, - -6.828887292275093 - ], - [ - 39.24871852862772, - -6.826210688475486 - ], - [ - 39.24873780887967, - -6.826104043462706 - ], - [ - 39.24871518124407, - -6.826095666463732 - ], - [ - 39.24876108061556, - -6.825838559040912 - ], - [ - 39.248745334613886, - -6.825824622762926 - ], - [ - 39.24883372959313, - -6.825108372989363 - ], - [ - 39.24881466651106, - -6.825100724860026 - ], - [ - 39.248823648081135, - -6.825021263999036 - ], - [ - 39.24878829196981, - -6.824964024555612 - ], - [ - 39.24875880383777, - -6.823975764750708 - ], - [ - 39.248614822687124, - -6.823955191386981 - ], - [ - 39.24852566077328, - -6.822015378803604 - ], - [ - 39.24847267302938, - -6.817448633758215 - ], - [ - 39.24852805358732, - -6.817447536777786 - ], - [ - 39.24852785202801, - -6.817334983971412 - ], - [ - 39.24851981536032, - -6.817052344829385 - ], - [ - 39.24850867395349, - -6.817040674531265 - ], - [ - 39.248462246290046, - -6.816355584534947 - ], - [ - 39.2484489815814, - -6.814858967526715 - ], - [ - 39.24857555480819, - -6.812582295545642 - ], - [ - 39.249003427800226, - -6.81250520642257 - ], - [ - 39.24898887783278, - -6.81234399560838 - ], - [ - 39.24896866449714, - -6.812339800430215 - ], - [ - 39.248924971349844, - -6.812068805181685 - ], - [ - 39.24880864683033, - -6.812098011765998 - ], - [ - 39.248778859104355, - -6.812074785411178 - ], - [ - 39.248719320462236, - -6.812093089498146 - ], - [ - 39.24861449191581, - -6.811914273108745 - ], - [ - 39.24889679656208, - -6.807117076678235 - ], - [ - 39.24890514165142, - -6.807103387095611 - ], - [ - 39.24895350334043, - -6.807098209917111 - ], - [ - 39.24890327231322, - -6.80700753713003 - ], - [ - 39.24907475678098, - -6.804094158740673 - ], - [ - 39.24930614048839, - -6.802705018401825 - ], - [ - 39.25081787969558, - -6.801411369325037 - ], - [ - 39.251008675447466, - -6.801297890493637 - ], - [ - 39.25320499806219, - -6.800774456159943 - ], - [ - 39.25874764808896, - -6.800811619113268 - ], - [ - 39.258786073608775, - -6.800825135486226 - ], - [ - 39.25879893597007, - -6.800813295767783 - ], - [ - 39.25895579718065, - -6.800866120225621 - ], - [ - 39.258974085499354, - -6.800814994369178 - ], - [ - 39.25902908759272, - -6.800813440425365 - ], - [ - 39.260730218645, - -6.800825015408699 - ], - [ - 39.260776088828045, - -6.800843742362178 - ], - [ - 39.26079119762641, - -6.800826328419392 - ], - [ - 39.26081964802796, - -6.80082562450859 - ], - [ - 39.26279103974784, - -6.800839018382041 - ], - [ - 39.26282408195466, - -6.800853484934448 - ], - [ - 39.26283135889312, - -6.800839827584873 - ], - [ - 39.262880469121384, - -6.800839627101004 - ], - [ - 39.2674255850371, - -6.800870658566417 - ], - [ - 39.27802431978168, - -6.801019804497031 - ], - [ - 39.28109921288827, - -6.801626688409457 - ], - [ - 39.28154897125957, - -6.802640253929808 - ], - [ - 39.281838163359225, - -6.803552989812799 - ], - [ - 39.28188220517211, - -6.804654362572848 - ], - [ - 39.28174842361446, - -6.804677677457344 - ], - [ - 39.2818422399688, - -6.804884685465061 - ], - [ - 39.28184158489463, - -6.804910067132295 - ], - [ - 39.281821768102056, - -6.805041729452175 - ], - [ - 39.28176132590204, - -6.805084810716516 - ], - [ - 39.28170218244199, - -6.805103501195034 - ], - [ - 39.28169704386786, - -6.805132894893024 - ], - [ - 39.28180979330479, - -6.805157268210907 - ], - [ - 39.2818006803067, - -6.805121275486576 - ], - [ - 39.28181210517936, - -6.80511328337132 - ], - [ - 39.28183808958605, - -6.805147777380223 - ], - [ - 39.28182612681898, - -6.805160810113123 - ], - [ - 39.281869847721794, - -6.805173622049742 - ], - [ - 39.28190633249704, - -6.805434077918824 - ], - [ - 39.281867601400805, - -6.805514017050015 - ], - [ - 39.28192556234148, - -6.805708808637539 - ], - [ - 39.282005671645834, - -6.807691339680273 - ], - [ - 39.28199943605757, - -6.807706273438956 - ], - [ - 39.28195533204774, - -6.807710185868851 - ], - [ - 39.28197796547748, - -6.807757364213221 - ], - [ - 39.28200883331969, - -6.807773047276546 - ], - [ - 39.282023019900635, - -6.808121846172164 - ], - [ - 39.282018245286956, - -6.808137714081887 - ], - [ - 39.28195634628146, - -6.808155853630331 - ], - [ - 39.28199944963618, - -6.808297352946989 - ], - [ - 39.28195181634511, - -6.80831680607628 - ], - [ - 39.28198882234564, - -6.808428329895218 - ], - [ - 39.282024499646646, - -6.808439547675201 - ], - [ - 39.2820369889843, - -6.808470622842016 - ], - [ - 39.282085070245415, - -6.80965589504642 - ], - [ - 39.28206930768178, - -6.809724680899688 - ], - [ - 39.28197604437582, - -6.809748107963618 - ], - [ - 39.28203658454973, - -6.809955641744993 - ], - [ - 39.28196678950842, - -6.809989174710164 - ], - [ - 39.28200076660283, - -6.809985427370294 - ], - [ - 39.282019456410715, - -6.810031452338205 - ], - [ - 39.28204972047887, - -6.810016433350921 - ], - [ - 39.28210025147508, - -6.810051116848933 - ], - [ - 39.28208152179033, - -6.810068511252877 - ], - [ - 39.28205676485107, - -6.810065686630296 - ], - [ - 39.28204318497603, - -6.810045394638353 - ], - [ - 39.28202652462141, - -6.810054127516999 - ], - [ - 39.28211105481988, - -6.810310955878061 - ], - [ - 39.28213177566899, - -6.810811361103773 - ], - [ - 39.2821320509615, - -6.811580168174703 - ], - [ - 39.28196212984445, - -6.81161380520041 - ], - [ - 39.28196324177067, - -6.811640766913107 - ], - [ - 39.28192745818485, - -6.811648558462478 - ], - [ - 39.28212985550575, - -6.812080389087699 - ], - [ - 39.282133235128924, - -6.812183754967635 - ], - [ - 39.28213536630495, - -6.814779570405246 - ], - [ - 39.28197188899595, - -6.814791111511188 - ], - [ - 39.28197562893217, - -6.814835126510185 - ], - [ - 39.28191559123218, - -6.814843893517796 - ], - [ - 39.28193291303407, - -6.814921201695186 - ], - [ - 39.2819237543314, - -6.81493645195515 - ], - [ - 39.28204752072457, - -6.815465796642168 - ], - [ - 39.28203191583694, - -6.81547995693839 - ], - [ - 39.28213668715259, - -6.815839528151637 - ], - [ - 39.282139961134924, - -6.82031295339354 - ], - [ - 39.28212156668364, - -6.820323535094702 - ], - [ - 39.282083452011165, - -6.820429480387951 - ], - [ - 39.2820979897894, - -6.820427505393686 - ], - [ - 39.28210159597546, - -6.820388271297486 - ], - [ - 39.28213848063579, - -6.820389430950556 - ], - [ - 39.28214024571535, - -6.820799338145754 - ], - [ - 39.28210969828819, - -6.82171079200005 - ], - [ - 39.28195130955397, - -6.821742318527214 - ], - [ - 39.2819621025051, - -6.821764513094872 - ], - [ - 39.2820301392614, - -6.821789494080819 - ], - [ - 39.28210146084555, - -6.821945651724311 - ], - [ - 39.28207040706704, - -6.822893035225293 - ], - [ - 39.28202470254904, - -6.822934919676698 - ], - [ - 39.28202109729184, - -6.822974817458986 - ], - [ - 39.28200660408125, - -6.822974998241254 - ], - [ - 39.28206129036098, - -6.823007414800348 - ], - [ - 39.28206592657398, - -6.82302820749804 - ], - [ - 39.28202064253523, - -6.824380481803342 - ], - [ - 39.281981544474924, - -6.824398479223031 - ], - [ - 39.28198457446479, - -6.824409215900801 - ], - [ - 39.282007489634466, - -6.824391763586223 - ], - [ - 39.28202004299919, - -6.824405229294226 - ], - [ - 39.28201771588613, - -6.824465696907729 - ], - [ - 39.2819989849681, - -6.824470675281921 - ], - [ - 39.28201551904975, - -6.82454063096336 - ], - [ - 39.281970927484814, - -6.82587821531825 - ], - [ - 39.28195816743914, - -6.825889196972958 - ], - [ - 39.281549414229346, - -6.825907201573767 - ], - [ - 39.281536280695086, - -6.825977236091125 - ], - [ - 39.28151348717576, - -6.825989987664138 - ], - [ - 39.281654833408055, - -6.826537198414719 - ], - [ - 39.281616883627095, - -6.826665413771542 - ], - [ - 39.28166851162509, - -6.826681587515675 - ], - [ - 39.28170780397164, - -6.826934383460437 - ], - [ - 39.28164411603734, - -6.827064614531757 - ], - [ - 39.28157087941187, - -6.827067306789635 - ], - [ - 39.28158180421901, - -6.827250179303952 - ], - [ - 39.281652062880944, - -6.827212345943851 - ], - [ - 39.281661122188204, - -6.827254722874545 - ], - [ - 39.28186998371223, - -6.827299194884757 - ], - [ - 39.281879687390074, - -6.827327728734536 - ], - [ - 39.28192180185399, - -6.827334112070436 - ], - [ - 39.28182547653564, - -6.830240875372596 - ], - [ - 39.281807154293304, - -6.830374916457267 - ], - [ - 39.28171581577605, - -6.830474463144125 - ], - [ - 39.280358440001955, - -6.831172974478872 - ], - [ - 39.27736178031955, - -6.832006509610587 - ], - [ - 39.27676315251181, - -6.832050277630079 - ], - [ - 39.26584625859982, - -6.832170132981521 - ], - [ - 39.249536580127696, - -6.832021721810229 - ], - [ - 39.24950165016739, - -6.831993443914228 - ], - [ - 39.24941999314367, - -6.831844309519701 - ], - [ - 39.249113885000924, - -6.830281768837318 - ] - ], - [ - [ - 39.282098666051674, - -6.82047613815803 - ], - [ - 39.28209567183957, - -6.820469231737571 - ], - [ - 39.2820671143494, - -6.820462273624464 - ], - [ - 39.28207043911302, - -6.820476154654143 - ], - [ - 39.282098666051674, - -6.82047613815803 - ] - ], - [ - [ - 39.28167616089308, - -6.805130308068077 - ], - [ - 39.28167391746429, - -6.805111703716632 - ], - [ - 39.28164656952175, - -6.805120400817218 - ], - [ - 39.28164943969814, - -6.805125077344592 - ], - [ - 39.28167616089308, - -6.805130308068077 - ] - ] - ], - [ - [ - [ - 39.281860334465605, - -6.805146602602473 - ], - [ - 39.281870004608614, - -6.80515718683268 - ], - [ - 39.28185880151722, - -6.805166623631171 - ], - [ - 39.28185067602336, - -6.805156082059399 - ], - [ - 39.281860334465605, - -6.805146602602473 - ] - ] - ], - [ - [ - [ - 39.281777446400945, - -6.805088153206213 - ], - [ - 39.281790280725005, - -6.805110130150037 - ], - [ - 39.28177175352243, - -6.805119220116509 - ], - [ - 39.28176463641958, - -6.805107930094916 - ], - [ - 39.281777446400945, - -6.805088153206213 - ] + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "42f235", + "properties": { + "area": "dar", + "license": "ODbL-1.0", + "datetime": "2017-11-01T00:00:00Z" + }, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [ + 39.249113885000924, + -6.830281768837318 + ], + [ + 39.24884161123377, + -6.828887292275093 + ], + [ + 39.24871852862772, + -6.826210688475486 + ], + [ + 39.24873780887967, + -6.826104043462706 + ], + [ + 39.24871518124407, + -6.826095666463732 + ], + [ + 39.24876108061556, + -6.825838559040912 + ], + [ + 39.248745334613886, + -6.825824622762926 + ], + [ + 39.24883372959313, + -6.825108372989363 + ], + [ + 39.24881466651106, + -6.825100724860026 + ], + [ + 39.248823648081135, + -6.825021263999036 + ], + [ + 39.24878829196981, + -6.824964024555612 + ], + [ + 39.24875880383777, + -6.823975764750708 + ], + [ + 39.248614822687124, + -6.823955191386981 + ], + [ + 39.24852566077328, + -6.822015378803604 + ], + [ + 39.24847267302938, + -6.817448633758215 + ], + [ + 39.24852805358732, + -6.817447536777786 + ], + [ + 39.24852785202801, + -6.817334983971412 + ], + [ + 39.24851981536032, + -6.817052344829385 + ], + [ + 39.24850867395349, + -6.817040674531265 + ], + [ + 39.248462246290046, + -6.816355584534947 + ], + [ + 39.2484489815814, + -6.814858967526715 + ], + [ + 39.24857555480819, + -6.812582295545642 + ], + [ + 39.249003427800226, + -6.81250520642257 + ], + [ + 39.24898887783278, + -6.81234399560838 + ], + [ + 39.24896866449714, + -6.812339800430215 + ], + [ + 39.248924971349844, + -6.812068805181685 + ], + [ + 39.24880864683033, + -6.812098011765998 + ], + [ + 39.248778859104355, + -6.812074785411178 + ], + [ + 39.248719320462236, + -6.812093089498146 + ], + [ + 39.24861449191581, + -6.811914273108745 + ], + [ + 39.24889679656208, + -6.807117076678235 + ], + [ + 39.24890514165142, + -6.807103387095611 + ], + [ + 39.24895350334043, + -6.807098209917111 + ], + [ + 39.24890327231322, + -6.80700753713003 + ], + [ + 39.24907475678098, + -6.804094158740673 + ], + [ + 39.24930614048839, + -6.802705018401825 + ], + [ + 39.25081787969558, + -6.801411369325037 + ], + [ + 39.251008675447466, + -6.801297890493637 + ], + [ + 39.25320499806219, + -6.800774456159943 + ], + [ + 39.25874764808896, + -6.800811619113268 + ], + [ + 39.258786073608775, + -6.800825135486226 + ], + [ + 39.25879893597007, + -6.800813295767783 + ], + [ + 39.25895579718065, + -6.800866120225621 + ], + [ + 39.258974085499354, + -6.800814994369178 + ], + [ + 39.25902908759272, + -6.800813440425365 + ], + [ + 39.260730218645, + -6.800825015408699 + ], + [ + 39.260776088828045, + -6.800843742362178 + ], + [ + 39.26079119762641, + -6.800826328419392 + ], + [ + 39.26081964802796, + -6.80082562450859 + ], + [ + 39.26279103974784, + -6.800839018382041 + ], + [ + 39.26282408195466, + -6.800853484934448 + ], + [ + 39.26283135889312, + -6.800839827584873 + ], + [ + 39.262880469121384, + -6.800839627101004 + ], + [ + 39.2674255850371, + -6.800870658566417 + ], + [ + 39.27802431978168, + -6.801019804497031 + ], + [ + 39.28109921288827, + -6.801626688409457 + ], + [ + 39.28154897125957, + -6.802640253929808 + ], + [ + 39.281838163359225, + -6.803552989812799 + ], + [ + 39.28188220517211, + -6.804654362572848 + ], + [ + 39.28174842361446, + -6.804677677457344 + ], + [ + 39.2818422399688, + -6.804884685465061 + ], + [ + 39.28184158489463, + -6.804910067132295 + ], + [ + 39.281821768102056, + -6.805041729452175 + ], + [ + 39.28176132590204, + -6.805084810716516 + ], + [ + 39.28170218244199, + -6.805103501195034 + ], + [ + 39.28169704386786, + -6.805132894893024 + ], + [ + 39.28180979330479, + -6.805157268210907 + ], + [ + 39.2818006803067, + -6.805121275486576 + ], + [ + 39.28181210517936, + -6.80511328337132 + ], + [ + 39.28183808958605, + -6.805147777380223 + ], + [ + 39.28182612681898, + -6.805160810113123 + ], + [ + 39.281869847721794, + -6.805173622049742 + ], + [ + 39.28190633249704, + -6.805434077918824 + ], + [ + 39.281867601400805, + -6.805514017050015 + ], + [ + 39.28192556234148, + -6.805708808637539 + ], + [ + 39.282005671645834, + -6.807691339680273 + ], + [ + 39.28199943605757, + -6.807706273438956 + ], + [ + 39.28195533204774, + -6.807710185868851 + ], + [ + 39.28197796547748, + -6.807757364213221 + ], + [ + 39.28200883331969, + -6.807773047276546 + ], + [ + 39.282023019900635, + -6.808121846172164 + ], + [ + 39.282018245286956, + -6.808137714081887 + ], + [ + 39.28195634628146, + -6.808155853630331 + ], + [ + 39.28199944963618, + -6.808297352946989 + ], + [ + 39.28195181634511, + -6.80831680607628 + ], + [ + 39.28198882234564, + -6.808428329895218 + ], + [ + 39.282024499646646, + -6.808439547675201 + ], + [ + 39.2820369889843, + -6.808470622842016 + ], + [ + 39.282085070245415, + -6.80965589504642 + ], + [ + 39.28206930768178, + -6.809724680899688 + ], + [ + 39.28197604437582, + -6.809748107963618 + ], + [ + 39.28203658454973, + -6.809955641744993 + ], + [ + 39.28196678950842, + -6.809989174710164 + ], + [ + 39.28200076660283, + -6.809985427370294 + ], + [ + 39.282019456410715, + -6.810031452338205 + ], + [ + 39.28204972047887, + -6.810016433350921 + ], + [ + 39.28210025147508, + -6.810051116848933 + ], + [ + 39.28208152179033, + -6.810068511252877 + ], + [ + 39.28205676485107, + -6.810065686630296 + ], + [ + 39.28204318497603, + -6.810045394638353 + ], + [ + 39.28202652462141, + -6.810054127516999 + ], + [ + 39.28211105481988, + -6.810310955878061 + ], + [ + 39.28213177566899, + -6.810811361103773 + ], + [ + 39.2821320509615, + -6.811580168174703 + ], + [ + 39.28196212984445, + -6.81161380520041 + ], + [ + 39.28196324177067, + -6.811640766913107 + ], + [ + 39.28192745818485, + -6.811648558462478 + ], + [ + 39.28212985550575, + -6.812080389087699 + ], + [ + 39.282133235128924, + -6.812183754967635 + ], + [ + 39.28213536630495, + -6.814779570405246 + ], + [ + 39.28197188899595, + -6.814791111511188 + ], + [ + 39.28197562893217, + -6.814835126510185 + ], + [ + 39.28191559123218, + -6.814843893517796 + ], + [ + 39.28193291303407, + -6.814921201695186 + ], + [ + 39.2819237543314, + -6.81493645195515 + ], + [ + 39.28204752072457, + -6.815465796642168 + ], + [ + 39.28203191583694, + -6.81547995693839 + ], + [ + 39.28213668715259, + -6.815839528151637 + ], + [ + 39.282139961134924, + -6.82031295339354 + ], + [ + 39.28212156668364, + -6.820323535094702 + ], + [ + 39.282083452011165, + -6.820429480387951 + ], + [ + 39.2820979897894, + -6.820427505393686 + ], + [ + 39.28210159597546, + -6.820388271297486 + ], + [ + 39.28213848063579, + -6.820389430950556 + ], + [ + 39.28214024571535, + -6.820799338145754 + ], + [ + 39.28210969828819, + -6.82171079200005 + ], + [ + 39.28195130955397, + -6.821742318527214 + ], + [ + 39.2819621025051, + -6.821764513094872 + ], + [ + 39.2820301392614, + -6.821789494080819 + ], + [ + 39.28210146084555, + -6.821945651724311 + ], + [ + 39.28207040706704, + -6.822893035225293 + ], + [ + 39.28202470254904, + -6.822934919676698 + ], + [ + 39.28202109729184, + -6.822974817458986 + ], + [ + 39.28200660408125, + -6.822974998241254 + ], + [ + 39.28206129036098, + -6.823007414800348 + ], + [ + 39.28206592657398, + -6.82302820749804 + ], + [ + 39.28202064253523, + -6.824380481803342 + ], + [ + 39.281981544474924, + -6.824398479223031 + ], + [ + 39.28198457446479, + -6.824409215900801 + ], + [ + 39.282007489634466, + -6.824391763586223 + ], + [ + 39.28202004299919, + -6.824405229294226 + ], + [ + 39.28201771588613, + -6.824465696907729 + ], + [ + 39.2819989849681, + -6.824470675281921 + ], + [ + 39.28201551904975, + -6.82454063096336 + ], + [ + 39.281970927484814, + -6.82587821531825 + ], + [ + 39.28195816743914, + -6.825889196972958 + ], + [ + 39.281549414229346, + -6.825907201573767 + ], + [ + 39.281536280695086, + -6.825977236091125 + ], + [ + 39.28151348717576, + -6.825989987664138 + ], + [ + 39.281654833408055, + -6.826537198414719 + ], + [ + 39.281616883627095, + -6.826665413771542 + ], + [ + 39.28166851162509, + -6.826681587515675 + ], + [ + 39.28170780397164, + -6.826934383460437 + ], + [ + 39.28164411603734, + -6.827064614531757 + ], + [ + 39.28157087941187, + -6.827067306789635 + ], + [ + 39.28158180421901, + -6.827250179303952 + ], + [ + 39.281652062880944, + -6.827212345943851 + ], + [ + 39.281661122188204, + -6.827254722874545 + ], + [ + 39.28186998371223, + -6.827299194884757 + ], + [ + 39.281879687390074, + -6.827327728734536 + ], + [ + 39.28192180185399, + -6.827334112070436 + ], + [ + 39.28182547653564, + -6.830240875372596 + ], + [ + 39.281807154293304, + -6.830374916457267 + ], + [ + 39.28171581577605, + -6.830474463144125 + ], + [ + 39.280358440001955, + -6.831172974478872 + ], + [ + 39.27736178031955, + -6.832006509610587 + ], + [ + 39.27676315251181, + -6.832050277630079 + ], + [ + 39.26584625859982, + -6.832170132981521 + ], + [ + 39.249536580127696, + -6.832021721810229 + ], + [ + 39.24950165016739, + -6.831993443914228 + ], + [ + 39.24941999314367, + -6.831844309519701 + ], + [ + 39.249113885000924, + -6.830281768837318 + ] + ], + [ + [ + 39.282098666051674, + -6.82047613815803 + ], + [ + 39.28209567183957, + -6.820469231737571 + ], + [ + 39.2820671143494, + -6.820462273624464 + ], + [ + 39.28207043911302, + -6.820476154654143 + ], + [ + 39.282098666051674, + -6.82047613815803 + ] + ], + [ + [ + 39.28167616089308, + -6.805130308068077 + ], + [ + 39.28167391746429, + -6.805111703716632 + ], + [ + 39.28164656952175, + -6.805120400817218 + ], + [ + 39.28164943969814, + -6.805125077344592 + ], + [ + 39.28167616089308, + -6.805130308068077 + ] + ] + ], + [ + [ + [ + 39.281860334465605, + -6.805146602602473 + ], + [ + 39.281870004608614, + -6.80515718683268 + ], + [ + 39.28185880151722, + -6.805166623631171 + ], + [ + 39.28185067602336, + -6.805156082059399 + ], + [ + 39.281860334465605, + -6.805146602602473 + ] + ] + ], + [ + [ + [ + 39.281777446400945, + -6.805088153206213 + ], + [ + 39.281790280725005, + -6.805110130150037 + ], + [ + 39.28177175352243, + -6.805119220116509 + ], + [ + 39.28176463641958, + -6.805107930094916 + ], + [ + 39.281777446400945, + -6.805088153206213 + ] + ] + ] ] - ] - ] - }, - "bbox": [ - 39.2484489815814, - -6.832170132981521, - 39.28214024571535, - -6.800774407651622 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "image": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/dar/42f235/42f235.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "GeoTIFF" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "image": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/dar/42f235/42f235.tif", - "type": "image/tiff; application=geotiff; profile=cloud-optimized", - "title": "GeoTIFF" - } - }, - "collection": "dar" + "bbox": [ + 39.2484489815814, + -6.832170132981521, + 39.28214024571535, + -6.800774407651622 + ], + "stac_extensions": [], + "collection": "dar" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/dar/a017f9-labels/a017f9-labels.json b/tests/data-files/catalogs/test-case-4/dar/a017f9-labels/a017f9-labels.json index 6e9feefe1..1025e7bf8 100644 --- a/tests/data-files/catalogs/test-case-4/dar/a017f9-labels/a017f9-labels.json +++ b/tests/data-files/catalogs/test-case-4/dar/a017f9-labels/a017f9-labels.json @@ -1,825 +1,826 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "a017f9-labels", - "properties": { - "label:description": "Geojson building labels for scene a017f9", - "area": "dar", - "label:type": "vector", - "label:properties": [ - "building" - ], - "label:overviews": [ - { - "property_key": "building", - "counts": [ - { - "name": "yes", - "count": 8466 - } - ] - } - ], - "license": "ODbL-1.0", - "datetime": "2015-04-17T00:00:00Z", - "label:classes": [ - { - "name": "building", - "classes": [ - "yes" - ] - } - ] - }, - "geometry": { - "coordinates": [ - [ - [ - 39.26926014396197, - -6.778408889724252 - ], - [ - 39.26917573821576, - -6.778059433830696 - ], - [ - 39.269135899723494, - -6.777817111177557 - ], - [ - 39.26903939444476, - -6.777807075160049 - ], - [ - 39.26903081931803, - -6.777772501737724 - ], - [ - 39.26906382558145, - -6.777602227096167 - ], - [ - 39.26904873507929, - -6.777478560312792 - ], - [ - 39.26906977566508, - -6.777464896790929 - ], - [ - 39.26907206971568, - -6.777431243033367 - ], - [ - 39.26905482925254, - -6.777366237073936 - ], - [ - 39.26907664234658, - -6.777355931873772 - ], - [ - 39.26908175247129, - -6.777328474644556 - ], - [ - 39.26911153777823, - -6.7767048297691925 - ], - [ - 39.268882527014895, - -6.776678363032119 - ], - [ - 39.26893474099891, - -6.776264192380035 - ], - [ - 39.26888836161254, - -6.776253809942015 - ], - [ - 39.26890017221041, - -6.775895949943107 - ], - [ - 39.268876747767386, - -6.775880651901013 - ], - [ - 39.26887301554542, - -6.775825989281363 - ], - [ - 39.268905857415454, - -6.775201612825259 - ], - [ - 39.26894490739935, - -6.775063227577604 - ], - [ - 39.268941730886425, - -6.7746895631725605 - ], - [ - 39.26914364260038, - -6.774688448799986 - ], - [ - 39.269122361922676, - -6.774489250907138 - ], - [ - 39.26911632867811, - -6.774476515539691 - ], - [ - 39.268713642568706, - -6.7744760981296235 - ], - [ - 39.268737012604355, - -6.774398791342552 - ], - [ - 39.268732532666085, - -6.773790005571118 - ], - [ - 39.26843497013009, - -6.773735427452071 - ], - [ - 39.26795336212609, - -6.77391654782026 - ], - [ - 39.26791971568522, - -6.773724191695024 - ], - [ - 39.2673415071351, - -6.773740528442519 - ], - [ - 39.267350063052604, - -6.773399215834541 - ], - [ - 39.26723521167855, - -6.773414701179516 - ], - [ - 39.26720466086805, - -6.773248698765951 - ], - [ - 39.26678014120764, - -6.773242894087743 - ], - [ - 39.266762284676794, - -6.772986892804697 - ], - [ - 39.26675892922693, - -6.772350856460975 - ], - [ - 39.26674681765211, - -6.772255700716951 - ], - [ - 39.266689201437146, - -6.772246368011811 - ], - [ - 39.26668350788613, - -6.772191783623815 - ], - [ - 39.26672244519504, - -6.771767088705046 - ], - [ - 39.26626283690872, - -6.771780875871251 - ], - [ - 39.26625879082112, - -6.771454101013188 - ], - [ - 39.266132977817925, - -6.771472067783455 - ], - [ - 39.26611967798805, - -6.771424057777588 - ], - [ - 39.26608419604109, - -6.771424077200688 - ], - [ - 39.26577319095754, - -6.7715025578108285 - ], - [ - 39.265752052763695, - -6.771435782627501 - ], - [ - 39.265127479719204, - -6.77145467575174 - ], - [ - 39.26511907017294, - -6.771328213140658 - ], - [ - 39.26493015593419, - -6.771364468688907 - ], - [ - 39.264912911500495, - -6.771432744389225 - ], - [ - 39.26488039779026, - -6.771436738799636 - ], - [ - 39.26475100488943, - -6.771406733473938 - ], - [ - 39.2646926955789, - -6.771412615337635 - ], - [ - 39.2646606028275, - -6.771388711051411 - ], - [ - 39.26392674348407, - -6.771256584601807 - ], - [ - 39.26394389453707, - -6.771551356063654 - ], - [ - 39.263667091483114, - -6.771557919685502 - ], - [ - 39.26366183135522, - -6.771600089723924 - ], - [ - 39.263278347477964, - -6.77157318737759 - ], - [ - 39.26283023251785, - -6.771600245021459 - ], - [ - 39.262838493462255, - -6.771634543496247 - ], - [ - 39.262821747451255, - -6.771719954194481 - ], - [ - 39.26265424567296, - -6.771690993457386 - ], - [ - 39.26268995014445, - -6.771860885107266 - ], - [ - 39.26252831334852, - -6.771895873157618 - ], - [ - 39.26252880337638, - -6.7719554235439245 - ], - [ - 39.26210122775403, - -6.771977406295051 - ], - [ - 39.26143116288968, - -6.772125372485002 - ], - [ - 39.2614075982154, - -6.772141135811242 - ], - [ - 39.2613973736888, - -6.772275813955157 - ], - [ - 39.260536340561174, - -6.772228258989134 - ], - [ - 39.26053980618854, - -6.772319083364469 - ], - [ - 39.26056969675572, - -6.772373190295851 - ], - [ - 39.26060315386137, - -6.772554749985303 - ], - [ - 39.26059568903891, - -6.772595510376657 - ], - [ - 39.26001518300299, - -6.772559851743274 - ], - [ - 39.25890041510944, - -6.7725543793501695 - ], - [ - 39.258876087403834, - -6.772494197053711 - ], - [ - 39.258514479088554, - -6.772422102891361 - ], - [ - 39.258340434530666, - -6.772428219316269 - ], - [ - 39.25828032895121, - -6.77272075666584 - ], - [ - 39.25826082874752, - -6.772915188024547 - ], - [ - 39.25823949031402, - -6.772922057829271 - ], - [ - 39.2578520090327, - -6.772838102931263 - ], - [ - 39.257888798127965, - -6.77312332117879 - ], - [ - 39.25787979922622, - -6.773136270542293 - ], - [ - 39.25688475867173, - -6.773097642255739 - ], - [ - 39.25682520466523, - -6.773109721503685 - ], - [ - 39.25660478951343, - -6.773091077694639 - ], - [ - 39.255055254694156, - -6.772380238732794 - ], - [ - 39.25421275712266, - -6.771620622438099 - ], - [ - 39.25404556903243, - -6.77004589995448 - ], - [ - 39.25403029430106, - -6.769728767128998 - ], - [ - 39.25411994186844, - -6.768221861425687 - ], - [ - 39.254234107717096, - -6.767341435882211 - ], - [ - 39.25545106018141, - -6.764159936003817 - ], - [ - 39.257116110067585, - -6.76294877364334 - ], - [ - 39.25718438415638, - -6.762917093607382 - ], - [ - 39.25719972988617, - -6.762889019397921 - ], - [ - 39.257442153683776, - -6.76271321325156 - ], - [ - 39.25823278499986, - -6.762669559070356 - ], - [ - 39.25834142312088, - -6.762242194863409 - ], - [ - 39.25939647121495, - -6.762572558084997 - ], - [ - 39.25940845544633, - -6.762487777603404 - ], - [ - 39.259435774764846, - -6.762476198533605 - ], - [ - 39.26006839728735, - -6.76261436674474 - ], - [ - 39.260386403814906, - -6.762668411712047 - ], - [ - 39.260437484245585, - -6.762439496926193 - ], - [ - 39.260004647501674, - -6.762312837170598 - ], - [ - 39.2598716936977, - -6.762259959251641 - ], - [ - 39.2600401439903, - -6.761820065451443 - ], - [ - 39.26029388247496, - -6.761028721580892 - ], - [ - 39.26032420174658, - -6.761018967933076 - ], - [ - 39.26053391798681, - -6.76114659187534 - ], - [ - 39.260536816410294, - -6.760851252611107 - ], - [ - 39.260557853080336, - -6.760831034771786 - ], - [ - 39.260566844200056, - -6.76074069093421 - ], - [ - 39.26036239395784, - -6.760812697920982 - ], - [ - 39.26027824156397, - -6.760662075341912 - ], - [ - 39.261001400117976, - -6.760133550248436 - ], - [ - 39.261527087791784, - -6.759873405077786 - ], - [ - 39.26858580547449, - -6.759308696494632 - ], - [ - 39.268890992058246, - -6.759302984619273 - ], - [ - 39.268903430340835, - -6.759284771586644 - ], - [ - 39.26896542655929, - -6.759278367546962 - ], - [ - 39.271286224101196, - -6.759102343973786 - ], - [ - 39.27211963371433, - -6.759204458764863 - ], - [ - 39.27236321137411, - -6.759271479674409 - ], - [ - 39.273154184137965, - -6.7601369678318965 - ], - [ - 39.27316422844033, - -6.760700644939782 - ], - [ - 39.27314084480545, - -6.7619837448331745 - ], - [ - 39.27305675463236, - -6.762505234243227 - ], - [ - 39.273056789844496, - -6.762534967504247 - ], - [ - 39.27312507291691, - -6.762521393506317 - ], - [ - 39.27313212710874, - -6.76255601845254 - ], - [ - 39.27310309297801, - -6.764507772203796 - ], - [ - 39.27308849603215, - -6.764558304932267 - ], - [ - 39.27300138154325, - -6.764546994635472 - ], - [ - 39.273024316262344, - -6.7646614152403 - ], - [ - 39.27304589268655, - -6.7646695624275575 - ], - [ - 39.27304617892309, - -6.765101677547554 - ], - [ - 39.27308204747948, - -6.7651152272390975 - ], - [ - 39.27309139442161, - -6.765137274306364 - ], - [ - 39.273051905630446, - -6.765239264368901 - ], - [ - 39.27306448349893, - -6.765504735996792 - ], - [ - 39.27308187939778, - -6.765516334329867 - ], - [ - 39.27308560012812, - -6.765549913380341 - ], - [ - 39.27304752697193, - -6.767501671978607 - ], - [ - 39.273038935703134, - -6.767516058055352 - ], - [ - 39.27299835422545, - -6.7675217280475755 - ], - [ - 39.27299933800813, - -6.767537832177631 - ], - [ - 39.273045495033486, - -6.767541113558746 - ], - [ - 39.273050590782745, - -6.767592028459917 - ], - [ - 39.27302400267546, - -6.768534259451833 - ], - [ - 39.272968932976305, - -6.772411177910341 - ], - [ - 39.272959627433714, - -6.772630668635193 - ], - [ - 39.272905788858104, - -6.772643489838023 - ], - [ - 39.27288173837768, - -6.772739885404247 - ], - [ - 39.272882307015124, - -6.7727514232524175 - ], - [ - 39.272956057298394, - -6.772741000926849 - ], - [ - 39.272963123503956, - -6.772796709421321 - ], - [ - 39.27286982682731, - -6.778350777504887 - ], - [ - 39.27283086855745, - -6.7790374037343115 - ], - [ - 39.272701979976624, - -6.779284945399111 - ], - [ - 39.272261619559565, - -6.779665292928737 - ], - [ - 39.27210271074345, - -6.7797571049359115 - ], - [ - 39.271704543803665, - -6.779784747451681 - ], - [ - 39.27144452806939, - -6.779784849288132 - ], - [ - 39.27115738781928, - -6.779758148606385 - ], - [ - 39.27049709925575, - -6.779461996132346 - ], - [ - 39.270493082234935, - -6.779326099696981 - ], - [ - 39.2702131801902, - -6.779330763890751 - ], - [ - 39.26995991242604, - -6.779214787256136 - ], - [ - 39.2699510390659, - -6.77909635634638 - ], - [ - 39.26977275112402, - -6.779102490914896 - ], - [ - 39.26968410885647, - -6.779086412311449 - ], - [ - 39.26966426752008, - -6.77902210533535 - ], - [ - 39.269673217618006, - -6.778939901472921 - ], - [ - 39.26934578546989, - -6.778920487053642 - ], - [ - 39.26932971998377, - -6.778857872932586 - ], - [ - 39.26936566177434, - -6.778547988756392 - ], - [ - 39.2693481357915, - -6.778494457194883 - ], - [ - 39.269311412694705, - -6.778506382971034 - ], - [ - 39.2692772941224, - -6.778497070722168 - ], - [ - 39.26926014396197, - -6.778408889724252 + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "a017f9-labels", + "properties": { + "label:description": "Geojson building labels for scene a017f9", + "area": "dar", + "label:type": "vector", + "label:properties": [ + "building" + ], + "label:overviews": [ + { + "property_key": "building", + "counts": [ + { + "name": "yes", + "count": 8466 + } + ] + } + ], + "license": "ODbL-1.0", + "datetime": "2015-04-17T00:00:00Z", + "label:classes": [ + { + "name": "building", + "classes": [ + "yes" + ] + } ] - ] - ], - "type": "Polygon" - }, - "bbox": [ - 39.25403029430106, - -6.779784892393674, - 39.2731659202684, - -6.759102343973786 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "geometry": { + "coordinates": [ + [ + [ + 39.26926014396197, + -6.778408889724252 + ], + [ + 39.26917573821576, + -6.778059433830696 + ], + [ + 39.269135899723494, + -6.777817111177557 + ], + [ + 39.26903939444476, + -6.777807075160049 + ], + [ + 39.26903081931803, + -6.777772501737724 + ], + [ + 39.26906382558145, + -6.777602227096167 + ], + [ + 39.26904873507929, + -6.777478560312792 + ], + [ + 39.26906977566508, + -6.777464896790929 + ], + [ + 39.26907206971568, + -6.777431243033367 + ], + [ + 39.26905482925254, + -6.777366237073936 + ], + [ + 39.26907664234658, + -6.777355931873772 + ], + [ + 39.26908175247129, + -6.777328474644556 + ], + [ + 39.26911153777823, + -6.7767048297691925 + ], + [ + 39.268882527014895, + -6.776678363032119 + ], + [ + 39.26893474099891, + -6.776264192380035 + ], + [ + 39.26888836161254, + -6.776253809942015 + ], + [ + 39.26890017221041, + -6.775895949943107 + ], + [ + 39.268876747767386, + -6.775880651901013 + ], + [ + 39.26887301554542, + -6.775825989281363 + ], + [ + 39.268905857415454, + -6.775201612825259 + ], + [ + 39.26894490739935, + -6.775063227577604 + ], + [ + 39.268941730886425, + -6.7746895631725605 + ], + [ + 39.26914364260038, + -6.774688448799986 + ], + [ + 39.269122361922676, + -6.774489250907138 + ], + [ + 39.26911632867811, + -6.774476515539691 + ], + [ + 39.268713642568706, + -6.7744760981296235 + ], + [ + 39.268737012604355, + -6.774398791342552 + ], + [ + 39.268732532666085, + -6.773790005571118 + ], + [ + 39.26843497013009, + -6.773735427452071 + ], + [ + 39.26795336212609, + -6.77391654782026 + ], + [ + 39.26791971568522, + -6.773724191695024 + ], + [ + 39.2673415071351, + -6.773740528442519 + ], + [ + 39.267350063052604, + -6.773399215834541 + ], + [ + 39.26723521167855, + -6.773414701179516 + ], + [ + 39.26720466086805, + -6.773248698765951 + ], + [ + 39.26678014120764, + -6.773242894087743 + ], + [ + 39.266762284676794, + -6.772986892804697 + ], + [ + 39.26675892922693, + -6.772350856460975 + ], + [ + 39.26674681765211, + -6.772255700716951 + ], + [ + 39.266689201437146, + -6.772246368011811 + ], + [ + 39.26668350788613, + -6.772191783623815 + ], + [ + 39.26672244519504, + -6.771767088705046 + ], + [ + 39.26626283690872, + -6.771780875871251 + ], + [ + 39.26625879082112, + -6.771454101013188 + ], + [ + 39.266132977817925, + -6.771472067783455 + ], + [ + 39.26611967798805, + -6.771424057777588 + ], + [ + 39.26608419604109, + -6.771424077200688 + ], + [ + 39.26577319095754, + -6.7715025578108285 + ], + [ + 39.265752052763695, + -6.771435782627501 + ], + [ + 39.265127479719204, + -6.77145467575174 + ], + [ + 39.26511907017294, + -6.771328213140658 + ], + [ + 39.26493015593419, + -6.771364468688907 + ], + [ + 39.264912911500495, + -6.771432744389225 + ], + [ + 39.26488039779026, + -6.771436738799636 + ], + [ + 39.26475100488943, + -6.771406733473938 + ], + [ + 39.2646926955789, + -6.771412615337635 + ], + [ + 39.2646606028275, + -6.771388711051411 + ], + [ + 39.26392674348407, + -6.771256584601807 + ], + [ + 39.26394389453707, + -6.771551356063654 + ], + [ + 39.263667091483114, + -6.771557919685502 + ], + [ + 39.26366183135522, + -6.771600089723924 + ], + [ + 39.263278347477964, + -6.77157318737759 + ], + [ + 39.26283023251785, + -6.771600245021459 + ], + [ + 39.262838493462255, + -6.771634543496247 + ], + [ + 39.262821747451255, + -6.771719954194481 + ], + [ + 39.26265424567296, + -6.771690993457386 + ], + [ + 39.26268995014445, + -6.771860885107266 + ], + [ + 39.26252831334852, + -6.771895873157618 + ], + [ + 39.26252880337638, + -6.7719554235439245 + ], + [ + 39.26210122775403, + -6.771977406295051 + ], + [ + 39.26143116288968, + -6.772125372485002 + ], + [ + 39.2614075982154, + -6.772141135811242 + ], + [ + 39.2613973736888, + -6.772275813955157 + ], + [ + 39.260536340561174, + -6.772228258989134 + ], + [ + 39.26053980618854, + -6.772319083364469 + ], + [ + 39.26056969675572, + -6.772373190295851 + ], + [ + 39.26060315386137, + -6.772554749985303 + ], + [ + 39.26059568903891, + -6.772595510376657 + ], + [ + 39.26001518300299, + -6.772559851743274 + ], + [ + 39.25890041510944, + -6.7725543793501695 + ], + [ + 39.258876087403834, + -6.772494197053711 + ], + [ + 39.258514479088554, + -6.772422102891361 + ], + [ + 39.258340434530666, + -6.772428219316269 + ], + [ + 39.25828032895121, + -6.77272075666584 + ], + [ + 39.25826082874752, + -6.772915188024547 + ], + [ + 39.25823949031402, + -6.772922057829271 + ], + [ + 39.2578520090327, + -6.772838102931263 + ], + [ + 39.257888798127965, + -6.77312332117879 + ], + [ + 39.25787979922622, + -6.773136270542293 + ], + [ + 39.25688475867173, + -6.773097642255739 + ], + [ + 39.25682520466523, + -6.773109721503685 + ], + [ + 39.25660478951343, + -6.773091077694639 + ], + [ + 39.255055254694156, + -6.772380238732794 + ], + [ + 39.25421275712266, + -6.771620622438099 + ], + [ + 39.25404556903243, + -6.77004589995448 + ], + [ + 39.25403029430106, + -6.769728767128998 + ], + [ + 39.25411994186844, + -6.768221861425687 + ], + [ + 39.254234107717096, + -6.767341435882211 + ], + [ + 39.25545106018141, + -6.764159936003817 + ], + [ + 39.257116110067585, + -6.76294877364334 + ], + [ + 39.25718438415638, + -6.762917093607382 + ], + [ + 39.25719972988617, + -6.762889019397921 + ], + [ + 39.257442153683776, + -6.76271321325156 + ], + [ + 39.25823278499986, + -6.762669559070356 + ], + [ + 39.25834142312088, + -6.762242194863409 + ], + [ + 39.25939647121495, + -6.762572558084997 + ], + [ + 39.25940845544633, + -6.762487777603404 + ], + [ + 39.259435774764846, + -6.762476198533605 + ], + [ + 39.26006839728735, + -6.76261436674474 + ], + [ + 39.260386403814906, + -6.762668411712047 + ], + [ + 39.260437484245585, + -6.762439496926193 + ], + [ + 39.260004647501674, + -6.762312837170598 + ], + [ + 39.2598716936977, + -6.762259959251641 + ], + [ + 39.2600401439903, + -6.761820065451443 + ], + [ + 39.26029388247496, + -6.761028721580892 + ], + [ + 39.26032420174658, + -6.761018967933076 + ], + [ + 39.26053391798681, + -6.76114659187534 + ], + [ + 39.260536816410294, + -6.760851252611107 + ], + [ + 39.260557853080336, + -6.760831034771786 + ], + [ + 39.260566844200056, + -6.76074069093421 + ], + [ + 39.26036239395784, + -6.760812697920982 + ], + [ + 39.26027824156397, + -6.760662075341912 + ], + [ + 39.261001400117976, + -6.760133550248436 + ], + [ + 39.261527087791784, + -6.759873405077786 + ], + [ + 39.26858580547449, + -6.759308696494632 + ], + [ + 39.268890992058246, + -6.759302984619273 + ], + [ + 39.268903430340835, + -6.759284771586644 + ], + [ + 39.26896542655929, + -6.759278367546962 + ], + [ + 39.271286224101196, + -6.759102343973786 + ], + [ + 39.27211963371433, + -6.759204458764863 + ], + [ + 39.27236321137411, + -6.759271479674409 + ], + [ + 39.273154184137965, + -6.7601369678318965 + ], + [ + 39.27316422844033, + -6.760700644939782 + ], + [ + 39.27314084480545, + -6.7619837448331745 + ], + [ + 39.27305675463236, + -6.762505234243227 + ], + [ + 39.273056789844496, + -6.762534967504247 + ], + [ + 39.27312507291691, + -6.762521393506317 + ], + [ + 39.27313212710874, + -6.76255601845254 + ], + [ + 39.27310309297801, + -6.764507772203796 + ], + [ + 39.27308849603215, + -6.764558304932267 + ], + [ + 39.27300138154325, + -6.764546994635472 + ], + [ + 39.273024316262344, + -6.7646614152403 + ], + [ + 39.27304589268655, + -6.7646695624275575 + ], + [ + 39.27304617892309, + -6.765101677547554 + ], + [ + 39.27308204747948, + -6.7651152272390975 + ], + [ + 39.27309139442161, + -6.765137274306364 + ], + [ + 39.273051905630446, + -6.765239264368901 + ], + [ + 39.27306448349893, + -6.765504735996792 + ], + [ + 39.27308187939778, + -6.765516334329867 + ], + [ + 39.27308560012812, + -6.765549913380341 + ], + [ + 39.27304752697193, + -6.767501671978607 + ], + [ + 39.273038935703134, + -6.767516058055352 + ], + [ + 39.27299835422545, + -6.7675217280475755 + ], + [ + 39.27299933800813, + -6.767537832177631 + ], + [ + 39.273045495033486, + -6.767541113558746 + ], + [ + 39.273050590782745, + -6.767592028459917 + ], + [ + 39.27302400267546, + -6.768534259451833 + ], + [ + 39.272968932976305, + -6.772411177910341 + ], + [ + 39.272959627433714, + -6.772630668635193 + ], + [ + 39.272905788858104, + -6.772643489838023 + ], + [ + 39.27288173837768, + -6.772739885404247 + ], + [ + 39.272882307015124, + -6.7727514232524175 + ], + [ + 39.272956057298394, + -6.772741000926849 + ], + [ + 39.272963123503956, + -6.772796709421321 + ], + [ + 39.27286982682731, + -6.778350777504887 + ], + [ + 39.27283086855745, + -6.7790374037343115 + ], + [ + 39.272701979976624, + -6.779284945399111 + ], + [ + 39.272261619559565, + -6.779665292928737 + ], + [ + 39.27210271074345, + -6.7797571049359115 + ], + [ + 39.271704543803665, + -6.779784747451681 + ], + [ + 39.27144452806939, + -6.779784849288132 + ], + [ + 39.27115738781928, + -6.779758148606385 + ], + [ + 39.27049709925575, + -6.779461996132346 + ], + [ + 39.270493082234935, + -6.779326099696981 + ], + [ + 39.2702131801902, + -6.779330763890751 + ], + [ + 39.26995991242604, + -6.779214787256136 + ], + [ + 39.2699510390659, + -6.77909635634638 + ], + [ + 39.26977275112402, + -6.779102490914896 + ], + [ + 39.26968410885647, + -6.779086412311449 + ], + [ + 39.26966426752008, + -6.77902210533535 + ], + [ + 39.269673217618006, + -6.778939901472921 + ], + [ + 39.26934578546989, + -6.778920487053642 + ], + [ + 39.26932971998377, + -6.778857872932586 + ], + [ + 39.26936566177434, + -6.778547988756392 + ], + [ + 39.2693481357915, + -6.778494457194883 + ], + [ + 39.269311412694705, + -6.778506382971034 + ], + [ + 39.2692772941224, + -6.778497070722168 + ], + [ + 39.26926014396197, + -6.778408889724252 + ] + ] + ], + "type": "Polygon" + }, + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "labels": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/dar/a017f9-labels/a017f9.geojson", + "type": "application/geo+json" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "labels": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/dar/a017f9-labels/a017f9.geojson", - "type": "application/geo+json" - } - }, - "stac_extensions": [ - "label" - ] + "bbox": [ + 39.25403029430106, + -6.779784892393674, + 39.2731659202684, + -6.759102343973786 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "dar" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/dar/a017f9/a017f9.json b/tests/data-files/catalogs/test-case-4/dar/a017f9/a017f9.json index 9f5b115a0..be22c5b66 100644 --- a/tests/data-files/catalogs/test-case-4/dar/a017f9/a017f9.json +++ b/tests/data-files/catalogs/test-case-4/dar/a017f9/a017f9.json @@ -1,800 +1,801 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "a017f9", - "properties": { - "area": "dar", - "license": "CC-BY-4.0", - "datetime": "2015-04-17T00:00:00Z" - }, - "geometry": { - "coordinates": [ - [ - [ - 39.26926014396197, - -6.778408889724252 - ], - [ - 39.26917573821576, - -6.778059433830696 - ], - [ - 39.269135899723494, - -6.777817111177557 - ], - [ - 39.26903939444476, - -6.777807075160049 - ], - [ - 39.26903081931803, - -6.777772501737724 - ], - [ - 39.26906382558145, - -6.777602227096167 - ], - [ - 39.26904873507929, - -6.777478560312792 - ], - [ - 39.26906977566508, - -6.777464896790929 - ], - [ - 39.26907206971568, - -6.777431243033367 - ], - [ - 39.26905482925254, - -6.777366237073936 - ], - [ - 39.26907664234658, - -6.777355931873772 - ], - [ - 39.26908175247129, - -6.777328474644556 - ], - [ - 39.26911153777823, - -6.7767048297691925 - ], - [ - 39.268882527014895, - -6.776678363032119 - ], - [ - 39.26893474099891, - -6.776264192380035 - ], - [ - 39.26888836161254, - -6.776253809942015 - ], - [ - 39.26890017221041, - -6.775895949943107 - ], - [ - 39.268876747767386, - -6.775880651901013 - ], - [ - 39.26887301554542, - -6.775825989281363 - ], - [ - 39.268905857415454, - -6.775201612825259 - ], - [ - 39.26894490739935, - -6.775063227577604 - ], - [ - 39.268941730886425, - -6.7746895631725605 - ], - [ - 39.26914364260038, - -6.774688448799986 - ], - [ - 39.269122361922676, - -6.774489250907138 - ], - [ - 39.26911632867811, - -6.774476515539691 - ], - [ - 39.268713642568706, - -6.7744760981296235 - ], - [ - 39.268737012604355, - -6.774398791342552 - ], - [ - 39.268732532666085, - -6.773790005571118 - ], - [ - 39.26843497013009, - -6.773735427452071 - ], - [ - 39.26795336212609, - -6.77391654782026 - ], - [ - 39.26791971568522, - -6.773724191695024 - ], - [ - 39.2673415071351, - -6.773740528442519 - ], - [ - 39.267350063052604, - -6.773399215834541 - ], - [ - 39.26723521167855, - -6.773414701179516 - ], - [ - 39.26720466086805, - -6.773248698765951 - ], - [ - 39.26678014120764, - -6.773242894087743 - ], - [ - 39.266762284676794, - -6.772986892804697 - ], - [ - 39.26675892922693, - -6.772350856460975 - ], - [ - 39.26674681765211, - -6.772255700716951 - ], - [ - 39.266689201437146, - -6.772246368011811 - ], - [ - 39.26668350788613, - -6.772191783623815 - ], - [ - 39.26672244519504, - -6.771767088705046 - ], - [ - 39.26626283690872, - -6.771780875871251 - ], - [ - 39.26625879082112, - -6.771454101013188 - ], - [ - 39.266132977817925, - -6.771472067783455 - ], - [ - 39.26611967798805, - -6.771424057777588 - ], - [ - 39.26608419604109, - -6.771424077200688 - ], - [ - 39.26577319095754, - -6.7715025578108285 - ], - [ - 39.265752052763695, - -6.771435782627501 - ], - [ - 39.265127479719204, - -6.77145467575174 - ], - [ - 39.26511907017294, - -6.771328213140658 - ], - [ - 39.26493015593419, - -6.771364468688907 - ], - [ - 39.264912911500495, - -6.771432744389225 - ], - [ - 39.26488039779026, - -6.771436738799636 - ], - [ - 39.26475100488943, - -6.771406733473938 - ], - [ - 39.2646926955789, - -6.771412615337635 - ], - [ - 39.2646606028275, - -6.771388711051411 - ], - [ - 39.26392674348407, - -6.771256584601807 - ], - [ - 39.26394389453707, - -6.771551356063654 - ], - [ - 39.263667091483114, - -6.771557919685502 - ], - [ - 39.26366183135522, - -6.771600089723924 - ], - [ - 39.263278347477964, - -6.77157318737759 - ], - [ - 39.26283023251785, - -6.771600245021459 - ], - [ - 39.262838493462255, - -6.771634543496247 - ], - [ - 39.262821747451255, - -6.771719954194481 - ], - [ - 39.26265424567296, - -6.771690993457386 - ], - [ - 39.26268995014445, - -6.771860885107266 - ], - [ - 39.26252831334852, - -6.771895873157618 - ], - [ - 39.26252880337638, - -6.7719554235439245 - ], - [ - 39.26210122775403, - -6.771977406295051 - ], - [ - 39.26143116288968, - -6.772125372485002 - ], - [ - 39.2614075982154, - -6.772141135811242 - ], - [ - 39.2613973736888, - -6.772275813955157 - ], - [ - 39.260536340561174, - -6.772228258989134 - ], - [ - 39.26053980618854, - -6.772319083364469 - ], - [ - 39.26056969675572, - -6.772373190295851 - ], - [ - 39.26060315386137, - -6.772554749985303 - ], - [ - 39.26059568903891, - -6.772595510376657 - ], - [ - 39.26001518300299, - -6.772559851743274 - ], - [ - 39.25890041510944, - -6.7725543793501695 - ], - [ - 39.258876087403834, - -6.772494197053711 - ], - [ - 39.258514479088554, - -6.772422102891361 - ], - [ - 39.258340434530666, - -6.772428219316269 - ], - [ - 39.25828032895121, - -6.77272075666584 - ], - [ - 39.25826082874752, - -6.772915188024547 - ], - [ - 39.25823949031402, - -6.772922057829271 - ], - [ - 39.2578520090327, - -6.772838102931263 - ], - [ - 39.257888798127965, - -6.77312332117879 - ], - [ - 39.25787979922622, - -6.773136270542293 - ], - [ - 39.25688475867173, - -6.773097642255739 - ], - [ - 39.25682520466523, - -6.773109721503685 - ], - [ - 39.25660478951343, - -6.773091077694639 - ], - [ - 39.255055254694156, - -6.772380238732794 - ], - [ - 39.25421275712266, - -6.771620622438099 - ], - [ - 39.25404556903243, - -6.77004589995448 - ], - [ - 39.25403029430106, - -6.769728767128998 - ], - [ - 39.25411994186844, - -6.768221861425687 - ], - [ - 39.254234107717096, - -6.767341435882211 - ], - [ - 39.25545106018141, - -6.764159936003817 - ], - [ - 39.257116110067585, - -6.76294877364334 - ], - [ - 39.25718438415638, - -6.762917093607382 - ], - [ - 39.25719972988617, - -6.762889019397921 - ], - [ - 39.257442153683776, - -6.76271321325156 - ], - [ - 39.25823278499986, - -6.762669559070356 - ], - [ - 39.25834142312088, - -6.762242194863409 - ], - [ - 39.25939647121495, - -6.762572558084997 - ], - [ - 39.25940845544633, - -6.762487777603404 - ], - [ - 39.259435774764846, - -6.762476198533605 - ], - [ - 39.26006839728735, - -6.76261436674474 - ], - [ - 39.260386403814906, - -6.762668411712047 - ], - [ - 39.260437484245585, - -6.762439496926193 - ], - [ - 39.260004647501674, - -6.762312837170598 - ], - [ - 39.2598716936977, - -6.762259959251641 - ], - [ - 39.2600401439903, - -6.761820065451443 - ], - [ - 39.26029388247496, - -6.761028721580892 - ], - [ - 39.26032420174658, - -6.761018967933076 - ], - [ - 39.26053391798681, - -6.76114659187534 - ], - [ - 39.260536816410294, - -6.760851252611107 - ], - [ - 39.260557853080336, - -6.760831034771786 - ], - [ - 39.260566844200056, - -6.76074069093421 - ], - [ - 39.26036239395784, - -6.760812697920982 - ], - [ - 39.26027824156397, - -6.760662075341912 - ], - [ - 39.261001400117976, - -6.760133550248436 - ], - [ - 39.261527087791784, - -6.759873405077786 - ], - [ - 39.26858580547449, - -6.759308696494632 - ], - [ - 39.268890992058246, - -6.759302984619273 - ], - [ - 39.268903430340835, - -6.759284771586644 - ], - [ - 39.26896542655929, - -6.759278367546962 - ], - [ - 39.271286224101196, - -6.759102343973786 - ], - [ - 39.27211963371433, - -6.759204458764863 - ], - [ - 39.27236321137411, - -6.759271479674409 - ], - [ - 39.273154184137965, - -6.7601369678318965 - ], - [ - 39.27316422844033, - -6.760700644939782 - ], - [ - 39.27314084480545, - -6.7619837448331745 - ], - [ - 39.27305675463236, - -6.762505234243227 - ], - [ - 39.273056789844496, - -6.762534967504247 - ], - [ - 39.27312507291691, - -6.762521393506317 - ], - [ - 39.27313212710874, - -6.76255601845254 - ], - [ - 39.27310309297801, - -6.764507772203796 - ], - [ - 39.27308849603215, - -6.764558304932267 - ], - [ - 39.27300138154325, - -6.764546994635472 - ], - [ - 39.273024316262344, - -6.7646614152403 - ], - [ - 39.27304589268655, - -6.7646695624275575 - ], - [ - 39.27304617892309, - -6.765101677547554 - ], - [ - 39.27308204747948, - -6.7651152272390975 - ], - [ - 39.27309139442161, - -6.765137274306364 - ], - [ - 39.273051905630446, - -6.765239264368901 - ], - [ - 39.27306448349893, - -6.765504735996792 - ], - [ - 39.27308187939778, - -6.765516334329867 - ], - [ - 39.27308560012812, - -6.765549913380341 - ], - [ - 39.27304752697193, - -6.767501671978607 - ], - [ - 39.273038935703134, - -6.767516058055352 - ], - [ - 39.27299835422545, - -6.7675217280475755 - ], - [ - 39.27299933800813, - -6.767537832177631 - ], - [ - 39.273045495033486, - -6.767541113558746 - ], - [ - 39.273050590782745, - -6.767592028459917 - ], - [ - 39.27302400267546, - -6.768534259451833 - ], - [ - 39.272968932976305, - -6.772411177910341 - ], - [ - 39.272959627433714, - -6.772630668635193 - ], - [ - 39.272905788858104, - -6.772643489838023 - ], - [ - 39.27288173837768, - -6.772739885404247 - ], - [ - 39.272882307015124, - -6.7727514232524175 - ], - [ - 39.272956057298394, - -6.772741000926849 - ], - [ - 39.272963123503956, - -6.772796709421321 - ], - [ - 39.27286982682731, - -6.778350777504887 - ], - [ - 39.27283086855745, - -6.7790374037343115 - ], - [ - 39.272701979976624, - -6.779284945399111 - ], - [ - 39.272261619559565, - -6.779665292928737 - ], - [ - 39.27210271074345, - -6.7797571049359115 - ], - [ - 39.271704543803665, - -6.779784747451681 - ], - [ - 39.27144452806939, - -6.779784849288132 - ], - [ - 39.27115738781928, - -6.779758148606385 - ], - [ - 39.27049709925575, - -6.779461996132346 - ], - [ - 39.270493082234935, - -6.779326099696981 - ], - [ - 39.2702131801902, - -6.779330763890751 - ], - [ - 39.26995991242604, - -6.779214787256136 - ], - [ - 39.2699510390659, - -6.77909635634638 - ], - [ - 39.26977275112402, - -6.779102490914896 - ], - [ - 39.26968410885647, - -6.779086412311449 - ], - [ - 39.26966426752008, - -6.77902210533535 - ], - [ - 39.269673217618006, - -6.778939901472921 - ], - [ - 39.26934578546989, - -6.778920487053642 - ], - [ - 39.26932971998377, - -6.778857872932586 - ], - [ - 39.26936566177434, - -6.778547988756392 - ], - [ - 39.2693481357915, - -6.778494457194883 - ], - [ - 39.269311412694705, - -6.778506382971034 - ], - [ - 39.2692772941224, - -6.778497070722168 - ], - [ - 39.26926014396197, - -6.778408889724252 - ] - ] - ], - "type": "Polygon" - }, - "bbox": [ - 39.25403029430106, - -6.779784892393674, - 39.2731659202684, - -6.759102343973786 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "a017f9", + "properties": { + "area": "dar", + "license": "CC-BY-4.0", + "datetime": "2015-04-17T00:00:00Z" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "geometry": { + "coordinates": [ + [ + [ + 39.26926014396197, + -6.778408889724252 + ], + [ + 39.26917573821576, + -6.778059433830696 + ], + [ + 39.269135899723494, + -6.777817111177557 + ], + [ + 39.26903939444476, + -6.777807075160049 + ], + [ + 39.26903081931803, + -6.777772501737724 + ], + [ + 39.26906382558145, + -6.777602227096167 + ], + [ + 39.26904873507929, + -6.777478560312792 + ], + [ + 39.26906977566508, + -6.777464896790929 + ], + [ + 39.26907206971568, + -6.777431243033367 + ], + [ + 39.26905482925254, + -6.777366237073936 + ], + [ + 39.26907664234658, + -6.777355931873772 + ], + [ + 39.26908175247129, + -6.777328474644556 + ], + [ + 39.26911153777823, + -6.7767048297691925 + ], + [ + 39.268882527014895, + -6.776678363032119 + ], + [ + 39.26893474099891, + -6.776264192380035 + ], + [ + 39.26888836161254, + -6.776253809942015 + ], + [ + 39.26890017221041, + -6.775895949943107 + ], + [ + 39.268876747767386, + -6.775880651901013 + ], + [ + 39.26887301554542, + -6.775825989281363 + ], + [ + 39.268905857415454, + -6.775201612825259 + ], + [ + 39.26894490739935, + -6.775063227577604 + ], + [ + 39.268941730886425, + -6.7746895631725605 + ], + [ + 39.26914364260038, + -6.774688448799986 + ], + [ + 39.269122361922676, + -6.774489250907138 + ], + [ + 39.26911632867811, + -6.774476515539691 + ], + [ + 39.268713642568706, + -6.7744760981296235 + ], + [ + 39.268737012604355, + -6.774398791342552 + ], + [ + 39.268732532666085, + -6.773790005571118 + ], + [ + 39.26843497013009, + -6.773735427452071 + ], + [ + 39.26795336212609, + -6.77391654782026 + ], + [ + 39.26791971568522, + -6.773724191695024 + ], + [ + 39.2673415071351, + -6.773740528442519 + ], + [ + 39.267350063052604, + -6.773399215834541 + ], + [ + 39.26723521167855, + -6.773414701179516 + ], + [ + 39.26720466086805, + -6.773248698765951 + ], + [ + 39.26678014120764, + -6.773242894087743 + ], + [ + 39.266762284676794, + -6.772986892804697 + ], + [ + 39.26675892922693, + -6.772350856460975 + ], + [ + 39.26674681765211, + -6.772255700716951 + ], + [ + 39.266689201437146, + -6.772246368011811 + ], + [ + 39.26668350788613, + -6.772191783623815 + ], + [ + 39.26672244519504, + -6.771767088705046 + ], + [ + 39.26626283690872, + -6.771780875871251 + ], + [ + 39.26625879082112, + -6.771454101013188 + ], + [ + 39.266132977817925, + -6.771472067783455 + ], + [ + 39.26611967798805, + -6.771424057777588 + ], + [ + 39.26608419604109, + -6.771424077200688 + ], + [ + 39.26577319095754, + -6.7715025578108285 + ], + [ + 39.265752052763695, + -6.771435782627501 + ], + [ + 39.265127479719204, + -6.77145467575174 + ], + [ + 39.26511907017294, + -6.771328213140658 + ], + [ + 39.26493015593419, + -6.771364468688907 + ], + [ + 39.264912911500495, + -6.771432744389225 + ], + [ + 39.26488039779026, + -6.771436738799636 + ], + [ + 39.26475100488943, + -6.771406733473938 + ], + [ + 39.2646926955789, + -6.771412615337635 + ], + [ + 39.2646606028275, + -6.771388711051411 + ], + [ + 39.26392674348407, + -6.771256584601807 + ], + [ + 39.26394389453707, + -6.771551356063654 + ], + [ + 39.263667091483114, + -6.771557919685502 + ], + [ + 39.26366183135522, + -6.771600089723924 + ], + [ + 39.263278347477964, + -6.77157318737759 + ], + [ + 39.26283023251785, + -6.771600245021459 + ], + [ + 39.262838493462255, + -6.771634543496247 + ], + [ + 39.262821747451255, + -6.771719954194481 + ], + [ + 39.26265424567296, + -6.771690993457386 + ], + [ + 39.26268995014445, + -6.771860885107266 + ], + [ + 39.26252831334852, + -6.771895873157618 + ], + [ + 39.26252880337638, + -6.7719554235439245 + ], + [ + 39.26210122775403, + -6.771977406295051 + ], + [ + 39.26143116288968, + -6.772125372485002 + ], + [ + 39.2614075982154, + -6.772141135811242 + ], + [ + 39.2613973736888, + -6.772275813955157 + ], + [ + 39.260536340561174, + -6.772228258989134 + ], + [ + 39.26053980618854, + -6.772319083364469 + ], + [ + 39.26056969675572, + -6.772373190295851 + ], + [ + 39.26060315386137, + -6.772554749985303 + ], + [ + 39.26059568903891, + -6.772595510376657 + ], + [ + 39.26001518300299, + -6.772559851743274 + ], + [ + 39.25890041510944, + -6.7725543793501695 + ], + [ + 39.258876087403834, + -6.772494197053711 + ], + [ + 39.258514479088554, + -6.772422102891361 + ], + [ + 39.258340434530666, + -6.772428219316269 + ], + [ + 39.25828032895121, + -6.77272075666584 + ], + [ + 39.25826082874752, + -6.772915188024547 + ], + [ + 39.25823949031402, + -6.772922057829271 + ], + [ + 39.2578520090327, + -6.772838102931263 + ], + [ + 39.257888798127965, + -6.77312332117879 + ], + [ + 39.25787979922622, + -6.773136270542293 + ], + [ + 39.25688475867173, + -6.773097642255739 + ], + [ + 39.25682520466523, + -6.773109721503685 + ], + [ + 39.25660478951343, + -6.773091077694639 + ], + [ + 39.255055254694156, + -6.772380238732794 + ], + [ + 39.25421275712266, + -6.771620622438099 + ], + [ + 39.25404556903243, + -6.77004589995448 + ], + [ + 39.25403029430106, + -6.769728767128998 + ], + [ + 39.25411994186844, + -6.768221861425687 + ], + [ + 39.254234107717096, + -6.767341435882211 + ], + [ + 39.25545106018141, + -6.764159936003817 + ], + [ + 39.257116110067585, + -6.76294877364334 + ], + [ + 39.25718438415638, + -6.762917093607382 + ], + [ + 39.25719972988617, + -6.762889019397921 + ], + [ + 39.257442153683776, + -6.76271321325156 + ], + [ + 39.25823278499986, + -6.762669559070356 + ], + [ + 39.25834142312088, + -6.762242194863409 + ], + [ + 39.25939647121495, + -6.762572558084997 + ], + [ + 39.25940845544633, + -6.762487777603404 + ], + [ + 39.259435774764846, + -6.762476198533605 + ], + [ + 39.26006839728735, + -6.76261436674474 + ], + [ + 39.260386403814906, + -6.762668411712047 + ], + [ + 39.260437484245585, + -6.762439496926193 + ], + [ + 39.260004647501674, + -6.762312837170598 + ], + [ + 39.2598716936977, + -6.762259959251641 + ], + [ + 39.2600401439903, + -6.761820065451443 + ], + [ + 39.26029388247496, + -6.761028721580892 + ], + [ + 39.26032420174658, + -6.761018967933076 + ], + [ + 39.26053391798681, + -6.76114659187534 + ], + [ + 39.260536816410294, + -6.760851252611107 + ], + [ + 39.260557853080336, + -6.760831034771786 + ], + [ + 39.260566844200056, + -6.76074069093421 + ], + [ + 39.26036239395784, + -6.760812697920982 + ], + [ + 39.26027824156397, + -6.760662075341912 + ], + [ + 39.261001400117976, + -6.760133550248436 + ], + [ + 39.261527087791784, + -6.759873405077786 + ], + [ + 39.26858580547449, + -6.759308696494632 + ], + [ + 39.268890992058246, + -6.759302984619273 + ], + [ + 39.268903430340835, + -6.759284771586644 + ], + [ + 39.26896542655929, + -6.759278367546962 + ], + [ + 39.271286224101196, + -6.759102343973786 + ], + [ + 39.27211963371433, + -6.759204458764863 + ], + [ + 39.27236321137411, + -6.759271479674409 + ], + [ + 39.273154184137965, + -6.7601369678318965 + ], + [ + 39.27316422844033, + -6.760700644939782 + ], + [ + 39.27314084480545, + -6.7619837448331745 + ], + [ + 39.27305675463236, + -6.762505234243227 + ], + [ + 39.273056789844496, + -6.762534967504247 + ], + [ + 39.27312507291691, + -6.762521393506317 + ], + [ + 39.27313212710874, + -6.76255601845254 + ], + [ + 39.27310309297801, + -6.764507772203796 + ], + [ + 39.27308849603215, + -6.764558304932267 + ], + [ + 39.27300138154325, + -6.764546994635472 + ], + [ + 39.273024316262344, + -6.7646614152403 + ], + [ + 39.27304589268655, + -6.7646695624275575 + ], + [ + 39.27304617892309, + -6.765101677547554 + ], + [ + 39.27308204747948, + -6.7651152272390975 + ], + [ + 39.27309139442161, + -6.765137274306364 + ], + [ + 39.273051905630446, + -6.765239264368901 + ], + [ + 39.27306448349893, + -6.765504735996792 + ], + [ + 39.27308187939778, + -6.765516334329867 + ], + [ + 39.27308560012812, + -6.765549913380341 + ], + [ + 39.27304752697193, + -6.767501671978607 + ], + [ + 39.273038935703134, + -6.767516058055352 + ], + [ + 39.27299835422545, + -6.7675217280475755 + ], + [ + 39.27299933800813, + -6.767537832177631 + ], + [ + 39.273045495033486, + -6.767541113558746 + ], + [ + 39.273050590782745, + -6.767592028459917 + ], + [ + 39.27302400267546, + -6.768534259451833 + ], + [ + 39.272968932976305, + -6.772411177910341 + ], + [ + 39.272959627433714, + -6.772630668635193 + ], + [ + 39.272905788858104, + -6.772643489838023 + ], + [ + 39.27288173837768, + -6.772739885404247 + ], + [ + 39.272882307015124, + -6.7727514232524175 + ], + [ + 39.272956057298394, + -6.772741000926849 + ], + [ + 39.272963123503956, + -6.772796709421321 + ], + [ + 39.27286982682731, + -6.778350777504887 + ], + [ + 39.27283086855745, + -6.7790374037343115 + ], + [ + 39.272701979976624, + -6.779284945399111 + ], + [ + 39.272261619559565, + -6.779665292928737 + ], + [ + 39.27210271074345, + -6.7797571049359115 + ], + [ + 39.271704543803665, + -6.779784747451681 + ], + [ + 39.27144452806939, + -6.779784849288132 + ], + [ + 39.27115738781928, + -6.779758148606385 + ], + [ + 39.27049709925575, + -6.779461996132346 + ], + [ + 39.270493082234935, + -6.779326099696981 + ], + [ + 39.2702131801902, + -6.779330763890751 + ], + [ + 39.26995991242604, + -6.779214787256136 + ], + [ + 39.2699510390659, + -6.77909635634638 + ], + [ + 39.26977275112402, + -6.779102490914896 + ], + [ + 39.26968410885647, + -6.779086412311449 + ], + [ + 39.26966426752008, + -6.77902210533535 + ], + [ + 39.269673217618006, + -6.778939901472921 + ], + [ + 39.26934578546989, + -6.778920487053642 + ], + [ + 39.26932971998377, + -6.778857872932586 + ], + [ + 39.26936566177434, + -6.778547988756392 + ], + [ + 39.2693481357915, + -6.778494457194883 + ], + [ + 39.269311412694705, + -6.778506382971034 + ], + [ + 39.2692772941224, + -6.778497070722168 + ], + [ + 39.26926014396197, + -6.778408889724252 + ] + ] + ], + "type": "Polygon" }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "image": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/dar/a017f9/a017f9.tif", - "type": "image/tiff; application=geotiff; profile=cloud-optimized", - "title": "GeoTIFF" - } - }, - "collection": "dar" + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "image": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/dar/a017f9/a017f9.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "GeoTIFF" + } + }, + "bbox": [ + 39.25403029430106, + -6.779784892393674, + 39.2731659202684, + -6.759102343973786 + ], + "stac_extensions": [], + "collection": "dar" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/dar/b15fce-labels/b15fce-labels.json b/tests/data-files/catalogs/test-case-4/dar/b15fce-labels/b15fce-labels.json index f536383c7..80c95e106 100644 --- a/tests/data-files/catalogs/test-case-4/dar/b15fce-labels/b15fce-labels.json +++ b/tests/data-files/catalogs/test-case-4/dar/b15fce-labels/b15fce-labels.json @@ -1,181 +1,182 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "b15fce-labels", - "properties": { - "label:description": "Geojson building labels for scene b15fce", - "area": "dar", - "label:type": "vector", - "label:properties": [ - "building" - ], - "label:overviews": [ - { - "property_key": "building", - "counts": [ - { - "name": "yes", - "count": 23458 - } - ] - } - ], - "license": "ODbL-1.0", - "datetime": "2015-05-20T00:00:00Z", - "label:classes": [ - { - "name": "building", - "classes": [ - "yes" + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "b15fce-labels", + "properties": { + "label:description": "Geojson building labels for scene b15fce", + "area": "dar", + "label:type": "vector", + "label:properties": [ + "building" + ], + "label:overviews": [ + { + "property_key": "building", + "counts": [ + { + "name": "yes", + "count": 23458 + } + ] + } + ], + "license": "ODbL-1.0", + "datetime": "2015-05-20T00:00:00Z", + "label:classes": [ + { + "name": "building", + "classes": [ + "yes" + ] + } ] - } - ] - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [ - 39.23203578164141, - -6.79095224397089 - ], - [ - 39.23213878048826, - -6.789102523233581 - ], - [ - 39.23424736448953, - -6.786630199691261 - ], - [ - 39.24240426507967, - -6.787815561113139 - ], - [ - 39.24837432725425, - -6.789223358831122 - ], - [ - 39.24999459439558, - -6.792382403376687 - ], - [ - 39.250160911880975, - -6.792733513382334 - ], - [ - 39.25165161397758, - -6.799519472339792 - ], - [ - 39.252150559748735, - -6.805433243902031 - ], - [ - 39.25215431131969, - -6.80558550517296 - ], - [ - 39.252130818230775, - -6.805626361276197 - ], - [ - 39.252021891878556, - -6.805745910544025 - ], - [ - 39.251481491584926, - -6.806062768768616 - ], - [ - 39.25140290770081, - -6.806085857110386 - ], - [ - 39.246437022609506, - -6.805537709438442 - ], - [ - 39.24639412436282, - -6.805529495943441 - ], - [ - 39.24634489238881, - -6.805491830951268 - ], - [ - 39.245924545758825, - -6.805105022778037 - ], - [ - 39.245898468007404, - -6.805097690645329 - ], - [ - 39.23970175749278, - -6.804381219357365 - ], - [ - 39.23893051436519, - -6.80327787406404 - ], - [ - 39.23890949996164, - -6.803265948061028 - ], - [ - 39.23450774412018, - -6.80280156767769 - ], - [ - 39.23210317956967, - -6.801549954393777 - ], - [ - 39.231930285079976, - -6.801280005215021 - ], - [ - 39.23158398015406, - -6.799288999676232 - ], - [ - 39.23203578164141, - -6.79095224397089 + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + 39.23203578164141, + -6.79095224397089 + ], + [ + 39.23213878048826, + -6.789102523233581 + ], + [ + 39.23424736448953, + -6.786630199691261 + ], + [ + 39.24240426507967, + -6.787815561113139 + ], + [ + 39.24837432725425, + -6.789223358831122 + ], + [ + 39.24999459439558, + -6.792382403376687 + ], + [ + 39.250160911880975, + -6.792733513382334 + ], + [ + 39.25165161397758, + -6.799519472339792 + ], + [ + 39.252150559748735, + -6.805433243902031 + ], + [ + 39.25215431131969, + -6.80558550517296 + ], + [ + 39.252130818230775, + -6.805626361276197 + ], + [ + 39.252021891878556, + -6.805745910544025 + ], + [ + 39.251481491584926, + -6.806062768768616 + ], + [ + 39.25140290770081, + -6.806085857110386 + ], + [ + 39.246437022609506, + -6.805537709438442 + ], + [ + 39.24639412436282, + -6.805529495943441 + ], + [ + 39.24634489238881, + -6.805491830951268 + ], + [ + 39.245924545758825, + -6.805105022778037 + ], + [ + 39.245898468007404, + -6.805097690645329 + ], + [ + 39.23970175749278, + -6.804381219357365 + ], + [ + 39.23893051436519, + -6.80327787406404 + ], + [ + 39.23890949996164, + -6.803265948061028 + ], + [ + 39.23450774412018, + -6.80280156767769 + ], + [ + 39.23210317956967, + -6.801549954393777 + ], + [ + 39.231930285079976, + -6.801280005215021 + ], + [ + 39.23158398015406, + -6.799288999676232 + ], + [ + 39.23203578164141, + -6.79095224397089 + ] + ] ] - ] - ] - }, - "bbox": [ - 39.231583919750726, - -6.806085900208043, - 39.25215435443532, - -6.786630132161881 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "labels": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/dar/b15fce-labels/b15fce.geojson", + "type": "application/geo+json" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "labels": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/dar/b15fce-labels/b15fce.geojson", - "type": "application/geo+json" - } - }, - "stac_extensions": [ - "label" - ] + "bbox": [ + 39.231583919750726, + -6.806085900208043, + 39.25215435443532, + -6.786630132161881 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "dar" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/dar/b15fce/b15fce.json b/tests/data-files/catalogs/test-case-4/dar/b15fce/b15fce.json index 4d0a0af71..9920d57d4 100644 --- a/tests/data-files/catalogs/test-case-4/dar/b15fce/b15fce.json +++ b/tests/data-files/catalogs/test-case-4/dar/b15fce/b15fce.json @@ -1,156 +1,157 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "b15fce", - "properties": { - "area": "dar", - "license": "CC-BY-4.0", - "datetime": "2015-05-20T00:00:00Z" - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [ - 39.23203578164141, - -6.79095224397089 - ], - [ - 39.23213878048826, - -6.789102523233581 - ], - [ - 39.23424736448953, - -6.786630199691261 - ], - [ - 39.24240426507967, - -6.787815561113139 - ], - [ - 39.24837432725425, - -6.789223358831122 - ], - [ - 39.24999459439558, - -6.792382403376687 - ], - [ - 39.250160911880975, - -6.792733513382334 - ], - [ - 39.25165161397758, - -6.799519472339792 - ], - [ - 39.252150559748735, - -6.805433243902031 - ], - [ - 39.25215431131969, - -6.80558550517296 - ], - [ - 39.252130818230775, - -6.805626361276197 - ], - [ - 39.252021891878556, - -6.805745910544025 - ], - [ - 39.251481491584926, - -6.806062768768616 - ], - [ - 39.25140290770081, - -6.806085857110386 - ], - [ - 39.246437022609506, - -6.805537709438442 - ], - [ - 39.24639412436282, - -6.805529495943441 - ], - [ - 39.24634489238881, - -6.805491830951268 - ], - [ - 39.245924545758825, - -6.805105022778037 - ], - [ - 39.245898468007404, - -6.805097690645329 - ], - [ - 39.23970175749278, - -6.804381219357365 - ], - [ - 39.23893051436519, - -6.80327787406404 - ], - [ - 39.23890949996164, - -6.803265948061028 - ], - [ - 39.23450774412018, - -6.80280156767769 - ], - [ - 39.23210317956967, - -6.801549954393777 - ], - [ - 39.231930285079976, - -6.801280005215021 - ], - [ - 39.23158398015406, - -6.799288999676232 - ], - [ - 39.23203578164141, - -6.79095224397089 + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "b15fce", + "properties": { + "area": "dar", + "license": "CC-BY-4.0", + "datetime": "2015-05-20T00:00:00Z" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + 39.23203578164141, + -6.79095224397089 + ], + [ + 39.23213878048826, + -6.789102523233581 + ], + [ + 39.23424736448953, + -6.786630199691261 + ], + [ + 39.24240426507967, + -6.787815561113139 + ], + [ + 39.24837432725425, + -6.789223358831122 + ], + [ + 39.24999459439558, + -6.792382403376687 + ], + [ + 39.250160911880975, + -6.792733513382334 + ], + [ + 39.25165161397758, + -6.799519472339792 + ], + [ + 39.252150559748735, + -6.805433243902031 + ], + [ + 39.25215431131969, + -6.80558550517296 + ], + [ + 39.252130818230775, + -6.805626361276197 + ], + [ + 39.252021891878556, + -6.805745910544025 + ], + [ + 39.251481491584926, + -6.806062768768616 + ], + [ + 39.25140290770081, + -6.806085857110386 + ], + [ + 39.246437022609506, + -6.805537709438442 + ], + [ + 39.24639412436282, + -6.805529495943441 + ], + [ + 39.24634489238881, + -6.805491830951268 + ], + [ + 39.245924545758825, + -6.805105022778037 + ], + [ + 39.245898468007404, + -6.805097690645329 + ], + [ + 39.23970175749278, + -6.804381219357365 + ], + [ + 39.23893051436519, + -6.80327787406404 + ], + [ + 39.23890949996164, + -6.803265948061028 + ], + [ + 39.23450774412018, + -6.80280156767769 + ], + [ + 39.23210317956967, + -6.801549954393777 + ], + [ + 39.231930285079976, + -6.801280005215021 + ], + [ + 39.23158398015406, + -6.799288999676232 + ], + [ + 39.23203578164141, + -6.79095224397089 + ] + ] ] - ] - ] - }, - "bbox": [ - 39.231583919750726, - -6.806085900208043, - 39.25215435443532, - -6.786630132161881 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "image": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/dar/b15fce/b15fce.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "GeoTIFF" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "image": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/dar/b15fce/b15fce.tif", - "type": "image/tiff; application=geotiff; profile=cloud-optimized", - "title": "GeoTIFF" - } - }, - "collection": "dar" + "bbox": [ + 39.231583919750726, + -6.806085900208043, + 39.25215435443532, + -6.786630132161881 + ], + "stac_extensions": [], + "collection": "dar" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/dar/collection.json b/tests/data-files/catalogs/test-case-4/dar/collection.json index 2b58d6a92..8048d22e1 100644 --- a/tests/data-files/catalogs/test-case-4/dar/collection.json +++ b/tests/data-files/catalogs/test-case-4/dar/collection.json @@ -1,6 +1,7 @@ { + "type": "Collection", "id": "dar", - "stac_version": "1.0.0-beta.2", + "stac_version": "1.0.0-rc.3", "description": "Tier 1 training data from dar", "links": [ { @@ -74,6 +75,7 @@ "type": "application/json" } ], + "stac_extensions": [], "extent": { "spatial": { "bbox": [ @@ -94,8 +96,5 @@ ] } }, - "license": "various", - "stac_extensions": [ - "label" - ] + "license": "various" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/dar/f883a0-labels/f883a0-labels.json b/tests/data-files/catalogs/test-case-4/dar/f883a0-labels/f883a0-labels.json index 86b53fa4d..1bb93fb69 100644 --- a/tests/data-files/catalogs/test-case-4/dar/f883a0-labels/f883a0-labels.json +++ b/tests/data-files/catalogs/test-case-4/dar/f883a0-labels/f883a0-labels.json @@ -1,1291 +1,1292 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "f883a0-labels", - "properties": { - "label:description": "Geojson building labels for scene f883a0", - "area": "dar", - "label:type": "vector", - "label:properties": [ - "building" - ], - "label:overviews": [ - { - "property_key": "building", - "counts": [ - { - "name": "yes", - "count": 35952 - } - ] - } - ], - "license": "ODbL-1.0", - "datetime": "2017-11-01T00:00:00Z", - "label:classes": [ - { - "name": "building", - "classes": [ - "yes" - ] - } - ] - }, - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 39.27315718647447, - -6.804030897967275 - ], - [ - 39.273165048748965, - -6.804015735580677 - ], - [ - 39.273213892047806, - -6.804006275126262 - ], - [ - 39.27322980988637, - -6.804022244653453 - ], - [ - 39.273170342425956, - -6.804047430372633 - ], - [ - 39.27315718647447, - -6.804030897967275 - ] - ] - ], - [ - [ - [ - 39.273270319050496, - -6.804022808953547 - ], - [ - 39.273288769025, - -6.803992819792749 - ], - [ - 39.27331911984259, - -6.804029517800871 - ], - [ - 39.2732773025055, - -6.804036732038151 - ], - [ - 39.273270319050496, - -6.804022808953547 - ] - ] - ], - [ - [ - [ - 39.273416845431285, - -6.803993658369023 - ], - [ - 39.273432966277255, - -6.803999383623384 - ], - [ - 39.27345314382025, - -6.803979786475935 - ], - [ - 39.27322440426283, - -6.803973842746188 - ], - [ - 39.273203984545894, - -6.804001738617233 - ], - [ - 39.27307652605739, - -6.804015326271316 - ], - [ - 39.27305748415282, - -6.804061875764365 - ], - [ - 39.27243654623383, - -6.804062182204895 - ], - [ - 39.272422506412305, - -6.804030782430953 - ], - [ - 39.27233818959957, - -6.804033592321105 - ], - [ - 39.27232684217891, - -6.804062287567047 - ], - [ - 39.27050720474849, - -6.804063308351038 - ], - [ - 39.27050003464541, - -6.804267571943514 - ], - [ - 39.26958162504325, - -6.804292771833833 - ], - [ - 39.268183769535355, - -6.804289804955942 - ], - [ - 39.26817548170555, - -6.804064606402513 - ], - [ - 39.26638040640152, - -6.804065554449549 - ], - [ - 39.26635869387405, - -6.80392326747663 - ], - [ - 39.26612966449484, - -6.803973347620189 - ], - [ - 39.2660934787131, - -6.804065755940294 - ], - [ - 39.26187296555017, - -6.804068058726235 - ], - [ - 39.26184507218486, - -6.804052028033205 - ], - [ - 39.26184066298603, - -6.804023191210663 - ], - [ - 39.26172396812868, - -6.804068139349033 - ], - [ - 39.25777183400359, - -6.804070261106554 - ], - [ - 39.257755345525474, - -6.804004808291634 - ], - [ - 39.25731554868908, - -6.804070460389402 - ], - [ - 39.256625459443185, - -6.804070870513325 - ], - [ - 39.25662348593693, - -6.80422297079218 - ], - [ - 39.256462846950114, - -6.804260546096121 - ], - [ - 39.256084987159134, - -6.804259012772288 - ], - [ - 39.256069700572326, - -6.804123376288454 - ], - [ - 39.25557123594966, - -6.804199546422531 - ], - [ - 39.25540366700173, - -6.804257868759697 - ], - [ - 39.25364580884159, - -6.804253286905217 - ], - [ - 39.25336404330564, - -6.804245528109689 - ], - [ - 39.25184949473127, - -6.804063493477143 - ], - [ - 39.25045725022109, - -6.803626776738144 - ], - [ - 39.250038582443665, - -6.80287820958753 - ], - [ - 39.25000304212214, - -6.802509337350906 - ], - [ - 39.24988415760574, - -6.799080315984306 - ], - [ - 39.24990450849855, - -6.799063247023449 - ], - [ - 39.2498947561629, - -6.798995102709657 - ], - [ - 39.24988086958492, - -6.79898550113401 - ], - [ - 39.249810881599906, - -6.796966175954005 - ], - [ - 39.24981645844359, - -6.796947177743604 - ], - [ - 39.249872411376465, - -6.796943310209003 - ], - [ - 39.249872317302916, - -6.79667664523118 - ], - [ - 39.24989594446884, - -6.796632192786874 - ], - [ - 39.2498929959209, - -6.796620487479649 - ], - [ - 39.24981140260522, - -6.796653264268834 - ], - [ - 39.249799651394305, - -6.796639604421224 - ], - [ - 39.249702848316815, - -6.793849310612861 - ], - [ - 39.249709580102994, - -6.793444194527318 - ], - [ - 39.24968269293236, - -6.793263269989816 - ], - [ - 39.24966102436161, - -6.792603766179727 - ], - [ - 39.24967954445545, - -6.791728669025114 - ], - [ - 39.24970804593678, - -6.791366446494281 - ], - [ - 39.24968767919196, - -6.791352173642583 - ], - [ - 39.24969901238331, - -6.790812445435837 - ], - [ - 39.24971718787532, - -6.790709956750732 - ], - [ - 39.24976000940216, - -6.790676190366502 - ], - [ - 39.24974335811433, - -6.79066757715095 - ], - [ - 39.24975954380845, - -6.7905720968061 - ], - [ - 39.24971030856871, - -6.790285552729824 - ], - [ - 39.24971251701262, - -6.790166259808814 - ], - [ - 39.249755177302276, - -6.79007657102466 - ], - [ - 39.24978363439594, - -6.790069338302176 - ], - [ - 39.24973059995279, - -6.789901141277205 - ], - [ - 39.249748519583505, - -6.789843130737693 - ], - [ - 39.249722462770514, - -6.789712522643217 - ], - [ - 39.249757283518974, - -6.788060421836336 - ], - [ - 39.24981581028674, - -6.788035256591358 - ], - [ - 39.2497613539383, - -6.787878110167098 - ], - [ - 39.249768572097224, - -6.787518805148783 - ], - [ - 39.25004009533414, - -6.787434103342062 - ], - [ - 39.25002896611271, - -6.787302674153842 - ], - [ - 39.25004835160351, - -6.787293592535141 - ], - [ - 39.25004462643536, - -6.787248062083075 - ], - [ - 39.249913527740446, - -6.787275621098578 - ], - [ - 39.24987623121805, - -6.787223585244646 - ], - [ - 39.2498870533108, - -6.78675947061919 - ], - [ - 39.249878668979136, - -6.786651689669421 - ], - [ - 39.249854185335714, - -6.786644521595329 - ], - [ - 39.24985427604204, - -6.786567866890232 - ], - [ - 39.249878150583925, - -6.786543683174986 - ], - [ - 39.24987767258752, - -6.786514031590554 - ], - [ - 39.24985595176083, - -6.786480788612282 - ], - [ - 39.24985427458511, - -6.786004693765936 - ], - [ - 39.249835799952045, - -6.785985440085538 - ], - [ - 39.24981894796509, - -6.785692711962167 - ], - [ - 39.249835592123326, - -6.785666857043904 - ], - [ - 39.2498132441077, - -6.785399014698585 - ], - [ - 39.24982665102962, - -6.785376346020647 - ], - [ - 39.24981460672529, - -6.785349524356427 - ], - [ - 39.24981956779118, - -6.785099760997835 - ], - [ - 39.249871024621996, - -6.783491089857915 - ], - [ - 39.24990124402507, - -6.783476958079939 - ], - [ - 39.24987648913789, - -6.783320417149405 - ], - [ - 39.24990659151731, - -6.782389387144009 - ], - [ - 39.25010086176018, - -6.782346474227426 - ], - [ - 39.2501017767606, - -6.78232629074711 - ], - [ - 39.250066934399854, - -6.782156990037679 - ], - [ - 39.24992289431197, - -6.782182852009128 - ], - [ - 39.2499138298333, - -6.782153922351434 - ], - [ - 39.25006519231678, - -6.777778404257647 - ], - [ - 39.250159011995514, - -6.775687803188281 - ], - [ - 39.250652695356244, - -6.774710612955933 - ], - [ - 39.25973527817753, - -6.774051636265581 - ], - [ - 39.26420907625315, - -6.774027485936578 - ], - [ - 39.26430505647687, - -6.774065405657963 - ], - [ - 39.26433909336156, - -6.774026490186999 - ], - [ - 39.27016488290843, - -6.773994609904983 - ], - [ - 39.27021692938301, - -6.773995269543569 - ], - [ - 39.27026644245446, - -6.774033162706626 - ], - [ - 39.27031016915434, - -6.773994066588543 - ], - [ - 39.27159183301611, - -6.773986876672367 - ], - [ - 39.27168780046295, - -6.774108785772873 - ], - [ - 39.271686763240815, - -6.774136172079665 - ], - [ - 39.27192122999216, - -6.774436870625464 - ], - [ - 39.27225338516659, - -6.773984336984419 - ], - [ - 39.27280594364432, - -6.773980646345491 - ], - [ - 39.274209296190605, - -6.774041415140496 - ], - [ - 39.27802675727596, - -6.774426374513278 - ], - [ - 39.27864214751531, - -6.774515880892984 - ], - [ - 39.280023369706576, - -6.774755350012424 - ], - [ - 39.28050916887765, - -6.775147428625842 - ], - [ - 39.28074438487075, - -6.775756768054177 - ], - [ - 39.28081527672994, - -6.776054440091325 - ], - [ - 39.28082717168011, - -6.776695908769849 - ], - [ - 39.2807657423886, - -6.776717815104587 - ], - [ - 39.280775518747866, - -6.776754016935989 - ], - [ - 39.280818510912624, - -6.776750660815322 - ], - [ - 39.28082911053632, - -6.776772724163326 - ], - [ - 39.28091689459758, - -6.781345598621182 - ], - [ - 39.28080388738358, - -6.7813839793259 - ], - [ - 39.28084388776356, - -6.781454612139605 - ], - [ - 39.28085319429884, - -6.78143154903115 - ], - [ - 39.28087584049512, - -6.781437812905911 - ], - [ - 39.28086609036416, - -6.781472364858208 - ], - [ - 39.280881881877654, - -6.781483136266438 - ], - [ - 39.28086943504425, - -6.78149915312294 - ], - [ - 39.28088554011426, - -6.781534324494014 - ], - [ - 39.280873569959816, - -6.781638136661505 - ], - [ - 39.28092499494767, - -6.781750298004826 - ], - [ - 39.28095457939287, - -6.783298331704033 - ], - [ - 39.28086026889085, - -6.783333866874134 - ], - [ - 39.280959342849336, - -6.783533751067348 - ], - [ - 39.28096937002043, - -6.784069342141371 - ], - [ - 39.28095243868693, - -6.78408149778495 - ], - [ - 39.280970796197394, - -6.784135018997731 - ], - [ - 39.280990362247046, - -6.785161799575521 - ], - [ - 39.28090314512198, - -6.785218441815514 - ], - [ - 39.28094438037573, - -6.785212514854102 - ], - [ - 39.280994123789, - -6.785340368033896 - ], - [ - 39.28103471876776, - -6.787446616974048 - ], - [ - 39.281027381291025, - -6.787464990541269 - ], - [ - 39.280827513135605, - -6.787500088788153 - ], - [ - 39.28099960926122, - -6.78779064973444 - ], - [ - 39.28100210101566, - -6.787851081760929 - ], - [ - 39.281026585687755, - -6.787859226828259 - ], - [ - 39.28102285279996, - -6.787966432946407 - ], - [ - 39.28093203937434, - -6.788005057346286 - ], - [ - 39.28100675911835, - -6.788204324299769 - ], - [ - 39.280997459334884, - -6.788308436132202 - ], - [ - 39.28105380334917, - -6.788440096324056 - ], - [ - 39.281068553938496, - -6.789216155958014 - ], - [ - 39.28096066849781, - -6.789245774186083 - ], - [ - 39.281073839006595, - -6.789477514362669 - ], - [ - 39.28114397070973, - -6.793117958745426 - ], - [ - 39.28113420729278, - -6.79383486840148 - ], - [ - 39.281114726156694, - -6.793847842189681 - ], - [ - 39.28113330952829, - -6.79388250834817 - ], - [ - 39.281129262608935, - -6.794159983557968 - ], - [ - 39.28109084175889, - -6.794179680568165 - ], - [ - 39.28112752361519, - -6.794277502669122 - ], - [ - 39.28111635395094, - -6.795038314028078 - ], - [ - 39.281016070626016, - -6.795075741198945 - ], - [ - 39.281112775297714, - -6.795250226366647 - ], - [ - 39.2810949704288, - -6.79646195887955 - ], - [ - 39.2809583747182, - -6.796479910277594 - ], - [ - 39.280976796828014, - -6.79655746965899 - ], - [ - 39.28106599069538, - -6.796757139303622 - ], - [ - 39.28105528128861, - -6.79686803066901 - ], - [ - 39.281087453345336, - -6.796987885295481 - ], - [ - 39.28108073143122, - -6.797439731548687 - ], - [ - 39.28083992809423, - -6.797461906062759 - ], - [ - 39.28083642610969, - -6.797501481434426 - ], - [ - 39.28072006370183, - -6.797559721622083 - ], - [ - 39.280792511077834, - -6.797755460113359 - ], - [ - 39.280782299142885, - -6.797822644537164 - ], - [ - 39.28087877377628, - -6.798094898764859 - ], - [ - 39.28087160779872, - -6.798109486776828 - ], - [ - 39.28084495591411, - -6.798106189716947 - ], - [ - 39.28091358669126, - -6.798282661131834 - ], - [ - 39.280894058903186, - -6.798303988028182 - ], - [ - 39.28089993648302, - -6.798318476273004 - ], - [ - 39.28094807709286, - -6.798317376152552 - ], - [ - 39.28097704846284, - -6.798338565814496 - ], - [ - 39.280968589108724, - -6.798359909541208 - ], - [ - 39.28098862495911, - -6.798363833982053 - ], - [ - 39.28106384308544, - -6.798560924842693 - ], - [ - 39.281060047781274, - -6.798789172787439 - ], - [ - 39.280964648702366, - -6.79881579282715 - ], - [ - 39.2810549062557, - -6.799182593389792 - ], - [ - 39.281051210712, - -6.799417431324301 - ], - [ - 39.281012045218766, - -6.799461973169469 - ], - [ - 39.28092870982996, - -6.799469616595563 - ], - [ - 39.28102911738072, - -6.800116395040011 - ], - [ - 39.28096755147659, - -6.800136517203233 - ], - [ - 39.28098227562801, - -6.800231504054254 - ], - [ - 39.28092089023231, - -6.800365292854012 - ], - [ - 39.28092243227157, - -6.800466481559217 - ], - [ - 39.28099285109281, - -6.800487505251037 - ], - [ - 39.2809865598948, - -6.80056017366214 - ], - [ - 39.281022039297945, - -6.800676509145848 - ], - [ - 39.28100512867587, - -6.800686027414948 - ], - [ - 39.28094639492564, - -6.800673573505817 - ], - [ - 39.28098960816634, - -6.80080288458438 - ], - [ - 39.28100608830849, - -6.800808079923416 - ], - [ - 39.28101818264724, - -6.800788226357124 - ], - [ - 39.28103090221736, - -6.800799071421509 - ], - [ - 39.28100953313295, - -6.802247229426974 - ], - [ - 39.280969530277055, - -6.802983496860963 - ], - [ - 39.279742849863105, - -6.803751726145401 - ], - [ - 39.279491514203464, - -6.803861587800235 - ], - [ - 39.277158588001264, - -6.804087251350162 - ], - [ - 39.27513747683199, - -6.804142100699255 - ], - [ - 39.27511678207263, - -6.804135692385428 - ], - [ - 39.2751163497056, - -6.804060709416309 - ], - [ - 39.27391722620214, - -6.804061389785589 - ], - [ - 39.27385826397281, - -6.804047806856571 - ], - [ - 39.27384911606231, - -6.803999913343275 - ], - [ - 39.2735965361418, - -6.80398525563719 - ], - [ - 39.273500708320924, - -6.80401301734282 - ], - [ - 39.27346293523808, - -6.804003966970788 - ], - [ - 39.27342162790581, - -6.804025593648304 - ], - [ - 39.27340672680942, - -6.804008608011346 - ], - [ - 39.273416845431285, - -6.803993658369023 - ] - ], - [ - [ - 39.2734931545649, - -6.80398387288763 - ], - [ - 39.27349774748707, - -6.803981148820998 - ], - [ - 39.2734846042507, - -6.80398069373159 - ], - [ - 39.27348722790041, - -6.80398493599873 - ], - [ - 39.2734931545649, - -6.80398387288763 - ] - ], - [ - [ - 39.281045469223024, - -6.796406485350073 - ], - [ - 39.28104614552522, - -6.79640624303539 - ], - [ - 39.28104624219622, - -6.796405856316271 - ], - [ - 39.28104544832558, - -6.796406065132672 - ], - [ - 39.281045469223024, - -6.796406485350073 - ] + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "f883a0-labels", + "properties": { + "label:description": "Geojson building labels for scene f883a0", + "area": "dar", + "label:type": "vector", + "label:properties": [ + "building" ], - [ - [ - 39.25013462741531, - -6.7822284539465 - ], - [ - 39.250139342204406, - -6.782225634227249 - ], - [ - 39.25013885529763, - -6.782223167263246 - ], - [ - 39.25013601751904, - -6.782223433931297 - ], - [ - 39.25013462741531, - -6.7822284539465 - ] + "label:overviews": [ + { + "property_key": "building", + "counts": [ + { + "name": "yes", + "count": 35952 + } + ] + } ], - [ - [ - 39.250133340148714, - -6.782197609422264 - ], - [ - 39.25013227568109, - -6.782192336183768 - ], - [ - 39.25013085449504, - -6.782186240541199 - ], - [ - 39.25012984461586, - -6.782195145644085 - ], - [ - 39.250133340148714, - -6.782197609422264 - ] + "license": "ODbL-1.0", + "datetime": "2017-11-01T00:00:00Z", + "label:classes": [ + { + "name": "building", + "classes": [ + "yes" + ] + } ] - ], - [ - [ - [ - 39.28101229778558, - -6.800726929325503 - ], - [ - 39.28102979517802, - -6.800722356034623 - ], - [ - 39.28102777800557, - -6.800751554944212 - ], - [ - 39.281011984140875, - -6.800747680790295 - ], - [ - 39.28101229778558, - -6.800726929325503 - ] - ] - ], - [ - [ - [ - 39.28098638863562, - -6.800732494588853 - ], - [ - 39.280997245783674, - -6.800723485911647 - ], - [ - 39.28100583405759, - -6.80073429499442 - ], - [ - 39.280995019972025, - -6.800742416990294 - ], - [ - 39.28098638863562, - -6.800732494588853 - ] - ] - ], - [ - [ - [ - 39.27333576292948, - -6.804020758896268 - ], - [ - 39.27334712034972, - -6.804009856466778 - ], - [ - 39.27335756490539, - -6.804021209097676 - ], - [ - 39.273346206700516, - -6.804030723971451 - ], - [ - 39.27333576292948, - -6.804020758896268 - ] - ] - ], - [ - [ - [ - 39.27338784445309, - -6.804011179704081 - ], - [ - 39.27340165825813, - -6.804007187497802 - ], - [ - 39.27340508925115, - -6.804022507747959 - ], - [ - 39.2733897619233, - -6.804025474696425 - ], - [ - 39.27338784445309, - -6.804011179704081 - ] - ] - ], - [ - [ - [ - 39.28093735076017, - -6.798277365237194 - ], - [ - 39.28094786501646, - -6.798293757944892 - ], - [ - 39.28092636574822, - -6.798297946514793 - ], - [ - 39.28091893391865, - -6.798272295760583 - ], - [ - 39.28093735076017, - -6.798277365237194 - ] + }, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [ + 39.27315718647447, + -6.804030897967275 + ], + [ + 39.273165048748965, + -6.804015735580677 + ], + [ + 39.273213892047806, + -6.804006275126262 + ], + [ + 39.27322980988637, + -6.804022244653453 + ], + [ + 39.273170342425956, + -6.804047430372633 + ], + [ + 39.27315718647447, + -6.804030897967275 + ] + ] + ], + [ + [ + [ + 39.273270319050496, + -6.804022808953547 + ], + [ + 39.273288769025, + -6.803992819792749 + ], + [ + 39.27331911984259, + -6.804029517800871 + ], + [ + 39.2732773025055, + -6.804036732038151 + ], + [ + 39.273270319050496, + -6.804022808953547 + ] + ] + ], + [ + [ + [ + 39.273416845431285, + -6.803993658369023 + ], + [ + 39.273432966277255, + -6.803999383623384 + ], + [ + 39.27345314382025, + -6.803979786475935 + ], + [ + 39.27322440426283, + -6.803973842746188 + ], + [ + 39.273203984545894, + -6.804001738617233 + ], + [ + 39.27307652605739, + -6.804015326271316 + ], + [ + 39.27305748415282, + -6.804061875764365 + ], + [ + 39.27243654623383, + -6.804062182204895 + ], + [ + 39.272422506412305, + -6.804030782430953 + ], + [ + 39.27233818959957, + -6.804033592321105 + ], + [ + 39.27232684217891, + -6.804062287567047 + ], + [ + 39.27050720474849, + -6.804063308351038 + ], + [ + 39.27050003464541, + -6.804267571943514 + ], + [ + 39.26958162504325, + -6.804292771833833 + ], + [ + 39.268183769535355, + -6.804289804955942 + ], + [ + 39.26817548170555, + -6.804064606402513 + ], + [ + 39.26638040640152, + -6.804065554449549 + ], + [ + 39.26635869387405, + -6.80392326747663 + ], + [ + 39.26612966449484, + -6.803973347620189 + ], + [ + 39.2660934787131, + -6.804065755940294 + ], + [ + 39.26187296555017, + -6.804068058726235 + ], + [ + 39.26184507218486, + -6.804052028033205 + ], + [ + 39.26184066298603, + -6.804023191210663 + ], + [ + 39.26172396812868, + -6.804068139349033 + ], + [ + 39.25777183400359, + -6.804070261106554 + ], + [ + 39.257755345525474, + -6.804004808291634 + ], + [ + 39.25731554868908, + -6.804070460389402 + ], + [ + 39.256625459443185, + -6.804070870513325 + ], + [ + 39.25662348593693, + -6.80422297079218 + ], + [ + 39.256462846950114, + -6.804260546096121 + ], + [ + 39.256084987159134, + -6.804259012772288 + ], + [ + 39.256069700572326, + -6.804123376288454 + ], + [ + 39.25557123594966, + -6.804199546422531 + ], + [ + 39.25540366700173, + -6.804257868759697 + ], + [ + 39.25364580884159, + -6.804253286905217 + ], + [ + 39.25336404330564, + -6.804245528109689 + ], + [ + 39.25184949473127, + -6.804063493477143 + ], + [ + 39.25045725022109, + -6.803626776738144 + ], + [ + 39.250038582443665, + -6.80287820958753 + ], + [ + 39.25000304212214, + -6.802509337350906 + ], + [ + 39.24988415760574, + -6.799080315984306 + ], + [ + 39.24990450849855, + -6.799063247023449 + ], + [ + 39.2498947561629, + -6.798995102709657 + ], + [ + 39.24988086958492, + -6.79898550113401 + ], + [ + 39.249810881599906, + -6.796966175954005 + ], + [ + 39.24981645844359, + -6.796947177743604 + ], + [ + 39.249872411376465, + -6.796943310209003 + ], + [ + 39.249872317302916, + -6.79667664523118 + ], + [ + 39.24989594446884, + -6.796632192786874 + ], + [ + 39.2498929959209, + -6.796620487479649 + ], + [ + 39.24981140260522, + -6.796653264268834 + ], + [ + 39.249799651394305, + -6.796639604421224 + ], + [ + 39.249702848316815, + -6.793849310612861 + ], + [ + 39.249709580102994, + -6.793444194527318 + ], + [ + 39.24968269293236, + -6.793263269989816 + ], + [ + 39.24966102436161, + -6.792603766179727 + ], + [ + 39.24967954445545, + -6.791728669025114 + ], + [ + 39.24970804593678, + -6.791366446494281 + ], + [ + 39.24968767919196, + -6.791352173642583 + ], + [ + 39.24969901238331, + -6.790812445435837 + ], + [ + 39.24971718787532, + -6.790709956750732 + ], + [ + 39.24976000940216, + -6.790676190366502 + ], + [ + 39.24974335811433, + -6.79066757715095 + ], + [ + 39.24975954380845, + -6.7905720968061 + ], + [ + 39.24971030856871, + -6.790285552729824 + ], + [ + 39.24971251701262, + -6.790166259808814 + ], + [ + 39.249755177302276, + -6.79007657102466 + ], + [ + 39.24978363439594, + -6.790069338302176 + ], + [ + 39.24973059995279, + -6.789901141277205 + ], + [ + 39.249748519583505, + -6.789843130737693 + ], + [ + 39.249722462770514, + -6.789712522643217 + ], + [ + 39.249757283518974, + -6.788060421836336 + ], + [ + 39.24981581028674, + -6.788035256591358 + ], + [ + 39.2497613539383, + -6.787878110167098 + ], + [ + 39.249768572097224, + -6.787518805148783 + ], + [ + 39.25004009533414, + -6.787434103342062 + ], + [ + 39.25002896611271, + -6.787302674153842 + ], + [ + 39.25004835160351, + -6.787293592535141 + ], + [ + 39.25004462643536, + -6.787248062083075 + ], + [ + 39.249913527740446, + -6.787275621098578 + ], + [ + 39.24987623121805, + -6.787223585244646 + ], + [ + 39.2498870533108, + -6.78675947061919 + ], + [ + 39.249878668979136, + -6.786651689669421 + ], + [ + 39.249854185335714, + -6.786644521595329 + ], + [ + 39.24985427604204, + -6.786567866890232 + ], + [ + 39.249878150583925, + -6.786543683174986 + ], + [ + 39.24987767258752, + -6.786514031590554 + ], + [ + 39.24985595176083, + -6.786480788612282 + ], + [ + 39.24985427458511, + -6.786004693765936 + ], + [ + 39.249835799952045, + -6.785985440085538 + ], + [ + 39.24981894796509, + -6.785692711962167 + ], + [ + 39.249835592123326, + -6.785666857043904 + ], + [ + 39.2498132441077, + -6.785399014698585 + ], + [ + 39.24982665102962, + -6.785376346020647 + ], + [ + 39.24981460672529, + -6.785349524356427 + ], + [ + 39.24981956779118, + -6.785099760997835 + ], + [ + 39.249871024621996, + -6.783491089857915 + ], + [ + 39.24990124402507, + -6.783476958079939 + ], + [ + 39.24987648913789, + -6.783320417149405 + ], + [ + 39.24990659151731, + -6.782389387144009 + ], + [ + 39.25010086176018, + -6.782346474227426 + ], + [ + 39.2501017767606, + -6.78232629074711 + ], + [ + 39.250066934399854, + -6.782156990037679 + ], + [ + 39.24992289431197, + -6.782182852009128 + ], + [ + 39.2499138298333, + -6.782153922351434 + ], + [ + 39.25006519231678, + -6.777778404257647 + ], + [ + 39.250159011995514, + -6.775687803188281 + ], + [ + 39.250652695356244, + -6.774710612955933 + ], + [ + 39.25973527817753, + -6.774051636265581 + ], + [ + 39.26420907625315, + -6.774027485936578 + ], + [ + 39.26430505647687, + -6.774065405657963 + ], + [ + 39.26433909336156, + -6.774026490186999 + ], + [ + 39.27016488290843, + -6.773994609904983 + ], + [ + 39.27021692938301, + -6.773995269543569 + ], + [ + 39.27026644245446, + -6.774033162706626 + ], + [ + 39.27031016915434, + -6.773994066588543 + ], + [ + 39.27159183301611, + -6.773986876672367 + ], + [ + 39.27168780046295, + -6.774108785772873 + ], + [ + 39.271686763240815, + -6.774136172079665 + ], + [ + 39.27192122999216, + -6.774436870625464 + ], + [ + 39.27225338516659, + -6.773984336984419 + ], + [ + 39.27280594364432, + -6.773980646345491 + ], + [ + 39.274209296190605, + -6.774041415140496 + ], + [ + 39.27802675727596, + -6.774426374513278 + ], + [ + 39.27864214751531, + -6.774515880892984 + ], + [ + 39.280023369706576, + -6.774755350012424 + ], + [ + 39.28050916887765, + -6.775147428625842 + ], + [ + 39.28074438487075, + -6.775756768054177 + ], + [ + 39.28081527672994, + -6.776054440091325 + ], + [ + 39.28082717168011, + -6.776695908769849 + ], + [ + 39.2807657423886, + -6.776717815104587 + ], + [ + 39.280775518747866, + -6.776754016935989 + ], + [ + 39.280818510912624, + -6.776750660815322 + ], + [ + 39.28082911053632, + -6.776772724163326 + ], + [ + 39.28091689459758, + -6.781345598621182 + ], + [ + 39.28080388738358, + -6.7813839793259 + ], + [ + 39.28084388776356, + -6.781454612139605 + ], + [ + 39.28085319429884, + -6.78143154903115 + ], + [ + 39.28087584049512, + -6.781437812905911 + ], + [ + 39.28086609036416, + -6.781472364858208 + ], + [ + 39.280881881877654, + -6.781483136266438 + ], + [ + 39.28086943504425, + -6.78149915312294 + ], + [ + 39.28088554011426, + -6.781534324494014 + ], + [ + 39.280873569959816, + -6.781638136661505 + ], + [ + 39.28092499494767, + -6.781750298004826 + ], + [ + 39.28095457939287, + -6.783298331704033 + ], + [ + 39.28086026889085, + -6.783333866874134 + ], + [ + 39.280959342849336, + -6.783533751067348 + ], + [ + 39.28096937002043, + -6.784069342141371 + ], + [ + 39.28095243868693, + -6.78408149778495 + ], + [ + 39.280970796197394, + -6.784135018997731 + ], + [ + 39.280990362247046, + -6.785161799575521 + ], + [ + 39.28090314512198, + -6.785218441815514 + ], + [ + 39.28094438037573, + -6.785212514854102 + ], + [ + 39.280994123789, + -6.785340368033896 + ], + [ + 39.28103471876776, + -6.787446616974048 + ], + [ + 39.281027381291025, + -6.787464990541269 + ], + [ + 39.280827513135605, + -6.787500088788153 + ], + [ + 39.28099960926122, + -6.78779064973444 + ], + [ + 39.28100210101566, + -6.787851081760929 + ], + [ + 39.281026585687755, + -6.787859226828259 + ], + [ + 39.28102285279996, + -6.787966432946407 + ], + [ + 39.28093203937434, + -6.788005057346286 + ], + [ + 39.28100675911835, + -6.788204324299769 + ], + [ + 39.280997459334884, + -6.788308436132202 + ], + [ + 39.28105380334917, + -6.788440096324056 + ], + [ + 39.281068553938496, + -6.789216155958014 + ], + [ + 39.28096066849781, + -6.789245774186083 + ], + [ + 39.281073839006595, + -6.789477514362669 + ], + [ + 39.28114397070973, + -6.793117958745426 + ], + [ + 39.28113420729278, + -6.79383486840148 + ], + [ + 39.281114726156694, + -6.793847842189681 + ], + [ + 39.28113330952829, + -6.79388250834817 + ], + [ + 39.281129262608935, + -6.794159983557968 + ], + [ + 39.28109084175889, + -6.794179680568165 + ], + [ + 39.28112752361519, + -6.794277502669122 + ], + [ + 39.28111635395094, + -6.795038314028078 + ], + [ + 39.281016070626016, + -6.795075741198945 + ], + [ + 39.281112775297714, + -6.795250226366647 + ], + [ + 39.2810949704288, + -6.79646195887955 + ], + [ + 39.2809583747182, + -6.796479910277594 + ], + [ + 39.280976796828014, + -6.79655746965899 + ], + [ + 39.28106599069538, + -6.796757139303622 + ], + [ + 39.28105528128861, + -6.79686803066901 + ], + [ + 39.281087453345336, + -6.796987885295481 + ], + [ + 39.28108073143122, + -6.797439731548687 + ], + [ + 39.28083992809423, + -6.797461906062759 + ], + [ + 39.28083642610969, + -6.797501481434426 + ], + [ + 39.28072006370183, + -6.797559721622083 + ], + [ + 39.280792511077834, + -6.797755460113359 + ], + [ + 39.280782299142885, + -6.797822644537164 + ], + [ + 39.28087877377628, + -6.798094898764859 + ], + [ + 39.28087160779872, + -6.798109486776828 + ], + [ + 39.28084495591411, + -6.798106189716947 + ], + [ + 39.28091358669126, + -6.798282661131834 + ], + [ + 39.280894058903186, + -6.798303988028182 + ], + [ + 39.28089993648302, + -6.798318476273004 + ], + [ + 39.28094807709286, + -6.798317376152552 + ], + [ + 39.28097704846284, + -6.798338565814496 + ], + [ + 39.280968589108724, + -6.798359909541208 + ], + [ + 39.28098862495911, + -6.798363833982053 + ], + [ + 39.28106384308544, + -6.798560924842693 + ], + [ + 39.281060047781274, + -6.798789172787439 + ], + [ + 39.280964648702366, + -6.79881579282715 + ], + [ + 39.2810549062557, + -6.799182593389792 + ], + [ + 39.281051210712, + -6.799417431324301 + ], + [ + 39.281012045218766, + -6.799461973169469 + ], + [ + 39.28092870982996, + -6.799469616595563 + ], + [ + 39.28102911738072, + -6.800116395040011 + ], + [ + 39.28096755147659, + -6.800136517203233 + ], + [ + 39.28098227562801, + -6.800231504054254 + ], + [ + 39.28092089023231, + -6.800365292854012 + ], + [ + 39.28092243227157, + -6.800466481559217 + ], + [ + 39.28099285109281, + -6.800487505251037 + ], + [ + 39.2809865598948, + -6.80056017366214 + ], + [ + 39.281022039297945, + -6.800676509145848 + ], + [ + 39.28100512867587, + -6.800686027414948 + ], + [ + 39.28094639492564, + -6.800673573505817 + ], + [ + 39.28098960816634, + -6.80080288458438 + ], + [ + 39.28100608830849, + -6.800808079923416 + ], + [ + 39.28101818264724, + -6.800788226357124 + ], + [ + 39.28103090221736, + -6.800799071421509 + ], + [ + 39.28100953313295, + -6.802247229426974 + ], + [ + 39.280969530277055, + -6.802983496860963 + ], + [ + 39.279742849863105, + -6.803751726145401 + ], + [ + 39.279491514203464, + -6.803861587800235 + ], + [ + 39.277158588001264, + -6.804087251350162 + ], + [ + 39.27513747683199, + -6.804142100699255 + ], + [ + 39.27511678207263, + -6.804135692385428 + ], + [ + 39.2751163497056, + -6.804060709416309 + ], + [ + 39.27391722620214, + -6.804061389785589 + ], + [ + 39.27385826397281, + -6.804047806856571 + ], + [ + 39.27384911606231, + -6.803999913343275 + ], + [ + 39.2735965361418, + -6.80398525563719 + ], + [ + 39.273500708320924, + -6.80401301734282 + ], + [ + 39.27346293523808, + -6.804003966970788 + ], + [ + 39.27342162790581, + -6.804025593648304 + ], + [ + 39.27340672680942, + -6.804008608011346 + ], + [ + 39.273416845431285, + -6.803993658369023 + ] + ], + [ + [ + 39.2734931545649, + -6.80398387288763 + ], + [ + 39.27349774748707, + -6.803981148820998 + ], + [ + 39.2734846042507, + -6.80398069373159 + ], + [ + 39.27348722790041, + -6.80398493599873 + ], + [ + 39.2734931545649, + -6.80398387288763 + ] + ], + [ + [ + 39.281045469223024, + -6.796406485350073 + ], + [ + 39.28104614552522, + -6.79640624303539 + ], + [ + 39.28104624219622, + -6.796405856316271 + ], + [ + 39.28104544832558, + -6.796406065132672 + ], + [ + 39.281045469223024, + -6.796406485350073 + ] + ], + [ + [ + 39.25013462741531, + -6.7822284539465 + ], + [ + 39.250139342204406, + -6.782225634227249 + ], + [ + 39.25013885529763, + -6.782223167263246 + ], + [ + 39.25013601751904, + -6.782223433931297 + ], + [ + 39.25013462741531, + -6.7822284539465 + ] + ], + [ + [ + 39.250133340148714, + -6.782197609422264 + ], + [ + 39.25013227568109, + -6.782192336183768 + ], + [ + 39.25013085449504, + -6.782186240541199 + ], + [ + 39.25012984461586, + -6.782195145644085 + ], + [ + 39.250133340148714, + -6.782197609422264 + ] + ] + ], + [ + [ + [ + 39.28101229778558, + -6.800726929325503 + ], + [ + 39.28102979517802, + -6.800722356034623 + ], + [ + 39.28102777800557, + -6.800751554944212 + ], + [ + 39.281011984140875, + -6.800747680790295 + ], + [ + 39.28101229778558, + -6.800726929325503 + ] + ] + ], + [ + [ + [ + 39.28098638863562, + -6.800732494588853 + ], + [ + 39.280997245783674, + -6.800723485911647 + ], + [ + 39.28100583405759, + -6.80073429499442 + ], + [ + 39.280995019972025, + -6.800742416990294 + ], + [ + 39.28098638863562, + -6.800732494588853 + ] + ] + ], + [ + [ + [ + 39.27333576292948, + -6.804020758896268 + ], + [ + 39.27334712034972, + -6.804009856466778 + ], + [ + 39.27335756490539, + -6.804021209097676 + ], + [ + 39.273346206700516, + -6.804030723971451 + ], + [ + 39.27333576292948, + -6.804020758896268 + ] + ] + ], + [ + [ + [ + 39.27338784445309, + -6.804011179704081 + ], + [ + 39.27340165825813, + -6.804007187497802 + ], + [ + 39.27340508925115, + -6.804022507747959 + ], + [ + 39.2733897619233, + -6.804025474696425 + ], + [ + 39.27338784445309, + -6.804011179704081 + ] + ] + ], + [ + [ + [ + 39.28093735076017, + -6.798277365237194 + ], + [ + 39.28094786501646, + -6.798293757944892 + ], + [ + 39.28092636574822, + -6.798297946514793 + ], + [ + 39.28091893391865, + -6.798272295760583 + ], + [ + 39.28093735076017, + -6.798277365237194 + ] + ] + ] ] - ] - ] - }, - "bbox": [ - 39.24966102436161, - -6.804292908938633, - 39.28114400293776, - -6.773980646345491 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "labels": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/dar/f883a0-labels/f883a0.geojson", + "type": "application/geo+json" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "labels": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/dar/f883a0-labels/f883a0.geojson", - "type": "application/geo+json" - } - }, - "stac_extensions": [ - "label" - ] + "bbox": [ + 39.24966102436161, + -6.804292908938633, + 39.28114400293776, + -6.773980646345491 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "dar" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/dar/f883a0/f883a0.json b/tests/data-files/catalogs/test-case-4/dar/f883a0/f883a0.json index e9533e821..817441517 100644 --- a/tests/data-files/catalogs/test-case-4/dar/f883a0/f883a0.json +++ b/tests/data-files/catalogs/test-case-4/dar/f883a0/f883a0.json @@ -1,1266 +1,1267 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "f883a0", - "properties": { - "area": "dar", - "license": "ODbL-1.0", - "datetime": "2017-11-01T00:00:00Z" - }, - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 39.27315718647447, - -6.804030897967275 - ], - [ - 39.273165048748965, - -6.804015735580677 - ], - [ - 39.273213892047806, - -6.804006275126262 - ], - [ - 39.27322980988637, - -6.804022244653453 - ], - [ - 39.273170342425956, - -6.804047430372633 - ], - [ - 39.27315718647447, - -6.804030897967275 - ] - ] - ], - [ - [ - [ - 39.273270319050496, - -6.804022808953547 - ], - [ - 39.273288769025, - -6.803992819792749 - ], - [ - 39.27331911984259, - -6.804029517800871 - ], - [ - 39.2732773025055, - -6.804036732038151 - ], - [ - 39.273270319050496, - -6.804022808953547 - ] - ] - ], - [ - [ - [ - 39.273416845431285, - -6.803993658369023 - ], - [ - 39.273432966277255, - -6.803999383623384 - ], - [ - 39.27345314382025, - -6.803979786475935 - ], - [ - 39.27322440426283, - -6.803973842746188 - ], - [ - 39.273203984545894, - -6.804001738617233 - ], - [ - 39.27307652605739, - -6.804015326271316 - ], - [ - 39.27305748415282, - -6.804061875764365 - ], - [ - 39.27243654623383, - -6.804062182204895 - ], - [ - 39.272422506412305, - -6.804030782430953 - ], - [ - 39.27233818959957, - -6.804033592321105 - ], - [ - 39.27232684217891, - -6.804062287567047 - ], - [ - 39.27050720474849, - -6.804063308351038 - ], - [ - 39.27050003464541, - -6.804267571943514 - ], - [ - 39.26958162504325, - -6.804292771833833 - ], - [ - 39.268183769535355, - -6.804289804955942 - ], - [ - 39.26817548170555, - -6.804064606402513 - ], - [ - 39.26638040640152, - -6.804065554449549 - ], - [ - 39.26635869387405, - -6.80392326747663 - ], - [ - 39.26612966449484, - -6.803973347620189 - ], - [ - 39.2660934787131, - -6.804065755940294 - ], - [ - 39.26187296555017, - -6.804068058726235 - ], - [ - 39.26184507218486, - -6.804052028033205 - ], - [ - 39.26184066298603, - -6.804023191210663 - ], - [ - 39.26172396812868, - -6.804068139349033 - ], - [ - 39.25777183400359, - -6.804070261106554 - ], - [ - 39.257755345525474, - -6.804004808291634 - ], - [ - 39.25731554868908, - -6.804070460389402 - ], - [ - 39.256625459443185, - -6.804070870513325 - ], - [ - 39.25662348593693, - -6.80422297079218 - ], - [ - 39.256462846950114, - -6.804260546096121 - ], - [ - 39.256084987159134, - -6.804259012772288 - ], - [ - 39.256069700572326, - -6.804123376288454 - ], - [ - 39.25557123594966, - -6.804199546422531 - ], - [ - 39.25540366700173, - -6.804257868759697 - ], - [ - 39.25364580884159, - -6.804253286905217 - ], - [ - 39.25336404330564, - -6.804245528109689 - ], - [ - 39.25184949473127, - -6.804063493477143 - ], - [ - 39.25045725022109, - -6.803626776738144 - ], - [ - 39.250038582443665, - -6.80287820958753 - ], - [ - 39.25000304212214, - -6.802509337350906 - ], - [ - 39.24988415760574, - -6.799080315984306 - ], - [ - 39.24990450849855, - -6.799063247023449 - ], - [ - 39.2498947561629, - -6.798995102709657 - ], - [ - 39.24988086958492, - -6.79898550113401 - ], - [ - 39.249810881599906, - -6.796966175954005 - ], - [ - 39.24981645844359, - -6.796947177743604 - ], - [ - 39.249872411376465, - -6.796943310209003 - ], - [ - 39.249872317302916, - -6.79667664523118 - ], - [ - 39.24989594446884, - -6.796632192786874 - ], - [ - 39.2498929959209, - -6.796620487479649 - ], - [ - 39.24981140260522, - -6.796653264268834 - ], - [ - 39.249799651394305, - -6.796639604421224 - ], - [ - 39.249702848316815, - -6.793849310612861 - ], - [ - 39.249709580102994, - -6.793444194527318 - ], - [ - 39.24968269293236, - -6.793263269989816 - ], - [ - 39.24966102436161, - -6.792603766179727 - ], - [ - 39.24967954445545, - -6.791728669025114 - ], - [ - 39.24970804593678, - -6.791366446494281 - ], - [ - 39.24968767919196, - -6.791352173642583 - ], - [ - 39.24969901238331, - -6.790812445435837 - ], - [ - 39.24971718787532, - -6.790709956750732 - ], - [ - 39.24976000940216, - -6.790676190366502 - ], - [ - 39.24974335811433, - -6.79066757715095 - ], - [ - 39.24975954380845, - -6.7905720968061 - ], - [ - 39.24971030856871, - -6.790285552729824 - ], - [ - 39.24971251701262, - -6.790166259808814 - ], - [ - 39.249755177302276, - -6.79007657102466 - ], - [ - 39.24978363439594, - -6.790069338302176 - ], - [ - 39.24973059995279, - -6.789901141277205 - ], - [ - 39.249748519583505, - -6.789843130737693 - ], - [ - 39.249722462770514, - -6.789712522643217 - ], - [ - 39.249757283518974, - -6.788060421836336 - ], - [ - 39.24981581028674, - -6.788035256591358 - ], - [ - 39.2497613539383, - -6.787878110167098 - ], - [ - 39.249768572097224, - -6.787518805148783 - ], - [ - 39.25004009533414, - -6.787434103342062 - ], - [ - 39.25002896611271, - -6.787302674153842 - ], - [ - 39.25004835160351, - -6.787293592535141 - ], - [ - 39.25004462643536, - -6.787248062083075 - ], - [ - 39.249913527740446, - -6.787275621098578 - ], - [ - 39.24987623121805, - -6.787223585244646 - ], - [ - 39.2498870533108, - -6.78675947061919 - ], - [ - 39.249878668979136, - -6.786651689669421 - ], - [ - 39.249854185335714, - -6.786644521595329 - ], - [ - 39.24985427604204, - -6.786567866890232 - ], - [ - 39.249878150583925, - -6.786543683174986 - ], - [ - 39.24987767258752, - -6.786514031590554 - ], - [ - 39.24985595176083, - -6.786480788612282 - ], - [ - 39.24985427458511, - -6.786004693765936 - ], - [ - 39.249835799952045, - -6.785985440085538 - ], - [ - 39.24981894796509, - -6.785692711962167 - ], - [ - 39.249835592123326, - -6.785666857043904 - ], - [ - 39.2498132441077, - -6.785399014698585 - ], - [ - 39.24982665102962, - -6.785376346020647 - ], - [ - 39.24981460672529, - -6.785349524356427 - ], - [ - 39.24981956779118, - -6.785099760997835 - ], - [ - 39.249871024621996, - -6.783491089857915 - ], - [ - 39.24990124402507, - -6.783476958079939 - ], - [ - 39.24987648913789, - -6.783320417149405 - ], - [ - 39.24990659151731, - -6.782389387144009 - ], - [ - 39.25010086176018, - -6.782346474227426 - ], - [ - 39.2501017767606, - -6.78232629074711 - ], - [ - 39.250066934399854, - -6.782156990037679 - ], - [ - 39.24992289431197, - -6.782182852009128 - ], - [ - 39.2499138298333, - -6.782153922351434 - ], - [ - 39.25006519231678, - -6.777778404257647 - ], - [ - 39.250159011995514, - -6.775687803188281 - ], - [ - 39.250652695356244, - -6.774710612955933 - ], - [ - 39.25973527817753, - -6.774051636265581 - ], - [ - 39.26420907625315, - -6.774027485936578 - ], - [ - 39.26430505647687, - -6.774065405657963 - ], - [ - 39.26433909336156, - -6.774026490186999 - ], - [ - 39.27016488290843, - -6.773994609904983 - ], - [ - 39.27021692938301, - -6.773995269543569 - ], - [ - 39.27026644245446, - -6.774033162706626 - ], - [ - 39.27031016915434, - -6.773994066588543 - ], - [ - 39.27159183301611, - -6.773986876672367 - ], - [ - 39.27168780046295, - -6.774108785772873 - ], - [ - 39.271686763240815, - -6.774136172079665 - ], - [ - 39.27192122999216, - -6.774436870625464 - ], - [ - 39.27225338516659, - -6.773984336984419 - ], - [ - 39.27280594364432, - -6.773980646345491 - ], - [ - 39.274209296190605, - -6.774041415140496 - ], - [ - 39.27802675727596, - -6.774426374513278 - ], - [ - 39.27864214751531, - -6.774515880892984 - ], - [ - 39.280023369706576, - -6.774755350012424 - ], - [ - 39.28050916887765, - -6.775147428625842 - ], - [ - 39.28074438487075, - -6.775756768054177 - ], - [ - 39.28081527672994, - -6.776054440091325 - ], - [ - 39.28082717168011, - -6.776695908769849 - ], - [ - 39.2807657423886, - -6.776717815104587 - ], - [ - 39.280775518747866, - -6.776754016935989 - ], - [ - 39.280818510912624, - -6.776750660815322 - ], - [ - 39.28082911053632, - -6.776772724163326 - ], - [ - 39.28091689459758, - -6.781345598621182 - ], - [ - 39.28080388738358, - -6.7813839793259 - ], - [ - 39.28084388776356, - -6.781454612139605 - ], - [ - 39.28085319429884, - -6.78143154903115 - ], - [ - 39.28087584049512, - -6.781437812905911 - ], - [ - 39.28086609036416, - -6.781472364858208 - ], - [ - 39.280881881877654, - -6.781483136266438 - ], - [ - 39.28086943504425, - -6.78149915312294 - ], - [ - 39.28088554011426, - -6.781534324494014 - ], - [ - 39.280873569959816, - -6.781638136661505 - ], - [ - 39.28092499494767, - -6.781750298004826 - ], - [ - 39.28095457939287, - -6.783298331704033 - ], - [ - 39.28086026889085, - -6.783333866874134 - ], - [ - 39.280959342849336, - -6.783533751067348 - ], - [ - 39.28096937002043, - -6.784069342141371 - ], - [ - 39.28095243868693, - -6.78408149778495 - ], - [ - 39.280970796197394, - -6.784135018997731 - ], - [ - 39.280990362247046, - -6.785161799575521 - ], - [ - 39.28090314512198, - -6.785218441815514 - ], - [ - 39.28094438037573, - -6.785212514854102 - ], - [ - 39.280994123789, - -6.785340368033896 - ], - [ - 39.28103471876776, - -6.787446616974048 - ], - [ - 39.281027381291025, - -6.787464990541269 - ], - [ - 39.280827513135605, - -6.787500088788153 - ], - [ - 39.28099960926122, - -6.78779064973444 - ], - [ - 39.28100210101566, - -6.787851081760929 - ], - [ - 39.281026585687755, - -6.787859226828259 - ], - [ - 39.28102285279996, - -6.787966432946407 - ], - [ - 39.28093203937434, - -6.788005057346286 - ], - [ - 39.28100675911835, - -6.788204324299769 - ], - [ - 39.280997459334884, - -6.788308436132202 - ], - [ - 39.28105380334917, - -6.788440096324056 - ], - [ - 39.281068553938496, - -6.789216155958014 - ], - [ - 39.28096066849781, - -6.789245774186083 - ], - [ - 39.281073839006595, - -6.789477514362669 - ], - [ - 39.28114397070973, - -6.793117958745426 - ], - [ - 39.28113420729278, - -6.79383486840148 - ], - [ - 39.281114726156694, - -6.793847842189681 - ], - [ - 39.28113330952829, - -6.79388250834817 - ], - [ - 39.281129262608935, - -6.794159983557968 - ], - [ - 39.28109084175889, - -6.794179680568165 - ], - [ - 39.28112752361519, - -6.794277502669122 - ], - [ - 39.28111635395094, - -6.795038314028078 - ], - [ - 39.281016070626016, - -6.795075741198945 - ], - [ - 39.281112775297714, - -6.795250226366647 - ], - [ - 39.2810949704288, - -6.79646195887955 - ], - [ - 39.2809583747182, - -6.796479910277594 - ], - [ - 39.280976796828014, - -6.79655746965899 - ], - [ - 39.28106599069538, - -6.796757139303622 - ], - [ - 39.28105528128861, - -6.79686803066901 - ], - [ - 39.281087453345336, - -6.796987885295481 - ], - [ - 39.28108073143122, - -6.797439731548687 - ], - [ - 39.28083992809423, - -6.797461906062759 - ], - [ - 39.28083642610969, - -6.797501481434426 - ], - [ - 39.28072006370183, - -6.797559721622083 - ], - [ - 39.280792511077834, - -6.797755460113359 - ], - [ - 39.280782299142885, - -6.797822644537164 - ], - [ - 39.28087877377628, - -6.798094898764859 - ], - [ - 39.28087160779872, - -6.798109486776828 - ], - [ - 39.28084495591411, - -6.798106189716947 - ], - [ - 39.28091358669126, - -6.798282661131834 - ], - [ - 39.280894058903186, - -6.798303988028182 - ], - [ - 39.28089993648302, - -6.798318476273004 - ], - [ - 39.28094807709286, - -6.798317376152552 - ], - [ - 39.28097704846284, - -6.798338565814496 - ], - [ - 39.280968589108724, - -6.798359909541208 - ], - [ - 39.28098862495911, - -6.798363833982053 - ], - [ - 39.28106384308544, - -6.798560924842693 - ], - [ - 39.281060047781274, - -6.798789172787439 - ], - [ - 39.280964648702366, - -6.79881579282715 - ], - [ - 39.2810549062557, - -6.799182593389792 - ], - [ - 39.281051210712, - -6.799417431324301 - ], - [ - 39.281012045218766, - -6.799461973169469 - ], - [ - 39.28092870982996, - -6.799469616595563 - ], - [ - 39.28102911738072, - -6.800116395040011 - ], - [ - 39.28096755147659, - -6.800136517203233 - ], - [ - 39.28098227562801, - -6.800231504054254 - ], - [ - 39.28092089023231, - -6.800365292854012 - ], - [ - 39.28092243227157, - -6.800466481559217 - ], - [ - 39.28099285109281, - -6.800487505251037 - ], - [ - 39.2809865598948, - -6.80056017366214 - ], - [ - 39.281022039297945, - -6.800676509145848 - ], - [ - 39.28100512867587, - -6.800686027414948 - ], - [ - 39.28094639492564, - -6.800673573505817 - ], - [ - 39.28098960816634, - -6.80080288458438 - ], - [ - 39.28100608830849, - -6.800808079923416 - ], - [ - 39.28101818264724, - -6.800788226357124 - ], - [ - 39.28103090221736, - -6.800799071421509 - ], - [ - 39.28100953313295, - -6.802247229426974 - ], - [ - 39.280969530277055, - -6.802983496860963 - ], - [ - 39.279742849863105, - -6.803751726145401 - ], - [ - 39.279491514203464, - -6.803861587800235 - ], - [ - 39.277158588001264, - -6.804087251350162 - ], - [ - 39.27513747683199, - -6.804142100699255 - ], - [ - 39.27511678207263, - -6.804135692385428 - ], - [ - 39.2751163497056, - -6.804060709416309 - ], - [ - 39.27391722620214, - -6.804061389785589 - ], - [ - 39.27385826397281, - -6.804047806856571 - ], - [ - 39.27384911606231, - -6.803999913343275 - ], - [ - 39.2735965361418, - -6.80398525563719 - ], - [ - 39.273500708320924, - -6.80401301734282 - ], - [ - 39.27346293523808, - -6.804003966970788 - ], - [ - 39.27342162790581, - -6.804025593648304 - ], - [ - 39.27340672680942, - -6.804008608011346 - ], - [ - 39.273416845431285, - -6.803993658369023 - ] - ], - [ - [ - 39.2734931545649, - -6.80398387288763 - ], - [ - 39.27349774748707, - -6.803981148820998 - ], - [ - 39.2734846042507, - -6.80398069373159 - ], - [ - 39.27348722790041, - -6.80398493599873 - ], - [ - 39.2734931545649, - -6.80398387288763 - ] - ], - [ - [ - 39.281045469223024, - -6.796406485350073 - ], - [ - 39.28104614552522, - -6.79640624303539 - ], - [ - 39.28104624219622, - -6.796405856316271 - ], - [ - 39.28104544832558, - -6.796406065132672 - ], - [ - 39.281045469223024, - -6.796406485350073 - ] - ], - [ - [ - 39.25013462741531, - -6.7822284539465 - ], - [ - 39.250139342204406, - -6.782225634227249 - ], - [ - 39.25013885529763, - -6.782223167263246 - ], - [ - 39.25013601751904, - -6.782223433931297 - ], - [ - 39.25013462741531, - -6.7822284539465 - ] - ], - [ - [ - 39.250133340148714, - -6.782197609422264 - ], - [ - 39.25013227568109, - -6.782192336183768 - ], - [ - 39.25013085449504, - -6.782186240541199 - ], - [ - 39.25012984461586, - -6.782195145644085 - ], - [ - 39.250133340148714, - -6.782197609422264 - ] - ] - ], - [ - [ - [ - 39.28101229778558, - -6.800726929325503 - ], - [ - 39.28102979517802, - -6.800722356034623 - ], - [ - 39.28102777800557, - -6.800751554944212 - ], - [ - 39.281011984140875, - -6.800747680790295 - ], - [ - 39.28101229778558, - -6.800726929325503 - ] - ] - ], - [ - [ - [ - 39.28098638863562, - -6.800732494588853 - ], - [ - 39.280997245783674, - -6.800723485911647 - ], - [ - 39.28100583405759, - -6.80073429499442 - ], - [ - 39.280995019972025, - -6.800742416990294 - ], - [ - 39.28098638863562, - -6.800732494588853 - ] - ] - ], - [ - [ - [ - 39.27333576292948, - -6.804020758896268 - ], - [ - 39.27334712034972, - -6.804009856466778 - ], - [ - 39.27335756490539, - -6.804021209097676 - ], - [ - 39.273346206700516, - -6.804030723971451 - ], - [ - 39.27333576292948, - -6.804020758896268 - ] - ] - ], - [ - [ - [ - 39.27338784445309, - -6.804011179704081 - ], - [ - 39.27340165825813, - -6.804007187497802 - ], - [ - 39.27340508925115, - -6.804022507747959 - ], - [ - 39.2733897619233, - -6.804025474696425 - ], - [ - 39.27338784445309, - -6.804011179704081 - ] - ] - ], - [ - [ - [ - 39.28093735076017, - -6.798277365237194 - ], - [ - 39.28094786501646, - -6.798293757944892 - ], - [ - 39.28092636574822, - -6.798297946514793 - ], - [ - 39.28091893391865, - -6.798272295760583 - ], - [ - 39.28093735076017, - -6.798277365237194 - ] + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "f883a0", + "properties": { + "area": "dar", + "license": "ODbL-1.0", + "datetime": "2017-11-01T00:00:00Z" + }, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [ + 39.27315718647447, + -6.804030897967275 + ], + [ + 39.273165048748965, + -6.804015735580677 + ], + [ + 39.273213892047806, + -6.804006275126262 + ], + [ + 39.27322980988637, + -6.804022244653453 + ], + [ + 39.273170342425956, + -6.804047430372633 + ], + [ + 39.27315718647447, + -6.804030897967275 + ] + ] + ], + [ + [ + [ + 39.273270319050496, + -6.804022808953547 + ], + [ + 39.273288769025, + -6.803992819792749 + ], + [ + 39.27331911984259, + -6.804029517800871 + ], + [ + 39.2732773025055, + -6.804036732038151 + ], + [ + 39.273270319050496, + -6.804022808953547 + ] + ] + ], + [ + [ + [ + 39.273416845431285, + -6.803993658369023 + ], + [ + 39.273432966277255, + -6.803999383623384 + ], + [ + 39.27345314382025, + -6.803979786475935 + ], + [ + 39.27322440426283, + -6.803973842746188 + ], + [ + 39.273203984545894, + -6.804001738617233 + ], + [ + 39.27307652605739, + -6.804015326271316 + ], + [ + 39.27305748415282, + -6.804061875764365 + ], + [ + 39.27243654623383, + -6.804062182204895 + ], + [ + 39.272422506412305, + -6.804030782430953 + ], + [ + 39.27233818959957, + -6.804033592321105 + ], + [ + 39.27232684217891, + -6.804062287567047 + ], + [ + 39.27050720474849, + -6.804063308351038 + ], + [ + 39.27050003464541, + -6.804267571943514 + ], + [ + 39.26958162504325, + -6.804292771833833 + ], + [ + 39.268183769535355, + -6.804289804955942 + ], + [ + 39.26817548170555, + -6.804064606402513 + ], + [ + 39.26638040640152, + -6.804065554449549 + ], + [ + 39.26635869387405, + -6.80392326747663 + ], + [ + 39.26612966449484, + -6.803973347620189 + ], + [ + 39.2660934787131, + -6.804065755940294 + ], + [ + 39.26187296555017, + -6.804068058726235 + ], + [ + 39.26184507218486, + -6.804052028033205 + ], + [ + 39.26184066298603, + -6.804023191210663 + ], + [ + 39.26172396812868, + -6.804068139349033 + ], + [ + 39.25777183400359, + -6.804070261106554 + ], + [ + 39.257755345525474, + -6.804004808291634 + ], + [ + 39.25731554868908, + -6.804070460389402 + ], + [ + 39.256625459443185, + -6.804070870513325 + ], + [ + 39.25662348593693, + -6.80422297079218 + ], + [ + 39.256462846950114, + -6.804260546096121 + ], + [ + 39.256084987159134, + -6.804259012772288 + ], + [ + 39.256069700572326, + -6.804123376288454 + ], + [ + 39.25557123594966, + -6.804199546422531 + ], + [ + 39.25540366700173, + -6.804257868759697 + ], + [ + 39.25364580884159, + -6.804253286905217 + ], + [ + 39.25336404330564, + -6.804245528109689 + ], + [ + 39.25184949473127, + -6.804063493477143 + ], + [ + 39.25045725022109, + -6.803626776738144 + ], + [ + 39.250038582443665, + -6.80287820958753 + ], + [ + 39.25000304212214, + -6.802509337350906 + ], + [ + 39.24988415760574, + -6.799080315984306 + ], + [ + 39.24990450849855, + -6.799063247023449 + ], + [ + 39.2498947561629, + -6.798995102709657 + ], + [ + 39.24988086958492, + -6.79898550113401 + ], + [ + 39.249810881599906, + -6.796966175954005 + ], + [ + 39.24981645844359, + -6.796947177743604 + ], + [ + 39.249872411376465, + -6.796943310209003 + ], + [ + 39.249872317302916, + -6.79667664523118 + ], + [ + 39.24989594446884, + -6.796632192786874 + ], + [ + 39.2498929959209, + -6.796620487479649 + ], + [ + 39.24981140260522, + -6.796653264268834 + ], + [ + 39.249799651394305, + -6.796639604421224 + ], + [ + 39.249702848316815, + -6.793849310612861 + ], + [ + 39.249709580102994, + -6.793444194527318 + ], + [ + 39.24968269293236, + -6.793263269989816 + ], + [ + 39.24966102436161, + -6.792603766179727 + ], + [ + 39.24967954445545, + -6.791728669025114 + ], + [ + 39.24970804593678, + -6.791366446494281 + ], + [ + 39.24968767919196, + -6.791352173642583 + ], + [ + 39.24969901238331, + -6.790812445435837 + ], + [ + 39.24971718787532, + -6.790709956750732 + ], + [ + 39.24976000940216, + -6.790676190366502 + ], + [ + 39.24974335811433, + -6.79066757715095 + ], + [ + 39.24975954380845, + -6.7905720968061 + ], + [ + 39.24971030856871, + -6.790285552729824 + ], + [ + 39.24971251701262, + -6.790166259808814 + ], + [ + 39.249755177302276, + -6.79007657102466 + ], + [ + 39.24978363439594, + -6.790069338302176 + ], + [ + 39.24973059995279, + -6.789901141277205 + ], + [ + 39.249748519583505, + -6.789843130737693 + ], + [ + 39.249722462770514, + -6.789712522643217 + ], + [ + 39.249757283518974, + -6.788060421836336 + ], + [ + 39.24981581028674, + -6.788035256591358 + ], + [ + 39.2497613539383, + -6.787878110167098 + ], + [ + 39.249768572097224, + -6.787518805148783 + ], + [ + 39.25004009533414, + -6.787434103342062 + ], + [ + 39.25002896611271, + -6.787302674153842 + ], + [ + 39.25004835160351, + -6.787293592535141 + ], + [ + 39.25004462643536, + -6.787248062083075 + ], + [ + 39.249913527740446, + -6.787275621098578 + ], + [ + 39.24987623121805, + -6.787223585244646 + ], + [ + 39.2498870533108, + -6.78675947061919 + ], + [ + 39.249878668979136, + -6.786651689669421 + ], + [ + 39.249854185335714, + -6.786644521595329 + ], + [ + 39.24985427604204, + -6.786567866890232 + ], + [ + 39.249878150583925, + -6.786543683174986 + ], + [ + 39.24987767258752, + -6.786514031590554 + ], + [ + 39.24985595176083, + -6.786480788612282 + ], + [ + 39.24985427458511, + -6.786004693765936 + ], + [ + 39.249835799952045, + -6.785985440085538 + ], + [ + 39.24981894796509, + -6.785692711962167 + ], + [ + 39.249835592123326, + -6.785666857043904 + ], + [ + 39.2498132441077, + -6.785399014698585 + ], + [ + 39.24982665102962, + -6.785376346020647 + ], + [ + 39.24981460672529, + -6.785349524356427 + ], + [ + 39.24981956779118, + -6.785099760997835 + ], + [ + 39.249871024621996, + -6.783491089857915 + ], + [ + 39.24990124402507, + -6.783476958079939 + ], + [ + 39.24987648913789, + -6.783320417149405 + ], + [ + 39.24990659151731, + -6.782389387144009 + ], + [ + 39.25010086176018, + -6.782346474227426 + ], + [ + 39.2501017767606, + -6.78232629074711 + ], + [ + 39.250066934399854, + -6.782156990037679 + ], + [ + 39.24992289431197, + -6.782182852009128 + ], + [ + 39.2499138298333, + -6.782153922351434 + ], + [ + 39.25006519231678, + -6.777778404257647 + ], + [ + 39.250159011995514, + -6.775687803188281 + ], + [ + 39.250652695356244, + -6.774710612955933 + ], + [ + 39.25973527817753, + -6.774051636265581 + ], + [ + 39.26420907625315, + -6.774027485936578 + ], + [ + 39.26430505647687, + -6.774065405657963 + ], + [ + 39.26433909336156, + -6.774026490186999 + ], + [ + 39.27016488290843, + -6.773994609904983 + ], + [ + 39.27021692938301, + -6.773995269543569 + ], + [ + 39.27026644245446, + -6.774033162706626 + ], + [ + 39.27031016915434, + -6.773994066588543 + ], + [ + 39.27159183301611, + -6.773986876672367 + ], + [ + 39.27168780046295, + -6.774108785772873 + ], + [ + 39.271686763240815, + -6.774136172079665 + ], + [ + 39.27192122999216, + -6.774436870625464 + ], + [ + 39.27225338516659, + -6.773984336984419 + ], + [ + 39.27280594364432, + -6.773980646345491 + ], + [ + 39.274209296190605, + -6.774041415140496 + ], + [ + 39.27802675727596, + -6.774426374513278 + ], + [ + 39.27864214751531, + -6.774515880892984 + ], + [ + 39.280023369706576, + -6.774755350012424 + ], + [ + 39.28050916887765, + -6.775147428625842 + ], + [ + 39.28074438487075, + -6.775756768054177 + ], + [ + 39.28081527672994, + -6.776054440091325 + ], + [ + 39.28082717168011, + -6.776695908769849 + ], + [ + 39.2807657423886, + -6.776717815104587 + ], + [ + 39.280775518747866, + -6.776754016935989 + ], + [ + 39.280818510912624, + -6.776750660815322 + ], + [ + 39.28082911053632, + -6.776772724163326 + ], + [ + 39.28091689459758, + -6.781345598621182 + ], + [ + 39.28080388738358, + -6.7813839793259 + ], + [ + 39.28084388776356, + -6.781454612139605 + ], + [ + 39.28085319429884, + -6.78143154903115 + ], + [ + 39.28087584049512, + -6.781437812905911 + ], + [ + 39.28086609036416, + -6.781472364858208 + ], + [ + 39.280881881877654, + -6.781483136266438 + ], + [ + 39.28086943504425, + -6.78149915312294 + ], + [ + 39.28088554011426, + -6.781534324494014 + ], + [ + 39.280873569959816, + -6.781638136661505 + ], + [ + 39.28092499494767, + -6.781750298004826 + ], + [ + 39.28095457939287, + -6.783298331704033 + ], + [ + 39.28086026889085, + -6.783333866874134 + ], + [ + 39.280959342849336, + -6.783533751067348 + ], + [ + 39.28096937002043, + -6.784069342141371 + ], + [ + 39.28095243868693, + -6.78408149778495 + ], + [ + 39.280970796197394, + -6.784135018997731 + ], + [ + 39.280990362247046, + -6.785161799575521 + ], + [ + 39.28090314512198, + -6.785218441815514 + ], + [ + 39.28094438037573, + -6.785212514854102 + ], + [ + 39.280994123789, + -6.785340368033896 + ], + [ + 39.28103471876776, + -6.787446616974048 + ], + [ + 39.281027381291025, + -6.787464990541269 + ], + [ + 39.280827513135605, + -6.787500088788153 + ], + [ + 39.28099960926122, + -6.78779064973444 + ], + [ + 39.28100210101566, + -6.787851081760929 + ], + [ + 39.281026585687755, + -6.787859226828259 + ], + [ + 39.28102285279996, + -6.787966432946407 + ], + [ + 39.28093203937434, + -6.788005057346286 + ], + [ + 39.28100675911835, + -6.788204324299769 + ], + [ + 39.280997459334884, + -6.788308436132202 + ], + [ + 39.28105380334917, + -6.788440096324056 + ], + [ + 39.281068553938496, + -6.789216155958014 + ], + [ + 39.28096066849781, + -6.789245774186083 + ], + [ + 39.281073839006595, + -6.789477514362669 + ], + [ + 39.28114397070973, + -6.793117958745426 + ], + [ + 39.28113420729278, + -6.79383486840148 + ], + [ + 39.281114726156694, + -6.793847842189681 + ], + [ + 39.28113330952829, + -6.79388250834817 + ], + [ + 39.281129262608935, + -6.794159983557968 + ], + [ + 39.28109084175889, + -6.794179680568165 + ], + [ + 39.28112752361519, + -6.794277502669122 + ], + [ + 39.28111635395094, + -6.795038314028078 + ], + [ + 39.281016070626016, + -6.795075741198945 + ], + [ + 39.281112775297714, + -6.795250226366647 + ], + [ + 39.2810949704288, + -6.79646195887955 + ], + [ + 39.2809583747182, + -6.796479910277594 + ], + [ + 39.280976796828014, + -6.79655746965899 + ], + [ + 39.28106599069538, + -6.796757139303622 + ], + [ + 39.28105528128861, + -6.79686803066901 + ], + [ + 39.281087453345336, + -6.796987885295481 + ], + [ + 39.28108073143122, + -6.797439731548687 + ], + [ + 39.28083992809423, + -6.797461906062759 + ], + [ + 39.28083642610969, + -6.797501481434426 + ], + [ + 39.28072006370183, + -6.797559721622083 + ], + [ + 39.280792511077834, + -6.797755460113359 + ], + [ + 39.280782299142885, + -6.797822644537164 + ], + [ + 39.28087877377628, + -6.798094898764859 + ], + [ + 39.28087160779872, + -6.798109486776828 + ], + [ + 39.28084495591411, + -6.798106189716947 + ], + [ + 39.28091358669126, + -6.798282661131834 + ], + [ + 39.280894058903186, + -6.798303988028182 + ], + [ + 39.28089993648302, + -6.798318476273004 + ], + [ + 39.28094807709286, + -6.798317376152552 + ], + [ + 39.28097704846284, + -6.798338565814496 + ], + [ + 39.280968589108724, + -6.798359909541208 + ], + [ + 39.28098862495911, + -6.798363833982053 + ], + [ + 39.28106384308544, + -6.798560924842693 + ], + [ + 39.281060047781274, + -6.798789172787439 + ], + [ + 39.280964648702366, + -6.79881579282715 + ], + [ + 39.2810549062557, + -6.799182593389792 + ], + [ + 39.281051210712, + -6.799417431324301 + ], + [ + 39.281012045218766, + -6.799461973169469 + ], + [ + 39.28092870982996, + -6.799469616595563 + ], + [ + 39.28102911738072, + -6.800116395040011 + ], + [ + 39.28096755147659, + -6.800136517203233 + ], + [ + 39.28098227562801, + -6.800231504054254 + ], + [ + 39.28092089023231, + -6.800365292854012 + ], + [ + 39.28092243227157, + -6.800466481559217 + ], + [ + 39.28099285109281, + -6.800487505251037 + ], + [ + 39.2809865598948, + -6.80056017366214 + ], + [ + 39.281022039297945, + -6.800676509145848 + ], + [ + 39.28100512867587, + -6.800686027414948 + ], + [ + 39.28094639492564, + -6.800673573505817 + ], + [ + 39.28098960816634, + -6.80080288458438 + ], + [ + 39.28100608830849, + -6.800808079923416 + ], + [ + 39.28101818264724, + -6.800788226357124 + ], + [ + 39.28103090221736, + -6.800799071421509 + ], + [ + 39.28100953313295, + -6.802247229426974 + ], + [ + 39.280969530277055, + -6.802983496860963 + ], + [ + 39.279742849863105, + -6.803751726145401 + ], + [ + 39.279491514203464, + -6.803861587800235 + ], + [ + 39.277158588001264, + -6.804087251350162 + ], + [ + 39.27513747683199, + -6.804142100699255 + ], + [ + 39.27511678207263, + -6.804135692385428 + ], + [ + 39.2751163497056, + -6.804060709416309 + ], + [ + 39.27391722620214, + -6.804061389785589 + ], + [ + 39.27385826397281, + -6.804047806856571 + ], + [ + 39.27384911606231, + -6.803999913343275 + ], + [ + 39.2735965361418, + -6.80398525563719 + ], + [ + 39.273500708320924, + -6.80401301734282 + ], + [ + 39.27346293523808, + -6.804003966970788 + ], + [ + 39.27342162790581, + -6.804025593648304 + ], + [ + 39.27340672680942, + -6.804008608011346 + ], + [ + 39.273416845431285, + -6.803993658369023 + ] + ], + [ + [ + 39.2734931545649, + -6.80398387288763 + ], + [ + 39.27349774748707, + -6.803981148820998 + ], + [ + 39.2734846042507, + -6.80398069373159 + ], + [ + 39.27348722790041, + -6.80398493599873 + ], + [ + 39.2734931545649, + -6.80398387288763 + ] + ], + [ + [ + 39.281045469223024, + -6.796406485350073 + ], + [ + 39.28104614552522, + -6.79640624303539 + ], + [ + 39.28104624219622, + -6.796405856316271 + ], + [ + 39.28104544832558, + -6.796406065132672 + ], + [ + 39.281045469223024, + -6.796406485350073 + ] + ], + [ + [ + 39.25013462741531, + -6.7822284539465 + ], + [ + 39.250139342204406, + -6.782225634227249 + ], + [ + 39.25013885529763, + -6.782223167263246 + ], + [ + 39.25013601751904, + -6.782223433931297 + ], + [ + 39.25013462741531, + -6.7822284539465 + ] + ], + [ + [ + 39.250133340148714, + -6.782197609422264 + ], + [ + 39.25013227568109, + -6.782192336183768 + ], + [ + 39.25013085449504, + -6.782186240541199 + ], + [ + 39.25012984461586, + -6.782195145644085 + ], + [ + 39.250133340148714, + -6.782197609422264 + ] + ] + ], + [ + [ + [ + 39.28101229778558, + -6.800726929325503 + ], + [ + 39.28102979517802, + -6.800722356034623 + ], + [ + 39.28102777800557, + -6.800751554944212 + ], + [ + 39.281011984140875, + -6.800747680790295 + ], + [ + 39.28101229778558, + -6.800726929325503 + ] + ] + ], + [ + [ + [ + 39.28098638863562, + -6.800732494588853 + ], + [ + 39.280997245783674, + -6.800723485911647 + ], + [ + 39.28100583405759, + -6.80073429499442 + ], + [ + 39.280995019972025, + -6.800742416990294 + ], + [ + 39.28098638863562, + -6.800732494588853 + ] + ] + ], + [ + [ + [ + 39.27333576292948, + -6.804020758896268 + ], + [ + 39.27334712034972, + -6.804009856466778 + ], + [ + 39.27335756490539, + -6.804021209097676 + ], + [ + 39.273346206700516, + -6.804030723971451 + ], + [ + 39.27333576292948, + -6.804020758896268 + ] + ] + ], + [ + [ + [ + 39.27338784445309, + -6.804011179704081 + ], + [ + 39.27340165825813, + -6.804007187497802 + ], + [ + 39.27340508925115, + -6.804022507747959 + ], + [ + 39.2733897619233, + -6.804025474696425 + ], + [ + 39.27338784445309, + -6.804011179704081 + ] + ] + ], + [ + [ + [ + 39.28093735076017, + -6.798277365237194 + ], + [ + 39.28094786501646, + -6.798293757944892 + ], + [ + 39.28092636574822, + -6.798297946514793 + ], + [ + 39.28091893391865, + -6.798272295760583 + ], + [ + 39.28093735076017, + -6.798277365237194 + ] + ] + ] ] - ] - ] - }, - "bbox": [ - 39.24966102436161, - -6.804292908938633, - 39.28114400293776, - -6.773980646345491 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "image": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/dar/f883a0/f883a0.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "GeoTIFF" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "image": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/dar/f883a0/f883a0.tif", - "type": "image/tiff; application=geotiff; profile=cloud-optimized", - "title": "GeoTIFF" - } - }, - "collection": "dar" + "bbox": [ + 39.24966102436161, + -6.804292908938633, + 39.28114400293776, + -6.773980646345491 + ], + "stac_extensions": [], + "collection": "dar" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/kam/4e7c7f-labels/4e7c7f-labels.json b/tests/data-files/catalogs/test-case-4/kam/4e7c7f-labels/4e7c7f-labels.json index 1f8c8569e..38250e5ff 100644 --- a/tests/data-files/catalogs/test-case-4/kam/4e7c7f-labels/4e7c7f-labels.json +++ b/tests/data-files/catalogs/test-case-4/kam/4e7c7f-labels/4e7c7f-labels.json @@ -1,425 +1,426 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "4e7c7f-labels", - "properties": { - "label:description": "Geojson building labels for scene 4e7c7f", - "area": "kam", - "label:type": "vector", - "label:properties": [ - "building" - ], - "label:overviews": [ - { - "property_key": "building", - "counts": [ - { - "name": "yes", - "count": 4056 - } - ] - } - ], - "license": "ODbL-1.0", - "datetime": "2018-09-17T00:00:00Z", - "label:classes": [ - { - "name": "building", - "classes": [ - "yes" - ] - } - ] - }, - "geometry": { - "coordinates": [ - [ - [ - 32.62648054593931, - 0.256417512540714 - ], - [ - 32.627126980840195, - 0.25620295116935593 - ], - [ - 32.62783415844573, - 0.255410994304475 - ], - [ - 32.629199259432276, - 0.2543302475722729 - ], - [ - 32.629052083887395, - 0.25414046858019 - ], - [ - 32.62942671102056, - 0.253927225241941 - ], - [ - 32.63011734620023, - 0.25322826915649893 - ], - [ - 32.6311796485047, - 0.252518218530017 - ], - [ - 32.63161216376019, - 0.25231626643179605 - ], - [ - 32.63213655266929, - 0.251658391599513 - ], - [ - 32.63272372642811, - 0.2511272429507839 - ], - [ - 32.63254169351733, - 0.25084451098298594 - ], - [ - 32.63314588785948, - 0.25055790597453304 - ], - [ - 32.633568049290844, - 0.251150481194712 - ], - [ - 32.633925547411806, - 0.25091228371465596 - ], - [ - 32.63412964018579, - 0.251274418495665 - ], - [ - 32.635159868999956, - 0.25041460347030703 - ], - [ - 32.635167615081265, - 0.24997307683566403 - ], - [ - 32.635764063342094, - 0.24950443891643803 - ], - [ - 32.63606616051317, - 0.24964386838000902 - ], - [ - 32.636248193423945, - 0.24927592951780594 - ], - [ - 32.63745658210823, - 0.24989174298191394 - ], - [ - 32.63721258054698, - 0.2503681269824499 - ], - [ - 32.63840929998812, - 0.250942713819728 - ], - [ - 32.63778349823557, - 0.2520010873099949 - ], - [ - 32.6377025843977, - 0.25218375675407106 - ], - [ - 32.63804242251679, - 0.25231321889467795 - ], - [ - 32.63796150867891, - 0.252685422548926 - ], - [ - 32.638649276300896, - 0.25271778808407813 - ], - [ - 32.638584545230586, - 0.25419041993349195 - ], - [ - 32.63860072799817, - 0.256917216270045 - ], - [ - 32.638649276300896, - 0.25820374629233506 - ], - [ - 32.638325620949374, - 0.258195654908547 - ], - [ - 32.63775113270042, - 0.258527401643855 - ], - [ - 32.638438900322406, - 0.25946600216326193 - ], - [ - 32.63706336507845, - 0.26075253218555194 - ], - [ - 32.63691772017026, - 0.26070398388282406 - ], - [ - 32.636747801110715, - 0.26080108048828 - ], - [ - 32.636950085705415, - 0.261068096153284 - ], - [ - 32.63539468442814, - 0.26201630282476607 - ], - [ - 32.63522848916817, - 0.26190455083961195 - ], - [ - 32.63505942847269, - 0.26207074609958386 - ], - [ - 32.63460382422552, - 0.26152344791588394 - ], - [ - 32.634022140815624, - 0.2612884822035099 - ], - [ - 32.63370407747327, - 0.261259827848342 - ], - [ - 32.63349203524503, - 0.261454677463481 - ], - [ - 32.63296766054546, - 0.260944629941499 - ], - [ - 32.63280719615652, - 0.261047785620102 - ], - [ - 32.632423227797275, - 0.260606508550522 - ], - [ - 32.632497729120715, - 0.260509083742952 - ], - [ - 32.63205645205113, - 0.2602569254174769 - ], - [ - 32.63213095337457, - 0.26007926841543794 - ], - [ - 32.63202493226045, - 0.259950323817184 - ], - [ - 32.631772773934976, - 0.259703896362743 - ], - [ - 32.631672483691894, - 0.25962939503930793 - ], - [ - 32.63148049951227, - 0.259586413506556 - ], - [ - 32.63135155491401, - 0.2596494530879249 - ], - [ - 32.63109939658854, - 0.259308466261431 - ], - [ - 32.631053549620276, - 0.259305600825914 - ], - [ - 32.630712562793775, - 0.2595061813120871 - ], - [ - 32.63042028837107, - 0.25911361664629196 - ], - [ - 32.63052630948519, - 0.25900759553217195 - ], - [ - 32.63037444140281, - 0.25878409156186494 - ], - [ - 32.63023116962697, - 0.2588901126759849 - ], - [ - 32.630067839802514, - 0.25860643455982596 - ], - [ - 32.629947491510805, - 0.2587267828515289 - ], - [ - 32.62981568147704, - 0.258560587591558 - ], - [ - 32.6297411801536, - 0.258620761737409 - ], - [ - 32.62950334900572, - 0.25829983295953296 - ], - [ - 32.629362942665395, - 0.2583857960250349 - ], - [ - 32.629236863502655, - 0.25821673532954686 - ], - [ - 32.6288328370948, - 0.258431642993304 - ], - [ - 32.62873254685171, - 0.25833421818573393 - ], - [ - 32.628357174799014, - 0.25857204933362493 - ], - [ - 32.62818689539351, - 0.25834584330486 - ], - [ - 32.627884377938756, - 0.258560587591558 - ], - [ - 32.627586372645005, - 0.258119310521977 - ], - [ - 32.62737719585229, - 0.25788721024511996 - ], - [ - 32.6273284834485, - 0.257947384390972 - ], - [ - 32.62717661536612, - 0.257821305228234 - ], - [ - 32.62729123278679, - 0.25772101498514793 - ], - [ - 32.627130768397855, - 0.257554819725176 - ], - [ - 32.62700755467063, - 0.25764937909722896 - ], - [ - 32.6265576812945, - 0.2572969305286679 - ], - [ - 32.626179443806286, - 0.256944481960107 - ], - [ - 32.6264545256159, - 0.2566779964570488 - ], - [ - 32.62631411927558, - 0.256600629698096 - ], - [ - 32.62648054593931, - 0.256417512540714 + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "4e7c7f-labels", + "properties": { + "label:description": "Geojson building labels for scene 4e7c7f", + "area": "kam", + "label:type": "vector", + "label:properties": [ + "building" + ], + "label:overviews": [ + { + "property_key": "building", + "counts": [ + { + "name": "yes", + "count": 4056 + } + ] + } + ], + "license": "ODbL-1.0", + "datetime": "2018-09-17T00:00:00Z", + "label:classes": [ + { + "name": "building", + "classes": [ + "yes" + ] + } ] - ] - ], - "type": "Polygon" - }, - "bbox": [ - 32.626179443806286, - 0.24927592951780594, - 32.638649276300896, - 0.26207074609958386 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "geometry": { + "coordinates": [ + [ + [ + 32.62648054593931, + 0.256417512540714 + ], + [ + 32.627126980840195, + 0.25620295116935593 + ], + [ + 32.62783415844573, + 0.255410994304475 + ], + [ + 32.629199259432276, + 0.2543302475722729 + ], + [ + 32.629052083887395, + 0.25414046858019 + ], + [ + 32.62942671102056, + 0.253927225241941 + ], + [ + 32.63011734620023, + 0.25322826915649893 + ], + [ + 32.6311796485047, + 0.252518218530017 + ], + [ + 32.63161216376019, + 0.25231626643179605 + ], + [ + 32.63213655266929, + 0.251658391599513 + ], + [ + 32.63272372642811, + 0.2511272429507839 + ], + [ + 32.63254169351733, + 0.25084451098298594 + ], + [ + 32.63314588785948, + 0.25055790597453304 + ], + [ + 32.633568049290844, + 0.251150481194712 + ], + [ + 32.633925547411806, + 0.25091228371465596 + ], + [ + 32.63412964018579, + 0.251274418495665 + ], + [ + 32.635159868999956, + 0.25041460347030703 + ], + [ + 32.635167615081265, + 0.24997307683566403 + ], + [ + 32.635764063342094, + 0.24950443891643803 + ], + [ + 32.63606616051317, + 0.24964386838000902 + ], + [ + 32.636248193423945, + 0.24927592951780594 + ], + [ + 32.63745658210823, + 0.24989174298191394 + ], + [ + 32.63721258054698, + 0.2503681269824499 + ], + [ + 32.63840929998812, + 0.250942713819728 + ], + [ + 32.63778349823557, + 0.2520010873099949 + ], + [ + 32.6377025843977, + 0.25218375675407106 + ], + [ + 32.63804242251679, + 0.25231321889467795 + ], + [ + 32.63796150867891, + 0.252685422548926 + ], + [ + 32.638649276300896, + 0.25271778808407813 + ], + [ + 32.638584545230586, + 0.25419041993349195 + ], + [ + 32.63860072799817, + 0.256917216270045 + ], + [ + 32.638649276300896, + 0.25820374629233506 + ], + [ + 32.638325620949374, + 0.258195654908547 + ], + [ + 32.63775113270042, + 0.258527401643855 + ], + [ + 32.638438900322406, + 0.25946600216326193 + ], + [ + 32.63706336507845, + 0.26075253218555194 + ], + [ + 32.63691772017026, + 0.26070398388282406 + ], + [ + 32.636747801110715, + 0.26080108048828 + ], + [ + 32.636950085705415, + 0.261068096153284 + ], + [ + 32.63539468442814, + 0.26201630282476607 + ], + [ + 32.63522848916817, + 0.26190455083961195 + ], + [ + 32.63505942847269, + 0.26207074609958386 + ], + [ + 32.63460382422552, + 0.26152344791588394 + ], + [ + 32.634022140815624, + 0.2612884822035099 + ], + [ + 32.63370407747327, + 0.261259827848342 + ], + [ + 32.63349203524503, + 0.261454677463481 + ], + [ + 32.63296766054546, + 0.260944629941499 + ], + [ + 32.63280719615652, + 0.261047785620102 + ], + [ + 32.632423227797275, + 0.260606508550522 + ], + [ + 32.632497729120715, + 0.260509083742952 + ], + [ + 32.63205645205113, + 0.2602569254174769 + ], + [ + 32.63213095337457, + 0.26007926841543794 + ], + [ + 32.63202493226045, + 0.259950323817184 + ], + [ + 32.631772773934976, + 0.259703896362743 + ], + [ + 32.631672483691894, + 0.25962939503930793 + ], + [ + 32.63148049951227, + 0.259586413506556 + ], + [ + 32.63135155491401, + 0.2596494530879249 + ], + [ + 32.63109939658854, + 0.259308466261431 + ], + [ + 32.631053549620276, + 0.259305600825914 + ], + [ + 32.630712562793775, + 0.2595061813120871 + ], + [ + 32.63042028837107, + 0.25911361664629196 + ], + [ + 32.63052630948519, + 0.25900759553217195 + ], + [ + 32.63037444140281, + 0.25878409156186494 + ], + [ + 32.63023116962697, + 0.2588901126759849 + ], + [ + 32.630067839802514, + 0.25860643455982596 + ], + [ + 32.629947491510805, + 0.2587267828515289 + ], + [ + 32.62981568147704, + 0.258560587591558 + ], + [ + 32.6297411801536, + 0.258620761737409 + ], + [ + 32.62950334900572, + 0.25829983295953296 + ], + [ + 32.629362942665395, + 0.2583857960250349 + ], + [ + 32.629236863502655, + 0.25821673532954686 + ], + [ + 32.6288328370948, + 0.258431642993304 + ], + [ + 32.62873254685171, + 0.25833421818573393 + ], + [ + 32.628357174799014, + 0.25857204933362493 + ], + [ + 32.62818689539351, + 0.25834584330486 + ], + [ + 32.627884377938756, + 0.258560587591558 + ], + [ + 32.627586372645005, + 0.258119310521977 + ], + [ + 32.62737719585229, + 0.25788721024511996 + ], + [ + 32.6273284834485, + 0.257947384390972 + ], + [ + 32.62717661536612, + 0.257821305228234 + ], + [ + 32.62729123278679, + 0.25772101498514793 + ], + [ + 32.627130768397855, + 0.257554819725176 + ], + [ + 32.62700755467063, + 0.25764937909722896 + ], + [ + 32.6265576812945, + 0.2572969305286679 + ], + [ + 32.626179443806286, + 0.256944481960107 + ], + [ + 32.6264545256159, + 0.2566779964570488 + ], + [ + 32.62631411927558, + 0.256600629698096 + ], + [ + 32.62648054593931, + 0.256417512540714 + ] + ] + ], + "type": "Polygon" + }, + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "labels": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/kam/4e7c7f-labels/4e7c7f.geojson", + "type": "application/geo+json" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "labels": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/kam/4e7c7f-labels/4e7c7f.geojson", - "type": "application/geo+json" - } - }, - "stac_extensions": [ - "label" - ] + "bbox": [ + 32.626179443806286, + 0.24927592951780594, + 32.638649276300896, + 0.26207074609958386 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "kam" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/kam/4e7c7f/4e7c7f.json b/tests/data-files/catalogs/test-case-4/kam/4e7c7f/4e7c7f.json index d686c181d..a49d7626f 100644 --- a/tests/data-files/catalogs/test-case-4/kam/4e7c7f/4e7c7f.json +++ b/tests/data-files/catalogs/test-case-4/kam/4e7c7f/4e7c7f.json @@ -1,400 +1,401 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "4e7c7f", - "properties": { - "area": "kam", - "license": "CC-BY-4.0", - "datetime": "2018-09-17T00:00:00Z" - }, - "geometry": { - "coordinates": [ - [ - [ - 32.62648054593931, - 0.256417512540714 - ], - [ - 32.627126980840195, - 0.25620295116935593 - ], - [ - 32.62783415844573, - 0.255410994304475 - ], - [ - 32.629199259432276, - 0.2543302475722729 - ], - [ - 32.629052083887395, - 0.25414046858019 - ], - [ - 32.62942671102056, - 0.253927225241941 - ], - [ - 32.63011734620023, - 0.25322826915649893 - ], - [ - 32.6311796485047, - 0.252518218530017 - ], - [ - 32.63161216376019, - 0.25231626643179605 - ], - [ - 32.63213655266929, - 0.251658391599513 - ], - [ - 32.63272372642811, - 0.2511272429507839 - ], - [ - 32.63254169351733, - 0.25084451098298594 - ], - [ - 32.63314588785948, - 0.25055790597453304 - ], - [ - 32.633568049290844, - 0.251150481194712 - ], - [ - 32.633925547411806, - 0.25091228371465596 - ], - [ - 32.63412964018579, - 0.251274418495665 - ], - [ - 32.635159868999956, - 0.25041460347030703 - ], - [ - 32.635167615081265, - 0.24997307683566403 - ], - [ - 32.635764063342094, - 0.24950443891643803 - ], - [ - 32.63606616051317, - 0.24964386838000902 - ], - [ - 32.636248193423945, - 0.24927592951780594 - ], - [ - 32.63745658210823, - 0.24989174298191394 - ], - [ - 32.63721258054698, - 0.2503681269824499 - ], - [ - 32.63840929998812, - 0.250942713819728 - ], - [ - 32.63778349823557, - 0.2520010873099949 - ], - [ - 32.6377025843977, - 0.25218375675407106 - ], - [ - 32.63804242251679, - 0.25231321889467795 - ], - [ - 32.63796150867891, - 0.252685422548926 - ], - [ - 32.638649276300896, - 0.25271778808407813 - ], - [ - 32.638584545230586, - 0.25419041993349195 - ], - [ - 32.63860072799817, - 0.256917216270045 - ], - [ - 32.638649276300896, - 0.25820374629233506 - ], - [ - 32.638325620949374, - 0.258195654908547 - ], - [ - 32.63775113270042, - 0.258527401643855 - ], - [ - 32.638438900322406, - 0.25946600216326193 - ], - [ - 32.63706336507845, - 0.26075253218555194 - ], - [ - 32.63691772017026, - 0.26070398388282406 - ], - [ - 32.636747801110715, - 0.26080108048828 - ], - [ - 32.636950085705415, - 0.261068096153284 - ], - [ - 32.63539468442814, - 0.26201630282476607 - ], - [ - 32.63522848916817, - 0.26190455083961195 - ], - [ - 32.63505942847269, - 0.26207074609958386 - ], - [ - 32.63460382422552, - 0.26152344791588394 - ], - [ - 32.634022140815624, - 0.2612884822035099 - ], - [ - 32.63370407747327, - 0.261259827848342 - ], - [ - 32.63349203524503, - 0.261454677463481 - ], - [ - 32.63296766054546, - 0.260944629941499 - ], - [ - 32.63280719615652, - 0.261047785620102 - ], - [ - 32.632423227797275, - 0.260606508550522 - ], - [ - 32.632497729120715, - 0.260509083742952 - ], - [ - 32.63205645205113, - 0.2602569254174769 - ], - [ - 32.63213095337457, - 0.26007926841543794 - ], - [ - 32.63202493226045, - 0.259950323817184 - ], - [ - 32.631772773934976, - 0.259703896362743 - ], - [ - 32.631672483691894, - 0.25962939503930793 - ], - [ - 32.63148049951227, - 0.259586413506556 - ], - [ - 32.63135155491401, - 0.2596494530879249 - ], - [ - 32.63109939658854, - 0.259308466261431 - ], - [ - 32.631053549620276, - 0.259305600825914 - ], - [ - 32.630712562793775, - 0.2595061813120871 - ], - [ - 32.63042028837107, - 0.25911361664629196 - ], - [ - 32.63052630948519, - 0.25900759553217195 - ], - [ - 32.63037444140281, - 0.25878409156186494 - ], - [ - 32.63023116962697, - 0.2588901126759849 - ], - [ - 32.630067839802514, - 0.25860643455982596 - ], - [ - 32.629947491510805, - 0.2587267828515289 - ], - [ - 32.62981568147704, - 0.258560587591558 - ], - [ - 32.6297411801536, - 0.258620761737409 - ], - [ - 32.62950334900572, - 0.25829983295953296 - ], - [ - 32.629362942665395, - 0.2583857960250349 - ], - [ - 32.629236863502655, - 0.25821673532954686 - ], - [ - 32.6288328370948, - 0.258431642993304 - ], - [ - 32.62873254685171, - 0.25833421818573393 - ], - [ - 32.628357174799014, - 0.25857204933362493 - ], - [ - 32.62818689539351, - 0.25834584330486 - ], - [ - 32.627884377938756, - 0.258560587591558 - ], - [ - 32.627586372645005, - 0.258119310521977 - ], - [ - 32.62737719585229, - 0.25788721024511996 - ], - [ - 32.6273284834485, - 0.257947384390972 - ], - [ - 32.62717661536612, - 0.257821305228234 - ], - [ - 32.62729123278679, - 0.25772101498514793 - ], - [ - 32.627130768397855, - 0.257554819725176 - ], - [ - 32.62700755467063, - 0.25764937909722896 - ], - [ - 32.6265576812945, - 0.2572969305286679 - ], - [ - 32.626179443806286, - 0.256944481960107 - ], - [ - 32.6264545256159, - 0.2566779964570488 - ], - [ - 32.62631411927558, - 0.256600629698096 - ], - [ - 32.62648054593931, - 0.256417512540714 - ] - ] - ], - "type": "Polygon" - }, - "bbox": [ - 32.626179443806286, - 0.24927592951780594, - 32.638649276300896, - 0.26207074609958386 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "4e7c7f", + "properties": { + "area": "kam", + "license": "CC-BY-4.0", + "datetime": "2018-09-17T00:00:00Z" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "geometry": { + "coordinates": [ + [ + [ + 32.62648054593931, + 0.256417512540714 + ], + [ + 32.627126980840195, + 0.25620295116935593 + ], + [ + 32.62783415844573, + 0.255410994304475 + ], + [ + 32.629199259432276, + 0.2543302475722729 + ], + [ + 32.629052083887395, + 0.25414046858019 + ], + [ + 32.62942671102056, + 0.253927225241941 + ], + [ + 32.63011734620023, + 0.25322826915649893 + ], + [ + 32.6311796485047, + 0.252518218530017 + ], + [ + 32.63161216376019, + 0.25231626643179605 + ], + [ + 32.63213655266929, + 0.251658391599513 + ], + [ + 32.63272372642811, + 0.2511272429507839 + ], + [ + 32.63254169351733, + 0.25084451098298594 + ], + [ + 32.63314588785948, + 0.25055790597453304 + ], + [ + 32.633568049290844, + 0.251150481194712 + ], + [ + 32.633925547411806, + 0.25091228371465596 + ], + [ + 32.63412964018579, + 0.251274418495665 + ], + [ + 32.635159868999956, + 0.25041460347030703 + ], + [ + 32.635167615081265, + 0.24997307683566403 + ], + [ + 32.635764063342094, + 0.24950443891643803 + ], + [ + 32.63606616051317, + 0.24964386838000902 + ], + [ + 32.636248193423945, + 0.24927592951780594 + ], + [ + 32.63745658210823, + 0.24989174298191394 + ], + [ + 32.63721258054698, + 0.2503681269824499 + ], + [ + 32.63840929998812, + 0.250942713819728 + ], + [ + 32.63778349823557, + 0.2520010873099949 + ], + [ + 32.6377025843977, + 0.25218375675407106 + ], + [ + 32.63804242251679, + 0.25231321889467795 + ], + [ + 32.63796150867891, + 0.252685422548926 + ], + [ + 32.638649276300896, + 0.25271778808407813 + ], + [ + 32.638584545230586, + 0.25419041993349195 + ], + [ + 32.63860072799817, + 0.256917216270045 + ], + [ + 32.638649276300896, + 0.25820374629233506 + ], + [ + 32.638325620949374, + 0.258195654908547 + ], + [ + 32.63775113270042, + 0.258527401643855 + ], + [ + 32.638438900322406, + 0.25946600216326193 + ], + [ + 32.63706336507845, + 0.26075253218555194 + ], + [ + 32.63691772017026, + 0.26070398388282406 + ], + [ + 32.636747801110715, + 0.26080108048828 + ], + [ + 32.636950085705415, + 0.261068096153284 + ], + [ + 32.63539468442814, + 0.26201630282476607 + ], + [ + 32.63522848916817, + 0.26190455083961195 + ], + [ + 32.63505942847269, + 0.26207074609958386 + ], + [ + 32.63460382422552, + 0.26152344791588394 + ], + [ + 32.634022140815624, + 0.2612884822035099 + ], + [ + 32.63370407747327, + 0.261259827848342 + ], + [ + 32.63349203524503, + 0.261454677463481 + ], + [ + 32.63296766054546, + 0.260944629941499 + ], + [ + 32.63280719615652, + 0.261047785620102 + ], + [ + 32.632423227797275, + 0.260606508550522 + ], + [ + 32.632497729120715, + 0.260509083742952 + ], + [ + 32.63205645205113, + 0.2602569254174769 + ], + [ + 32.63213095337457, + 0.26007926841543794 + ], + [ + 32.63202493226045, + 0.259950323817184 + ], + [ + 32.631772773934976, + 0.259703896362743 + ], + [ + 32.631672483691894, + 0.25962939503930793 + ], + [ + 32.63148049951227, + 0.259586413506556 + ], + [ + 32.63135155491401, + 0.2596494530879249 + ], + [ + 32.63109939658854, + 0.259308466261431 + ], + [ + 32.631053549620276, + 0.259305600825914 + ], + [ + 32.630712562793775, + 0.2595061813120871 + ], + [ + 32.63042028837107, + 0.25911361664629196 + ], + [ + 32.63052630948519, + 0.25900759553217195 + ], + [ + 32.63037444140281, + 0.25878409156186494 + ], + [ + 32.63023116962697, + 0.2588901126759849 + ], + [ + 32.630067839802514, + 0.25860643455982596 + ], + [ + 32.629947491510805, + 0.2587267828515289 + ], + [ + 32.62981568147704, + 0.258560587591558 + ], + [ + 32.6297411801536, + 0.258620761737409 + ], + [ + 32.62950334900572, + 0.25829983295953296 + ], + [ + 32.629362942665395, + 0.2583857960250349 + ], + [ + 32.629236863502655, + 0.25821673532954686 + ], + [ + 32.6288328370948, + 0.258431642993304 + ], + [ + 32.62873254685171, + 0.25833421818573393 + ], + [ + 32.628357174799014, + 0.25857204933362493 + ], + [ + 32.62818689539351, + 0.25834584330486 + ], + [ + 32.627884377938756, + 0.258560587591558 + ], + [ + 32.627586372645005, + 0.258119310521977 + ], + [ + 32.62737719585229, + 0.25788721024511996 + ], + [ + 32.6273284834485, + 0.257947384390972 + ], + [ + 32.62717661536612, + 0.257821305228234 + ], + [ + 32.62729123278679, + 0.25772101498514793 + ], + [ + 32.627130768397855, + 0.257554819725176 + ], + [ + 32.62700755467063, + 0.25764937909722896 + ], + [ + 32.6265576812945, + 0.2572969305286679 + ], + [ + 32.626179443806286, + 0.256944481960107 + ], + [ + 32.6264545256159, + 0.2566779964570488 + ], + [ + 32.62631411927558, + 0.256600629698096 + ], + [ + 32.62648054593931, + 0.256417512540714 + ] + ] + ], + "type": "Polygon" }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "image": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/kam/4e7c7f/4e7c7f.tif", - "type": "image/tiff; application=geotiff; profile=cloud-optimized", - "title": "GeoTIFF" - } - }, - "collection": "kam" + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "image": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/kam/4e7c7f/4e7c7f.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "GeoTIFF" + } + }, + "bbox": [ + 32.626179443806286, + 0.24927592951780594, + 32.638649276300896, + 0.26207074609958386 + ], + "stac_extensions": [], + "collection": "kam" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/kam/collection.json b/tests/data-files/catalogs/test-case-4/kam/collection.json index 417f23677..1ddca3485 100644 --- a/tests/data-files/catalogs/test-case-4/kam/collection.json +++ b/tests/data-files/catalogs/test-case-4/kam/collection.json @@ -1,6 +1,7 @@ { + "type": "Collection", "id": "kam", - "stac_version": "1.0.0-beta.2", + "stac_version": "1.0.0-rc.3", "description": "Tier 1 training data from kam", "links": [ { @@ -24,6 +25,7 @@ "type": "application/json" } ], + "stac_extensions": [], "extent": { "spatial": { "bbox": [ @@ -44,8 +46,5 @@ ] } }, - "license": "various", - "stac_extensions": [ - "label" - ] + "license": "various" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/mon/207cc7-labels/207cc7-labels.json b/tests/data-files/catalogs/test-case-4/mon/207cc7-labels/207cc7-labels.json index 2d04bce3c..55fc79920 100644 --- a/tests/data-files/catalogs/test-case-4/mon/207cc7-labels/207cc7-labels.json +++ b/tests/data-files/catalogs/test-case-4/mon/207cc7-labels/207cc7-labels.json @@ -1,241 +1,242 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "207cc7-labels", - "properties": { - "label:description": "Geojson building labels for scene 207cc7", - "area": "mon", - "label:type": "vector", - "label:properties": [ - "building" - ], - "label:overviews": [ - { - "property_key": "building", - "counts": [ - { - "name": "yes", - "count": 1544 - } - ] - } - ], - "license": "ODbL-1.0", - "datetime": "2018-10-05T00:00:00Z", - "label:classes": [ - { - "name": "building", - "classes": [ - "yes" - ] - } - ] - }, - "geometry": { - "coordinates": [ - [ - [ - -10.790252263071974, - 6.327654354234644 - ], - [ - -10.790755009504934, - 6.327458076517664 - ], - [ - -10.792373439802875, - 6.326361331730665 - ], - [ - -10.79307590742153, - 6.325934341609507 - ], - [ - -10.794090582870746, - 6.326383714277333 - ], - [ - -10.794546592256534, - 6.327018919524551 - ], - [ - -10.79407103916773, - 6.3272900234540765 - ], - [ - -10.793652114520532, - 6.328857846551934 - ], - [ - -10.79473795498992, - 6.329210228184179 - ], - [ - -10.796888975116362, - 6.329375514682693 - ], - [ - -10.798182715496184, - 6.329509777779871 - ], - [ - -10.798182715496177, - 6.329617191840718 - ], - [ - -10.798040329415507, - 6.329979402045897 - ], - [ - -10.797341492635896, - 6.330470791722323 - ], - [ - -10.797253982800587, - 6.33049464201636 - ], - [ - -10.796452802411968, - 6.330585893937414 - ], - [ - -10.796390819975015, - 6.330783319477304 - ], - [ - -10.796461984995213, - 6.330975005902661 - ], - [ - -10.79623242041395, - 6.3309543450903485 - ], - [ - -10.795979899374569, - 6.330988779777538 - ], - [ - -10.79595923856226, - 6.3314731610440065 - ], - [ - -10.795541431024347, - 6.331449630674429 - ], - [ - -10.795467876148185, - 6.33183839832465 - ], - [ - -10.795339414192823, - 6.331880638175758 - ], - [ - -10.795109849611574, - 6.3318622730092535 - ], - [ - -10.795178532885092, - 6.33203976757905 - ], - [ - -10.794388556717536, - 6.332538112815994 - ], - [ - -10.79351733283488, - 6.332929896116368 - ], - [ - -10.793124115983604, - 6.333146686841442 - ], - [ - -10.792915212214664, - 6.332830461630747 - ], - [ - -10.792644326008762, - 6.33220375032389 - ], - [ - -10.792022205993543, - 6.332094133236333 - ], - [ - -10.790640227214311, - 6.330934258189489 - ], - [ - -10.790072304258905, - 6.331193742761042 - ], - [ - -10.789681563288742, - 6.332031112763716 - ], - [ - -10.78938409766017, - 6.331880134151346 - ], - [ - -10.788359662453985, - 6.33118582694528 - ], - [ - -10.789184787769084, - 6.330292625184847 - ], - [ - -10.789487813016356, - 6.3300934779106 - ], - [ - -10.788826667022306, - 6.3294334797394605 - ], - [ - -10.788652197940552, - 6.328021083653217 - ], - [ - -10.790252263071974, - 6.327654354234644 + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "207cc7-labels", + "properties": { + "label:description": "Geojson building labels for scene 207cc7", + "area": "mon", + "label:type": "vector", + "label:properties": [ + "building" + ], + "label:overviews": [ + { + "property_key": "building", + "counts": [ + { + "name": "yes", + "count": 1544 + } + ] + } + ], + "license": "ODbL-1.0", + "datetime": "2018-10-05T00:00:00Z", + "label:classes": [ + { + "name": "building", + "classes": [ + "yes" + ] + } ] - ] - ], - "type": "Polygon" - }, - "bbox": [ - -10.798182715496184, - 6.325934341609507, - -10.788359662453985, - 6.333146686841442 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "geometry": { + "coordinates": [ + [ + [ + -10.790252263071974, + 6.327654354234644 + ], + [ + -10.790755009504934, + 6.327458076517664 + ], + [ + -10.792373439802875, + 6.326361331730665 + ], + [ + -10.79307590742153, + 6.325934341609507 + ], + [ + -10.794090582870746, + 6.326383714277333 + ], + [ + -10.794546592256534, + 6.327018919524551 + ], + [ + -10.79407103916773, + 6.3272900234540765 + ], + [ + -10.793652114520532, + 6.328857846551934 + ], + [ + -10.79473795498992, + 6.329210228184179 + ], + [ + -10.796888975116362, + 6.329375514682693 + ], + [ + -10.798182715496184, + 6.329509777779871 + ], + [ + -10.798182715496177, + 6.329617191840718 + ], + [ + -10.798040329415507, + 6.329979402045897 + ], + [ + -10.797341492635896, + 6.330470791722323 + ], + [ + -10.797253982800587, + 6.33049464201636 + ], + [ + -10.796452802411968, + 6.330585893937414 + ], + [ + -10.796390819975015, + 6.330783319477304 + ], + [ + -10.796461984995213, + 6.330975005902661 + ], + [ + -10.79623242041395, + 6.3309543450903485 + ], + [ + -10.795979899374569, + 6.330988779777538 + ], + [ + -10.79595923856226, + 6.3314731610440065 + ], + [ + -10.795541431024347, + 6.331449630674429 + ], + [ + -10.795467876148185, + 6.33183839832465 + ], + [ + -10.795339414192823, + 6.331880638175758 + ], + [ + -10.795109849611574, + 6.3318622730092535 + ], + [ + -10.795178532885092, + 6.33203976757905 + ], + [ + -10.794388556717536, + 6.332538112815994 + ], + [ + -10.79351733283488, + 6.332929896116368 + ], + [ + -10.793124115983604, + 6.333146686841442 + ], + [ + -10.792915212214664, + 6.332830461630747 + ], + [ + -10.792644326008762, + 6.33220375032389 + ], + [ + -10.792022205993543, + 6.332094133236333 + ], + [ + -10.790640227214311, + 6.330934258189489 + ], + [ + -10.790072304258905, + 6.331193742761042 + ], + [ + -10.789681563288742, + 6.332031112763716 + ], + [ + -10.78938409766017, + 6.331880134151346 + ], + [ + -10.788359662453985, + 6.33118582694528 + ], + [ + -10.789184787769084, + 6.330292625184847 + ], + [ + -10.789487813016356, + 6.3300934779106 + ], + [ + -10.788826667022306, + 6.3294334797394605 + ], + [ + -10.788652197940552, + 6.328021083653217 + ], + [ + -10.790252263071974, + 6.327654354234644 + ] + ] + ], + "type": "Polygon" + }, + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "labels": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/mon/207cc7-labels/207cc7.geojson", + "type": "application/geo+json" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "labels": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/mon/207cc7-labels/207cc7.geojson", - "type": "application/geo+json" - } - }, - "stac_extensions": [ - "label" - ] + "bbox": [ + -10.798182715496184, + 6.325934341609507, + -10.788359662453985, + 6.333146686841442 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "mon" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/mon/207cc7/207cc7.json b/tests/data-files/catalogs/test-case-4/mon/207cc7/207cc7.json index b667a1517..e5ec355f9 100644 --- a/tests/data-files/catalogs/test-case-4/mon/207cc7/207cc7.json +++ b/tests/data-files/catalogs/test-case-4/mon/207cc7/207cc7.json @@ -1,216 +1,217 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "207cc7", - "properties": { - "area": "mon", - "license": "CC-BY-4.0", - "datetime": "2018-10-05T00:00:00Z" - }, - "geometry": { - "coordinates": [ - [ - [ - -10.790252263071974, - 6.327654354234644 - ], - [ - -10.790755009504934, - 6.327458076517664 - ], - [ - -10.792373439802875, - 6.326361331730665 - ], - [ - -10.79307590742153, - 6.325934341609507 - ], - [ - -10.794090582870746, - 6.326383714277333 - ], - [ - -10.794546592256534, - 6.327018919524551 - ], - [ - -10.79407103916773, - 6.3272900234540765 - ], - [ - -10.793652114520532, - 6.328857846551934 - ], - [ - -10.79473795498992, - 6.329210228184179 - ], - [ - -10.796888975116362, - 6.329375514682693 - ], - [ - -10.798182715496184, - 6.329509777779871 - ], - [ - -10.798182715496177, - 6.329617191840718 - ], - [ - -10.798040329415507, - 6.329979402045897 - ], - [ - -10.797341492635896, - 6.330470791722323 - ], - [ - -10.797253982800587, - 6.33049464201636 - ], - [ - -10.796452802411968, - 6.330585893937414 - ], - [ - -10.796390819975015, - 6.330783319477304 - ], - [ - -10.796461984995213, - 6.330975005902661 - ], - [ - -10.79623242041395, - 6.3309543450903485 - ], - [ - -10.795979899374569, - 6.330988779777538 - ], - [ - -10.79595923856226, - 6.3314731610440065 - ], - [ - -10.795541431024347, - 6.331449630674429 - ], - [ - -10.795467876148185, - 6.33183839832465 - ], - [ - -10.795339414192823, - 6.331880638175758 - ], - [ - -10.795109849611574, - 6.3318622730092535 - ], - [ - -10.795178532885092, - 6.33203976757905 - ], - [ - -10.794388556717536, - 6.332538112815994 - ], - [ - -10.79351733283488, - 6.332929896116368 - ], - [ - -10.793124115983604, - 6.333146686841442 - ], - [ - -10.792915212214664, - 6.332830461630747 - ], - [ - -10.792644326008762, - 6.33220375032389 - ], - [ - -10.792022205993543, - 6.332094133236333 - ], - [ - -10.790640227214311, - 6.330934258189489 - ], - [ - -10.790072304258905, - 6.331193742761042 - ], - [ - -10.789681563288742, - 6.332031112763716 - ], - [ - -10.78938409766017, - 6.331880134151346 - ], - [ - -10.788359662453985, - 6.33118582694528 - ], - [ - -10.789184787769084, - 6.330292625184847 - ], - [ - -10.789487813016356, - 6.3300934779106 - ], - [ - -10.788826667022306, - 6.3294334797394605 - ], - [ - -10.788652197940552, - 6.328021083653217 - ], - [ - -10.790252263071974, - 6.327654354234644 - ] - ] - ], - "type": "Polygon" - }, - "bbox": [ - -10.798182715496184, - 6.325934341609507, - -10.788359662453985, - 6.333146686841442 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "207cc7", + "properties": { + "area": "mon", + "license": "CC-BY-4.0", + "datetime": "2018-10-05T00:00:00Z" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "geometry": { + "coordinates": [ + [ + [ + -10.790252263071974, + 6.327654354234644 + ], + [ + -10.790755009504934, + 6.327458076517664 + ], + [ + -10.792373439802875, + 6.326361331730665 + ], + [ + -10.79307590742153, + 6.325934341609507 + ], + [ + -10.794090582870746, + 6.326383714277333 + ], + [ + -10.794546592256534, + 6.327018919524551 + ], + [ + -10.79407103916773, + 6.3272900234540765 + ], + [ + -10.793652114520532, + 6.328857846551934 + ], + [ + -10.79473795498992, + 6.329210228184179 + ], + [ + -10.796888975116362, + 6.329375514682693 + ], + [ + -10.798182715496184, + 6.329509777779871 + ], + [ + -10.798182715496177, + 6.329617191840718 + ], + [ + -10.798040329415507, + 6.329979402045897 + ], + [ + -10.797341492635896, + 6.330470791722323 + ], + [ + -10.797253982800587, + 6.33049464201636 + ], + [ + -10.796452802411968, + 6.330585893937414 + ], + [ + -10.796390819975015, + 6.330783319477304 + ], + [ + -10.796461984995213, + 6.330975005902661 + ], + [ + -10.79623242041395, + 6.3309543450903485 + ], + [ + -10.795979899374569, + 6.330988779777538 + ], + [ + -10.79595923856226, + 6.3314731610440065 + ], + [ + -10.795541431024347, + 6.331449630674429 + ], + [ + -10.795467876148185, + 6.33183839832465 + ], + [ + -10.795339414192823, + 6.331880638175758 + ], + [ + -10.795109849611574, + 6.3318622730092535 + ], + [ + -10.795178532885092, + 6.33203976757905 + ], + [ + -10.794388556717536, + 6.332538112815994 + ], + [ + -10.79351733283488, + 6.332929896116368 + ], + [ + -10.793124115983604, + 6.333146686841442 + ], + [ + -10.792915212214664, + 6.332830461630747 + ], + [ + -10.792644326008762, + 6.33220375032389 + ], + [ + -10.792022205993543, + 6.332094133236333 + ], + [ + -10.790640227214311, + 6.330934258189489 + ], + [ + -10.790072304258905, + 6.331193742761042 + ], + [ + -10.789681563288742, + 6.332031112763716 + ], + [ + -10.78938409766017, + 6.331880134151346 + ], + [ + -10.788359662453985, + 6.33118582694528 + ], + [ + -10.789184787769084, + 6.330292625184847 + ], + [ + -10.789487813016356, + 6.3300934779106 + ], + [ + -10.788826667022306, + 6.3294334797394605 + ], + [ + -10.788652197940552, + 6.328021083653217 + ], + [ + -10.790252263071974, + 6.327654354234644 + ] + ] + ], + "type": "Polygon" }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "image": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/mon/207cc7/207cc7.tif", - "type": "image/tiff; application=geotiff; profile=cloud-optimized", - "title": "GeoTIFF" - } - }, - "collection": "mon" + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "image": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/mon/207cc7/207cc7.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "GeoTIFF" + } + }, + "bbox": [ + -10.798182715496184, + 6.325934341609507, + -10.788359662453985, + 6.333146686841442 + ], + "stac_extensions": [], + "collection": "mon" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/mon/401175-labels/401175-labels.json b/tests/data-files/catalogs/test-case-4/mon/401175-labels/401175-labels.json index 88dae5986..3bfc716aa 100644 --- a/tests/data-files/catalogs/test-case-4/mon/401175-labels/401175-labels.json +++ b/tests/data-files/catalogs/test-case-4/mon/401175-labels/401175-labels.json @@ -1,233 +1,234 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "401175-labels", - "properties": { - "label:description": "Geojson building labels for scene 401175", - "area": "mon", - "label:type": "vector", - "label:properties": [ - "building" - ], - "label:overviews": [ - { - "property_key": "building", - "counts": [ - { - "name": "yes", - "count": 2296 - } - ] - } - ], - "license": "ODbL-1.0", - "datetime": "2018-11-21T00:00:00Z", - "label:classes": [ - { - "name": "building", - "classes": [ - "yes" - ] - } - ] - }, - "geometry": { - "coordinates": [ - [ - [ - -10.792405216952368, - 6.337610599919112 - ], - [ - -10.791331344097435, - 6.33837279463673 - ], - [ - -10.789197765575608, - 6.339049277866593 - ], - [ - -10.788920088689641, - 6.339080445680323 - ], - [ - -10.78832790022873, - 6.339029443803308 - ], - [ - -10.787707377391706, - 6.338913272861214 - ], - [ - -10.787147623429378, - 6.338765894526389 - ], - [ - -10.78626515764722, - 6.338429463388974 - ], - [ - -10.78595914638511, - 6.338061824858818 - ], - [ - -10.785080780725423, - 6.337114039977611 - ], - [ - -10.784375254760038, - 6.3362923430701406 - ], - [ - -10.784117411937343, - 6.335824117504759 - ], - [ - -10.783947405680633, - 6.3348664155919145 - ], - [ - -10.7841514131887, - 6.334414482292804 - ], - [ - -10.784429090074655, - 6.334001508760861 - ], - [ - -10.785565298557051, - 6.333184062009808 - ], - [ - -10.786270824522447, - 6.3327880891035315 - ], - [ - -10.7872285264353, - 6.332159065953676 - ], - [ - -10.787795213957688, - 6.33168659023188 - ], - [ - -10.788344900854407, - 6.3311680711488885 - ], - [ - -10.789047593382183, - 6.331842429300539 - ], - [ - -10.789665282781591, - 6.332250444316662 - ], - [ - -10.789897624665784, - 6.332151274000243 - ], - [ - -10.789985461231744, - 6.33195860024263 - ], - [ - -10.789914625291447, - 6.33187147203606 - ], - [ - -10.789906124978605, - 6.3316391301518795 - ], - [ - -10.790359474996508, - 6.330781306914856 - ], - [ - -10.791089757077815, - 6.331292928586951 - ], - [ - -10.791388012849666, - 6.33157041928979 - ], - [ - -10.791399346600114, - 6.331768051563226 - ], - [ - -10.791886697869387, - 6.332269570020544 - ], - [ - -10.792147374129684, - 6.332218568143528 - ], - [ - -10.792306046635945, - 6.332289404083829 - ], - [ - -10.792685727275948, - 6.332373698852782 - ], - [ - -10.792889734784001, - 6.33279871449458 - ], - [ - -10.793204246358947, - 6.333226563573987 - ], - [ - -10.793107909480138, - 6.335605234449236 - ], - [ - -10.79296057072432, - 6.336548060814622 - ], - [ - -10.792903901972071, - 6.3367449847286546 - ], - [ - -10.792405216952368, - 6.337610599919112 + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "401175-labels", + "properties": { + "label:description": "Geojson building labels for scene 401175", + "area": "mon", + "label:type": "vector", + "label:properties": [ + "building" + ], + "label:overviews": [ + { + "property_key": "building", + "counts": [ + { + "name": "yes", + "count": 2296 + } + ] + } + ], + "license": "ODbL-1.0", + "datetime": "2018-11-21T00:00:00Z", + "label:classes": [ + { + "name": "building", + "classes": [ + "yes" + ] + } ] - ] - ], - "type": "Polygon" - }, - "bbox": [ - -10.793204246358947, - 6.330781306914856, - -10.783947405680633, - 6.339080445680323 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "geometry": { + "coordinates": [ + [ + [ + -10.792405216952368, + 6.337610599919112 + ], + [ + -10.791331344097435, + 6.33837279463673 + ], + [ + -10.789197765575608, + 6.339049277866593 + ], + [ + -10.788920088689641, + 6.339080445680323 + ], + [ + -10.78832790022873, + 6.339029443803308 + ], + [ + -10.787707377391706, + 6.338913272861214 + ], + [ + -10.787147623429378, + 6.338765894526389 + ], + [ + -10.78626515764722, + 6.338429463388974 + ], + [ + -10.78595914638511, + 6.338061824858818 + ], + [ + -10.785080780725423, + 6.337114039977611 + ], + [ + -10.784375254760038, + 6.3362923430701406 + ], + [ + -10.784117411937343, + 6.335824117504759 + ], + [ + -10.783947405680633, + 6.3348664155919145 + ], + [ + -10.7841514131887, + 6.334414482292804 + ], + [ + -10.784429090074655, + 6.334001508760861 + ], + [ + -10.785565298557051, + 6.333184062009808 + ], + [ + -10.786270824522447, + 6.3327880891035315 + ], + [ + -10.7872285264353, + 6.332159065953676 + ], + [ + -10.787795213957688, + 6.33168659023188 + ], + [ + -10.788344900854407, + 6.3311680711488885 + ], + [ + -10.789047593382183, + 6.331842429300539 + ], + [ + -10.789665282781591, + 6.332250444316662 + ], + [ + -10.789897624665784, + 6.332151274000243 + ], + [ + -10.789985461231744, + 6.33195860024263 + ], + [ + -10.789914625291447, + 6.33187147203606 + ], + [ + -10.789906124978605, + 6.3316391301518795 + ], + [ + -10.790359474996508, + 6.330781306914856 + ], + [ + -10.791089757077815, + 6.331292928586951 + ], + [ + -10.791388012849666, + 6.33157041928979 + ], + [ + -10.791399346600114, + 6.331768051563226 + ], + [ + -10.791886697869387, + 6.332269570020544 + ], + [ + -10.792147374129684, + 6.332218568143528 + ], + [ + -10.792306046635945, + 6.332289404083829 + ], + [ + -10.792685727275948, + 6.332373698852782 + ], + [ + -10.792889734784001, + 6.33279871449458 + ], + [ + -10.793204246358947, + 6.333226563573987 + ], + [ + -10.793107909480138, + 6.335605234449236 + ], + [ + -10.79296057072432, + 6.336548060814622 + ], + [ + -10.792903901972071, + 6.3367449847286546 + ], + [ + -10.792405216952368, + 6.337610599919112 + ] + ] + ], + "type": "Polygon" + }, + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "labels": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/mon/401175-labels/401175.geojson", + "type": "application/geo+json" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "labels": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/mon/401175-labels/401175.geojson", - "type": "application/geo+json" - } - }, - "stac_extensions": [ - "label" - ] + "bbox": [ + -10.793204246358947, + 6.330781306914856, + -10.783947405680633, + 6.339080445680323 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "mon" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/mon/401175/401175.json b/tests/data-files/catalogs/test-case-4/mon/401175/401175.json index 231aaacde..26a75cca8 100644 --- a/tests/data-files/catalogs/test-case-4/mon/401175/401175.json +++ b/tests/data-files/catalogs/test-case-4/mon/401175/401175.json @@ -1,208 +1,209 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "401175", - "properties": { - "area": "mon", - "license": "CC-BY-4.0", - "datetime": "2018-11-21T00:00:00Z" - }, - "geometry": { - "coordinates": [ - [ - [ - -10.792405216952368, - 6.337610599919112 - ], - [ - -10.791331344097435, - 6.33837279463673 - ], - [ - -10.789197765575608, - 6.339049277866593 - ], - [ - -10.788920088689641, - 6.339080445680323 - ], - [ - -10.78832790022873, - 6.339029443803308 - ], - [ - -10.787707377391706, - 6.338913272861214 - ], - [ - -10.787147623429378, - 6.338765894526389 - ], - [ - -10.78626515764722, - 6.338429463388974 - ], - [ - -10.78595914638511, - 6.338061824858818 - ], - [ - -10.785080780725423, - 6.337114039977611 - ], - [ - -10.784375254760038, - 6.3362923430701406 - ], - [ - -10.784117411937343, - 6.335824117504759 - ], - [ - -10.783947405680633, - 6.3348664155919145 - ], - [ - -10.7841514131887, - 6.334414482292804 - ], - [ - -10.784429090074655, - 6.334001508760861 - ], - [ - -10.785565298557051, - 6.333184062009808 - ], - [ - -10.786270824522447, - 6.3327880891035315 - ], - [ - -10.7872285264353, - 6.332159065953676 - ], - [ - -10.787795213957688, - 6.33168659023188 - ], - [ - -10.788344900854407, - 6.3311680711488885 - ], - [ - -10.789047593382183, - 6.331842429300539 - ], - [ - -10.789665282781591, - 6.332250444316662 - ], - [ - -10.789897624665784, - 6.332151274000243 - ], - [ - -10.789985461231744, - 6.33195860024263 - ], - [ - -10.789914625291447, - 6.33187147203606 - ], - [ - -10.789906124978605, - 6.3316391301518795 - ], - [ - -10.790359474996508, - 6.330781306914856 - ], - [ - -10.791089757077815, - 6.331292928586951 - ], - [ - -10.791388012849666, - 6.33157041928979 - ], - [ - -10.791399346600114, - 6.331768051563226 - ], - [ - -10.791886697869387, - 6.332269570020544 - ], - [ - -10.792147374129684, - 6.332218568143528 - ], - [ - -10.792306046635945, - 6.332289404083829 - ], - [ - -10.792685727275948, - 6.332373698852782 - ], - [ - -10.792889734784001, - 6.33279871449458 - ], - [ - -10.793204246358947, - 6.333226563573987 - ], - [ - -10.793107909480138, - 6.335605234449236 - ], - [ - -10.79296057072432, - 6.336548060814622 - ], - [ - -10.792903901972071, - 6.3367449847286546 - ], - [ - -10.792405216952368, - 6.337610599919112 - ] - ] - ], - "type": "Polygon" - }, - "bbox": [ - -10.793204246358947, - 6.330781306914856, - -10.783947405680633, - 6.339080445680323 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "401175", + "properties": { + "area": "mon", + "license": "CC-BY-4.0", + "datetime": "2018-11-21T00:00:00Z" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "geometry": { + "coordinates": [ + [ + [ + -10.792405216952368, + 6.337610599919112 + ], + [ + -10.791331344097435, + 6.33837279463673 + ], + [ + -10.789197765575608, + 6.339049277866593 + ], + [ + -10.788920088689641, + 6.339080445680323 + ], + [ + -10.78832790022873, + 6.339029443803308 + ], + [ + -10.787707377391706, + 6.338913272861214 + ], + [ + -10.787147623429378, + 6.338765894526389 + ], + [ + -10.78626515764722, + 6.338429463388974 + ], + [ + -10.78595914638511, + 6.338061824858818 + ], + [ + -10.785080780725423, + 6.337114039977611 + ], + [ + -10.784375254760038, + 6.3362923430701406 + ], + [ + -10.784117411937343, + 6.335824117504759 + ], + [ + -10.783947405680633, + 6.3348664155919145 + ], + [ + -10.7841514131887, + 6.334414482292804 + ], + [ + -10.784429090074655, + 6.334001508760861 + ], + [ + -10.785565298557051, + 6.333184062009808 + ], + [ + -10.786270824522447, + 6.3327880891035315 + ], + [ + -10.7872285264353, + 6.332159065953676 + ], + [ + -10.787795213957688, + 6.33168659023188 + ], + [ + -10.788344900854407, + 6.3311680711488885 + ], + [ + -10.789047593382183, + 6.331842429300539 + ], + [ + -10.789665282781591, + 6.332250444316662 + ], + [ + -10.789897624665784, + 6.332151274000243 + ], + [ + -10.789985461231744, + 6.33195860024263 + ], + [ + -10.789914625291447, + 6.33187147203606 + ], + [ + -10.789906124978605, + 6.3316391301518795 + ], + [ + -10.790359474996508, + 6.330781306914856 + ], + [ + -10.791089757077815, + 6.331292928586951 + ], + [ + -10.791388012849666, + 6.33157041928979 + ], + [ + -10.791399346600114, + 6.331768051563226 + ], + [ + -10.791886697869387, + 6.332269570020544 + ], + [ + -10.792147374129684, + 6.332218568143528 + ], + [ + -10.792306046635945, + 6.332289404083829 + ], + [ + -10.792685727275948, + 6.332373698852782 + ], + [ + -10.792889734784001, + 6.33279871449458 + ], + [ + -10.793204246358947, + 6.333226563573987 + ], + [ + -10.793107909480138, + 6.335605234449236 + ], + [ + -10.79296057072432, + 6.336548060814622 + ], + [ + -10.792903901972071, + 6.3367449847286546 + ], + [ + -10.792405216952368, + 6.337610599919112 + ] + ] + ], + "type": "Polygon" }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "image": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/mon/401175/401175.tif", - "type": "image/tiff; application=geotiff; profile=cloud-optimized", - "title": "GeoTIFF" - } - }, - "collection": "mon" + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "image": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/mon/401175/401175.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "GeoTIFF" + } + }, + "bbox": [ + -10.793204246358947, + 6.330781306914856, + -10.783947405680633, + 6.339080445680323 + ], + "stac_extensions": [], + "collection": "mon" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/mon/493701-labels/493701-labels.json b/tests/data-files/catalogs/test-case-4/mon/493701-labels/493701-labels.json index 18c08dc12..691d1632f 100644 --- a/tests/data-files/catalogs/test-case-4/mon/493701-labels/493701-labels.json +++ b/tests/data-files/catalogs/test-case-4/mon/493701-labels/493701-labels.json @@ -1,201 +1,202 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "493701-labels", - "properties": { - "label:description": "Geojson building labels for scene 493701", - "area": "mon", - "label:type": "vector", - "label:properties": [ - "building" - ], - "label:overviews": [ - { - "property_key": "building", - "counts": [ - { - "name": "yes", - "count": 1719 - } - ] - } - ], - "license": "ODbL-1.0", - "datetime": "2018-08-21T00:00:00Z", - "label:classes": [ - { - "name": "building", - "classes": [ - "yes" - ] - } - ] - }, - "geometry": { - "coordinates": [ - [ - [ - -10.78417140164097, - 6.334404010066445 - ], - [ - -10.783782349974084, - 6.3342425162635685 - ], - [ - -10.783682825442487, - 6.334403211739324 - ], - [ - -10.783654085666106, - 6.334626743333399 - ], - [ - -10.782721639587955, - 6.3339609385139 - ], - [ - -10.782462981600524, - 6.333322276816537 - ], - [ - -10.782076591273617, - 6.332277266614225 - ], - [ - -10.781770033658884, - 6.331613856776092 - ], - [ - -10.78130061731132, - 6.330110606805922 - ], - [ - -10.7812814574604, - 6.329879091940628 - ], - [ - -10.78311760984032, - 6.327981468372338 - ], - [ - -10.783258115413739, - 6.327764323395235 - ], - [ - -10.78415862840702, - 6.326823894045865 - ], - [ - -10.784758970402542, - 6.326574815983895 - ], - [ - -10.785656290087339, - 6.326348091081331 - ], - [ - -10.7863683978799, - 6.326344897772844 - ], - [ - -10.787227397862853, - 6.3266259089196835 - ], - [ - -10.789750111567438, - 6.3274002862277365 - ], - [ - -10.788768561338868, - 6.328341669029932 - ], - [ - -10.788575194406437, - 6.328808135190596 - ], - [ - -10.788669501067371, - 6.329046924492319 - ], - [ - -10.788638065513727, - 6.329432614554341 - ], - [ - -10.788855696269728, - 6.329710698298121 - ], - [ - -10.789325401538692, - 6.330232750855542 - ], - [ - -10.78900607069001, - 6.330509770366774 - ], - [ - -10.788430537721016, - 6.331145533682599 - ], - [ - -10.787152958356145, - 6.332263063398193 - ], - [ - -10.786062605322904, - 6.332942645814849 - ], - [ - -10.785497458219522, - 6.33325268915716 - ], - [ - -10.784928215752343, - 6.333651187590679 - ], - [ - -10.78437777790976, - 6.334071511536476 - ], - [ - -10.78417140164097, - 6.334404010066445 + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "493701-labels", + "properties": { + "label:description": "Geojson building labels for scene 493701", + "area": "mon", + "label:type": "vector", + "label:properties": [ + "building" + ], + "label:overviews": [ + { + "property_key": "building", + "counts": [ + { + "name": "yes", + "count": 1719 + } + ] + } + ], + "license": "ODbL-1.0", + "datetime": "2018-08-21T00:00:00Z", + "label:classes": [ + { + "name": "building", + "classes": [ + "yes" + ] + } ] - ] - ], - "type": "Polygon" - }, - "bbox": [ - -10.789750111567438, - 6.326344897772844, - -10.7812814574604, - 6.334626743333399 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "geometry": { + "coordinates": [ + [ + [ + -10.78417140164097, + 6.334404010066445 + ], + [ + -10.783782349974084, + 6.3342425162635685 + ], + [ + -10.783682825442487, + 6.334403211739324 + ], + [ + -10.783654085666106, + 6.334626743333399 + ], + [ + -10.782721639587955, + 6.3339609385139 + ], + [ + -10.782462981600524, + 6.333322276816537 + ], + [ + -10.782076591273617, + 6.332277266614225 + ], + [ + -10.781770033658884, + 6.331613856776092 + ], + [ + -10.78130061731132, + 6.330110606805922 + ], + [ + -10.7812814574604, + 6.329879091940628 + ], + [ + -10.78311760984032, + 6.327981468372338 + ], + [ + -10.783258115413739, + 6.327764323395235 + ], + [ + -10.78415862840702, + 6.326823894045865 + ], + [ + -10.784758970402542, + 6.326574815983895 + ], + [ + -10.785656290087339, + 6.326348091081331 + ], + [ + -10.7863683978799, + 6.326344897772844 + ], + [ + -10.787227397862853, + 6.3266259089196835 + ], + [ + -10.789750111567438, + 6.3274002862277365 + ], + [ + -10.788768561338868, + 6.328341669029932 + ], + [ + -10.788575194406437, + 6.328808135190596 + ], + [ + -10.788669501067371, + 6.329046924492319 + ], + [ + -10.788638065513727, + 6.329432614554341 + ], + [ + -10.788855696269728, + 6.329710698298121 + ], + [ + -10.789325401538692, + 6.330232750855542 + ], + [ + -10.78900607069001, + 6.330509770366774 + ], + [ + -10.788430537721016, + 6.331145533682599 + ], + [ + -10.787152958356145, + 6.332263063398193 + ], + [ + -10.786062605322904, + 6.332942645814849 + ], + [ + -10.785497458219522, + 6.33325268915716 + ], + [ + -10.784928215752343, + 6.333651187590679 + ], + [ + -10.78437777790976, + 6.334071511536476 + ], + [ + -10.78417140164097, + 6.334404010066445 + ] + ] + ], + "type": "Polygon" + }, + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "labels": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/mon/493701-labels/493701.geojson", + "type": "application/geo+json" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "labels": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/mon/493701-labels/493701.geojson", - "type": "application/geo+json" - } - }, - "stac_extensions": [ - "label" - ] + "bbox": [ + -10.789750111567438, + 6.326344897772844, + -10.7812814574604, + 6.334626743333399 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "mon" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/mon/493701/493701.json b/tests/data-files/catalogs/test-case-4/mon/493701/493701.json index 9ecbfb86f..951db2aab 100644 --- a/tests/data-files/catalogs/test-case-4/mon/493701/493701.json +++ b/tests/data-files/catalogs/test-case-4/mon/493701/493701.json @@ -1,176 +1,177 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "493701", - "properties": { - "area": "mon", - "license": "CC-BY-4.0", - "datetime": "2018-08-21T00:00:00Z" - }, - "geometry": { - "coordinates": [ - [ - [ - -10.78417140164097, - 6.334404010066445 - ], - [ - -10.783782349974084, - 6.3342425162635685 - ], - [ - -10.783682825442487, - 6.334403211739324 - ], - [ - -10.783654085666106, - 6.334626743333399 - ], - [ - -10.782721639587955, - 6.3339609385139 - ], - [ - -10.782462981600524, - 6.333322276816537 - ], - [ - -10.782076591273617, - 6.332277266614225 - ], - [ - -10.781770033658884, - 6.331613856776092 - ], - [ - -10.78130061731132, - 6.330110606805922 - ], - [ - -10.7812814574604, - 6.329879091940628 - ], - [ - -10.78311760984032, - 6.327981468372338 - ], - [ - -10.783258115413739, - 6.327764323395235 - ], - [ - -10.78415862840702, - 6.326823894045865 - ], - [ - -10.784758970402542, - 6.326574815983895 - ], - [ - -10.785656290087339, - 6.326348091081331 - ], - [ - -10.7863683978799, - 6.326344897772844 - ], - [ - -10.787227397862853, - 6.3266259089196835 - ], - [ - -10.789750111567438, - 6.3274002862277365 - ], - [ - -10.788768561338868, - 6.328341669029932 - ], - [ - -10.788575194406437, - 6.328808135190596 - ], - [ - -10.788669501067371, - 6.329046924492319 - ], - [ - -10.788638065513727, - 6.329432614554341 - ], - [ - -10.788855696269728, - 6.329710698298121 - ], - [ - -10.789325401538692, - 6.330232750855542 - ], - [ - -10.78900607069001, - 6.330509770366774 - ], - [ - -10.788430537721016, - 6.331145533682599 - ], - [ - -10.787152958356145, - 6.332263063398193 - ], - [ - -10.786062605322904, - 6.332942645814849 - ], - [ - -10.785497458219522, - 6.33325268915716 - ], - [ - -10.784928215752343, - 6.333651187590679 - ], - [ - -10.78437777790976, - 6.334071511536476 - ], - [ - -10.78417140164097, - 6.334404010066445 - ] - ] - ], - "type": "Polygon" - }, - "bbox": [ - -10.789750111567438, - 6.326344897772844, - -10.7812814574604, - 6.334626743333399 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "493701", + "properties": { + "area": "mon", + "license": "CC-BY-4.0", + "datetime": "2018-08-21T00:00:00Z" + }, + "geometry": { + "coordinates": [ + [ + [ + -10.78417140164097, + 6.334404010066445 + ], + [ + -10.783782349974084, + 6.3342425162635685 + ], + [ + -10.783682825442487, + 6.334403211739324 + ], + [ + -10.783654085666106, + 6.334626743333399 + ], + [ + -10.782721639587955, + 6.3339609385139 + ], + [ + -10.782462981600524, + 6.333322276816537 + ], + [ + -10.782076591273617, + 6.332277266614225 + ], + [ + -10.781770033658884, + 6.331613856776092 + ], + [ + -10.78130061731132, + 6.330110606805922 + ], + [ + -10.7812814574604, + 6.329879091940628 + ], + [ + -10.78311760984032, + 6.327981468372338 + ], + [ + -10.783258115413739, + 6.327764323395235 + ], + [ + -10.78415862840702, + 6.326823894045865 + ], + [ + -10.784758970402542, + 6.326574815983895 + ], + [ + -10.785656290087339, + 6.326348091081331 + ], + [ + -10.7863683978799, + 6.326344897772844 + ], + [ + -10.787227397862853, + 6.3266259089196835 + ], + [ + -10.789750111567438, + 6.3274002862277365 + ], + [ + -10.788768561338868, + 6.328341669029932 + ], + [ + -10.788575194406437, + 6.328808135190596 + ], + [ + -10.788669501067371, + 6.329046924492319 + ], + [ + -10.788638065513727, + 6.329432614554341 + ], + [ + -10.788855696269728, + 6.329710698298121 + ], + [ + -10.789325401538692, + 6.330232750855542 + ], + [ + -10.78900607069001, + 6.330509770366774 + ], + [ + -10.788430537721016, + 6.331145533682599 + ], + [ + -10.787152958356145, + 6.332263063398193 + ], + [ + -10.786062605322904, + 6.332942645814849 + ], + [ + -10.785497458219522, + 6.33325268915716 + ], + [ + -10.784928215752343, + 6.333651187590679 + ], + [ + -10.78437777790976, + 6.334071511536476 + ], + [ + -10.78417140164097, + 6.334404010066445 + ] + ] + ], + "type": "Polygon" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "image": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/mon/493701/493701.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "GeoTIFF" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "image": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/mon/493701/493701.tif", - "type": "image/tiff; application=geotiff; profile=cloud-optimized", - "title": "GeoTIFF" - } - }, - "collection": "mon" + "bbox": [ + -10.789750111567438, + 6.326344897772844, + -10.7812814574604, + 6.334626743333399 + ], + "stac_extensions": [], + "collection": "mon" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/mon/collection.json b/tests/data-files/catalogs/test-case-4/mon/collection.json index 7deab20ab..7cd984ba7 100644 --- a/tests/data-files/catalogs/test-case-4/mon/collection.json +++ b/tests/data-files/catalogs/test-case-4/mon/collection.json @@ -1,6 +1,7 @@ { + "type": "Collection", "id": "mon", - "stac_version": "1.0.0-beta.2", + "stac_version": "1.0.0-rc.3", "description": "Tier 1 training data from mon", "links": [ { @@ -54,6 +55,7 @@ "type": "application/json" } ], + "stac_extensions": [], "extent": { "spatial": { "bbox": [ @@ -74,8 +76,5 @@ ] } }, - "license": "various", - "stac_extensions": [ - "label" - ] + "license": "various" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/mon/f15272-labels/f15272-labels.json b/tests/data-files/catalogs/test-case-4/mon/f15272-labels/f15272-labels.json index 296758970..ac04f9b15 100644 --- a/tests/data-files/catalogs/test-case-4/mon/f15272-labels/f15272-labels.json +++ b/tests/data-files/catalogs/test-case-4/mon/f15272-labels/f15272-labels.json @@ -1,189 +1,190 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "f15272-labels", - "properties": { - "label:description": "Geojson building labels for scene f15272", - "area": "mon", - "label:type": "vector", - "label:properties": [ - "building" - ], - "label:overviews": [ - { - "property_key": "building", - "counts": [ - { - "name": "yes", - "count": 1388 - } - ] - } - ], - "license": "ODbL-1.0", - "datetime": "2018-08-22T00:00:00Z", - "label:classes": [ - { - "name": "building", - "classes": [ - "yes" + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "f15272-labels", + "properties": { + "label:description": "Geojson building labels for scene f15272", + "area": "mon", + "label:type": "vector", + "label:properties": [ + "building" + ], + "label:overviews": [ + { + "property_key": "building", + "counts": [ + { + "name": "yes", + "count": 1388 + } + ] + } + ], + "license": "ODbL-1.0", + "datetime": "2018-08-22T00:00:00Z", + "label:classes": [ + { + "name": "building", + "classes": [ + "yes" + ] + } ] - } - ] - }, - "geometry": { - "coordinates": [ - [ - [ - -10.794428391700563, - 6.326222824390839 - ], - [ - -10.795373361048709, - 6.32561672308313 - ], - [ - -10.79669225375182, - 6.325126964775813 - ], - [ - -10.797218591517776, - 6.324881069526079 - ], - [ - -10.797472615536094, - 6.324816547425426 - ], - [ - -10.79781605600886, - 6.32481451523328 - ], - [ - -10.798600482177429, - 6.32516354423445 - ], - [ - -10.799510904259083, - 6.325520702004206 - ], - [ - -10.8001490125931, - 6.325927140433517 - ], - [ - -10.800346135231315, - 6.326223332438877 - ], - [ - -10.800917181224495, - 6.326974227437026 - ], - [ - -10.801045209329727, - 6.327219614638724 - ], - [ - -10.801037982501601, - 6.327698090884192 - ], - [ - -10.800916330894824, - 6.328479190557416 - ], - [ - -10.800516446405219, - 6.329250955577641 - ], - [ - -10.800423702110942, - 6.329471373835468 - ], - [ - -10.800280370019788, - 6.330338292092678 - ], - [ - -10.799843863013646, - 6.331181449435057 - ], - [ - -10.79954513120753, - 6.331302091125989 - ], - [ - -10.798068706704237, - 6.330587576349347 - ], - [ - -10.798479462937644, - 6.32966265671888 - ], - [ - -10.796845055267655, - 6.328911518571778 - ], - [ - -10.794969521570112, - 6.32923047881336 - ], - [ - -10.79457153985325, - 6.329173326087836 - ], - [ - -10.793669675961551, - 6.328883800628626 - ], - [ - -10.794061962320207, - 6.32729047689175 - ], - [ - -10.794599095840873, - 6.326978799869356 - ], - [ - -10.79484295889846, - 6.326960510140037 - ], - [ - -10.794428391700563, - 6.326222824390839 - ] - ] - ], - "type": "Polygon" - }, - "bbox": [ - -10.801045209329727, - 6.32481451523328, - -10.793669675961551, - 6.331302091125989 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "geometry": { + "coordinates": [ + [ + [ + -10.794428391700563, + 6.326222824390839 + ], + [ + -10.795373361048709, + 6.32561672308313 + ], + [ + -10.79669225375182, + 6.325126964775813 + ], + [ + -10.797218591517776, + 6.324881069526079 + ], + [ + -10.797472615536094, + 6.324816547425426 + ], + [ + -10.79781605600886, + 6.32481451523328 + ], + [ + -10.798600482177429, + 6.32516354423445 + ], + [ + -10.799510904259083, + 6.325520702004206 + ], + [ + -10.8001490125931, + 6.325927140433517 + ], + [ + -10.800346135231315, + 6.326223332438877 + ], + [ + -10.800917181224495, + 6.326974227437026 + ], + [ + -10.801045209329727, + 6.327219614638724 + ], + [ + -10.801037982501601, + 6.327698090884192 + ], + [ + -10.800916330894824, + 6.328479190557416 + ], + [ + -10.800516446405219, + 6.329250955577641 + ], + [ + -10.800423702110942, + 6.329471373835468 + ], + [ + -10.800280370019788, + 6.330338292092678 + ], + [ + -10.799843863013646, + 6.331181449435057 + ], + [ + -10.79954513120753, + 6.331302091125989 + ], + [ + -10.798068706704237, + 6.330587576349347 + ], + [ + -10.798479462937644, + 6.32966265671888 + ], + [ + -10.796845055267655, + 6.328911518571778 + ], + [ + -10.794969521570112, + 6.32923047881336 + ], + [ + -10.79457153985325, + 6.329173326087836 + ], + [ + -10.793669675961551, + 6.328883800628626 + ], + [ + -10.794061962320207, + 6.32729047689175 + ], + [ + -10.794599095840873, + 6.326978799869356 + ], + [ + -10.79484295889846, + 6.326960510140037 + ], + [ + -10.794428391700563, + 6.326222824390839 + ] + ] + ], + "type": "Polygon" }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "labels": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/mon/f15272-labels/f15272.geojson", - "type": "application/geo+json" - } - }, - "stac_extensions": [ - "label" - ] + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "labels": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/mon/f15272-labels/f15272.geojson", + "type": "application/geo+json" + } + }, + "bbox": [ + -10.801045209329727, + 6.32481451523328, + -10.793669675961551, + 6.331302091125989 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "mon" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/mon/f15272/f15272.json b/tests/data-files/catalogs/test-case-4/mon/f15272/f15272.json index 26a03f8b3..1d5f9fbb3 100644 --- a/tests/data-files/catalogs/test-case-4/mon/f15272/f15272.json +++ b/tests/data-files/catalogs/test-case-4/mon/f15272/f15272.json @@ -1,164 +1,165 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "f15272", - "properties": { - "area": "mon", - "license": "CC-BY-4.0", - "datetime": "2018-08-22T00:00:00Z" - }, - "geometry": { - "coordinates": [ - [ - [ - -10.794428391700563, - 6.326222824390839 - ], - [ - -10.795373361048709, - 6.32561672308313 - ], - [ - -10.79669225375182, - 6.325126964775813 - ], - [ - -10.797218591517776, - 6.324881069526079 - ], - [ - -10.797472615536094, - 6.324816547425426 - ], - [ - -10.79781605600886, - 6.32481451523328 - ], - [ - -10.798600482177429, - 6.32516354423445 - ], - [ - -10.799510904259083, - 6.325520702004206 - ], - [ - -10.8001490125931, - 6.325927140433517 - ], - [ - -10.800346135231315, - 6.326223332438877 - ], - [ - -10.800917181224495, - 6.326974227437026 - ], - [ - -10.801045209329727, - 6.327219614638724 - ], - [ - -10.801037982501601, - 6.327698090884192 - ], - [ - -10.800916330894824, - 6.328479190557416 - ], - [ - -10.800516446405219, - 6.329250955577641 - ], - [ - -10.800423702110942, - 6.329471373835468 - ], - [ - -10.800280370019788, - 6.330338292092678 - ], - [ - -10.799843863013646, - 6.331181449435057 - ], - [ - -10.79954513120753, - 6.331302091125989 - ], - [ - -10.798068706704237, - 6.330587576349347 - ], - [ - -10.798479462937644, - 6.32966265671888 - ], - [ - -10.796845055267655, - 6.328911518571778 - ], - [ - -10.794969521570112, - 6.32923047881336 - ], - [ - -10.79457153985325, - 6.329173326087836 - ], - [ - -10.793669675961551, - 6.328883800628626 - ], - [ - -10.794061962320207, - 6.32729047689175 - ], - [ - -10.794599095840873, - 6.326978799869356 - ], - [ - -10.79484295889846, - 6.326960510140037 - ], - [ - -10.794428391700563, - 6.326222824390839 - ] - ] - ], - "type": "Polygon" - }, - "bbox": [ - -10.801045209329727, - 6.32481451523328, - -10.793669675961551, - 6.331302091125989 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "f15272", + "properties": { + "area": "mon", + "license": "CC-BY-4.0", + "datetime": "2018-08-22T00:00:00Z" + }, + "geometry": { + "coordinates": [ + [ + [ + -10.794428391700563, + 6.326222824390839 + ], + [ + -10.795373361048709, + 6.32561672308313 + ], + [ + -10.79669225375182, + 6.325126964775813 + ], + [ + -10.797218591517776, + 6.324881069526079 + ], + [ + -10.797472615536094, + 6.324816547425426 + ], + [ + -10.79781605600886, + 6.32481451523328 + ], + [ + -10.798600482177429, + 6.32516354423445 + ], + [ + -10.799510904259083, + 6.325520702004206 + ], + [ + -10.8001490125931, + 6.325927140433517 + ], + [ + -10.800346135231315, + 6.326223332438877 + ], + [ + -10.800917181224495, + 6.326974227437026 + ], + [ + -10.801045209329727, + 6.327219614638724 + ], + [ + -10.801037982501601, + 6.327698090884192 + ], + [ + -10.800916330894824, + 6.328479190557416 + ], + [ + -10.800516446405219, + 6.329250955577641 + ], + [ + -10.800423702110942, + 6.329471373835468 + ], + [ + -10.800280370019788, + 6.330338292092678 + ], + [ + -10.799843863013646, + 6.331181449435057 + ], + [ + -10.79954513120753, + 6.331302091125989 + ], + [ + -10.798068706704237, + 6.330587576349347 + ], + [ + -10.798479462937644, + 6.32966265671888 + ], + [ + -10.796845055267655, + 6.328911518571778 + ], + [ + -10.794969521570112, + 6.32923047881336 + ], + [ + -10.79457153985325, + 6.329173326087836 + ], + [ + -10.793669675961551, + 6.328883800628626 + ], + [ + -10.794061962320207, + 6.32729047689175 + ], + [ + -10.794599095840873, + 6.326978799869356 + ], + [ + -10.79484295889846, + 6.326960510140037 + ], + [ + -10.794428391700563, + 6.326222824390839 + ] + ] + ], + "type": "Polygon" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "image": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/mon/f15272/f15272.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "GeoTIFF" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "image": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/mon/f15272/f15272.tif", - "type": "image/tiff; application=geotiff; profile=cloud-optimized", - "title": "GeoTIFF" - } - }, - "collection": "mon" + "bbox": [ + -10.801045209329727, + 6.32481451523328, + -10.793669675961551, + 6.331302091125989 + ], + "stac_extensions": [], + "collection": "mon" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/nia/825a50-labels/825a50-labels.json b/tests/data-files/catalogs/test-case-4/nia/825a50-labels/825a50-labels.json index ee58e9008..a14743923 100644 --- a/tests/data-files/catalogs/test-case-4/nia/825a50-labels/825a50-labels.json +++ b/tests/data-files/catalogs/test-case-4/nia/825a50-labels/825a50-labels.json @@ -1,129 +1,130 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "825a50-labels", - "properties": { - "label:description": "Geojson building labels for scene 825a50", - "area": "nia", - "label:type": "vector", - "label:properties": [ - "building" - ], - "label:overviews": [ - { - "property_key": "building", - "counts": [ - { - "name": "yes", - "count": 634 - } - ] - } - ], - "license": "ODbL-1.0", - "datetime": "2017-09-19T00:00:00Z", - "label:classes": [ - { - "name": "building", - "classes": [ - "yes" - ] - } - ] - }, - "geometry": { - "coordinates": [ - [ - [ - 2.000607112710697, - 13.577784497569377 - ], - [ - 2.000938627053272, - 13.57440384053762 - ], - [ - 2.0026898208721526, - 13.572186843360377 - ], - [ - 2.0046604894641256, - 13.570445755015827 - ], - [ - 2.005587501792436, - 13.572743332485638 - ], - [ - 2.004114104714325, - 13.574600773336414 - ], - [ - 2.007048620561563, - 13.576033006956274 - ], - [ - 2.0084759739809837, - 13.579792579072723 + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "825a50-labels", + "properties": { + "label:description": "Geojson building labels for scene 825a50", + "area": "nia", + "label:type": "vector", + "label:properties": [ + "building" ], - [ - 2.0089069498293726, - 13.580816192675927 + "label:overviews": [ + { + "property_key": "building", + "counts": [ + { + "name": "yes", + "count": 634 + } + ] + } ], - [ - 2.007310769661418, - 13.581639705514045 - ], - [ - 2.007598074888608, - 13.58234965082254 - ], - [ - 2.0043965058209636, - 13.583969811536608 - ], - [ - 2.001787365161808, - 13.578048562749643 - ], - [ - 2.000607112710697, - 13.577784497569377 + "license": "ODbL-1.0", + "datetime": "2017-09-19T00:00:00Z", + "label:classes": [ + { + "name": "building", + "classes": [ + "yes" + ] + } ] - ] - ], - "type": "Polygon" - }, - "bbox": [ - 2.000607112710697, - 13.570445755015827, - 2.0089069498293726, - 13.583969811536608 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "geometry": { + "coordinates": [ + [ + [ + 2.000607112710697, + 13.577784497569377 + ], + [ + 2.000938627053272, + 13.57440384053762 + ], + [ + 2.0026898208721526, + 13.572186843360377 + ], + [ + 2.0046604894641256, + 13.570445755015827 + ], + [ + 2.005587501792436, + 13.572743332485638 + ], + [ + 2.004114104714325, + 13.574600773336414 + ], + [ + 2.007048620561563, + 13.576033006956274 + ], + [ + 2.0084759739809837, + 13.579792579072723 + ], + [ + 2.0089069498293726, + 13.580816192675927 + ], + [ + 2.007310769661418, + 13.581639705514045 + ], + [ + 2.007598074888608, + 13.58234965082254 + ], + [ + 2.0043965058209636, + 13.583969811536608 + ], + [ + 2.001787365161808, + 13.578048562749643 + ], + [ + 2.000607112710697, + 13.577784497569377 + ] + ] + ], + "type": "Polygon" + }, + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "labels": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/nia/825a50-labels/825a50.geojson", + "type": "application/geo+json" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "labels": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/nia/825a50-labels/825a50.geojson", - "type": "application/geo+json" - } - }, - "stac_extensions": [ - "label" - ] + "bbox": [ + 2.000607112710697, + 13.570445755015827, + 2.0089069498293726, + 13.583969811536608 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "nia" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/nia/825a50/825a50.json b/tests/data-files/catalogs/test-case-4/nia/825a50/825a50.json index 68f0d6f96..506945f9c 100644 --- a/tests/data-files/catalogs/test-case-4/nia/825a50/825a50.json +++ b/tests/data-files/catalogs/test-case-4/nia/825a50/825a50.json @@ -1,104 +1,105 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "825a50", - "properties": { - "area": "nia", - "license": "CC-BY-4.0", - "datetime": "2017-09-19T00:00:00Z" - }, - "geometry": { - "coordinates": [ - [ - [ - 2.000607112710697, - 13.577784497569377 - ], - [ - 2.000938627053272, - 13.57440384053762 - ], - [ - 2.0026898208721526, - 13.572186843360377 - ], - [ - 2.0046604894641256, - 13.570445755015827 - ], - [ - 2.005587501792436, - 13.572743332485638 - ], - [ - 2.004114104714325, - 13.574600773336414 - ], - [ - 2.007048620561563, - 13.576033006956274 - ], - [ - 2.0084759739809837, - 13.579792579072723 - ], - [ - 2.0089069498293726, - 13.580816192675927 - ], - [ - 2.007310769661418, - 13.581639705514045 - ], - [ - 2.007598074888608, - 13.58234965082254 - ], - [ - 2.0043965058209636, - 13.583969811536608 - ], - [ - 2.001787365161808, - 13.578048562749643 + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "825a50", + "properties": { + "area": "nia", + "license": "CC-BY-4.0", + "datetime": "2017-09-19T00:00:00Z" + }, + "geometry": { + "coordinates": [ + [ + [ + 2.000607112710697, + 13.577784497569377 + ], + [ + 2.000938627053272, + 13.57440384053762 + ], + [ + 2.0026898208721526, + 13.572186843360377 + ], + [ + 2.0046604894641256, + 13.570445755015827 + ], + [ + 2.005587501792436, + 13.572743332485638 + ], + [ + 2.004114104714325, + 13.574600773336414 + ], + [ + 2.007048620561563, + 13.576033006956274 + ], + [ + 2.0084759739809837, + 13.579792579072723 + ], + [ + 2.0089069498293726, + 13.580816192675927 + ], + [ + 2.007310769661418, + 13.581639705514045 + ], + [ + 2.007598074888608, + 13.58234965082254 + ], + [ + 2.0043965058209636, + 13.583969811536608 + ], + [ + 2.001787365161808, + 13.578048562749643 + ], + [ + 2.000607112710697, + 13.577784497569377 + ] + ] ], - [ - 2.000607112710697, - 13.577784497569377 - ] - ] - ], - "type": "Polygon" - }, - "bbox": [ - 2.000607112710697, - 13.570445755015827, - 2.0089069498293726, - 13.583969811536608 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" + "type": "Polygon" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "image": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/nia/825a50/825a50.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "GeoTIFF" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "image": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/nia/825a50/825a50.tif", - "type": "image/tiff; application=geotiff; profile=cloud-optimized", - "title": "GeoTIFF" - } - }, - "collection": "nia" + "bbox": [ + 2.000607112710697, + 13.570445755015827, + 2.0089069498293726, + 13.583969811536608 + ], + "stac_extensions": [], + "collection": "nia" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/nia/collection.json b/tests/data-files/catalogs/test-case-4/nia/collection.json index 19cc515b0..7a3f0cc48 100644 --- a/tests/data-files/catalogs/test-case-4/nia/collection.json +++ b/tests/data-files/catalogs/test-case-4/nia/collection.json @@ -1,6 +1,7 @@ { + "type": "Collection", "id": "nia", - "stac_version": "1.0.0-beta.2", + "stac_version": "1.0.0-rc.3", "description": "Tier 1 training data from nia", "links": [ { @@ -24,6 +25,7 @@ "type": "application/json" } ], + "stac_extensions": [], "extent": { "spatial": { "bbox": [ @@ -44,8 +46,5 @@ ] } }, - "license": "various", - "stac_extensions": [ - "label" - ] + "license": "various" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/ptn/abe1a3-labels/abe1a3-labels.json b/tests/data-files/catalogs/test-case-4/ptn/abe1a3-labels/abe1a3-labels.json index 7503c9325..3896ab604 100644 --- a/tests/data-files/catalogs/test-case-4/ptn/abe1a3-labels/abe1a3-labels.json +++ b/tests/data-files/catalogs/test-case-4/ptn/abe1a3-labels/abe1a3-labels.json @@ -1,165 +1,166 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "abe1a3-labels", - "properties": { - "label:description": "Geojson building labels for scene abe1a3", - "area": "ptn", - "label:type": "vector", - "label:properties": [ - "building" - ], - "label:overviews": [ - { - "property_key": "building", - "counts": [ - { - "name": "yes", - "count": 6135 - } - ] - } - ], - "license": "ODbL-1.0", - "datetime": "2019-01-04T00:00:00Z", - "label:classes": [ - { - "name": "building", - "classes": [ - "yes" + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "abe1a3-labels", + "properties": { + "label:description": "Geojson building labels for scene abe1a3", + "area": "ptn", + "label:type": "vector", + "label:properties": [ + "building" + ], + "label:overviews": [ + { + "property_key": "building", + "counts": [ + { + "name": "yes", + "count": 6135 + } + ] + } + ], + "license": "ODbL-1.0", + "datetime": "2019-01-04T00:00:00Z", + "label:classes": [ + { + "name": "building", + "classes": [ + "yes" + ] + } ] - } - ] - }, - "geometry": { - "coordinates": [ - [ - [ - 11.885812792703362, - -4.768169362911695 - ], - [ - 11.887542976197118, - -4.7665107950056145 - ], - [ - 11.889180125287497, - -4.768291240422982 - ], - [ - 11.889699192128468, - -4.76889842830112 - ], - [ - 11.891293402748685, - -4.770574825339869 - ], - [ - 11.891822637745463, - -4.771199743826555 - ], - [ - 11.892485554938661, - -4.772038920080106 - ], - [ - 11.893232710228231, - -4.773116160519051 - ], - [ - 11.894047213717943, - -4.774217893668799 - ], - [ - 11.893651788278861, - -4.774975492862306 - ], - [ - 11.891492150063526, - -4.775882417747232 - ], - [ - 11.892229753203969, - -4.776764206607942 - ], - [ - 11.89160985269232, - -4.777368413435742 - ], - [ - 11.889106144363504, - -4.779159021273276 - ], - [ - 11.88601220532287, - -4.780589144725401 - ], - [ - 11.884413418672295, - -4.77899238585692 - ], - [ - 11.882857386891155, - -4.777623866347985 - ], - [ - 11.881942666093218, - -4.776764898160677 - ], - [ - 11.88116779930158, - -4.7758010394686305 - ], - [ - 11.881077083189387, - -4.775321000041606 - ], - [ - 11.879921982584099, - -4.773801879823182 - ], - [ - 11.880932380701283, - -4.772793177004842 - ], - [ - 11.885812792703362, - -4.768169362911695 - ] - ] - ], - "type": "Polygon" - }, - "bbox": [ - 11.879921982584099, - -4.780589144725401, - 11.894047213717943, - -4.7665107950056145 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "geometry": { + "coordinates": [ + [ + [ + 11.885812792703362, + -4.768169362911695 + ], + [ + 11.887542976197118, + -4.7665107950056145 + ], + [ + 11.889180125287497, + -4.768291240422982 + ], + [ + 11.889699192128468, + -4.76889842830112 + ], + [ + 11.891293402748685, + -4.770574825339869 + ], + [ + 11.891822637745463, + -4.771199743826555 + ], + [ + 11.892485554938661, + -4.772038920080106 + ], + [ + 11.893232710228231, + -4.773116160519051 + ], + [ + 11.894047213717943, + -4.774217893668799 + ], + [ + 11.893651788278861, + -4.774975492862306 + ], + [ + 11.891492150063526, + -4.775882417747232 + ], + [ + 11.892229753203969, + -4.776764206607942 + ], + [ + 11.89160985269232, + -4.777368413435742 + ], + [ + 11.889106144363504, + -4.779159021273276 + ], + [ + 11.88601220532287, + -4.780589144725401 + ], + [ + 11.884413418672295, + -4.77899238585692 + ], + [ + 11.882857386891155, + -4.777623866347985 + ], + [ + 11.881942666093218, + -4.776764898160677 + ], + [ + 11.88116779930158, + -4.7758010394686305 + ], + [ + 11.881077083189387, + -4.775321000041606 + ], + [ + 11.879921982584099, + -4.773801879823182 + ], + [ + 11.880932380701283, + -4.772793177004842 + ], + [ + 11.885812792703362, + -4.768169362911695 + ] + ] + ], + "type": "Polygon" }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "labels": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/ptn/abe1a3-labels/abe1a3.geojson", - "type": "application/geo+json" - } - }, - "stac_extensions": [ - "label" - ] + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "labels": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/ptn/abe1a3-labels/abe1a3.geojson", + "type": "application/geo+json" + } + }, + "bbox": [ + 11.879921982584099, + -4.780589144725401, + 11.894047213717943, + -4.7665107950056145 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "ptn" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/ptn/abe1a3/abe1a3.json b/tests/data-files/catalogs/test-case-4/ptn/abe1a3/abe1a3.json index eb0be417d..b8deb4c6a 100644 --- a/tests/data-files/catalogs/test-case-4/ptn/abe1a3/abe1a3.json +++ b/tests/data-files/catalogs/test-case-4/ptn/abe1a3/abe1a3.json @@ -1,140 +1,141 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "abe1a3", - "properties": { - "area": "ptn", - "license": "CC-BY-4.0", - "datetime": "2019-01-04T00:00:00Z" - }, - "geometry": { - "coordinates": [ - [ - [ - 11.885812792703362, - -4.768169362911695 - ], - [ - 11.887542976197118, - -4.7665107950056145 - ], - [ - 11.889180125287497, - -4.768291240422982 - ], - [ - 11.889699192128468, - -4.76889842830112 - ], - [ - 11.891293402748685, - -4.770574825339869 - ], - [ - 11.891822637745463, - -4.771199743826555 - ], - [ - 11.892485554938661, - -4.772038920080106 - ], - [ - 11.893232710228231, - -4.773116160519051 - ], - [ - 11.894047213717943, - -4.774217893668799 - ], - [ - 11.893651788278861, - -4.774975492862306 - ], - [ - 11.891492150063526, - -4.775882417747232 - ], - [ - 11.892229753203969, - -4.776764206607942 - ], - [ - 11.89160985269232, - -4.777368413435742 - ], - [ - 11.889106144363504, - -4.779159021273276 - ], - [ - 11.88601220532287, - -4.780589144725401 - ], - [ - 11.884413418672295, - -4.77899238585692 - ], - [ - 11.882857386891155, - -4.777623866347985 - ], - [ - 11.881942666093218, - -4.776764898160677 - ], - [ - 11.88116779930158, - -4.7758010394686305 - ], - [ - 11.881077083189387, - -4.775321000041606 - ], - [ - 11.879921982584099, - -4.773801879823182 - ], - [ - 11.880932380701283, - -4.772793177004842 - ], - [ - 11.885812792703362, - -4.768169362911695 - ] - ] - ], - "type": "Polygon" - }, - "bbox": [ - 11.879921982584099, - -4.780589144725401, - 11.894047213717943, - -4.7665107950056145 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "abe1a3", + "properties": { + "area": "ptn", + "license": "CC-BY-4.0", + "datetime": "2019-01-04T00:00:00Z" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "geometry": { + "coordinates": [ + [ + [ + 11.885812792703362, + -4.768169362911695 + ], + [ + 11.887542976197118, + -4.7665107950056145 + ], + [ + 11.889180125287497, + -4.768291240422982 + ], + [ + 11.889699192128468, + -4.76889842830112 + ], + [ + 11.891293402748685, + -4.770574825339869 + ], + [ + 11.891822637745463, + -4.771199743826555 + ], + [ + 11.892485554938661, + -4.772038920080106 + ], + [ + 11.893232710228231, + -4.773116160519051 + ], + [ + 11.894047213717943, + -4.774217893668799 + ], + [ + 11.893651788278861, + -4.774975492862306 + ], + [ + 11.891492150063526, + -4.775882417747232 + ], + [ + 11.892229753203969, + -4.776764206607942 + ], + [ + 11.89160985269232, + -4.777368413435742 + ], + [ + 11.889106144363504, + -4.779159021273276 + ], + [ + 11.88601220532287, + -4.780589144725401 + ], + [ + 11.884413418672295, + -4.77899238585692 + ], + [ + 11.882857386891155, + -4.777623866347985 + ], + [ + 11.881942666093218, + -4.776764898160677 + ], + [ + 11.88116779930158, + -4.7758010394686305 + ], + [ + 11.881077083189387, + -4.775321000041606 + ], + [ + 11.879921982584099, + -4.773801879823182 + ], + [ + 11.880932380701283, + -4.772793177004842 + ], + [ + 11.885812792703362, + -4.768169362911695 + ] + ] + ], + "type": "Polygon" }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "image": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/ptn/abe1a3/abe1a3.tif", - "type": "image/tiff; application=geotiff; profile=cloud-optimized", - "title": "GeoTIFF" - } - }, - "collection": "ptn" + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "image": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/ptn/abe1a3/abe1a3.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "GeoTIFF" + } + }, + "bbox": [ + 11.879921982584099, + -4.780589144725401, + 11.894047213717943, + -4.7665107950056145 + ], + "stac_extensions": [], + "collection": "ptn" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/ptn/collection.json b/tests/data-files/catalogs/test-case-4/ptn/collection.json index e09ddd6f0..9f537d14a 100644 --- a/tests/data-files/catalogs/test-case-4/ptn/collection.json +++ b/tests/data-files/catalogs/test-case-4/ptn/collection.json @@ -1,6 +1,7 @@ { + "type": "Collection", "id": "ptn", - "stac_version": "1.0.0-beta.2", + "stac_version": "1.0.0-rc.3", "description": "Tier 1 training data from ptn", "links": [ { @@ -34,6 +35,7 @@ "type": "application/json" } ], + "stac_extensions": [], "extent": { "spatial": { "bbox": [ @@ -54,8 +56,5 @@ ] } }, - "license": "various", - "stac_extensions": [ - "label" - ] + "license": "various" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/ptn/f49f31-labels/f49f31-labels.json b/tests/data-files/catalogs/test-case-4/ptn/f49f31-labels/f49f31-labels.json index 53b77823f..b29df6e49 100644 --- a/tests/data-files/catalogs/test-case-4/ptn/f49f31-labels/f49f31-labels.json +++ b/tests/data-files/catalogs/test-case-4/ptn/f49f31-labels/f49f31-labels.json @@ -1,121 +1,122 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "f49f31-labels", - "properties": { - "label:description": "Geojson building labels for scene f49f31", - "area": "ptn", - "label:type": "vector", - "label:properties": [ - "building" - ], - "label:overviews": [ - { - "property_key": "building", - "counts": [ - { - "name": "yes", - "count": 2596 - } - ] - } - ], - "license": "ODbL-1.0", - "datetime": "2019-01-04T00:00:00Z", - "label:classes": [ - { - "name": "building", - "classes": [ - "yes" - ] - } - ] - }, - "geometry": { - "coordinates": [ - [ - [ - 11.8872283746714, - -4.797808782187126 - ], - [ - 11.88972534766154, - -4.798264503493327 - ], - [ - 11.891605198049556, - -4.798340457044355 - ], - [ - 11.8955075180291, - -4.802072082202417 - ], - [ - 11.897849273966862, - -4.804253455211011 - ], - [ - 11.897268627830597, - -4.804913066085889 - ], - [ - 11.89685404132025, - -4.805243717903951 + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "f49f31-labels", + "properties": { + "label:description": "Geojson building labels for scene f49f31", + "area": "ptn", + "label:type": "vector", + "label:properties": [ + "building" ], - [ - 11.891979599532954, - -4.803719848444295 + "label:overviews": [ + { + "property_key": "building", + "counts": [ + { + "name": "yes", + "count": 2596 + } + ] + } ], - [ - 11.885939170933694, - -4.801674355838536 - ], - [ - 11.886296262431463, - -4.800109049407727 - ], - [ - 11.886753664977459, - -4.797722543259397 - ], - [ - 11.8872283746714, - -4.797808782187126 + "license": "ODbL-1.0", + "datetime": "2019-01-04T00:00:00Z", + "label:classes": [ + { + "name": "building", + "classes": [ + "yes" + ] + } ] - ] - ], - "type": "Polygon" - }, - "bbox": [ - 11.885939170933694, - -4.805243717903951, - 11.897849273966862, - -4.797722543259397 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "geometry": { + "coordinates": [ + [ + [ + 11.8872283746714, + -4.797808782187126 + ], + [ + 11.88972534766154, + -4.798264503493327 + ], + [ + 11.891605198049556, + -4.798340457044355 + ], + [ + 11.8955075180291, + -4.802072082202417 + ], + [ + 11.897849273966862, + -4.804253455211011 + ], + [ + 11.897268627830597, + -4.804913066085889 + ], + [ + 11.89685404132025, + -4.805243717903951 + ], + [ + 11.891979599532954, + -4.803719848444295 + ], + [ + 11.885939170933694, + -4.801674355838536 + ], + [ + 11.886296262431463, + -4.800109049407727 + ], + [ + 11.886753664977459, + -4.797722543259397 + ], + [ + 11.8872283746714, + -4.797808782187126 + ] + ] + ], + "type": "Polygon" }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "labels": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/ptn/f49f31-labels/f49f31.geojson", - "type": "application/geo+json" - } - }, - "stac_extensions": [ - "label" - ] + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "labels": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/ptn/f49f31-labels/f49f31.geojson", + "type": "application/geo+json" + } + }, + "bbox": [ + 11.885939170933694, + -4.805243717903951, + 11.897849273966862, + -4.797722543259397 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "ptn" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/ptn/f49f31/f49f31.json b/tests/data-files/catalogs/test-case-4/ptn/f49f31/f49f31.json index 82ca1c2df..777c31a96 100644 --- a/tests/data-files/catalogs/test-case-4/ptn/f49f31/f49f31.json +++ b/tests/data-files/catalogs/test-case-4/ptn/f49f31/f49f31.json @@ -1,96 +1,97 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "f49f31", - "properties": { - "area": "ptn", - "license": "CC-BY-4.0", - "datetime": "2019-01-04T00:00:00Z" - }, - "geometry": { - "coordinates": [ - [ - [ - 11.8872283746714, - -4.797808782187126 - ], - [ - 11.88972534766154, - -4.798264503493327 - ], - [ - 11.891605198049556, - -4.798340457044355 - ], - [ - 11.8955075180291, - -4.802072082202417 - ], - [ - 11.897849273966862, - -4.804253455211011 - ], - [ - 11.897268627830597, - -4.804913066085889 - ], - [ - 11.89685404132025, - -4.805243717903951 - ], - [ - 11.891979599532954, - -4.803719848444295 - ], - [ - 11.885939170933694, - -4.801674355838536 - ], - [ - 11.886296262431463, - -4.800109049407727 - ], - [ - 11.886753664977459, - -4.797722543259397 + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "f49f31", + "properties": { + "area": "ptn", + "license": "CC-BY-4.0", + "datetime": "2019-01-04T00:00:00Z" + }, + "geometry": { + "coordinates": [ + [ + [ + 11.8872283746714, + -4.797808782187126 + ], + [ + 11.88972534766154, + -4.798264503493327 + ], + [ + 11.891605198049556, + -4.798340457044355 + ], + [ + 11.8955075180291, + -4.802072082202417 + ], + [ + 11.897849273966862, + -4.804253455211011 + ], + [ + 11.897268627830597, + -4.804913066085889 + ], + [ + 11.89685404132025, + -4.805243717903951 + ], + [ + 11.891979599532954, + -4.803719848444295 + ], + [ + 11.885939170933694, + -4.801674355838536 + ], + [ + 11.886296262431463, + -4.800109049407727 + ], + [ + 11.886753664977459, + -4.797722543259397 + ], + [ + 11.8872283746714, + -4.797808782187126 + ] + ] ], - [ - 11.8872283746714, - -4.797808782187126 - ] - ] - ], - "type": "Polygon" - }, - "bbox": [ - 11.885939170933694, - -4.805243717903951, - 11.897849273966862, - -4.797722543259397 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" + "type": "Polygon" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "image": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/ptn/f49f31/f49f31.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "GeoTIFF" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "image": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/ptn/f49f31/f49f31.tif", - "type": "image/tiff; application=geotiff; profile=cloud-optimized", - "title": "GeoTIFF" - } - }, - "collection": "ptn" + "bbox": [ + 11.885939170933694, + -4.805243717903951, + 11.897849273966862, + -4.797722543259397 + ], + "stac_extensions": [], + "collection": "ptn" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/znz/06f252-labels/06f252-labels.json b/tests/data-files/catalogs/test-case-4/znz/06f252-labels/06f252-labels.json index 2c5d38a35..2c8ea9eef 100644 --- a/tests/data-files/catalogs/test-case-4/znz/06f252-labels/06f252-labels.json +++ b/tests/data-files/catalogs/test-case-4/znz/06f252-labels/06f252-labels.json @@ -1,96 +1,97 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "06f252-labels", - "properties": { - "label:description": "Geojson building labels for scene 06f252", - "area": "znz", - "label:type": "vector", - "label:properties": [ - "building" - ], - "label:overviews": [ - { - "property_key": "building", - "counts": [ - { - "name": "yes", - "count": 1181 - } - ] - } - ], - "datetime": "2016-09-21T00:00:00Z", - "label:classes": [ - { - "name": "building", - "classes": [ - "yes" - ] - } - ] - }, - "geometry": { - "coordinates": [ - [ - [ - 39.316367972905894, - -5.905850055917426 - ], - [ - 39.31369474037646, - -5.905851570308218 - ], - [ - 39.31367952293228, - -5.878740108331854 - ], - [ - 39.34078047573221, - -5.878724233277496 + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "06f252-labels", + "properties": { + "label:description": "Geojson building labels for scene 06f252", + "area": "znz", + "label:type": "vector", + "label:properties": [ + "building" ], - [ - 39.340797007857546, - -5.905835621542266 + "label:overviews": [ + { + "property_key": "building", + "counts": [ + { + "name": "yes", + "count": 1181 + } + ] + } ], - [ - 39.316367972905894, - -5.905850055917426 + "datetime": "2016-09-21T00:00:00Z", + "label:classes": [ + { + "name": "building", + "classes": [ + "yes" + ] + } ] - ] - ], - "type": "Polygon" - }, - "bbox": [ - 39.31367952293228, - -5.905851570308218, - 39.340797007857546, - -5.878724233277496 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "geometry": { + "coordinates": [ + [ + [ + 39.316367972905894, + -5.905850055917426 + ], + [ + 39.31369474037646, + -5.905851570308218 + ], + [ + 39.31367952293228, + -5.878740108331854 + ], + [ + 39.34078047573221, + -5.878724233277496 + ], + [ + 39.340797007857546, + -5.905835621542266 + ], + [ + 39.316367972905894, + -5.905850055917426 + ] + ] + ], + "type": "Polygon" + }, + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "labels": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/06f252-labels/06f252.geojson", + "type": "application/geo+json" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "labels": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/06f252-labels/06f252.geojson", - "type": "application/geo+json" - } - }, - "stac_extensions": [ - "label" - ] + "bbox": [ + 39.31367952293228, + -5.905851570308218, + 39.340797007857546, + -5.878724233277496 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "znz" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/znz/06f252/06f252.json b/tests/data-files/catalogs/test-case-4/znz/06f252/06f252.json index d897564a1..0650d7bec 100644 --- a/tests/data-files/catalogs/test-case-4/znz/06f252/06f252.json +++ b/tests/data-files/catalogs/test-case-4/znz/06f252/06f252.json @@ -1,71 +1,72 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "06f252", - "properties": { - "area": "znz", - "datetime": "2016-09-21T00:00:00Z" - }, - "geometry": { - "coordinates": [ - [ - [ - 39.316367972905894, - -5.905850055917426 - ], - [ - 39.31369474037646, - -5.905851570308218 - ], - [ - 39.31367952293228, - -5.878740108331854 - ], - [ - 39.34078047573221, - -5.878724233277496 - ], - [ - 39.340797007857546, - -5.905835621542266 + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "06f252", + "properties": { + "area": "znz", + "datetime": "2016-09-21T00:00:00Z" + }, + "geometry": { + "coordinates": [ + [ + [ + 39.316367972905894, + -5.905850055917426 + ], + [ + 39.31369474037646, + -5.905851570308218 + ], + [ + 39.31367952293228, + -5.878740108331854 + ], + [ + 39.34078047573221, + -5.878724233277496 + ], + [ + 39.340797007857546, + -5.905835621542266 + ], + [ + 39.316367972905894, + -5.905850055917426 + ] + ] ], - [ - 39.316367972905894, - -5.905850055917426 - ] - ] - ], - "type": "Polygon" - }, - "bbox": [ - 39.31367952293228, - -5.905851570308218, - 39.340797007857546, - -5.878724233277496 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" + "type": "Polygon" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "image": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/06f252/06f252.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "GeoTIFF" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "image": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/06f252/06f252.tif", - "type": "image/tiff; application=geotiff; profile=cloud-optimized", - "title": "GeoTIFF" - } - }, - "collection": "znz" + "bbox": [ + 39.31367952293228, + -5.905851570308218, + 39.340797007857546, + -5.878724233277496 + ], + "stac_extensions": [], + "collection": "znz" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/znz/076995-labels/076995-labels.json b/tests/data-files/catalogs/test-case-4/znz/076995-labels/076995-labels.json index 06b9a91de..366e5f7f0 100644 --- a/tests/data-files/catalogs/test-case-4/znz/076995-labels/076995-labels.json +++ b/tests/data-files/catalogs/test-case-4/znz/076995-labels/076995-labels.json @@ -1,108 +1,109 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "076995-labels", - "properties": { - "label:description": "Geojson building labels for scene 076995", - "area": "znz", - "label:type": "vector", - "label:properties": [ - "building" - ], - "label:overviews": [ - { - "property_key": "building", - "counts": [ - { - "name": "yes", - "count": 843 - } - ] - } - ], - "datetime": "2016-10-04T00:00:00Z", - "label:classes": [ - { - "name": "building", - "classes": [ - "yes" - ] - } - ] - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [ - 39.3407474698636, - -5.824437937045834 - ], - [ - 39.36248225709067, - -5.824427688553141 - ], - [ - 39.3625604145535, - -5.824877893423849 - ], - [ - 39.36300752853781, - -5.828561459551643 - ], - [ - 39.36335786823858, - -5.832067348597373 + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "076995-labels", + "properties": { + "label:description": "Geojson building labels for scene 076995", + "area": "znz", + "label:type": "vector", + "label:properties": [ + "building" ], - [ - 39.3631508602256, - -5.849635373302928 + "label:overviews": [ + { + "property_key": "building", + "counts": [ + { + "name": "yes", + "count": 843 + } + ] + } ], - [ - 39.362683761021664, - -5.851560567141806 - ], - [ - 39.34075687849739, - -5.851573055804989 - ], - [ - 39.3407474698636, - -5.824437937045834 + "datetime": "2016-10-04T00:00:00Z", + "label:classes": [ + { + "name": "building", + "classes": [ + "yes" + ] + } ] - ] - ] - }, - "bbox": [ - 39.34073844240503, - -5.851576358919395, - 39.36335800442592, - -5.824424385662977 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + 39.3407474698636, + -5.824437937045834 + ], + [ + 39.36248225709067, + -5.824427688553141 + ], + [ + 39.3625604145535, + -5.824877893423849 + ], + [ + 39.36300752853781, + -5.828561459551643 + ], + [ + 39.36335786823858, + -5.832067348597373 + ], + [ + 39.3631508602256, + -5.849635373302928 + ], + [ + 39.362683761021664, + -5.851560567141806 + ], + [ + 39.34075687849739, + -5.851573055804989 + ], + [ + 39.3407474698636, + -5.824437937045834 + ] + ] + ] }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "labels": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/076995-labels/076995.geojson", - "type": "application/geo+json" - } - }, - "stac_extensions": [ - "label" - ] + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "labels": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/076995-labels/076995.geojson", + "type": "application/geo+json" + } + }, + "bbox": [ + 39.34073844240503, + -5.851576358919395, + 39.36335800442592, + -5.824424385662977 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "znz" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/znz/076995/076995.json b/tests/data-files/catalogs/test-case-4/znz/076995/076995.json index 987303e83..b411ef394 100644 --- a/tests/data-files/catalogs/test-case-4/znz/076995/076995.json +++ b/tests/data-files/catalogs/test-case-4/znz/076995/076995.json @@ -1,83 +1,84 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "076995", - "properties": { - "area": "znz", - "datetime": "2016-10-04T00:00:00Z" - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [ - 39.3407474698636, - -5.824437937045834 - ], - [ - 39.36248225709067, - -5.824427688553141 - ], - [ - 39.3625604145535, - -5.824877893423849 - ], - [ - 39.36300752853781, - -5.828561459551643 - ], - [ - 39.36335786823858, - -5.832067348597373 - ], - [ - 39.3631508602256, - -5.849635373302928 - ], - [ - 39.362683761021664, - -5.851560567141806 - ], - [ - 39.34075687849739, - -5.851573055804989 - ], - [ - 39.3407474698636, - -5.824437937045834 + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "076995", + "properties": { + "area": "znz", + "datetime": "2016-10-04T00:00:00Z" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + 39.3407474698636, + -5.824437937045834 + ], + [ + 39.36248225709067, + -5.824427688553141 + ], + [ + 39.3625604145535, + -5.824877893423849 + ], + [ + 39.36300752853781, + -5.828561459551643 + ], + [ + 39.36335786823858, + -5.832067348597373 + ], + [ + 39.3631508602256, + -5.849635373302928 + ], + [ + 39.362683761021664, + -5.851560567141806 + ], + [ + 39.34075687849739, + -5.851573055804989 + ], + [ + 39.3407474698636, + -5.824437937045834 + ] + ] ] - ] - ] - }, - "bbox": [ - 39.34073844240503, - -5.851576358919395, - 39.36335800442592, - -5.824424385662977 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "image": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/076995/076995.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "GeoTIFF" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "image": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/076995/076995.tif", - "type": "image/tiff; application=geotiff; profile=cloud-optimized", - "title": "GeoTIFF" - } - }, - "collection": "znz" + "bbox": [ + 39.34073844240503, + -5.851576358919395, + 39.36335800442592, + -5.824424385662977 + ], + "stac_extensions": [], + "collection": "znz" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/znz/33cae6-labels/33cae6-labels.json b/tests/data-files/catalogs/test-case-4/znz/33cae6-labels/33cae6-labels.json index c466c3505..c7e40d47f 100644 --- a/tests/data-files/catalogs/test-case-4/znz/33cae6-labels/33cae6-labels.json +++ b/tests/data-files/catalogs/test-case-4/znz/33cae6-labels/33cae6-labels.json @@ -1,1164 +1,1165 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "33cae6-labels", - "properties": { - "label:description": "Geojson building labels for scene 33cae6", - "area": "znz", - "label:type": "vector", - "label:properties": [ - "building" - ], - "label:overviews": [ - { - "property_key": "building", - "counts": [ - { - "name": "yes", - "count": 4439 - } - ] - } - ], - "datetime": "2016-08-28T00:00:00Z", - "label:classes": [ - { - "name": "building", - "classes": [ - "yes" + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "33cae6-labels", + "properties": { + "label:description": "Geojson building labels for scene 33cae6", + "area": "znz", + "label:type": "vector", + "label:properties": [ + "building" + ], + "label:overviews": [ + { + "property_key": "building", + "counts": [ + { + "name": "yes", + "count": 4439 + } + ] + } + ], + "datetime": "2016-08-28T00:00:00Z", + "label:classes": [ + { + "name": "building", + "classes": [ + "yes" + ] + } ] - } - ] - }, - "geometry": { - "coordinates": [ - [ - [ - 39.313602918515315, - -5.740028584511519 - ], - [ - 39.31360456846548, - -5.743046680921876 - ], - [ - 39.28771158148321, - -5.743060299502631 - ], - [ - 39.287833992413255, - -5.7415673066017945 - ], - [ - 39.28784518594579, - -5.741561693713168 - ], - [ - 39.287867395743724, - -5.741197211035715 - ], - [ - 39.28787859137919, - -5.741195803586043 - ], - [ - 39.28788965898581, - -5.740939266150898 - ], - [ - 39.28789736103782, - -5.740948374060875 - ], - [ - 39.28794532863633, - -5.740317533846062 - ], - [ - 39.287956518978035, - -5.740305612797183 - ], - [ - 39.28795645988263, - -5.740187860493621 - ], - [ - 39.28796695643181, - -5.7401878552086325 - ], - [ - 39.287978729048056, - -5.739941831012015 - ], - [ - 39.28799062442844, - -5.739940423208991 - ], - [ - 39.28801212626218, - -5.739559820014053 - ], - [ - 39.288023319754615, - -5.739554207123601 - ], - [ - 39.28805666134313, - -5.7390614528792385 - ], - [ - 39.28806785412197, - -5.739054438175143 - ], - [ - 39.288068492322395, - -5.7389317791690555 - ], - [ - 39.28807898849667, - -5.7389310729765715 - ], - [ - 39.288078926927646, - -5.738808414322463 - ], - [ - 39.28809012040507, - -5.738802801431323 - ], - [ - 39.288123461924656, - -5.73831004717524 - ], - [ - 39.28813465468841, - -5.738303032470432 - ], - [ - 39.28813459311428, - -5.73818037381424 - ], - [ - 39.288145786579165, - -5.738174760922529 - ], - [ - 39.28817912804129, - -5.737682006656658 - ], - [ - 39.28819032114434, - -5.737675692857872 - ], - [ - 39.28819025921321, - -5.737552333292979 - ], - [ - 39.28820145548069, - -5.737552327653656 - ], - [ - 39.28825705989423, - -5.736801628458127 - ], - [ - 39.28826825297967, - -5.736795314658528 - ], - [ - 39.28826819420862, - -5.736678263250428 - ], - [ - 39.288279389755104, - -5.736676855797169 - ], - [ - 39.28829046247506, - -5.736430831926878 - ], - [ - 39.288301655905016, - -5.736425219033569 - ], - [ - 39.28831272544848, - -5.736172887001599 - ], - [ - 39.28832392168893, - -5.736172881361234 - ], - [ - 39.28832386009737, - -5.736050222697981 - ], - [ - 39.28833505316777, - -5.736043908897686 - ], - [ - 39.28833569380363, - -5.735926156228032 - ], - [ - 39.28833849849387, - -5.735937369324319 - ], - [ - 39.28834688968728, - -5.735925449680809 - ], - [ - 39.288368397250515, - -5.735556761851868 - ], - [ - 39.28837959277493, - -5.7355553543976985 - ], - [ - 39.28843519161201, - -5.734794141554009 - ], - [ - 39.288446387121425, - -5.734792734099254 - ], - [ - 39.28844632551862, - -5.734670075431432 - ], - [ - 39.28845752137762, - -5.73466936888325 - ], - [ - 39.288468594025474, - -5.734423344998106 - ], - [ - 39.28847978741536, - -5.734417732102973 - ], - [ - 39.288490857237925, - -5.734166100962491 - ], - [ - 39.28850205273499, - -5.734164693507241 - ], - [ - 39.28855765700006, - -5.733414695136926 - ], - [ - 39.28856885248234, - -5.733413287681076 - ], - [ - 39.28856879122039, - -5.733291329915387 - ], - [ - 39.288579986700235, - -5.733289922459435 - ], - [ - 39.288579925085166, - -5.7331672637866395 - ], - [ - 39.288586228570765, - -5.733178475119921 - ], - [ - 39.288591061058995, - -5.733047403097616 - ], - [ - 39.28860225301303, - -5.733038986574412 - ], - [ - 39.28861332243345, - -5.732786654516813 - ], - [ - 39.28862451790337, - -5.732785247060469 - ], - [ - 39.28862445663636, - -5.732663289292712 - ], - [ - 39.288635652103856, - -5.732661881836264 - ], - [ - 39.28863629024428, - -5.7325392228087 - ], - [ - 39.28865791802952, - -5.732410245039324 - ], - [ - 39.28866898742718, - -5.732157912976972 - ], - [ - 39.28868018358902, - -5.7321579073335736 - ], - [ - 39.28868012196481, - -5.732035248657027 - ], - [ - 39.28869131495492, - -5.732028934853017 - ], - [ - 39.2886912557947, - -5.731911182523131 - ], - [ - 39.28870315135938, - -5.731910475620081 - ], - [ - 39.288802586506456, - -5.730655802114353 - ], - [ - 39.28881378193448, - -5.730654394656317 - ], - [ - 39.28881372029802, - -5.730531735974798 - ], - [ - 39.28882002375656, - -5.73054294730776 - ], - [ - 39.28883599174512, - -5.730291313668497 - ], - [ - 39.288847182939215, - -5.730281495329069 - ], - [ - 39.288847117073004, - -5.730150425765198 - ], - [ - 39.28885831319556, - -5.73015042012029 - ], - [ - 39.28885825155506, - -5.730027761437102 - ], - [ - 39.28886944450505, - -5.730021447631236 - ], - [ - 39.28886938709037, - -5.7299071998288 - ], - [ - 39.28888058109469, - -5.729902988743108 - ], - [ - 39.288880523326746, - -5.729788040033545 - ], - [ - 39.28890284721865, - -5.729652052830054 - ], - [ - 39.288902782051544, - -5.7295223850775026 - ], - [ - 39.28891397816181, - -5.72952237943212 - ], - [ - 39.28894247655001, - -5.729141071679603 - ], - [ - 39.288947380129216, - -5.729151582811278 - ], - [ - 39.28904751678759, - -5.727901815188423 - ], - [ - 39.28905940945, - -5.7278955010276675 - ], - [ - 39.28914770917402, - -5.726763491701007 - ], - [ - 39.28916029346079, - -5.726741056329244 - ], - [ - 39.28918111127163, - -5.726393395953501 - ], - [ - 39.289192304853835, - -5.726388483957942 - ], - [ - 39.28919223965883, - -5.726258816193987 - ], - [ - 39.28920343288595, - -5.72625320329149 - ], - [ - 39.289214507699526, - -5.726012085692045 - ], - [ - 39.289225700921726, - -5.72600647278932 - ], - [ - 39.289225641714694, - -5.725888720440319 - ], - [ - 39.28923613764901, - -5.725888014238375 - ], - [ - 39.2892367757264, - -5.725765355188089 - ], - [ - 39.28924727165846, - -5.7257646489860505 - ], - [ - 39.289403768567006, - -5.7238812328140325 - ], - [ - 39.289415663964434, - -5.723880525904426 - ], - [ - 39.289503962766254, - -5.7227485164315155 - ], - [ - 39.28951654695881, - -5.722726081053947 - ], - [ - 39.289537364530666, - -5.722378420634993 - ], - [ - 39.289548559090875, - -5.722375611356616 - ], - [ - 39.28961529374991, - -5.721498742899586 - ], - [ - 39.29004098667544, - -5.720599264075941 - ], - [ - 39.290073866967184, - -5.7205838275003424 - ], - [ - 39.29009694163223, - -5.720550172295505 - ], - [ - 39.29011863375526, - -5.720550161329309 - ], - [ - 39.29013051778038, - -5.720527025387051 - ], - [ - 39.29015220990249, - -5.720527014419632 - ], - [ - 39.290164094279014, - -5.720504579383667 - ], - [ - 39.290181588278394, - -5.720505271444961 - ], - [ - 39.290208861408814, - -5.720471614112995 - ], - [ - 39.29026413001999, - -5.720449157133799 - ], - [ - 39.2903207811543, - -5.72039305590999 - ], - [ - 39.29034317266325, - -5.720392343674706 - ], - [ - 39.2903543576374, - -5.720370609896142 - ], - [ - 39.290421516252074, - -5.720336932373324 - ], - [ - 39.29043270086868, - -5.720314497686497 - ], - [ - 39.290488668847225, - -5.720291339425736 - ], - [ - 39.29054462055196, - -5.720235939442509 - ], - [ - 39.29059988877251, - -5.720212781525714 - ], - [ - 39.29065654020414, - -5.720157381178035 - ], - [ - 39.290711808412254, - -5.7201342232510095 - ], - [ - 39.290768459825216, - -5.720078822893069 - ], - [ - 39.290823728020904, - -5.720055664955817 - ], - [ - 39.290880379415185, - -5.720000264587617 - ], - [ - 39.29093564759845, - -5.719977106640133 - ], - [ - 39.29099229897406, - -5.719921706261678 - ], - [ - 39.29104756714489, - -5.719898548303964 - ], - [ - 39.29110421850183, - -5.719843147915251 - ], - [ - 39.291159486660234, - -5.71981998994731 - ], - [ - 39.2912161379985, - -5.719764589548339 - ], - [ - 39.29127140614448, - -5.719741431570171 - ], - [ - 39.291328057464064, - -5.719686031160943 - ], - [ - 39.29138332559762, - -5.719662873172546 - ], - [ - 39.29143997689853, - -5.7196074727530615 - ], - [ - 39.29149524501966, - -5.71958431475444 - ], - [ - 39.2915518963019, - -5.7195289143247 - ], - [ - 39.2916071644106, - -5.719505756315848 - ], - [ - 39.29166381567417, - -5.719450355875855 - ], - [ - 39.29171908377044, - -5.719427197856779 - ], - [ - 39.291775735015335, - -5.719371797406529 - ], - [ - 39.291831003099176, - -5.719348639377229 - ], - [ - 39.2918876543254, - -5.719293238916724 - ], - [ - 39.291942922396814, - -5.719270080877199 - ], - [ - 39.29199957360437, - -5.719214680406439 - ], - [ - 39.29205484166336, - -5.719191522356688 - ], - [ - 39.29211149249672, - -5.719135420968851 - ], - [ - 39.292166760898795, - -5.719112963815699 - ], - [ - 39.29222341171336, - -5.7190568624176175 - ], - [ - 39.292279379847066, - -5.719034404897935 - ], - [ - 39.29228986497856, - -5.719012671441992 - ], - [ - 39.294664106892064, - -5.719033185666966 - ], - [ - 39.29467603158522, - -5.719089953000165 - ], - [ - 39.29465437431092, - -5.719157952082305 - ], - [ - 39.29465371114527, - -5.719229444921172 - ], - [ - 39.29463135734711, - -5.7193037525216885 - ], - [ - 39.29462023566773, - -5.719448845947391 - ], - [ - 39.29460904011777, - -5.719449552600848 - ], - [ - 39.29447793731705, - -5.720327856151281 - ], - [ - 39.29566180023131, - -5.720120479955832 - ], - [ - 39.29563842688224, - -5.719571681995611 - ], - [ - 39.29681400855618, - -5.719592803370352 - ], - [ - 39.29682521096831, - -5.7196054138976775 - ], - [ - 39.29732832640864, - -5.719603751672776 - ], - [ - 39.29734023364275, - -5.719626174517702 - ], - [ - 39.297709699002866, - -5.7196266839006 - ], - [ - 39.297720125955514, - -5.719492805322403 - ], - [ - 39.29773201073462, - -5.719471771958087 - ], - [ - 39.297743206640426, - -5.719471766150352 - ], - [ - 39.29900146876119, - -5.71970661665732 - ], - [ - 39.29903085693057, - -5.719704498626807 - ], - [ - 39.2990308274491, - -5.719647725210644 - ], - [ - 39.2991875701586, - -5.719647643525276 - ], - [ - 39.29918827572937, - -5.719658857662318 - ], - [ - 39.2993443186954, - -5.719658776298749 - ], - [ - 39.29951086985279, - -5.719681819324766 - ], - [ - 39.299517826100136, - -5.719602613256507 - ], - [ - 39.29961229156103, - -5.719602563951844 - ], - [ - 39.299615796116605, - -5.71961377662683 - ], - [ - 39.29974665411206, - -5.719624922805369 - ], - [ - 39.29974805943782, - -5.719636136575718 - ], - [ - 39.299847423111444, - -5.719636084673931 - ], - [ - 39.299851627415954, - -5.719647296981645 - ], - [ - 39.29994819795517, - -5.719658461025615 - ], - [ - 39.299925719258574, - -5.719491657023776 - ], - [ - 39.299914522989596, - -5.719490961967785 - ], - [ - 39.29991514680767, - -5.719345173087227 - ], - [ - 39.3000830849578, - -5.7193443844051135 - ], - [ - 39.30009354641723, - -5.719277792817777 - ], - [ - 39.300127096127426, - -5.719204880999829 - ], - [ - 39.300138941725315, - -5.719108850614782 - ], - [ - 39.3015986183503, - -5.719130514515799 - ], - [ - 39.301606321401344, - -5.7191417249709 - ], - [ - 39.30197509796063, - -5.71916396008395 - ], - [ - 39.30197650332791, - -5.719175173846801 - ], - [ - 39.30209755894922, - -5.719175110147159 - ], - [ - 39.302103862523296, - -5.719186321331581 - ], - [ - 39.30408422522446, - -5.719353493113251 - ], - [ - 39.30409122895187, - -5.7193654048089595 - ], - [ - 39.30421508356364, - -5.719365339177715 - ], - [ - 39.30421998732256, - -5.719375850172232 - ], - [ - 39.30433754424296, - -5.719375787852325 - ], - [ - 39.304338249542674, - -5.719386301071832 - ], - [ - 39.304460005295915, - -5.719386937406598 - ], - [ - 39.30446071059788, - -5.71939745062583 - ], - [ - 39.304583865839405, - -5.719398086191834 - ], - [ - 39.30458457114364, - -5.719408599410791 - ], - [ - 39.3047063268991, - -5.719409235693033 - ], - [ - 39.304707731949186, - -5.719419748540238 - ], - [ - 39.30483018744935, - -5.719420384424596 - ], - [ - 39.30483509159077, - -5.719431596319216 - ], - [ - 39.304964544156945, - -5.719431527552395 - ], - [ - 39.304965249839356, - -5.719442741676491 - ], - [ - 39.30570350908857, - -5.719498421435598 - ], - [ - 39.305737803224545, - -5.719511019479368 - ], - [ - 39.30571619973147, - -5.7196778466475715 - ], - [ - 39.30605068324513, - -5.719688882882785 - ], - [ - 39.30610737404596, - -5.7197105807395285 - ], - [ - 39.30641456569894, - -5.719718126786076 - ], - [ - 39.30643057887232, - -5.719566021615056 - ], - [ - 39.30644737234725, - -5.7195653117428185 - ], - [ - 39.30658243481406, - -5.71958766860887 - ], - [ - 39.30755791938568, - -5.71966564819061 - ], - [ - 39.30756702204364, - -5.719676857809007 - ], - [ - 39.30805965961166, - -5.719710237089115 - ], - [ - 39.308066663423446, - -5.719722148731534 - ], - [ - 39.308189818321985, - -5.719722082614072 - ], - [ - 39.308312279104385, - -5.719732530432556 - ], - [ - 39.308312284733425, - -5.719743044019035 - ], - [ - 39.30843544000899, - -5.719743678754385 - ], - [ - 39.30843544564029, - -5.719754192340735 - ], - [ - 39.30855860091696, - -5.7197548270495195 - ], - [ - 39.30855930629429, - -5.7197653402595465 - ], - [ - 39.308681761828296, - -5.719765975317966 - ], - [ - 39.30868246720789, - -5.719776488527715 - ], - [ - 39.308804922742986, - -5.719777123559718 - ], - [ - 39.308805628124844, - -5.71978763676919 - ], - [ - 39.308927383917265, - -5.719788272151425 - ], - [ - 39.308928789045154, - -5.719798784983975 - ], - [ - 39.30905124458244, - -5.71979941996315 - ], - [ - 39.309056148807734, - -5.719810631816969 - ], - [ - 39.309923167539615, - -5.719877451244321 - ], - [ - 39.31063422293008, - -5.720091544007215 - ], - [ - 39.31065381500645, - -5.720090131590763 - ], - [ - 39.310662899577814, - -5.720067697687457 - ], - [ - 39.31067404178256, - -5.7199681630314965 - ], - [ - 39.31074121076393, - -5.719956211268805 - ], - [ - 39.31163696137919, - -5.720100813064275 - ], - [ - 39.311699250733554, - -5.720123208220514 - ], - [ - 39.31180561219929, - -5.720123851348939 - ], - [ - 39.311906387102475, - -5.720145524665541 - ], - [ - 39.311906393177225, - -5.720156739153791 - ], - [ - 39.31197216911476, - -5.720156703401592 - ], - [ - 39.31197427442288, - -5.720167916748612 - ], - [ - 39.31210233973633, - -5.720190276099752 - ], - [ - 39.31212192953011, - -5.720184658200196 - ], - [ - 39.3121295815013, - -5.720101246259322 - ], - [ - 39.31215196266817, - -5.720081608726603 - ], - [ - 39.31337307522748, - -5.720190284531242 - ], - [ - 39.3133506857093, - -5.720194502190286 - ], - [ - 39.31358511825828, - -5.720228017609581 - ], - [ - 39.313602918515315, - -5.740028584511519 - ] - ] - ], - "type": "Polygon" - }, - "bbox": [ - 39.287711527683925, - -5.743060299502631, - 39.31360456846548, - -5.719012276837555 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "geometry": { + "coordinates": [ + [ + [ + 39.313602918515315, + -5.740028584511519 + ], + [ + 39.31360456846548, + -5.743046680921876 + ], + [ + 39.28771158148321, + -5.743060299502631 + ], + [ + 39.287833992413255, + -5.7415673066017945 + ], + [ + 39.28784518594579, + -5.741561693713168 + ], + [ + 39.287867395743724, + -5.741197211035715 + ], + [ + 39.28787859137919, + -5.741195803586043 + ], + [ + 39.28788965898581, + -5.740939266150898 + ], + [ + 39.28789736103782, + -5.740948374060875 + ], + [ + 39.28794532863633, + -5.740317533846062 + ], + [ + 39.287956518978035, + -5.740305612797183 + ], + [ + 39.28795645988263, + -5.740187860493621 + ], + [ + 39.28796695643181, + -5.7401878552086325 + ], + [ + 39.287978729048056, + -5.739941831012015 + ], + [ + 39.28799062442844, + -5.739940423208991 + ], + [ + 39.28801212626218, + -5.739559820014053 + ], + [ + 39.288023319754615, + -5.739554207123601 + ], + [ + 39.28805666134313, + -5.7390614528792385 + ], + [ + 39.28806785412197, + -5.739054438175143 + ], + [ + 39.288068492322395, + -5.7389317791690555 + ], + [ + 39.28807898849667, + -5.7389310729765715 + ], + [ + 39.288078926927646, + -5.738808414322463 + ], + [ + 39.28809012040507, + -5.738802801431323 + ], + [ + 39.288123461924656, + -5.73831004717524 + ], + [ + 39.28813465468841, + -5.738303032470432 + ], + [ + 39.28813459311428, + -5.73818037381424 + ], + [ + 39.288145786579165, + -5.738174760922529 + ], + [ + 39.28817912804129, + -5.737682006656658 + ], + [ + 39.28819032114434, + -5.737675692857872 + ], + [ + 39.28819025921321, + -5.737552333292979 + ], + [ + 39.28820145548069, + -5.737552327653656 + ], + [ + 39.28825705989423, + -5.736801628458127 + ], + [ + 39.28826825297967, + -5.736795314658528 + ], + [ + 39.28826819420862, + -5.736678263250428 + ], + [ + 39.288279389755104, + -5.736676855797169 + ], + [ + 39.28829046247506, + -5.736430831926878 + ], + [ + 39.288301655905016, + -5.736425219033569 + ], + [ + 39.28831272544848, + -5.736172887001599 + ], + [ + 39.28832392168893, + -5.736172881361234 + ], + [ + 39.28832386009737, + -5.736050222697981 + ], + [ + 39.28833505316777, + -5.736043908897686 + ], + [ + 39.28833569380363, + -5.735926156228032 + ], + [ + 39.28833849849387, + -5.735937369324319 + ], + [ + 39.28834688968728, + -5.735925449680809 + ], + [ + 39.288368397250515, + -5.735556761851868 + ], + [ + 39.28837959277493, + -5.7355553543976985 + ], + [ + 39.28843519161201, + -5.734794141554009 + ], + [ + 39.288446387121425, + -5.734792734099254 + ], + [ + 39.28844632551862, + -5.734670075431432 + ], + [ + 39.28845752137762, + -5.73466936888325 + ], + [ + 39.288468594025474, + -5.734423344998106 + ], + [ + 39.28847978741536, + -5.734417732102973 + ], + [ + 39.288490857237925, + -5.734166100962491 + ], + [ + 39.28850205273499, + -5.734164693507241 + ], + [ + 39.28855765700006, + -5.733414695136926 + ], + [ + 39.28856885248234, + -5.733413287681076 + ], + [ + 39.28856879122039, + -5.733291329915387 + ], + [ + 39.288579986700235, + -5.733289922459435 + ], + [ + 39.288579925085166, + -5.7331672637866395 + ], + [ + 39.288586228570765, + -5.733178475119921 + ], + [ + 39.288591061058995, + -5.733047403097616 + ], + [ + 39.28860225301303, + -5.733038986574412 + ], + [ + 39.28861332243345, + -5.732786654516813 + ], + [ + 39.28862451790337, + -5.732785247060469 + ], + [ + 39.28862445663636, + -5.732663289292712 + ], + [ + 39.288635652103856, + -5.732661881836264 + ], + [ + 39.28863629024428, + -5.7325392228087 + ], + [ + 39.28865791802952, + -5.732410245039324 + ], + [ + 39.28866898742718, + -5.732157912976972 + ], + [ + 39.28868018358902, + -5.7321579073335736 + ], + [ + 39.28868012196481, + -5.732035248657027 + ], + [ + 39.28869131495492, + -5.732028934853017 + ], + [ + 39.2886912557947, + -5.731911182523131 + ], + [ + 39.28870315135938, + -5.731910475620081 + ], + [ + 39.288802586506456, + -5.730655802114353 + ], + [ + 39.28881378193448, + -5.730654394656317 + ], + [ + 39.28881372029802, + -5.730531735974798 + ], + [ + 39.28882002375656, + -5.73054294730776 + ], + [ + 39.28883599174512, + -5.730291313668497 + ], + [ + 39.288847182939215, + -5.730281495329069 + ], + [ + 39.288847117073004, + -5.730150425765198 + ], + [ + 39.28885831319556, + -5.73015042012029 + ], + [ + 39.28885825155506, + -5.730027761437102 + ], + [ + 39.28886944450505, + -5.730021447631236 + ], + [ + 39.28886938709037, + -5.7299071998288 + ], + [ + 39.28888058109469, + -5.729902988743108 + ], + [ + 39.288880523326746, + -5.729788040033545 + ], + [ + 39.28890284721865, + -5.729652052830054 + ], + [ + 39.288902782051544, + -5.7295223850775026 + ], + [ + 39.28891397816181, + -5.72952237943212 + ], + [ + 39.28894247655001, + -5.729141071679603 + ], + [ + 39.288947380129216, + -5.729151582811278 + ], + [ + 39.28904751678759, + -5.727901815188423 + ], + [ + 39.28905940945, + -5.7278955010276675 + ], + [ + 39.28914770917402, + -5.726763491701007 + ], + [ + 39.28916029346079, + -5.726741056329244 + ], + [ + 39.28918111127163, + -5.726393395953501 + ], + [ + 39.289192304853835, + -5.726388483957942 + ], + [ + 39.28919223965883, + -5.726258816193987 + ], + [ + 39.28920343288595, + -5.72625320329149 + ], + [ + 39.289214507699526, + -5.726012085692045 + ], + [ + 39.289225700921726, + -5.72600647278932 + ], + [ + 39.289225641714694, + -5.725888720440319 + ], + [ + 39.28923613764901, + -5.725888014238375 + ], + [ + 39.2892367757264, + -5.725765355188089 + ], + [ + 39.28924727165846, + -5.7257646489860505 + ], + [ + 39.289403768567006, + -5.7238812328140325 + ], + [ + 39.289415663964434, + -5.723880525904426 + ], + [ + 39.289503962766254, + -5.7227485164315155 + ], + [ + 39.28951654695881, + -5.722726081053947 + ], + [ + 39.289537364530666, + -5.722378420634993 + ], + [ + 39.289548559090875, + -5.722375611356616 + ], + [ + 39.28961529374991, + -5.721498742899586 + ], + [ + 39.29004098667544, + -5.720599264075941 + ], + [ + 39.290073866967184, + -5.7205838275003424 + ], + [ + 39.29009694163223, + -5.720550172295505 + ], + [ + 39.29011863375526, + -5.720550161329309 + ], + [ + 39.29013051778038, + -5.720527025387051 + ], + [ + 39.29015220990249, + -5.720527014419632 + ], + [ + 39.290164094279014, + -5.720504579383667 + ], + [ + 39.290181588278394, + -5.720505271444961 + ], + [ + 39.290208861408814, + -5.720471614112995 + ], + [ + 39.29026413001999, + -5.720449157133799 + ], + [ + 39.2903207811543, + -5.72039305590999 + ], + [ + 39.29034317266325, + -5.720392343674706 + ], + [ + 39.2903543576374, + -5.720370609896142 + ], + [ + 39.290421516252074, + -5.720336932373324 + ], + [ + 39.29043270086868, + -5.720314497686497 + ], + [ + 39.290488668847225, + -5.720291339425736 + ], + [ + 39.29054462055196, + -5.720235939442509 + ], + [ + 39.29059988877251, + -5.720212781525714 + ], + [ + 39.29065654020414, + -5.720157381178035 + ], + [ + 39.290711808412254, + -5.7201342232510095 + ], + [ + 39.290768459825216, + -5.720078822893069 + ], + [ + 39.290823728020904, + -5.720055664955817 + ], + [ + 39.290880379415185, + -5.720000264587617 + ], + [ + 39.29093564759845, + -5.719977106640133 + ], + [ + 39.29099229897406, + -5.719921706261678 + ], + [ + 39.29104756714489, + -5.719898548303964 + ], + [ + 39.29110421850183, + -5.719843147915251 + ], + [ + 39.291159486660234, + -5.71981998994731 + ], + [ + 39.2912161379985, + -5.719764589548339 + ], + [ + 39.29127140614448, + -5.719741431570171 + ], + [ + 39.291328057464064, + -5.719686031160943 + ], + [ + 39.29138332559762, + -5.719662873172546 + ], + [ + 39.29143997689853, + -5.7196074727530615 + ], + [ + 39.29149524501966, + -5.71958431475444 + ], + [ + 39.2915518963019, + -5.7195289143247 + ], + [ + 39.2916071644106, + -5.719505756315848 + ], + [ + 39.29166381567417, + -5.719450355875855 + ], + [ + 39.29171908377044, + -5.719427197856779 + ], + [ + 39.291775735015335, + -5.719371797406529 + ], + [ + 39.291831003099176, + -5.719348639377229 + ], + [ + 39.2918876543254, + -5.719293238916724 + ], + [ + 39.291942922396814, + -5.719270080877199 + ], + [ + 39.29199957360437, + -5.719214680406439 + ], + [ + 39.29205484166336, + -5.719191522356688 + ], + [ + 39.29211149249672, + -5.719135420968851 + ], + [ + 39.292166760898795, + -5.719112963815699 + ], + [ + 39.29222341171336, + -5.7190568624176175 + ], + [ + 39.292279379847066, + -5.719034404897935 + ], + [ + 39.29228986497856, + -5.719012671441992 + ], + [ + 39.294664106892064, + -5.719033185666966 + ], + [ + 39.29467603158522, + -5.719089953000165 + ], + [ + 39.29465437431092, + -5.719157952082305 + ], + [ + 39.29465371114527, + -5.719229444921172 + ], + [ + 39.29463135734711, + -5.7193037525216885 + ], + [ + 39.29462023566773, + -5.719448845947391 + ], + [ + 39.29460904011777, + -5.719449552600848 + ], + [ + 39.29447793731705, + -5.720327856151281 + ], + [ + 39.29566180023131, + -5.720120479955832 + ], + [ + 39.29563842688224, + -5.719571681995611 + ], + [ + 39.29681400855618, + -5.719592803370352 + ], + [ + 39.29682521096831, + -5.7196054138976775 + ], + [ + 39.29732832640864, + -5.719603751672776 + ], + [ + 39.29734023364275, + -5.719626174517702 + ], + [ + 39.297709699002866, + -5.7196266839006 + ], + [ + 39.297720125955514, + -5.719492805322403 + ], + [ + 39.29773201073462, + -5.719471771958087 + ], + [ + 39.297743206640426, + -5.719471766150352 + ], + [ + 39.29900146876119, + -5.71970661665732 + ], + [ + 39.29903085693057, + -5.719704498626807 + ], + [ + 39.2990308274491, + -5.719647725210644 + ], + [ + 39.2991875701586, + -5.719647643525276 + ], + [ + 39.29918827572937, + -5.719658857662318 + ], + [ + 39.2993443186954, + -5.719658776298749 + ], + [ + 39.29951086985279, + -5.719681819324766 + ], + [ + 39.299517826100136, + -5.719602613256507 + ], + [ + 39.29961229156103, + -5.719602563951844 + ], + [ + 39.299615796116605, + -5.71961377662683 + ], + [ + 39.29974665411206, + -5.719624922805369 + ], + [ + 39.29974805943782, + -5.719636136575718 + ], + [ + 39.299847423111444, + -5.719636084673931 + ], + [ + 39.299851627415954, + -5.719647296981645 + ], + [ + 39.29994819795517, + -5.719658461025615 + ], + [ + 39.299925719258574, + -5.719491657023776 + ], + [ + 39.299914522989596, + -5.719490961967785 + ], + [ + 39.29991514680767, + -5.719345173087227 + ], + [ + 39.3000830849578, + -5.7193443844051135 + ], + [ + 39.30009354641723, + -5.719277792817777 + ], + [ + 39.300127096127426, + -5.719204880999829 + ], + [ + 39.300138941725315, + -5.719108850614782 + ], + [ + 39.3015986183503, + -5.719130514515799 + ], + [ + 39.301606321401344, + -5.7191417249709 + ], + [ + 39.30197509796063, + -5.71916396008395 + ], + [ + 39.30197650332791, + -5.719175173846801 + ], + [ + 39.30209755894922, + -5.719175110147159 + ], + [ + 39.302103862523296, + -5.719186321331581 + ], + [ + 39.30408422522446, + -5.719353493113251 + ], + [ + 39.30409122895187, + -5.7193654048089595 + ], + [ + 39.30421508356364, + -5.719365339177715 + ], + [ + 39.30421998732256, + -5.719375850172232 + ], + [ + 39.30433754424296, + -5.719375787852325 + ], + [ + 39.304338249542674, + -5.719386301071832 + ], + [ + 39.304460005295915, + -5.719386937406598 + ], + [ + 39.30446071059788, + -5.71939745062583 + ], + [ + 39.304583865839405, + -5.719398086191834 + ], + [ + 39.30458457114364, + -5.719408599410791 + ], + [ + 39.3047063268991, + -5.719409235693033 + ], + [ + 39.304707731949186, + -5.719419748540238 + ], + [ + 39.30483018744935, + -5.719420384424596 + ], + [ + 39.30483509159077, + -5.719431596319216 + ], + [ + 39.304964544156945, + -5.719431527552395 + ], + [ + 39.304965249839356, + -5.719442741676491 + ], + [ + 39.30570350908857, + -5.719498421435598 + ], + [ + 39.305737803224545, + -5.719511019479368 + ], + [ + 39.30571619973147, + -5.7196778466475715 + ], + [ + 39.30605068324513, + -5.719688882882785 + ], + [ + 39.30610737404596, + -5.7197105807395285 + ], + [ + 39.30641456569894, + -5.719718126786076 + ], + [ + 39.30643057887232, + -5.719566021615056 + ], + [ + 39.30644737234725, + -5.7195653117428185 + ], + [ + 39.30658243481406, + -5.71958766860887 + ], + [ + 39.30755791938568, + -5.71966564819061 + ], + [ + 39.30756702204364, + -5.719676857809007 + ], + [ + 39.30805965961166, + -5.719710237089115 + ], + [ + 39.308066663423446, + -5.719722148731534 + ], + [ + 39.308189818321985, + -5.719722082614072 + ], + [ + 39.308312279104385, + -5.719732530432556 + ], + [ + 39.308312284733425, + -5.719743044019035 + ], + [ + 39.30843544000899, + -5.719743678754385 + ], + [ + 39.30843544564029, + -5.719754192340735 + ], + [ + 39.30855860091696, + -5.7197548270495195 + ], + [ + 39.30855930629429, + -5.7197653402595465 + ], + [ + 39.308681761828296, + -5.719765975317966 + ], + [ + 39.30868246720789, + -5.719776488527715 + ], + [ + 39.308804922742986, + -5.719777123559718 + ], + [ + 39.308805628124844, + -5.71978763676919 + ], + [ + 39.308927383917265, + -5.719788272151425 + ], + [ + 39.308928789045154, + -5.719798784983975 + ], + [ + 39.30905124458244, + -5.71979941996315 + ], + [ + 39.309056148807734, + -5.719810631816969 + ], + [ + 39.309923167539615, + -5.719877451244321 + ], + [ + 39.31063422293008, + -5.720091544007215 + ], + [ + 39.31065381500645, + -5.720090131590763 + ], + [ + 39.310662899577814, + -5.720067697687457 + ], + [ + 39.31067404178256, + -5.7199681630314965 + ], + [ + 39.31074121076393, + -5.719956211268805 + ], + [ + 39.31163696137919, + -5.720100813064275 + ], + [ + 39.311699250733554, + -5.720123208220514 + ], + [ + 39.31180561219929, + -5.720123851348939 + ], + [ + 39.311906387102475, + -5.720145524665541 + ], + [ + 39.311906393177225, + -5.720156739153791 + ], + [ + 39.31197216911476, + -5.720156703401592 + ], + [ + 39.31197427442288, + -5.720167916748612 + ], + [ + 39.31210233973633, + -5.720190276099752 + ], + [ + 39.31212192953011, + -5.720184658200196 + ], + [ + 39.3121295815013, + -5.720101246259322 + ], + [ + 39.31215196266817, + -5.720081608726603 + ], + [ + 39.31337307522748, + -5.720190284531242 + ], + [ + 39.3133506857093, + -5.720194502190286 + ], + [ + 39.31358511825828, + -5.720228017609581 + ], + [ + 39.313602918515315, + -5.740028584511519 + ] + ] + ], + "type": "Polygon" }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "labels": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/33cae6-labels/33cae6.geojson", - "type": "application/geo+json" - } - }, - "stac_extensions": [ - "label" - ] + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "labels": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/33cae6-labels/33cae6.geojson", + "type": "application/geo+json" + } + }, + "bbox": [ + 39.287711527683925, + -5.743060299502631, + 39.31360456846548, + -5.719012276837555 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "znz" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/znz/33cae6/33cae6.json b/tests/data-files/catalogs/test-case-4/znz/33cae6/33cae6.json index 0646a5ec6..f1928cb44 100644 --- a/tests/data-files/catalogs/test-case-4/znz/33cae6/33cae6.json +++ b/tests/data-files/catalogs/test-case-4/znz/33cae6/33cae6.json @@ -1,1139 +1,1140 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "33cae6", - "properties": { - "area": "znz", - "datetime": "2016-08-28T00:00:00Z" - }, - "geometry": { - "coordinates": [ - [ - [ - 39.313602918515315, - -5.740028584511519 - ], - [ - 39.31360456846548, - -5.743046680921876 - ], - [ - 39.28771158148321, - -5.743060299502631 - ], - [ - 39.287833992413255, - -5.7415673066017945 - ], - [ - 39.28784518594579, - -5.741561693713168 - ], - [ - 39.287867395743724, - -5.741197211035715 - ], - [ - 39.28787859137919, - -5.741195803586043 - ], - [ - 39.28788965898581, - -5.740939266150898 - ], - [ - 39.28789736103782, - -5.740948374060875 - ], - [ - 39.28794532863633, - -5.740317533846062 - ], - [ - 39.287956518978035, - -5.740305612797183 - ], - [ - 39.28795645988263, - -5.740187860493621 - ], - [ - 39.28796695643181, - -5.7401878552086325 - ], - [ - 39.287978729048056, - -5.739941831012015 - ], - [ - 39.28799062442844, - -5.739940423208991 - ], - [ - 39.28801212626218, - -5.739559820014053 - ], - [ - 39.288023319754615, - -5.739554207123601 - ], - [ - 39.28805666134313, - -5.7390614528792385 - ], - [ - 39.28806785412197, - -5.739054438175143 - ], - [ - 39.288068492322395, - -5.7389317791690555 - ], - [ - 39.28807898849667, - -5.7389310729765715 - ], - [ - 39.288078926927646, - -5.738808414322463 - ], - [ - 39.28809012040507, - -5.738802801431323 - ], - [ - 39.288123461924656, - -5.73831004717524 - ], - [ - 39.28813465468841, - -5.738303032470432 - ], - [ - 39.28813459311428, - -5.73818037381424 - ], - [ - 39.288145786579165, - -5.738174760922529 - ], - [ - 39.28817912804129, - -5.737682006656658 - ], - [ - 39.28819032114434, - -5.737675692857872 - ], - [ - 39.28819025921321, - -5.737552333292979 - ], - [ - 39.28820145548069, - -5.737552327653656 - ], - [ - 39.28825705989423, - -5.736801628458127 - ], - [ - 39.28826825297967, - -5.736795314658528 - ], - [ - 39.28826819420862, - -5.736678263250428 - ], - [ - 39.288279389755104, - -5.736676855797169 - ], - [ - 39.28829046247506, - -5.736430831926878 - ], - [ - 39.288301655905016, - -5.736425219033569 - ], - [ - 39.28831272544848, - -5.736172887001599 - ], - [ - 39.28832392168893, - -5.736172881361234 - ], - [ - 39.28832386009737, - -5.736050222697981 - ], - [ - 39.28833505316777, - -5.736043908897686 - ], - [ - 39.28833569380363, - -5.735926156228032 - ], - [ - 39.28833849849387, - -5.735937369324319 - ], - [ - 39.28834688968728, - -5.735925449680809 - ], - [ - 39.288368397250515, - -5.735556761851868 - ], - [ - 39.28837959277493, - -5.7355553543976985 - ], - [ - 39.28843519161201, - -5.734794141554009 - ], - [ - 39.288446387121425, - -5.734792734099254 - ], - [ - 39.28844632551862, - -5.734670075431432 - ], - [ - 39.28845752137762, - -5.73466936888325 - ], - [ - 39.288468594025474, - -5.734423344998106 - ], - [ - 39.28847978741536, - -5.734417732102973 - ], - [ - 39.288490857237925, - -5.734166100962491 - ], - [ - 39.28850205273499, - -5.734164693507241 - ], - [ - 39.28855765700006, - -5.733414695136926 - ], - [ - 39.28856885248234, - -5.733413287681076 - ], - [ - 39.28856879122039, - -5.733291329915387 - ], - [ - 39.288579986700235, - -5.733289922459435 - ], - [ - 39.288579925085166, - -5.7331672637866395 - ], - [ - 39.288586228570765, - -5.733178475119921 - ], - [ - 39.288591061058995, - -5.733047403097616 - ], - [ - 39.28860225301303, - -5.733038986574412 - ], - [ - 39.28861332243345, - -5.732786654516813 - ], - [ - 39.28862451790337, - -5.732785247060469 - ], - [ - 39.28862445663636, - -5.732663289292712 - ], - [ - 39.288635652103856, - -5.732661881836264 - ], - [ - 39.28863629024428, - -5.7325392228087 - ], - [ - 39.28865791802952, - -5.732410245039324 - ], - [ - 39.28866898742718, - -5.732157912976972 - ], - [ - 39.28868018358902, - -5.7321579073335736 - ], - [ - 39.28868012196481, - -5.732035248657027 - ], - [ - 39.28869131495492, - -5.732028934853017 - ], - [ - 39.2886912557947, - -5.731911182523131 - ], - [ - 39.28870315135938, - -5.731910475620081 - ], - [ - 39.288802586506456, - -5.730655802114353 - ], - [ - 39.28881378193448, - -5.730654394656317 - ], - [ - 39.28881372029802, - -5.730531735974798 - ], - [ - 39.28882002375656, - -5.73054294730776 - ], - [ - 39.28883599174512, - -5.730291313668497 - ], - [ - 39.288847182939215, - -5.730281495329069 - ], - [ - 39.288847117073004, - -5.730150425765198 - ], - [ - 39.28885831319556, - -5.73015042012029 - ], - [ - 39.28885825155506, - -5.730027761437102 - ], - [ - 39.28886944450505, - -5.730021447631236 - ], - [ - 39.28886938709037, - -5.7299071998288 - ], - [ - 39.28888058109469, - -5.729902988743108 - ], - [ - 39.288880523326746, - -5.729788040033545 - ], - [ - 39.28890284721865, - -5.729652052830054 - ], - [ - 39.288902782051544, - -5.7295223850775026 - ], - [ - 39.28891397816181, - -5.72952237943212 - ], - [ - 39.28894247655001, - -5.729141071679603 - ], - [ - 39.288947380129216, - -5.729151582811278 - ], - [ - 39.28904751678759, - -5.727901815188423 - ], - [ - 39.28905940945, - -5.7278955010276675 - ], - [ - 39.28914770917402, - -5.726763491701007 - ], - [ - 39.28916029346079, - -5.726741056329244 - ], - [ - 39.28918111127163, - -5.726393395953501 - ], - [ - 39.289192304853835, - -5.726388483957942 - ], - [ - 39.28919223965883, - -5.726258816193987 - ], - [ - 39.28920343288595, - -5.72625320329149 - ], - [ - 39.289214507699526, - -5.726012085692045 - ], - [ - 39.289225700921726, - -5.72600647278932 - ], - [ - 39.289225641714694, - -5.725888720440319 - ], - [ - 39.28923613764901, - -5.725888014238375 - ], - [ - 39.2892367757264, - -5.725765355188089 - ], - [ - 39.28924727165846, - -5.7257646489860505 - ], - [ - 39.289403768567006, - -5.7238812328140325 - ], - [ - 39.289415663964434, - -5.723880525904426 - ], - [ - 39.289503962766254, - -5.7227485164315155 - ], - [ - 39.28951654695881, - -5.722726081053947 - ], - [ - 39.289537364530666, - -5.722378420634993 - ], - [ - 39.289548559090875, - -5.722375611356616 - ], - [ - 39.28961529374991, - -5.721498742899586 - ], - [ - 39.29004098667544, - -5.720599264075941 - ], - [ - 39.290073866967184, - -5.7205838275003424 - ], - [ - 39.29009694163223, - -5.720550172295505 - ], - [ - 39.29011863375526, - -5.720550161329309 - ], - [ - 39.29013051778038, - -5.720527025387051 - ], - [ - 39.29015220990249, - -5.720527014419632 - ], - [ - 39.290164094279014, - -5.720504579383667 - ], - [ - 39.290181588278394, - -5.720505271444961 - ], - [ - 39.290208861408814, - -5.720471614112995 - ], - [ - 39.29026413001999, - -5.720449157133799 - ], - [ - 39.2903207811543, - -5.72039305590999 - ], - [ - 39.29034317266325, - -5.720392343674706 - ], - [ - 39.2903543576374, - -5.720370609896142 - ], - [ - 39.290421516252074, - -5.720336932373324 - ], - [ - 39.29043270086868, - -5.720314497686497 - ], - [ - 39.290488668847225, - -5.720291339425736 - ], - [ - 39.29054462055196, - -5.720235939442509 - ], - [ - 39.29059988877251, - -5.720212781525714 - ], - [ - 39.29065654020414, - -5.720157381178035 - ], - [ - 39.290711808412254, - -5.7201342232510095 - ], - [ - 39.290768459825216, - -5.720078822893069 - ], - [ - 39.290823728020904, - -5.720055664955817 - ], - [ - 39.290880379415185, - -5.720000264587617 - ], - [ - 39.29093564759845, - -5.719977106640133 - ], - [ - 39.29099229897406, - -5.719921706261678 - ], - [ - 39.29104756714489, - -5.719898548303964 - ], - [ - 39.29110421850183, - -5.719843147915251 - ], - [ - 39.291159486660234, - -5.71981998994731 - ], - [ - 39.2912161379985, - -5.719764589548339 - ], - [ - 39.29127140614448, - -5.719741431570171 - ], - [ - 39.291328057464064, - -5.719686031160943 - ], - [ - 39.29138332559762, - -5.719662873172546 - ], - [ - 39.29143997689853, - -5.7196074727530615 - ], - [ - 39.29149524501966, - -5.71958431475444 - ], - [ - 39.2915518963019, - -5.7195289143247 - ], - [ - 39.2916071644106, - -5.719505756315848 - ], - [ - 39.29166381567417, - -5.719450355875855 - ], - [ - 39.29171908377044, - -5.719427197856779 - ], - [ - 39.291775735015335, - -5.719371797406529 - ], - [ - 39.291831003099176, - -5.719348639377229 - ], - [ - 39.2918876543254, - -5.719293238916724 - ], - [ - 39.291942922396814, - -5.719270080877199 - ], - [ - 39.29199957360437, - -5.719214680406439 - ], - [ - 39.29205484166336, - -5.719191522356688 - ], - [ - 39.29211149249672, - -5.719135420968851 - ], - [ - 39.292166760898795, - -5.719112963815699 - ], - [ - 39.29222341171336, - -5.7190568624176175 - ], - [ - 39.292279379847066, - -5.719034404897935 - ], - [ - 39.29228986497856, - -5.719012671441992 - ], - [ - 39.294664106892064, - -5.719033185666966 - ], - [ - 39.29467603158522, - -5.719089953000165 - ], - [ - 39.29465437431092, - -5.719157952082305 - ], - [ - 39.29465371114527, - -5.719229444921172 - ], - [ - 39.29463135734711, - -5.7193037525216885 - ], - [ - 39.29462023566773, - -5.719448845947391 - ], - [ - 39.29460904011777, - -5.719449552600848 - ], - [ - 39.29447793731705, - -5.720327856151281 - ], - [ - 39.29566180023131, - -5.720120479955832 - ], - [ - 39.29563842688224, - -5.719571681995611 - ], - [ - 39.29681400855618, - -5.719592803370352 - ], - [ - 39.29682521096831, - -5.7196054138976775 - ], - [ - 39.29732832640864, - -5.719603751672776 - ], - [ - 39.29734023364275, - -5.719626174517702 - ], - [ - 39.297709699002866, - -5.7196266839006 - ], - [ - 39.297720125955514, - -5.719492805322403 - ], - [ - 39.29773201073462, - -5.719471771958087 - ], - [ - 39.297743206640426, - -5.719471766150352 - ], - [ - 39.29900146876119, - -5.71970661665732 - ], - [ - 39.29903085693057, - -5.719704498626807 - ], - [ - 39.2990308274491, - -5.719647725210644 - ], - [ - 39.2991875701586, - -5.719647643525276 - ], - [ - 39.29918827572937, - -5.719658857662318 - ], - [ - 39.2993443186954, - -5.719658776298749 - ], - [ - 39.29951086985279, - -5.719681819324766 - ], - [ - 39.299517826100136, - -5.719602613256507 - ], - [ - 39.29961229156103, - -5.719602563951844 - ], - [ - 39.299615796116605, - -5.71961377662683 - ], - [ - 39.29974665411206, - -5.719624922805369 - ], - [ - 39.29974805943782, - -5.719636136575718 - ], - [ - 39.299847423111444, - -5.719636084673931 - ], - [ - 39.299851627415954, - -5.719647296981645 - ], - [ - 39.29994819795517, - -5.719658461025615 - ], - [ - 39.299925719258574, - -5.719491657023776 - ], - [ - 39.299914522989596, - -5.719490961967785 - ], - [ - 39.29991514680767, - -5.719345173087227 - ], - [ - 39.3000830849578, - -5.7193443844051135 - ], - [ - 39.30009354641723, - -5.719277792817777 - ], - [ - 39.300127096127426, - -5.719204880999829 - ], - [ - 39.300138941725315, - -5.719108850614782 - ], - [ - 39.3015986183503, - -5.719130514515799 - ], - [ - 39.301606321401344, - -5.7191417249709 - ], - [ - 39.30197509796063, - -5.71916396008395 - ], - [ - 39.30197650332791, - -5.719175173846801 - ], - [ - 39.30209755894922, - -5.719175110147159 - ], - [ - 39.302103862523296, - -5.719186321331581 - ], - [ - 39.30408422522446, - -5.719353493113251 - ], - [ - 39.30409122895187, - -5.7193654048089595 - ], - [ - 39.30421508356364, - -5.719365339177715 - ], - [ - 39.30421998732256, - -5.719375850172232 - ], - [ - 39.30433754424296, - -5.719375787852325 - ], - [ - 39.304338249542674, - -5.719386301071832 - ], - [ - 39.304460005295915, - -5.719386937406598 - ], - [ - 39.30446071059788, - -5.71939745062583 - ], - [ - 39.304583865839405, - -5.719398086191834 - ], - [ - 39.30458457114364, - -5.719408599410791 - ], - [ - 39.3047063268991, - -5.719409235693033 - ], - [ - 39.304707731949186, - -5.719419748540238 - ], - [ - 39.30483018744935, - -5.719420384424596 - ], - [ - 39.30483509159077, - -5.719431596319216 - ], - [ - 39.304964544156945, - -5.719431527552395 - ], - [ - 39.304965249839356, - -5.719442741676491 - ], - [ - 39.30570350908857, - -5.719498421435598 - ], - [ - 39.305737803224545, - -5.719511019479368 - ], - [ - 39.30571619973147, - -5.7196778466475715 - ], - [ - 39.30605068324513, - -5.719688882882785 - ], - [ - 39.30610737404596, - -5.7197105807395285 - ], - [ - 39.30641456569894, - -5.719718126786076 - ], - [ - 39.30643057887232, - -5.719566021615056 - ], - [ - 39.30644737234725, - -5.7195653117428185 - ], - [ - 39.30658243481406, - -5.71958766860887 - ], - [ - 39.30755791938568, - -5.71966564819061 - ], - [ - 39.30756702204364, - -5.719676857809007 - ], - [ - 39.30805965961166, - -5.719710237089115 - ], - [ - 39.308066663423446, - -5.719722148731534 - ], - [ - 39.308189818321985, - -5.719722082614072 - ], - [ - 39.308312279104385, - -5.719732530432556 - ], - [ - 39.308312284733425, - -5.719743044019035 - ], - [ - 39.30843544000899, - -5.719743678754385 - ], - [ - 39.30843544564029, - -5.719754192340735 - ], - [ - 39.30855860091696, - -5.7197548270495195 - ], - [ - 39.30855930629429, - -5.7197653402595465 - ], - [ - 39.308681761828296, - -5.719765975317966 - ], - [ - 39.30868246720789, - -5.719776488527715 - ], - [ - 39.308804922742986, - -5.719777123559718 - ], - [ - 39.308805628124844, - -5.71978763676919 - ], - [ - 39.308927383917265, - -5.719788272151425 - ], - [ - 39.308928789045154, - -5.719798784983975 - ], - [ - 39.30905124458244, - -5.71979941996315 - ], - [ - 39.309056148807734, - -5.719810631816969 - ], - [ - 39.309923167539615, - -5.719877451244321 - ], - [ - 39.31063422293008, - -5.720091544007215 - ], - [ - 39.31065381500645, - -5.720090131590763 - ], - [ - 39.310662899577814, - -5.720067697687457 - ], - [ - 39.31067404178256, - -5.7199681630314965 - ], - [ - 39.31074121076393, - -5.719956211268805 - ], - [ - 39.31163696137919, - -5.720100813064275 - ], - [ - 39.311699250733554, - -5.720123208220514 - ], - [ - 39.31180561219929, - -5.720123851348939 - ], - [ - 39.311906387102475, - -5.720145524665541 - ], - [ - 39.311906393177225, - -5.720156739153791 - ], - [ - 39.31197216911476, - -5.720156703401592 - ], - [ - 39.31197427442288, - -5.720167916748612 - ], - [ - 39.31210233973633, - -5.720190276099752 - ], - [ - 39.31212192953011, - -5.720184658200196 - ], - [ - 39.3121295815013, - -5.720101246259322 - ], - [ - 39.31215196266817, - -5.720081608726603 - ], - [ - 39.31337307522748, - -5.720190284531242 - ], - [ - 39.3133506857093, - -5.720194502190286 - ], - [ - 39.31358511825828, - -5.720228017609581 - ], - [ - 39.313602918515315, - -5.740028584511519 - ] - ] - ], - "type": "Polygon" - }, - "bbox": [ - 39.287711527683925, - -5.743060299502631, - 39.31360456846548, - -5.719012276837555 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "33cae6", + "properties": { + "area": "znz", + "datetime": "2016-08-28T00:00:00Z" + }, + "geometry": { + "coordinates": [ + [ + [ + 39.313602918515315, + -5.740028584511519 + ], + [ + 39.31360456846548, + -5.743046680921876 + ], + [ + 39.28771158148321, + -5.743060299502631 + ], + [ + 39.287833992413255, + -5.7415673066017945 + ], + [ + 39.28784518594579, + -5.741561693713168 + ], + [ + 39.287867395743724, + -5.741197211035715 + ], + [ + 39.28787859137919, + -5.741195803586043 + ], + [ + 39.28788965898581, + -5.740939266150898 + ], + [ + 39.28789736103782, + -5.740948374060875 + ], + [ + 39.28794532863633, + -5.740317533846062 + ], + [ + 39.287956518978035, + -5.740305612797183 + ], + [ + 39.28795645988263, + -5.740187860493621 + ], + [ + 39.28796695643181, + -5.7401878552086325 + ], + [ + 39.287978729048056, + -5.739941831012015 + ], + [ + 39.28799062442844, + -5.739940423208991 + ], + [ + 39.28801212626218, + -5.739559820014053 + ], + [ + 39.288023319754615, + -5.739554207123601 + ], + [ + 39.28805666134313, + -5.7390614528792385 + ], + [ + 39.28806785412197, + -5.739054438175143 + ], + [ + 39.288068492322395, + -5.7389317791690555 + ], + [ + 39.28807898849667, + -5.7389310729765715 + ], + [ + 39.288078926927646, + -5.738808414322463 + ], + [ + 39.28809012040507, + -5.738802801431323 + ], + [ + 39.288123461924656, + -5.73831004717524 + ], + [ + 39.28813465468841, + -5.738303032470432 + ], + [ + 39.28813459311428, + -5.73818037381424 + ], + [ + 39.288145786579165, + -5.738174760922529 + ], + [ + 39.28817912804129, + -5.737682006656658 + ], + [ + 39.28819032114434, + -5.737675692857872 + ], + [ + 39.28819025921321, + -5.737552333292979 + ], + [ + 39.28820145548069, + -5.737552327653656 + ], + [ + 39.28825705989423, + -5.736801628458127 + ], + [ + 39.28826825297967, + -5.736795314658528 + ], + [ + 39.28826819420862, + -5.736678263250428 + ], + [ + 39.288279389755104, + -5.736676855797169 + ], + [ + 39.28829046247506, + -5.736430831926878 + ], + [ + 39.288301655905016, + -5.736425219033569 + ], + [ + 39.28831272544848, + -5.736172887001599 + ], + [ + 39.28832392168893, + -5.736172881361234 + ], + [ + 39.28832386009737, + -5.736050222697981 + ], + [ + 39.28833505316777, + -5.736043908897686 + ], + [ + 39.28833569380363, + -5.735926156228032 + ], + [ + 39.28833849849387, + -5.735937369324319 + ], + [ + 39.28834688968728, + -5.735925449680809 + ], + [ + 39.288368397250515, + -5.735556761851868 + ], + [ + 39.28837959277493, + -5.7355553543976985 + ], + [ + 39.28843519161201, + -5.734794141554009 + ], + [ + 39.288446387121425, + -5.734792734099254 + ], + [ + 39.28844632551862, + -5.734670075431432 + ], + [ + 39.28845752137762, + -5.73466936888325 + ], + [ + 39.288468594025474, + -5.734423344998106 + ], + [ + 39.28847978741536, + -5.734417732102973 + ], + [ + 39.288490857237925, + -5.734166100962491 + ], + [ + 39.28850205273499, + -5.734164693507241 + ], + [ + 39.28855765700006, + -5.733414695136926 + ], + [ + 39.28856885248234, + -5.733413287681076 + ], + [ + 39.28856879122039, + -5.733291329915387 + ], + [ + 39.288579986700235, + -5.733289922459435 + ], + [ + 39.288579925085166, + -5.7331672637866395 + ], + [ + 39.288586228570765, + -5.733178475119921 + ], + [ + 39.288591061058995, + -5.733047403097616 + ], + [ + 39.28860225301303, + -5.733038986574412 + ], + [ + 39.28861332243345, + -5.732786654516813 + ], + [ + 39.28862451790337, + -5.732785247060469 + ], + [ + 39.28862445663636, + -5.732663289292712 + ], + [ + 39.288635652103856, + -5.732661881836264 + ], + [ + 39.28863629024428, + -5.7325392228087 + ], + [ + 39.28865791802952, + -5.732410245039324 + ], + [ + 39.28866898742718, + -5.732157912976972 + ], + [ + 39.28868018358902, + -5.7321579073335736 + ], + [ + 39.28868012196481, + -5.732035248657027 + ], + [ + 39.28869131495492, + -5.732028934853017 + ], + [ + 39.2886912557947, + -5.731911182523131 + ], + [ + 39.28870315135938, + -5.731910475620081 + ], + [ + 39.288802586506456, + -5.730655802114353 + ], + [ + 39.28881378193448, + -5.730654394656317 + ], + [ + 39.28881372029802, + -5.730531735974798 + ], + [ + 39.28882002375656, + -5.73054294730776 + ], + [ + 39.28883599174512, + -5.730291313668497 + ], + [ + 39.288847182939215, + -5.730281495329069 + ], + [ + 39.288847117073004, + -5.730150425765198 + ], + [ + 39.28885831319556, + -5.73015042012029 + ], + [ + 39.28885825155506, + -5.730027761437102 + ], + [ + 39.28886944450505, + -5.730021447631236 + ], + [ + 39.28886938709037, + -5.7299071998288 + ], + [ + 39.28888058109469, + -5.729902988743108 + ], + [ + 39.288880523326746, + -5.729788040033545 + ], + [ + 39.28890284721865, + -5.729652052830054 + ], + [ + 39.288902782051544, + -5.7295223850775026 + ], + [ + 39.28891397816181, + -5.72952237943212 + ], + [ + 39.28894247655001, + -5.729141071679603 + ], + [ + 39.288947380129216, + -5.729151582811278 + ], + [ + 39.28904751678759, + -5.727901815188423 + ], + [ + 39.28905940945, + -5.7278955010276675 + ], + [ + 39.28914770917402, + -5.726763491701007 + ], + [ + 39.28916029346079, + -5.726741056329244 + ], + [ + 39.28918111127163, + -5.726393395953501 + ], + [ + 39.289192304853835, + -5.726388483957942 + ], + [ + 39.28919223965883, + -5.726258816193987 + ], + [ + 39.28920343288595, + -5.72625320329149 + ], + [ + 39.289214507699526, + -5.726012085692045 + ], + [ + 39.289225700921726, + -5.72600647278932 + ], + [ + 39.289225641714694, + -5.725888720440319 + ], + [ + 39.28923613764901, + -5.725888014238375 + ], + [ + 39.2892367757264, + -5.725765355188089 + ], + [ + 39.28924727165846, + -5.7257646489860505 + ], + [ + 39.289403768567006, + -5.7238812328140325 + ], + [ + 39.289415663964434, + -5.723880525904426 + ], + [ + 39.289503962766254, + -5.7227485164315155 + ], + [ + 39.28951654695881, + -5.722726081053947 + ], + [ + 39.289537364530666, + -5.722378420634993 + ], + [ + 39.289548559090875, + -5.722375611356616 + ], + [ + 39.28961529374991, + -5.721498742899586 + ], + [ + 39.29004098667544, + -5.720599264075941 + ], + [ + 39.290073866967184, + -5.7205838275003424 + ], + [ + 39.29009694163223, + -5.720550172295505 + ], + [ + 39.29011863375526, + -5.720550161329309 + ], + [ + 39.29013051778038, + -5.720527025387051 + ], + [ + 39.29015220990249, + -5.720527014419632 + ], + [ + 39.290164094279014, + -5.720504579383667 + ], + [ + 39.290181588278394, + -5.720505271444961 + ], + [ + 39.290208861408814, + -5.720471614112995 + ], + [ + 39.29026413001999, + -5.720449157133799 + ], + [ + 39.2903207811543, + -5.72039305590999 + ], + [ + 39.29034317266325, + -5.720392343674706 + ], + [ + 39.2903543576374, + -5.720370609896142 + ], + [ + 39.290421516252074, + -5.720336932373324 + ], + [ + 39.29043270086868, + -5.720314497686497 + ], + [ + 39.290488668847225, + -5.720291339425736 + ], + [ + 39.29054462055196, + -5.720235939442509 + ], + [ + 39.29059988877251, + -5.720212781525714 + ], + [ + 39.29065654020414, + -5.720157381178035 + ], + [ + 39.290711808412254, + -5.7201342232510095 + ], + [ + 39.290768459825216, + -5.720078822893069 + ], + [ + 39.290823728020904, + -5.720055664955817 + ], + [ + 39.290880379415185, + -5.720000264587617 + ], + [ + 39.29093564759845, + -5.719977106640133 + ], + [ + 39.29099229897406, + -5.719921706261678 + ], + [ + 39.29104756714489, + -5.719898548303964 + ], + [ + 39.29110421850183, + -5.719843147915251 + ], + [ + 39.291159486660234, + -5.71981998994731 + ], + [ + 39.2912161379985, + -5.719764589548339 + ], + [ + 39.29127140614448, + -5.719741431570171 + ], + [ + 39.291328057464064, + -5.719686031160943 + ], + [ + 39.29138332559762, + -5.719662873172546 + ], + [ + 39.29143997689853, + -5.7196074727530615 + ], + [ + 39.29149524501966, + -5.71958431475444 + ], + [ + 39.2915518963019, + -5.7195289143247 + ], + [ + 39.2916071644106, + -5.719505756315848 + ], + [ + 39.29166381567417, + -5.719450355875855 + ], + [ + 39.29171908377044, + -5.719427197856779 + ], + [ + 39.291775735015335, + -5.719371797406529 + ], + [ + 39.291831003099176, + -5.719348639377229 + ], + [ + 39.2918876543254, + -5.719293238916724 + ], + [ + 39.291942922396814, + -5.719270080877199 + ], + [ + 39.29199957360437, + -5.719214680406439 + ], + [ + 39.29205484166336, + -5.719191522356688 + ], + [ + 39.29211149249672, + -5.719135420968851 + ], + [ + 39.292166760898795, + -5.719112963815699 + ], + [ + 39.29222341171336, + -5.7190568624176175 + ], + [ + 39.292279379847066, + -5.719034404897935 + ], + [ + 39.29228986497856, + -5.719012671441992 + ], + [ + 39.294664106892064, + -5.719033185666966 + ], + [ + 39.29467603158522, + -5.719089953000165 + ], + [ + 39.29465437431092, + -5.719157952082305 + ], + [ + 39.29465371114527, + -5.719229444921172 + ], + [ + 39.29463135734711, + -5.7193037525216885 + ], + [ + 39.29462023566773, + -5.719448845947391 + ], + [ + 39.29460904011777, + -5.719449552600848 + ], + [ + 39.29447793731705, + -5.720327856151281 + ], + [ + 39.29566180023131, + -5.720120479955832 + ], + [ + 39.29563842688224, + -5.719571681995611 + ], + [ + 39.29681400855618, + -5.719592803370352 + ], + [ + 39.29682521096831, + -5.7196054138976775 + ], + [ + 39.29732832640864, + -5.719603751672776 + ], + [ + 39.29734023364275, + -5.719626174517702 + ], + [ + 39.297709699002866, + -5.7196266839006 + ], + [ + 39.297720125955514, + -5.719492805322403 + ], + [ + 39.29773201073462, + -5.719471771958087 + ], + [ + 39.297743206640426, + -5.719471766150352 + ], + [ + 39.29900146876119, + -5.71970661665732 + ], + [ + 39.29903085693057, + -5.719704498626807 + ], + [ + 39.2990308274491, + -5.719647725210644 + ], + [ + 39.2991875701586, + -5.719647643525276 + ], + [ + 39.29918827572937, + -5.719658857662318 + ], + [ + 39.2993443186954, + -5.719658776298749 + ], + [ + 39.29951086985279, + -5.719681819324766 + ], + [ + 39.299517826100136, + -5.719602613256507 + ], + [ + 39.29961229156103, + -5.719602563951844 + ], + [ + 39.299615796116605, + -5.71961377662683 + ], + [ + 39.29974665411206, + -5.719624922805369 + ], + [ + 39.29974805943782, + -5.719636136575718 + ], + [ + 39.299847423111444, + -5.719636084673931 + ], + [ + 39.299851627415954, + -5.719647296981645 + ], + [ + 39.29994819795517, + -5.719658461025615 + ], + [ + 39.299925719258574, + -5.719491657023776 + ], + [ + 39.299914522989596, + -5.719490961967785 + ], + [ + 39.29991514680767, + -5.719345173087227 + ], + [ + 39.3000830849578, + -5.7193443844051135 + ], + [ + 39.30009354641723, + -5.719277792817777 + ], + [ + 39.300127096127426, + -5.719204880999829 + ], + [ + 39.300138941725315, + -5.719108850614782 + ], + [ + 39.3015986183503, + -5.719130514515799 + ], + [ + 39.301606321401344, + -5.7191417249709 + ], + [ + 39.30197509796063, + -5.71916396008395 + ], + [ + 39.30197650332791, + -5.719175173846801 + ], + [ + 39.30209755894922, + -5.719175110147159 + ], + [ + 39.302103862523296, + -5.719186321331581 + ], + [ + 39.30408422522446, + -5.719353493113251 + ], + [ + 39.30409122895187, + -5.7193654048089595 + ], + [ + 39.30421508356364, + -5.719365339177715 + ], + [ + 39.30421998732256, + -5.719375850172232 + ], + [ + 39.30433754424296, + -5.719375787852325 + ], + [ + 39.304338249542674, + -5.719386301071832 + ], + [ + 39.304460005295915, + -5.719386937406598 + ], + [ + 39.30446071059788, + -5.71939745062583 + ], + [ + 39.304583865839405, + -5.719398086191834 + ], + [ + 39.30458457114364, + -5.719408599410791 + ], + [ + 39.3047063268991, + -5.719409235693033 + ], + [ + 39.304707731949186, + -5.719419748540238 + ], + [ + 39.30483018744935, + -5.719420384424596 + ], + [ + 39.30483509159077, + -5.719431596319216 + ], + [ + 39.304964544156945, + -5.719431527552395 + ], + [ + 39.304965249839356, + -5.719442741676491 + ], + [ + 39.30570350908857, + -5.719498421435598 + ], + [ + 39.305737803224545, + -5.719511019479368 + ], + [ + 39.30571619973147, + -5.7196778466475715 + ], + [ + 39.30605068324513, + -5.719688882882785 + ], + [ + 39.30610737404596, + -5.7197105807395285 + ], + [ + 39.30641456569894, + -5.719718126786076 + ], + [ + 39.30643057887232, + -5.719566021615056 + ], + [ + 39.30644737234725, + -5.7195653117428185 + ], + [ + 39.30658243481406, + -5.71958766860887 + ], + [ + 39.30755791938568, + -5.71966564819061 + ], + [ + 39.30756702204364, + -5.719676857809007 + ], + [ + 39.30805965961166, + -5.719710237089115 + ], + [ + 39.308066663423446, + -5.719722148731534 + ], + [ + 39.308189818321985, + -5.719722082614072 + ], + [ + 39.308312279104385, + -5.719732530432556 + ], + [ + 39.308312284733425, + -5.719743044019035 + ], + [ + 39.30843544000899, + -5.719743678754385 + ], + [ + 39.30843544564029, + -5.719754192340735 + ], + [ + 39.30855860091696, + -5.7197548270495195 + ], + [ + 39.30855930629429, + -5.7197653402595465 + ], + [ + 39.308681761828296, + -5.719765975317966 + ], + [ + 39.30868246720789, + -5.719776488527715 + ], + [ + 39.308804922742986, + -5.719777123559718 + ], + [ + 39.308805628124844, + -5.71978763676919 + ], + [ + 39.308927383917265, + -5.719788272151425 + ], + [ + 39.308928789045154, + -5.719798784983975 + ], + [ + 39.30905124458244, + -5.71979941996315 + ], + [ + 39.309056148807734, + -5.719810631816969 + ], + [ + 39.309923167539615, + -5.719877451244321 + ], + [ + 39.31063422293008, + -5.720091544007215 + ], + [ + 39.31065381500645, + -5.720090131590763 + ], + [ + 39.310662899577814, + -5.720067697687457 + ], + [ + 39.31067404178256, + -5.7199681630314965 + ], + [ + 39.31074121076393, + -5.719956211268805 + ], + [ + 39.31163696137919, + -5.720100813064275 + ], + [ + 39.311699250733554, + -5.720123208220514 + ], + [ + 39.31180561219929, + -5.720123851348939 + ], + [ + 39.311906387102475, + -5.720145524665541 + ], + [ + 39.311906393177225, + -5.720156739153791 + ], + [ + 39.31197216911476, + -5.720156703401592 + ], + [ + 39.31197427442288, + -5.720167916748612 + ], + [ + 39.31210233973633, + -5.720190276099752 + ], + [ + 39.31212192953011, + -5.720184658200196 + ], + [ + 39.3121295815013, + -5.720101246259322 + ], + [ + 39.31215196266817, + -5.720081608726603 + ], + [ + 39.31337307522748, + -5.720190284531242 + ], + [ + 39.3133506857093, + -5.720194502190286 + ], + [ + 39.31358511825828, + -5.720228017609581 + ], + [ + 39.313602918515315, + -5.740028584511519 + ] + ] + ], + "type": "Polygon" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "image": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/33cae6/33cae6.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "GeoTIFF" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "image": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/33cae6/33cae6.tif", - "type": "image/tiff; application=geotiff; profile=cloud-optimized", - "title": "GeoTIFF" - } - }, - "collection": "znz" + "bbox": [ + 39.287711527683925, + -5.743060299502631, + 39.31360456846548, + -5.719012276837555 + ], + "stac_extensions": [], + "collection": "znz" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/znz/3b20d4-labels/3b20d4-labels.json b/tests/data-files/catalogs/test-case-4/znz/3b20d4-labels/3b20d4-labels.json index de52a0fa0..32b53802c 100644 --- a/tests/data-files/catalogs/test-case-4/znz/3b20d4-labels/3b20d4-labels.json +++ b/tests/data-files/catalogs/test-case-4/znz/3b20d4-labels/3b20d4-labels.json @@ -1,92 +1,93 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "3b20d4-labels", - "properties": { - "label:description": "Geojson building labels for scene 3b20d4", - "area": "znz", - "label:type": "vector", - "label:properties": [ - "building" - ], - "label:overviews": [ - { - "property_key": "building", - "counts": [ - { - "name": "yes", - "count": 702 - } - ] - } - ], - "datetime": "2016-10-05T00:00:00Z", - "label:classes": [ - { - "name": "building", - "classes": [ - "yes" - ] - } - ] - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [ - 39.313582732137256, - -5.824334109106769 - ], - [ - 39.34087084324396, - -5.824386185654682 - ], - [ - 39.34092291979187, - -5.8517263733093 + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "3b20d4-labels", + "properties": { + "label:description": "Geojson building labels for scene 3b20d4", + "area": "znz", + "label:type": "vector", + "label:properties": [ + "building" ], - [ - 39.31347857904143, - -5.851778449857214 + "label:overviews": [ + { + "property_key": "building", + "counts": [ + { + "name": "yes", + "count": 702 + } + ] + } ], - [ - 39.313582732137256, - -5.824334109106769 + "datetime": "2016-10-05T00:00:00Z", + "label:classes": [ + { + "name": "building", + "classes": [ + "yes" + ] + } ] - ] - ] - }, - "bbox": [ - 39.31347857904143, - -5.851778449857214, - 39.34092291979187, - -5.824334109106769 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + 39.313582732137256, + -5.824334109106769 + ], + [ + 39.34087084324396, + -5.824386185654682 + ], + [ + 39.34092291979187, + -5.8517263733093 + ], + [ + 39.31347857904143, + -5.851778449857214 + ], + [ + 39.313582732137256, + -5.824334109106769 + ] + ] + ] + }, + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "labels": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/3b20d4-labels/3b20d4.geojson", + "type": "application/geo+json" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "labels": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/3b20d4-labels/3b20d4.geojson", - "type": "application/geo+json" - } - }, - "stac_extensions": [ - "label" - ] + "bbox": [ + 39.31347857904143, + -5.851778449857214, + 39.34092291979187, + -5.824334109106769 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "znz" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/znz/3b20d4/3b20d4.json b/tests/data-files/catalogs/test-case-4/znz/3b20d4/3b20d4.json index df27f835a..9a385cf3c 100644 --- a/tests/data-files/catalogs/test-case-4/znz/3b20d4/3b20d4.json +++ b/tests/data-files/catalogs/test-case-4/znz/3b20d4/3b20d4.json @@ -1,67 +1,68 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "3b20d4", - "properties": { - "area": "znz", - "datetime": "2016-10-05T00:00:00Z" - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [ - 39.313582732137256, - -5.824334109106769 - ], - [ - 39.34087084324396, - -5.824386185654682 - ], - [ - 39.34092291979187, - -5.8517263733093 - ], - [ - 39.31347857904143, - -5.851778449857214 - ], - [ - 39.313582732137256, - -5.824334109106769 + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "3b20d4", + "properties": { + "area": "znz", + "datetime": "2016-10-05T00:00:00Z" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + 39.313582732137256, + -5.824334109106769 + ], + [ + 39.34087084324396, + -5.824386185654682 + ], + [ + 39.34092291979187, + -5.8517263733093 + ], + [ + 39.31347857904143, + -5.851778449857214 + ], + [ + 39.313582732137256, + -5.824334109106769 + ] + ] ] - ] - ] - }, - "bbox": [ - 39.31347857904143, - -5.851778449857214, - 39.34092291979187, - -5.824334109106769 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "image": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/3b20d4/3b20d4.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "GeoTIFF" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "image": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/3b20d4/3b20d4.tif", - "type": "image/tiff; application=geotiff; profile=cloud-optimized", - "title": "GeoTIFF" - } - }, - "collection": "znz" + "bbox": [ + 39.31347857904143, + -5.851778449857214, + 39.34092291979187, + -5.824334109106769 + ], + "stac_extensions": [], + "collection": "znz" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/znz/3f8360-labels/3f8360-labels.json b/tests/data-files/catalogs/test-case-4/znz/3f8360-labels/3f8360-labels.json index 597f03962..4a0d84832 100644 --- a/tests/data-files/catalogs/test-case-4/znz/3f8360-labels/3f8360-labels.json +++ b/tests/data-files/catalogs/test-case-4/znz/3f8360-labels/3f8360-labels.json @@ -1,96 +1,97 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "3f8360-labels", - "properties": { - "label:description": "Geojson building labels for scene 3f8360", - "area": "znz", - "label:type": "vector", - "label:properties": [ - "building" - ], - "label:overviews": [ - { - "property_key": "building", - "counts": [ - { - "name": "yes", - "count": 1441 - } - ] - } - ], - "datetime": "2016-10-08T00:00:00Z", - "label:classes": [ - { - "name": "building", - "classes": [ - "yes" - ] - } - ] - }, - "geometry": { - "coordinates": [ - [ - [ - 39.36446538964943, - -5.9307731675787885 - ], - [ - 39.36446684258708, - -5.932986095454288 - ], - [ - 39.34081351509101, - -5.933001162750248 - ], - [ - 39.34079687232617, - -5.905835680371048 + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "3f8360-labels", + "properties": { + "label:description": "Geojson building labels for scene 3f8360", + "area": "znz", + "label:type": "vector", + "label:properties": [ + "building" ], - [ - 39.364449044832185, - -5.905820682536527 + "label:overviews": [ + { + "property_key": "building", + "counts": [ + { + "name": "yes", + "count": 1441 + } + ] + } ], - [ - 39.36446538964943, - -5.9307731675787885 + "datetime": "2016-10-08T00:00:00Z", + "label:classes": [ + { + "name": "building", + "classes": [ + "yes" + ] + } ] - ] - ], - "type": "Polygon" - }, - "bbox": [ - 39.34079687232617, - -5.933001162750248, - 39.36446684258708, - -5.905820682536527 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "geometry": { + "coordinates": [ + [ + [ + 39.36446538964943, + -5.9307731675787885 + ], + [ + 39.36446684258708, + -5.932986095454288 + ], + [ + 39.34081351509101, + -5.933001162750248 + ], + [ + 39.34079687232617, + -5.905835680371048 + ], + [ + 39.364449044832185, + -5.905820682536527 + ], + [ + 39.36446538964943, + -5.9307731675787885 + ] + ] + ], + "type": "Polygon" + }, + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "labels": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/3f8360-labels/3f8360.geojson", + "type": "application/geo+json" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "labels": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/3f8360-labels/3f8360.geojson", - "type": "application/geo+json" - } - }, - "stac_extensions": [ - "label" - ] + "bbox": [ + 39.34079687232617, + -5.933001162750248, + 39.36446684258708, + -5.905820682536527 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "znz" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/znz/3f8360/3f8360.json b/tests/data-files/catalogs/test-case-4/znz/3f8360/3f8360.json index f80e1ad34..e002c85c8 100644 --- a/tests/data-files/catalogs/test-case-4/znz/3f8360/3f8360.json +++ b/tests/data-files/catalogs/test-case-4/znz/3f8360/3f8360.json @@ -1,71 +1,72 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "3f8360", - "properties": { - "area": "znz", - "datetime": "2016-10-08T00:00:00Z" - }, - "geometry": { - "coordinates": [ - [ - [ - 39.36446538964943, - -5.9307731675787885 - ], - [ - 39.36446684258708, - -5.932986095454288 - ], - [ - 39.34081351509101, - -5.933001162750248 - ], - [ - 39.34079687232617, - -5.905835680371048 - ], - [ - 39.364449044832185, - -5.905820682536527 + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "3f8360", + "properties": { + "area": "znz", + "datetime": "2016-10-08T00:00:00Z" + }, + "geometry": { + "coordinates": [ + [ + [ + 39.36446538964943, + -5.9307731675787885 + ], + [ + 39.36446684258708, + -5.932986095454288 + ], + [ + 39.34081351509101, + -5.933001162750248 + ], + [ + 39.34079687232617, + -5.905835680371048 + ], + [ + 39.364449044832185, + -5.905820682536527 + ], + [ + 39.36446538964943, + -5.9307731675787885 + ] + ] ], - [ - 39.36446538964943, - -5.9307731675787885 - ] - ] - ], - "type": "Polygon" - }, - "bbox": [ - 39.34079687232617, - -5.933001162750248, - 39.36446684258708, - -5.905820682536527 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" + "type": "Polygon" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "image": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/3f8360/3f8360.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "GeoTIFF" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "image": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/3f8360/3f8360.tif", - "type": "image/tiff; application=geotiff; profile=cloud-optimized", - "title": "GeoTIFF" - } - }, - "collection": "znz" + "bbox": [ + 39.34079687232617, + -5.933001162750248, + 39.36446684258708, + -5.905820682536527 + ], + "stac_extensions": [], + "collection": "znz" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/znz/425403-labels/425403-labels.json b/tests/data-files/catalogs/test-case-4/znz/425403-labels/425403-labels.json index 34f6488e1..336ba134f 100644 --- a/tests/data-files/catalogs/test-case-4/znz/425403-labels/425403-labels.json +++ b/tests/data-files/catalogs/test-case-4/znz/425403-labels/425403-labels.json @@ -1,92 +1,93 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "425403-labels", - "properties": { - "label:description": "Geojson building labels for scene 425403", - "area": "znz", - "label:type": "vector", - "label:properties": [ - "building" - ], - "label:overviews": [ - { - "property_key": "building", - "counts": [ - { - "name": "yes", - "count": 224 - } - ] - } - ], - "datetime": "2016-10-10T00:00:00Z", - "label:classes": [ - { - "name": "building", - "classes": [ - "yes" - ] - } - ] - }, - "geometry": { - "coordinates": [ - [ - [ - 39.34082996500427, - -5.960158147553525 - ], - [ - 39.340813249870706, - -5.933001378219889 - ], - [ - 39.31371005982263, - -5.933017400605379 + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "425403-labels", + "properties": { + "label:description": "Geojson building labels for scene 425403", + "area": "znz", + "label:type": "vector", + "label:properties": [ + "building" ], - [ - 39.313725445739834, - -5.960174243786799 + "label:overviews": [ + { + "property_key": "building", + "counts": [ + { + "name": "yes", + "count": 224 + } + ] + } ], - [ - 39.34082996500427, - -5.960158147553525 + "datetime": "2016-10-10T00:00:00Z", + "label:classes": [ + { + "name": "building", + "classes": [ + "yes" + ] + } ] - ] - ], - "type": "Polygon" - }, - "bbox": [ - 39.31371005982263, - -5.960174243786799, - 39.34082996500427, - -5.933001378219889 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "geometry": { + "coordinates": [ + [ + [ + 39.34082996500427, + -5.960158147553525 + ], + [ + 39.340813249870706, + -5.933001378219889 + ], + [ + 39.31371005982263, + -5.933017400605379 + ], + [ + 39.313725445739834, + -5.960174243786799 + ], + [ + 39.34082996500427, + -5.960158147553525 + ] + ] + ], + "type": "Polygon" + }, + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "labels": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/425403-labels/425403.geojson", + "type": "application/geo+json" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "labels": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/425403-labels/425403.geojson", - "type": "application/geo+json" - } - }, - "stac_extensions": [ - "label" - ] + "bbox": [ + 39.31371005982263, + -5.960174243786799, + 39.34082996500427, + -5.933001378219889 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "znz" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/znz/425403/425403.json b/tests/data-files/catalogs/test-case-4/znz/425403/425403.json index 8109f3315..d15a6f17c 100644 --- a/tests/data-files/catalogs/test-case-4/znz/425403/425403.json +++ b/tests/data-files/catalogs/test-case-4/znz/425403/425403.json @@ -1,67 +1,68 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "425403", - "properties": { - "area": "znz", - "datetime": "2016-10-10T00:00:00Z" - }, - "geometry": { - "coordinates": [ - [ - [ - 39.34082996500427, - -5.960158147553525 - ], - [ - 39.340813249870706, - -5.933001378219889 - ], - [ - 39.31371005982263, - -5.933017400605379 - ], - [ - 39.313725445739834, - -5.960174243786799 + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "425403", + "properties": { + "area": "znz", + "datetime": "2016-10-10T00:00:00Z" + }, + "geometry": { + "coordinates": [ + [ + [ + 39.34082996500427, + -5.960158147553525 + ], + [ + 39.340813249870706, + -5.933001378219889 + ], + [ + 39.31371005982263, + -5.933017400605379 + ], + [ + 39.313725445739834, + -5.960174243786799 + ], + [ + 39.34082996500427, + -5.960158147553525 + ] + ] ], - [ - 39.34082996500427, - -5.960158147553525 - ] - ] - ], - "type": "Polygon" - }, - "bbox": [ - 39.31371005982263, - -5.960174243786799, - 39.34082996500427, - -5.933001378219889 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" + "type": "Polygon" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "image": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/425403/425403.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "GeoTIFF" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "image": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/425403/425403.tif", - "type": "image/tiff; application=geotiff; profile=cloud-optimized", - "title": "GeoTIFF" - } - }, - "collection": "znz" + "bbox": [ + 39.31371005982263, + -5.960174243786799, + 39.34082996500427, + -5.933001378219889 + ], + "stac_extensions": [], + "collection": "znz" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/znz/75cdfa-labels/75cdfa-labels.json b/tests/data-files/catalogs/test-case-4/znz/75cdfa-labels/75cdfa-labels.json index afa23c322..967f03394 100644 --- a/tests/data-files/catalogs/test-case-4/znz/75cdfa-labels/75cdfa-labels.json +++ b/tests/data-files/catalogs/test-case-4/znz/75cdfa-labels/75cdfa-labels.json @@ -1,96 +1,97 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "75cdfa-labels", - "properties": { - "label:description": "Geojson building labels for scene 75cdfa", - "area": "znz", - "label:type": "vector", - "label:properties": [ - "building" - ], - "label:overviews": [ - { - "property_key": "building", - "counts": [ - { - "name": "yes", - "count": 566 - } - ] - } - ], - "datetime": "2016-10-05T00:00:00Z", - "label:classes": [ - { - "name": "building", - "classes": [ - "yes" - ] - } - ] - }, - "geometry": { - "coordinates": [ - [ - [ - 39.31640547357606, - -5.878738481386144 - ], - [ - 39.31367952288209, - -5.8787400187081476 - ], - [ - 39.31366435148484, - -5.851583330154158 - ], - [ - 39.34076386428035, - -5.851567529006198 + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "75cdfa-labels", + "properties": { + "label:description": "Geojson building labels for scene 75cdfa", + "area": "znz", + "label:type": "vector", + "label:properties": [ + "building" ], - [ - 39.34078034637437, - -5.878724143732914 + "label:overviews": [ + { + "property_key": "building", + "counts": [ + { + "name": "yes", + "count": 566 + } + ] + } ], - [ - 39.31640547357606, - -5.878738481386144 + "datetime": "2016-10-05T00:00:00Z", + "label:classes": [ + { + "name": "building", + "classes": [ + "yes" + ] + } ] - ] - ], - "type": "Polygon" - }, - "bbox": [ - 39.31366435148484, - -5.8787400187081476, - 39.34078034637437, - -5.851567529006198 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "geometry": { + "coordinates": [ + [ + [ + 39.31640547357606, + -5.878738481386144 + ], + [ + 39.31367952288209, + -5.8787400187081476 + ], + [ + 39.31366435148484, + -5.851583330154158 + ], + [ + 39.34076386428035, + -5.851567529006198 + ], + [ + 39.34078034637437, + -5.878724143732914 + ], + [ + 39.31640547357606, + -5.878738481386144 + ] + ] + ], + "type": "Polygon" + }, + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "labels": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/75cdfa-labels/75cdfa.geojson", + "type": "application/geo+json" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "labels": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/75cdfa-labels/75cdfa.geojson", - "type": "application/geo+json" - } - }, - "stac_extensions": [ - "label" - ] + "bbox": [ + 39.31366435148484, + -5.8787400187081476, + 39.34078034637437, + -5.851567529006198 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "znz" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/znz/75cdfa/75cdfa.json b/tests/data-files/catalogs/test-case-4/znz/75cdfa/75cdfa.json index d107f3524..567f22d8d 100644 --- a/tests/data-files/catalogs/test-case-4/znz/75cdfa/75cdfa.json +++ b/tests/data-files/catalogs/test-case-4/znz/75cdfa/75cdfa.json @@ -1,71 +1,72 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "75cdfa", - "properties": { - "area": "znz", - "datetime": "2016-10-05T00:00:00Z" - }, - "geometry": { - "coordinates": [ - [ - [ - 39.31640547357606, - -5.878738481386144 - ], - [ - 39.31367952288209, - -5.8787400187081476 - ], - [ - 39.31366435148484, - -5.851583330154158 - ], - [ - 39.34076386428035, - -5.851567529006198 - ], - [ - 39.34078034637437, - -5.878724143732914 + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "75cdfa", + "properties": { + "area": "znz", + "datetime": "2016-10-05T00:00:00Z" + }, + "geometry": { + "coordinates": [ + [ + [ + 39.31640547357606, + -5.878738481386144 + ], + [ + 39.31367952288209, + -5.8787400187081476 + ], + [ + 39.31366435148484, + -5.851583330154158 + ], + [ + 39.34076386428035, + -5.851567529006198 + ], + [ + 39.34078034637437, + -5.878724143732914 + ], + [ + 39.31640547357606, + -5.878738481386144 + ] + ] ], - [ - 39.31640547357606, - -5.878738481386144 - ] - ] - ], - "type": "Polygon" - }, - "bbox": [ - 39.31366435148484, - -5.8787400187081476, - 39.34078034637437, - -5.851567529006198 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" + "type": "Polygon" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "image": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/75cdfa/75cdfa.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "GeoTIFF" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "image": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/75cdfa/75cdfa.tif", - "type": "image/tiff; application=geotiff; profile=cloud-optimized", - "title": "GeoTIFF" - } - }, - "collection": "znz" + "bbox": [ + 39.31366435148484, + -5.8787400187081476, + 39.34078034637437, + -5.851567529006198 + ], + "stac_extensions": [], + "collection": "znz" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/znz/9b8638-labels/9b8638-labels.json b/tests/data-files/catalogs/test-case-4/znz/9b8638-labels/9b8638-labels.json index 1a925a142..2483ad14e 100644 --- a/tests/data-files/catalogs/test-case-4/znz/9b8638-labels/9b8638-labels.json +++ b/tests/data-files/catalogs/test-case-4/znz/9b8638-labels/9b8638-labels.json @@ -1,148 +1,149 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "9b8638-labels", - "properties": { - "label:description": "Geojson building labels for scene 9b8638", - "area": "znz", - "label:type": "vector", - "label:properties": [ - "building" - ], - "label:overviews": [ - { - "property_key": "building", - "counts": [ - { - "name": "yes", - "count": 1612 - } - ] - } - ], - "datetime": "2016-10-04T00:00:00Z", - "label:classes": [ - { - "name": "building", - "classes": [ - "yes" + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "9b8638-labels", + "properties": { + "label:description": "Geojson building labels for scene 9b8638", + "area": "znz", + "label:type": "vector", + "label:properties": [ + "building" + ], + "label:overviews": [ + { + "property_key": "building", + "counts": [ + { + "name": "yes", + "count": 1612 + } + ] + } + ], + "datetime": "2016-10-04T00:00:00Z", + "label:classes": [ + { + "name": "building", + "classes": [ + "yes" + ] + } ] - } - ] - }, - "geometry": { - "coordinates": [ - [ - [ - 39.36017861532632, - -5.878613910758856 - ], - [ - 39.360158862698874, - -5.878711935371034 - ], - [ - 39.340780340086106, - -5.878724092981988 - ], - [ - 39.34076385802326, - -5.851567529009997 - ], - [ - 39.362418331025296, - -5.8515539621204695 - ], - [ - 39.362288479204956, - -5.858769648634405 - ], - [ - 39.3622848764889, - -5.858769650963058 - ], - [ - 39.362284870287944, - -5.858760030164733 - ], - [ - 39.362282468089724, - -5.858759430417258 - ], - [ - 39.36185063775144, - -5.864190652017378 - ], - [ - 39.36154486752859, - -5.867707853453685 - ], - [ - 39.36154424537411, - -5.867674181055383 - ], - [ - 39.361538262830855, - -5.867708459020328 - ], - [ - 39.36057452042873, - -5.86770847946345 - ], - [ - 39.36057837987134, - -5.8737124575003525 - ], - [ - 39.36102032449061, - -5.87371157100246 - ], - [ - 39.36102099271992, - -5.8738167980549205 - ], - [ - 39.360801036431035, - -5.876328569704563 - ], - [ - 39.36017861532632, - -5.878613910758856 - ] - ] - ], - "type": "Polygon" - }, - "bbox": [ - 39.34076385802326, - -5.878724092981988, - 39.362419204085, - -5.8515539621204695 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "geometry": { + "coordinates": [ + [ + [ + 39.36017861532632, + -5.878613910758856 + ], + [ + 39.360158862698874, + -5.878711935371034 + ], + [ + 39.340780340086106, + -5.878724092981988 + ], + [ + 39.34076385802326, + -5.851567529009997 + ], + [ + 39.362418331025296, + -5.8515539621204695 + ], + [ + 39.362288479204956, + -5.858769648634405 + ], + [ + 39.3622848764889, + -5.858769650963058 + ], + [ + 39.362284870287944, + -5.858760030164733 + ], + [ + 39.362282468089724, + -5.858759430417258 + ], + [ + 39.36185063775144, + -5.864190652017378 + ], + [ + 39.36154486752859, + -5.867707853453685 + ], + [ + 39.36154424537411, + -5.867674181055383 + ], + [ + 39.361538262830855, + -5.867708459020328 + ], + [ + 39.36057452042873, + -5.86770847946345 + ], + [ + 39.36057837987134, + -5.8737124575003525 + ], + [ + 39.36102032449061, + -5.87371157100246 + ], + [ + 39.36102099271992, + -5.8738167980549205 + ], + [ + 39.360801036431035, + -5.876328569704563 + ], + [ + 39.36017861532632, + -5.878613910758856 + ] + ] + ], + "type": "Polygon" + }, + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "labels": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/9b8638-labels/9b8638.geojson", + "type": "application/geo+json" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "labels": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/9b8638-labels/9b8638.geojson", - "type": "application/geo+json" - } - }, - "stac_extensions": [ - "label" - ] + "bbox": [ + 39.34076385802326, + -5.878724092981988, + 39.362419204085, + -5.8515539621204695 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "znz" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/znz/9b8638/9b8638.json b/tests/data-files/catalogs/test-case-4/znz/9b8638/9b8638.json index ec0746e74..421b75f92 100644 --- a/tests/data-files/catalogs/test-case-4/znz/9b8638/9b8638.json +++ b/tests/data-files/catalogs/test-case-4/znz/9b8638/9b8638.json @@ -1,123 +1,124 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "9b8638", - "properties": { - "area": "znz", - "datetime": "2016-10-04T00:00:00Z" - }, - "geometry": { - "coordinates": [ - [ - [ - 39.36017861532632, - -5.878613910758856 - ], - [ - 39.360158862698874, - -5.878711935371034 - ], - [ - 39.340780340086106, - -5.878724092981988 - ], - [ - 39.34076385802326, - -5.851567529009997 - ], - [ - 39.362418331025296, - -5.8515539621204695 - ], - [ - 39.362288479204956, - -5.858769648634405 - ], - [ - 39.3622848764889, - -5.858769650963058 - ], - [ - 39.362284870287944, - -5.858760030164733 - ], - [ - 39.362282468089724, - -5.858759430417258 - ], - [ - 39.36185063775144, - -5.864190652017378 - ], - [ - 39.36154486752859, - -5.867707853453685 - ], - [ - 39.36154424537411, - -5.867674181055383 - ], - [ - 39.361538262830855, - -5.867708459020328 - ], - [ - 39.36057452042873, - -5.86770847946345 - ], - [ - 39.36057837987134, - -5.8737124575003525 - ], - [ - 39.36102032449061, - -5.87371157100246 - ], - [ - 39.36102099271992, - -5.8738167980549205 - ], - [ - 39.360801036431035, - -5.876328569704563 - ], - [ - 39.36017861532632, - -5.878613910758856 - ] - ] - ], - "type": "Polygon" - }, - "bbox": [ - 39.34076385802326, - -5.878724092981988, - 39.362419204085, - -5.8515539621204695 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "9b8638", + "properties": { + "area": "znz", + "datetime": "2016-10-04T00:00:00Z" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "geometry": { + "coordinates": [ + [ + [ + 39.36017861532632, + -5.878613910758856 + ], + [ + 39.360158862698874, + -5.878711935371034 + ], + [ + 39.340780340086106, + -5.878724092981988 + ], + [ + 39.34076385802326, + -5.851567529009997 + ], + [ + 39.362418331025296, + -5.8515539621204695 + ], + [ + 39.362288479204956, + -5.858769648634405 + ], + [ + 39.3622848764889, + -5.858769650963058 + ], + [ + 39.362284870287944, + -5.858760030164733 + ], + [ + 39.362282468089724, + -5.858759430417258 + ], + [ + 39.36185063775144, + -5.864190652017378 + ], + [ + 39.36154486752859, + -5.867707853453685 + ], + [ + 39.36154424537411, + -5.867674181055383 + ], + [ + 39.361538262830855, + -5.867708459020328 + ], + [ + 39.36057452042873, + -5.86770847946345 + ], + [ + 39.36057837987134, + -5.8737124575003525 + ], + [ + 39.36102032449061, + -5.87371157100246 + ], + [ + 39.36102099271992, + -5.8738167980549205 + ], + [ + 39.360801036431035, + -5.876328569704563 + ], + [ + 39.36017861532632, + -5.878613910758856 + ] + ] + ], + "type": "Polygon" }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "image": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/9b8638/9b8638.tif", - "type": "image/tiff; application=geotiff; profile=cloud-optimized", - "title": "GeoTIFF" - } - }, - "collection": "znz" + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "image": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/9b8638/9b8638.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "GeoTIFF" + } + }, + "bbox": [ + 39.34076385802326, + -5.878724092981988, + 39.362419204085, + -5.8515539621204695 + ], + "stac_extensions": [], + "collection": "znz" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/znz/aee7fd-labels/aee7fd-labels.json b/tests/data-files/catalogs/test-case-4/znz/aee7fd-labels/aee7fd-labels.json index 8a45872d3..4db538c37 100644 --- a/tests/data-files/catalogs/test-case-4/znz/aee7fd-labels/aee7fd-labels.json +++ b/tests/data-files/catalogs/test-case-4/znz/aee7fd-labels/aee7fd-labels.json @@ -1,96 +1,97 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "aee7fd-labels", - "properties": { - "label:description": "Geojson building labels for scene aee7fd", - "area": "znz", - "label:type": "vector", - "label:properties": [ - "building" - ], - "label:overviews": [ - { - "property_key": "building", - "counts": [ - { - "name": "yes", - "count": 551 - } - ] - } - ], - "datetime": "2016-10-08T00:00:00Z", - "label:classes": [ - { - "name": "building", - "classes": [ - "yes" - ] - } - ] - }, - "geometry": { - "coordinates": [ - [ - [ - 39.31705255429268, - -5.933015462962362 - ], - [ - 39.31371062447159, - -5.933017366868187 - ], - [ - 39.31369530504979, - -5.905851628735563 - ], - [ - 39.340797668473954, - -5.905835679883141 + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "aee7fd-labels", + "properties": { + "label:description": "Geojson building labels for scene aee7fd", + "area": "znz", + "label:type": "vector", + "label:properties": [ + "building" ], - [ - 39.340814311389366, - -5.933001344149245 + "label:overviews": [ + { + "property_key": "building", + "counts": [ + { + "name": "yes", + "count": 551 + } + ] + } ], - [ - 39.31705255429268, - -5.933015462962362 + "datetime": "2016-10-08T00:00:00Z", + "label:classes": [ + { + "name": "building", + "classes": [ + "yes" + ] + } ] - ] - ], - "type": "Polygon" - }, - "bbox": [ - 39.31369530504979, - -5.933017366868187, - 39.340814311389366, - -5.905835679883141 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "geometry": { + "coordinates": [ + [ + [ + 39.31705255429268, + -5.933015462962362 + ], + [ + 39.31371062447159, + -5.933017366868187 + ], + [ + 39.31369530504979, + -5.905851628735563 + ], + [ + 39.340797668473954, + -5.905835679883141 + ], + [ + 39.340814311389366, + -5.933001344149245 + ], + [ + 39.31705255429268, + -5.933015462962362 + ] + ] + ], + "type": "Polygon" + }, + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "labels": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/aee7fd-labels/aee7fd.geojson", + "type": "application/geo+json" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "labels": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/aee7fd-labels/aee7fd.geojson", - "type": "application/geo+json" - } - }, - "stac_extensions": [ - "label" - ] + "bbox": [ + 39.31369530504979, + -5.933017366868187, + 39.340814311389366, + -5.905835679883141 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "znz" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/znz/aee7fd/aee7fd.json b/tests/data-files/catalogs/test-case-4/znz/aee7fd/aee7fd.json index 8aab01c82..fc130af26 100644 --- a/tests/data-files/catalogs/test-case-4/znz/aee7fd/aee7fd.json +++ b/tests/data-files/catalogs/test-case-4/znz/aee7fd/aee7fd.json @@ -1,71 +1,72 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "aee7fd", - "properties": { - "area": "znz", - "datetime": "2016-10-08T00:00:00Z" - }, - "geometry": { - "coordinates": [ - [ - [ - 39.31705255429268, - -5.933015462962362 - ], - [ - 39.31371062447159, - -5.933017366868187 - ], - [ - 39.31369530504979, - -5.905851628735563 - ], - [ - 39.340797668473954, - -5.905835679883141 - ], - [ - 39.340814311389366, - -5.933001344149245 + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "aee7fd", + "properties": { + "area": "znz", + "datetime": "2016-10-08T00:00:00Z" + }, + "geometry": { + "coordinates": [ + [ + [ + 39.31705255429268, + -5.933015462962362 + ], + [ + 39.31371062447159, + -5.933017366868187 + ], + [ + 39.31369530504979, + -5.905851628735563 + ], + [ + 39.340797668473954, + -5.905835679883141 + ], + [ + 39.340814311389366, + -5.933001344149245 + ], + [ + 39.31705255429268, + -5.933015462962362 + ] + ] ], - [ - 39.31705255429268, - -5.933015462962362 - ] - ] - ], - "type": "Polygon" - }, - "bbox": [ - 39.31369530504979, - -5.933017366868187, - 39.340814311389366, - -5.905835679883141 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" + "type": "Polygon" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "image": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/aee7fd/aee7fd.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "GeoTIFF" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "image": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/aee7fd/aee7fd.tif", - "type": "image/tiff; application=geotiff; profile=cloud-optimized", - "title": "GeoTIFF" - } - }, - "collection": "znz" + "bbox": [ + 39.31369530504979, + -5.933017366868187, + 39.340814311389366, + -5.905835679883141 + ], + "stac_extensions": [], + "collection": "znz" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/znz/bc32f1-labels/bc32f1-labels.json b/tests/data-files/catalogs/test-case-4/znz/bc32f1-labels/bc32f1-labels.json index 07e7a2efc..44efd7d87 100644 --- a/tests/data-files/catalogs/test-case-4/znz/bc32f1-labels/bc32f1-labels.json +++ b/tests/data-files/catalogs/test-case-4/znz/bc32f1-labels/bc32f1-labels.json @@ -1,96 +1,97 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "bc32f1-labels", - "properties": { - "label:description": "Geojson building labels for scene bc32f1", - "area": "znz", - "label:type": "vector", - "label:properties": [ - "building" - ], - "label:overviews": [ - { - "property_key": "building", - "counts": [ - { - "name": "yes", - "count": 97 - } - ] - } - ], - "datetime": "2016-10-12T00:00:00Z", - "label:classes": [ - { - "name": "building", - "classes": [ - "yes" - ] - } - ] - }, - "geometry": { - "coordinates": [ - [ - [ - 39.344219970219626, - -5.987276061137261 - ], - [ - 39.340847000464755, - -5.987278166971163 - ], - [ - 39.34083023028068, - -5.960158002925742 - ], - [ - 39.36793404669621, - -5.960140574104503 + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "bc32f1-labels", + "properties": { + "label:description": "Geojson building labels for scene bc32f1", + "area": "znz", + "label:type": "vector", + "label:properties": [ + "building" ], - [ - 39.36795215042373, - -5.987260658288568 + "label:overviews": [ + { + "property_key": "building", + "counts": [ + { + "name": "yes", + "count": 97 + } + ] + } ], - [ - 39.344219970219626, - -5.987276061137261 + "datetime": "2016-10-12T00:00:00Z", + "label:classes": [ + { + "name": "building", + "classes": [ + "yes" + ] + } ] - ] - ], - "type": "Polygon" - }, - "bbox": [ - 39.34083023028068, - -5.987278166971163, - 39.36795215042373, - -5.960140574104503 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "geometry": { + "coordinates": [ + [ + [ + 39.344219970219626, + -5.987276061137261 + ], + [ + 39.340847000464755, + -5.987278166971163 + ], + [ + 39.34083023028068, + -5.960158002925742 + ], + [ + 39.36793404669621, + -5.960140574104503 + ], + [ + 39.36795215042373, + -5.987260658288568 + ], + [ + 39.344219970219626, + -5.987276061137261 + ] + ] + ], + "type": "Polygon" + }, + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "labels": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/bc32f1-labels/bc32f1.geojson", + "type": "application/geo+json" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "labels": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/bc32f1-labels/bc32f1.geojson", - "type": "application/geo+json" - } - }, - "stac_extensions": [ - "label" - ] + "bbox": [ + 39.34083023028068, + -5.987278166971163, + 39.36795215042373, + -5.960140574104503 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "znz" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/znz/bc32f1/bc32f1.json b/tests/data-files/catalogs/test-case-4/znz/bc32f1/bc32f1.json index 726b4c15c..1d2709183 100644 --- a/tests/data-files/catalogs/test-case-4/znz/bc32f1/bc32f1.json +++ b/tests/data-files/catalogs/test-case-4/znz/bc32f1/bc32f1.json @@ -1,71 +1,72 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "bc32f1", - "properties": { - "area": "znz", - "datetime": "2016-10-12T00:00:00Z" - }, - "geometry": { - "coordinates": [ - [ - [ - 39.344219970219626, - -5.987276061137261 - ], - [ - 39.340847000464755, - -5.987278166971163 - ], - [ - 39.34083023028068, - -5.960158002925742 - ], - [ - 39.36793404669621, - -5.960140574104503 - ], - [ - 39.36795215042373, - -5.987260658288568 + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "bc32f1", + "properties": { + "area": "znz", + "datetime": "2016-10-12T00:00:00Z" + }, + "geometry": { + "coordinates": [ + [ + [ + 39.344219970219626, + -5.987276061137261 + ], + [ + 39.340847000464755, + -5.987278166971163 + ], + [ + 39.34083023028068, + -5.960158002925742 + ], + [ + 39.36793404669621, + -5.960140574104503 + ], + [ + 39.36795215042373, + -5.987260658288568 + ], + [ + 39.344219970219626, + -5.987276061137261 + ] + ] ], - [ - 39.344219970219626, - -5.987276061137261 - ] - ] - ], - "type": "Polygon" - }, - "bbox": [ - 39.34083023028068, - -5.987278166971163, - 39.36795215042373, - -5.960140574104503 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" + "type": "Polygon" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "image": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/bc32f1/bc32f1.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "GeoTIFF" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "image": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/bc32f1/bc32f1.tif", - "type": "image/tiff; application=geotiff; profile=cloud-optimized", - "title": "GeoTIFF" - } - }, - "collection": "znz" + "bbox": [ + 39.34083023028068, + -5.987278166971163, + 39.36795215042373, + -5.960140574104503 + ], + "stac_extensions": [], + "collection": "znz" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/znz/bd5c14-labels/bd5c14-labels.json b/tests/data-files/catalogs/test-case-4/znz/bd5c14-labels/bd5c14-labels.json index 8c46a71d5..766476c23 100644 --- a/tests/data-files/catalogs/test-case-4/znz/bd5c14-labels/bd5c14-labels.json +++ b/tests/data-files/catalogs/test-case-4/znz/bd5c14-labels/bd5c14-labels.json @@ -1,96 +1,97 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "bd5c14-labels", - "properties": { - "label:description": "Geojson building labels for scene bd5c14", - "area": "znz", - "label:type": "vector", - "label:properties": [ - "building" - ], - "label:overviews": [ - { - "property_key": "building", - "counts": [ - { - "name": "yes", - "count": 781 - } - ] - } - ], - "datetime": "2016-10-11T00:00:00Z", - "label:classes": [ - { - "name": "building", - "classes": [ - "yes" - ] - } - ] - }, - "geometry": { - "coordinates": [ - [ - [ - 39.367932205551796, - -5.957816165919622 - ], - [ - 39.367933753210345, - -5.960140452755652 - ], - [ - 39.3408296655117, - -5.960157881729879 - ], - [ - 39.34081295055692, - -5.9330013784041595 + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "bd5c14-labels", + "properties": { + "label:description": "Geojson building labels for scene bd5c14", + "area": "znz", + "label:type": "vector", + "label:properties": [ + "building" ], - [ - 39.36791570908837, - -5.932984029391401 + "label:overviews": [ + { + "property_key": "building", + "counts": [ + { + "name": "yes", + "count": 781 + } + ] + } ], - [ - 39.367932205551796, - -5.957816165919622 + "datetime": "2016-10-11T00:00:00Z", + "label:classes": [ + { + "name": "building", + "classes": [ + "yes" + ] + } ] - ] - ], - "type": "Polygon" - }, - "bbox": [ - 39.34081295055692, - -5.960157881729879, - 39.367933753210345, - -5.932984029391401 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "geometry": { + "coordinates": [ + [ + [ + 39.367932205551796, + -5.957816165919622 + ], + [ + 39.367933753210345, + -5.960140452755652 + ], + [ + 39.3408296655117, + -5.960157881729879 + ], + [ + 39.34081295055692, + -5.9330013784041595 + ], + [ + 39.36791570908837, + -5.932984029391401 + ], + [ + 39.367932205551796, + -5.957816165919622 + ] + ] + ], + "type": "Polygon" + }, + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "labels": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/bd5c14-labels/bd5c14.geojson", + "type": "application/geo+json" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "labels": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/bd5c14-labels/bd5c14.geojson", - "type": "application/geo+json" - } - }, - "stac_extensions": [ - "label" - ] + "bbox": [ + 39.34081295055692, + -5.960157881729879, + 39.367933753210345, + -5.932984029391401 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "znz" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/znz/bd5c14/bd5c14.json b/tests/data-files/catalogs/test-case-4/znz/bd5c14/bd5c14.json index 659a087d5..19cad7c97 100644 --- a/tests/data-files/catalogs/test-case-4/znz/bd5c14/bd5c14.json +++ b/tests/data-files/catalogs/test-case-4/znz/bd5c14/bd5c14.json @@ -1,71 +1,72 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "bd5c14", - "properties": { - "area": "znz", - "datetime": "2016-10-11T00:00:00Z" - }, - "geometry": { - "coordinates": [ - [ - [ - 39.367932205551796, - -5.957816165919622 - ], - [ - 39.367933753210345, - -5.960140452755652 - ], - [ - 39.3408296655117, - -5.960157881729879 - ], - [ - 39.34081295055692, - -5.9330013784041595 - ], - [ - 39.36791570908837, - -5.932984029391401 + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "bd5c14", + "properties": { + "area": "znz", + "datetime": "2016-10-11T00:00:00Z" + }, + "geometry": { + "coordinates": [ + [ + [ + 39.367932205551796, + -5.957816165919622 + ], + [ + 39.367933753210345, + -5.960140452755652 + ], + [ + 39.3408296655117, + -5.960157881729879 + ], + [ + 39.34081295055692, + -5.9330013784041595 + ], + [ + 39.36791570908837, + -5.932984029391401 + ], + [ + 39.367932205551796, + -5.957816165919622 + ] + ] ], - [ - 39.367932205551796, - -5.957816165919622 - ] - ] - ], - "type": "Polygon" - }, - "bbox": [ - 39.34081295055692, - -5.960157881729879, - 39.367933753210345, - -5.932984029391401 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" + "type": "Polygon" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "image": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/bd5c14/bd5c14.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "GeoTIFF" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "image": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/bd5c14/bd5c14.tif", - "type": "image/tiff; application=geotiff; profile=cloud-optimized", - "title": "GeoTIFF" - } - }, - "collection": "znz" + "bbox": [ + 39.34081295055692, + -5.960157881729879, + 39.367933753210345, + -5.932984029391401 + ], + "stac_extensions": [], + "collection": "znz" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/znz/c7415c-labels/c7415c-labels.json b/tests/data-files/catalogs/test-case-4/znz/c7415c-labels/c7415c-labels.json index e658a7245..08497f0e7 100644 --- a/tests/data-files/catalogs/test-case-4/znz/c7415c-labels/c7415c-labels.json +++ b/tests/data-files/catalogs/test-case-4/znz/c7415c-labels/c7415c-labels.json @@ -1,96 +1,97 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "c7415c-labels", - "properties": { - "label:description": "Geojson building labels for scene c7415c", - "area": "znz", - "label:type": "vector", - "label:properties": [ - "building" - ], - "label:overviews": [ - { - "property_key": "building", - "counts": [ - { - "name": "yes", - "count": 949 - } - ] - } - ], - "datetime": "2016-09-21T00:00:00Z", - "label:classes": [ - { - "name": "building", - "classes": [ - "yes" - ] - } - ] - }, - "geometry": { - "coordinates": [ - [ - [ - 39.36029029677782, - -5.904972600767203 - ], - [ - 39.360290846530575, - -5.9058234437561135 - ], - [ - 39.34079687235772, - -5.9058357319970805 - ], - [ - 39.340780340171506, - -5.878724233360191 + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "c7415c-labels", + "properties": { + "label:description": "Geojson building labels for scene c7415c", + "area": "znz", + "label:type": "vector", + "label:properties": [ + "building" ], - [ - 39.36027336873274, - -5.878712001912929 + "label:overviews": [ + { + "property_key": "building", + "counts": [ + { + "name": "yes", + "count": 949 + } + ] + } ], - [ - 39.36029029677782, - -5.904972600767203 + "datetime": "2016-09-21T00:00:00Z", + "label:classes": [ + { + "name": "building", + "classes": [ + "yes" + ] + } ] - ] - ], - "type": "Polygon" - }, - "bbox": [ - 39.340780340171506, - -5.9058357319970805, - 39.360290846530575, - -5.878712001912929 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "geometry": { + "coordinates": [ + [ + [ + 39.36029029677782, + -5.904972600767203 + ], + [ + 39.360290846530575, + -5.9058234437561135 + ], + [ + 39.34079687235772, + -5.9058357319970805 + ], + [ + 39.340780340171506, + -5.878724233360191 + ], + [ + 39.36027336873274, + -5.878712001912929 + ], + [ + 39.36029029677782, + -5.904972600767203 + ] + ] + ], + "type": "Polygon" + }, + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "labels": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/c7415c-labels/c7415c.geojson", + "type": "application/geo+json" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "labels": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/c7415c-labels/c7415c.geojson", - "type": "application/geo+json" - } - }, - "stac_extensions": [ - "label" - ] + "bbox": [ + 39.340780340171506, + -5.9058357319970805, + 39.360290846530575, + -5.878712001912929 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "znz" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/znz/c7415c/c7415c.json b/tests/data-files/catalogs/test-case-4/znz/c7415c/c7415c.json index 5a694d191..9c7991b75 100644 --- a/tests/data-files/catalogs/test-case-4/znz/c7415c/c7415c.json +++ b/tests/data-files/catalogs/test-case-4/znz/c7415c/c7415c.json @@ -1,71 +1,72 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "c7415c", - "properties": { - "area": "znz", - "datetime": "2016-09-21T00:00:00Z" - }, - "geometry": { - "coordinates": [ - [ - [ - 39.36029029677782, - -5.904972600767203 - ], - [ - 39.360290846530575, - -5.9058234437561135 - ], - [ - 39.34079687235772, - -5.9058357319970805 - ], - [ - 39.340780340171506, - -5.878724233360191 - ], - [ - 39.36027336873274, - -5.878712001912929 + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "c7415c", + "properties": { + "area": "znz", + "datetime": "2016-09-21T00:00:00Z" + }, + "geometry": { + "coordinates": [ + [ + [ + 39.36029029677782, + -5.904972600767203 + ], + [ + 39.360290846530575, + -5.9058234437561135 + ], + [ + 39.34079687235772, + -5.9058357319970805 + ], + [ + 39.340780340171506, + -5.878724233360191 + ], + [ + 39.36027336873274, + -5.878712001912929 + ], + [ + 39.36029029677782, + -5.904972600767203 + ] + ] ], - [ - 39.36029029677782, - -5.904972600767203 - ] - ] - ], - "type": "Polygon" - }, - "bbox": [ - 39.340780340171506, - -5.9058357319970805, - 39.360290846530575, - -5.878712001912929 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" + "type": "Polygon" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "image": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/c7415c/c7415c.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "GeoTIFF" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "image": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/c7415c/c7415c.tif", - "type": "image/tiff; application=geotiff; profile=cloud-optimized", - "title": "GeoTIFF" - } - }, - "collection": "znz" + "bbox": [ + 39.340780340171506, + -5.9058357319970805, + 39.360290846530575, + -5.878712001912929 + ], + "stac_extensions": [], + "collection": "znz" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/znz/collection.json b/tests/data-files/catalogs/test-case-4/znz/collection.json index 13c466783..a974a7e9a 100644 --- a/tests/data-files/catalogs/test-case-4/znz/collection.json +++ b/tests/data-files/catalogs/test-case-4/znz/collection.json @@ -1,6 +1,7 @@ { + "type": "Collection", "id": "znz", - "stac_version": "1.0.0-beta.2", + "stac_version": "1.0.0-rc.3", "description": "Tier 1 training data from znz", "links": [ { @@ -144,6 +145,7 @@ "type": "application/json" } ], + "stac_extensions": [], "extent": { "spatial": { "bbox": [ @@ -164,8 +166,5 @@ ] } }, - "license": "CC-BY-4.0", - "stac_extensions": [ - "label" - ] + "license": "CC-BY-4.0" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/znz/e52478-labels/e52478-labels.json b/tests/data-files/catalogs/test-case-4/znz/e52478-labels/e52478-labels.json index 56d1953b0..a8437dbc7 100644 --- a/tests/data-files/catalogs/test-case-4/znz/e52478-labels/e52478-labels.json +++ b/tests/data-files/catalogs/test-case-4/znz/e52478-labels/e52478-labels.json @@ -1,96 +1,97 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "e52478-labels", - "properties": { - "label:description": "Geojson building labels for scene e52478", - "area": "znz", - "label:type": "vector", - "label:properties": [ - "building" - ], - "label:overviews": [ - { - "property_key": "building", - "counts": [ - { - "name": "yes", - "count": 21 - } - ] - } - ], - "datetime": "2016-11-05T00:00:00Z", - "label:classes": [ - { - "name": "building", - "classes": [ - "yes" - ] - } - ] - }, - "geometry": { - "coordinates": [ - [ - [ - 39.37891355673581, - -5.959065689521422 - ], - [ - 39.378914288970435, - -5.960133384034927 - ], - [ - 39.367933808083876, - -5.9601408243123455 - ], - [ - 39.36791576371174, - -5.932984029355098 + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "e52478-labels", + "properties": { + "label:description": "Geojson building labels for scene e52478", + "area": "znz", + "label:type": "vector", + "label:properties": [ + "building" ], - [ - 39.37889570611965, - -5.9329766232129995 + "label:overviews": [ + { + "property_key": "building", + "counts": [ + { + "name": "yes", + "count": 21 + } + ] + } ], - [ - 39.37891355673581, - -5.959065689521422 + "datetime": "2016-11-05T00:00:00Z", + "label:classes": [ + { + "name": "building", + "classes": [ + "yes" + ] + } ] - ] - ], - "type": "Polygon" - }, - "bbox": [ - 39.36791576371174, - -5.9601408243123455, - 39.378914288970435, - -5.9329766232129995 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "geometry": { + "coordinates": [ + [ + [ + 39.37891355673581, + -5.959065689521422 + ], + [ + 39.378914288970435, + -5.960133384034927 + ], + [ + 39.367933808083876, + -5.9601408243123455 + ], + [ + 39.36791576371174, + -5.932984029355098 + ], + [ + 39.37889570611965, + -5.9329766232129995 + ], + [ + 39.37891355673581, + -5.959065689521422 + ] + ] + ], + "type": "Polygon" + }, + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "labels": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/e52478-labels/e52478.geojson", + "type": "application/geo+json" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "labels": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/e52478-labels/e52478.geojson", - "type": "application/geo+json" - } - }, - "stac_extensions": [ - "label" - ] + "bbox": [ + 39.36791576371174, + -5.9601408243123455, + 39.378914288970435, + -5.9329766232129995 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "znz" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-4/znz/e52478/e52478.json b/tests/data-files/catalogs/test-case-4/znz/e52478/e52478.json index e1a89b2fa..1632da701 100644 --- a/tests/data-files/catalogs/test-case-4/znz/e52478/e52478.json +++ b/tests/data-files/catalogs/test-case-4/znz/e52478/e52478.json @@ -1,71 +1,72 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "e52478", - "properties": { - "area": "znz", - "datetime": "2016-11-05T00:00:00Z" - }, - "geometry": { - "coordinates": [ - [ - [ - 39.37891355673581, - -5.959065689521422 - ], - [ - 39.378914288970435, - -5.960133384034927 - ], - [ - 39.367933808083876, - -5.9601408243123455 - ], - [ - 39.36791576371174, - -5.932984029355098 - ], - [ - 39.37889570611965, - -5.9329766232129995 + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "e52478", + "properties": { + "area": "znz", + "datetime": "2016-11-05T00:00:00Z" + }, + "geometry": { + "coordinates": [ + [ + [ + 39.37891355673581, + -5.959065689521422 + ], + [ + 39.378914288970435, + -5.960133384034927 + ], + [ + 39.367933808083876, + -5.9601408243123455 + ], + [ + 39.36791576371174, + -5.932984029355098 + ], + [ + 39.37889570611965, + -5.9329766232129995 + ], + [ + 39.37891355673581, + -5.959065689521422 + ] + ] ], - [ - 39.37891355673581, - -5.959065689521422 - ] - ] - ], - "type": "Polygon" - }, - "bbox": [ - 39.36791576371174, - -5.9601408243123455, - 39.378914288970435, - -5.9329766232129995 - ], - "links": [ - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" + "type": "Polygon" }, - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" + "links": [ + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "image": { + "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/e52478/e52478.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "GeoTIFF" + } }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": { - "image": { - "href": "https://drivendata-competition-building-segmentation.s3-us-west-1.amazonaws.com/train_tier_1/znz/e52478/e52478.tif", - "type": "image/tiff; application=geotiff; profile=cloud-optimized", - "title": "GeoTIFF" - } - }, - "collection": "znz" + "bbox": [ + 39.36791576371174, + -5.9601408243123455, + 39.378914288970435, + -5.9329766232129995 + ], + "stac_extensions": [], + "collection": "znz" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-5/CBERS4/CBERS4MUX/CBERS4-MUX-027/CBERS4-MUX-027/069/CBERS_4_MUX_20190510_027_069_L2/CBERS_4_MUX_20190510_027_069_L2.json b/tests/data-files/catalogs/test-case-5/CBERS4/CBERS4MUX/CBERS4-MUX-027/CBERS4-MUX-027/069/CBERS_4_MUX_20190510_027_069_L2/CBERS_4_MUX_20190510_027_069_L2.json index 7e90bee86..6c1adf870 100644 --- a/tests/data-files/catalogs/test-case-5/CBERS4/CBERS4MUX/CBERS4-MUX-027/CBERS4-MUX-027/069/CBERS_4_MUX_20190510_027_069_L2/CBERS_4_MUX_20190510_027_069_L2.json +++ b/tests/data-files/catalogs/test-case-5/CBERS4/CBERS4MUX/CBERS4-MUX-027/CBERS4-MUX-027/069/CBERS_4_MUX_20190510_027_069_L2/CBERS_4_MUX_20190510_027_069_L2.json @@ -1,108 +1,146 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "CBERS_4_MUX_20190510_027_069_L2", - "properties": { - "datetime": "2019-05-10T04:29:23Z", - "cbers:data_type": "L2", - "cbers:path": 27, - "cbers:row": 69, - "eo:epsg": 32687, - "eo:off_nadir": 0.00239349, - "eo:sun_azimuth": 110.943, - "eo:sun_elevation": 66.3097 - }, - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 87.532508, - 27.297172 - ], - [ - 88.734927, - 27.111523 - ], - [ - 89.018294, - 28.168944 - ], - [ - 87.804272, - 28.356352 - ], - [ - 87.532508, - 27.297172 - ] - ] - ] - ] - }, - "bbox": [ - 87.52967, - 27.111179, - 89.025681, - 28.3637 - ], - "links": [ - { - "rel": "collection", - "href": "../../collection.json" - }, - { - "rel": "root", - "href": "../../../../../../catalog.json", - "type": "application/json" - }, - { - "rel": "parent", - "href": "../catalog.json", - "type": "application/json" - } - ], - "assets": { - "thumbnail": { - "href": "https://s3.amazonaws.com/cbers-meta-pds/CBERS4/MUX/027/069/CBERS_4_MUX_20190510_027_069_L2/CBERS_4_MUX_20190510_027_069.jpg", - "type": "image/jpeg" + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "CBERS_4_MUX_20190510_027_069_L2", + "properties": { + "gsd": 20.0, + "platform": "CBERS-4", + "instruments": [ + "MUX" + ], + "eo:bands": [ + { + "name": "B5", + "common_name": "blue" + }, + { + "name": "B6", + "common_name": "green" + }, + { + "name": "B7", + "common_name": "red" + }, + { + "name": "B8", + "common_name": "nir" + } + ], + "datetime": "2019-05-10T04:29:23Z", + "cbers:data_type": "L2", + "cbers:path": 27, + "cbers:row": 69, + "proj:epsg": 32687, + "view:off_nadir": 0.00239349, + "view:sun_azimuth": 110.943, + "view:sun_elevation": 66.3097 }, - "metadata": { - "href": "s3://cbers-pds/CBERS4/MUX/027/069/CBERS_4_MUX_20190510_027_069_L2/CBERS_4_MUX_20190510_027_069_L2_BAND6.xml", - "type": "text/xml", - "title": "INPE original metadata" - }, - "B5": { - "href": "s3://cbers-pds/CBERS4/MUX/027/069/CBERS_4_MUX_20190510_027_069_L2/CBERS_4_MUX_20190510_027_069_L2_BAND5.tif", - "type": "image/vnd.stac.geotiff; cloud-optimized=true", - "eo:bands": [ - 0 - ] - }, - "B6": { - "href": "s3://cbers-pds/CBERS4/MUX/027/069/CBERS_4_MUX_20190510_027_069_L2/CBERS_4_MUX_20190510_027_069_L2_BAND6.tif", - "type": "image/vnd.stac.geotiff; cloud-optimized=true", - "eo:bands": [ - 1 - ] + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [ + 87.532508, + 27.297172 + ], + [ + 88.734927, + 27.111523 + ], + [ + 89.018294, + 28.168944 + ], + [ + 87.804272, + 28.356352 + ], + [ + 87.532508, + 27.297172 + ] + ] + ] + ] }, - "B7": { - "href": "s3://cbers-pds/CBERS4/MUX/027/069/CBERS_4_MUX_20190510_027_069_L2/CBERS_4_MUX_20190510_027_069_L2_BAND7.tif", - "type": "image/vnd.stac.geotiff; cloud-optimized=true", - "eo:bands": [ - 2 - ] + "links": [ + { + "rel": "collection", + "href": "../../collection.json" + }, + { + "rel": "root", + "href": "../../../../../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../catalog.json", + "type": "application/json" + } + ], + "assets": { + "thumbnail": { + "href": "https://s3.amazonaws.com/cbers-meta-pds/CBERS4/MUX/027/069/CBERS_4_MUX_20190510_027_069_L2/CBERS_4_MUX_20190510_027_069.jpg", + "type": "image/jpeg" + }, + "metadata": { + "href": "s3://cbers-pds/CBERS4/MUX/027/069/CBERS_4_MUX_20190510_027_069_L2/CBERS_4_MUX_20190510_027_069_L2_BAND6.xml", + "type": "text/xml", + "title": "INPE original metadata" + }, + "B5": { + "href": "s3://cbers-pds/CBERS4/MUX/027/069/CBERS_4_MUX_20190510_027_069_L2/CBERS_4_MUX_20190510_027_069_L2_BAND5.tif", + "type": "image/vnd.stac.geotiff; cloud-optimized=true", + "eo:bands": [ + { + "name": "B5", + "common_name": "blue" + } + ] + }, + "B6": { + "href": "s3://cbers-pds/CBERS4/MUX/027/069/CBERS_4_MUX_20190510_027_069_L2/CBERS_4_MUX_20190510_027_069_L2_BAND6.tif", + "type": "image/vnd.stac.geotiff; cloud-optimized=true", + "eo:bands": [ + { + "name": "B6", + "common_name": "green" + } + ] + }, + "B7": { + "href": "s3://cbers-pds/CBERS4/MUX/027/069/CBERS_4_MUX_20190510_027_069_L2/CBERS_4_MUX_20190510_027_069_L2_BAND7.tif", + "type": "image/vnd.stac.geotiff; cloud-optimized=true", + "eo:bands": [ + { + "name": "B7", + "common_name": "red" + } + ] + }, + "B8": { + "href": "s3://cbers-pds/CBERS4/MUX/027/069/CBERS_4_MUX_20190510_027_069_L2/CBERS_4_MUX_20190510_027_069_L2_BAND8.tif", + "type": "image/vnd.stac.geotiff; cloud-optimized=true", + "eo:bands": [ + { + "name": "B8", + "common_name": "nir" + } + ] + } }, - "B8": { - "href": "s3://cbers-pds/CBERS4/MUX/027/069/CBERS_4_MUX_20190510_027_069_L2/CBERS_4_MUX_20190510_027_069_L2_BAND8.tif", - "type": "image/vnd.stac.geotiff; cloud-optimized=true", - "eo:bands": [ - 3 - ] - } - }, - "stac_extensions": [ - "eo" - ] + "bbox": [ + 87.52967, + 27.111179, + 89.025681, + 28.3637 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/eo/v1.0.0/schema.json", + "https://stac-extensions.github.io/projection/v1.0.0/schema.json", + "https://stac-extensions.github.io/view/v1.0.0/schema.json" + ], + "collection": "CBERS4MUX" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-5/CBERS4/CBERS4MUX/CBERS4-MUX-027/CBERS4-MUX-027/069/catalog.json b/tests/data-files/catalogs/test-case-5/CBERS4/CBERS4MUX/CBERS4-MUX-027/CBERS4-MUX-027/069/catalog.json index a1b066b80..71471f1de 100644 --- a/tests/data-files/catalogs/test-case-5/CBERS4/CBERS4MUX/CBERS4-MUX-027/CBERS4-MUX-027/069/catalog.json +++ b/tests/data-files/catalogs/test-case-5/CBERS4/CBERS4MUX/CBERS4-MUX-027/CBERS4-MUX-027/069/catalog.json @@ -1,6 +1,7 @@ { + "type": "Catalog", "id": "CBERS4 MUX 027/069", - "stac_version": "1.0.0-beta.2", + "stac_version": "1.0.0-rc.3", "description": "CBERS4 MUX camera path 027 row 069 catalog", "links": [ { @@ -18,5 +19,6 @@ "href": "../../catalog.json", "type": "application/json" } - ] + ], + "stac_extensions": [] } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-5/CBERS4/CBERS4MUX/CBERS4-MUX-027/CBERS4-MUX-027/collection.json b/tests/data-files/catalogs/test-case-5/CBERS4/CBERS4MUX/CBERS4-MUX-027/CBERS4-MUX-027/collection.json index 3501cd2c6..c3824daa2 100644 --- a/tests/data-files/catalogs/test-case-5/CBERS4/CBERS4MUX/CBERS4-MUX-027/CBERS4-MUX-027/collection.json +++ b/tests/data-files/catalogs/test-case-5/CBERS4/CBERS4MUX/CBERS4-MUX-027/CBERS4-MUX-027/collection.json @@ -1,6 +1,7 @@ { - "stac_version": "1.0.0-beta.2", + "type": "Collection", "id": "CBERS4MUX", + "stac_version": "1.0.0-rc.3", "description": "CBERS4 MUX camera catalog", "links": [ { @@ -16,7 +17,7 @@ "href": "069/catalog.json" } ], - "license": "CC-BY-SA-3.0", + "stac_extensions": [], "providers": [ { "name": "Instituto Nacional de Pesquisas Espaciais, INPE", @@ -27,10 +28,10 @@ }, { "name": "AMS Kepler", + "description": "Convert INPE's original TIFF to COG and copy to Amazon Web Services", "roles": [ "processor" ], - "description": "Convert INPE's original TIFF to COG and copy to Amazon Web Services", "url": "https://github.com/fredliporace/cbers-on-aws" }, { @@ -41,18 +42,6 @@ "url": "https://registry.opendata.aws/cbers/" } ], - "extent": { - "spatial": [ - -180.0, - -83.0, - 180.0, - 83.0 - ], - "temporal": [ - "2014-12-08T00:00:00Z", - null - ] - }, "properties": { "eo:gsd": 20.0, "eo:platform": "CBERS-4", @@ -75,5 +64,26 @@ "common_name": "nir" } ] - } + }, + "extent": { + "spatial": { + "bbox": [ + [ + -180.0, + -83.0, + 180.0, + 83.0 + ] + ] + }, + "temporal": { + "interval": [ + [ + "2014-12-08T00:00:00Z", + null + ] + ] + } + }, + "license": "CC-BY-SA-3.0" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-5/CBERS4/CBERS4MUX/CBERS4-MUX-027/catalog.json b/tests/data-files/catalogs/test-case-5/CBERS4/CBERS4MUX/CBERS4-MUX-027/catalog.json index 1451bdd28..9f4061521 100644 --- a/tests/data-files/catalogs/test-case-5/CBERS4/CBERS4MUX/CBERS4-MUX-027/catalog.json +++ b/tests/data-files/catalogs/test-case-5/CBERS4/CBERS4MUX/CBERS4-MUX-027/catalog.json @@ -1,6 +1,7 @@ { + "type": "Catalog", "id": "CBERS4 MUX 027", - "stac_version": "1.0.0-beta.2", + "stac_version": "1.0.0-rc.3", "description": "CBERS4 MUX camera path 027 catalog", "links": [ { @@ -18,5 +19,6 @@ "href": "../collection.json", "type": "application/json" } - ] -} + ], + "stac_extensions": [] +} \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-5/CBERS4/CBERS4MUX/collection.json b/tests/data-files/catalogs/test-case-5/CBERS4/CBERS4MUX/collection.json index 2315bd5ab..574ffdf77 100644 --- a/tests/data-files/catalogs/test-case-5/CBERS4/CBERS4MUX/collection.json +++ b/tests/data-files/catalogs/test-case-5/CBERS4/CBERS4MUX/collection.json @@ -1,6 +1,7 @@ { + "type": "Collection", "id": "CBERS4MUX", - "stac_version": "1.0.0-beta.2", + "stac_version": "1.0.0-rc.3", "description": "CBERS4 MUX camera catalog", "links": [ { @@ -19,27 +20,6 @@ "type": "application/json" } ], - "extent": { - "spatial": { - "bbox": [ - [ - -180.0, - -83.0, - 180.0, - 83.0 - ] - ] - }, - "temporal": { - "interval": [ - [ - "2014-12-08T00:00:00Z", - null - ] - ] - } - }, - "license": "CC-BY-SA-3.0", "stac_extensions": [], "providers": [ { @@ -65,27 +45,25 @@ "url": "https://registry.opendata.aws/cbers/" } ], - "properties": { - "eo:gsd": 20.0, - "eo:platform": "CBERS-4", - "eo:instrument": "MUX", - "eo:bands": [ - { - "name": "B5", - "common_name": "blue" - }, - { - "name": "B6", - "common_name": "green" - }, - { - "name": "B7", - "common_name": "red" - }, - { - "name": "B8", - "common_name": "nir" - } - ] - } -} + "extent": { + "spatial": { + "bbox": [ + [ + -180.0, + -83.0, + 180.0, + 83.0 + ] + ] + }, + "temporal": { + "interval": [ + [ + "2014-12-08T00:00:00Z", + null + ] + ] + } + }, + "license": "CC-BY-SA-3.0" +} \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-5/CBERS4/catalog.json b/tests/data-files/catalogs/test-case-5/CBERS4/catalog.json index 303b0a8d7..1992938ae 100644 --- a/tests/data-files/catalogs/test-case-5/CBERS4/catalog.json +++ b/tests/data-files/catalogs/test-case-5/CBERS4/catalog.json @@ -1,6 +1,7 @@ { + "type": "Catalog", "id": "CBERS4", - "stac_version": "1.0.0-beta.2", + "stac_version": "1.0.0-rc.3", "description": "Catalogs of CBERS-4 mission's imagery on AWS", "links": [ { @@ -18,5 +19,6 @@ "href": "../catalog.json", "type": "application/json" } - ] + ], + "stac_extensions": [] } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-5/catalog.json b/tests/data-files/catalogs/test-case-5/catalog.json index 3c4b838fb..ddf80e8d9 100644 --- a/tests/data-files/catalogs/test-case-5/catalog.json +++ b/tests/data-files/catalogs/test-case-5/catalog.json @@ -1,6 +1,7 @@ { + "type": "Catalog", "id": "CBERS", - "stac_version": "1.0.0-beta.2", + "stac_version": "1.0.0-rc.3", "description": "Catalogs of CBERS mission's imagery on AWS", "links": [ { @@ -14,5 +15,6 @@ "type": "application/json" } ], + "stac_extensions": [], "title": "CBERS 4 on AWS" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/400c22e3-5b54-438b-b600-5e9bd6d0a498/3c67b59c-2e6f-47fb-ba3c-0dd106941096.json b/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/400c22e3-5b54-438b-b600-5e9bd6d0a498/3c67b59c-2e6f-47fb-ba3c-0dd106941096.json index 14876501e..b22202b1b 100644 --- a/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/400c22e3-5b54-438b-b600-5e9bd6d0a498/3c67b59c-2e6f-47fb-ba3c-0dd106941096.json +++ b/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/400c22e3-5b54-438b-b600-5e9bd6d0a498/3c67b59c-2e6f-47fb-ba3c-0dd106941096.json @@ -1,10 +1,50 @@ { - "id": "3c67b59c-2e6f-47fb-ba3c-0dd106941096", - "stac_version": "1.0.0-beta.2", - "stac_extensions": [ - "label" - ], "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "3c67b59c-2e6f-47fb-ba3c-0dd106941096", + "properties": { + "label:description": "Labels in layer", + "label:type": "vector", + "datetime": "2019-08-21T15:51:17.881000Z", + "label:method": [ + "manual" + ], + "label:classes": [ + { + "name": "Coverage", + "classes": [ + "Obstructed", + "0-10%", + "11-50%", + "51-90%", + "91-100%" + ] + }, + { + "name": "Data Quality", + "classes": [ + "Bad", + "Good" + ] + }, + { + "name": "Alignment", + "classes": [ + "Obstructed/Unknown", + "< 90% overlap", + "\u2265 90% overlap" + ] + } + ], + "label:task": [ + "classification" + ], + "label:property": [ + "Coverage", + "Data Quality", + "Alignment" + ] + }, "geometry": { "type": "Polygon", "coordinates": [ @@ -4002,37 +4042,31 @@ ] ] }, - "bbox": [ - 39.191417450329524, - -6.892441704534412, - 39.34885007331245, - -6.729678190172387 - ], "links": [ { - "href": "./collection.json", "rel": "parent", + "href": "./collection.json", "type": "application/json", "title": "Label Collection", "label:assets": [] }, { - "href": "./collection.json", "rel": "collection", + "href": "./collection.json", "type": "application/json", "title": "Label Collection", "label:assets": [] }, { - "href": "../../catalog.json", "rel": "root", + "href": "../../catalog.json", "type": "application/json", "title": "Root", "label:assets": [] }, { - "href": "../9420e0fd-3731-40e8-93ff-5b6ad0067048/3bfb5bd3-5740-4ed0-92c9-968cc532dbc5.json", "rel": "source", + "href": "../9420e0fd-3731-40e8-93ff-5b6ad0067048/3bfb5bd3-5740-4ed0-92c9-968cc532dbc5.json", "type": "image/vnd.stac.geotiff; cloud-optimized=true", "title": "Source image STAC item for the label item", "label:assets": [ @@ -4040,8 +4074,8 @@ ] }, { - "href": "../9420e0fd-3731-40e8-93ff-5b6ad0067048/41c57cea-50ba-495c-9ee7-17ddba837380.json", "rel": "source", + "href": "../9420e0fd-3731-40e8-93ff-5b6ad0067048/41c57cea-50ba-495c-9ee7-17ddba837380.json", "type": "image/vnd.stac.geotiff; cloud-optimized=true", "title": "Source image STAC item for the label item", "label:assets": [ @@ -4049,8 +4083,8 @@ ] }, { - "href": "../9420e0fd-3731-40e8-93ff-5b6ad0067048/4514bbc6-cd17-4c14-816d-1709dfc61079.json", "rel": "source", + "href": "../9420e0fd-3731-40e8-93ff-5b6ad0067048/4514bbc6-cd17-4c14-816d-1709dfc61079.json", "type": "image/vnd.stac.geotiff; cloud-optimized=true", "title": "Source image STAC item for the label item", "label:assets": [ @@ -4058,8 +4092,8 @@ ] }, { - "href": "../9420e0fd-3731-40e8-93ff-5b6ad0067048/52072b95-0275-4255-be5e-c567006f80cb.json", "rel": "source", + "href": "../9420e0fd-3731-40e8-93ff-5b6ad0067048/52072b95-0275-4255-be5e-c567006f80cb.json", "type": "image/vnd.stac.geotiff; cloud-optimized=true", "title": "Source image STAC item for the label item", "label:assets": [ @@ -4067,8 +4101,8 @@ ] }, { - "href": "../9420e0fd-3731-40e8-93ff-5b6ad0067048/84fe42c0-9d23-404a-bd0f-1406112cca8c.json", "rel": "source", + "href": "../9420e0fd-3731-40e8-93ff-5b6ad0067048/84fe42c0-9d23-404a-bd0f-1406112cca8c.json", "type": "image/vnd.stac.geotiff; cloud-optimized=true", "title": "Source image STAC item for the label item", "label:assets": [ @@ -4076,8 +4110,8 @@ ] }, { - "href": "../9420e0fd-3731-40e8-93ff-5b6ad0067048/884a939d-1d73-4351-9601-f9ee89a980b0.json", "rel": "source", + "href": "../9420e0fd-3731-40e8-93ff-5b6ad0067048/884a939d-1d73-4351-9601-f9ee89a980b0.json", "type": "image/vnd.stac.geotiff; cloud-optimized=true", "title": "Source image STAC item for the label item", "label:assets": [ @@ -4085,8 +4119,8 @@ ] }, { - "href": "../9420e0fd-3731-40e8-93ff-5b6ad0067048/a6bd2ff9-3805-40ab-96fa-b7f112b18973.json", "rel": "source", + "href": "../9420e0fd-3731-40e8-93ff-5b6ad0067048/a6bd2ff9-3805-40ab-96fa-b7f112b18973.json", "type": "image/vnd.stac.geotiff; cloud-optimized=true", "title": "Source image STAC item for the label item", "label:assets": [ @@ -4094,8 +4128,8 @@ ] }, { - "href": "../9420e0fd-3731-40e8-93ff-5b6ad0067048/e40bb30d-0295-42ed-ba04-6cf563b057f9.json", "rel": "source", + "href": "../9420e0fd-3731-40e8-93ff-5b6ad0067048/e40bb30d-0295-42ed-ba04-6cf563b057f9.json", "type": "image/vnd.stac.geotiff; cloud-optimized=true", "title": "Source image STAC item for the label item", "label:assets": [ @@ -4103,8 +4137,8 @@ ] }, { - "href": "../9420e0fd-3731-40e8-93ff-5b6ad0067048/eb1124cc-3b45-4487-bc2c-4855ac877ad9.json", "rel": "source", + "href": "../9420e0fd-3731-40e8-93ff-5b6ad0067048/eb1124cc-3b45-4487-bc2c-4855ac877ad9.json", "type": "image/vnd.stac.geotiff; cloud-optimized=true", "title": "Source image STAC item for the label item", "label:assets": [ @@ -4115,52 +4149,18 @@ "assets": { "3c67b59c-2e6f-47fb-ba3c-0dd106941096": { "href": "./data.geojson", - "title": "Label Data Feature Collection", - "type": "application/geo+json" + "type": "application/geo+json", + "title": "Label Data Feature Collection" } }, - "collection": "400c22e3-5b54-438b-b600-5e9bd6d0a498", - "properties": { - "label:description": "Labels in layer", - "label:type": "vector", - "datetime": "2019-08-21T15:51:17.881Z", - "label:method": [ - "manual" - ], - "label:classes": [ - { - "name": "Coverage", - "classes": [ - "Obstructed", - "0-10%", - "11-50%", - "51-90%", - "91-100%" - ] - }, - { - "name": "Data Quality", - "classes": [ - "Bad", - "Good" - ] - }, - { - "name": "Alignment", - "classes": [ - "Obstructed/Unknown", - "< 90% overlap", - "\u2265 90% overlap" - ] - } - ], - "label:task": [ - "classification" - ], - "label:property": [ - "Coverage", - "Data Quality", - "Alignment" - ] - } + "bbox": [ + 39.191417450329524, + -6.892441704534412, + 39.34885007331245, + -6.729678190172387 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/label/v1.0.0/schema.json" + ], + "collection": "400c22e3-5b54-438b-b600-5e9bd6d0a498" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/400c22e3-5b54-438b-b600-5e9bd6d0a498/collection.json b/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/400c22e3-5b54-438b-b600-5e9bd6d0a498/collection.json index 1c353b1bb..b9c746c92 100644 --- a/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/400c22e3-5b54-438b-b600-5e9bd6d0a498/collection.json +++ b/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/400c22e3-5b54-438b-b600-5e9bd6d0a498/collection.json @@ -1,12 +1,39 @@ { - "stac_version": "1.0.0-beta.2", + "type": "Collection", "id": "400c22e3-5b54-438b-b600-5e9bd6d0a498", - "title": "Label Collection", + "stac_version": "1.0.0-rc.3", "description": "Label Collection in layer 12cb17a8-ae08-469c-a2be-4d0619240014", + "links": [ + { + "rel": "item", + "href": "./3c67b59c-2e6f-47fb-ba3c-0dd106941096.json", + "type": "application/json", + "label:assets": [] + }, + { + "rel": "license", + "href": "http://www.apache.org/licenses/LICENSE-2.0", + "label:assets": [] + }, + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json", + "title": "Layer Collection", + "label:assets": [] + } + ], + "stac_extensions": [], + "title": "Label Collection", "keywords": [], "version": "1", - "license": "Apache-2.0", "providers": [], + "properties": {}, "extent": { "spatial": { "bbox": [ @@ -21,38 +48,11 @@ "temporal": { "interval": [ [ - "2019-08-21T15:51:17.881Z", - "2019-08-21T15:51:17.881Z" + "2019-08-21T15:51:17.881000Z", + "2019-08-21T15:51:17.881000Z" ] ] } }, - "properties": {}, - "links": [ - { - "href": "./3c67b59c-2e6f-47fb-ba3c-0dd106941096.json", - "rel": "item", - "type": "application/json", - "label:assets": [] - }, - { - "href": "http://www.apache.org/licenses/LICENSE-2.0", - "rel": "license", - "label:assets": [] - }, - { - "href": "../../catalog.json", - "rel": "root", - "type": "application/json", - "title": "Root", - "label:assets": [] - }, - { - "href": "../collection.json", - "rel": "parent", - "type": "application/json", - "title": "Layer Collection", - "label:assets": [] - } - ] + "license": "Apache-2.0" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/9420e0fd-3731-40e8-93ff-5b6ad0067048/3bfb5bd3-5740-4ed0-92c9-968cc532dbc5.json b/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/9420e0fd-3731-40e8-93ff-5b6ad0067048/3bfb5bd3-5740-4ed0-92c9-968cc532dbc5.json index 31fa600f6..9e45044ca 100644 --- a/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/9420e0fd-3731-40e8-93ff-5b6ad0067048/3bfb5bd3-5740-4ed0-92c9-968cc532dbc5.json +++ b/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/9420e0fd-3731-40e8-93ff-5b6ad0067048/3bfb5bd3-5740-4ed0-92c9-968cc532dbc5.json @@ -1,8 +1,10 @@ { - "id": "3bfb5bd3-5740-4ed0-92c9-968cc532dbc5", - "stac_version": "1.0.0-beta.2", - "stac_extensions": [], "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "3bfb5bd3-5740-4ed0-92c9-968cc532dbc5", + "properties": { + "datetime": "2019-08-21T15:51:17.881000Z" + }, "geometry": { "type": "MultiPolygon", "coordinates": [ @@ -32,30 +34,24 @@ ] ] }, - "bbox": [ - 39.191471485924936, - -6.873418639717923, - 39.26232911919128, - -6.8025353342930215 - ], "links": [ { - "href": "./collection.json", "rel": "parent", + "href": "./collection.json", "type": "application/json", "title": "Scene Collection", "label:assets": [] }, { - "href": "./collection.json", "rel": "collection", + "href": "./collection.json", "type": "application/json", "title": "Scene Collection", "label:assets": [] }, { - "href": "../../catalog.json", "rel": "root", + "href": "../../catalog.json", "type": "application/json", "title": "Root", "label:assets": [] @@ -64,12 +60,16 @@ "assets": { "3bfb5bd3-5740-4ed0-92c9-968cc532dbc5": { "href": "s3://rasterfoundry-production-data-us-east-1/user-uploads/auth0|5c4201f36b7b7c0da8243313/3bfb5bd3-5740-4ed0-92c9-968cc532dbc5/cog.tif", - "title": "scene", - "type": "image/vnd.stac.geotiff; cloud-optimized=true" + "type": "image/vnd.stac.geotiff; cloud-optimized=true", + "title": "scene" } }, - "collection": "9420e0fd-3731-40e8-93ff-5b6ad0067048", - "properties": { - "datetime": "2019-08-21T15:51:17.881" - } + "bbox": [ + 39.191471485924936, + -6.873418639717923, + 39.26232911919128, + -6.8025353342930215 + ], + "stac_extensions": [], + "collection": "9420e0fd-3731-40e8-93ff-5b6ad0067048" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/9420e0fd-3731-40e8-93ff-5b6ad0067048/41c57cea-50ba-495c-9ee7-17ddba837380.json b/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/9420e0fd-3731-40e8-93ff-5b6ad0067048/41c57cea-50ba-495c-9ee7-17ddba837380.json index 1cc1791d5..fc75910e4 100644 --- a/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/9420e0fd-3731-40e8-93ff-5b6ad0067048/41c57cea-50ba-495c-9ee7-17ddba837380.json +++ b/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/9420e0fd-3731-40e8-93ff-5b6ad0067048/41c57cea-50ba-495c-9ee7-17ddba837380.json @@ -1,8 +1,10 @@ { - "id": "41c57cea-50ba-495c-9ee7-17ddba837380", - "stac_version": "1.0.0-beta.2", - "stac_extensions": [], "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "41c57cea-50ba-495c-9ee7-17ddba837380", + "properties": { + "datetime": "2019-08-21T15:51:17.881000Z" + }, "geometry": { "type": "MultiPolygon", "coordinates": [ @@ -32,30 +34,24 @@ ] ] }, - "bbox": [ - 39.26232911919128, - -6.88620244952769, - 39.33324512902654, - -6.873418639717923 - ], "links": [ { - "href": "./collection.json", "rel": "parent", + "href": "./collection.json", "type": "application/json", "title": "Scene Collection", "label:assets": [] }, { - "href": "./collection.json", "rel": "collection", + "href": "./collection.json", "type": "application/json", "title": "Scene Collection", "label:assets": [] }, { - "href": "../../catalog.json", "rel": "root", + "href": "../../catalog.json", "type": "application/json", "title": "Root", "label:assets": [] @@ -64,12 +60,16 @@ "assets": { "41c57cea-50ba-495c-9ee7-17ddba837380": { "href": "s3://rasterfoundry-production-data-us-east-1/user-uploads/auth0|5c4201f36b7b7c0da8243313/41c57cea-50ba-495c-9ee7-17ddba837380/cog.tif", - "title": "scene", - "type": "image/vnd.stac.geotiff; cloud-optimized=true" + "type": "image/vnd.stac.geotiff; cloud-optimized=true", + "title": "scene" } }, - "collection": "9420e0fd-3731-40e8-93ff-5b6ad0067048", - "properties": { - "datetime": "2019-08-21T15:51:17.881" - } + "bbox": [ + 39.26232911919128, + -6.88620244952769, + 39.33324512902654, + -6.873418639717923 + ], + "stac_extensions": [], + "collection": "9420e0fd-3731-40e8-93ff-5b6ad0067048" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/9420e0fd-3731-40e8-93ff-5b6ad0067048/4514bbc6-cd17-4c14-816d-1709dfc61079.json b/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/9420e0fd-3731-40e8-93ff-5b6ad0067048/4514bbc6-cd17-4c14-816d-1709dfc61079.json index 100a2a41a..da107ace6 100644 --- a/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/9420e0fd-3731-40e8-93ff-5b6ad0067048/4514bbc6-cd17-4c14-816d-1709dfc61079.json +++ b/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/9420e0fd-3731-40e8-93ff-5b6ad0067048/4514bbc6-cd17-4c14-816d-1709dfc61079.json @@ -1,8 +1,10 @@ { - "id": "4514bbc6-cd17-4c14-816d-1709dfc61079", - "stac_version": "1.0.0-beta.2", - "stac_extensions": [], "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "4514bbc6-cd17-4c14-816d-1709dfc61079", + "properties": { + "datetime": "2019-08-21T15:51:17.881000Z" + }, "geometry": { "type": "MultiPolygon", "coordinates": [ @@ -32,30 +34,24 @@ ] ] }, - "bbox": [ - 39.33324512902654, - -6.8025353342930215, - 39.3484066149445, - -6.731655507762342 - ], "links": [ { - "href": "./collection.json", "rel": "parent", + "href": "./collection.json", "type": "application/json", "title": "Scene Collection", "label:assets": [] }, { - "href": "./collection.json", "rel": "collection", + "href": "./collection.json", "type": "application/json", "title": "Scene Collection", "label:assets": [] }, { - "href": "../../catalog.json", "rel": "root", + "href": "../../catalog.json", "type": "application/json", "title": "Root", "label:assets": [] @@ -64,12 +60,16 @@ "assets": { "4514bbc6-cd17-4c14-816d-1709dfc61079": { "href": "s3://rasterfoundry-production-data-us-east-1/user-uploads/auth0|5c4201f36b7b7c0da8243313/4514bbc6-cd17-4c14-816d-1709dfc61079/cog.tif", - "title": "scene", - "type": "image/vnd.stac.geotiff; cloud-optimized=true" + "type": "image/vnd.stac.geotiff; cloud-optimized=true", + "title": "scene" } }, - "collection": "9420e0fd-3731-40e8-93ff-5b6ad0067048", - "properties": { - "datetime": "2019-08-21T15:51:17.881" - } + "bbox": [ + 39.33324512902654, + -6.8025353342930215, + 39.3484066149445, + -6.731655507762342 + ], + "stac_extensions": [], + "collection": "9420e0fd-3731-40e8-93ff-5b6ad0067048" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/9420e0fd-3731-40e8-93ff-5b6ad0067048/52072b95-0275-4255-be5e-c567006f80cb.json b/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/9420e0fd-3731-40e8-93ff-5b6ad0067048/52072b95-0275-4255-be5e-c567006f80cb.json index 5d1047ce8..97e5024b9 100644 --- a/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/9420e0fd-3731-40e8-93ff-5b6ad0067048/52072b95-0275-4255-be5e-c567006f80cb.json +++ b/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/9420e0fd-3731-40e8-93ff-5b6ad0067048/52072b95-0275-4255-be5e-c567006f80cb.json @@ -1,8 +1,10 @@ { - "id": "52072b95-0275-4255-be5e-c567006f80cb", - "stac_version": "1.0.0-beta.2", - "stac_extensions": [], "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "52072b95-0275-4255-be5e-c567006f80cb", + "properties": { + "datetime": "2019-08-21T15:51:17.881000Z" + }, "geometry": { "type": "MultiPolygon", "coordinates": [ @@ -32,30 +34,24 @@ ] ] }, - "bbox": [ - 39.19141745032953, - -6.892441704534412, - 39.26232911919128, - -6.873418639717923 - ], "links": [ { - "href": "./collection.json", "rel": "parent", + "href": "./collection.json", "type": "application/json", "title": "Scene Collection", "label:assets": [] }, { - "href": "./collection.json", "rel": "collection", + "href": "./collection.json", "type": "application/json", "title": "Scene Collection", "label:assets": [] }, { - "href": "../../catalog.json", "rel": "root", + "href": "../../catalog.json", "type": "application/json", "title": "Root", "label:assets": [] @@ -64,12 +60,16 @@ "assets": { "52072b95-0275-4255-be5e-c567006f80cb": { "href": "s3://rasterfoundry-production-data-us-east-1/user-uploads/auth0|5c4201f36b7b7c0da8243313/52072b95-0275-4255-be5e-c567006f80cb/cog.tif", - "title": "scene", - "type": "image/vnd.stac.geotiff; cloud-optimized=true" + "type": "image/vnd.stac.geotiff; cloud-optimized=true", + "title": "scene" } }, - "collection": "9420e0fd-3731-40e8-93ff-5b6ad0067048", - "properties": { - "datetime": "2019-08-21T15:51:17.881" - } + "bbox": [ + 39.19141745032953, + -6.892441704534412, + 39.26232911919128, + -6.873418639717923 + ], + "stac_extensions": [], + "collection": "9420e0fd-3731-40e8-93ff-5b6ad0067048" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/9420e0fd-3731-40e8-93ff-5b6ad0067048/84fe42c0-9d23-404a-bd0f-1406112cca8c.json b/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/9420e0fd-3731-40e8-93ff-5b6ad0067048/84fe42c0-9d23-404a-bd0f-1406112cca8c.json index 32a36ec77..e5d95103c 100644 --- a/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/9420e0fd-3731-40e8-93ff-5b6ad0067048/84fe42c0-9d23-404a-bd0f-1406112cca8c.json +++ b/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/9420e0fd-3731-40e8-93ff-5b6ad0067048/84fe42c0-9d23-404a-bd0f-1406112cca8c.json @@ -1,8 +1,10 @@ { - "id": "84fe42c0-9d23-404a-bd0f-1406112cca8c", - "stac_version": "1.0.0-beta.2", - "stac_extensions": [], "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "84fe42c0-9d23-404a-bd0f-1406112cca8c", + "properties": { + "datetime": "2019-08-21T15:51:17.881000Z" + }, "geometry": { "type": "MultiPolygon", "coordinates": [ @@ -32,30 +34,24 @@ ] ] }, - "bbox": [ - 39.33324512902654, - -6.873418639717923, - 39.34866053761873, - -6.8025353342930215 - ], "links": [ { - "href": "./collection.json", "rel": "parent", + "href": "./collection.json", "type": "application/json", "title": "Scene Collection", "label:assets": [] }, { - "href": "./collection.json", "rel": "collection", + "href": "./collection.json", "type": "application/json", "title": "Scene Collection", "label:assets": [] }, { - "href": "../../catalog.json", "rel": "root", + "href": "../../catalog.json", "type": "application/json", "title": "Root", "label:assets": [] @@ -64,12 +60,16 @@ "assets": { "84fe42c0-9d23-404a-bd0f-1406112cca8c": { "href": "s3://rasterfoundry-production-data-us-east-1/user-uploads/auth0|5c4201f36b7b7c0da8243313/84fe42c0-9d23-404a-bd0f-1406112cca8c/cog.tif", - "title": "scene", - "type": "image/vnd.stac.geotiff; cloud-optimized=true" + "type": "image/vnd.stac.geotiff; cloud-optimized=true", + "title": "scene" } }, - "collection": "9420e0fd-3731-40e8-93ff-5b6ad0067048", - "properties": { - "datetime": "2019-08-21T15:51:17.881" - } + "bbox": [ + 39.33324512902654, + -6.873418639717923, + 39.34866053761873, + -6.8025353342930215 + ], + "stac_extensions": [], + "collection": "9420e0fd-3731-40e8-93ff-5b6ad0067048" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/9420e0fd-3731-40e8-93ff-5b6ad0067048/884a939d-1d73-4351-9601-f9ee89a980b0.json b/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/9420e0fd-3731-40e8-93ff-5b6ad0067048/884a939d-1d73-4351-9601-f9ee89a980b0.json index 0b0be1415..7805c1d82 100644 --- a/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/9420e0fd-3731-40e8-93ff-5b6ad0067048/884a939d-1d73-4351-9601-f9ee89a980b0.json +++ b/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/9420e0fd-3731-40e8-93ff-5b6ad0067048/884a939d-1d73-4351-9601-f9ee89a980b0.json @@ -1,8 +1,10 @@ { - "id": "884a939d-1d73-4351-9601-f9ee89a980b0", - "stac_version": "1.0.0-beta.2", - "stac_extensions": [], "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "884a939d-1d73-4351-9601-f9ee89a980b0", + "properties": { + "datetime": "2019-08-21T15:51:17.881000Z" + }, "geometry": { "type": "MultiPolygon", "coordinates": [ @@ -32,30 +34,24 @@ ] ] }, - "bbox": [ - 39.26232911919128, - -6.873418639717923, - 39.33324512902654, - -6.8025353342930215 - ], "links": [ { - "href": "./collection.json", "rel": "parent", + "href": "./collection.json", "type": "application/json", "title": "Scene Collection", "label:assets": [] }, { - "href": "./collection.json", "rel": "collection", + "href": "./collection.json", "type": "application/json", "title": "Scene Collection", "label:assets": [] }, { - "href": "../../catalog.json", "rel": "root", + "href": "../../catalog.json", "type": "application/json", "title": "Root", "label:assets": [] @@ -64,12 +60,16 @@ "assets": { "884a939d-1d73-4351-9601-f9ee89a980b0": { "href": "s3://rasterfoundry-production-data-us-east-1/user-uploads/auth0|5c4201f36b7b7c0da8243313/884a939d-1d73-4351-9601-f9ee89a980b0/cog.tif", - "title": "scene", - "type": "image/vnd.stac.geotiff; cloud-optimized=true" + "type": "image/vnd.stac.geotiff; cloud-optimized=true", + "title": "scene" } }, - "collection": "9420e0fd-3731-40e8-93ff-5b6ad0067048", - "properties": { - "datetime": "2019-08-21T15:51:17.881" - } + "bbox": [ + 39.26232911919128, + -6.873418639717923, + 39.33324512902654, + -6.8025353342930215 + ], + "stac_extensions": [], + "collection": "9420e0fd-3731-40e8-93ff-5b6ad0067048" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/9420e0fd-3731-40e8-93ff-5b6ad0067048/a6bd2ff9-3805-40ab-96fa-b7f112b18973.json b/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/9420e0fd-3731-40e8-93ff-5b6ad0067048/a6bd2ff9-3805-40ab-96fa-b7f112b18973.json index a4005fffe..da0d5ad1a 100644 --- a/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/9420e0fd-3731-40e8-93ff-5b6ad0067048/a6bd2ff9-3805-40ab-96fa-b7f112b18973.json +++ b/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/9420e0fd-3731-40e8-93ff-5b6ad0067048/a6bd2ff9-3805-40ab-96fa-b7f112b18973.json @@ -1,8 +1,10 @@ { - "id": "a6bd2ff9-3805-40ab-96fa-b7f112b18973", - "stac_version": "1.0.0-beta.2", - "stac_extensions": [], "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "a6bd2ff9-3805-40ab-96fa-b7f112b18973", + "properties": { + "datetime": "2019-08-21T15:51:17.881000Z" + }, "geometry": { "type": "MultiPolygon", "coordinates": [ @@ -32,30 +34,24 @@ ] ] }, - "bbox": [ - 39.19167311569687, - -6.8025353342930215, - 39.26232911919128, - -6.738583593313782 - ], "links": [ { - "href": "./collection.json", "rel": "parent", + "href": "./collection.json", "type": "application/json", "title": "Scene Collection", "label:assets": [] }, { - "href": "./collection.json", "rel": "collection", + "href": "./collection.json", "type": "application/json", "title": "Scene Collection", "label:assets": [] }, { - "href": "../../catalog.json", "rel": "root", + "href": "../../catalog.json", "type": "application/json", "title": "Root", "label:assets": [] @@ -64,12 +60,16 @@ "assets": { "a6bd2ff9-3805-40ab-96fa-b7f112b18973": { "href": "s3://rasterfoundry-production-data-us-east-1/user-uploads/auth0|5c4201f36b7b7c0da8243313/a6bd2ff9-3805-40ab-96fa-b7f112b18973/cog.tif", - "title": "scene", - "type": "image/vnd.stac.geotiff; cloud-optimized=true" + "type": "image/vnd.stac.geotiff; cloud-optimized=true", + "title": "scene" } }, - "collection": "9420e0fd-3731-40e8-93ff-5b6ad0067048", - "properties": { - "datetime": "2019-08-21T15:51:17.881" - } + "bbox": [ + 39.19167311569687, + -6.8025353342930215, + 39.26232911919128, + -6.738583593313782 + ], + "stac_extensions": [], + "collection": "9420e0fd-3731-40e8-93ff-5b6ad0067048" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/9420e0fd-3731-40e8-93ff-5b6ad0067048/collection.json b/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/9420e0fd-3731-40e8-93ff-5b6ad0067048/collection.json index 116805eaf..46b2b2c38 100644 --- a/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/9420e0fd-3731-40e8-93ff-5b6ad0067048/collection.json +++ b/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/9420e0fd-3731-40e8-93ff-5b6ad0067048/collection.json @@ -1,106 +1,106 @@ { - "stac_version": "1.0.0-beta.2", + "type": "Collection", "id": "9420e0fd-3731-40e8-93ff-5b6ad0067048", - "title": "Scene Collection", + "stac_version": "1.0.0-rc.3", "description": "Scene collection in layer 12cb17a8-ae08-469c-a2be-4d0619240014", - "keywords": [], - "version": "1", - "license": "Apache-2.0", - "providers": [], - "extent": { - "spatial": { - "bbox": [ - [ - 39.191417450329524, - -6.892441704534412, - 39.34867907353046, - -6.73165550776233 - ] - ] - }, - "temporal": { - "interval": [ - [ - "2019-08-21T15:51:17.881Z", - "2019-08-21T15:51:17.881Z" - ] - ] - } - }, - "properties": {}, "links": [ { - "href": "http://www.apache.org/licenses/LICENSE-2.0", "rel": "license", + "href": "http://www.apache.org/licenses/LICENSE-2.0", "label:assets": [] }, { - "href": "../../catalog.json", "rel": "root", - "type": "application/json", - "title": "Root", - "label:assets": [] + "href": "../../catalog.json", + "type": "application/json" }, { - "href": "../collection.json", "rel": "parent", + "href": "../collection.json", "type": "application/json", "title": "Layer Collection", "label:assets": [] }, { - "href": "./3bfb5bd3-5740-4ed0-92c9-968cc532dbc5.json", "rel": "item", + "href": "./3bfb5bd3-5740-4ed0-92c9-968cc532dbc5.json", "type": "application/json", "label:assets": [] }, { - "href": "./41c57cea-50ba-495c-9ee7-17ddba837380.json", "rel": "item", + "href": "./41c57cea-50ba-495c-9ee7-17ddba837380.json", "type": "application/json", "label:assets": [] }, { - "href": "./4514bbc6-cd17-4c14-816d-1709dfc61079.json", "rel": "item", + "href": "./4514bbc6-cd17-4c14-816d-1709dfc61079.json", "type": "application/json", "label:assets": [] }, { - "href": "./52072b95-0275-4255-be5e-c567006f80cb.json", "rel": "item", + "href": "./52072b95-0275-4255-be5e-c567006f80cb.json", "type": "application/json", "label:assets": [] }, { - "href": "./84fe42c0-9d23-404a-bd0f-1406112cca8c.json", "rel": "item", + "href": "./84fe42c0-9d23-404a-bd0f-1406112cca8c.json", "type": "application/json", "label:assets": [] }, { - "href": "./884a939d-1d73-4351-9601-f9ee89a980b0.json", "rel": "item", + "href": "./884a939d-1d73-4351-9601-f9ee89a980b0.json", "type": "application/json", "label:assets": [] }, { - "href": "./a6bd2ff9-3805-40ab-96fa-b7f112b18973.json", "rel": "item", + "href": "./a6bd2ff9-3805-40ab-96fa-b7f112b18973.json", "type": "application/json", "label:assets": [] }, { - "href": "./e40bb30d-0295-42ed-ba04-6cf563b057f9.json", "rel": "item", + "href": "./e40bb30d-0295-42ed-ba04-6cf563b057f9.json", "type": "application/json", "label:assets": [] }, { - "href": "./eb1124cc-3b45-4487-bc2c-4855ac877ad9.json", "rel": "item", + "href": "./eb1124cc-3b45-4487-bc2c-4855ac877ad9.json", "type": "application/json", "label:assets": [] } - ] + ], + "stac_extensions": [], + "title": "Scene Collection", + "keywords": [], + "version": "1", + "providers": [], + "properties": {}, + "extent": { + "spatial": { + "bbox": [ + [ + 39.191417450329524, + -6.892441704534412, + 39.34867907353046, + -6.73165550776233 + ] + ] + }, + "temporal": { + "interval": [ + [ + "2019-08-21T15:51:17.881000Z", + "2019-08-21T15:51:17.881000Z" + ] + ] + } + }, + "license": "Apache-2.0" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/9420e0fd-3731-40e8-93ff-5b6ad0067048/e40bb30d-0295-42ed-ba04-6cf563b057f9.json b/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/9420e0fd-3731-40e8-93ff-5b6ad0067048/e40bb30d-0295-42ed-ba04-6cf563b057f9.json index a09a16df7..b53852c38 100644 --- a/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/9420e0fd-3731-40e8-93ff-5b6ad0067048/e40bb30d-0295-42ed-ba04-6cf563b057f9.json +++ b/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/9420e0fd-3731-40e8-93ff-5b6ad0067048/e40bb30d-0295-42ed-ba04-6cf563b057f9.json @@ -1,8 +1,10 @@ { - "id": "e40bb30d-0295-42ed-ba04-6cf563b057f9", - "stac_version": "1.0.0-beta.2", - "stac_extensions": [], "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "e40bb30d-0295-42ed-ba04-6cf563b057f9", + "properties": { + "datetime": "2019-08-21T15:51:17.881000Z" + }, "geometry": { "type": "MultiPolygon", "coordinates": [ @@ -32,30 +34,24 @@ ] ] }, - "bbox": [ - 39.26232911919128, - -6.8025353342930215, - 39.33324512902654, - -6.732860045871766 - ], "links": [ { - "href": "./collection.json", "rel": "parent", + "href": "./collection.json", "type": "application/json", "title": "Scene Collection", "label:assets": [] }, { - "href": "./collection.json", "rel": "collection", + "href": "./collection.json", "type": "application/json", "title": "Scene Collection", "label:assets": [] }, { - "href": "../../catalog.json", "rel": "root", + "href": "../../catalog.json", "type": "application/json", "title": "Root", "label:assets": [] @@ -64,12 +60,16 @@ "assets": { "e40bb30d-0295-42ed-ba04-6cf563b057f9": { "href": "s3://rasterfoundry-production-data-us-east-1/user-uploads/auth0|5c4201f36b7b7c0da8243313/e40bb30d-0295-42ed-ba04-6cf563b057f9/cog.tif", - "title": "scene", - "type": "image/vnd.stac.geotiff; cloud-optimized=true" + "type": "image/vnd.stac.geotiff; cloud-optimized=true", + "title": "scene" } }, - "collection": "9420e0fd-3731-40e8-93ff-5b6ad0067048", - "properties": { - "datetime": "2019-08-21T15:51:17.881" - } + "bbox": [ + 39.26232911919128, + -6.8025353342930215, + 39.33324512902654, + -6.732860045871766 + ], + "stac_extensions": [], + "collection": "9420e0fd-3731-40e8-93ff-5b6ad0067048" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/9420e0fd-3731-40e8-93ff-5b6ad0067048/eb1124cc-3b45-4487-bc2c-4855ac877ad9.json b/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/9420e0fd-3731-40e8-93ff-5b6ad0067048/eb1124cc-3b45-4487-bc2c-4855ac877ad9.json index 60bf637f9..c61f90bc2 100644 --- a/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/9420e0fd-3731-40e8-93ff-5b6ad0067048/eb1124cc-3b45-4487-bc2c-4855ac877ad9.json +++ b/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/9420e0fd-3731-40e8-93ff-5b6ad0067048/eb1124cc-3b45-4487-bc2c-4855ac877ad9.json @@ -1,8 +1,10 @@ { - "id": "eb1124cc-3b45-4487-bc2c-4855ac877ad9", - "stac_version": "1.0.0-beta.2", - "stac_extensions": [], "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "eb1124cc-3b45-4487-bc2c-4855ac877ad9", + "properties": { + "datetime": "2019-08-21T15:51:17.881000Z" + }, "geometry": { "type": "MultiPolygon", "coordinates": [ @@ -32,30 +34,24 @@ ] ] }, - "bbox": [ - 39.33324512902654, - -6.879948848100303, - 39.34867907353046, - -6.873418639717923 - ], "links": [ { - "href": "./collection.json", "rel": "parent", + "href": "./collection.json", "type": "application/json", "title": "Scene Collection", "label:assets": [] }, { - "href": "./collection.json", "rel": "collection", + "href": "./collection.json", "type": "application/json", "title": "Scene Collection", "label:assets": [] }, { - "href": "../../catalog.json", "rel": "root", + "href": "../../catalog.json", "type": "application/json", "title": "Root", "label:assets": [] @@ -64,12 +60,16 @@ "assets": { "eb1124cc-3b45-4487-bc2c-4855ac877ad9": { "href": "s3://rasterfoundry-production-data-us-east-1/user-uploads/auth0|5c4201f36b7b7c0da8243313/eb1124cc-3b45-4487-bc2c-4855ac877ad9/cog.tif", - "title": "scene", - "type": "image/vnd.stac.geotiff; cloud-optimized=true" + "type": "image/vnd.stac.geotiff; cloud-optimized=true", + "title": "scene" } }, - "collection": "9420e0fd-3731-40e8-93ff-5b6ad0067048", - "properties": { - "datetime": "2019-08-21T15:51:17.881" - } + "bbox": [ + 39.33324512902654, + -6.879948848100303, + 39.34867907353046, + -6.873418639717923 + ], + "stac_extensions": [], + "collection": "9420e0fd-3731-40e8-93ff-5b6ad0067048" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/collection.json b/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/collection.json index 71cda2fed..eb5514295 100644 --- a/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/collection.json +++ b/tests/data-files/catalogs/test-case-6/12cb17a8-ae08-469c-a2be-4d0619240014/collection.json @@ -1,66 +1,66 @@ { - "stac_version": "1.0.0-beta.2", + "type": "Collection", "id": "12cb17a8-ae08-469c-a2be-4d0619240014", - "title": "Layers", + "stac_version": "1.0.0-rc.3", "description": "Project Layer Collection", - "keywords": [], - "version": "1.0", - "license": "Apache-2.0", - "providers": [], - "extent": { - "spatial": { - "bbox": [ - [ - 39.191417450329524, - -6.892441704534412, - 39.34867907353046, - -6.73165550776233 - ] - ] - }, - "temporal": { - "interval": [ - [ - "2019-08-21T15:51:17.881Z", - "2019-08-21T15:51:17.881Z" - ] - ] - } - }, - "properties": {}, "links": [ { - "href": "http://www.apache.org/licenses/LICENSE-2.0", "rel": "license", + "href": "http://www.apache.org/licenses/LICENSE-2.0", "label:assets": [] }, { - "href": "../catalog.json", "rel": "parent", + "href": "../catalog.json", "type": "application/json", "title": "Catalog fd478c2b-3f71-41e4-a87b-e97a8a0d0afa", "label:assets": [] }, { - "href": "../catalog.json", "rel": "root", - "type": "application/json", - "title": "Root Catalog", - "label:assets": [] + "href": "../catalog.json", + "type": "application/json" }, { - "href": "./9420e0fd-3731-40e8-93ff-5b6ad0067048/collection.json", "rel": "child", + "href": "./9420e0fd-3731-40e8-93ff-5b6ad0067048/collection.json", "type": "application/json", "title": "Scene Collection: 9420e0fd-3731-40e8-93ff-5b6ad0067048", "label:assets": [] }, { - "href": "./400c22e3-5b54-438b-b600-5e9bd6d0a498/collection.json", "rel": "child", + "href": "./400c22e3-5b54-438b-b600-5e9bd6d0a498/collection.json", "type": "application/json", "title": "Label Collection: 400c22e3-5b54-438b-b600-5e9bd6d0a498", "label:assets": [] } - ] + ], + "stac_extensions": [], + "title": "Layers", + "keywords": [], + "version": "1.0", + "providers": [], + "properties": {}, + "extent": { + "spatial": { + "bbox": [ + [ + 39.191417450329524, + -6.892441704534412, + 39.34867907353046, + -6.73165550776233 + ] + ] + }, + "temporal": { + "interval": [ + [ + "2019-08-21T15:51:17.881000Z", + "2019-08-21T15:51:17.881000Z" + ] + ] + } + }, + "license": "Apache-2.0" } \ No newline at end of file diff --git a/tests/data-files/catalogs/test-case-6/catalog.json b/tests/data-files/catalogs/test-case-6/catalog.json index e7b8f520d..a78e5fbe8 100644 --- a/tests/data-files/catalogs/test-case-6/catalog.json +++ b/tests/data-files/catalogs/test-case-6/catalog.json @@ -1,21 +1,23 @@ { - "stac_version": "1.0.0-beta.2", + "type": "Catalog", "id": "fd478c2b-3f71-41e4-a87b-e97a8a0d0afa", + "stac_version": "1.0.0-rc.3", "description": "Exported from Raster Foundry 2020-01-09 21:17:20.186", "links": [ { - "href": "./catalog.json", "rel": "root", + "href": "./catalog.json", "type": "application/json", "title": "Catalog fd478c2b-3f71-41e4-a87b-e97a8a0d0afa", "label:assets": [] }, { - "href": "./12cb17a8-ae08-469c-a2be-4d0619240014/collection.json", "rel": "child", + "href": "./12cb17a8-ae08-469c-a2be-4d0619240014/collection.json", "type": "application/json", "title": "Layer Collection 12cb17a8-ae08-469c-a2be-4d0619240014", "label:assets": [] } - ] + ], + "stac_extensions": [] } \ No newline at end of file diff --git a/tests/data-files/change_stac_version.py b/tests/data-files/change_stac_version.py index 28ae59997..bc8ab8b1f 100644 --- a/tests/data-files/change_stac_version.py +++ b/tests/data-files/change_stac_version.py @@ -3,34 +3,65 @@ This is used when upgrading to a new version of STAC. """ import os +import re import argparse import json -if __name__ == '__main__': - parser = argparse.ArgumentParser(description='Process some integers.') - parser.add_argument('stac_version', - metavar='STAC_VERSION', - help='The STAC_VERSION to ensure all STAC objects are using.') +import pystac + +TARGET_VERSION = pystac.get_stac_version() + + +def migrate(path: str) -> None: + try: + with open(path) as f: + stac_json = json.load(f) + except json.decoder.JSONDecodeError: + print(f"Cannot read {path}") + raise + + if "stac_version" in stac_json: + cur_ver = stac_json["stac_version"] + if not cur_ver == TARGET_VERSION: + print( + " - Migrating {} from {} to {}...".format( + path, cur_ver, TARGET_VERSION + ) + ) + obj = pystac.read_dict(stac_json, href=path) + migrated = obj.to_dict(include_self_link=False) + with open(path, "w") as f: + json.dump(migrated, f, indent=2) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Process some integers.") + parser.add_argument( + "--file", metavar="FILE", help="Only migrate this specific file." + ) args = parser.parse_args() - data_files_dir = os.path.dirname(os.path.realpath(__file__)) - - # Skip examples directory, which contains version specific STACs... - dirs_to_check = [x for x in os.listdir(data_files_dir) if x != 'examples'] - - for d in dirs_to_check: - for root, _, files in os.walk(d): - for fname in files: - if fname.endswith('.json'): - path = os.path.join(root, fname) - with open(path) as f: - stac_json = json.load(f) - if 'stac_version' in stac_json: - cur_ver = stac_json['stac_version'] - if not cur_ver == args.stac_version: - print('Changing {} version from {} to {}...'.format( - fname, cur_ver, args.stac_version)) - stac_json['stac_version'] = args.stac_version - with open(path, 'w') as f: - json.dump(stac_json, f, indent=2) + if args.file: + migrate(os.path.abspath(args.file)) + else: + + data_files_dir = os.path.dirname(os.path.realpath(__file__)) + + # Skip examples directory, which contains version specific STACs... + dirs_to_check = [ + os.path.join(data_files_dir, x) + for x in os.listdir(data_files_dir) + if x != "examples" + ] + + for d in dirs_to_check: + print(f"checking in {d}..") + for root, _, files in os.walk(d): + # Skip directories with a version tag + if re.match(r".*-v\d.*", root): + continue + for fname in files: + if fname.endswith(".json"): + path = os.path.join(root, fname) + migrate(path) diff --git a/tests/data-files/collections/multi-extent.json b/tests/data-files/collections/multi-extent.json index afcdb1a81..e7b272121 100644 --- a/tests/data-files/collections/multi-extent.json +++ b/tests/data-files/collections/multi-extent.json @@ -1,8 +1,15 @@ { + "type": "Collection", "id": "area-1-1", - "stac_version": "1.0.0-beta.2", + "stac_version": "1.0.0-rc.3", "description": "test collection country-1", - "links": [{ + "links": [ + { + "rel": "root", + "href": "./multi-extent.json", + "type": "application/json" + }, + { "rel": "item", "href": "./area-1-1-imagery/area-1-1-imagery.json", "type": "application/json" @@ -18,6 +25,7 @@ "type": "application/json" } ], + "stac_extensions": [], "extent": { "spatial": { "bbox": [ diff --git a/tests/data-files/commons/example-collection-with-commons.json b/tests/data-files/commons/example-collection-with-commons.json index 76e3b7a34..caccd227a 100644 --- a/tests/data-files/commons/example-collection-with-commons.json +++ b/tests/data-files/commons/example-collection-with-commons.json @@ -1,68 +1,62 @@ { - "stac_version": "1.0.0-beta.2", + "type": "Collection", + "id": "collection-with", + "stac_version": "1.0.0-rc.3", + "description": "Landat 8 imagery radiometrically calibrated and orthorectified using gound points and Digital Elevation Model (DEM) data to correct relief displacement.", + "links": [ + { + "rel": "parent", + "href": "./example-collection-with-commons.json" + }, + { + "rel": "root", + "href": "./example-collection-with-commons.json", + "type": "application/json" + }, + { + "rel": "item", + "href": "./example-item-with-commons.json" + } + ], "stac_extensions": [ - "commons", "view", "eo" ], - "id": "collection-with", "title": "Landsat 8 L1", - "description": "Landat 8 imagery radiometrically calibrated and orthorectified using gound points and Digital Elevation Model (DEM) data to correct relief displacement.", "keywords": [ "landsat" ], - "extent": { - "spatial": { - "bbox": [ - [ - -180, - -90, - 180, - 90 - ] - ] - }, - "temporal": { - "interval": [ - [ - "2013-06-01T00:00:00Z", - null - ] - ] - } - }, "providers": [ { "name": "USGS", - "url": "https://landsat.usgs.gov/", "roles": [ "producer", "licensor" - ] + ], + "url": "https://landsat.usgs.gov/" }, { "name": "Planet Labs", - "url": "https://github.com/landsat-pds/landsat_ingestor", "roles": [ "processor" - ] + ], + "url": "https://github.com/landsat-pds/landsat_ingestor" }, { "name": "AWS", - "url": "https://landsatonaws.com/", "roles": [ "host" - ] + ], + "url": "https://landsatonaws.com/" }, { "name": "Development Seed", - "url": "https://developmentseed.org/", "roles": [ "processor" - ] + ], + "url": "https://developmentseed.org/" } ], - "license": "PDDL-1.0", "properties": { "platform": "landsat-8", "instruments": [ @@ -140,18 +134,25 @@ } ] }, - "links": [ - { - "rel": "parent", - "href": "./example-collection-with-commons.json" - }, - { - "rel": "root", - "href": "./example-collection-with-commons.json" + "extent": { + "spatial": { + "bbox": [ + [ + -180, + -90, + 180, + 90 + ] + ] }, - { - "rel": "item", - "href": "./example-item-with-commons.json" + "temporal": { + "interval": [ + [ + "2013-06-01T00:00:00Z", + null + ] + ] } - ] + }, + "license": "PDDL-1.0" } \ No newline at end of file diff --git a/tests/data-files/commons/example-collection-without-commons.json b/tests/data-files/commons/example-collection-without-commons.json index ae6756aff..b5e1211c6 100644 --- a/tests/data-files/commons/example-collection-without-commons.json +++ b/tests/data-files/commons/example-collection-without-commons.json @@ -1,67 +1,62 @@ { - "stac_version": "1.0.0-beta.2", + "type": "Collection", + "id": "collection-without", + "stac_version": "1.0.0-rc.3", + "description": "Landat 8 imagery radiometrically calibrated and orthorectified using gound points and Digital Elevation Model (DEM) data to correct relief displacement.", + "links": [ + { + "rel": "parent", + "href": "./example-collection-without-commons.json" + }, + { + "rel": "root", + "href": "./example-collection-without-commons.json", + "type": "application/json" + }, + { + "rel": "item", + "href": "./example-item-without-commons.json" + } + ], "stac_extensions": [ "view", "eo" ], - "id": "collection-without", "title": "Landsat 8 L1", - "description": "Landat 8 imagery radiometrically calibrated and orthorectified using gound points and Digital Elevation Model (DEM) data to correct relief displacement.", "keywords": [ "landsat" ], - "extent": { - "spatial": { - "bbox": [ - [ - -180, - -90, - 180, - 90 - ] - ] - }, - "temporal": { - "interval": [ - [ - "2013-06-01T00:00:00Z", - null - ] - ] - } - }, "providers": [ { "name": "USGS", - "url": "https://landsat.usgs.gov/", "roles": [ "producer", "licensor" - ] + ], + "url": "https://landsat.usgs.gov/" }, { "name": "Planet Labs", - "url": "https://github.com/landsat-pds/landsat_ingestor", "roles": [ "processor" - ] + ], + "url": "https://github.com/landsat-pds/landsat_ingestor" }, { "name": "AWS", - "url": "https://landsatonaws.com/", "roles": [ "host" - ] + ], + "url": "https://landsatonaws.com/" }, { "name": "Development Seed", - "url": "https://developmentseed.org/", "roles": [ "processor" - ] + ], + "url": "https://developmentseed.org/" } ], - "license": "PDDL-1.0", "properties": { "platform": "landsat-8", "instruments": [ @@ -139,18 +134,25 @@ } ] }, - "links": [ - { - "rel": "parent", - "href": "./example-collection-without-commons.json" - }, - { - "rel": "root", - "href": "./example-collection-without-commons.json" + "extent": { + "spatial": { + "bbox": [ + [ + -180, + -90, + 180, + 90 + ] + ] }, - { - "rel": "item", - "href": "./example-item-without-commons.json" + "temporal": { + "interval": [ + [ + "2013-06-01T00:00:00Z", + null + ] + ] } - ] + }, + "license": "PDDL-1.0" } \ No newline at end of file diff --git a/tests/data-files/commons/example-item-with-commons.json b/tests/data-files/commons/example-item-with-commons.json index 0e1cc197a..02e8cd3ac 100644 --- a/tests/data-files/commons/example-item-with-commons.json +++ b/tests/data-files/commons/example-item-with-commons.json @@ -1,19 +1,15 @@ { - "stac_version": "1.0.0-beta.2", - "stac_extensions": [ - "commons", - "eo", - "view", - "https://example.com/stac/landsat-extension/1.0/schema.json" - ], - "id": "item-with", "type": "Feature", - "bbox": [ - 148.13933, - 59.51584, - 152.52758, - 60.63437 - ], + "stac_version": "1.0.0-rc.3", + "id": "item-with", + "properties": { + "datetime": "2018-10-01T01:08:32.033000Z", + "eo:cloud_cover": 78, + "view:sun_azimuth": 168.8989761, + "view:sun_elevation": 26.32596431, + "landsat:path": 107, + "landsat:row": 18 + }, "geometry": { "type": "Polygon", "coordinates": [ @@ -41,123 +37,128 @@ ] ] }, - "collection": "collection-with", - "properties": { - "datetime": "2018-10-01T01:08:32.033Z", - "eo:cloud_cover": 78, - "view:sun_azimuth": 168.8989761, - "view:sun_elevation": 26.32596431, - "landsat:path": 107, - "landsat:row": 18 - }, + "links": [ + { + "rel": "collection", + "href": "./example-collection-with-commons.json" + }, + { + "rel": "parent", + "href": "./example-collection-with-commons.json" + }, + { + "rel": "root", + "href": "./example-collection-with-commons.json" + } + ], "assets": { "ANG": { "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_ANG.txt", - "title": "Angle coefficients file", - "type": "text/plain" + "type": "text/plain", + "title": "Angle coefficients file" }, "B1": { "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B1.TIF", "type": "image/tiff; application=geotiff", + "title": "Band 1 (coastal)", "eo:bands": [ 0 - ], - "title": "Band 1 (coastal)" + ] }, "B2": { "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B2.TIF", "type": "image/tiff; application=geotiff", + "title": "Band 2 (blue)", "eo:bands": [ 1 - ], - "title": "Band 2 (blue)" + ] }, "B3": { "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B3.TIF", "type": "image/tiff; application=geotiff", + "title": "Band 3 (green)", "eo:bands": [ 2 - ], - "title": "Band 3 (green)" + ] }, "B4": { "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B4.TIF", "type": "image/tiff; application=geotiff", + "title": "Band 4 (red)", "eo:bands": [ 3 - ], - "title": "Band 4 (red)" + ] }, "B5": { "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B5.TIF", "type": "image/tiff; application=geotiff", + "title": "Band 5 (nir)", "eo:bands": [ 4 - ], - "title": "Band 5 (nir)" + ] }, "B6": { "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B6.TIF", "type": "image/tiff; application=geotiff", + "title": "Band 6 (swir16)", "eo:bands": [ 5 - ], - "title": "Band 6 (swir16)" + ] }, "B7": { "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B7.TIF", "type": "image/tiff; application=geotiff", + "title": "Band 7 (swir22)", "eo:bands": [ 6 - ], - "title": "Band 7 (swir22)" + ] }, "B8": { "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B8.TIF", "type": "image/tiff; application=geotiff", + "title": "Band 8 (pan)", "eo:bands": [ 7 - ], - "title": "Band 8 (pan)" + ] }, "B9": { "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B9.TIF", "type": "image/tiff; application=geotiff", + "title": "Band 9 (cirrus)", "eo:bands": [ 8 - ], - "title": "Band 9 (cirrus)" + ] }, "B10": { "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B10.TIF", "type": "image/tiff; application=geotiff", + "title": "Band 10 (lwir)", "eo:bands": [ 9 - ], - "title": "Band 10 (lwir)" + ] }, "B11": { "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B11.TIF", "type": "image/tiff; application=geotiff", + "title": "Band 11 (lwir)", "eo:bands": [ 10 - ], - "title": "Band 11 (lwir)" + ] }, "BQA": { "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_BQA.TIF", - "title": "Band quality data", - "type": "image/tiff; application=geotiff" + "type": "image/tiff; application=geotiff", + "title": "Band quality data" }, "MTL": { "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_MTL.txt", - "title": "original metadata file", - "type": "text/plain" + "type": "text/plain", + "title": "original metadata file" }, "thumbnail": { "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_thumb_large.jpg", - "title": "Thumbnail image", - "type": "image/jpeg" + "type": "image/jpeg", + "title": "Thumbnail image" }, "index": { "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/index.html", @@ -165,18 +166,16 @@ "title": "HTML index page" } }, - "links": [ - { - "rel": "collection", - "href": "./example-collection-with-commons.json" - }, - { - "rel": "parent", - "href": "./example-collection-with-commons.json" - }, - { - "rel": "root", - "href": "./example-collection-with-commons.json" - } - ] + "bbox": [ + 148.13933, + 59.51584, + 152.52758, + 60.63437 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/eo/v1.0.0/schema.json", + "https://stac-extensions.github.io/view/v1.0.0/schema.json", + "https://example.com/stac/landsat-extension/1.0/schema.json" + ], + "collection": "collection-with" } \ No newline at end of file diff --git a/tests/data-files/commons/example-item-without-commons.json b/tests/data-files/commons/example-item-without-commons.json index b2e486b69..cc042d460 100644 --- a/tests/data-files/commons/example-item-without-commons.json +++ b/tests/data-files/commons/example-item-without-commons.json @@ -1,18 +1,15 @@ { - "stac_version": "1.0.0-beta.2", - "stac_extensions": [ - "eo", - "view", - "https://example.com/stac/landsat-extension/1.0/schema.json" - ], - "id": "item-without", "type": "Feature", - "bbox": [ - 148.13933, - 59.51584, - 152.52758, - 60.63437 - ], + "stac_version": "1.0.0-rc.3", + "id": "item-without", + "properties": { + "datetime": "2018-10-01T01:08:32.033000Z", + "eo:cloud_cover": 78, + "view:sun_azimuth": 168.8989761, + "view:sun_elevation": 26.32596431, + "landsat:path": 107, + "landsat:row": 18 + }, "geometry": { "type": "Polygon", "coordinates": [ @@ -40,123 +37,124 @@ ] ] }, - "collection": "collection-without", - "properties": { - "datetime": "2018-10-01T01:08:32.033Z", - "eo:cloud_cover": 78, - "view:sun_azimuth": 168.8989761, - "view:sun_elevation": 26.32596431, - "landsat:path": 107, - "landsat:row": 18 - }, + "links": [ + { + "rel": "parent", + "href": "./example-collection-without-commons.json" + }, + { + "rel": "root", + "href": "./example-collection-without-commons.json" + } + ], "assets": { "ANG": { "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_ANG.txt", - "title": "Angle coefficients file", - "type": "text/plain" + "type": "text/plain", + "title": "Angle coefficients file" }, "B1": { "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B1.TIF", "type": "image/tiff; application=geotiff", + "title": "Band 1 (coastal)", "eo:bands": [ 0 - ], - "title": "Band 1 (coastal)" + ] }, "B2": { "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B2.TIF", "type": "image/tiff; application=geotiff", + "title": "Band 2 (blue)", "eo:bands": [ 1 - ], - "title": "Band 2 (blue)" + ] }, "B3": { "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B3.TIF", "type": "image/tiff; application=geotiff", + "title": "Band 3 (green)", "eo:bands": [ 2 - ], - "title": "Band 3 (green)" + ] }, "B4": { "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B4.TIF", "type": "image/tiff; application=geotiff", + "title": "Band 4 (red)", "eo:bands": [ 3 - ], - "title": "Band 4 (red)" + ] }, "B5": { "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B5.TIF", "type": "image/tiff; application=geotiff", + "title": "Band 5 (nir)", "eo:bands": [ 4 - ], - "title": "Band 5 (nir)" + ] }, "B6": { "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B6.TIF", "type": "image/tiff; application=geotiff", + "title": "Band 6 (swir16)", "eo:bands": [ 5 - ], - "title": "Band 6 (swir16)" + ] }, "B7": { "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B7.TIF", "type": "image/tiff; application=geotiff", + "title": "Band 7 (swir22)", "eo:bands": [ 6 - ], - "title": "Band 7 (swir22)" + ] }, "B8": { "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B8.TIF", "type": "image/tiff; application=geotiff", + "title": "Band 8 (pan)", "eo:bands": [ 7 - ], - "title": "Band 8 (pan)" + ] }, "B9": { "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B9.TIF", "type": "image/tiff; application=geotiff", + "title": "Band 9 (cirrus)", "eo:bands": [ 8 - ], - "title": "Band 9 (cirrus)" + ] }, "B10": { "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B10.TIF", "type": "image/tiff; application=geotiff", + "title": "Band 10 (lwir)", "eo:bands": [ 9 - ], - "title": "Band 10 (lwir)" + ] }, "B11": { "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B11.TIF", "type": "image/tiff; application=geotiff", + "title": "Band 11 (lwir)", "eo:bands": [ 10 - ], - "title": "Band 11 (lwir)" + ] }, "BQA": { "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_BQA.TIF", - "title": "Band quality data", - "type": "image/tiff; application=geotiff" + "type": "image/tiff; application=geotiff", + "title": "Band quality data" }, "MTL": { "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_MTL.txt", - "title": "original metadata file", - "type": "text/plain" + "type": "text/plain", + "title": "original metadata file" }, "thumbnail": { "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_thumb_large.jpg", - "title": "Thumbnail image", - "type": "image/jpeg" + "type": "image/jpeg", + "title": "Thumbnail image" }, "index": { "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/index.html", @@ -164,14 +162,16 @@ "title": "HTML index page" } }, - "links": [ - { - "rel": "parent", - "href": "./example-collection-without-commons.json" - }, - { - "rel": "root", - "href": "./example-collection-without-commons.json" - } - ] + "bbox": [ + 148.13933, + 59.51584, + 152.52758, + 60.63437 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/eo/v1.0.0/schema.json", + "https://stac-extensions.github.io/view/v1.0.0/schema.json", + "https://example.com/stac/landsat-extension/1.0/schema.json" + ], + "collection": "collection-without" } \ No newline at end of file diff --git a/tests/data-files/eo/eo-collection.json b/tests/data-files/eo/eo-collection.json new file mode 100644 index 000000000..0efb3cb36 --- /dev/null +++ b/tests/data-files/eo/eo-collection.json @@ -0,0 +1,152 @@ +{ + "type": "Collection", + "id": "landsat-8-l1", + "stac_version": "1.0.0-rc.3", + "description": "Landat 8 imagery radiometrically calibrated and orthorectified using gound points and Digital Elevation Model (DEM) data to correct relief displacement.", + "links": [ + { + "rel": "parent", + "href": "https://landsat-stac.s3.amazonaws.com/catalog.json" + }, + { + "rel": "root", + "href": "https://landsat-stac.s3.amazonaws.com/catalog.json", + "type": "application/json" + }, + { + "rel": "child", + "href": "https://landsat-stac.s3.amazonaws.com/landsat-8-l1/paths/catalog.json" + } + ], + "stac_extensions": [], + "title": "Landsat 8 L1", + "keywords": [ + "landsat" + ], + "providers": [ + { + "name": "USGS", + "roles": [ + "producer", + "licensor" + ], + "url": "https://landsat.usgs.gov/" + }, + { + "name": "Planet Labs", + "roles": [ + "processor" + ], + "url": "https://github.com/landsat-pds/landsat_ingestor" + }, + { + "name": "AWS", + "roles": [ + "host" + ], + "url": "https://landsatonaws.com/" + }, + { + "name": "Development Seed", + "roles": [ + "processor" + ], + "url": "https://developmentseed.org/" + } + ], + "summaries": { + "eo:bands": [ + { + "name": "B1", + "common_name": "coastal", + "center_wavelength": 0.44, + "full_width_half_max": 0.02 + }, + { + "name": "B2", + "common_name": "blue", + "center_wavelength": 0.48, + "full_width_half_max": 0.06 + }, + { + "name": "B3", + "common_name": "green", + "center_wavelength": 0.56, + "full_width_half_max": 0.06 + }, + { + "name": "B4", + "common_name": "red", + "center_wavelength": 0.65, + "full_width_half_max": 0.04 + }, + { + "name": "B5", + "common_name": "nir", + "center_wavelength": 0.86, + "full_width_half_max": 0.03 + }, + { + "name": "B6", + "common_name": "swir16", + "center_wavelength": 1.6, + "full_width_half_max": 0.08 + }, + { + "name": "B7", + "common_name": "swir22", + "center_wavelength": 2.2, + "full_width_half_max": 0.2 + }, + { + "name": "B8", + "common_name": "pan", + "center_wavelength": 0.59, + "full_width_half_max": 0.18 + }, + { + "name": "B9", + "common_name": "cirrus", + "center_wavelength": 1.37, + "full_width_half_max": 0.02 + }, + { + "name": "B10", + "common_name": "lwir11", + "center_wavelength": 10.9, + "full_width_half_max": 0.8 + }, + { + "name": "B11", + "common_name": "lwir12", + "center_wavelength": 12, + "full_width_half_max": 1 + } + ], + "eo:cloud_cover": { + "minimum": 0.0, + "maximum": 80.0 + } + }, + "extent": { + "spatial": { + "bbox": [ + [ + -180, + -90, + 180, + 90 + ] + ] + }, + "temporal": { + "interval": [ + [ + "2013-06-01T00:00:00Z", + null + ] + ] + } + }, + "license": "PDDL-1.0" +} \ No newline at end of file diff --git a/tests/data-files/eo/eo-landsat-example.json b/tests/data-files/eo/eo-landsat-example.json index 75b110721..824b42772 100644 --- a/tests/data-files/eo/eo-landsat-example.json +++ b/tests/data-files/eo/eo-landsat-example.json @@ -1,231 +1,235 @@ { - "stac_version": "1.0.0-beta.2", - "stac_extensions": [ - "eo", - "view", - "https://example.com/stac/landsat-extension/1.0/schema.json" + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "LC08_L1TP_107018_20181001_20181001_01_RT", + "properties": { + "platform": "landsat-8", + "instrument": [ + "oli", + "tirs" ], - "id": "LC08_L1TP_107018_20181001_20181001_01_RT", - "collection": "landsat-8-l1", - "type": "Feature", - "bbox": [ - 148.13933, - 59.51584, - 152.52758, - 60.63437 - ], - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [ - 152.52758, - 60.63437 - ], - [ - 149.1755, - 61.19016 - ], - [ - 148.13933, - 59.51584 - ], - [ - 151.33786, - 58.97792 - ], - [ - 152.52758, - 60.63437 - ] - ] + "datetime": "2018-10-01T01:08:32.033000Z", + "gsd": 30, + "view:sun_azimuth": 168.8989761, + "view:sun_elevation": 26.32596431, + "view:off_nadir": 0, + "landsat:path": 107, + "landsat:row": 18, + "eo:cloud_cover": 78 + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + 152.52758, + 60.63437 + ], + [ + 149.1755, + 61.19016 + ], + [ + 148.13933, + 59.51584 + ], + [ + 151.33786, + 58.97792 + ], + [ + 152.52758, + 60.63437 ] + ] + ] + }, + "links": [ + { + "rel": "collection", + "href": "http://cool-sat.com/catalog/CS3-20160503_132130_04/catalog.json" + } + ], + "assets": { + "ANG": { + "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_ANG.txt", + "type": "text/plain", + "title": "Angle coefficients file" }, - "properties": { - "platform": "landsat-8", - "instrument": [ - "oli", - "tirs" - ], - "datetime": "2018-10-01T01:08:32.033Z", - "gsd": 30, - "view:sun_azimuth": 168.8989761, - "view:sun_elevation": 26.32596431, - "view:off_nadir": 0, - "landsat:path": 107, - "landsat:row": 18, - "eo:cloud_cover": 78 + "B1": { + "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B1.TIF", + "type": "image/tiff; application=geotiff", + "title": "Band 1 (coastal)", + "eo:bands": [ + { + "name": "B1", + "common_name": "coastal", + "center_wavelength": 0.44, + "full_width_half_max": 0.02 + } + ] + }, + "B2": { + "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B2.TIF", + "type": "image/tiff; application=geotiff", + "title": "Band 2 (blue)", + "eo:bands": [ + { + "name": "B2", + "common_name": "blue", + "center_wavelength": 0.48, + "full_width_half_max": 0.06 + } + ] + }, + "B3": { + "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B3.TIF", + "type": "image/tiff; application=geotiff", + "title": "Band 3 (green)", + "eo:bands": [ + { + "name": "B3", + "common_name": "green", + "center_wavelength": 0.56, + "full_width_half_max": 0.06 + } + ], + "eo:cloud_cover": 20 + }, + "B4": { + "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B4.TIF", + "type": "image/tiff; application=geotiff", + "title": "Band 4 (red)", + "eo:bands": [ + { + "name": "B4", + "common_name": "red", + "center_wavelength": 0.65, + "full_width_half_max": 0.04 + } + ] + }, + "B5": { + "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B5.TIF", + "type": "image/tiff; application=geotiff", + "title": "Band 5 (nir)", + "eo:bands": [ + { + "name": "B5", + "common_name": "nir", + "center_wavelength": 0.86, + "full_width_half_max": 0.03 + } + ] + }, + "B6": { + "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B6.TIF", + "type": "image/tiff; application=geotiff", + "title": "Band 6 (swir16)", + "eo:bands": [ + { + "name": "B6", + "common_name": "swir16", + "center_wavelength": 1.6, + "full_width_half_max": 0.08 + } + ] + }, + "B7": { + "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B7.TIF", + "type": "image/tiff; application=geotiff", + "title": "Band 7 (swir22)", + "eo:bands": [ + { + "name": "B7", + "common_name": "swir22", + "center_wavelength": 2.2, + "full_width_half_max": 0.2 + } + ] + }, + "B8": { + "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B8.TIF", + "type": "image/tiff; application=geotiff", + "title": "Band 8 (pan)", + "eo:bands": [ + { + "name": "B8", + "common_name": "pan", + "center_wavelength": 0.59, + "full_width_half_max": 0.18 + } + ] }, - "assets": { - "ANG": { - "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_ANG.txt", - "title": "Angle coefficients file", - "type": "text/plain" - }, - "B1": { - "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B1.TIF", - "type": "image/tiff; application=geotiff", - "eo:bands": [ - { - "name": "B1", - "common_name": "coastal", - "center_wavelength": 0.44, - "full_width_half_max": 0.02 - } - ], - "title": "Band 1 (coastal)" - }, - "B2": { - "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B2.TIF", - "type": "image/tiff; application=geotiff", - "eo:bands": [ - { - "name": "B2", - "common_name": "blue", - "center_wavelength": 0.48, - "full_width_half_max": 0.06 - } - ], - "title": "Band 2 (blue)" - }, - "B3": { - "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B3.TIF", - "type": "image/tiff; application=geotiff", - "eo:bands": [ - { - "name": "B3", - "common_name": "green", - "center_wavelength": 0.56, - "full_width_half_max": 0.06 - } - ], - "title": "Band 3 (green)", - "eo:cloud_cover": 20 - }, - "B4": { - "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B4.TIF", - "type": "image/tiff; application=geotiff", - "eo:bands": [ - { - "name": "B4", - "common_name": "red", - "center_wavelength": 0.65, - "full_width_half_max": 0.04 - } - ], - "title": "Band 4 (red)" - }, - "B5": { - "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B5.TIF", - "type": "image/tiff; application=geotiff", - "eo:bands": [ - { - "name": "B5", - "common_name": "nir", - "center_wavelength": 0.86, - "full_width_half_max": 0.03 - } - ], - "title": "Band 5 (nir)" - }, - "B6": { - "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B6.TIF", - "type": "image/tiff; application=geotiff", - "eo:bands": [ - { - "name": "B6", - "common_name": "swir16", - "center_wavelength": 1.6, - "full_width_half_max": 0.08 - } - ], - "title": "Band 6 (swir16)" - }, - "B7": { - "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B7.TIF", - "type": "image/tiff; application=geotiff", - "eo:bands": [ - { - "name": "B7", - "common_name": "swir22", - "center_wavelength": 2.2, - "full_width_half_max": 0.2 - } - ], - "title": "Band 7 (swir22)" - }, - "B8": { - "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B8.TIF", - "type": "image/tiff; application=geotiff", - "eo:bands": [ - { - "name": "B8", - "common_name": "pan", - "center_wavelength": 0.59, - "full_width_half_max": 0.18 - } - ], - "title": "Band 8 (pan)" - }, - "B9": { - "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B9.TIF", - "type": "image/tiff; application=geotiff", - "eo:bands": [ - { - "name": "B9", - "common_name": "cirrus", - "center_wavelength": 1.37, - "full_width_half_max": 0.02 - } - ], - "title": "Band 9 (cirrus)" - }, - "B10": { - "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B10.TIF", - "type": "image/tiff; application=geotiff", - "eo:bands": [ - { - "name": "B10", - "common_name": "lwir11", - "center_wavelength": 10.9, - "full_width_half_max": 0.8 - } - ], - "title": "Band 10 (lwir)" - }, - "B11": { - "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B11.TIF", - "type": "image/tiff; application=geotiff", - "eo:bands": [ - { - "name": "B11", - "common_name": "lwir12", - "center_wavelength": 12, - "full_width_half_max": 1 - } - ], - "title": "Band 11 (lwir)" - }, - "BQA": { - "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_BQA.TIF", - "title": "Band quality data", - "type": "image/tiff; application=geotiff" - }, - "MTL": { - "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_MTL.txt", - "title": "original metadata file", - "type": "text/plain" - }, - "thumbnail": { - "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_thumb_large.jpg", - "title": "Thumbnail image", - "type": "image/jpeg" - }, - "index": { - "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/index.html", - "type": "text/html", - "title": "HTML index page" + "B9": { + "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B9.TIF", + "type": "image/tiff; application=geotiff", + "title": "Band 9 (cirrus)", + "eo:bands": [ + { + "name": "B9", + "common_name": "cirrus", + "center_wavelength": 1.37, + "full_width_half_max": 0.02 } + ] + }, + "B10": { + "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B10.TIF", + "type": "image/tiff; application=geotiff", + "title": "Band 10 (lwir)", + "eo:bands": [ + { + "name": "B10", + "common_name": "lwir11", + "center_wavelength": 10.9, + "full_width_half_max": 0.8 + } + ] + }, + "B11": { + "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B11.TIF", + "type": "image/tiff; application=geotiff", + "title": "Band 11 (lwir)", + "eo:bands": [ + { + "name": "B11", + "common_name": "lwir12", + "center_wavelength": 12, + "full_width_half_max": 1 + } + ] + }, + "BQA": { + "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_BQA.TIF", + "type": "image/tiff; application=geotiff", + "title": "Band quality data" + }, + "MTL": { + "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_MTL.txt", + "type": "text/plain", + "title": "original metadata file" + }, + "thumbnail": { + "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_thumb_large.jpg", + "type": "image/jpeg", + "title": "Thumbnail image" }, - "links": [] -} + "index": { + "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/index.html", + "type": "text/html", + "title": "HTML index page" + } + }, + "bbox": [ + 148.13933, + 59.51584, + 152.52758, + 60.63437 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/eo/v1.0.0/schema.json", + "https://stac-extensions.github.io/view/v1.0.0/schema.json" + ], + "collection": "landsat-8-l1" +} \ No newline at end of file diff --git a/tests/data-files/eo/sample-bands-in-item-properties.json b/tests/data-files/eo/sample-bands-in-item-properties.json index 8781005bb..a4c7e0dce 100644 --- a/tests/data-files/eo/sample-bands-in-item-properties.json +++ b/tests/data-files/eo/sample-bands-in-item-properties.json @@ -1,25 +1,7 @@ { - "stac_version": "1.0.0-beta.2", - "stac_extensions": [ - "eo", - "view", - "https://example.com/cs-extension/1.0/schema.json" - ], "type": "Feature", - "id" : "CS3-20160503_132131_05", - "bbox": [-122.59750209, 37.48803556, -122.2880486, 37.613537207], - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [-122.308150179, 37.488035566], - [-122.597502109, 37.538869539], - [-122.576687533, 37.613537207], - [-122.288048600, 37.562818007], - [-122.308150179, 37.488035566] - ] - ] - }, + "stac_version": "1.0.0-rc.3", + "id": "CS3-20160503_132131_05", "properties": { "datetime": "2016-05-03T13:22:30Z", "title": "A CS3 item", @@ -40,7 +22,9 @@ "eo:cloud_cover": 0.12, "view:off_nadir": 1.4, "platform": "coolsat2", - "instruments": ["cool_sensor_v1"], + "instruments": [ + "cool_sensor_v1" + ], "eo:bands": [ { "name": "band1" @@ -59,27 +43,78 @@ "gsd": 0.512, "cs:type": "scene", "cs:anomalous_pixels": 0.14, - "cs:earth_sun_distance": 1.0141560, + "cs:earth_sun_distance": 1.014156, "cs:sat_id": "CS3", "cs:product_level": "LV1B" }, - "collection": "CS3", + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + -122.308150179, + 37.488035566 + ], + [ + -122.597502109, + 37.538869539 + ], + [ + -122.576687533, + 37.613537207 + ], + [ + -122.2880486, + 37.562818007 + ], + [ + -122.308150179, + 37.488035566 + ] + ] + ] + }, "links": [ - {"rel": "self", "href": "http://cool-sat.com/catalog/CS3-20160503_132130_04/CS3-20160503_132130_04.json"}, - {"rel": "parent", "href": "http://cool-sat.com/catalog/CS3-20160503_132130_04/catalog.json"}, - {"rel": "collection", "href": "http://cool-sat.com/catalog/CS3-20160503_132130_04/catalog.json"}, - {"rel": "alternate", "type": "text/html", "href": "http://cool-sat.com/catalog/CS3-20160503_132130_04/CS3-20160503_132130_04.html"} + { + "rel": "parent", + "href": "http://cool-sat.com/catalog/CS3-20160503_132130_04/catalog.json" + }, + { + "rel": "collection", + "href": "http://cool-sat.com/catalog/CS3-20160503_132130_04/catalog.json" + }, + { + "rel": "alternate", + "href": "http://cool-sat.com/catalog/CS3-20160503_132130_04/CS3-20160503_132130_04.html", + "type": "text/html" + } ], "assets": { "analytic": { "href": "http://cool-sat.com/catalog/CS3-20160503_132130_04/analytic.tif", - "title": "4-Band Analytic" + "title": "4-Band Analytic", + "eo:bands": [ + { + "name": "band1" + }, + { + "name": "band2" + }, + { + "name": "band3" + }, + { + "name": "band4" + } + ] }, "thumbnail": { "href": "http://cool-sat.com/catalog/CS3-20160503_132130_04/thumbnail.png", - "title": "Thumbnail", "type": "image/png", - "roles": [ "thumbnail" ] + "title": "Thumbnail", + "roles": [ + "thumbnail" + ] }, "udm": { "href": "http://cool-sat.com/catalog/CS3-20160503_132130_04/UDM.tif", @@ -87,14 +122,26 @@ }, "json-metadata": { "href": "http://cool-sat.com/catalog/CS3-20160503_132130_04/extended-metadata.json", - "title": "Extended Metadata", "type": "application/json", - "roles": [ "metadata" ] + "title": "Extended Metadata", + "roles": [ + "metadata" + ] }, "ephemeris": { "href": "http://cool-sat.com/catalog/CS3-20160503_132130_04/S3-20160503_132130_04.EPH", "title": "Satellite Ephemeris Metadata" } - } - -} + }, + "bbox": [ + -122.59750209, + 37.48803556, + -122.2880486, + 37.613537207 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/eo/v1.0.0/schema.json", + "https://stac-extensions.github.io/view/v1.0.0/schema.json" + ], + "collection": "CS3" +} \ No newline at end of file diff --git a/tests/data-files/examples/1.0.0-RC1/README.md b/tests/data-files/examples/1.0.0-RC1/README.md new file mode 100644 index 000000000..85b5f5a1d --- /dev/null +++ b/tests/data-files/examples/1.0.0-RC1/README.md @@ -0,0 +1,89 @@ +# STAC Examples + +This directory contains various examples for all parts of the STAC specification. It is structured to be two valid STACs, meaning both [catalog.json](catalog.json) and [collection.json](collection.json) should successfully load in various tools. They do not follow *all* the [best practices](../best-practices.md) for STAC, mostly +due to the fact that they contrive examples to show the spec and we are hosting in GitHub. But we note below where they differ from an ideal catalog. + +The various fields are mostly fictional, to be able to demonstrate the various aspects of the spec as tersely as possible. To get a sense +of real world STAC implementations we recommend exploring the [stac-examples](http://github.com/stac-utils/stac-examples) repo, which +gathers in one place copies of STAC [Items](../item-spec/item-spec.md) and [Collection](../collection-spec/collection-spec.md) +from a number of different production catalogs that all follow good STAC practices. And you should also explore the various catalogs +listed on [STAC Index](http://stacindex.org), to see full catalogs in production. + +## Organization + +This directory contains two STAC implementations, both valid, but simplified a bit to be illustrative of the key concepts, so +they do not quite follow all the best practices. + +### Simple Collection + +This STAC implementation consists of three files, all contained at the root of the examples directory + +**[collection.json](collection.json)** is a minimal 'simple collection', that links to three items. + +**[simple-item.json](simple-item.json)** is the most minimal possible compliant Item record. Most all data will +include additional fields, as STAC is designed to be a minimal common subset. But it is useful for showing exactly what is +required. + +**[core-item.json](core-item.json)** is a more realistic example, for a hypothetical analytic image +acquisition from a satellite company called 'Remote Data'. It includes additional fields covering the [common +metadata](../item-spec/common-metadata.md). It also links to a variety of assets that is typical for +satellite imagery, as most providers include a number of complementary files. + +**[extended-item.json](extended-item.json)** is arguably an even more realistic example, as it includes a number of the +[extensions](../extensions/) that are commonly used, to demonstrate how implementations tend to start with the core, and add in +a number of the core extensions. + +**[collectionless-item.json](collectionless-item.json)** demonstrates the common metadata that is only used when an Item does not have +a collection. It is recommended to organize items in collections, but we wanted to show how this works. This is not technically in the +'simple collection' of this section, but it follows the same pattern, so is included here. + +### Nested Catalog + +This STAC implementation shows a common pattern, starting with a catalog that links to a number of distinct collections, which may +link down to a number of items. + +**[catalog.json](catalog.json)** is a minimal catalog implementation, linking to two other collections. + +**[collection-only/collection.json](collection-only/collection.json)** is a collection that does not link to any items. This +demonstrates how is is possible to make use of STAC Collections without needing items, to serve as nice summarizing metadata for +tools that work with full layers / collections. This example collection is based on real Sentinel-2 values, so is not quite fictional, +but should be taken as just an example. + +**[extensions-collection/collection.json](extensions-collection/collection.json)** contains a small number of items, that demonstrate +more functionality available in STAC [extensions](../extensions/). These are linked to directly from the individual extensions. These +items follow the recommendations for [Catalog Layout Best Practices](../best-practices.md#catalog-layout). + +## In Depth + +As mentioned above, the files in this examples directory form valid STAC implementations. They are all based on a +fictional remote sensing company called 'Remote Data', with a URL at remotedata.io. This domain has not been set up, so those links +will not work, but any valid data provider should provide valid links to their homepage. + +The examples use the `rd:` prefix to show how providers can use custom fields when there are not set fields. In the examples these +do not link to a schema which is completely valid, but it is recommended that providers do write a JSON schema that can validate +their custom fields (we will work to add an example schema for the `rd:` fields in the future). + +### Catalog Type + +One of the most important STAC Best Practices is to [use links consistently](../best-practices.md#use-of-links), following one of the +described 'catalog types'. The catalogs described here are [Relative Published Catalogs](../best-practices.md#relative-published-catalog), +that use absolute URL's to refer to their assets (so would be an example of a [Self-contained Metadata +Only](../best-practices.md#self-contained-metadata-only) catalog that is published). + +### Differences with STAC Best Practices + +One of the most important documents in this repository is the one about [best practices](../best-practices.md). It describes a number +of practical recommendations gained by people actually implementing STAC. The core spec is designed to be as flexible as possible, so +that it is not too rigid and unable to handle unanticipated needs. But we recommend following as many of the best practices as is +feasible, as it will help ensure various STAC tools work much better. The examples in this folder don't align with all the best +practices, mostly because they are meant to demonstrate things as tersely as possible, and also because they live directly inside +a github repository. As many people will look at these examples and take them as 'how things should be' we felt its important to +highlight where things here differ from the actual best practices. + +#### Catalog Layout + +Another important recommendations concerns the [layout of STAC catalogs](../best-practices.md#catalog-layout). This is important +for tools to be able to expect a certain layout, and most tools will follow the described layout. The simple collection that consists +of the collection.json and its 3 linked items violates this. This is done to be able to show item examples directly in the root of +the 'examples' folder, so people don't have to dig deep into folders to get a quick example. But a proper catalog layout would +put the items in sub-directories, along with their assets. diff --git a/tests/data-files/examples/1.0.0-RC1/catalog.json b/tests/data-files/examples/1.0.0-RC1/catalog.json new file mode 100644 index 000000000..086a734e0 --- /dev/null +++ b/tests/data-files/examples/1.0.0-RC1/catalog.json @@ -0,0 +1,30 @@ +{ + "id": "examples", + "type": "Catalog", + "stac_version": "1.0.0-beta.2", + "description": "This catalog is a simple demonstration of an example catalog that is used to organize a hierarchy of collections and their items.", + "links": [ + { + "rel": "root", + "href": "./catalog.json", + "type": "application/json" + }, + { + "rel": "child", + "href": "./extensions-collection/collection.json", + "type": "application/json", + "title": "Collection Demonstrating STAC Extensions" + }, + { + "rel": "child", + "href": "./collection-only/collection.json", + "type": "application/json", + "title": "Collection with no items (standalone)" + }, + { + "rel": "self", + "href": "https://raw.githubusercontent.com/radiantearth/stac-spec/v1.0.0-RC.1/examples/catalog.json", + "type": "application/json" + } + ] +} \ No newline at end of file diff --git a/tests/data-files/examples/1.0.0-RC1/collection-only/collection.json b/tests/data-files/examples/1.0.0-RC1/collection-only/collection.json new file mode 100644 index 000000000..2c83d7df8 --- /dev/null +++ b/tests/data-files/examples/1.0.0-RC1/collection-only/collection.json @@ -0,0 +1,228 @@ +{ + "type": "Collection", + "stac_version": "1.0.0-beta.2", + "stac_extensions": [], + "id": "sentinel-2", + "title": "Sentinel-2 MSI: MultiSpectral Instrument, Level-1C", + "description": "Sentinel-2 is a wide-swath, high-resolution, multi-spectral\nimaging mission supporting Copernicus Land Monitoring studies,\nincluding the monitoring of vegetation, soil and water cover,\nas well as observation of inland waterways and coastal areas.\n\nThe Sentinel-2 data contain 13 UINT16 spectral bands representing\nTOA reflectance scaled by 10000. See the [Sentinel-2 User Handbook](https://sentinel.esa.int/documents/247904/685211/Sentinel-2_User_Handbook)\nfor details. In addition, three QA bands are present where one\n(QA60) is a bitmask band with cloud mask information. For more\ndetails, [see the full explanation of how cloud masks are computed.](https://sentinel.esa.int/web/sentinel/technical-guides/sentinel-2-msi/level-1c/cloud-masks)\n\nEach Sentinel-2 product (zip archive) may contain multiple\ngranules. Each granule becomes a separate Earth Engine asset.\nEE asset ids for Sentinel-2 assets have the following format:\nCOPERNICUS/S2/20151128T002653_20151128T102149_T56MNN. Here the\nfirst numeric part represents the sensing date and time, the\nsecond numeric part represents the product generation date and\ntime, and the final 6-character string is a unique granule identifier\nindicating its UTM grid reference (see [MGRS](https://en.wikipedia.org/wiki/Military_Grid_Reference_System)).\n\nFor more details on Sentinel-2 radiometric resoltuon, [see this page](https://earth.esa.int/web/sentinel/user-guides/sentinel-2-msi/resolutions/radiometric).\n", + "license": "proprietary", + "keywords": [ + "copernicus", + "esa", + "eu", + "msi", + "radiance", + "sentinel" + ], + "providers": [ + { + "name": "European Union/ESA/Copernicus", + "roles": [ + "producer", + "licensor" + ], + "url": "https://sentinel.esa.int/web/sentinel/user-guides/sentinel-2-msi" + } + ], + "extent": { + "spatial": { + "bbox": [ + [ + -180, + -56, + 180, + 83 + ] + ] + }, + "temporal": { + "interval": [ + [ + "2015-06-23T00:00:00Z", + null + ] + ] + } + }, + "assets": { + "metadata_iso_19139": { + "roles": [ + "metadata", + "iso-19139" + ], + "href": "https://storage.googleapis.com/open-cogs/stac-examples/sentinel-2-iso-19139.xml", + "title": "ISO 19139 metadata", + "type": "application/vnd.iso.19139+xml" + } + }, + "summaries": { + "datetime": { + "minimum": "2015-06-23T00:00:00Z", + "maximum": "2019-07-10T13:44:56Z" + }, + "platform": [ + "sentinel-2a", + "sentinel-2b" + ], + "constellation": [ + "sentinel-2" + ], + "instruments": [ + "msi" + ], + "view:off_nadir": { + "minimum": 0, + "maximum": 100 + }, + "view:sun_elevation": { + "minimum": 6.78, + "maximum": 89.9 + }, + "sci:citation": [ + "Copernicus Sentinel data [Year]" + ], + "gsd": [ + 10, + 30, + 60 + ], + "proj:epsg": [ + 32601, + 32602, + 32603, + 32604, + 32605, + 32606, + 32607, + 32608, + 32609, + 32610, + 32611, + 32612, + 32613, + 32614, + 32615, + 32616, + 32617, + 32618, + 32619, + 32620, + 32621, + 32622, + 32623, + 32624, + 32625, + 32626, + 32627, + 32628, + 32629, + 32630, + 32631, + 32632, + 32633, + 32634, + 32635, + 32636, + 32637, + 32638, + 32639, + 32640, + 32641, + 32642, + 32643, + 32644, + 32645, + 32646, + 32647, + 32648, + 32649, + 32650, + 32651, + 32652, + 32653, + 32654, + 32655, + 32656, + 32657, + 32658, + 32659, + 32660 + ], + "eo:bands": [ + { + "name": "B1", + "common_name": "coastal", + "center_wavelength": 4.439 + }, + { + "name": "B2", + "common_name": "blue", + "center_wavelength": 4.966 + }, + { + "name": "B3", + "common_name": "green", + "center_wavelength": 5.6 + }, + { + "name": "B4", + "common_name": "red", + "center_wavelength": 6.645 + }, + { + "name": "B5", + "center_wavelength": 7.039 + }, + { + "name": "B6", + "center_wavelength": 7.402 + }, + { + "name": "B7", + "center_wavelength": 7.825 + }, + { + "name": "B8", + "common_name": "nir", + "center_wavelength": 8.351 + }, + { + "name": "B8A", + "center_wavelength": 8.648 + }, + { + "name": "B9", + "center_wavelength": 9.45 + }, + { + "name": "B10", + "center_wavelength": 1.3735 + }, + { + "name": "B11", + "common_name": "swir16", + "center_wavelength": 1.6137 + }, + { + "name": "B12", + "common_name": "swir22", + "center_wavelength": 2.2024 + } + ] + }, + "links": [ + { + "rel": "parent", + "href": "../catalog.json" + }, + { + "rel": "root", + "href": "../catalog.json" + }, + { + "rel": "license", + "href": "https://scihub.copernicus.eu/twiki/pub/SciHubWebPortal/TermsConditions/Sentinel_Data_Terms_and_Conditions.pdf", + "title": "Legal notice on the use of Copernicus Sentinel Data and Service Information" + } + ] +} diff --git a/tests/data-files/examples/1.0.0-RC1/collection.json b/tests/data-files/examples/1.0.0-RC1/collection.json new file mode 100644 index 000000000..45356b103 --- /dev/null +++ b/tests/data-files/examples/1.0.0-RC1/collection.json @@ -0,0 +1,93 @@ +{ + "id": "simple-collection", + "type": "Collection", + "stac_version": "1.0.0-beta.2", + "description": "A simple collection demonstrating core catalog fields with links to a couple of items", + "title": "Simple Example Collection", + "providers": [ + { + "name": "Remote Data, Inc", + "description": "Producers of awesome spatiotemporal assets", + "roles": [ + "producer", + "processor" + ], + "url": "http://remotedata.io" + } + ], + "extent": { + "spatial": { + "bbox": [ + [ + 172.911, + 1.343, + 172.955, + 1.3691 + ] + ] + }, + "temporal": { + "interval": [ + [ + "2020-12-11T09:06:43.312000Z", + "2020-12-14T18:02:31.437000Z" + ] + ] + } + }, + "license": "CC-BY-4.0", + "summaries": { + "platform": [ + "cool_sat2", + "cool_sat1" + ], + "constellation": [ + "ion" + ], + "instruments": [ + "cool_sensor_v1" + ], + "gsd": { + "minimum": 0.512, + "maximum": 0.7 + }, + "view:off_nadir": { + "minimum": 0, + "maximum": 15 + }, + "view:sun_elevation": { + "minimum": 6.78, + "maximum": 40 + } + }, + "links": [ + { + "rel": "root", + "href": "./collection.json", + "type": "application/json" + }, + { + "rel": "item", + "href": "./simple-item.json", + "type": "application/geo+json", + "title": "Simple Item" + }, + { + "rel": "item", + "href": "./core-item.json", + "type": "application/geo+json", + "title": "Core Item" + }, + { + "rel": "item", + "href": "./extended-item.json", + "type": "application/geo+json", + "title": "Extended Item" + }, + { + "rel": "self", + "href": "https://raw.githubusercontent.com/radiantearth/stac-spec/v1.0.0-RC.1/examples/collection.json", + "type": "application/json" + } + ] +} \ No newline at end of file diff --git a/tests/data-files/examples/1.0.0-RC1/collectionless-item.json b/tests/data-files/examples/1.0.0-RC1/collectionless-item.json new file mode 100644 index 000000000..8b2e3aa09 --- /dev/null +++ b/tests/data-files/examples/1.0.0-RC1/collectionless-item.json @@ -0,0 +1,147 @@ +{ + "stac_version": "1.0.0-beta.2", + "stac_extensions": [ + "eo", + "view" + ], + "type": "Feature", + "id": "CS3-20160503_132131_08", + "bbox": [ + -122.59750209, + 37.48803556, + -122.2880486, + 37.613537207 + ], + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + -122.308150179, + 37.488035566 + ], + [ + -122.597502109, + 37.538869539 + ], + [ + -122.576687533, + 37.613537207 + ], + [ + -122.2880486, + 37.562818007 + ], + [ + -122.308150179, + 37.488035566 + ] + ] + ] + }, + "properties": { + "title": "Full Item", + "description": "A sample STAC Item demonstrates an Item that does not have a collection, which is not recommended, but allowed by the spec.", + "datetime": null, + "start_datetime": "2016-05-03T13:22:30Z", + "end_datetime": "2016-05-03T13:27:30Z", + "created": "2016-05-04T00:00:01Z", + "updated": "2017-01-01T00:30:55Z", + "license": "various", + "providers": [ + { + "name": "Remote Data, Inc", + "description": "Producers of awesome spatiotemporal assets", + "roles": [ + "producer", + "processor" + ], + "url": "http://remotedata.it" + } + ], + "platform": "cool_sat2", + "instruments": [ + "cool_sensor_v1" + ], + "view:sun_elevation": 33.4, + "gsd": 0.512, + "cs:type": "scene", + "cs:anomalous_pixels": 0.14, + "cs:earth_sun_distance": 1.014156, + "cs:sat_id": "CS3", + "cs:product_level": "LV1B" + }, + "collection": "CS3", + "links": [ + { + "rel": "collection", + "href": "./collection.json", + "type": "application/json", + "title": "Simple Example Collection" + }, + { + "rel": "root", + "href": "./collection.json", + "type": "application/json" + }, + { + "rel": "root", + "href": "./collection.json", + "type": "application/json" + }, + { + "rel": "alternate", + "type": "text/html", + "href": "http://cool-sat.com/catalog/CS3-20160503_132130_04/CS3-20160503_132130_04.html" + }, + { + "rel": "license", + "type": "text/html", + "href": "http://remotedata.io/license.html" + } + ], + "assets": { + "analytic": { + "href": "http://cool-sat.com/catalog/CS3-20160503_132130_04/analytic.tif", + "title": "4-Band Analytic", + "eo:bands": [ + { + "name": "band1" + }, + { + "name": "band1" + }, + { + "name": "band2" + }, + { + "name": "band3" + } + ] + }, + "thumbnail": { + "href": "http://cool-sat.com/catalog/CS3-20160503_132130_04/thumbnail.png", + "title": "Thumbnail", + "type": "image/png", + "roles": [ + "thumbnail" + ] + }, + "udm": { + "href": "http://cool-sat.com/catalog/CS3-20160503_132130_04/UDM.tif", + "title": "Unusable Data Mask" + }, + "json-metadata": { + "href": "http://cool-sat.com/catalog/CS3-20160503_132130_04/extended-metadata.json", + "title": "Extended Metadata", + "type": "application/json", + "roles": [ + "metadata" + ] + }, + "ephemeris": { + "href": "http://cool-sat.com/catalog/CS3-20160503_132130_04/S3-20160503_132130_04.EPH", + "title": "Satellite Ephemeris Metadata" + } + } +} \ No newline at end of file diff --git a/tests/data-files/examples/1.0.0-RC1/core-item.json b/tests/data-files/examples/1.0.0-RC1/core-item.json new file mode 100644 index 000000000..3004df37d --- /dev/null +++ b/tests/data-files/examples/1.0.0-RC1/core-item.json @@ -0,0 +1,117 @@ +{ + "stac_version": "1.0.0-beta.2", + "stac_extensions": [], + "type": "Feature", + "id": "20201211_223832_CS2", + "bbox": [ + 172.91173669923782, + 1.3438851951615003, + 172.95469614953714, + 1.3690476620161975 + ], + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + 172.91173669923782, + 1.3438851951615003 + ], + [ + 172.95469614953714, + 1.3438851951615003 + ], + [ + 172.95469614953714, + 1.3690476620161975 + ], + [ + 172.91173669923782, + 1.3690476620161975 + ], + [ + 172.91173669923782, + 1.3438851951615003 + ] + ] + ] + }, + "properties": { + "title": "Core Item", + "description": "A sample STAC Item that includes examples of all common metadata", + "datetime": null, + "start_datetime": "2020-12-11T22:38:32.125Z", + "end_datetime": "2020-12-11T22:38:32.327Z", + "created": "2020-12-12T01:48:13.725Z", + "updated": "2020-12-12T01:48:13.725Z", + "platform": "cool_sat2", + "instruments": [ + "cool_sensor_v1" + ], + "constellation": "ion", + "mission": "collection 5624", + "gsd": 0.512 + }, + "collection": "simple-collection", + "links": [ + { + "rel": "collection", + "href": "./collection.json", + "type": "application/json", + "title": "Simple Example Collection" + }, + { + "rel": "root", + "href": "./collection.json", + "type": "application/json" + }, + { + "rel": "alternate", + "type": "text/html", + "href": "http://remotedata.io/catalog/20201211_223832_CS2/index.html" + } + ], + "assets": { + "analytic": { + "href": "https://storage.googleapis.com/open-cogs/stac-examples/20201211_223832_CS2_analytic.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "4-Band Analytic", + "roles": [ + "data" + ] + }, + "thumbnail": { + "href": "https://storage.googleapis.com/open-cogs/stac-examples/20201211_223832_CS2.jpg", + "title": "Thumbnail", + "type": "image/png", + "roles": [ + "thumbnail" + ] + }, + "visual": { + "href": "https://storage.googleapis.com/open-cogs/stac-examples/20201211_223832_CS2.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "3-Band Visual", + "roles": [ + "visual" + ] + }, + "udm": { + "href": "https://storage.googleapis.com/open-cogs/stac-examples/20201211_223832_CS2_analytic_udm.tif", + "title": "Unusable Data Mask", + "type": "image/tiff; application=geotiff;" + }, + "json-metadata": { + "href": "http://remotedata.io/catalog/20201211_223832_CS2/extended-metadata.json", + "title": "Extended Metadata", + "type": "application/json", + "roles": [ + "metadata" + ] + }, + "ephemeris": { + "href": "http://cool-sat.com/catalog/20201211_223832_CS2/20201211_223832_CS2.EPH", + "title": "Satellite Ephemeris Metadata" + } + } +} \ No newline at end of file diff --git a/tests/data-files/examples/1.0.0-RC1/extended-item.json b/tests/data-files/examples/1.0.0-RC1/extended-item.json new file mode 100644 index 000000000..a84586008 --- /dev/null +++ b/tests/data-files/examples/1.0.0-RC1/extended-item.json @@ -0,0 +1,190 @@ +{ + "stac_version": "1.0.0-beta.2", + "stac_extensions": [ + "eo", + "projection", + "scientific", + "view" + ], + "type": "Feature", + "id": "20201211_223832_CS2", + "bbox": [ + 172.91173669923782, + 1.3438851951615003, + 172.95469614953714, + 1.3690476620161975 + ], + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + 172.91173669923782, + 1.3438851951615003 + ], + [ + 172.95469614953714, + 1.3438851951615003 + ], + [ + 172.95469614953714, + 1.3690476620161975 + ], + [ + 172.91173669923782, + 1.3690476620161975 + ], + [ + 172.91173669923782, + 1.3438851951615003 + ] + ] + ] + }, + "properties": { + "title": "Extended Item", + "description": "A sample STAC Item that includes a variety of examples from the stable extensions", + "datetime": "2020-12-11T22:38:32.125Z", + "created": "2020-12-12T01:48:13.725Z", + "updated": "2020-12-12T01:48:13.725Z", + "platform": "cool_sat2", + "instruments": [ + "cool_sensor_v1" + ], + "gsd": 0.66, + "eo:cloud_cover": 1.2, + "proj:epsg": 32659, + "proj:shape": [ + 5558, + 9559 + ], + "proj:transform": [ + 0.5, + 0, + 712710, + 0, + -0.5, + 151406, + 0, + 0, + 1 + ], + "view:sun_elevation": 54.9, + "view:off_nadir": 3.8, + "view:sun_azimuth": 135.7, + "rd:type": "scene", + "rd:anomalous_pixels": 0.14, + "rd:earth_sun_distance": 1.014156, + "rd:sat_id": "cool_sat2", + "rd:product_level": "LV3A", + "sci:doi": "10.5061/dryad.s2v81.2/27.2" + }, + "collection": "simple-collection", + "links": [ + { + "rel": "collection", + "href": "./collection.json", + "type": "application/json", + "title": "Simple Example Collection" + }, + { + "rel": "root", + "href": "./collection.json", + "type": "application/json" + }, + { + "rel": "alternate", + "type": "text/html", + "href": "http://remotedata.io/catalog/20201211_223832_CS2/index.html" + } + ], + "assets": { + "analytic": { + "href": "https://storage.googleapis.com/open-cogs/stac-examples/20201211_223832_CS2_analytic.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "4-Band Analytic", + "roles": [ + "data" + ], + "eo:bands": [ + { + "name": "band1", + "common_name": "blue", + "center_wavelength": 470, + "full_width_half_max": 70 + }, + { + "name": "band2", + "common_name": "green", + "center_wavelength": 560, + "full_width_half_max": 80 + }, + { + "name": "band3", + "common_name": "red", + "center_wavelength": 645, + "full_width_half_max": 90 + }, + { + "name": "band4", + "common_name": "nir", + "center_wavelength": 800, + "full_width_half_max": 152 + } + ] + }, + "thumbnail": { + "href": "https://storage.googleapis.com/open-cogs/stac-examples/20201211_223832_CS2.jpg", + "title": "Thumbnail", + "type": "image/png", + "roles": [ + "thumbnail" + ] + }, + "visual": { + "href": "https://storage.googleapis.com/open-cogs/stac-examples/20201211_223832_CS2.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "3-Band Visual", + "roles": [ + "visual" + ], + "eo:bands": [ + { + "name": "band3", + "common_name": "red", + "center_wavelength": 645, + "full_width_half_max": 90 + }, + { + "name": "band2", + "common_name": "green", + "center_wavelength": 560, + "full_width_half_max": 80 + }, + { + "name": "band1", + "common_name": "blue", + "center_wavelength": 470, + "full_width_half_max": 70 + } + ] + }, + "udm": { + "href": "https://storage.googleapis.com/open-cogs/stac-examples/20201211_223832_CS2_analytic_udm.tif", + "title": "Unusable Data Mask", + "type": "image/tiff; application=geotiff;" + }, + "json-metadata": { + "href": "http://remotedata.io/catalog/20201211_223832_CS2/extended-metadata.json", + "title": "Extended Metadata", + "type": "application/json", + "roles": [ + "metadata" + ] + }, + "ephemeris": { + "href": "http://cool-sat.com/catalog/20201211_223832_CS2/20201211_223832_CS2.EPH", + "title": "Satellite Ephemeris Metadata" + } + } +} \ No newline at end of file diff --git a/tests/data-files/examples/1.0.0-RC1/extensions-collection/collection.json b/tests/data-files/examples/1.0.0-RC1/extensions-collection/collection.json new file mode 100644 index 000000000..dabbbeda3 --- /dev/null +++ b/tests/data-files/examples/1.0.0-RC1/extensions-collection/collection.json @@ -0,0 +1,66 @@ +{ + "id": "extensions-collection", + "type": "Collection", + "stac_version": "1.0.0-beta.2", + "description": "A heterogenous collection containing deeper examples of various extensions", + "links": [ + { + "rel": "root", + "href": "../catalog.json", + "type": "application/json" + }, + { + "rel": "item", + "href": "./proj-example/proj-example.json", + "title": "Proj extension example" + }, + { + "rel": "license", + "href": "https://remotedata.io/license.html", + "title": "Remote Data License Terms" + }, + { + "rel": "parent", + "href": "../catalog.json", + "type": "application/json" + } + ], + "stac_extensions": [], + "title": "Collection of Extension Items", + "keywords": [ + "examples", + "sar", + "projection" + ], + "providers": [ + { + "name": "Remote Data, Inc.", + "roles": [ + "producer", + "licensor" + ], + "url": "https://remotedata.io" + } + ], + "extent": { + "spatial": { + "bbox": [ + [ + -180, + -56, + 180, + 83 + ] + ] + }, + "temporal": { + "interval": [ + [ + "2009-05-20T02:40:01.042784Z", + "2018-11-03T23:59:55.112875Z" + ] + ] + } + }, + "license": "PDDL-1.0" +} \ No newline at end of file diff --git a/tests/data-files/examples/1.0.0-RC1/extensions-collection/proj-example/proj-example.json b/tests/data-files/examples/1.0.0-RC1/extensions-collection/proj-example/proj-example.json new file mode 100644 index 000000000..c3eca2040 --- /dev/null +++ b/tests/data-files/examples/1.0.0-RC1/extensions-collection/proj-example/proj-example.json @@ -0,0 +1,278 @@ +{ + "type": "Feature", + "stac_version": "1.0.0-beta.2", + "id": "proj-example", + "properties": { + "datetime": "2018-10-01T01:08:32.033000Z", + "proj:epsg": 32614, + "proj:wkt2": "PROJCS[\"WGS 84 / UTM zone 14N\",GEOGCS[\"WGS 84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS 84\",6378137,298.257223563,AUTHORITY[\"EPSG\",\"7030\"]],AUTHORITY[\"EPSG\",\"6326\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.01745329251994328,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\",\"4326\"]],UNIT[\"metre\",1,AUTHORITY[\"EPSG\",\"9001\"]],PROJECTION[\"Transverse_Mercator\"],PARAMETER[\"latitude_of_origin\",0],PARAMETER[\"central_meridian\",-99],PARAMETER[\"scale_factor\",0.9996],PARAMETER[\"false_easting\",500000],PARAMETER[\"false_northing\",0],AUTHORITY[\"EPSG\",\"32614\"],AXIS[\"Easting\",EAST],AXIS[\"Northing\",NORTH]]", + "proj:projjson": { + "$schema": "https://proj.org/schemas/v0.2/projjson.schema.json", + "type": "ProjectedCRS", + "name": "WGS 84 / UTM zone 14N", + "base_crs": { + "name": "WGS 84", + "datum": { + "type": "GeodeticReferenceFrame", + "name": "World Geodetic System 1984", + "ellipsoid": { + "name": "WGS 84", + "semi_major_axis": 6378137, + "inverse_flattening": 298.257223563 + } + }, + "coordinate_system": { + "subtype": "ellipsoidal", + "axis": [ + { + "name": "Geodetic latitude", + "abbreviation": "Lat", + "direction": "north", + "unit": "degree" + }, + { + "name": "Geodetic longitude", + "abbreviation": "Lon", + "direction": "east", + "unit": "degree" + } + ] + }, + "id": { + "authority": "EPSG", + "code": 4326 + } + }, + "conversion": { + "name": "UTM zone 14N", + "method": { + "name": "Transverse Mercator", + "id": { + "authority": "EPSG", + "code": 9807 + } + }, + "parameters": [ + { + "name": "Latitude of natural origin", + "value": 0, + "unit": "degree", + "id": { + "authority": "EPSG", + "code": 8801 + } + }, + { + "name": "Longitude of natural origin", + "value": -99, + "unit": "degree", + "id": { + "authority": "EPSG", + "code": 8802 + } + }, + { + "name": "Scale factor at natural origin", + "value": 0.9996, + "unit": "unity", + "id": { + "authority": "EPSG", + "code": 8805 + } + }, + { + "name": "False easting", + "value": 500000, + "unit": "metre", + "id": { + "authority": "EPSG", + "code": 8806 + } + }, + { + "name": "False northing", + "value": 0, + "unit": "metre", + "id": { + "authority": "EPSG", + "code": 8807 + } + } + ] + }, + "coordinate_system": { + "subtype": "Cartesian", + "axis": [ + { + "name": "Easting", + "abbreviation": "E", + "direction": "east", + "unit": "metre" + }, + { + "name": "Northing", + "abbreviation": "N", + "direction": "north", + "unit": "metre" + } + ] + }, + "area": "World - N hemisphere - 102°W to 96°W - by country", + "bbox": { + "south_latitude": 0, + "west_longitude": -102, + "north_latitude": 84, + "east_longitude": -96 + }, + "id": { + "authority": "EPSG", + "code": 32614 + } + }, + "proj:geometry": { + "coordinates": [ + [ + [ + 169200, + 3712800 + ], + [ + 403200, + 3712800 + ], + [ + 403200, + 3951000 + ], + [ + 169200, + 3951000 + ], + [ + 169200, + 3712800 + ] + ] + ], + "type": "Polygon" + }, + "proj:bbox": [ + 169200, + 3712800, + 403200, + 3951000 + ], + "proj:centroid": { + "lat": 34.595302781575604, + "lon": -101.34448382627504 + }, + "proj:shape": [ + 8391, + 8311 + ], + "proj:transform": [ + 30, + 0, + 224985, + 0, + -30, + 6790215, + 0, + 0, + 1 + ] + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + 152.52758, + 60.63437 + ], + [ + 149.1755, + 61.19016 + ], + [ + 148.13933, + 59.51584 + ], + [ + 151.33786, + 58.97792 + ], + [ + 152.52758, + 60.63437 + ] + ] + ] + }, + "links": [ + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "B1": { + "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B1.TIF", + "type": "image/tiff; application=geotiff", + "title": "Band 1 (coastal)", + "eo:bands": [ + { + "name": "B1", + "common_name": "coastal", + "center_wavelength": 0.44, + "full_width_half_max": 0.02 + } + ] + }, + "B8": { + "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B8.TIF", + "type": "image/tiff; application=geotiff", + "title": "Band 8 (panchromatic)", + "eo:bands": [ + { + "name": "B8", + "common_name": "panchromatic", + "center_wavelength": 0.59, + "full_width_half_max": 0.18 + } + ], + "proj:shape": [ + 16781, + 16621 + ], + "proj:transform": [ + 15, + 0, + 224992.5, + 0, + -15, + 6790207.5, + 0, + 0, + 1 + ] + } + }, + "bbox": [ + 148.13933, + 59.51584, + 152.52758, + 60.63437 + ], + "stac_extensions": [ + "eo", + "projection" + ], + "collection": "landsat-8-l1" +} \ No newline at end of file diff --git a/tests/data-files/examples/1.0.0-RC1/simple-item.json b/tests/data-files/examples/1.0.0-RC1/simple-item.json new file mode 100644 index 000000000..38921081d --- /dev/null +++ b/tests/data-files/examples/1.0.0-RC1/simple-item.json @@ -0,0 +1,74 @@ +{ + "stac_version": "1.0.0-beta.2", + "stac_extensions": [], + "type": "Feature", + "id": "20201211_223832_CS2", + "bbox": [ + 172.91173669923782, + 1.3438851951615003, + 172.95469614953714, + 1.3690476620161975 + ], + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + 172.91173669923782, + 1.3438851951615003 + ], + [ + 172.95469614953714, + 1.3438851951615003 + ], + [ + 172.95469614953714, + 1.3690476620161975 + ], + [ + 172.91173669923782, + 1.3690476620161975 + ], + [ + 172.91173669923782, + 1.3438851951615003 + ] + ] + ] + }, + "properties": { + "datetime": "2020-12-11T22:38:32.125000Z", + "collection": "simple-collection" + }, + "links": [ + { + "rel": "collection", + "href": "./collection.json", + "type": "application/json", + "title": "Simple Example Collection" + }, + { + "rel": "root", + "href": "./collection.json", + "type": "application/json" + } + ], + "assets": { + "visual": { + "href": "https://storage.googleapis.com/open-cogs/stac-examples/20201211_223832_CS2.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "3-Band Visual", + "roles": [ + "visual" + ] + }, + "thumbnail": { + "href": "https://storage.googleapis.com/open-cogs/stac-examples/20201211_223832_CS2.jpg", + "title": "Thumbnail", + "type": "image/jpeg", + "roles": [ + "thumbnail" + ] + } + } +} \ No newline at end of file diff --git a/tests/data-files/examples/1.0.0-RC3/README.md b/tests/data-files/examples/1.0.0-RC3/README.md new file mode 100644 index 000000000..a4d046a94 --- /dev/null +++ b/tests/data-files/examples/1.0.0-RC3/README.md @@ -0,0 +1,91 @@ +# STAC Examples + +This directory contains various examples for all parts of the STAC specification. +It is structured to be two valid STACs, meaning both [catalog.json](catalog.json) and [collection.json](collection.json) +should successfully load in various tools. They do not follow *all* the [best practices](../best-practices.md) for STAC, mostly +due to the fact that they contrive examples to show the spec and we are hosting in GitHub. But we note below where they differ from an ideal catalog. + +The various fields are mostly fictional, to be able to demonstrate the various aspects of the spec as tersely as possible. To get a sense +of real world STAC implementations we recommend exploring the [stac-examples](http://github.com/stac-utils/stac-examples) repo, which +gathers in one place copies of STAC [Items](../item-spec/item-spec.md) and [Collection](../collection-spec/collection-spec.md) +from a number of different production catalogs that all follow good STAC practices. And you should also explore the various catalogs +listed on [STAC Index](http://stacindex.org), to see full catalogs in production. + +## Organization + +This directory contains two STAC implementations, both valid, but simplified a bit to be illustrative of the key concepts, so +they do not quite follow all the best practices. + +### Simple Collection + +This STAC implementation consists of three files, all contained at the root of the examples directory + +**[collection.json](collection.json)** is a minimal 'simple collection', that links to three items. + +**[simple-item.json](simple-item.json)** is the most minimal possible compliant Item record. Most all data will +include additional fields, as STAC is designed to be a minimal common subset. But it is useful for showing exactly what is +required. + +**[core-item.json](core-item.json)** is a more realistic example, for a hypothetical analytic image +acquisition from a satellite company called 'Remote Data'. It includes additional fields covering the [common +metadata](../item-spec/common-metadata.md). It also links to a variety of assets that is typical for +satellite imagery, as most providers include a number of complementary files. + +**[extended-item.json](extended-item.json)** is arguably an even more realistic example, as it includes a number of the +[extensions](../extensions/) that are commonly used, to demonstrate how implementations tend to start with the core, and add in +a number of the core extensions. + +**[collectionless-item.json](collectionless-item.json)** demonstrates the common metadata that is only used when an Item does not have +a collection. It is recommended to organize items in collections, but we wanted to show how this works. This is not technically in the +'simple collection' of this section, but it follows the same pattern, so is included here. + +### Nested Catalog + +This STAC implementation shows a common pattern, starting with a catalog that links to a number of distinct collections, which may +link down to a number of items. + +**[catalog.json](catalog.json)** is a minimal catalog implementation, linking to two other collections. + +**[collection-only/collection.json](collection-only/collection.json)** is a collection that does not link to any items. This +demonstrates how is is possible to make use of STAC Collections without needing items, to serve as nice summarizing metadata for +tools that work with full layers / collections. This example collection is based on real Sentinel-2 values, so is not quite fictional, +but should be taken as just an example. + +**[extensions-collection/collection.json](extensions-collection/collection.json)** contains a small number of items, that demonstrate +more functionality available in STAC [extensions](../extensions/). These are linked to directly from the individual extensions. These +items follow the recommendations for [Catalog Layout Best Practices](../best-practices.md#catalog-layout). + +## In Depth + +As mentioned above, the files in this examples directory form valid STAC implementations. They are all based on a +fictional remote sensing company called 'Remote Data', with a URL at remotedata.io. This domain has not been set up, so those links +will not work, but any valid data provider should provide valid links to their homepage. + +The examples use the `rd:` prefix to show how providers can use custom fields when there are not set fields. In the examples these +do not link to a schema which is completely valid, but it is recommended that providers do write a JSON schema that can validate +their custom fields (we will work to add an example schema for the `rd:` fields in the future). + +### Catalog Type + +One of the most important STAC Best Practices is to [use links consistently](../best-practices.md#use-of-links), following one of the +described 'catalog types'. The catalogs described here are [Relative Published Catalogs](../best-practices.md#relative-published-catalog), +that use absolute URL's to refer to their assets (so would be an example of a [Self-contained Metadata +Only](../best-practices.md#self-contained-metadata-only) catalog that is published). + +### Differences with STAC Best Practices + +One of the most important documents in this repository is the one about [best practices](../best-practices.md). It describes a number +of practical recommendations gained by people actually implementing STAC. The core spec is designed to be as flexible as possible, so +that it is not too rigid and unable to handle unanticipated needs. But we recommend following as many of the best practices as is +feasible, as it will help ensure various STAC tools work much better. The examples in this folder don't align with all the best +practices, mostly because they are meant to demonstrate things as tersely as possible, and also because they live directly inside +a github repository. As many people will look at these examples and take them as 'how things should be' we felt its important to +highlight where things here differ from the actual best practices. + +#### Catalog Layout + +Another important recommendations concerns the [layout of STAC catalogs](../best-practices.md#catalog-layout). This is important +for tools to be able to expect a certain layout, and most tools will follow the described layout. The simple collection that consists +of the collection.json and its 3 linked items violates this. This is done to be able to show item examples directly in the root of +the 'examples' folder, so people don't have to dig deep into folders to get a quick example. But a proper catalog layout would +put the items in sub-directories, along with their assets. diff --git a/tests/data-files/examples/1.0.0-RC3/catalog.json b/tests/data-files/examples/1.0.0-RC3/catalog.json new file mode 100644 index 000000000..1003b20b7 --- /dev/null +++ b/tests/data-files/examples/1.0.0-RC3/catalog.json @@ -0,0 +1,42 @@ +{ + "id": "examples", + "type": "Catalog", + "stac_version": "1.0.0-rc.3", + "description": "This catalog is a simple demonstration of an example catalog that is used to organize a hierarchy of collections and their items.", + "links": [ + { + "rel": "root", + "href": "./catalog.json", + "type": "application/json" + }, + { + "rel": "child", + "href": "./extensions-collection/collection.json", + "type": "application/json", + "title": "Collection Demonstrating STAC Extensions" + }, + { + "rel": "child", + "href": "./collection-only/collection.json", + "type": "application/json", + "title": "Collection with no items (standalone)" + }, + { + "rel": "child", + "href": "./collection-only/collection-with-schemas.json", + "type": "application/json", + "title": "Collection with no items (standalone with JSON Schemas)" + }, + { + "rel": "item", + "href": "./collectionless-item.json", + "type": "application/json", + "title": "Collection with no items (standalone)" + }, + { + "rel": "self", + "href": "https://raw.githubusercontent.com/radiantearth/stac-spec/v1.0.0-rc.3/examples/catalog.json", + "type": "application/json" + } + ] +} diff --git a/tests/data-files/examples/1.0.0-RC3/collection-only/collection-with-schemas.json b/tests/data-files/examples/1.0.0-RC3/collection-only/collection-with-schemas.json new file mode 100644 index 000000000..1cddc65c7 --- /dev/null +++ b/tests/data-files/examples/1.0.0-RC3/collection-only/collection-with-schemas.json @@ -0,0 +1,273 @@ +{ + "stac_version": "1.0.0-rc.3", + "stac_extensions": [ + "https://stac-extensions.github.io/eo/v1.0.0/schema.json", + "https://stac-extensions.github.io/sat/v1.0.0/schema.json", + "https://stac-extensions.github.io/view/v1.0.0/schema.json" + ], + "id": "sentinel-2", + "type": "Collection", + "title": "Sentinel-2 MSI: MultiSpectral Instrument, Level-2A", + "description": "The SENTINEL-2 mission is a land monitoring constellation of two satellites each equipped with a MSI (Multispectral Imager) instrument covering 13 spectral bands providing high resolution optical imagery (i.e., 10m, 20m, 60 m) every 10 days with one satellite and 5 days with two satellites", + "license": "proprietary", + "extent": { + "spatial": { + "bbox": [ + [ + -180, + -82.852377834669, + 180, + 82.819463367711 + ] + ] + }, + "temporal": { + "interval": [ + [ + "2017-04-12T02:57:21.459000Z", + "2021-04-22T11:30:12.767000Z" + ] + ] + } + }, + "links": [ + { + "rel": "parent", + "href": "../catalog.json" + }, + { + "rel": "root", + "href": "../catalog.json" + }, + { + "rel": "license", + "href": "https://scihub.copernicus.eu/twiki/pub/SciHubWebPortal/TermsConditions/Sentinel_Data_Terms_and_Conditions.pdf", + "title": "Legal notice on the use of Copernicus Sentinel Data and Service Information" + } + ], + "providers": [ + { + "name": "European Union/ESA/Copernicus", + "roles": [ + "producer", + "licensor" + ], + "url": "https://sentinel.esa.int/web/sentinel/user-guides/sentinel-2-msi" + }, + { + "name": "AWS", + "roles": [ + "host" + ], + "url": "https://registry.opendata.aws/sentinel-2/" + }, + { + "name": "jeobrowser", + "roles": [ + "processor" + ], + "url": "https://github.com/jjrom/resto" + } + ], + "summaries": { + "datetime": { + "minimum": "2017-04-12T02:57:21Z", + "maximum": "2021-04-22T11:30:12Z" + }, + "instruments": { + "type": "string", + "const": "msi", + "title": "Multispectral Intrument", + "count": 6613431 + }, + "resto:landcover": { + "type": "string", + "oneOf": [ + { + "const": "cultivated", + "title": "Cultivated", + "count": 490750 + }, + { + "const": "desert", + "title": "Desert", + "count": 543120 + }, + { + "const": "flooded", + "title": "Flooded", + "count": 5187 + }, + { + "const": "forest", + "title": "Forest", + "count": 767807 + }, + { + "const": "herbaceous", + "title": "Herbaceous", + "count": 674281 + }, + { + "const": "ice", + "title": "Ice", + "count": 231285 + }, + { + "const": "urban", + "title": "Urban", + "count": 1219 + }, + { + "const": "water", + "title": "Water", + "count": 2303314 + } + ] + }, + "resto:location": { + "type": "string", + "oneOf": [ + { + "const": "tropical", + "title": "Tropical", + "count": 1807474 + }, + { + "const": "southern", + "title": "Southern", + "count": 1671685 + }, + { + "const": "northern", + "title": "Northern", + "count": 4876669 + }, + { + "const": "equatorial", + "title": "Equatorial", + "count": 27302 + }, + { + "const": "coastal", + "title": "Coastal", + "count": 1495516 + } + ] + }, + "platform": { + "type": "string", + "oneOf": [ + { + "const": "sentinel-2b", + "title": "Sentinel 2B", + "count": 3495597 + }, + { + "const": "sentinel-2a", + "title": "Sentinel 2A", + "count": 3117831 + } + ] + }, + "resto:season": { + "type": "integer", + "oneOf": [ + { + "const": 0, + "title": "Winter", + "count": 1621108 + }, + { + "const": 2, + "title": "Summer", + "count": 2279472 + }, + { + "const": 1, + "title": "Spring", + "count": 1577067 + }, + { + "const": 3, + "title": "Autumn", + "count": 1098015 + } + ] + }, + "eo:bands": [ + { + "title": "B1", + "common_name": "coastal", + "center_wavelength": 4.439, + "gsd": 60 + }, + { + "title": "B2", + "common_name": "blue", + "center_wavelength": 4.966, + "gsd": 10 + }, + { + "title": "B3", + "common_name": "green", + "center_wavelength": 5.6, + "gsd": 10 + }, + { + "title": "B4", + "common_name": "red", + "center_wavelength": 6.645, + "gsd": 10 + }, + { + "title": "B5", + "center_wavelength": 7.039, + "gsd": 20 + }, + { + "title": "B6", + "center_wavelength": 7.402, + "gsd": 20 + }, + { + "title": "B7", + "center_wavelength": 7.825, + "gsd": 20 + }, + { + "title": "B8", + "common_name": "nir", + "center_wavelength": 8.351, + "gsd": 10 + }, + { + "title": "B8A", + "center_wavelength": 8.648, + "gsd": 20 + }, + { + "title": "B9", + "center_wavelength": 9.45, + "gsd": 60 + }, + { + "title": "B10", + "center_wavelength": 1.3735, + "gsd": 60 + }, + { + "title": "B11", + "common_name": "swir16", + "center_wavelength": 1.6137, + "gsd": 20 + }, + { + "title": "B12", + "common_name": "swir22", + "center_wavelength": 2.2024, + "gsd": 20 + } + ] + } +} \ No newline at end of file diff --git a/tests/data-files/examples/1.0.0-RC3/collection-only/collection.json b/tests/data-files/examples/1.0.0-RC3/collection-only/collection.json new file mode 100644 index 000000000..c5cb7a2cc --- /dev/null +++ b/tests/data-files/examples/1.0.0-RC3/collection-only/collection.json @@ -0,0 +1,229 @@ +{ + "type": "Collection", + "stac_version": "1.0.0-rc.3", + "stac_extensions": [ + "https://stac-extensions.github.io/eo/v1.0.0/schema.json", + "https://stac-extensions.github.io/projection/v1.0.0/schema.json", + "https://stac-extensions.github.io/view/v1.0.0/schema.json" + ], + "id": "sentinel-2", + "title": "Sentinel-2 MSI: MultiSpectral Instrument, Level-1C", + "description": "Sentinel-2 is a wide-swath, high-resolution, multi-spectral\nimaging mission supporting Copernicus Land Monitoring studies,\nincluding the monitoring of vegetation, soil and water cover,\nas well as observation of inland waterways and coastal areas.\n\nThe Sentinel-2 data contain 13 UINT16 spectral bands representing\nTOA reflectance scaled by 10000. See the [Sentinel-2 User Handbook](https://sentinel.esa.int/documents/247904/685211/Sentinel-2_User_Handbook)\nfor details. In addition, three QA bands are present where one\n(QA60) is a bitmask band with cloud mask information. For more\ndetails, [see the full explanation of how cloud masks are computed.](https://sentinel.esa.int/web/sentinel/technical-guides/sentinel-2-msi/level-1c/cloud-masks)\n\nEach Sentinel-2 product (zip archive) may contain multiple\ngranules. Each granule becomes a separate Earth Engine asset.\nEE asset ids for Sentinel-2 assets have the following format:\nCOPERNICUS/S2/20151128T002653_20151128T102149_T56MNN. Here the\nfirst numeric part represents the sensing date and time, the\nsecond numeric part represents the product generation date and\ntime, and the final 6-character string is a unique granule identifier\nindicating its UTM grid reference (see [MGRS](https://en.wikipedia.org/wiki/Military_Grid_Reference_System)).\n\nFor more details on Sentinel-2 radiometric resoltuon, [see this page](https://earth.esa.int/web/sentinel/user-guides/sentinel-2-msi/resolutions/radiometric).\n", + "license": "proprietary", + "keywords": [ + "copernicus", + "esa", + "eu", + "msi", + "radiance", + "sentinel" + ], + "providers": [ + { + "name": "European Union/ESA/Copernicus", + "roles": [ + "producer", + "licensor" + ], + "url": "https://sentinel.esa.int/web/sentinel/user-guides/sentinel-2-msi" + } + ], + "extent": { + "spatial": { + "bbox": [ + [ + -180, + -56, + 180, + 83 + ] + ] + }, + "temporal": { + "interval": [ + [ + "2015-06-23T00:00:00Z", + null + ] + ] + } + }, + "assets": { + "metadata_iso_19139": { + "roles": [ + "metadata", + "iso-19139" + ], + "href": "https://storage.googleapis.com/open-cogs/stac-examples/sentinel-2-iso-19139.xml", + "title": "ISO 19139 metadata", + "type": "application/vnd.iso.19139+xml" + } + }, + "summaries": { + "datetime": { + "minimum": "2015-06-23T00:00:00Z", + "maximum": "2019-07-10T13:44:56Z" + }, + "platform": [ + "sentinel-2a", + "sentinel-2b" + ], + "constellation": [ + "sentinel-2" + ], + "instruments": [ + "msi" + ], + "view:off_nadir": { + "minimum": 0, + "maximum": 100 + }, + "view:sun_elevation": { + "minimum": 6.78, + "maximum": 89.9 + }, + "gsd": [ + 10, + 30, + 60 + ], + "proj:epsg": [ + 32601, + 32602, + 32603, + 32604, + 32605, + 32606, + 32607, + 32608, + 32609, + 32610, + 32611, + 32612, + 32613, + 32614, + 32615, + 32616, + 32617, + 32618, + 32619, + 32620, + 32621, + 32622, + 32623, + 32624, + 32625, + 32626, + 32627, + 32628, + 32629, + 32630, + 32631, + 32632, + 32633, + 32634, + 32635, + 32636, + 32637, + 32638, + 32639, + 32640, + 32641, + 32642, + 32643, + 32644, + 32645, + 32646, + 32647, + 32648, + 32649, + 32650, + 32651, + 32652, + 32653, + 32654, + 32655, + 32656, + 32657, + 32658, + 32659, + 32660 + ], + "eo:bands": [ + { + "name": "B1", + "common_name": "coastal", + "center_wavelength": 4.439 + }, + { + "name": "B2", + "common_name": "blue", + "center_wavelength": 4.966 + }, + { + "name": "B3", + "common_name": "green", + "center_wavelength": 5.6 + }, + { + "name": "B4", + "common_name": "red", + "center_wavelength": 6.645 + }, + { + "name": "B5", + "center_wavelength": 7.039 + }, + { + "name": "B6", + "center_wavelength": 7.402 + }, + { + "name": "B7", + "center_wavelength": 7.825 + }, + { + "name": "B8", + "common_name": "nir", + "center_wavelength": 8.351 + }, + { + "name": "B8A", + "center_wavelength": 8.648 + }, + { + "name": "B9", + "center_wavelength": 9.45 + }, + { + "name": "B10", + "center_wavelength": 1.3735 + }, + { + "name": "B11", + "common_name": "swir16", + "center_wavelength": 1.6137 + }, + { + "name": "B12", + "common_name": "swir22", + "center_wavelength": 2.2024 + } + ] + }, + "links": [ + { + "rel": "parent", + "href": "../catalog.json" + }, + { + "rel": "root", + "href": "../catalog.json" + }, + { + "rel": "license", + "href": "https://scihub.copernicus.eu/twiki/pub/SciHubWebPortal/TermsConditions/Sentinel_Data_Terms_and_Conditions.pdf", + "title": "Legal notice on the use of Copernicus Sentinel Data and Service Information" + } + ] +} diff --git a/tests/data-files/examples/1.0.0-RC3/collection.json b/tests/data-files/examples/1.0.0-RC3/collection.json new file mode 100644 index 000000000..790bcf8da --- /dev/null +++ b/tests/data-files/examples/1.0.0-RC3/collection.json @@ -0,0 +1,110 @@ +{ + "id": "simple-collection", + "type": "Collection", + "stac_extensions": [ + "https://stac-extensions.github.io/eo/v1.0.0/schema.json", + "https://stac-extensions.github.io/view/v1.0.0/schema.json" + ], + "stac_version": "1.0.0-rc.3", + "description": "A simple collection demonstrating core catalog fields with links to a couple of items", + "title": "Simple Example Collection", + "providers": [ + { + "name": "Remote Data, Inc", + "description": "Producers of awesome spatiotemporal assets", + "roles": [ + "producer", + "processor" + ], + "url": "http://remotedata.io" + } + ], + "extent": { + "spatial": { + "bbox": [ + [ + 172.91173669923782, + 1.3438851951615003, + 172.95469614953714, + 1.3690476620161975 + ] + ] + }, + "temporal": { + "interval": [ + [ + "2020-12-11T22:38:32.125Z", + "2020-12-14T18:02:31.437Z" + ] + ] + } + }, + "license": "CC-BY-4.0", + "summaries": { + "platform": [ + "cool_sat1", + "cool_sat2" + ], + "constellation": [ + "ion" + ], + "instruments": [ + "cool_sensor_v1", + "cool_sensor_v2" + ], + "gsd": { + "minimum": 0.512, + "maximum": 0.66 + }, + "eo:cloud_cover": { + "minimum": 1.2, + "maximum": 1.2 + }, + "proj:epsg": { + "minimum": 32659, + "maximum": 32659 + }, + "view:sun_elevation": { + "minimum": 54.9, + "maximum": 54.9 + }, + "view:off_nadir": { + "minimum": 3.8, + "maximum": 3.8 + }, + "view:sun_azimuth": { + "minimum": 135.7, + "maximum": 135.7 + } + }, + "links": [ + { + "rel": "root", + "href": "./collection.json", + "type": "application/json" + }, + { + "rel": "item", + "href": "./simple-item.json", + "type": "application/geo+json", + "title": "Simple Item" + }, + { + "rel": "item", + "href": "./core-item.json", + "type": "application/geo+json", + "title": "Core Item" + }, + { + "rel": "item", + "href": "./extended-item.json", + "type": "application/geo+json", + "title": "Extended Item" + }, + { + "rel": "self", + "href": "https://raw.githubusercontent.com/radiantearth/stac-spec/v1.0.0-rc.3/examples/collection.json", + "type": "application/json" + } + ] +} diff --git a/tests/data-files/examples/1.0.0-RC3/collectionless-item.json b/tests/data-files/examples/1.0.0-RC3/collectionless-item.json new file mode 100644 index 000000000..c4b224d5e --- /dev/null +++ b/tests/data-files/examples/1.0.0-RC3/collectionless-item.json @@ -0,0 +1,140 @@ +{ + "stac_version": "1.0.0-rc.3", + "stac_extensions": [ + "https://stac-extensions.github.io/eo/v1.0.0/schema.json", + "https://stac-extensions.github.io/view/v1.0.0/schema.json" + ], + "type": "Feature", + "id": "CS3-20160503_132131_08", + "bbox": [ + -122.59750209, + 37.48803556, + -122.2880486, + 37.613537207 + ], + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + -122.308150179, + 37.488035566 + ], + [ + -122.597502109, + 37.538869539 + ], + [ + -122.576687533, + 37.613537207 + ], + [ + -122.2880486, + 37.562818007 + ], + [ + -122.308150179, + 37.488035566 + ] + ] + ] + }, + "properties": { + "title": "Full Item", + "description": "A sample STAC Item demonstrates an Item that does not have a collection, which is not recommended, but allowed by the spec.", + "datetime": null, + "start_datetime": "2016-05-03T13:22:30Z", + "end_datetime": "2016-05-03T13:27:30Z", + "created": "2016-05-04T00:00:01Z", + "updated": "2017-01-01T00:30:55Z", + "license": "various", + "providers": [ + { + "name": "Remote Data, Inc", + "description": "Producers of awesome spatiotemporal assets", + "roles": [ + "producer", + "processor" + ], + "url": "http://remotedata.it" + } + ], + "platform": "cool_sat2", + "instruments": [ + "cool_sensor_v1" + ], + "view:sun_elevation": 33.4, + "gsd": 0.512, + "cs:type": "scene", + "cs:anomalous_pixels": 0.14, + "cs:earth_sun_distance": 1.014156, + "cs:sat_id": "CS3", + "cs:product_level": "LV1B" + }, + "links": [ + { + "rel": "root", + "href": "./catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "./catalog.json", + "type": "application/json" + }, + { + "rel": "alternate", + "type": "text/html", + "href": "http://cool-sat.com/catalog/CS3-20160503_132130_04/CS3-20160503_132130_04.html" + }, + { + "rel": "license", + "type": "text/html", + "href": "http://remotedata.io/license.html" + } + ], + "assets": { + "analytic": { + "href": "http://cool-sat.com/catalog/CS3-20160503_132130_04/analytic.tif", + "title": "4-Band Analytic", + "eo:bands": [ + { + "name": "band1" + }, + { + "name": "band1" + }, + { + "name": "band2" + }, + { + "name": "band3" + } + ] + }, + "thumbnail": { + "href": "http://cool-sat.com/catalog/CS3-20160503_132130_04/thumbnail.png", + "title": "Thumbnail", + "type": "image/png", + "roles": [ + "thumbnail" + ] + }, + "udm": { + "href": "http://cool-sat.com/catalog/CS3-20160503_132130_04/UDM.tif", + "title": "Unusable Data Mask" + }, + "json-metadata": { + "href": "http://cool-sat.com/catalog/CS3-20160503_132130_04/extended-metadata.json", + "title": "Extended Metadata", + "type": "application/json", + "roles": [ + "metadata" + ] + }, + "ephemeris": { + "href": "http://cool-sat.com/catalog/CS3-20160503_132130_04/S3-20160503_132130_04.EPH", + "title": "Satellite Ephemeris Metadata" + } + } +} diff --git a/tests/data-files/examples/1.0.0-RC3/core-item.json b/tests/data-files/examples/1.0.0-RC3/core-item.json new file mode 100644 index 000000000..dc95ff807 --- /dev/null +++ b/tests/data-files/examples/1.0.0-RC3/core-item.json @@ -0,0 +1,122 @@ +{ + "stac_version": "1.0.0-rc.3", + "stac_extensions": [], + "type": "Feature", + "id": "20201211_223832_CS2", + "bbox": [ + 172.91173669923782, + 1.3438851951615003, + 172.95469614953714, + 1.3690476620161975 + ], + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + 172.91173669923782, + 1.3438851951615003 + ], + [ + 172.95469614953714, + 1.3438851951615003 + ], + [ + 172.95469614953714, + 1.3690476620161975 + ], + [ + 172.91173669923782, + 1.3690476620161975 + ], + [ + 172.91173669923782, + 1.3438851951615003 + ] + ] + ] + }, + "properties": { + "title": "Core Item", + "description": "A sample STAC Item that includes examples of all common metadata", + "datetime": null, + "start_datetime": "2020-12-11T22:38:32.125Z", + "end_datetime": "2020-12-11T22:38:32.327Z", + "created": "2020-12-12T01:48:13.725Z", + "updated": "2020-12-12T01:48:13.725Z", + "platform": "cool_sat1", + "instruments": [ + "cool_sensor_v1" + ], + "constellation": "ion", + "mission": "collection 5624", + "gsd": 0.512 + }, + "collection": "simple-collection", + "links": [ + { + "rel": "collection", + "href": "./collection.json", + "type": "application/json", + "title": "Simple Example Collection" + }, + { + "rel": "root", + "href": "./collection.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "./collection.json", + "type": "application/json" + }, + { + "rel": "alternate", + "type": "text/html", + "href": "http://remotedata.io/catalog/20201211_223832_CS2/index.html" + } + ], + "assets": { + "analytic": { + "href": "https://storage.googleapis.com/open-cogs/stac-examples/20201211_223832_CS2_analytic.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "4-Band Analytic", + "roles": [ + "data" + ] + }, + "thumbnail": { + "href": "https://storage.googleapis.com/open-cogs/stac-examples/20201211_223832_CS2.jpg", + "title": "Thumbnail", + "type": "image/png", + "roles": [ + "thumbnail" + ] + }, + "visual": { + "href": "https://storage.googleapis.com/open-cogs/stac-examples/20201211_223832_CS2.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "3-Band Visual", + "roles": [ + "visual" + ] + }, + "udm": { + "href": "https://storage.googleapis.com/open-cogs/stac-examples/20201211_223832_CS2_analytic_udm.tif", + "title": "Unusable Data Mask", + "type": "image/tiff; application=geotiff;" + }, + "json-metadata": { + "href": "http://remotedata.io/catalog/20201211_223832_CS2/extended-metadata.json", + "title": "Extended Metadata", + "type": "application/json", + "roles": [ + "metadata" + ] + }, + "ephemeris": { + "href": "http://cool-sat.com/catalog/20201211_223832_CS2/20201211_223832_CS2.EPH", + "title": "Satellite Ephemeris Metadata" + } + } +} diff --git a/tests/data-files/examples/1.0.0-RC3/extended-item.json b/tests/data-files/examples/1.0.0-RC3/extended-item.json new file mode 100644 index 000000000..85b3f5987 --- /dev/null +++ b/tests/data-files/examples/1.0.0-RC3/extended-item.json @@ -0,0 +1,196 @@ +{ + "stac_version": "1.0.0-rc.3", + "stac_extensions": [ + "https://stac-extensions.github.io/eo/v1.0.0/schema.json", + "https://stac-extensions.github.io/projection/v1.0.0/schema.json", + "https://stac-extensions.github.io/scientific/v1.0.0/schema.json", + "https://stac-extensions.github.io/view/v1.0.0/schema.json", + "https://stac-extensions.github.io/remote-data/v1.0.0/schema.json" + ], + "type": "Feature", + "id": "20201211_223832_CS2", + "bbox": [ + 172.91173669923782, + 1.3438851951615003, + 172.95469614953714, + 1.3690476620161975 + ], + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + 172.91173669923782, + 1.3438851951615003 + ], + [ + 172.95469614953714, + 1.3438851951615003 + ], + [ + 172.95469614953714, + 1.3690476620161975 + ], + [ + 172.91173669923782, + 1.3690476620161975 + ], + [ + 172.91173669923782, + 1.3438851951615003 + ] + ] + ] + }, + "properties": { + "title": "Extended Item", + "description": "A sample STAC Item that includes a variety of examples from the stable extensions", + "datetime": "2020-12-14T18:02:31.437000Z", + "created": "2020-12-15T01:48:13.725Z", + "updated": "2020-12-15T01:48:13.725Z", + "platform": "cool_sat2", + "instruments": [ + "cool_sensor_v2" + ], + "gsd": 0.66, + "eo:cloud_cover": 1.2, + "proj:epsg": 32659, + "proj:shape": [ + 5558, + 9559 + ], + "proj:transform": [ + 0.5, + 0, + 712710, + 0, + -0.5, + 151406, + 0, + 0, + 1 + ], + "view:sun_elevation": 54.9, + "view:off_nadir": 3.8, + "view:sun_azimuth": 135.7, + "rd:type": "scene", + "rd:anomalous_pixels": 0.14, + "rd:earth_sun_distance": 1.014156, + "rd:sat_id": "cool_sat2", + "rd:product_level": "LV3A", + "sci:doi": "10.5061/dryad.s2v81.2/27.2" + }, + "collection": "simple-collection", + "links": [ + { + "rel": "collection", + "href": "./collection.json", + "type": "application/json", + "title": "Simple Example Collection" + }, + { + "rel": "root", + "href": "./collection.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "./collection.json", + "type": "application/json" + }, + { + "rel": "alternate", + "type": "text/html", + "href": "http://remotedata.io/catalog/20201211_223832_CS2/index.html" + } + ], + "assets": { + "analytic": { + "href": "https://storage.googleapis.com/open-cogs/stac-examples/20201211_223832_CS2_analytic.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "4-Band Analytic", + "roles": [ + "data" + ], + "eo:bands": [ + { + "name": "band1", + "common_name": "blue", + "center_wavelength": 470, + "full_width_half_max": 70 + }, + { + "name": "band2", + "common_name": "green", + "center_wavelength": 560, + "full_width_half_max": 80 + }, + { + "name": "band3", + "common_name": "red", + "center_wavelength": 645, + "full_width_half_max": 90 + }, + { + "name": "band4", + "common_name": "nir", + "center_wavelength": 800, + "full_width_half_max": 152 + } + ] + }, + "thumbnail": { + "href": "https://storage.googleapis.com/open-cogs/stac-examples/20201211_223832_CS2.jpg", + "title": "Thumbnail", + "type": "image/png", + "roles": [ + "thumbnail" + ] + }, + "visual": { + "href": "https://storage.googleapis.com/open-cogs/stac-examples/20201211_223832_CS2.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "3-Band Visual", + "roles": [ + "visual" + ], + "eo:bands": [ + { + "name": "band3", + "common_name": "red", + "center_wavelength": 645, + "full_width_half_max": 90 + }, + { + "name": "band2", + "common_name": "green", + "center_wavelength": 560, + "full_width_half_max": 80 + }, + { + "name": "band1", + "common_name": "blue", + "center_wavelength": 470, + "full_width_half_max": 70 + } + ] + }, + "udm": { + "href": "https://storage.googleapis.com/open-cogs/stac-examples/20201211_223832_CS2_analytic_udm.tif", + "title": "Unusable Data Mask", + "type": "image/tiff; application=geotiff;" + }, + "json-metadata": { + "href": "http://remotedata.io/catalog/20201211_223832_CS2/extended-metadata.json", + "title": "Extended Metadata", + "type": "application/json", + "roles": [ + "metadata" + ] + }, + "ephemeris": { + "href": "http://cool-sat.com/catalog/20201211_223832_CS2/20201211_223832_CS2.EPH", + "title": "Satellite Ephemeris Metadata" + } + } +} diff --git a/tests/data-files/examples/1.0.0-RC3/extensions-collection/collection.json b/tests/data-files/examples/1.0.0-RC3/extensions-collection/collection.json new file mode 100644 index 000000000..fa0fe85db --- /dev/null +++ b/tests/data-files/examples/1.0.0-RC3/extensions-collection/collection.json @@ -0,0 +1,66 @@ +{ + "id": "extensions-collection", + "type": "Collection", + "stac_version": "1.0.0-rc.3", + "description": "A heterogenous collection containing deeper examples of various extensions", + "links": [ + { + "rel": "root", + "href": "../catalog.json", + "type": "application/json" + }, + { + "rel": "item", + "href": "./proj-example/proj-example.json", + "title": "Proj extension example" + }, + { + "rel": "license", + "href": "https://remotedata.io/license.html", + "title": "Remote Data License Terms" + }, + { + "rel": "parent", + "href": "../catalog.json", + "type": "application/json" + } + ], + "stac_extensions": [], + "title": "Collection of Extension Items", + "keywords": [ + "examples", + "sar", + "projection" + ], + "providers": [ + { + "name": "Remote Data, Inc.", + "roles": [ + "producer", + "licensor" + ], + "url": "https://remotedata.io" + } + ], + "extent": { + "spatial": { + "bbox": [ + [ + -180, + -56, + 180, + 83 + ] + ] + }, + "temporal": { + "interval": [ + [ + "2009-05-20T02:40:01.042784Z", + "2018-11-03T23:59:55.112875Z" + ] + ] + } + }, + "license": "PDDL-1.0" +} diff --git a/tests/data-files/examples/1.0.0-RC3/extensions-collection/proj-example/proj-example.json b/tests/data-files/examples/1.0.0-RC3/extensions-collection/proj-example/proj-example.json new file mode 100644 index 000000000..64a42dc14 --- /dev/null +++ b/tests/data-files/examples/1.0.0-RC3/extensions-collection/proj-example/proj-example.json @@ -0,0 +1,282 @@ +{ + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "proj-example", + "properties": { + "datetime": "2018-10-01T01:08:32.033000Z", + "proj:epsg": 32614, + "proj:wkt2": "PROJCS[\"WGS 84 / UTM zone 14N\",GEOGCS[\"WGS 84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS 84\",6378137,298.257223563,AUTHORITY[\"EPSG\",\"7030\"]],AUTHORITY[\"EPSG\",\"6326\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.01745329251994328,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\",\"4326\"]],UNIT[\"metre\",1,AUTHORITY[\"EPSG\",\"9001\"]],PROJECTION[\"Transverse_Mercator\"],PARAMETER[\"latitude_of_origin\",0],PARAMETER[\"central_meridian\",-99],PARAMETER[\"scale_factor\",0.9996],PARAMETER[\"false_easting\",500000],PARAMETER[\"false_northing\",0],AUTHORITY[\"EPSG\",\"32614\"],AXIS[\"Easting\",EAST],AXIS[\"Northing\",NORTH]]", + "proj:projjson": { + "$schema": "https://proj.org/schemas/v0.2/projjson.schema.json", + "type": "ProjectedCRS", + "name": "WGS 84 / UTM zone 14N", + "base_crs": { + "name": "WGS 84", + "datum": { + "type": "GeodeticReferenceFrame", + "name": "World Geodetic System 1984", + "ellipsoid": { + "name": "WGS 84", + "semi_major_axis": 6378137, + "inverse_flattening": 298.257223563 + } + }, + "coordinate_system": { + "subtype": "ellipsoidal", + "axis": [ + { + "name": "Geodetic latitude", + "abbreviation": "Lat", + "direction": "north", + "unit": "degree" + }, + { + "name": "Geodetic longitude", + "abbreviation": "Lon", + "direction": "east", + "unit": "degree" + } + ] + }, + "id": { + "authority": "EPSG", + "code": 4326 + } + }, + "conversion": { + "name": "UTM zone 14N", + "method": { + "name": "Transverse Mercator", + "id": { + "authority": "EPSG", + "code": 9807 + } + }, + "parameters": [ + { + "name": "Latitude of natural origin", + "value": 0, + "unit": "degree", + "id": { + "authority": "EPSG", + "code": 8801 + } + }, + { + "name": "Longitude of natural origin", + "value": -99, + "unit": "degree", + "id": { + "authority": "EPSG", + "code": 8802 + } + }, + { + "name": "Scale factor at natural origin", + "value": 0.9996, + "unit": "unity", + "id": { + "authority": "EPSG", + "code": 8805 + } + }, + { + "name": "False easting", + "value": 500000, + "unit": "metre", + "id": { + "authority": "EPSG", + "code": 8806 + } + }, + { + "name": "False northing", + "value": 0, + "unit": "metre", + "id": { + "authority": "EPSG", + "code": 8807 + } + } + ] + }, + "coordinate_system": { + "subtype": "Cartesian", + "axis": [ + { + "name": "Easting", + "abbreviation": "E", + "direction": "east", + "unit": "metre" + }, + { + "name": "Northing", + "abbreviation": "N", + "direction": "north", + "unit": "metre" + } + ] + }, + "area": "World - N hemisphere - 102°W to 96°W - by country", + "bbox": { + "south_latitude": 0, + "west_longitude": -102, + "north_latitude": 84, + "east_longitude": -96 + }, + "id": { + "authority": "EPSG", + "code": 32614 + } + }, + "proj:geometry": { + "coordinates": [ + [ + [ + 169200, + 3712800 + ], + [ + 403200, + 3712800 + ], + [ + 403200, + 3951000 + ], + [ + 169200, + 3951000 + ], + [ + 169200, + 3712800 + ] + ] + ], + "type": "Polygon" + }, + "proj:bbox": [ + 169200, + 3712800, + 403200, + 3951000 + ], + "proj:centroid": { + "lat": 34.595302781575604, + "lon": -101.34448382627504 + }, + "proj:shape": [ + 8391, + 8311 + ], + "proj:transform": [ + 30, + 0, + 224985, + 0, + -30, + 6790215, + 0, + 0, + 1 + ] + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + 152.52758, + 60.63437 + ], + [ + 149.1755, + 61.19016 + ], + [ + 148.13933, + 59.51584 + ], + [ + 151.33786, + 58.97792 + ], + [ + 152.52758, + 60.63437 + ] + ] + ] + }, + "links": [ + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + }, + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": { + "B1": { + "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B1.TIF", + "type": "image/tiff; application=geotiff", + "title": "Band 1 (coastal)", + "eo:bands": [ + { + "name": "B1", + "common_name": "coastal", + "center_wavelength": 0.44, + "full_width_half_max": 0.02 + } + ] + }, + "B8": { + "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B8.TIF", + "type": "image/tiff; application=geotiff", + "title": "Band 8 (panchromatic)", + "eo:bands": [ + { + "name": "B8", + "center_wavelength": 0.59, + "full_width_half_max": 0.18 + } + ], + "proj:shape": [ + 16781, + 16621 + ], + "proj:transform": [ + 15, + 0, + 224992.5, + 0, + -15, + 6790207.5, + 0, + 0, + 1 + ] + } + }, + "bbox": [ + 148.13933, + 59.51584, + 152.52758, + 60.63437 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/eo/v1.0.0/schema.json", + "https://stac-extensions.github.io/projection/v1.0.0/schema.json" + ], + "collection": "landsat-8-l1" +} diff --git a/tests/data-files/examples/1.0.0-RC3/simple-item.json b/tests/data-files/examples/1.0.0-RC3/simple-item.json new file mode 100644 index 000000000..f74871fb3 --- /dev/null +++ b/tests/data-files/examples/1.0.0-RC3/simple-item.json @@ -0,0 +1,79 @@ +{ + "stac_version": "1.0.0-rc.3", + "stac_extensions": [], + "type": "Feature", + "id": "20201211_223832_CS2", + "bbox": [ + 172.91173669923782, + 1.3438851951615003, + 172.95469614953714, + 1.3690476620161975 + ], + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + 172.91173669923782, + 1.3438851951615003 + ], + [ + 172.95469614953714, + 1.3438851951615003 + ], + [ + 172.95469614953714, + 1.3690476620161975 + ], + [ + 172.91173669923782, + 1.3690476620161975 + ], + [ + 172.91173669923782, + 1.3438851951615003 + ] + ] + ] + }, + "properties": { + "datetime": "2020-12-11T22:38:32.125000Z" + }, + "collection": "simple-collection", + "links": [ + { + "rel": "collection", + "href": "./collection.json", + "type": "application/json", + "title": "Simple Example Collection" + }, + { + "rel": "root", + "href": "./collection.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "./collection.json", + "type": "application/json" + } + ], + "assets": { + "visual": { + "href": "https://storage.googleapis.com/open-cogs/stac-examples/20201211_223832_CS2.tif", + "type": "image/tiff; application=geotiff; profile=cloud-optimized", + "title": "3-Band Visual", + "roles": [ + "visual" + ] + }, + "thumbnail": { + "href": "https://storage.googleapis.com/open-cogs/stac-examples/20201211_223832_CS2.jpg", + "title": "Thumbnail", + "type": "image/jpeg", + "roles": [ + "thumbnail" + ] + } + } +} diff --git a/tests/data-files/examples/example-info.csv b/tests/data-files/examples/example-info.csv index e6de13398..b01726a7e 100644 --- a/tests/data-files/examples/example-info.csv +++ b/tests/data-files/examples/example-info.csv @@ -1,138 +1,146 @@ -"0.4.1/extensions/examples/landsat8-merged.json","ITEM","0.4.1","eo","" -"0.5.2/extensions/examples/landsat8-merged.json","ITEM","0.5.2","eo","" -"0.7.0/extensions/sar/examples/sentinel1.json","ITEM","0.7.0","sar|datetime-range","" -"0.8.1/catalog-spec/examples/catalog.json","CATALOG","0.8.1","","" -"0.8.1/catalog-spec/examples/summaries-s2.json","CATALOG","0.8.1","","" -"0.8.1/collection-spec/examples/landsat-collection.json","COLLECTION","0.8.1","","" -"0.8.1/collection-spec/examples/landsat-item.json","ITEM","0.8.1","eo","" -"0.8.1/collection-spec/examples/sentinel2.json","COLLECTION","0.8.1","","" -"0.8.1/extensions/asset/examples/example-landsat8.json","COLLECTION","0.8.1","asset","" -"0.8.1/extensions/checksum/examples/example-sentinel1.json","ITEM","0.8.1","checksum","" -"0.8.1/extensions/datacube/examples/example.json","ITEM","0.8.1","datacube","" -"0.8.1/extensions/datetime-range/examples/example-video.json","ITEM","0.8.1","datetime-range","" -"0.8.1/extensions/eo/examples/example-landsat8.json","ITEM","0.8.1","eo","https://example.com/stac/landsat-extension/1.0/schema.json" -"0.8.1/extensions/label/examples/multidataset/catalog.json","CATALOG","0.8.1","","" -"0.8.1/extensions/label/examples/multidataset/spacenet-buildings/AOI_2_Vegas_img2636.json","ITEM","0.8.1","label","" -"0.8.1/extensions/label/examples/multidataset/spacenet-buildings/AOI_3_Paris_img1648.json","ITEM","0.8.1","label","" -"0.8.1/extensions/label/examples/multidataset/spacenet-buildings/AOI_4_Shanghai_img3344.json","ITEM","0.8.1","label","" -"0.8.1/extensions/label/examples/multidataset/spacenet-buildings/collection.json","COLLECTION","0.8.1","","" -"0.8.1/extensions/label/examples/multidataset/zanzibar/collection.json","COLLECTION","0.8.1","","" -"0.8.1/extensions/label/examples/multidataset/zanzibar/znz001.json","ITEM","0.8.1","label","" -"0.8.1/extensions/label/examples/multidataset/zanzibar/znz029.json","ITEM","0.8.1","label","" -"0.8.1/extensions/label/examples/spacenet-roads/roads_collection.json","COLLECTION","0.8.1","","" -"0.8.1/extensions/label/examples/spacenet-roads/roads_item.json","ITEM","0.8.1","label","" -"0.8.1/extensions/label/examples/spacenet-roads/roads_source.json","ITEM","0.8.1","","" -"0.8.1/extensions/pointcloud/examples/example-autzen.json","ITEM","0.8.1","pointcloud","" -"0.8.1/extensions/sar/examples/envisat.json","ITEM","0.8.1","sar|datetime-range","" -"0.8.1/extensions/sar/examples/sentinel1.json","ITEM","0.8.1","checksum|sar|datetime-range","" -"0.8.1/extensions/scientific/examples/collection.json","COLLECTION","0.8.1","scientific","" -"0.8.1/extensions/scientific/examples/item.json","ITEM","0.8.1","datetime-range|checksum|scientific","" -"0.8.1/item-spec/examples/digitalglobe-sample.json","ITEM","0.8.1","eo","https://example.digitalglobe.com/stac/1.0/schema.json" -"0.8.1/item-spec/examples/landsat8-sample.json","ITEM","0.8.1","eo","https://example.com/stac/landsat-extension/1.0/schema.json" -"0.8.1/item-spec/examples/planet-sample.json","ITEM","0.8.1","eo","https://example.planet.com/stac/1.0/schema.json" -"0.8.1/item-spec/examples/sample-full.json","ITEM","0.8.1","eo","https://example.com/cs-extension/1.0/schema.json" -"0.8.1/item-spec/examples/sample.json","ITEM","0.8.1","","" -"0.8.1/item-spec/examples/sentinel2-sample.json","ITEM","0.8.1","eo","" -"0.9.0/catalog-spec/examples/catalog.json","CATALOG","0.9.0","","" -"0.9.0/collection-spec/examples/landsat-collection.json","COLLECTION","0.9.0","commons|view|eo","" -"0.9.0/collection-spec/examples/landsat-item.json","ITEM","0.9.0","commons|eo|view","https://example.com/stac/landsat-extension/1.0/schema.json","INVALID" -"0.9.0/collection-spec/examples/sentinel2.json","COLLECTION","0.9.0","","" -"0.9.0/extensions/asset/examples/example-landsat8.json","COLLECTION","0.9.0","asset|commons","" -"0.9.0/extensions/checksum/examples/sentinel1.json","ITEM","0.9.0","checksum","" -"0.9.0/extensions/commons/examples/landsat-collection.json","COLLECTION","0.9.0","commons","" -"0.9.0/extensions/commons/examples/landsat-item.json","ITEM","0.9.0","commons|eo|sat","https://example.com/stac/landsat-extension/1.0/schema.json" -"0.9.0/extensions/datacube/examples/example-collection.json","COLLECTION","0.9.0","datacube","" -"0.9.0/extensions/datacube/examples/example-item.json","ITEM","0.9.0","datacube","" -"0.9.0/extensions/eo/examples/example-landsat8.json","ITEM","0.9.0","eo|view|commons","https://example.com/stac/landsat-extension/1.0/schema.json" -"0.9.0/extensions/label/examples/multidataset/catalog.json","CATALOG","0.9.0","","" -"0.9.0/extensions/label/examples/multidataset/spacenet-buildings/AOI_2_Vegas_img2636.json","ITEM","0.9.0","label|version","","INVALID" -"0.9.0/extensions/label/examples/multidataset/spacenet-buildings/AOI_3_Paris_img1648.json","ITEM","0.9.0","label|version","","INVALID" -"0.9.0/extensions/label/examples/multidataset/spacenet-buildings/AOI_4_Shanghai_img3344.json","ITEM","0.9.0","label|version","","INVALID" -"0.9.0/extensions/label/examples/multidataset/spacenet-buildings/collection.json","COLLECTION","0.9.0","","" -"0.9.0/extensions/label/examples/multidataset/zanzibar/collection.json","COLLECTION","0.9.0","","" -"0.9.0/extensions/label/examples/multidataset/zanzibar/znz001.json","ITEM","0.9.0","label|version","","INVALID" -"0.9.0/extensions/label/examples/spacenet-roads/roads_collection.json","COLLECTION","0.9.0","","" -"0.9.0/extensions/label/examples/spacenet-roads/roads_item.json","ITEM","0.9.0","label|version","" -"0.9.0/extensions/label/examples/spacenet-roads/roads_source.json","ITEM","0.9.0","","" -"0.9.0/extensions/pointcloud/examples/example-autzen.json","ITEM","0.9.0","pointcloud","" -"0.9.0/extensions/projection/examples/example-landsat8.json","ITEM","0.9.0","proj|commons","" -"0.9.0/extensions/sar/examples/envisat.json","ITEM","0.9.0","sat|sar","" -"0.9.0/extensions/sar/examples/sentinel1.json","ITEM","0.9.0","checksum|sar|sat","" -"0.9.0/extensions/sat/examples/example-landsat8.json","ITEM","0.9.0","sat|view","" -"0.9.0/extensions/scientific/examples/collection.json","COLLECTION","0.9.0","scientific","" -"0.9.0/extensions/scientific/examples/item.json","ITEM","0.9.0","scientific|checksum","" -"0.9.0/extensions/version/examples/collection.json","COLLECTION","0.9.0","version","" -"0.9.0/extensions/version/examples/item.json","ITEM","0.9.0","version","","INVALID" -"0.9.0/extensions/view/examples/example-landsat8.json","ITEM","0.9.0","sat|view","" -"0.9.0/item-spec/examples/datetimerange.json","ITEM","0.9.0","","" -"0.9.0/item-spec/examples/digitalglobe-sample.json","ITEM","0.9.0","eo|proj|view","https://example.digitalglobe.com/stac/1.0/schema.json" -"0.9.0/item-spec/examples/landsat8-sample.json","ITEM","0.9.0","eo|view","https://example.com/stac/landsat-extension/1.0/schema.json" -"0.9.0/item-spec/examples/planet-sample.json","ITEM","0.9.0","eo|view","https://example.planet.com/stac/1.0/schema.json" -"0.9.0/item-spec/examples/sample-full.json","ITEM","0.9.0","eo|view","https://example.com/cs-extension/1.0/schema.json" -"0.9.0/item-spec/examples/sample.json","ITEM","0.9.0","","" -"0.9.0/item-spec/examples/sentinel2-sample.json","ITEM","0.9.0","eo|view|proj|commons","" -"1.0.0-beta.2/catalog-spec/examples/catalog-items.json","CATALOG","1.0.0-beta.2","","" -"1.0.0-beta.2/catalog-spec/examples/catalog.json","CATALOG","1.0.0-beta.2","","" -"1.0.0-beta.2/collection-spec/examples/landsat-collection.json","COLLECTION","1.0.0-beta.2","","" -"1.0.0-beta.2/collection-spec/examples/sentinel2.json","COLLECTION","1.0.0-beta.2","","" -"1.0.0-beta.2/extensions/checksum/examples/sentinel1.json","ITEM","1.0.0-beta.2","checksum","" -"1.0.0-beta.2/extensions/collection-assets/examples/example-esm.json","COLLECTION","1.0.0-beta.2","collection-assets","https://github.com/NCAR/esm-collection-spec/tree/v0.2.0/schema.json" -"1.0.0-beta.2/extensions/datacube/examples/example-collection.json","COLLECTION","1.0.0-beta.2","datacube","" -"1.0.0-beta.2/extensions/datacube/examples/example-item.json","ITEM","1.0.0-beta.2","datacube","" -"1.0.0-beta.2/extensions/eo/examples/example-landsat8.json","ITEM","1.0.0-beta.2","eo|view","https://example.com/stac/landsat-extension/1.0/schema.json" -"1.0.0-beta.2/extensions/item-assets/examples/example-landsat8.json","COLLECTION","1.0.0-beta.2","item-assets","" -"1.0.0-beta.2/extensions/label/examples/multidataset/catalog.json","CATALOG","1.0.0-beta.2","","" -"1.0.0-beta.2/extensions/label/examples/multidataset/spacenet-buildings/AOI_2_Vegas_img2636.json","ITEM","1.0.0-beta.2","label|version","" -"1.0.0-beta.2/extensions/label/examples/multidataset/spacenet-buildings/AOI_3_Paris_img1648.json","ITEM","1.0.0-beta.2","label|version","" -"1.0.0-beta.2/extensions/label/examples/multidataset/spacenet-buildings/AOI_4_Shanghai_img3344.json","ITEM","1.0.0-beta.2","label|version","" -"1.0.0-beta.2/extensions/label/examples/multidataset/spacenet-buildings/collection.json","COLLECTION","1.0.0-beta.2","","" -"1.0.0-beta.2/extensions/label/examples/multidataset/zanzibar/collection.json","COLLECTION","1.0.0-beta.2","","" -"1.0.0-beta.2/extensions/label/examples/multidataset/zanzibar/znz001.json","ITEM","1.0.0-beta.2","label|version","" -"1.0.0-beta.2/extensions/label/examples/multidataset/zanzibar/znz029.json","ITEM","1.0.0-beta.2","label|version","" -"1.0.0-beta.2/extensions/label/examples/spacenet-roads/roads_collection.json","COLLECTION","1.0.0-beta.2","","" -"1.0.0-beta.2/extensions/label/examples/spacenet-roads/roads_item.json","ITEM","1.0.0-beta.2","label|version","" -"1.0.0-beta.2/extensions/label/examples/spacenet-roads/roads_source.json","ITEM","1.0.0-beta.2","","" -"1.0.0-beta.2/extensions/pointcloud/examples/example-autzen.json","ITEM","1.0.0-beta.2","pointcloud","" -"1.0.0-beta.2/extensions/projection/examples/example-landsat8.json","ITEM","1.0.0-beta.2","eo|projection","" -"1.0.0-beta.2/extensions/sar/examples/envisat.json","ITEM","1.0.0-beta.2","sat|sar","" -"1.0.0-beta.2/extensions/sar/examples/sentinel1.json","ITEM","1.0.0-beta.2","checksum|sar|sat","" -"1.0.0-beta.2/extensions/sat/examples/example-landsat8.json","ITEM","1.0.0-beta.2","sat|view","" -"1.0.0-beta.2/extensions/scientific/examples/collection.json","COLLECTION","1.0.0-beta.2","scientific","" -"1.0.0-beta.2/extensions/scientific/examples/item.json","ITEM","1.0.0-beta.2","scientific|checksum","" -"1.0.0-beta.2/extensions/tiled-assets/examples/example-dimension.json","ITEM","1.0.0-beta.2","datacube|eo|tiled-assets","" -"1.0.0-beta.2/extensions/tiled-assets/examples/example-tiled.json","ITEM","1.0.0-beta.2","eo|tiled-assets","" -"1.0.0-beta.2/extensions/timestamps/examples/example-landsat8.json","ITEM","1.0.0-beta.2","timestamps","" -"1.0.0-beta.2/extensions/version/examples/collection.json","COLLECTION","1.0.0-beta.2","version","" -"1.0.0-beta.2/extensions/version/examples/item.json","ITEM","1.0.0-beta.2","version","" -"1.0.0-beta.2/extensions/view/examples/example-landsat8.json","ITEM","1.0.0-beta.2","sat|view","" -"1.0.0-beta.2/item-spec/examples/CBERS_4_MUX_20181029_177_106_L4.json","ITEM","1.0.0-beta.2","projection|view","https://example.com/stac/cbers-extension/1.0/schema.json" -"1.0.0-beta.2/item-spec/examples/datetimerange.json","ITEM","1.0.0-beta.2","","" -"1.0.0-beta.2/item-spec/examples/digitalglobe-sample.json","ITEM","1.0.0-beta.2","eo|projection|view","https://example.digitalglobe.com/stac/1.0/schema.json" -"1.0.0-beta.2/item-spec/examples/landsat8-sample.json","ITEM","1.0.0-beta.2","eo|view","https://example.com/stac/landsat-extension/1.0/schema.json" -"1.0.0-beta.2/item-spec/examples/planet-sample.json","ITEM","1.0.0-beta.2","eo|view","https://example.planet.com/stac/1.0/schema.json" -"1.0.0-beta.2/item-spec/examples/sample-full.json","ITEM","1.0.0-beta.2","eo|view","https://example.com/cs-extension/1.0/schema.json" -"1.0.0-beta.2/item-spec/examples/sample.json","ITEM","1.0.0-beta.2","","" -"1.0.0-beta.2/item-spec/examples/sentinel2-sample.json","ITEM","1.0.0-beta.2","view|projection","" -"gee-0.6.2/CIESIN_GPWv411_GPW_National_Identifier_Grid.json","COLLECTION","0.6.2","scientific","" -"gee-0.6.2/LANDSAT_LT05_C01_T1_ANNUAL_NDWI.json","COLLECTION","0.6.2","","" -"gee-0.6.2/catalog.json","CATALOG","0.6.2","","" -"iserv-0.6.1/2013/03/27/IP0201303271418280967S05834W.json","ITEM","0.6.1","eo","" -"iserv-0.6.1/2013/03/27/catalog.json","CATALOG","0.6.1","","" -"iserv-0.6.1/2013/03/catalog.json","CATALOG","0.6.1","","" -"iserv-0.6.1/2013/catalog.json","CATALOG","0.6.1","","" -"iserv-0.6.1/catalog.json","COLLECTION","0.6.1","","" -"landsat-0.6.0/010/117/2015-01-02/LC80101172015002LGN00.json","ITEM","0.6.0","eo","" -"landsat-0.6.0/010/117/catalog.json","CATALOG","0.6.0","","" -"landsat-0.6.0/010/catalog.json","COLLECTION","0.6.0","","" -"landsat-0.6.0/156/029/2015-01-01/LC81560292015001LGN00.json","ITEM","0.6.0","eo","" -"landsat-0.6.0/156/029/catalog.json","CATALOG","0.6.0","","" -"landsat-0.6.0/156/catalog.json","COLLECTION","0.6.0","","" -"landsat-0.6.0/catalog.json","CATALOG","0.6.0","","" -"sentinel-0.6.0/catalog.json","CATALOG","0.6.0","","" -"sentinel-0.6.0/sentinel-2-l1c/9/V/XK/2017-10-13/S2B_9VXK_20171013_0.json","ITEM","0.6.0","eo","" -"sentinel-0.6.0/sentinel-2-l1c/9/V/XK/catalog.json","CATALOG","0.6.0","","" -"sentinel-0.6.0/sentinel-2-l1c/9/V/catalog.json","CATALOG","0.6.0","","" -"sentinel-0.6.0/sentinel-2-l1c/9/catalog.json","CATALOG","0.6.0","","" -"sentinel-0.6.0/sentinel-2-l1c/catalog.json","COLLECTION","0.6.0","","" -"hand-0.9.0/collection.json","COLLECTION","0.9.0","","" -"hand-0.8.1/collection.json","COLLECTION","0.8.1","","" \ No newline at end of file +"0.4.1/extensions/examples/landsat8-merged.json","ITEM","0.4.1","eo" +"0.5.2/extensions/examples/landsat8-merged.json","ITEM","0.5.2","eo" +"0.7.0/extensions/sar/examples/sentinel1.json","ITEM","0.7.0","sar|datetime-range|checksum" +"0.8.1/catalog-spec/examples/catalog.json","CATALOG","0.8.1","" +"0.8.1/catalog-spec/examples/summaries-s2.json","CATALOG","0.8.1","" +"0.8.1/collection-spec/examples/landsat-collection.json","COLLECTION","0.8.1","" +"0.8.1/collection-spec/examples/landsat-item.json","ITEM","0.8.1","eo" +"0.8.1/collection-spec/examples/sentinel2.json","COLLECTION","0.8.1","" +"0.8.1/extensions/asset/examples/example-landsat8.json","COLLECTION","0.8.1","asset" +"0.8.1/extensions/checksum/examples/example-sentinel1.json","ITEM","0.8.1","checksum" +"0.8.1/extensions/datacube/examples/example.json","ITEM","0.8.1","datacube" +"0.8.1/extensions/datetime-range/examples/example-video.json","ITEM","0.8.1","datetime-range" +"0.8.1/extensions/eo/examples/example-landsat8.json","ITEM","0.8.1","eo|https://example.com/stac/landsat-extension/1.0/schema.json" +"0.8.1/extensions/label/examples/multidataset/catalog.json","CATALOG","0.8.1","" +"0.8.1/extensions/label/examples/multidataset/spacenet-buildings/AOI_2_Vegas_img2636.json","ITEM","0.8.1","label" +"0.8.1/extensions/label/examples/multidataset/spacenet-buildings/AOI_3_Paris_img1648.json","ITEM","0.8.1","label" +"0.8.1/extensions/label/examples/multidataset/spacenet-buildings/AOI_4_Shanghai_img3344.json","ITEM","0.8.1","label" +"0.8.1/extensions/label/examples/multidataset/spacenet-buildings/collection.json","COLLECTION","0.8.1","" +"0.8.1/extensions/label/examples/multidataset/zanzibar/collection.json","COLLECTION","0.8.1","" +"0.8.1/extensions/label/examples/multidataset/zanzibar/znz001.json","ITEM","0.8.1","label" +"0.8.1/extensions/label/examples/multidataset/zanzibar/znz029.json","ITEM","0.8.1","label" +"0.8.1/extensions/label/examples/spacenet-roads/roads_collection.json","COLLECTION","0.8.1","" +"0.8.1/extensions/label/examples/spacenet-roads/roads_item.json","ITEM","0.8.1","label" +"0.8.1/extensions/label/examples/spacenet-roads/roads_source.json","ITEM","0.8.1","" +"0.8.1/extensions/pointcloud/examples/example-autzen.json","ITEM","0.8.1","pointcloud" +"0.8.1/extensions/sar/examples/envisat.json","ITEM","0.8.1","sar|datetime-range" +"0.8.1/extensions/sar/examples/sentinel1.json","ITEM","0.8.1","checksum|sar|datetime-range" +"0.8.1/extensions/scientific/examples/collection.json","COLLECTION","0.8.1","scientific" +"0.8.1/extensions/scientific/examples/item.json","ITEM","0.8.1","datetime-range|checksum|scientific" +"0.8.1/item-spec/examples/digitalglobe-sample.json","ITEM","0.8.1","eo|https://example.digitalglobe.com/stac/1.0/schema.json" +"0.8.1/item-spec/examples/landsat8-sample.json","ITEM","0.8.1","eo|https://example.com/stac/landsat-extension/1.0/schema.json" +"0.8.1/item-spec/examples/planet-sample.json","ITEM","0.8.1","eo|https://example.planet.com/stac/1.0/schema.json" +"0.8.1/item-spec/examples/sample-full.json","ITEM","0.8.1","eo|https://example.com/cs-extension/1.0/schema.json" +"0.8.1/item-spec/examples/sample.json","ITEM","0.8.1","" +"0.8.1/item-spec/examples/sentinel2-sample.json","ITEM","0.8.1","eo" +"0.9.0/catalog-spec/examples/catalog.json","CATALOG","0.9.0","" +"0.9.0/collection-spec/examples/landsat-collection.json","COLLECTION","0.9.0","commons|view|eo" +"0.9.0/collection-spec/examples/landsat-item.json","ITEM","0.9.0","commons|eo|view|https://example.com/stac/landsat-extension/1.0/schema.json","INVALID" +"0.9.0/collection-spec/examples/sentinel2.json","COLLECTION","0.9.0","" +"0.9.0/extensions/asset/examples/example-landsat8.json","COLLECTION","0.9.0","asset|commons" +"0.9.0/extensions/checksum/examples/sentinel1.json","ITEM","0.9.0","checksum" +"0.9.0/extensions/commons/examples/landsat-collection.json","COLLECTION","0.9.0","commons" +"0.9.0/extensions/commons/examples/landsat-item.json","ITEM","0.9.0","commons|eo|sat|https://example.com/stac/landsat-extension/1.0/schema.json" +"0.9.0/extensions/datacube/examples/example-collection.json","COLLECTION","0.9.0","datacube" +"0.9.0/extensions/datacube/examples/example-item.json","ITEM","0.9.0","datacube" +"0.9.0/extensions/eo/examples/example-landsat8.json","ITEM","0.9.0","eo|view|commons|https://example.com/stac/landsat-extension/1.0/schema.json" +"0.9.0/extensions/label/examples/multidataset/catalog.json","CATALOG","0.9.0","" +"0.9.0/extensions/label/examples/multidataset/spacenet-buildings/AOI_2_Vegas_img2636.json","ITEM","0.9.0","label|version","INVALID" +"0.9.0/extensions/label/examples/multidataset/spacenet-buildings/AOI_3_Paris_img1648.json","ITEM","0.9.0","label|version","INVALID" +"0.9.0/extensions/label/examples/multidataset/spacenet-buildings/AOI_4_Shanghai_img3344.json","ITEM","0.9.0","label|version","INVALID" +"0.9.0/extensions/label/examples/multidataset/spacenet-buildings/collection.json","COLLECTION","0.9.0","" +"0.9.0/extensions/label/examples/multidataset/zanzibar/collection.json","COLLECTION","0.9.0","" +"0.9.0/extensions/label/examples/multidataset/zanzibar/znz001.json","ITEM","0.9.0","label|version","INVALID" +"0.9.0/extensions/label/examples/spacenet-roads/roads_collection.json","COLLECTION","0.9.0","" +"0.9.0/extensions/label/examples/spacenet-roads/roads_item.json","ITEM","0.9.0","label|version" +"0.9.0/extensions/label/examples/spacenet-roads/roads_source.json","ITEM","0.9.0","" +"0.9.0/extensions/pointcloud/examples/example-autzen.json","ITEM","0.9.0","pointcloud" +"0.9.0/extensions/projection/examples/example-landsat8.json","ITEM","0.9.0","proj|commons" +"0.9.0/extensions/sar/examples/envisat.json","ITEM","0.9.0","sat|sar" +"0.9.0/extensions/sar/examples/sentinel1.json","ITEM","0.9.0","checksum|sar|sat" +"0.9.0/extensions/sat/examples/example-landsat8.json","ITEM","0.9.0","sat|view" +"0.9.0/extensions/scientific/examples/collection.json","COLLECTION","0.9.0","scientific" +"0.9.0/extensions/scientific/examples/item.json","ITEM","0.9.0","scientific|checksum" +"0.9.0/extensions/version/examples/collection.json","COLLECTION","0.9.0","version" +"0.9.0/extensions/version/examples/item.json","ITEM","0.9.0","version","INVALID" +"0.9.0/extensions/view/examples/example-landsat8.json","ITEM","0.9.0","sat|view" +"0.9.0/item-spec/examples/datetimerange.json","ITEM","0.9.0","" +"0.9.0/item-spec/examples/digitalglobe-sample.json","ITEM","0.9.0","eo|proj|view|https://example.digitalglobe.com/stac/1.0/schema.json" +"0.9.0/item-spec/examples/landsat8-sample.json","ITEM","0.9.0","eo|view|https://example.com/stac/landsat-extension/1.0/schema.json" +"0.9.0/item-spec/examples/planet-sample.json","ITEM","0.9.0","eo|view|https://example.planet.com/stac/1.0/schema.json" +"0.9.0/item-spec/examples/sample-full.json","ITEM","0.9.0","eo|view|https://example.com/cs-extension/1.0/schema.json" +"0.9.0/item-spec/examples/sample.json","ITEM","0.9.0","" +"0.9.0/item-spec/examples/sentinel2-sample.json","ITEM","0.9.0","eo|view|proj|commons" +"1.0.0-beta.2/catalog-spec/examples/catalog-items.json","CATALOG","1.0.0-beta.2","" +"1.0.0-beta.2/catalog-spec/examples/catalog.json","CATALOG","1.0.0-beta.2","" +"1.0.0-beta.2/collection-spec/examples/landsat-collection.json","COLLECTION","1.0.0-beta.2","" +"1.0.0-beta.2/collection-spec/examples/sentinel2.json","COLLECTION","1.0.0-beta.2","" +"1.0.0-beta.2/extensions/checksum/examples/sentinel1.json","ITEM","1.0.0-beta.2","checksum" +"1.0.0-beta.2/extensions/collection-assets/examples/example-esm.json","COLLECTION","1.0.0-beta.2","collection-assets|https://github.com/NCAR/esm-collection-spec/tree/v0.2.0/schema.json" +"1.0.0-beta.2/extensions/datacube/examples/example-collection.json","COLLECTION","1.0.0-beta.2","datacube" +"1.0.0-beta.2/extensions/datacube/examples/example-item.json","ITEM","1.0.0-beta.2","datacube" +"1.0.0-beta.2/extensions/eo/examples/example-landsat8.json","ITEM","1.0.0-beta.2","eo|view|https://example.com/stac/landsat-extension/1.0/schema.json" +"1.0.0-beta.2/extensions/item-assets/examples/example-landsat8.json","COLLECTION","1.0.0-beta.2","item-assets" +"1.0.0-beta.2/extensions/label/examples/multidataset/catalog.json","CATALOG","1.0.0-beta.2","" +"1.0.0-beta.2/extensions/label/examples/multidataset/spacenet-buildings/AOI_2_Vegas_img2636.json","ITEM","1.0.0-beta.2","label|version" +"1.0.0-beta.2/extensions/label/examples/multidataset/spacenet-buildings/AOI_3_Paris_img1648.json","ITEM","1.0.0-beta.2","label|version" +"1.0.0-beta.2/extensions/label/examples/multidataset/spacenet-buildings/AOI_4_Shanghai_img3344.json","ITEM","1.0.0-beta.2","label|version" +"1.0.0-beta.2/extensions/label/examples/multidataset/spacenet-buildings/collection.json","COLLECTION","1.0.0-beta.2","" +"1.0.0-beta.2/extensions/label/examples/multidataset/zanzibar/collection.json","COLLECTION","1.0.0-beta.2","" +"1.0.0-beta.2/extensions/label/examples/multidataset/zanzibar/znz001.json","ITEM","1.0.0-beta.2","label|version" +"1.0.0-beta.2/extensions/label/examples/multidataset/zanzibar/znz029.json","ITEM","1.0.0-beta.2","label|version" +"1.0.0-beta.2/extensions/label/examples/spacenet-roads/roads_collection.json","COLLECTION","1.0.0-beta.2","" +"1.0.0-beta.2/extensions/label/examples/spacenet-roads/roads_item.json","ITEM","1.0.0-beta.2","label|version" +"1.0.0-beta.2/extensions/label/examples/spacenet-roads/roads_source.json","ITEM","1.0.0-beta.2","" +"1.0.0-beta.2/extensions/pointcloud/examples/example-autzen.json","ITEM","1.0.0-beta.2","pointcloud" +"1.0.0-beta.2/extensions/projection/examples/example-landsat8.json","ITEM","1.0.0-beta.2","eo|projection" +"1.0.0-beta.2/extensions/sar/examples/envisat.json","ITEM","1.0.0-beta.2","sat|sar" +"1.0.0-beta.2/extensions/sar/examples/sentinel1.json","ITEM","1.0.0-beta.2","checksum|sar|sat" +"1.0.0-beta.2/extensions/sat/examples/example-landsat8.json","ITEM","1.0.0-beta.2","sat|view" +"1.0.0-beta.2/extensions/scientific/examples/collection.json","COLLECTION","1.0.0-beta.2","scientific" +"1.0.0-beta.2/extensions/scientific/examples/item.json","ITEM","1.0.0-beta.2","scientific|checksum" +"1.0.0-beta.2/extensions/tiled-assets/examples/example-dimension.json","ITEM","1.0.0-beta.2","datacube|eo|tiled-assets" +"1.0.0-beta.2/extensions/tiled-assets/examples/example-tiled.json","ITEM","1.0.0-beta.2","eo|tiled-assets" +"1.0.0-beta.2/extensions/timestamps/examples/example-landsat8.json","ITEM","1.0.0-beta.2","timestamps" +"1.0.0-beta.2/extensions/version/examples/collection.json","COLLECTION","1.0.0-beta.2","version" +"1.0.0-beta.2/extensions/version/examples/item.json","ITEM","1.0.0-beta.2","version" +"1.0.0-beta.2/extensions/view/examples/example-landsat8.json","ITEM","1.0.0-beta.2","sat|view" +"1.0.0-beta.2/item-spec/examples/CBERS_4_MUX_20181029_177_106_L4.json","ITEM","1.0.0-beta.2","projection|view|https://example.com/stac/cbers-extension/1.0/schema.json" +"1.0.0-beta.2/item-spec/examples/datetimerange.json","ITEM","1.0.0-beta.2","" +"1.0.0-beta.2/item-spec/examples/digitalglobe-sample.json","ITEM","1.0.0-beta.2","eo|projection|view|https://example.digitalglobe.com/stac/1.0/schema.json" +"1.0.0-beta.2/item-spec/examples/landsat8-sample.json","ITEM","1.0.0-beta.2","eo|view|https://example.com/stac/landsat-extension/1.0/schema.json" +"1.0.0-beta.2/item-spec/examples/planet-sample.json","ITEM","1.0.0-beta.2","eo|view|https://example.planet.com/stac/1.0/schema.json" +"1.0.0-beta.2/item-spec/examples/sample-full.json","ITEM","1.0.0-beta.2","eo|view|https://example.com/cs-extension/1.0/schema.json" +"1.0.0-beta.2/item-spec/examples/sample.json","ITEM","1.0.0-beta.2","" +"1.0.0-beta.2/item-spec/examples/sentinel2-sample.json","ITEM","1.0.0-beta.2","view|projection" +"gee-0.6.2/CIESIN_GPWv411_GPW_National_Identifier_Grid.json","COLLECTION","0.6.2","scientific" +"gee-0.6.2/LANDSAT_LT05_C01_T1_ANNUAL_NDWI.json","COLLECTION","0.6.2","" +"gee-0.6.2/catalog.json","CATALOG","0.6.2","" +"iserv-0.6.1/2013/03/27/IP0201303271418280967S05834W.json","ITEM","0.6.1","eo" +"iserv-0.6.1/2013/03/27/catalog.json","CATALOG","0.6.1","" +"iserv-0.6.1/2013/03/catalog.json","CATALOG","0.6.1","" +"iserv-0.6.1/2013/catalog.json","CATALOG","0.6.1","" +"iserv-0.6.1/catalog.json","COLLECTION","0.6.1","" +"landsat-0.6.0/010/117/2015-01-02/LC80101172015002LGN00.json","ITEM","0.6.0","eo" +"landsat-0.6.0/010/117/catalog.json","CATALOG","0.6.0","" +"landsat-0.6.0/010/catalog.json","COLLECTION","0.6.0","" +"landsat-0.6.0/156/029/2015-01-01/LC81560292015001LGN00.json","ITEM","0.6.0","eo" +"landsat-0.6.0/156/029/catalog.json","CATALOG","0.6.0","" +"landsat-0.6.0/156/catalog.json","COLLECTION","0.6.0","" +"landsat-0.6.0/catalog.json","CATALOG","0.6.0","" +"sentinel-0.6.0/catalog.json","CATALOG","0.6.0","" +"sentinel-0.6.0/sentinel-2-l1c/9/V/XK/2017-10-13/S2B_9VXK_20171013_0.json","ITEM","0.6.0","eo" +"sentinel-0.6.0/sentinel-2-l1c/9/V/XK/catalog.json","CATALOG","0.6.0","" +"sentinel-0.6.0/sentinel-2-l1c/9/V/catalog.json","CATALOG","0.6.0","" +"sentinel-0.6.0/sentinel-2-l1c/9/catalog.json","CATALOG","0.6.0","" +"sentinel-0.6.0/sentinel-2-l1c/catalog.json","COLLECTION","0.6.0","" +"hand-0.9.0/collection.json","COLLECTION","0.9.0","" +"hand-0.8.1/collection.json","COLLECTION","0.8.1","" +"1.0.0-RC3/catalog.json","CATALOG","1.0.0-rc.3","" +"1.0.0-RC3/collection-only/collection.json","COLLECTION","1.0.0-rc.3","https://stac-extensions.github.io/eo/v1.0.0/schema.json|https://stac-extensions.github.io/projection/v1.0.0/schema.json|https://stac-extensions.github.io/view/v1.0.0/schema.json" +"1.0.0-RC3/collection.json","COLLECTION","1.0.0-rc.3","https://stac-extensions.github.io/eo/v1.0.0/schema.json|https://stac-extensions.github.io/view/v1.0.0/schema.json" +"1.0.0-RC3/collectionless-item.json","ITEM","1.0.0-rc.3","https://stac-extensions.github.io/eo/v1.0.0/schema.json|https://stac-extensions.github.io/view/v1.0.0/schema.json" +"1.0.0-RC3/core-item.json","ITEM","1.0.0-rc.3","" +"1.0.0-RC3/extended-item.json","ITEM","1.0.0-rc.3","https://stac-extensions.github.io/eo/v1.0.0/schema.json|https://stac-extensions.github.io/projection/v1.0.0/schema.json|https://stac-extensions.github.io/scientific/v1.0.0/schema.json|https://stac-extensions.github.io/view/v1.0.0/schema.json|https://stac-extensions.github.io/remote-data/v1.0.0/schema.json" +"1.0.0-RC3/extensions-collection/collection.json","COLLECTION","1.0.0-rc.3","" +"1.0.0-RC3/extensions-collection/proj-example/proj-example.json","ITEM","1.0.0-rc.3","https://stac-extensions.github.io/eo/v1.0.0/schema.json|https://stac-extensions.github.io/projection/v1.0.0/schema.json" diff --git a/tests/data-files/examples/landsat-0.6.0/156/029/2015-01-01/LC81560292015001LGN00.json b/tests/data-files/examples/landsat-0.6.0/156/029/2015-01-01/LC81560292015001LGN00.json index 7d965234e..1551ddea1 100644 --- a/tests/data-files/examples/landsat-0.6.0/156/029/2015-01-01/LC81560292015001LGN00.json +++ b/tests/data-files/examples/landsat-0.6.0/156/029/2015-01-01/LC81560292015001LGN00.json @@ -1 +1,216 @@ -{"type": "Feature", "id": "LC81560292015001LGN00", "bbox": [65.61297, 43.48724, 68.67079, 45.70204], "geometry": {"type": "Polygon", "coordinates": [[[65.73955965027932, 44.023633020813534], [65.7391, 44.0237], [65.75225096942373, 44.06283985206589], [65.76401104029125, 44.09784011852602], [66.21827897598023, 45.449830167949095], [66.2307828440451, 45.48704412005725], [66.2432, 45.524], [66.24367565592954, 45.5239306566934], [68.5514, 45.1875], [68.53817435040268, 45.152263090715735], [68.00329653164782, 43.72719575931885], [67.9914, 43.6955], [65.73955965027932, 44.023633020813534]]]}, "properties": {"collection": "landsat-8-l1", "datetime": "2015-01-01T06:16:17.836237+00:00", "eo:sun_azimuth": 160.8078976, "eo:sun_elevation": 20.22442041, "eo:cloud_cover": 94, "eo:row": "029", "eo:column": "156", "landsat:product_id": null, "landsat:scene_id": "LC81560292015001LGN00", "landsat:processing_level": "L1GT", "landsat:tier": "pre-collection", "eo:epsg": 32642}, "assets": {"index": {"type": "text/html", "title": "HTML index page", "href": "https://s3-us-west-2.amazonaws.com/landsat-pds/L8/156/029/LC81560292015001LGN00/index.html"}, "thumbnail": {"title": "Thumbnail image", "type": "image/jpeg", "href": "https://s3-us-west-2.amazonaws.com/landsat-pds/L8/156/029/LC81560292015001LGN00/LC81560292015001LGN00_thumb_large.jpg"}, "B1": {"type": "image/x.geotiff", "eo:bands": [0], "title": "Band 1 (coastal)", "href": "https://s3-us-west-2.amazonaws.com/landsat-pds/L8/156/029/LC81560292015001LGN00/LC81560292015001LGN00_B1.TIF"}, "B2": {"type": "image/x.geotiff", "eo:bands": [1], "title": "Band 2 (blue)", "href": "https://s3-us-west-2.amazonaws.com/landsat-pds/L8/156/029/LC81560292015001LGN00/LC81560292015001LGN00_B2.TIF"}, "B3": {"type": "image/x.geotiff", "eo:bands": [2], "title": "Band 3 (green)", "href": "https://s3-us-west-2.amazonaws.com/landsat-pds/L8/156/029/LC81560292015001LGN00/LC81560292015001LGN00_B3.TIF"}, "B4": {"type": "image/x.geotiff", "eo:bands": [3], "title": "Band 4 (red)", "href": "https://s3-us-west-2.amazonaws.com/landsat-pds/L8/156/029/LC81560292015001LGN00/LC81560292015001LGN00_B4.TIF"}, "B5": {"type": "image/x.geotiff", "eo:bands": [4], "title": "Band 5 (nir)", "href": "https://s3-us-west-2.amazonaws.com/landsat-pds/L8/156/029/LC81560292015001LGN00/LC81560292015001LGN00_B5.TIF"}, "B6": {"type": "image/x.geotiff", "eo:bands": [5], "title": "Band 6 (swir16)", "href": "https://s3-us-west-2.amazonaws.com/landsat-pds/L8/156/029/LC81560292015001LGN00/LC81560292015001LGN00_B6.TIF"}, "B7": {"type": "image/x.geotiff", "eo:bands": [6], "title": "Band 7 (swir22)", "href": "https://s3-us-west-2.amazonaws.com/landsat-pds/L8/156/029/LC81560292015001LGN00/LC81560292015001LGN00_B7.TIF"}, "B8": {"type": "image/x.geotiff", "eo:bands": [7], "title": "Band 8 (pan)", "href": "https://s3-us-west-2.amazonaws.com/landsat-pds/L8/156/029/LC81560292015001LGN00/LC81560292015001LGN00_B8.TIF"}, "B9": {"type": "image/x.geotiff", "eo:bands": [8], "title": "Band 9 (cirrus)", "href": "https://s3-us-west-2.amazonaws.com/landsat-pds/L8/156/029/LC81560292015001LGN00/LC81560292015001LGN00_B9.TIF"}, "B10": {"type": "image/x.geotiff", "eo:bands": [9], "title": "Band 10 (lwir)", "href": "https://s3-us-west-2.amazonaws.com/landsat-pds/L8/156/029/LC81560292015001LGN00/LC81560292015001LGN00_B10.TIF"}, "B11": {"type": "image/x.geotiff", "eo:bands": [10], "title": "Band 11 (lwir)", "href": "https://s3-us-west-2.amazonaws.com/landsat-pds/L8/156/029/LC81560292015001LGN00/LC81560292015001LGN00_B11.TIF"}, "ANG": {"title": "Angle coefficients file", "type": "text/plain", "href": "https://s3-us-west-2.amazonaws.com/landsat-pds/L8/156/029/LC81560292015001LGN00/LC81560292015001LGN00_ANG.txt"}, "MTL": {"title": "original metadata file", "type": "text/plain", "href": "https://s3-us-west-2.amazonaws.com/landsat-pds/L8/156/029/LC81560292015001LGN00/LC81560292015001LGN00_MTL.txt"}, "BQA": {"title": "Band quality data", "type": "image/x.geotiff", "href": "https://s3-us-west-2.amazonaws.com/landsat-pds/L8/156/029/LC81560292015001LGN00/LC81560292015001LGN00_BQA.TIF"}}, "links": [{"rel": "self", "href": "https://landsat-stac.s3.amazonaws.com/landsat-8-l1/156/029/2015-01-01/LC81560292015001LGN00.json"}, {"rel": "root", "href": "../../../../catalog.json"}, {"rel": "parent", "href": "../catalog.json"}, {"rel": "collection", "href": "../../catalog.json"}]} +{ + "type": "Feature", + "id": "LC81560292015001LGN00", + "bbox": [ + 65.61297, + 43.48724, + 68.67079, + 45.70204 + ], + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + 65.73955965027932, + 44.023633020813534 + ], + [ + 65.7391, + 44.0237 + ], + [ + 65.75225096942373, + 44.06283985206589 + ], + [ + 65.76401104029125, + 44.09784011852602 + ], + [ + 66.21827897598023, + 45.449830167949095 + ], + [ + 66.2307828440451, + 45.48704412005725 + ], + [ + 66.2432, + 45.524 + ], + [ + 66.24367565592954, + 45.5239306566934 + ], + [ + 68.5514, + 45.1875 + ], + [ + 68.53817435040268, + 45.152263090715735 + ], + [ + 68.00329653164782, + 43.72719575931885 + ], + [ + 67.9914, + 43.6955 + ], + [ + 65.73955965027932, + 44.023633020813534 + ] + ] + ] + }, + "properties": { + "collection": "landsat-8-l1", + "datetime": "2015-01-01T06:16:17.836237+00:00", + "eo:sun_azimuth": 160.8078976, + "eo:sun_elevation": 20.22442041, + "eo:cloud_cover": 94, + "eo:row": "029", + "eo:column": "156", + "landsat:product_id": null, + "landsat:scene_id": "LC81560292015001LGN00", + "landsat:processing_level": "L1GT", + "landsat:tier": "pre-collection", + "eo:epsg": 32642 + }, + "assets": { + "index": { + "type": "text/html", + "title": "HTML index page", + "href": "https://s3-us-west-2.amazonaws.com/landsat-pds/L8/156/029/LC81560292015001LGN00/index.html" + }, + "thumbnail": { + "title": "Thumbnail image", + "type": "image/jpeg", + "href": "https://s3-us-west-2.amazonaws.com/landsat-pds/L8/156/029/LC81560292015001LGN00/LC81560292015001LGN00_thumb_large.jpg" + }, + "B1": { + "type": "image/x.geotiff", + "eo:bands": [ + 0 + ], + "title": "Band 1 (coastal)", + "href": "https://s3-us-west-2.amazonaws.com/landsat-pds/L8/156/029/LC81560292015001LGN00/LC81560292015001LGN00_B1.TIF" + }, + "B2": { + "type": "image/x.geotiff", + "eo:bands": [ + 1 + ], + "title": "Band 2 (blue)", + "href": "https://s3-us-west-2.amazonaws.com/landsat-pds/L8/156/029/LC81560292015001LGN00/LC81560292015001LGN00_B2.TIF" + }, + "B3": { + "type": "image/x.geotiff", + "eo:bands": [ + 2 + ], + "title": "Band 3 (green)", + "href": "https://s3-us-west-2.amazonaws.com/landsat-pds/L8/156/029/LC81560292015001LGN00/LC81560292015001LGN00_B3.TIF" + }, + "B4": { + "type": "image/x.geotiff", + "eo:bands": [ + 3 + ], + "title": "Band 4 (red)", + "href": "https://s3-us-west-2.amazonaws.com/landsat-pds/L8/156/029/LC81560292015001LGN00/LC81560292015001LGN00_B4.TIF" + }, + "B5": { + "type": "image/x.geotiff", + "eo:bands": [ + 4 + ], + "title": "Band 5 (nir)", + "href": "https://s3-us-west-2.amazonaws.com/landsat-pds/L8/156/029/LC81560292015001LGN00/LC81560292015001LGN00_B5.TIF" + }, + "B6": { + "type": "image/x.geotiff", + "eo:bands": [ + 5 + ], + "title": "Band 6 (swir16)", + "href": "https://s3-us-west-2.amazonaws.com/landsat-pds/L8/156/029/LC81560292015001LGN00/LC81560292015001LGN00_B6.TIF" + }, + "B7": { + "type": "image/x.geotiff", + "eo:bands": [ + 6 + ], + "title": "Band 7 (swir22)", + "href": "https://s3-us-west-2.amazonaws.com/landsat-pds/L8/156/029/LC81560292015001LGN00/LC81560292015001LGN00_B7.TIF" + }, + "B8": { + "type": "image/x.geotiff", + "eo:bands": [ + 7 + ], + "title": "Band 8 (pan)", + "href": "https://s3-us-west-2.amazonaws.com/landsat-pds/L8/156/029/LC81560292015001LGN00/LC81560292015001LGN00_B8.TIF" + }, + "B9": { + "type": "image/x.geotiff", + "eo:bands": [ + 8 + ], + "title": "Band 9 (cirrus)", + "href": "https://s3-us-west-2.amazonaws.com/landsat-pds/L8/156/029/LC81560292015001LGN00/LC81560292015001LGN00_B9.TIF" + }, + "B10": { + "type": "image/x.geotiff", + "eo:bands": [ + 9 + ], + "title": "Band 10 (lwir)", + "href": "https://s3-us-west-2.amazonaws.com/landsat-pds/L8/156/029/LC81560292015001LGN00/LC81560292015001LGN00_B10.TIF" + }, + "B11": { + "type": "image/x.geotiff", + "eo:bands": [ + 10 + ], + "title": "Band 11 (lwir)", + "href": "https://s3-us-west-2.amazonaws.com/landsat-pds/L8/156/029/LC81560292015001LGN00/LC81560292015001LGN00_B11.TIF" + }, + "ANG": { + "title": "Angle coefficients file", + "type": "text/plain", + "href": "https://s3-us-west-2.amazonaws.com/landsat-pds/L8/156/029/LC81560292015001LGN00/LC81560292015001LGN00_ANG.txt" + }, + "MTL": { + "title": "original metadata file", + "type": "text/plain", + "href": "https://s3-us-west-2.amazonaws.com/landsat-pds/L8/156/029/LC81560292015001LGN00/LC81560292015001LGN00_MTL.txt" + }, + "BQA": { + "title": "Band quality data", + "type": "image/x.geotiff", + "href": "https://s3-us-west-2.amazonaws.com/landsat-pds/L8/156/029/LC81560292015001LGN00/LC81560292015001LGN00_BQA.TIF" + } + }, + "links": [ + { + "rel": "self", + "href": "https://landsat-stac.s3.amazonaws.com/landsat-8-l1/156/029/2015-01-01/LC81560292015001LGN00.json" + }, + { + "rel": "root", + "href": "../../../../catalog.json" + }, + { + "rel": "parent", + "href": "../catalog.json" + }, + { + "rel": "collection", + "href": "../../catalog.json" + } + ] +} \ No newline at end of file diff --git a/tests/data-files/file/file-example.json b/tests/data-files/file/file-example.json index 4533a4abc..76b37e303 100644 --- a/tests/data-files/file/file-example.json +++ b/tests/data-files/file/file-example.json @@ -1,16 +1,10 @@ { - "id": "S1A_EW_GRDM_1SSH_20181103T235855_20181103T235955_024430_02AD5D_5616", "type": "Feature", - "stac_version": "1.0.0-beta.2", - "stac_extensions": [ - "file" - ], - "bbox": [ - -70.275032, - -64.72924, - -65.087479, - -51.105831 - ], + "stac_version": "1.0.0-rc.3", + "id": "S1A_EW_GRDM_1SSH_20181103T235855_20181103T235955_024430_02AD5D_5616", + "properties": { + "datetime": "2018-11-03T23:58:55Z" + }, "geometry": { "type": "Polygon", "coordinates": [ @@ -38,32 +32,30 @@ ] ] }, - "properties": { - "datetime": "2018-11-03T23:58:55Z" - }, + "links": [], "assets": { "noises": { "href": "./annotation/calibration/noise-s1a-ew-grd-hh-20181103t235855-20181103t235955-024430-02ad5d-001.xml", - "title": "Calibration Schema", "type": "text/xml", + "title": "Calibration Schema", "file:checksum": "90e40210a30d1711e81a4b11ef67b28744321659" }, "calibrations": { "href": "./annotation/calibration/calibration-s1a-ew-grd-hh-20181103t235855-20181103t235955-024430-02ad5d-001.xml", - "title": "Noise Schema", "type": "text/xml", + "title": "Noise Schema", "file:checksum": "90e402104fc5351af67db0b8f1746efe421a05e4" }, "products": { "href": "./annotation/s1a-ew-grd-hh-20181103t235855-20181103t235955-024430-02ad5d-001.xml", - "title": "Product Schema", "type": "text/xml", + "title": "Product Schema", "file:checksum": "90e402107a7f2588a85362b9beea2a12d4514d45" }, "measurement": { "href": "./measurement/s1a-ew-grd-hh-20181103t235855-20181103t235955-024430-02ad5d-001.tiff", - "title": "Measurements", "type": "image/tiff", + "title": "Measurements", "file:byte_order": "little-endian", "file:data_type": "uint16", "file:size": 209715200, @@ -72,8 +64,8 @@ }, "thumbnail": { "href": "./preview/quick-look.png", - "title": "Thumbnail", "type": "image/png", + "title": "Thumbnail", "file:byte_order": "big-endian", "file:data_type": "uint8", "file:size": 146484, @@ -81,5 +73,13 @@ "file:nodata": [] } }, - "links": [] + "bbox": [ + -70.275032, + -64.72924, + -65.087479, + -51.105831 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/file/v1.0.0/schema.json" + ] } \ No newline at end of file diff --git a/tests/data-files/get_examples.py b/tests/data-files/get_examples.py index 6cf96810c..9811d75de 100644 --- a/tests/data-files/get_examples.py +++ b/tests/data-files/get_examples.py @@ -7,49 +7,64 @@ import json from tempfile import TemporaryDirectory from subprocess import call +from typing import Any, Dict, List, Optional from urllib.error import HTTPError import pystac -from pystac.serialization import identify_stac_object, STACObjectType +from pystac.serialization import identify_stac_object -def remove_bad_collection(js): - links = js.get('links') +def remove_bad_collection(js: Dict[str, Any]) -> Dict[str, Any]: + links: Optional[List[Dict[str, Any]]] = js.get("links") if links is not None: - filtered_links = [] + filtered_links: List[Dict[str, Any]] = [] for link in links: - rel = link.get('rel') - if rel is not None and rel == 'collection': - href = link['href'] + rel = link.get("rel") + if rel is not None and rel == "collection": + href: str = link["href"] try: - json.loads(pystac.STAC_IO.read_text(href)) + json.loads(pystac.StacIO.default().read_text(href)) filtered_links.append(link) except (HTTPError, FileNotFoundError, json.decoder.JSONDecodeError): - print('===REMOVING UNREADABLE COLLECTION AT {}'.format(href)) + print("===REMOVING UNREADABLE COLLECTION AT {}".format(href)) else: filtered_links.append(link) - js['links'] = filtered_links + js["links"] = filtered_links return js -if __name__ == '__main__': - parser = argparse.ArgumentParser(description='Get examples from the stac-spec repo.') +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description="Get examples from the stac-spec repo." + ) parser.add_argument( - 'previous_version', - metavar='PREVIOUS_VERSION', - help='The previous STAC_VERSION that examples have already been pulled from.') + "previous_version", + metavar="PREVIOUS_VERSION", + help="The previous STAC_VERSION that examples have already been pulled from.", + ) args = parser.parse_args() - stac_repo = 'https://github.com/radiantearth/stac-spec' - stac_spec_tag = 'v{}'.format(pystac.get_stac_version()) + stac_repo = "https://github.com/radiantearth/stac-spec" + stac_spec_tag = "v{}".format(pystac.get_stac_version()) - examples_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), 'examples')) + examples_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), "examples")) with TemporaryDirectory() as tmp_dir: - call(['git', 'clone', '--depth', '1', '--branch', stac_spec_tag, stac_repo, tmp_dir]) - - example_dirs = [] + call( + [ + "git", + "clone", + "--depth", + "1", + "--branch", + stac_spec_tag, + stac_repo, + tmp_dir, + ] + ) + + example_dirs: List[str] = [] for root, _, _ in os.walk(tmp_dir): example_dirs.append(os.path.join(root)) @@ -58,46 +73,52 @@ def remove_bad_collection(js): for example_dir in example_dirs: for root, _, files in os.walk(example_dir): for fname in files: - if fname.endswith('.json'): + if fname.endswith(".json"): path = os.path.join(root, fname) with open(path) as f: try: - js = json.loads(f.read()) + js: Dict[str, Any] = json.loads(f.read()) except json.decoder.JSONDecodeError: # Account for bad examples that can't be parsed. js = {} - example_version = js.get('stac_version') - if example_version is not None and \ - example_version > args.previous_version: - relpath = '{}/{}'.format(pystac.get_stac_version(), - path.replace('{}/'.format(tmp_dir), '')) + example_version = js.get("stac_version") + if ( + example_version is not None + and example_version > args.previous_version + ): + relpath = "{}/{}".format( + pystac.get_stac_version(), + path.replace("{}/".format(tmp_dir), ""), + ) target_path = os.path.join(examples_dir, relpath) - print('Creating example at {}'.format(target_path)) + print("Creating example at {}".format(target_path)) info = identify_stac_object(js) # Handle the case where there are collection links that # don't exist. - if info.object_type == STACObjectType.ITEM: + if info.object_type == pystac.STACObjectType.ITEM: js = remove_bad_collection(js) d = os.path.dirname(target_path) if not os.path.isdir(d): os.makedirs(d) - with open(target_path, 'w') as f: + with open(target_path, "w") as f: f.write(json.dumps(js, indent=4)) # Add info to the new example-info.csv lines - line_info = [ - relpath, info.object_type, example_version, - '|'.join(info.common_extensions), '|'.join(info.custom_extensions) + line_info: List[str] = [ + relpath, + info.object_type, + example_version, + "|".join(info.extensions), ] line = '"{}"'.format('","'.join(line_info)) example_csv_lines.add(line) # Write the new example-info.csv lines into a temp file for inspection - with open(os.path.join(examples_dir, 'examples-info-NEW.csv'), 'w') as f: - txt = '\n'.join(sorted(example_csv_lines)) + with open(os.path.join(examples_dir, "examples-info-NEW.csv"), "w") as f: + txt = "\n".join(sorted(example_csv_lines)) f.write(txt) diff --git a/tests/data-files/invalid/shared-id/catalog.json b/tests/data-files/invalid/shared-id/catalog.json index 0fd03d984..ac8b6bb6b 100644 --- a/tests/data-files/invalid/shared-id/catalog.json +++ b/tests/data-files/invalid/shared-id/catalog.json @@ -1,17 +1,19 @@ { - "id": "test", - "stac_version": "1.0.0-beta.2", - "description": "test desc", - "links": [ - { - "rel": "root", - "href": "./catalog.json", - "type": "application/json" - }, - { - "rel": "child", - "href": "./test/collection.json", - "type": "application/json" - } - ] + "type": "Catalog", + "id": "test", + "stac_version": "1.0.0-rc.3", + "description": "test desc", + "links": [ + { + "rel": "root", + "href": "./catalog.json", + "type": "application/json" + }, + { + "rel": "child", + "href": "./test/collection.json", + "type": "application/json" + } + ], + "stac_extensions": [] } \ No newline at end of file diff --git a/tests/data-files/invalid/shared-id/test/collection.json b/tests/data-files/invalid/shared-id/test/collection.json index 03455d70e..cbd2a55d9 100644 --- a/tests/data-files/invalid/shared-id/test/collection.json +++ b/tests/data-files/invalid/shared-id/test/collection.json @@ -1,43 +1,45 @@ { - "id": "test", - "stac_version": "1.0.0-beta.2", - "description": "test desc", - "links": [ - { - "rel": "root", - "href": "../catalog.json", - "type": "application/json" - }, - { - "rel": "item", - "href": "./test-item-1/test-item-1.json", - "type": "application/json" - }, - { - "rel": "parent", - "href": "../catalog.json", - "type": "application/json" - } - ], - "extent": { - "spatial": { - "bbox": [ - [ - -2.5048828125, - 3.8916575492899987, - -1.9610595703125, - 3.8916575492899987 - ] - ] - }, - "temporal": { - "interval": [ - [ - "2020-03-14T16:32:00Z", - null - ] - ] - } + "type": "Collection", + "id": "test", + "stac_version": "1.0.0-rc.3", + "description": "test desc", + "links": [ + { + "rel": "root", + "href": "../catalog.json", + "type": "application/json" }, - "license": "proprietary" + { + "rel": "item", + "href": "./test-item-1/test-item-1.json", + "type": "application/json" + }, + { + "rel": "parent", + "href": "../catalog.json", + "type": "application/json" + } + ], + "stac_extensions": [], + "extent": { + "spatial": { + "bbox": [ + [ + -2.5048828125, + 3.8916575492899987, + -1.9610595703125, + 3.8916575492899987 + ] + ] + }, + "temporal": { + "interval": [ + [ + "2020-03-14T16:32:00Z", + null + ] + ] + } + }, + "license": "proprietary" } \ No newline at end of file diff --git a/tests/data-files/invalid/shared-id/test/test-item-1/test-item-1.json b/tests/data-files/invalid/shared-id/test/test-item-1/test-item-1.json index 5afe56e3d..99a057ba4 100644 --- a/tests/data-files/invalid/shared-id/test/test-item-1/test-item-1.json +++ b/tests/data-files/invalid/shared-id/test/test-item-1/test-item-1.json @@ -1,60 +1,61 @@ { - "type": "Feature", - "stac_version": "1.0.0-beta.2", - "id": "test-item-1", - "properties": { - "datetime": "2020-03-14T16:32:00Z" - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [ - -2.5048828125, - 3.8916575492899987 - ], - [ - -1.9610595703125, - 3.8916575492899987 - ], - [ - -1.9610595703125, - 4.275202171119132 - ], - [ - -2.5048828125, - 4.275202171119132 - ], - [ - -2.5048828125, - 3.8916575492899987 - ] - ] + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "test-item-1", + "properties": { + "datetime": "2020-03-14T16:32:00Z" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + -2.5048828125, + 3.8916575492899987 + ], + [ + -1.9610595703125, + 3.8916575492899987 + ], + [ + -1.9610595703125, + 4.275202171119132 + ], + [ + -2.5048828125, + 4.275202171119132 + ], + [ + -2.5048828125, + 3.8916575492899987 ] + ] + ] + }, + "links": [ + { + "rel": "root", + "href": "../../catalog.json", + "type": "application/json" + }, + { + "rel": "collection", + "href": "../collection.json", + "type": "application/json" }, - "links": [ - { - "rel": "root", - "href": "../../catalog.json", - "type": "application/json" - }, - { - "rel": "collection", - "href": "../collection.json", - "type": "application/json" - }, - { - "rel": "parent", - "href": "../collection.json", - "type": "application/json" - } - ], - "assets": {}, - "bbox": [ - -2.5048828125, - 3.8916575492899987, - -1.9610595703125, - 3.8916575492899987 - ], - "collection": "test" + { + "rel": "parent", + "href": "../collection.json", + "type": "application/json" + } + ], + "assets": {}, + "bbox": [ + -2.5048828125, + 3.8916575492899987, + -1.9610595703125, + 3.8916575492899987 + ], + "stac_extensions": [], + "collection": "test" } \ No newline at end of file diff --git a/tests/data-files/item/sample-item-asset-properties.json b/tests/data-files/item/sample-item-asset-properties.json index 0d703c7ef..21dea398b 100644 --- a/tests/data-files/item/sample-item-asset-properties.json +++ b/tests/data-files/item/sample-item-asset-properties.json @@ -1,14 +1,32 @@ { - "stac_version": "1.0.0-beta.2", - "stac_extensions": [], "type": "Feature", + "stac_version": "1.0.0-rc.3", "id": "CS3-20160503_132131_05", - "bbox": [ - -122.59750209, - 37.48803556, - -122.2880486, - 37.613537207 - ], + "properties": { + "datetime": "2016-05-03T13:22:30.040000Z", + "title": "A CS3 item", + "license": "PDDL-1.0", + "providers": [ + { + "name": "CoolSat", + "roles": [ + "producer", + "licensor" + ], + "url": "https://cool-sat.com/" + } + ], + "gsd": 30, + "platform": "political", + "instruments": [ + "guitar", + "violin" + ], + "constellation": "big dipper", + "mission": "impossible", + "created": "2017-03-17T13:22:30.040Z", + "updated": "2017-03-18T13:22:30.040Z" + }, "geometry": { "type": "Polygon", "coordinates": [ @@ -36,34 +54,7 @@ ] ] }, - "properties": { - "datetime": "2016-05-03T13:22:30.040Z", - "title": "A CS3 item", - "license": "PDDL-1.0", - "providers": [ - { - "name": "CoolSat", - "roles": [ - "producer", - "licensor" - ], - "url": "https://cool-sat.com/" - } - ], - "gsd": 30, - "platform": "political", - "instruments": ["guitar", "violin"], - "constellation": "big dipper", - "mission": "impossible", - "created": "2017-03-17T13:22:30.040Z", - "updated": "2017-03-18T13:22:30.040Z" - }, - "collection": "CS3", "links": [ - { - "rel": "self", - "href": "http://cool-sat.com/catalog/CS3-20160503_132130_04/CS3-20160503_132130_04.json" - }, { "rel": "collection", "href": "https://raw.githubusercontent.com/radiantearth/stac-spec/v0.8.1/collection-spec/examples/sentinel2.json" @@ -85,21 +76,31 @@ "license": "CC-BY-4.0", "providers": [ { - "name": "USGS", - "url": "https://landsat.usgs.gov/", - "roles": [ - "producer", - "licensor" - ] + "name": "USGS", + "url": "https://landsat.usgs.gov/", + "roles": [ + "producer", + "licensor" + ] } ], "gsd": 40, "platform": "shoes", - "instruments": ["caliper"], + "instruments": [ + "caliper" + ], "constellation": "little dipper", "mission": "possible", "created": "2017-05-17T13:22:30.040Z", "updated": "2017-05-18T13:22:30.040Z" } - } -} + }, + "bbox": [ + -122.59750209, + 37.48803556, + -122.2880486, + 37.613537207 + ], + "stac_extensions": [], + "collection": "CS3" +} \ No newline at end of file diff --git a/tests/data-files/item/sample-item.json b/tests/data-files/item/sample-item.json index 64c6468de..f359fc443 100644 --- a/tests/data-files/item/sample-item.json +++ b/tests/data-files/item/sample-item.json @@ -1,14 +1,22 @@ { - "stac_version": "1.0.0-beta.2", - "stac_extensions": [], "type": "Feature", + "stac_version": "1.0.0-rc.3", "id": "CS3-20160503_132131_05", - "bbox": [ - -122.59750209, - 37.48803556, - -122.2880486, - 37.613537207 - ], + "properties": { + "datetime": "2016-05-03T13:22:30.040000Z", + "title": "A CS3 item", + "license": "PDDL-1.0", + "providers": [ + { + "name": "CoolSat", + "roles": [ + "producer", + "licensor" + ], + "url": "https://cool-sat.com/" + } + ] + }, "geometry": { "type": "Polygon", "coordinates": [ @@ -36,22 +44,6 @@ ] ] }, - "properties": { - "datetime": "2016-05-03T13:22:30.040Z", - "title": "A CS3 item", - "license": "PDDL-1.0", - "providers": [ - { - "name": "CoolSat", - "roles": [ - "producer", - "licensor" - ], - "url": "https://cool-sat.com/" - } - ] - }, - "collection": "CS3", "links": [ { "rel": "self", @@ -72,5 +64,13 @@ "href": "http://cool-sat.com/catalog/CS3-20160503_132130_04/thumbnail.png", "title": "Thumbnail" } - } -} + }, + "bbox": [ + -122.59750209, + 37.48803556, + -122.2880486, + 37.613537207 + ], + "stac_extensions": [], + "collection": "CS3" +} \ No newline at end of file diff --git a/tests/data-files/label/label-example-1.json b/tests/data-files/label/label-example-1.json index 366907823..81e96a532 100644 --- a/tests/data-files/label/label-example-1.json +++ b/tests/data-files/label/label-example-1.json @@ -1,9 +1,9 @@ { "type": "Feature", - "stac_version": "1.0.0-beta.2", + "stac_version": "1.0.0-rc.3", "id": "label-example-1-label-item", "properties": { - "datetime": "2019-10-04 18:55:37Z", + "datetime": "2019-10-04T18:55:37Z", "label:description": "labels for area-1-1", "label:type": "vector", "label:properties": [ @@ -86,12 +86,6 @@ ] ] }, - "bbox": [ - -2.5048828125, - 3.8916575492899987, - -1.9610595703125, - 3.8916575492899987 - ], "links": [ { "rel": "source", @@ -105,7 +99,13 @@ "type": "application/geo+json" } }, + "bbox": [ + -2.5048828125, + 3.8916575492899987, + -1.9610595703125, + 3.8916575492899987 + ], "stac_extensions": [ - "label" + "https://stac-extensions.github.io/label/v1.0.0/schema.json" ] } \ No newline at end of file diff --git a/tests/data-files/label/label-example-2.json b/tests/data-files/label/label-example-2.json index 5d46e1e2b..cd4a9ece4 100644 --- a/tests/data-files/label/label-example-2.json +++ b/tests/data-files/label/label-example-2.json @@ -1,9 +1,9 @@ { "type": "Feature", - "stac_version": "1.0.0-beta.2", + "stac_version": "1.0.0-rc.3", "id": "label-example-1-label-item", "properties": { - "datetime": "2019-10-04 18:55:37Z", + "datetime": "2019-10-04T18:55:37Z", "label:description": "labels for area-1-1", "label:type": "raster", "label:properties": null, @@ -79,12 +79,6 @@ ] ] }, - "bbox": [ - -2.5048828125, - 3.8916575492899987, - -1.9610595703125, - 3.8916575492899987 - ], "links": [ { "rel": "source", @@ -98,7 +92,13 @@ "type": "image/tiff; application=geotiff" } }, + "bbox": [ + -2.5048828125, + 3.8916575492899987, + -1.9610595703125, + 3.8916575492899987 + ], "stac_extensions": [ - "label" + "https://stac-extensions.github.io/label/v1.0.0/schema.json" ] } \ No newline at end of file diff --git a/tests/data-files/pointcloud/example-laz-no-statistics.json b/tests/data-files/pointcloud/example-laz-no-statistics.json index 102c94c07..89f5b948a 100644 --- a/tests/data-files/pointcloud/example-laz-no-statistics.json +++ b/tests/data-files/pointcloud/example-laz-no-statistics.json @@ -1,140 +1,135 @@ { - "stac_version": "1.0.0-beta.2", - "stac_extensions": [ - "pointcloud" + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "autzen-full.laz", + "properties": { + "datetime": "2013-07-17T00:00:00Z", + "pc:count": 10653336, + "pc:density": 0, + "pc:encoding": "LASzip", + "pc:schemas": [ + { + "name": "X", + "size": 8, + "type": "floating" + }, + { + "name": "Y", + "size": 8, + "type": "floating" + }, + { + "name": "Z", + "size": 8, + "type": "floating" + }, + { + "name": "Intensity", + "size": 2, + "type": "unsigned" + }, + { + "name": "ReturnNumber", + "size": 1, + "type": "unsigned" + }, + { + "name": "NumberOfReturns", + "size": 1, + "type": "unsigned" + }, + { + "name": "ScanDirectionFlag", + "size": 1, + "type": "unsigned" + }, + { + "name": "EdgeOfFlightLine", + "size": 1, + "type": "unsigned" + }, + { + "name": "Classification", + "size": 1, + "type": "unsigned" + }, + { + "name": "ScanAngleRank", + "size": 4, + "type": "floating" + }, + { + "name": "UserData", + "size": 1, + "type": "unsigned" + }, + { + "name": "PointSourceId", + "size": 2, + "type": "unsigned" + }, + { + "name": "GpsTime", + "size": 8, + "type": "floating" + }, + { + "name": "Red", + "size": 2, + "type": "unsigned" + }, + { + "name": "Green", + "size": 2, + "type": "unsigned" + }, + { + "name": "Blue", + "size": 2, + "type": "unsigned" + } ], - "assets": {}, - "bbox": [ - -123.0755422, - 44.04971882, - 123.791472, - -123.0619599, - 44.06278031, - 187.531248 - ], - "geometry": { - "coordinates": [ - [ - [ - -123.07498674, - 44.04971882 - ], - [ - -123.07554223, - 44.06248623 - ], - [ - -123.0625126, - 44.06278031 - ], - [ - -123.06195992, - 44.05001283 - ], - [ - -123.07498674, - 44.04971882 - ] - ] + "pc:type": "lidar", + "title": "USGS 3DEP LiDAR" + }, + "geometry": { + "coordinates": [ + [ + [ + -123.07498674, + 44.04971882 ], - "type": "Polygon" - }, - "id": "autzen-full.laz", - "links": [ - { - "href": "/Users/hobu/dev/git/pdal/test/data/autzen/autzen-full.laz", - "rel": "self" - } - ], - "properties": { - "datetime": "2013-07-17T00:00:00Z", - "pc:count": 10653336, - "pc:density": 0, - "pc:encoding": "LASzip", - "pc:schemas": [ - { - "name": "X", - "size": 8, - "type": "floating" - }, - { - "name": "Y", - "size": 8, - "type": "floating" - }, - { - "name": "Z", - "size": 8, - "type": "floating" - }, - { - "name": "Intensity", - "size": 2, - "type": "unsigned" - }, - { - "name": "ReturnNumber", - "size": 1, - "type": "unsigned" - }, - { - "name": "NumberOfReturns", - "size": 1, - "type": "unsigned" - }, - { - "name": "ScanDirectionFlag", - "size": 1, - "type": "unsigned" - }, - { - "name": "EdgeOfFlightLine", - "size": 1, - "type": "unsigned" - }, - { - "name": "Classification", - "size": 1, - "type": "unsigned" - }, - { - "name": "ScanAngleRank", - "size": 4, - "type": "floating" - }, - { - "name": "UserData", - "size": 1, - "type": "unsigned" - }, - { - "name": "PointSourceId", - "size": 2, - "type": "unsigned" - }, - { - "name": "GpsTime", - "size": 8, - "type": "floating" - }, - { - "name": "Red", - "size": 2, - "type": "unsigned" - }, - { - "name": "Green", - "size": 2, - "type": "unsigned" - }, - { - "name": "Blue", - "size": 2, - "type": "unsigned" - } + [ + -123.07554223, + 44.06248623 + ], + [ + -123.0625126, + 44.06278031 ], - "pc:type": "lidar", - "title": "USGS 3DEP LiDAR" - }, - "type": "Feature" + [ + -123.06195992, + 44.05001283 + ], + [ + -123.07498674, + 44.04971882 + ] + ] + ], + "type": "Polygon" + }, + "links": [], + "assets": {}, + "bbox": [ + -123.0755422, + 44.04971882, + 123.791472, + -123.0619599, + 44.06278031, + 187.531248 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/pointcloud/v1.0.0/schema.json" + ] } \ No newline at end of file diff --git a/tests/data-files/pointcloud/example-laz.json b/tests/data-files/pointcloud/example-laz.json index a9bfbf87e..c50eeebf6 100644 --- a/tests/data-files/pointcloud/example-laz.json +++ b/tests/data-files/pointcloud/example-laz.json @@ -1,51 +1,7 @@ { - "stac_version": "1.0.0-beta.2", - "stac_extensions": [ - "pointcloud" - ], - "assets": {}, - "bbox": [ - -123.0755422, - 44.04971882, - 123.791472, - -123.0619599, - 44.06278031, - 187.531248 - ], - "geometry": { - "coordinates": [ - [ - [ - -123.07498674, - 44.04971882 - ], - [ - -123.07554223, - 44.06248623 - ], - [ - -123.0625126, - 44.06278031 - ], - [ - -123.06195992, - 44.05001283 - ], - [ - -123.07498674, - 44.04971882 - ] - ] - ], - "type": "Polygon" - }, + "type": "Feature", + "stac_version": "1.0.0-rc.3", "id": "autzen-full.laz", - "links": [ - { - "href": "/Users/hobu/dev/git/pdal/test/data/autzen/autzen-full.laz", - "rel": "self" - } - ], "properties": { "datetime": "2013-07-17T00:00:00Z", "pc:count": 10653336, @@ -298,5 +254,44 @@ "pc:type": "lidar", "title": "USGS 3DEP LiDAR" }, - "type": "Feature" -} + "geometry": { + "coordinates": [ + [ + [ + -123.07498674, + 44.04971882 + ], + [ + -123.07554223, + 44.06248623 + ], + [ + -123.0625126, + 44.06278031 + ], + [ + -123.06195992, + 44.05001283 + ], + [ + -123.07498674, + 44.04971882 + ] + ] + ], + "type": "Polygon" + }, + "links": [], + "assets": {}, + "bbox": [ + -123.0755422, + 44.04971882, + 123.791472, + -123.0619599, + 44.06278031, + 187.531248 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/pointcloud/v1.0.0/schema.json" + ] +} \ No newline at end of file diff --git a/tests/data-files/projection/example-landsat8.json b/tests/data-files/projection/example-landsat8.json index 4e262cdea..21f1e6a2e 100644 --- a/tests/data-files/projection/example-landsat8.json +++ b/tests/data-files/projection/example-landsat8.json @@ -1,18 +1,187 @@ { - "stac_version": "1.0.0-beta.2", - "stac_extensions": [ - "eo", - "projection" - ], - "id": "LC81530252014153LGN00", "type": "Feature", - "collection": "landsat-8-l1", - "bbox": [ - 148.13933, - 59.51584, - 152.52758, - 60.63437 - ], + "stac_version": "1.0.0-rc.3", + "id": "LC81530252014153LGN00", + "properties": { + "datetime": "2018-10-01T01:08:32.033000Z", + "proj:epsg": 32614, + "proj:wkt2": "PROJCS[\"WGS 84 / UTM zone 14N\",GEOGCS[\"WGS 84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS 84\",6378137,298.257223563,AUTHORITY[\"EPSG\",\"7030\"]],AUTHORITY[\"EPSG\",\"6326\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.01745329251994328,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\",\"4326\"]],UNIT[\"metre\",1,AUTHORITY[\"EPSG\",\"9001\"]],PROJECTION[\"Transverse_Mercator\"],PARAMETER[\"latitude_of_origin\",0],PARAMETER[\"central_meridian\",-99],PARAMETER[\"scale_factor\",0.9996],PARAMETER[\"false_easting\",500000],PARAMETER[\"false_northing\",0],AUTHORITY[\"EPSG\",\"32614\"],AXIS[\"Easting\",EAST],AXIS[\"Northing\",NORTH]]", + "proj:projjson": { + "$schema": "https://proj.org/schemas/v0.2/projjson.schema.json", + "type": "ProjectedCRS", + "name": "WGS 84 / UTM zone 14N", + "base_crs": { + "name": "WGS 84", + "datum": { + "type": "GeodeticReferenceFrame", + "name": "World Geodetic System 1984", + "ellipsoid": { + "name": "WGS 84", + "semi_major_axis": 6378137, + "inverse_flattening": 298.257223563 + } + }, + "coordinate_system": { + "subtype": "ellipsoidal", + "axis": [ + { + "name": "Geodetic latitude", + "abbreviation": "Lat", + "direction": "north", + "unit": "degree" + }, + { + "name": "Geodetic longitude", + "abbreviation": "Lon", + "direction": "east", + "unit": "degree" + } + ] + }, + "id": { + "authority": "EPSG", + "code": 4326 + } + }, + "conversion": { + "name": "UTM zone 14N", + "method": { + "name": "Transverse Mercator", + "id": { + "authority": "EPSG", + "code": 9807 + } + }, + "parameters": [ + { + "name": "Latitude of natural origin", + "value": 0, + "unit": "degree", + "id": { + "authority": "EPSG", + "code": 8801 + } + }, + { + "name": "Longitude of natural origin", + "value": -99, + "unit": "degree", + "id": { + "authority": "EPSG", + "code": 8802 + } + }, + { + "name": "Scale factor at natural origin", + "value": 0.9996, + "unit": "unity", + "id": { + "authority": "EPSG", + "code": 8805 + } + }, + { + "name": "False easting", + "value": 500000, + "unit": "metre", + "id": { + "authority": "EPSG", + "code": 8806 + } + }, + { + "name": "False northing", + "value": 0, + "unit": "metre", + "id": { + "authority": "EPSG", + "code": 8807 + } + } + ] + }, + "coordinate_system": { + "subtype": "Cartesian", + "axis": [ + { + "name": "Easting", + "abbreviation": "E", + "direction": "east", + "unit": "metre" + }, + { + "name": "Northing", + "abbreviation": "N", + "direction": "north", + "unit": "metre" + } + ] + }, + "area": "World - N hemisphere - 102\u00b0W to 96\u00b0W - by country", + "bbox": { + "south_latitude": 0, + "west_longitude": -102, + "north_latitude": 84, + "east_longitude": -96 + }, + "id": { + "authority": "EPSG", + "code": 32614 + } + }, + "proj:geometry": { + "coordinates": [ + [ + [ + 169200.0, + 3712800.0 + ], + [ + 403200.0, + 3712800.0 + ], + [ + 403200.0, + 3951000.0 + ], + [ + 169200.0, + 3951000.0 + ], + [ + 169200.0, + 3712800.0 + ] + ] + ], + "type": "Polygon" + }, + "proj:bbox": [ + 169200.0, + 3712800.0, + 403200.0, + 3951000.0 + ], + "proj:centroid": { + "lat": 34.595302781575604, + "lon": -101.34448382627504 + }, + "proj:shape": [ + 8391, + 8311 + ], + "proj:transform": [ + 30.0, + 0.0, + 224985.0, + 0.0, + -30.0, + 6790215.0, + 0.0, + 0.0, + 1.0 + ] + }, "geometry": { "type": "Polygon", "coordinates": [ @@ -40,10 +209,17 @@ ] ] }, + "links": [ + { + "rel": "collection", + "href": "https://example.com/landsat/collection.json" + } + ], "assets": { "B1": { "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B1.TIF", "type": "image/tiff; application=geotiff", + "title": "Band 1 (coastal)", "eo:bands": [ { "name": "B1", @@ -51,21 +227,19 @@ "center_wavelength": 0.44, "full_width_half_max": 0.02 } - ], - "title": "Band 1 (coastal)" + ] }, "B8": { "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B8.TIF", "type": "image/tiff; application=geotiff", + "title": "Band 8 (panchromatic)", "eo:bands": [ { "name": "B8", - "common_name": "panchromatic", "center_wavelength": 0.59, "full_width_half_max": 0.18 } ], - "title": "Band 8 (panchromatic)", "proj:epsg": 9999, "proj:wkt2": "PROJCS[\"WGS 84 / UTM zone 14N\",GEOGCS[\"WGS 84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS 84\",6378137,298.257223563,AUTHORITY[\"EPSG\",\"7030\"]],AUTHORITY[\"EPSG\",\"6326\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.01745329251994328,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\",\"4326\"]],UNIT[\"metre\",1,AUTHORITY[\"EPSG\",\"9001\"]],PROJECTION[\"Transverse_Mercator\"],PARAMETER[\"latitude_of_origin\",0],PARAMETER[\"central_meridian\",-99],PARAMETER[\"scale_factor\",0.9996],PARAMETER[\"false_easting\",500000],PARAMETER[\"false_northing\",0],AUTHORITY[\"EPSG\",\"32614\"],AXIS[\"Easting\",EAST],AXIS[\"Northing\",TEST_TEXT]]", "proj:projjson": { @@ -245,190 +419,15 @@ ] } }, - "properties": { - "datetime": "2018-10-01T01:08:32.033Z", - "proj:epsg": 32614, - "proj:wkt2": "PROJCS[\"WGS 84 / UTM zone 14N\",GEOGCS[\"WGS 84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS 84\",6378137,298.257223563,AUTHORITY[\"EPSG\",\"7030\"]],AUTHORITY[\"EPSG\",\"6326\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.01745329251994328,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\",\"4326\"]],UNIT[\"metre\",1,AUTHORITY[\"EPSG\",\"9001\"]],PROJECTION[\"Transverse_Mercator\"],PARAMETER[\"latitude_of_origin\",0],PARAMETER[\"central_meridian\",-99],PARAMETER[\"scale_factor\",0.9996],PARAMETER[\"false_easting\",500000],PARAMETER[\"false_northing\",0],AUTHORITY[\"EPSG\",\"32614\"],AXIS[\"Easting\",EAST],AXIS[\"Northing\",NORTH]]", - "proj:projjson": { - "$schema": "https://proj.org/schemas/v0.2/projjson.schema.json", - "type": "ProjectedCRS", - "name": "WGS 84 / UTM zone 14N", - "base_crs": { - "name": "WGS 84", - "datum": { - "type": "GeodeticReferenceFrame", - "name": "World Geodetic System 1984", - "ellipsoid": { - "name": "WGS 84", - "semi_major_axis": 6378137, - "inverse_flattening": 298.257223563 - } - }, - "coordinate_system": { - "subtype": "ellipsoidal", - "axis": [ - { - "name": "Geodetic latitude", - "abbreviation": "Lat", - "direction": "north", - "unit": "degree" - }, - { - "name": "Geodetic longitude", - "abbreviation": "Lon", - "direction": "east", - "unit": "degree" - } - ] - }, - "id": { - "authority": "EPSG", - "code": 4326 - } - }, - "conversion": { - "name": "UTM zone 14N", - "method": { - "name": "Transverse Mercator", - "id": { - "authority": "EPSG", - "code": 9807 - } - }, - "parameters": [ - { - "name": "Latitude of natural origin", - "value": 0, - "unit": "degree", - "id": { - "authority": "EPSG", - "code": 8801 - } - }, - { - "name": "Longitude of natural origin", - "value": -99, - "unit": "degree", - "id": { - "authority": "EPSG", - "code": 8802 - } - }, - { - "name": "Scale factor at natural origin", - "value": 0.9996, - "unit": "unity", - "id": { - "authority": "EPSG", - "code": 8805 - } - }, - { - "name": "False easting", - "value": 500000, - "unit": "metre", - "id": { - "authority": "EPSG", - "code": 8806 - } - }, - { - "name": "False northing", - "value": 0, - "unit": "metre", - "id": { - "authority": "EPSG", - "code": 8807 - } - } - ] - }, - "coordinate_system": { - "subtype": "Cartesian", - "axis": [ - { - "name": "Easting", - "abbreviation": "E", - "direction": "east", - "unit": "metre" - }, - { - "name": "Northing", - "abbreviation": "N", - "direction": "north", - "unit": "metre" - } - ] - }, - "area": "World - N hemisphere - 102\u00b0W to 96\u00b0W - by country", - "bbox": { - "south_latitude": 0, - "west_longitude": -102, - "north_latitude": 84, - "east_longitude": -96 - }, - "id": { - "authority": "EPSG", - "code": 32614 - } - }, - "proj:geometry": { - "coordinates": [ - [ - [ - 169200.0, - 3712800.0 - ], - [ - 403200.0, - 3712800.0 - ], - [ - 403200.0, - 3951000.0 - ], - [ - 169200.0, - 3951000.0 - ], - [ - 169200.0, - 3712800.0 - ] - ] - ], - "type": "Polygon" - }, - "proj:bbox": [ - 169200.0, - 3712800.0, - 403200.0, - 3951000.0 - ], - "proj:centroid": { - "lat": 34.595302781575604, - "lon": -101.34448382627504 - }, - "proj:shape": [ - 8391, - 8311 - ], - "proj:transform": [ - 30.0, - 0.0, - 224985.0, - 0.0, - -30.0, - 6790215.0, - 0.0, - 0.0, - 1.0 - ] - }, - "links": [ - { - "rel": "self", - "href": "https://odu9mlf7d6.execute-api.us-east-1.amazonaws.com/stage/search?id=LC08_L1TP_107018_20181001_20181001_01_RT" - } - ] -} + "bbox": [ + 148.13933, + 59.51584, + 152.52758, + 60.63437 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/eo/v1.0.0/schema.json", + "https://stac-extensions.github.io/projection/v1.0.0/schema.json" + ], + "collection": "landsat-8-l1" +} \ No newline at end of file diff --git a/tests/data-files/timestamps/example-landsat8.json b/tests/data-files/timestamps/example-landsat8.json index 55c5e6697..17c1f0a18 100644 --- a/tests/data-files/timestamps/example-landsat8.json +++ b/tests/data-files/timestamps/example-landsat8.json @@ -1,91 +1,91 @@ { - "stac_version": "1.0.0-beta.2", - "stac_extensions": [ - "timestamps" + "type": "Feature", + "stac_version": "1.0.0-rc.3", + "id": "LC08_L1TP_107018_20181001", + "properties": { + "datetime": "2018-10-01T01:08:32Z", + "created": "2018-10-02T00:00:03Z", + "updated": "2020-05-20T12:13:02Z", + "published": "2018-10-03T06:45:55Z", + "expires": "2025-01-01T00:00:00Z", + "platform": "landsat-8", + "instruments": [ + "oli", + "tirs" ], - "id": "LC08_L1TP_107018_20181001", - "type": "Feature", - "bbox": [ - 148.13933, - 59.51584, - 152.52758, - 60.63437 - ], - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [ - 152.52758, - 60.63437 - ], - [ - 149.1755, - 61.19016 - ], - [ - 148.13933, - 59.51584 - ], - [ - 151.33786, - 58.97792 - ], - [ - 152.52758, - 60.63437 - ] - ] + "constellation": "landsat" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + 152.52758, + 60.63437 + ], + [ + 149.1755, + 61.19016 + ], + [ + 148.13933, + 59.51584 + ], + [ + 151.33786, + 58.97792 + ], + [ + 152.52758, + 60.63437 ] + ] + ] + }, + "links": [], + "assets": { + "blue": { + "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B2.TIF", + "type": "image/tiff; application=geotiff", + "title": "Band 2 (blue)", + "created": "2018-10-02T00:00:00Z", + "published": "2018-11-02T00:00:00Z", + "expires": "2018-12-02T00:00:00Z", + "unpublished": "2019-01-02T00:00:00Z" + }, + "green": { + "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B3.TIF", + "type": "image/tiff; application=geotiff", + "title": "Band 3 (green)", + "created": "2018-10-02T00:00:00Z" }, - "properties": { - "datetime": "2018-10-01T01:08:32Z", - "created": "2018-10-02T00:00:03Z", - "updated": "2020-05-20T12:13:02Z", - "published": "2018-10-03T06:45:55Z", - "expires": "2025-01-01T00:00:00Z", - "platform": "landsat-8", - "instruments": ["oli", "tirs"], - "constellation": "landsat" + "red": { + "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B4.TIF", + "type": "image/tiff; application=geotiff", + "title": "Band 4 (red)", + "created": "2018-10-02T00:00:00Z" }, - "assets": { - "blue": { - "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B2.TIF", - "type": "image/tiff; application=geotiff", - "title": "Band 2 (blue)", - "created": "2018-10-02T00:00:00Z", - "published": "2018-11-02T00:00:00Z", - "expires": "2018-12-02T00:00:00Z", - "unpublished": "2019-01-02T00:00:00Z" - }, - "green": { - "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B3.TIF", - "type": "image/tiff; application=geotiff", - "title": "Band 3 (green)", - "created": "2018-10-02T00:00:00Z" - }, - "red": { - "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B4.TIF", - "type": "image/tiff; application=geotiff", - "title": "Band 4 (red)", - "created": "2018-10-02T00:00:00Z" - }, - "thumbnail": { - "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_thumb_large.jpg", - "title": "Thumbnail image", - "type": "image/jpeg", - "created": "2018-10-02T00:00:01Z" - }, - "index": { - "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/index.html", - "type": "text/html", - "title": "HTML index page", - "created": "2018-10-02T00:00:02Z", - "updated": "2020-05-20T12:13:01Z" - } + "thumbnail": { + "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_thumb_large.jpg", + "type": "image/jpeg", + "title": "Thumbnail image", + "created": "2018-10-02T00:00:01Z" }, - "links": [{ - "rel": "self", - "href": "https://odu9mlf7d6.execute-api.us-east-1.amazonaws.com/stage/search?id=LC08_L1TP_107018_20181001_20181001_01_RT" - }] + "index": { + "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/index.html", + "type": "text/html", + "title": "HTML index page", + "created": "2018-10-02T00:00:02Z", + "updated": "2020-05-20T12:13:01Z" + } + }, + "bbox": [ + 148.13933, + 59.51584, + 152.52758, + 60.63437 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/timestamps/v1.0.0/schema.json" + ] } \ No newline at end of file diff --git a/tests/data-files/view/example-landsat8.json b/tests/data-files/view/example-landsat8.json index 9e2d20d44..fe737de02 100644 --- a/tests/data-files/view/example-landsat8.json +++ b/tests/data-files/view/example-landsat8.json @@ -1,18 +1,22 @@ { - "stac_version": "1.0.0-beta.2", - "stac_extensions": [ - "sat", - "view" - ], - "id": "LC08_L1TP_107018_20181001", - "collection": "landsat-8-l1", "type": "Feature", - "bbox": [ - 148.13933, - 59.51584, - 152.52758, - 60.63437 - ], + "stac_version": "1.0.0-rc.3", + "id": "LC08_L1TP_107018_20181001", + "properties": { + "datetime": "2018-10-01T01:08:32.033000Z", + "view:sun_azimuth": 168.8989761, + "view:sun_elevation": 26.32596431, + "view:off_nadir": 0, + "view:incidence_angle": 0, + "view:azimuth": 23.4, + "platform": "landsat-8", + "instruments": [ + "oli", + "tirs" + ], + "constellation": "landsat", + "sat:orbit_state": "ascending" + }, "geometry": { "type": "Polygon", "coordinates": [ @@ -40,21 +44,12 @@ ] ] }, - "properties": { - "datetime": "2018-10-01T01:08:32.033Z", - "view:sun_azimuth": 168.8989761, - "view:sun_elevation": 26.32596431, - "view:off_nadir": 0, - "view:incidence_angle": 0, - "view:azimuth": 23.4, - "platform": "landsat-8", - "instruments": [ - "oli", - "tirs" - ], - "constellation": "landsat", - "sat:orbit_state": "ascending" - }, + "links": [ + { + "rel": "collection", + "href": "http://landsat-stac.s3.amazonaws.com/landsat-8-l1/catalog.json" + } + ], "assets": { "blue": { "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_B2.TIF", @@ -78,8 +73,8 @@ }, "thumbnail": { "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/LC08_L1TP_107018_20181001_20181001_01_RT_thumb_large.jpg", - "title": "Thumbnail image", - "type": "image/jpeg" + "type": "image/jpeg", + "title": "Thumbnail image" }, "index": { "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC08_L1TP_107018_20181001_20181001_01_RT/index.html", @@ -87,10 +82,15 @@ "title": "HTML index page" } }, - "links": [ - { - "rel": "collection", - "href": "http://landsat-stac.s3.amazonaws.com/landsat-8-l1/catalog.json" - } - ] -} + "bbox": [ + 148.13933, + 59.51584, + 152.52758, + 60.63437 + ], + "stac_extensions": [ + "https://stac-extensions.github.io/view/v1.0.0/schema.json", + "https://stac-extensions.github.io/sat/v1.0.0/schema.json" + ], + "collection": "landsat-8-l1" +} \ No newline at end of file diff --git a/tests/extensions/test_custom.py b/tests/extensions/test_custom.py new file mode 100644 index 000000000..f3939b040 --- /dev/null +++ b/tests/extensions/test_custom.py @@ -0,0 +1,151 @@ +"""Tests creating a custom extension""" + +from pystac.collection import RangeSummary +from typing import Any, Dict, Generic, List, Optional, Set, TypeVar, Union, cast +import unittest + +import pystac +from pystac.serialization.identify import STACJSONDescription, STACVersionID +from pystac.extensions.base import ( + ExtensionManagementMixin, + PropertiesExtension, + SummariesExtension, +) +from pystac.extensions.hooks import ExtensionHooks + +T = TypeVar("T", pystac.Catalog, pystac.Collection, pystac.Item, pystac.Asset) + +SCHEMA_URI = "https://example.com/v2.0/custom-schema.json" + +TEST_PROP = "test:prop" +TEST_LINK_REL = "test-link" + + +class CustomExtension( + Generic[T], + PropertiesExtension, + ExtensionManagementMixin[Union[pystac.Catalog, pystac.Collection, pystac.Item]], +): + def __init__(self, obj: Optional[pystac.STACObject]) -> None: + self.obj = obj + + def apply(self, test_prop: Optional[str]) -> None: + self.test_prop = test_prop + + @property + def test_prop(self) -> Optional[str]: + self._get_property(TEST_PROP, str) + + @test_prop.setter + def test_prop(self, v: Optional[str]) -> None: + self._set_property(TEST_PROP, v) + + def add_link(self, target: pystac.STACObject) -> None: + if self.obj is not None: + self.obj.add_link(pystac.Link(TEST_LINK_REL, target)) + else: + raise pystac.ExtensionAlreadyExistsError(f"{self} does not support links") + + @classmethod + def get_schema_uri(cls) -> str: + return super().get_schema_uri() + + @staticmethod + def custom_ext(obj: T) -> "CustomExtension[T]": + if isinstance(obj, pystac.Asset): + return cast(CustomExtension[T], AssetCustomExtension(obj)) + if isinstance(obj, pystac.Item): + return cast(CustomExtension[T], ItemCustomExtension(obj)) + if isinstance(obj, pystac.Collection): + return cast(CustomExtension[T], CollectionCustomExtension(obj)) + if isinstance(obj, pystac.Catalog): + return cast(CustomExtension[T], CatalogCustomExtension(obj)) + + raise pystac.ExtensionTypeError( + f"Custom extension does not apply to {type(obj)}" + ) + + @staticmethod + def summaries(obj: pystac.Collection) -> "SummariesCustomExtension": + return SummariesCustomExtension(obj) + + +class CatalogCustomExtension(CustomExtension[pystac.Catalog]): + def __init__(self, catalog: pystac.Catalog) -> None: + self.catalog = catalog + self.properties = catalog.extra_fields + super().__init__(catalog) + + +class CollectionCustomExtension(CustomExtension[pystac.Collection]): + def __init__(self, collection: pystac.Collection) -> None: + self.catalog = collection + self.properties = collection.extra_fields + super().__init__(collection) + + +class ItemCustomExtension(CustomExtension[pystac.Item]): + def __init__(self, item: pystac.Item) -> None: + self.catalog = item + self.properties = item.properties + super().__init__(item) + + +class AssetCustomExtension(CustomExtension[pystac.Asset]): + def __init__(self, asset: pystac.Asset) -> None: + self.catalog = asset + self.properties = asset.properties + if asset.owner: + if isinstance(asset.owner, pystac.Item): + self.additional_read_properties = [asset.owner.properties] + elif isinstance(asset.owner, pystac.Collection): + self.additional_read_properties = [asset.owner.extra_fields] + super().__init__(None) + + +class SummariesCustomExtension(SummariesExtension): + @property + def test_prop(self) -> Optional[RangeSummary[str]]: + return self.summaries.get_range(TEST_PROP, str) + + @test_prop.setter + def test_prop(self, v: Optional[RangeSummary[str]]) -> None: + self._set_summary(TEST_PROP, v) + + +class CustomExtensionHooks(ExtensionHooks): + schema_uri: str = SCHEMA_URI + prev_extension_ids: Set[str] = set( + ["custom", "https://example.com/v1.0/custom-schema.json"] + ) + stac_object_types: Set[pystac.STACObjectType] = set( + [ + pystac.STACObjectType.CATALOG, + pystac.STACObjectType.COLLECTION, + pystac.STACObjectType.ITEM, + ] + ) + + def get_object_links(self, obj: pystac.STACObject) -> Optional[List[str]]: + return [TEST_LINK_REL] + + def migrate( + self, obj: Dict[str, Any], version: STACVersionID, info: STACJSONDescription + ) -> None: + if version < "1.0.0-rc2" and info.object_type == pystac.STACObjectType.ITEM: + if "test:old-prop-name" in obj["properties"]: + obj["properties"][TEST_PROP] = obj["properties"]["test:old-prop-name"] + super().migrate(obj, version, info) + + +class CustomExtensionTest(unittest.TestCase): + def setUp(self): + pystac.EXTENSION_HOOKS.add_extension_hooks(CustomExtensionHooks()) + + def tearDown(self) -> None: + pystac.EXTENSION_HOOKS.remove_extension_hooks(SCHEMA_URI) + + # TODO: Test custom extensions and extension hooks + + def test_migrates(self): + pass diff --git a/tests/extensions/test_eo.py b/tests/extensions/test_eo.py index ff012ddc1..0fe73ab10 100644 --- a/tests/extensions/test_eo.py +++ b/tests/extensions/test_eo.py @@ -3,13 +3,18 @@ import pystac from pystac import Item -from pystac.extensions.eo import Band -from tests.utils import (TestCases, test_to_from_dict) +from pystac.collection import RangeSummary +from pystac.utils import get_opt +from pystac.extensions.eo import EOExtension, Band +from tests.utils import TestCases, test_to_from_dict class EOTest(unittest.TestCase): - LANDSAT_EXAMPLE_URI = TestCases.get_path('data-files/eo/eo-landsat-example.json') - BANDS_IN_ITEM_URI = TestCases.get_path('data-files/eo/sample-bands-in-item-properties.json') + LANDSAT_EXAMPLE_URI = TestCases.get_path("data-files/eo/eo-landsat-example.json") + BANDS_IN_ITEM_URI = TestCases.get_path( + "data-files/eo/sample-bands-in-item-properties.json" + ) + EO_COLLECTION_URI = TestCases.get_path("data-files/eo/eo-collection.json") def setUp(self): self.maxDiff = None @@ -26,12 +31,15 @@ def test_validate_eo(self): item2.validate() def test_bands(self): - eo_item = pystac.read_file(self.BANDS_IN_ITEM_URI) + item = pystac.Item.from_file(self.BANDS_IN_ITEM_URI) # Get - self.assertIn("eo:bands", eo_item.properties) - bands = eo_item.ext.eo.bands - self.assertEqual(list(map(lambda x: x.name, bands)), ['band1', 'band2', 'band3', 'band4']) + self.assertIn("eo:bands", item.properties) + bands = EOExtension.ext(item).bands + assert bands is not None + self.assertEqual( + list(map(lambda x: x.name, bands)), ["band1", "band2", "band3", "band4"] + ) # Set new_bands = [ @@ -40,41 +48,43 @@ def test_bands(self): Band.create(name="blue", description=Band.band_description("blue")), ] - eo_item.ext.eo.bands = new_bands - self.assertEqual('Common name: red, Range: 0.6 to 0.7', - eo_item.properties['eo:bands'][0]['description']) - self.assertEqual(len(eo_item.ext.eo.bands), 3) - eo_item.validate() + EOExtension.ext(item).bands = new_bands + self.assertEqual( + "Common name: red, Range: 0.6 to 0.7", + item.properties["eo:bands"][0]["description"], + ) + self.assertEqual(len(EOExtension.ext(item).bands or []), 3) + item.validate() def test_asset_bands(self): - eo_item = pystac.read_file(self.LANDSAT_EXAMPLE_URI) + item = pystac.Item.from_file(self.LANDSAT_EXAMPLE_URI) # Get - b1_asset = eo_item.assets['B1'] - asset_bands = eo_item.ext.eo.get_bands(b1_asset) - self.assertIsNot(None, asset_bands) + b1_asset = item.assets["B1"] + asset_bands = EOExtension.ext(b1_asset).bands + assert asset_bands is not None self.assertEqual(len(asset_bands), 1) - self.assertEqual(asset_bands[0].name, 'B1') + self.assertEqual(asset_bands[0].name, "B1") - index_asset = eo_item.assets['index'] - asset_bands = eo_item.ext.eo.get_bands(index_asset) + index_asset = item.assets["index"] + asset_bands = EOExtension.ext(index_asset).bands self.assertIs(None, asset_bands) # No asset specified - asset_bands = eo_item.ext.eo.get_bands() - self.assertIsNot(None, asset_bands) + item_bands = EOExtension.ext(item).bands + self.assertIsNot(None, item_bands) # Set - b2_asset = eo_item.assets['B2'] - self.assertEqual(eo_item.ext.eo.get_bands(b2_asset)[0].name, "B2") - eo_item.ext.eo.set_bands(eo_item.ext.eo.get_bands(b1_asset), b2_asset) + b2_asset = item.assets["B2"] + self.assertEqual(get_opt(EOExtension.ext(b2_asset).bands)[0].name, "B2") + EOExtension.ext(b2_asset).bands = EOExtension.ext(b1_asset).bands - new_b2_asset_bands = eo_item.ext.eo.get_bands(eo_item.assets['B2']) + new_b2_asset_bands = EOExtension.ext(item.assets["B2"]).bands - self.assertEqual(new_b2_asset_bands[0].name, 'B1') + self.assertEqual(get_opt(new_b2_asset_bands)[0].name, "B1") - eo_item.validate() + item.validate() # Check adding a new asset new_bands = [ @@ -83,57 +93,88 @@ def test_asset_bands(self): Band.create(name="blue", description=Band.band_description("blue")), ] asset = pystac.Asset(href="some/path.tif", media_type=pystac.MediaType.GEOTIFF) - eo_item.ext.eo.set_bands(new_bands, asset) - eo_item.add_asset("test", asset) + EOExtension.ext(asset).bands = new_bands + item.add_asset("test", asset) - self.assertEqual(len(eo_item.assets["test"].properties["eo:bands"]), 3) + self.assertEqual(len(item.assets["test"].properties["eo:bands"]), 3) def test_cloud_cover(self): - item = pystac.read_file(self.LANDSAT_EXAMPLE_URI) + item = pystac.Item.from_file(self.LANDSAT_EXAMPLE_URI) # Get self.assertIn("eo:cloud_cover", item.properties) - cloud_cover = item.ext.eo.cloud_cover + cloud_cover = EOExtension.ext(item).cloud_cover self.assertEqual(cloud_cover, 78) # Set - item.ext.eo.cloud_cover = 50 - self.assertEqual(item.properties['eo:cloud_cover'], 50) + EOExtension.ext(item).cloud_cover = 50 + self.assertEqual(item.properties["eo:cloud_cover"], 50) # Get from Asset - b2_asset = item.assets['B2'] - self.assertEqual(item.ext.eo.get_cloud_cover(b2_asset), item.ext.eo.get_cloud_cover()) + b2_asset = item.assets["B2"] + self.assertEqual( + EOExtension.ext(b2_asset).cloud_cover, EOExtension.ext(item).cloud_cover + ) - b3_asset = item.assets['B3'] - self.assertEqual(item.ext.eo.get_cloud_cover(b3_asset), 20) + b3_asset = item.assets["B3"] + self.assertEqual(EOExtension.ext(b3_asset).cloud_cover, 20) # Set on Asset - item.ext.eo.set_cloud_cover(10, b2_asset) - self.assertEqual(item.ext.eo.get_cloud_cover(b2_asset), 10) + EOExtension.ext(b2_asset).cloud_cover = 10 + self.assertEqual(EOExtension.ext(b2_asset).cloud_cover, 10) item.validate() + def test_summaries(self): + col = pystac.Collection.from_file(self.EO_COLLECTION_URI) + eo_summaries = EOExtension.summaries(col) + + # Get + + cloud_cover_summaries = eo_summaries.cloud_cover + self.assertEqual(cloud_cover_summaries.minimum, 0.0) + self.assertEqual(cloud_cover_summaries.maximum, 80.0) + + bands = eo_summaries.bands + assert bands is not None + self.assertEqual(len(bands), 11) + + # Set + + eo_summaries.cloud_cover = RangeSummary(1.0, 2.0) + eo_summaries.bands = [Band.create(name="test")] + + col_dict = col.to_dict() + self.assertEqual(len(col_dict["summaries"]["eo:bands"]), 1) + self.assertEqual(col_dict["summaries"]["eo:cloud_cover"]["minimum"], 1.0) + def test_read_pre_09_fields_into_common_metadata(self): - eo_item = pystac.read_file( - TestCases.get_path('data-files/examples/0.8.1/item-spec/examples/' - 'landsat8-sample.json')) + eo_item = pystac.Item.from_file( + TestCases.get_path( + "data-files/examples/0.8.1/item-spec/examples/" "landsat8-sample.json" + ) + ) self.assertEqual(eo_item.common_metadata.platform, "landsat-8") self.assertEqual(eo_item.common_metadata.instruments, ["oli_tirs"]) def test_reads_asset_bands_in_pre_1_0_version(self): - eo_item = pystac.read_file( - TestCases.get_path('data-files/examples/0.9.0/item-spec/examples/' - 'landsat8-sample.json')) + item = pystac.Item.from_file( + TestCases.get_path( + "data-files/examples/0.9.0/item-spec/examples/" "landsat8-sample.json" + ) + ) - bands = eo_item.ext.eo.get_bands(eo_item.assets['B9']) + bands = EOExtension.ext(item.assets["B9"]).bands - self.assertEqual(len(bands), 1) - self.assertEqual(bands[0].common_name, 'cirrus') + self.assertEqual(len(bands or []), 1) + self.assertEqual(get_opt(bands)[0].common_name, "cirrus") def test_reads_gsd_in_pre_1_0_version(self): - eo_item = pystac.read_file( - TestCases.get_path('data-files/examples/0.9.0/item-spec/examples/' - 'landsat8-sample.json')) + eo_item = pystac.Item.from_file( + TestCases.get_path( + "data-files/examples/0.9.0/item-spec/examples/" "landsat8-sample.json" + ) + ) self.assertEqual(eo_item.common_metadata.gsd, 30.0) diff --git a/tests/extensions/test_extensions.py b/tests/extensions/test_extensions.py deleted file mode 100644 index cbb32b10f..000000000 --- a/tests/extensions/test_extensions.py +++ /dev/null @@ -1,100 +0,0 @@ -import unittest - -import pystac -from pystac import (Catalog, Collection, Item) -from pystac.extensions.base import (CatalogExtension, CollectionExtension, ItemExtension, - ExtensionDefinition, ExtendedObject, ExtensionError) -from pystac.stac_object import ExtensionIndex - -from tests.utils import TestCases - - -class TestCatalogExt(CatalogExtension): - def __init__(self, cat): - self.cat = cat - - @property - def test_id(self): - return self.cat.id - - @classmethod - def from_catalog(cls, cat): - return TestCatalogExt(cat) - - @classmethod - def _object_links(cls): - return [] - - -class TestCollectionExt(CollectionExtension): - def __init__(self, col): - self.col = col - - @property - def xmin(self): - return self.col.extent.spatial.bboxes[0][0] - - @classmethod - def from_collection(cls, col): - return TestCollectionExt(col) - - @classmethod - def _object_links(cls): - return [] - - -class TestItemExt(ItemExtension): - def __init__(self, item): - self.item = item - - @property - def asset_keys(self): - return set(self.item.assets) - - @classmethod - def from_item(cls, item): - return TestItemExt(item) - - @classmethod - def _object_links(cls): - return [] - - -class ExtensionsTest(unittest.TestCase): - def test_can_add_custom_extension(self): - prev_extensions = pystac.STAC_EXTENSIONS.get_registered_extensions() - - pystac.STAC_EXTENSIONS.add_extension( - ExtensionDefinition("test", [ - ExtendedObject(Catalog, TestCatalogExt), - ExtendedObject(Collection, TestCollectionExt), - ExtendedObject(Item, TestItemExt) - ])) - - try: - cat = TestCases.test_case_2() - col = cat.get_child('1a8c1632-fa91-4a62-b33e-3a87c2ebdf16') - item = next(cat.get_all_items()) - - cat.ext.enable("test") - col.ext.enable("test") - item.ext.enable("test") - - self.assertEqual(cat.ext.test.test_id, cat.id) - self.assertEqual(col.ext.test.xmin, col.extent.spatial.bboxes[0][0]) - self.assertEqual(item.ext.test.asset_keys, set(item.assets)) - - finally: - pystac.STAC_EXTENSIONS.remove_extension("test") - - self.assertFalse(pystac.STAC_EXTENSIONS.is_registered_extension("test")) - self.assertEqual(pystac.STAC_EXTENSIONS.get_registered_extensions(), prev_extensions) - - def test_getattribute_overload(self): - catalog = Catalog(id='test', description='test') - self.assertEqual(ExtensionIndex.__name__, 'ExtensionIndex') - self.assertRaises(ExtensionError, catalog.ext.__getattr__, 'foo') - self.assertRaises(ExtensionError, catalog.ext.__getattr__, 'eo') - catalog.ext.enable('single-file-stac') - self.assertTrue(catalog.ext.__getattr__('single-file-stac'), - pystac.extensions.single_file_stac.SingleFileSTACCatalogExt) diff --git a/tests/extensions/test_file.py b/tests/extensions/test_file.py index c6c014e5c..b0952ecf0 100644 --- a/tests/extensions/test_file.py +++ b/tests/extensions/test_file.py @@ -2,13 +2,12 @@ import unittest import pystac -from pystac import Item -from tests.utils import (TestCases, test_to_from_dict) -from pystac.extensions.file import FileDataType +from tests.utils import TestCases, test_to_from_dict +from pystac.extensions.file import FileExtension, FileDataType class FileTest(unittest.TestCase): - FILE_EXAMPLE_URI = TestCases.get_path('data-files/file/file-example.json') + FILE_EXAMPLE_URI = TestCases.get_path("data-files/file/file-example.json") def setUp(self): self.maxDiff = None @@ -16,61 +15,76 @@ def setUp(self): def test_to_from_dict(self): with open(self.FILE_EXAMPLE_URI) as f: item_dict = json.load(f) - test_to_from_dict(self, Item, item_dict) + test_to_from_dict(self, pystac.Item, item_dict) def test_validate_file(self): - item = pystac.read_file(self.FILE_EXAMPLE_URI) + item = pystac.Item.from_file(self.FILE_EXAMPLE_URI) item.validate() def test_asset_size(self): - item = pystac.read_file(self.FILE_EXAMPLE_URI) + item = pystac.Item.from_file(self.FILE_EXAMPLE_URI) asset = item.assets["thumbnail"] # Get - self.assertEqual(146484, item.ext.file.get_size(asset)) + self.assertEqual(146484, FileExtension.ext(asset).size) # Set new_size = 1 - item.ext.file.set_size(new_size, asset) - self.assertEqual(new_size, item.ext.file.get_size(asset)) + FileExtension.ext(asset).size = new_size + self.assertEqual(new_size, FileExtension.ext(asset).size) item.validate() def test_asset_checksum(self): - item = pystac.read_file(self.FILE_EXAMPLE_URI) + item = pystac.Item.from_file(self.FILE_EXAMPLE_URI) asset = item.assets["thumbnail"] # Get - self.assertEqual("90e40210f52acd32b09769d3b1871b420789456c", - item.ext.file.get_checksum(asset)) + self.assertEqual( + "90e40210f52acd32b09769d3b1871b420789456c", + FileExtension.ext(asset).checksum, + ) # Set new_checksum = "90e40210163700a8a6501eccd00b6d3b44ddaed0" - item.ext.file.set_checksum(new_checksum, asset) - self.assertEqual(new_checksum, item.ext.file.get_checksum(asset)) + FileExtension.ext(asset).checksum = new_checksum + self.assertEqual(new_checksum, FileExtension.ext(asset).checksum) item.validate() def test_asset_data_type(self): - item = pystac.read_file(self.FILE_EXAMPLE_URI) + item = pystac.Item.from_file(self.FILE_EXAMPLE_URI) asset = item.assets["thumbnail"] # Get - self.assertEqual(FileDataType.UINT8, item.ext.file.get_data_type(asset)) + self.assertEqual(FileDataType.UINT8, FileExtension.ext(asset).data_type) # Set new_data_type = FileDataType.UINT16 - item.ext.file.set_data_type(new_data_type, asset) - self.assertEqual(new_data_type, item.ext.file.get_data_type(asset)) + FileExtension.ext(asset).data_type = new_data_type + self.assertEqual(new_data_type, FileExtension.ext(asset).data_type) item.validate() def test_asset_nodata(self): - item = pystac.read_file(self.FILE_EXAMPLE_URI) + item = pystac.Item.from_file(self.FILE_EXAMPLE_URI) asset = item.assets["thumbnail"] # Get - self.assertEqual([], item.ext.file.get_nodata(asset)) + self.assertEqual([], FileExtension.ext(asset).nodata) # Set new_nodata = [-1] - item.ext.file.set_nodata(new_nodata, asset) - self.assertEqual(new_nodata, item.ext.file.get_nodata(asset)) + FileExtension.ext(asset).nodata = new_nodata + self.assertEqual(new_nodata, FileExtension.ext(asset).nodata) item.validate() + + def test_migrates_old_checksum(self): + example_path = TestCases.get_path( + "data-files/examples/1.0.0-beta.2/" + "extensions/checksum/examples/sentinel1.json" + ) + item = pystac.Item.from_file(example_path) + + self.assertTrue(FileExtension.has_extension(item)) + self.assertEqual( + FileExtension.ext(item.assets["noises"]).checksum, + "90e40210a30d1711e81a4b11ef67b28744321659", + ) diff --git a/tests/extensions/test_label.py b/tests/extensions/test_label.py index 30603b3c1..d6c08920d 100644 --- a/tests/extensions/test_label.py +++ b/tests/extensions/test_label.py @@ -4,16 +4,29 @@ from tempfile import TemporaryDirectory import pystac -from pystac import (Catalog, Item, CatalogType, STAC_IO) -from pystac.extensions import label -from tests.utils import (TestCases, test_to_from_dict) +from pystac import Catalog, Item, CatalogType +from pystac.extensions.label import ( + LabelExtension, + LabelClasses, + LabelCount, + LabelOverview, + LabelStatistics, + LabelType, +) +import pystac.validation +from pystac.utils import get_opt +from tests.utils import TestCases, test_to_from_dict class LabelTest(unittest.TestCase): def setUp(self): self.maxDiff = None - self.label_example_1_uri = TestCases.get_path('data-files/label/label-example-1.json') - self.label_example_2_uri = TestCases.get_path('data-files/label/label-example-2.json') + self.label_example_1_uri = TestCases.get_path( + "data-files/label/label-example-1.json" + ) + self.label_example_2_uri = TestCases.get_path( + "data-files/label/label-example-2.json" + ) def test_to_from_dict(self): with open(self.label_example_1_uri) as f: @@ -24,29 +37,31 @@ def test_to_from_dict(self): def test_from_file(self): label_example_1 = Item.from_file(self.label_example_1_uri) - self.assertEqual(len(label_example_1.ext.label.label_overviews[0].counts), 2) + overviews = get_opt(LabelExtension.ext(label_example_1).label_overviews) + self.assertEqual(len(get_opt(overviews[0].counts)), 2) label_example_1.validate() label_example_2 = Item.from_file(self.label_example_2_uri) - self.assertEqual(len(label_example_2.ext.label.label_overviews[0].counts), 2) + overviews2 = get_opt(LabelExtension.ext(label_example_2).label_overviews) + self.assertEqual(len(get_opt(overviews2[0].counts)), 2) label_example_2.validate() def test_from_file_pre_081(self): - d = STAC_IO.read_json(self.label_example_1_uri) + d = pystac.StacIO.default().read_json(self.label_example_1_uri) - d['stac_version'] = '0.8.0-rc1' - d['properties']['label:property'] = d['properties']['label:properties'] - d['properties'].pop('label:properties') - d['properties']['label:overview'] = d['properties']['label:overviews'] - d['properties'].pop('label:overviews') - d['properties']['label:method'] = d['properties']['label:methods'] - d['properties'].pop('label:methods') - d['properties']['label:task'] = d['properties']['label:tasks'] - d['properties'].pop('label:tasks') - label_example_1 = STAC_IO.stac_object_from_dict(d) + d["stac_version"] = "0.8.0-rc1" + d["properties"]["label:property"] = d["properties"]["label:properties"] + d["properties"].pop("label:properties") + d["properties"]["label:overview"] = d["properties"]["label:overviews"] + d["properties"].pop("label:overviews") + d["properties"]["label:method"] = d["properties"]["label:methods"] + d["properties"].pop("label:methods") + d["properties"]["label:task"] = d["properties"]["label:tasks"] + d["properties"].pop("label:tasks") + label_example_1 = pystac.Item.from_dict(d, migrate=True) - self.assertEqual(len(label_example_1.ext.label.label_tasks), 2) + self.assertEqual(len(LabelExtension.ext(label_example_1).label_tasks or []), 2) def test_get_sources(self): cat = TestCases.test_case_1() @@ -55,165 +70,196 @@ def test_get_sources(self): item_ids = set([i.id for i in items]) for li in items: - if li.ext.implements('label'): - sources = li.ext.label.get_sources() + if LabelExtension.ext(li).has_extension: + sources = list(LabelExtension.ext(li).get_sources() or []) self.assertEqual(len(sources), 1) self.assertTrue(sources[0].id in item_ids) def test_validate_label(self): with open(self.label_example_1_uri) as f: label_example_1_dict = json.load(f) - pystac.validation.validate_dict(label_example_1_dict, "ITEM") + pystac.validation.validate_dict( + label_example_1_dict, pystac.STACObjectType.ITEM + ) with TemporaryDirectory() as tmp_dir: - cat_dir = os.path.join(tmp_dir, 'catalog') + cat_dir = os.path.join(tmp_dir, "catalog") catalog = TestCases.test_case_1() catalog.normalize_and_save(cat_dir, catalog_type=CatalogType.SELF_CONTAINED) - cat_read = Catalog.from_file(os.path.join(cat_dir, 'catalog.json')) + cat_read = Catalog.from_file(os.path.join(cat_dir, "catalog.json")) label_item_read = cat_read.get_item("area-2-2-labels", recursive=True) label_item_read.validate() def test_read_label_item_owns_asset(self): - item = next(x for x in TestCases.test_case_2().get_all_items() if x.ext.implements("label")) + item = next( + x + for x in TestCases.test_case_2().get_all_items() + if LabelExtension.ext(x).has_extension + ) assert len(item.assets) > 0 for asset_key in item.assets: self.assertEqual(item.assets[asset_key].owner, item) def test_label_description(self): - label_item = pystac.read_file(self.label_example_1_uri) + label_item = pystac.Item.from_file(self.label_example_1_uri) # Get self.assertIn("label:description", label_item.properties) - label_desc = label_item.ext.label.label_description - self.assertEqual(label_desc, label_item.properties['label:description']) + label_desc = LabelExtension.ext(label_item).label_description + self.assertEqual(label_desc, label_item.properties["label:description"]) # Set - label_item.ext.label.label_description = "A detailed description" - self.assertEqual("A detailed description", label_item.properties['label:description']) + LabelExtension.ext(label_item).label_description = "A detailed description" + self.assertEqual( + "A detailed description", label_item.properties["label:description"] + ) label_item.validate() def test_label_type(self): - label_item = pystac.read_file(self.label_example_1_uri) + label_item = pystac.Item.from_file(self.label_example_1_uri) # Get self.assertIn("label:type", label_item.properties) - label_type = label_item.ext.label.label_type - self.assertEqual(label_type, label_item.properties['label:type']) + label_type = LabelExtension.ext(label_item).label_type + self.assertEqual(label_type, label_item.properties["label:type"]) # Set - label_item.ext.label.label_type = label.LabelType.RASTER - self.assertEqual(label.LabelType.RASTER, label_item.properties['label:type']) + LabelExtension.ext(label_item).label_type = LabelType.RASTER + self.assertEqual(LabelType.RASTER, label_item.properties["label:type"]) label_item.validate() def test_label_properties(self): - label_item = pystac.read_file(self.label_example_1_uri) - label_item2 = pystac.read_file(self.label_example_2_uri) + label_item = pystac.Item.from_file(self.label_example_1_uri) + label_item2 = pystac.Item.from_file(self.label_example_2_uri) # Get self.assertIn("label:properties", label_item.properties) - label_prop = label_item.ext.label.label_properties - self.assertEqual(label_prop, label_item.properties['label:properties']) - raster_label_prop = label_item2.ext.label.label_properties + label_prop = LabelExtension.ext(label_item).label_properties + self.assertEqual(label_prop, label_item.properties["label:properties"]) + raster_label_prop = LabelExtension.ext(label_item2).label_properties self.assertEqual(raster_label_prop, None) # Set - label_item.ext.label.label_properties = ["prop1", "prop2"] - self.assertEqual(["prop1", "prop2"], label_item.properties['label:properties']) + LabelExtension.ext(label_item).label_properties = ["prop1", "prop2"] + self.assertEqual(["prop1", "prop2"], label_item.properties["label:properties"]) label_item.validate() def test_label_classes(self): # Get - label_item = pystac.read_file(self.label_example_1_uri) - label_classes = label_item.ext.label.label_classes + label_item = pystac.Item.from_file(self.label_example_1_uri) + label_classes = LabelExtension.ext(label_item).label_classes - self.assertEqual(len(label_classes), 2) - self.assertEqual(label_classes[1].classes, ["three", "four"]) + self.assertEqual(len(get_opt(label_classes)), 2) + self.assertEqual(get_opt(label_classes)[1].classes, ["three", "four"]) # Set new_classes = [ - label.LabelClasses.create(name="label2", classes=["five", "six"]), - label.LabelClasses.create(name="label", classes=["seven", "eight"]) + LabelClasses.create(name="label2", classes=["five", "six"]), + LabelClasses.create(name="label", classes=["seven", "eight"]), ] - label_item.ext.label.label_classes = new_classes - self.assertEqual([ - class_name for lc in label_item.properties["label:classes"] - for class_name in lc["classes"] - ], ["five", "six", "seven", "eight"]) + LabelExtension.ext(label_item).label_classes = new_classes + self.assertEqual( + [ + class_name + for lc in label_item.properties["label:classes"] + for class_name in lc["classes"] + ], + ["five", "six", "seven", "eight"], + ) label_item.validate() def test_label_tasks(self): - label_item = pystac.read_file(self.label_example_1_uri) + label_item = pystac.Item.from_file(self.label_example_1_uri) # Get self.assertIn("label:tasks", label_item.properties) - label_prop = label_item.ext.label.label_tasks + label_prop = LabelExtension.ext(label_item).label_tasks self.assertEqual(label_prop, ["classification", "regression"]) # Set - label_item.ext.label.label_tasks = ["classification"] - self.assertEqual(["classification"], label_item.properties['label:tasks']) + LabelExtension.ext(label_item).label_tasks = ["classification"] + self.assertEqual(["classification"], label_item.properties["label:tasks"]) label_item.validate() def test_label_methods(self): - label_item = pystac.read_file(self.label_example_1_uri) + label_item = pystac.Item.from_file(self.label_example_1_uri) # Get self.assertIn("label:methods", label_item.properties) - label_prop = label_item.ext.label.label_methods + label_prop = LabelExtension.ext(label_item).label_methods self.assertEqual(label_prop, ["manual"]) # Set - label_item.ext.label.label_methods = ["manual", "automated"] - self.assertEqual(["manual", "automated"], label_item.properties['label:methods']) + LabelExtension.ext(label_item).label_methods = ["manual", "automated"] + self.assertEqual( + ["manual", "automated"], label_item.properties["label:methods"] + ) label_item.validate() def test_label_overviews(self): # Get - label_item = pystac.read_file(self.label_example_1_uri) - label_overviews = label_item.ext.label.label_overviews + label_item = pystac.Item.from_file(self.label_example_1_uri) + label_ext = LabelExtension.ext(label_item) + label_overviews = get_opt(label_ext.label_overviews) - label_item2 = pystac.read_file(self.label_example_2_uri) - label_overviews2 = label_item2.ext.label.label_overviews + label_item2 = pystac.Item.from_file(self.label_example_2_uri) + label_ext2 = LabelExtension.ext(label_item2) + label_overviews2 = get_opt(label_ext2.label_overviews) self.assertEqual(len(label_overviews), 2) self.assertEqual(label_overviews[1].property_key, "label-reg") self.assertEqual(label_overviews2[1].property_key, None) # Raster - label_counts = label_overviews[0].counts + label_counts = get_opt(label_overviews[0].counts) self.assertEqual(label_counts[1].count, 17) - label_item.ext.label.label_overviews[0].counts[1].count = 18 - self.assertEqual(label_item.properties['label:overviews'][0]['counts'][1]['count'], 18) + get_opt(label_ext.label_overviews)[0].counts[1].count = 18 + self.assertEqual( + label_item.properties["label:overviews"][0]["counts"][1]["count"], 18 + ) - label_statistics = label_overviews[1].statistics + label_statistics = get_opt(label_overviews[1].statistics) self.assertEqual(label_statistics[0].name, "mean") - label_item.ext.label.label_overviews[1].statistics[0].name = "avg" - self.assertEqual(label_item.properties['label:overviews'][1]['statistics'][0]['name'], - "avg") + get_opt(label_ext.label_overviews)[1].statistics[0].name = "avg" + self.assertEqual( + label_item.properties["label:overviews"][1]["statistics"][0]["name"], "avg" + ) # Set new_overviews = [ - label.LabelOverview.create(property_key="label2", - counts=[ - label.LabelCount.create(name="one", count=1), - label.LabelCount.create(name="two", count=1), - ]), - label.LabelOverview.create(property_key="label-reg", - statistics=[ - label.LabelStatistics.create(name="min", value=0.1), - label.LabelStatistics.create(name="max", value=1.0), - ]) + LabelOverview.create( + property_key="label2", + counts=[ + LabelCount.create(name="one", count=1), + LabelCount.create(name="two", count=1), + ], + ), + LabelOverview.create( + property_key="label-reg", + statistics=[ + LabelStatistics.create(name="min", value=0.1), + LabelStatistics.create(name="max", value=1.0), + ], + ), ] - label_item.ext.label.label_overviews = new_overviews - self.assertEqual([(count['name'], count['count']) - for count in label_item.properties["label:overviews"][0]['counts']], - [("one", 1), ("two", 1)]) - - self.assertEqual([(count['name'], count['value']) - for count in label_item.properties["label:overviews"][1]['statistics']], - [("min", 0.1), ("max", 1.0)]) + label_ext.label_overviews = new_overviews + self.assertEqual( + [ + (count["name"], count["count"]) + for count in label_item.properties["label:overviews"][0]["counts"] + ], + [("one", 1), ("two", 1)], + ) + + self.assertEqual( + [ + (count["name"], count["value"]) + for count in label_item.properties["label:overviews"][1]["statistics"] + ], + [("min", 0.1), ("max", 1.0)], + ) label_item.validate() diff --git a/tests/extensions/test_pointcloud.py b/tests/extensions/test_pointcloud.py index 22dd3db40..3a1b0d80f 100644 --- a/tests/extensions/test_pointcloud.py +++ b/tests/extensions/test_pointcloud.py @@ -1,54 +1,60 @@ import json +from typing import Any, Dict import unittest + # from copy import deepcopy import pystac -from pystac import (Item, Extensions) -from pystac.extensions import ExtensionError -from pystac.extensions.pointcloud import PointcloudSchema, PointcloudStatistic -from tests.utils import (TestCases, test_to_from_dict) +from pystac.extensions.pointcloud import ( + PointcloudExtension, + PointcloudSchema, + PointcloudStatistic, +) +from tests.utils import TestCases, test_to_from_dict class PointcloudTest(unittest.TestCase): def setUp(self): self.maxDiff = None - self.example_uri = TestCases.get_path('data-files/pointcloud/example-laz.json') + self.example_uri = TestCases.get_path("data-files/pointcloud/example-laz.json") self.example_uri_no_statistics = TestCases.get_path( - 'data-files/pointcloud/example-laz-no-statistics.json') + "data-files/pointcloud/example-laz-no-statistics.json" + ) def test_to_from_dict(self): with open(self.example_uri) as f: d = json.load(f) - test_to_from_dict(self, Item, d) + test_to_from_dict(self, pystac.Item, d) def test_apply(self): - item = next(TestCases.test_case_2().get_all_items()) - with self.assertRaises(ExtensionError): - item.ext.pointcloud - - item.ext.enable(Extensions.POINTCLOUD) - item.ext.pointcloud.apply(1000, 'lidar', 'laszip', - [PointcloudSchema({ - 'name': 'X', - 'size': 8, - 'type': 'floating' - })]) + item = next(iter(TestCases.test_case_2().get_all_items())) + + self.assertFalse(PointcloudExtension.has_extension(item)) + + PointcloudExtension.add_to(item) + PointcloudExtension.ext(item).apply( + 1000, + "lidar", + "laszip", + [PointcloudSchema({"name": "X", "size": 8, "type": "floating"})], + ) + self.assertTrue(PointcloudExtension.has_extension(item)) def test_validate_pointcloud(self): item = pystac.read_file(self.example_uri) item.validate() def test_count(self): - pc_item = pystac.read_file(self.example_uri) + pc_item = pystac.Item.from_file(self.example_uri) # Get self.assertIn("pc:count", pc_item.properties) - pc_count = pc_item.ext.pointcloud.count - self.assertEqual(pc_count, pc_item.properties['pc:count']) + pc_count = PointcloudExtension.ext(pc_item).count + self.assertEqual(pc_count, pc_item.properties["pc:count"]) # Set - pc_item.ext.pointcloud.count = pc_count + 100 - self.assertEqual(pc_count + 100, pc_item.properties['pc:count']) + PointcloudExtension.ext(pc_item).count = pc_count + 100 + self.assertEqual(pc_count + 100, pc_item.properties["pc:count"]) # Validate pc_item.validate @@ -56,98 +62,106 @@ def test_count(self): # Cannot test validation errors until the pointcloud schema.json syntax is fixed # Ensure setting bad count fails validation - # with self.assertRaises(STACValidationError): - # pc_item.ext.pointcloud.count = 'not_an_int' - # pc_item.validate() + with self.assertRaises(pystac.STACValidationError): + PointcloudExtension.ext(pc_item).count = "not_an_int" # type:ignore + pc_item.validate() def test_type(self): - pc_item = pystac.read_file(self.example_uri) + pc_item = pystac.Item.from_file(self.example_uri) # Get self.assertIn("pc:type", pc_item.properties) - pc_type = pc_item.ext.pointcloud.type - self.assertEqual(pc_type, pc_item.properties['pc:type']) + pc_type = PointcloudExtension.ext(pc_item).type + self.assertEqual(pc_type, pc_item.properties["pc:type"]) # Set - pc_item.ext.pointcloud.type = 'sonar' - self.assertEqual('sonar', pc_item.properties['pc:type']) + PointcloudExtension.ext(pc_item).type = "sonar" + self.assertEqual("sonar", pc_item.properties["pc:type"]) # Validate pc_item.validate def test_encoding(self): - pc_item = pystac.read_file(self.example_uri) + pc_item = pystac.Item.from_file(self.example_uri) # Get self.assertIn("pc:encoding", pc_item.properties) - pc_encoding = pc_item.ext.pointcloud.encoding - self.assertEqual(pc_encoding, pc_item.properties['pc:encoding']) + pc_encoding = PointcloudExtension.ext(pc_item).encoding + self.assertEqual(pc_encoding, pc_item.properties["pc:encoding"]) # Set - pc_item.ext.pointcloud.encoding = 'binary' - self.assertEqual('binary', pc_item.properties['pc:encoding']) + PointcloudExtension.ext(pc_item).encoding = "binary" + self.assertEqual("binary", pc_item.properties["pc:encoding"]) # Validate pc_item.validate def test_schemas(self): - pc_item = pystac.read_file(self.example_uri) + pc_item = pystac.Item.from_file(self.example_uri) # Get self.assertIn("pc:schemas", pc_item.properties) - pc_schemas = [s.to_dict() for s in pc_item.ext.pointcloud.schemas] - self.assertEqual(pc_schemas, pc_item.properties['pc:schemas']) + pc_schemas = [s.to_dict() for s in PointcloudExtension.ext(pc_item).schemas] + self.assertEqual(pc_schemas, pc_item.properties["pc:schemas"]) # Set - schema = [PointcloudSchema({'name': 'X', 'size': 8, 'type': 'floating'})] - pc_item.ext.pointcloud.schemas = schema - self.assertEqual([s.to_dict() for s in schema], pc_item.properties['pc:schemas']) + schema = [PointcloudSchema({"name": "X", "size": 8, "type": "floating"})] + PointcloudExtension.ext(pc_item).schemas = schema + self.assertEqual( + [s.to_dict() for s in schema], pc_item.properties["pc:schemas"] + ) # Validate pc_item.validate def test_statistics(self): - pc_item = pystac.read_file(self.example_uri) + pc_item = pystac.Item.from_file(self.example_uri) # Get self.assertIn("pc:statistics", pc_item.properties) - pc_statistics = [s.to_dict() for s in pc_item.ext.pointcloud.statistics] - self.assertEqual(pc_statistics, pc_item.properties['pc:statistics']) + pc_statistics = [ + s.to_dict() for s in PointcloudExtension.ext(pc_item).statistics + ] + self.assertEqual(pc_statistics, pc_item.properties["pc:statistics"]) # Set stats = [ - PointcloudStatistic({ - "average": 1, - "count": 1, - "maximum": 1, - "minimum": 1, - "name": "Test", - "position": 1, - "stddev": 1, - "variance": 1 - }) + PointcloudStatistic( + { + "average": 1, + "count": 1, + "maximum": 1, + "minimum": 1, + "name": "Test", + "position": 1, + "stddev": 1, + "variance": 1, + } + ) ] - pc_item.ext.pointcloud.statistics = stats - self.assertEqual([s.to_dict() for s in stats], pc_item.properties['pc:statistics']) + PointcloudExtension.ext(pc_item).statistics = stats + self.assertEqual( + [s.to_dict() for s in stats], pc_item.properties["pc:statistics"] + ) # Validate pc_item.validate def test_density(self): - pc_item = pystac.read_file(self.example_uri) + pc_item = pystac.Item.from_file(self.example_uri) # Get self.assertIn("pc:density", pc_item.properties) - pc_density = pc_item.ext.pointcloud.density - self.assertEqual(pc_density, pc_item.properties['pc:density']) + pc_density = PointcloudExtension.ext(pc_item).density + self.assertEqual(pc_density, pc_item.properties["pc:density"]) # Set density = 100 - pc_item.ext.pointcloud.density = density - self.assertEqual(density, pc_item.properties['pc:density']) + PointcloudExtension.ext(pc_item).density = density + self.assertEqual(density, pc_item.properties["pc:density"]) # Validate pc_item.validate def test_pointcloud_schema(self): - props = { + props: Dict[str, Any] = { "name": "test", "size": 8, "type": "floating", @@ -165,7 +179,7 @@ def test_pointcloud_schema(self): self.assertEqual(getattr(schema, k), val) def test_pointcloud_statistics(self): - props = { + props: Dict[str, Any] = { "average": 1, "count": 1, "maximum": 1, @@ -173,7 +187,7 @@ def test_pointcloud_statistics(self): "name": "Test", "position": 1, "stddev": 1, - "variance": 1 + "variance": 1, } stat = PointcloudStatistic(props) self.assertEqual(props, stat.properties) @@ -188,5 +202,5 @@ def test_pointcloud_statistics(self): self.assertEqual(getattr(stat, k), val) def test_statistics_accessor_when_no_stats(self): - pc_item = pystac.read_file(self.example_uri_no_statistics) - self.assertEqual(pc_item.ext.pointcloud.statistics, None) + pc_item = pystac.Item.from_file(self.example_uri_no_statistics) + self.assertEqual(PointcloudExtension.ext(pc_item).statistics, None) diff --git a/tests/extensions/test_projection.py b/tests/extensions/test_projection.py index 7e420b3bb..c77274645 100644 --- a/tests/extensions/test_projection.py +++ b/tests/extensions/test_projection.py @@ -1,12 +1,12 @@ import json +from typing import Any, Dict import unittest from copy import deepcopy import pystac -from pystac import (Item, Extensions) -from pystac.extensions import ExtensionError -from pystac.validation import STACValidationError -from tests.utils import (TestCases, test_to_from_dict) +from pystac.extensions.projection import ProjectionExtension +from pystac.utils import get_opt +from tests.utils import TestCases, test_to_from_dict WKT2 = """ GEOGCS["WGS 84", @@ -22,7 +22,8 @@ AXIS["Longitude",EAST], AUTHORITY["EPSG","4326"]] """ -PROJJSON = json.loads(""" +PROJJSON = json.loads( + """ { "$schema": "https://proj.org/schemas/v0.1/projjson.schema.json", "type": "GeographicCRS", @@ -65,301 +66,342 @@ "code": 4326 } } -""") +""" +) class ProjectionTest(unittest.TestCase): def setUp(self): self.maxDiff = None - self.example_uri = TestCases.get_path('data-files/projection/example-landsat8.json') + self.example_uri = TestCases.get_path( + "data-files/projection/example-landsat8.json" + ) def test_to_from_dict(self): with open(self.example_uri) as f: d = json.load(f) - test_to_from_dict(self, Item, d) + test_to_from_dict(self, pystac.Item, d) def test_apply(self): - item = next(TestCases.test_case_2().get_all_items()) - with self.assertRaises(ExtensionError): - item.ext.proj + item = next(iter(TestCases.test_case_2().get_all_items())) + self.assertFalse(ProjectionExtension.has_extension(item)) - item.ext.enable(Extensions.PROJECTION) - item.ext.projection.apply( + ProjectionExtension.add_to(item) + ProjectionExtension.ext(item).apply( 4326, wkt2=WKT2, projjson=PROJJSON, geometry=item.geometry, bbox=item.bbox, - centroid={ - 'lat': 0.0, - 'lon': 1.0 - }, + centroid={"lat": 0.0, "lon": 1.0}, shape=[100, 100], - transform=[30.0, 0.0, 224985.0, 0.0, -30.0, 6790215.0, 0.0, 0.0, 1.0]) + transform=[30.0, 0.0, 224985.0, 0.0, -30.0, 6790215.0, 0.0, 0.0, 1.0], + ) def test_partial_apply(self): - proj_item = pystac.read_file(self.example_uri) + proj_item = pystac.Item.from_file(self.example_uri) - proj_item.ext.projection.apply(epsg=1111) + ProjectionExtension.ext(proj_item).apply(epsg=1111) - self.assertEqual(proj_item.ext.projection.epsg, 1111) + self.assertEqual(ProjectionExtension.ext(proj_item).epsg, 1111) proj_item.validate() def test_validate_proj(self): - item = pystac.read_file(self.example_uri) + item = pystac.Item.from_file(self.example_uri) item.validate() def test_epsg(self): - proj_item = pystac.read_file(self.example_uri) + proj_item = pystac.Item.from_file(self.example_uri) # Get self.assertIn("proj:epsg", proj_item.properties) - proj_epsg = proj_item.ext.projection.epsg - self.assertEqual(proj_epsg, proj_item.properties['proj:epsg']) + proj_epsg = ProjectionExtension.ext(proj_item).epsg + self.assertEqual(proj_epsg, proj_item.properties["proj:epsg"]) # Set - proj_item.ext.projection.epsg = proj_epsg + 100 - self.assertEqual(proj_epsg + 100, proj_item.properties['proj:epsg']) + ProjectionExtension.ext(proj_item).epsg = proj_epsg + 100 + self.assertEqual(proj_epsg + 100, proj_item.properties["proj:epsg"]) # Get from Asset - asset_no_prop = proj_item.assets['B1'] - asset_prop = proj_item.assets['B8'] - self.assertEqual(proj_item.ext.projection.get_epsg(asset_no_prop), - proj_item.ext.projection.get_epsg()) - self.assertEqual(proj_item.ext.projection.get_epsg(asset_prop), 9999) + asset_no_prop = proj_item.assets["B1"] + asset_prop = proj_item.assets["B8"] + self.assertEqual( + ProjectionExtension.ext(asset_no_prop).epsg, + ProjectionExtension.ext(proj_item).epsg, + ) + self.assertEqual(ProjectionExtension.ext(asset_prop).epsg, 9999) # Set to Asset - proj_item.ext.projection.set_epsg(8888, asset_no_prop) - self.assertNotEqual(proj_item.ext.projection.get_epsg(asset_no_prop), - proj_item.ext.projection.get_epsg()) - self.assertEqual(proj_item.ext.projection.get_epsg(asset_no_prop), 8888) + ProjectionExtension.ext(asset_no_prop).epsg = 8888 + self.assertNotEqual( + ProjectionExtension.ext(asset_no_prop).epsg, + ProjectionExtension.ext(proj_item).epsg, + ) + self.assertEqual(ProjectionExtension.ext(asset_no_prop).epsg, 8888) # Validate proj_item.validate def test_wkt2(self): - proj_item = pystac.read_file(self.example_uri) + proj_item = pystac.Item.from_file(self.example_uri) # Get self.assertIn("proj:wkt2", proj_item.properties) - proj_wkt2 = proj_item.ext.projection.wkt2 - self.assertEqual(proj_wkt2, proj_item.properties['proj:wkt2']) + proj_wkt2 = ProjectionExtension.ext(proj_item).wkt2 + self.assertEqual(proj_wkt2, proj_item.properties["proj:wkt2"]) # Set - proj_item.ext.projection.wkt2 = WKT2 - self.assertEqual(WKT2, proj_item.properties['proj:wkt2']) + ProjectionExtension.ext(proj_item).wkt2 = WKT2 + self.assertEqual(WKT2, proj_item.properties["proj:wkt2"]) # Get from Asset - asset_no_prop = proj_item.assets['B1'] - asset_prop = proj_item.assets['B8'] - self.assertEqual(proj_item.ext.projection.get_wkt2(asset_no_prop), - proj_item.ext.projection.get_wkt2()) - self.assertTrue('TEST_TEXT' in proj_item.ext.projection.get_wkt2(asset_prop)) + asset_no_prop = proj_item.assets["B1"] + asset_prop = proj_item.assets["B8"] + self.assertEqual( + ProjectionExtension.ext(asset_no_prop).wkt2, + ProjectionExtension.ext(proj_item).wkt2, + ) + self.assertTrue( + "TEST_TEXT" in get_opt(ProjectionExtension.ext(asset_prop).wkt2) + ) # Set to Asset asset_value = "TEST TEXT 2" - proj_item.ext.projection.set_wkt2(asset_value, asset_no_prop) - self.assertNotEqual(proj_item.ext.projection.get_wkt2(asset_no_prop), - proj_item.ext.projection.get_wkt2()) - self.assertEqual(proj_item.ext.projection.get_wkt2(asset_no_prop), asset_value) + ProjectionExtension.ext(asset_no_prop).wkt2 = asset_value + self.assertNotEqual( + ProjectionExtension.ext(asset_no_prop).wkt2, + ProjectionExtension.ext(proj_item).wkt2, + ) + self.assertEqual(ProjectionExtension.ext(asset_no_prop).wkt2, asset_value) # Validate proj_item.validate() def test_projjson(self): - proj_item = pystac.read_file(self.example_uri) + proj_item = pystac.Item.from_file(self.example_uri) # Get self.assertIn("proj:projjson", proj_item.properties) - proj_projjson = proj_item.ext.projection.projjson - self.assertEqual(proj_projjson, proj_item.properties['proj:projjson']) + proj_projjson = ProjectionExtension.ext(proj_item).projjson + self.assertEqual(proj_projjson, proj_item.properties["proj:projjson"]) # Set - proj_item.ext.projection.projjson = PROJJSON - self.assertEqual(PROJJSON, proj_item.properties['proj:projjson']) + ProjectionExtension.ext(proj_item).projjson = PROJJSON + self.assertEqual(PROJJSON, proj_item.properties["proj:projjson"]) # Get from Asset - asset_no_prop = proj_item.assets['B1'] - asset_prop = proj_item.assets['B8'] - self.assertEqual(proj_item.ext.projection.get_projjson(asset_no_prop), - proj_item.ext.projection.get_projjson()) - self.assertEqual(proj_item.ext.projection.get_projjson(asset_prop)['id']['code'], 9999) + asset_no_prop = proj_item.assets["B1"] + asset_prop = proj_item.assets["B8"] + self.assertEqual( + ProjectionExtension.ext(asset_no_prop).projjson, + ProjectionExtension.ext(proj_item).projjson, + ) + self.assertEqual( + ProjectionExtension.ext(asset_prop).projjson["id"]["code"], 9999 + ) # Set to Asset asset_value = deepcopy(PROJJSON) - asset_value['id']['code'] = 7777 - proj_item.ext.projection.set_projjson(asset_value, asset_no_prop) - self.assertNotEqual(proj_item.ext.projection.get_projjson(asset_no_prop), - proj_item.ext.projection.get_projjson()) - self.assertEqual(proj_item.ext.projection.get_projjson(asset_no_prop)['id']['code'], 7777) + asset_value["id"]["code"] = 7777 + ProjectionExtension.ext(asset_no_prop).projjson = asset_value + self.assertNotEqual( + ProjectionExtension.ext(asset_no_prop).projjson, + ProjectionExtension.ext(proj_item).projjson, + ) + self.assertEqual( + ProjectionExtension.ext(asset_no_prop).projjson["id"]["code"], 7777 + ) # Validate proj_item.validate() # Ensure setting bad projjson fails validation - with self.assertRaises(STACValidationError): - proj_item.ext.projection.projjson = {"bad": "data"} + with self.assertRaises(pystac.STACValidationError): + ProjectionExtension.ext(proj_item).projjson = {"bad": "data"} proj_item.validate() def test_geometry(self): - proj_item = pystac.read_file(self.example_uri) + proj_item = pystac.Item.from_file(self.example_uri) # Get self.assertIn("proj:geometry", proj_item.properties) - proj_geometry = proj_item.ext.projection.geometry - self.assertEqual(proj_geometry, proj_item.properties['proj:geometry']) + proj_geometry = ProjectionExtension.ext(proj_item).geometry + self.assertEqual(proj_geometry, proj_item.properties["proj:geometry"]) # Set - proj_item.ext.projection.geometry = proj_item.geometry - self.assertEqual(proj_item.geometry, proj_item.properties['proj:geometry']) + ProjectionExtension.ext(proj_item).geometry = proj_item.geometry + self.assertEqual(proj_item.geometry, proj_item.properties["proj:geometry"]) # Get from Asset - asset_no_prop = proj_item.assets['B1'] - asset_prop = proj_item.assets['B8'] - self.assertEqual(proj_item.ext.projection.get_geometry(asset_no_prop), - proj_item.ext.projection.get_geometry()) + asset_no_prop = proj_item.assets["B1"] + asset_prop = proj_item.assets["B8"] + self.assertEqual( + ProjectionExtension.ext(asset_no_prop).geometry, + ProjectionExtension.ext(proj_item).geometry, + ) self.assertEqual( - proj_item.ext.projection.get_geometry(asset_prop)['coordinates'][0][0], [0.0, 0.0]) + ProjectionExtension.ext(asset_prop).geometry["coordinates"][0][0], + [0.0, 0.0], + ) # Set to Asset - asset_value = {'invalid': 'geom'} - proj_item.ext.projection.set_geometry(asset_value, asset_no_prop) - self.assertNotEqual(proj_item.ext.projection.get_geometry(asset_no_prop), - proj_item.ext.projection.get_geometry()) - self.assertEqual(proj_item.ext.projection.get_geometry(asset_no_prop), asset_value) + asset_value: Dict[str, Any] = {"type": "Point", "coordinates": [1.0, 2.0]} + ProjectionExtension.ext(asset_no_prop).geometry = asset_value + self.assertNotEqual( + ProjectionExtension.ext(asset_no_prop).geometry, + ProjectionExtension.ext(proj_item).geometry, + ) + self.assertEqual(ProjectionExtension.ext(asset_no_prop).geometry, asset_value) # Validate proj_item.validate() # Ensure setting bad geometry fails validation - with self.assertRaises(STACValidationError): - proj_item.ext.projection.geometry = {"bad": "data"} + with self.assertRaises(pystac.STACValidationError): + ProjectionExtension.ext(proj_item).geometry = {"bad": "data"} proj_item.validate() def test_bbox(self): - proj_item = pystac.read_file(self.example_uri) + proj_item = pystac.Item.from_file(self.example_uri) # Get self.assertIn("proj:bbox", proj_item.properties) - proj_bbox = proj_item.ext.projection.bbox - self.assertEqual(proj_bbox, proj_item.properties['proj:bbox']) + proj_bbox = ProjectionExtension.ext(proj_item).bbox + self.assertEqual(proj_bbox, proj_item.properties["proj:bbox"]) # Set - proj_item.ext.projection.bbox = [1.0, 2.0, 3.0, 4.0] - self.assertEqual(proj_item.properties['proj:bbox'], [1.0, 2.0, 3.0, 4.0]) + ProjectionExtension.ext(proj_item).bbox = [1.0, 2.0, 3.0, 4.0] + self.assertEqual(proj_item.properties["proj:bbox"], [1.0, 2.0, 3.0, 4.0]) # Get from Asset - asset_no_prop = proj_item.assets['B1'] - asset_prop = proj_item.assets['B8'] - self.assertEqual(proj_item.ext.projection.get_bbox(asset_no_prop), - proj_item.ext.projection.get_bbox()) - self.assertEqual(proj_item.ext.projection.get_bbox(asset_prop), [1.0, 2.0, 3.0, 4.0]) + asset_no_prop = proj_item.assets["B1"] + asset_prop = proj_item.assets["B8"] + self.assertEqual( + ProjectionExtension.ext(asset_no_prop).bbox, + ProjectionExtension.ext(proj_item).bbox, + ) + self.assertEqual(ProjectionExtension.ext(asset_prop).bbox, [1.0, 2.0, 3.0, 4.0]) # Set to Asset asset_value = [10.0, 20.0, 30.0, 40.0] - proj_item.ext.projection.set_bbox(asset_value, asset_no_prop) - self.assertNotEqual(proj_item.ext.projection.get_bbox(asset_no_prop), - proj_item.ext.projection.get_bbox()) - self.assertEqual(proj_item.ext.projection.get_bbox(asset_no_prop), asset_value) + ProjectionExtension.ext(asset_no_prop).bbox = asset_value + self.assertNotEqual( + ProjectionExtension.ext(asset_no_prop).bbox, + ProjectionExtension.ext(proj_item).bbox, + ) + self.assertEqual(ProjectionExtension.ext(asset_no_prop).bbox, asset_value) # Validate proj_item.validate() def test_centroid(self): - proj_item = pystac.read_file(self.example_uri) + proj_item = pystac.Item.from_file(self.example_uri) # Get self.assertIn("proj:centroid", proj_item.properties) - proj_centroid = proj_item.ext.projection.centroid - self.assertEqual(proj_centroid, proj_item.properties['proj:centroid']) + proj_centroid = ProjectionExtension.ext(proj_item).centroid + self.assertEqual(proj_centroid, proj_item.properties["proj:centroid"]) # Set - new_val = {'lat': 2.0, 'lon': 3.0} - proj_item.ext.projection.centroid = new_val - self.assertEqual(proj_item.properties['proj:centroid'], new_val) + new_val = {"lat": 2.0, "lon": 3.0} + ProjectionExtension.ext(proj_item).centroid = new_val + self.assertEqual(proj_item.properties["proj:centroid"], new_val) # Get from Asset - asset_no_prop = proj_item.assets['B1'] - asset_prop = proj_item.assets['B8'] - self.assertEqual(proj_item.ext.projection.get_centroid(asset_no_prop), - proj_item.ext.projection.get_centroid()) - self.assertEqual(proj_item.ext.projection.get_centroid(asset_prop), { - "lat": 0.5, - "lon": 0.3 - }) + asset_no_prop = proj_item.assets["B1"] + asset_prop = proj_item.assets["B8"] + self.assertEqual( + ProjectionExtension.ext(asset_no_prop).centroid, + ProjectionExtension.ext(proj_item).centroid, + ) + self.assertEqual( + ProjectionExtension.ext(asset_prop).centroid, {"lat": 0.5, "lon": 0.3} + ) # Set to Asset asset_value = {"lat": 1.5, "lon": 1.3} - proj_item.ext.projection.set_centroid(asset_value, asset_no_prop) - self.assertNotEqual(proj_item.ext.projection.get_centroid(asset_no_prop), - proj_item.ext.projection.get_centroid()) - self.assertEqual(proj_item.ext.projection.get_centroid(asset_no_prop), asset_value) + ProjectionExtension.ext(asset_no_prop).centroid = asset_value + self.assertNotEqual( + ProjectionExtension.ext(asset_no_prop).centroid, + ProjectionExtension.ext(proj_item).centroid, + ) + self.assertEqual(ProjectionExtension.ext(asset_no_prop).centroid, asset_value) # Validate proj_item.validate() # Ensure setting bad centroid fails validation - with self.assertRaises(STACValidationError): - proj_item.ext.projection.centroid = {'lat': 2.0, 'lng': 3.0} + with self.assertRaises(pystac.STACValidationError): + ProjectionExtension.ext(proj_item).centroid = {"lat": 2.0, "lng": 3.0} proj_item.validate() def test_shape(self): - proj_item = pystac.read_file(self.example_uri) + proj_item = pystac.Item.from_file(self.example_uri) # Get self.assertIn("proj:shape", proj_item.properties) - proj_shape = proj_item.ext.projection.shape - self.assertEqual(proj_shape, proj_item.properties['proj:shape']) + proj_shape = ProjectionExtension.ext(proj_item).shape + self.assertEqual(proj_shape, proj_item.properties["proj:shape"]) # Set new_val = [100, 200] - proj_item.ext.projection.shape = new_val - self.assertEqual(proj_item.properties['proj:shape'], new_val) + ProjectionExtension.ext(proj_item).shape = new_val + self.assertEqual(proj_item.properties["proj:shape"], new_val) # Get from Asset - asset_no_prop = proj_item.assets['B1'] - asset_prop = proj_item.assets['B8'] - self.assertEqual(proj_item.ext.projection.get_shape(asset_no_prop), - proj_item.ext.projection.get_shape()) - self.assertEqual(proj_item.ext.projection.get_shape(asset_prop), [16781, 16621]) + asset_no_prop = proj_item.assets["B1"] + asset_prop = proj_item.assets["B8"] + self.assertEqual( + ProjectionExtension.ext(asset_no_prop).shape, + ProjectionExtension.ext(proj_item).shape, + ) + self.assertEqual(ProjectionExtension.ext(asset_prop).shape, [16781, 16621]) # Set to Asset asset_value = [1, 2] - proj_item.ext.projection.set_shape(asset_value, asset_no_prop) - self.assertNotEqual(proj_item.ext.projection.get_shape(asset_no_prop), - proj_item.ext.projection.get_shape()) - self.assertEqual(proj_item.ext.projection.get_shape(asset_no_prop), asset_value) + ProjectionExtension.ext(asset_no_prop).shape = asset_value + self.assertNotEqual( + ProjectionExtension.ext(asset_no_prop).shape, + ProjectionExtension.ext(proj_item).shape, + ) + self.assertEqual(ProjectionExtension.ext(asset_no_prop).shape, asset_value) # Validate proj_item.validate() def test_transform(self): - proj_item = pystac.read_file(self.example_uri) + proj_item = pystac.Item.from_file(self.example_uri) # Get self.assertIn("proj:transform", proj_item.properties) - proj_transform = proj_item.ext.projection.transform - self.assertEqual(proj_transform, proj_item.properties['proj:transform']) + proj_transform = ProjectionExtension.ext(proj_item).transform + self.assertEqual(proj_transform, proj_item.properties["proj:transform"]) # Set new_val = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0] - proj_item.ext.projection.transform = new_val - self.assertEqual(proj_item.properties['proj:transform'], new_val) + ProjectionExtension.ext(proj_item).transform = new_val + self.assertEqual(proj_item.properties["proj:transform"], new_val) # Get from Asset - asset_no_prop = proj_item.assets['B1'] - asset_prop = proj_item.assets['B8'] - self.assertEqual(proj_item.ext.projection.get_transform(asset_no_prop), - proj_item.ext.projection.get_transform()) - self.assertEqual(proj_item.ext.projection.get_transform(asset_prop), - [15.0, 0.0, 224992.5, 0.0, -15.0, 6790207.5, 0.0, 0.0, 1.0]) + asset_no_prop = proj_item.assets["B1"] + asset_prop = proj_item.assets["B8"] + self.assertEqual( + ProjectionExtension.ext(asset_no_prop).transform, + ProjectionExtension.ext(proj_item).transform, + ) + self.assertEqual( + ProjectionExtension.ext(asset_prop).transform, + [15.0, 0.0, 224992.5, 0.0, -15.0, 6790207.5, 0.0, 0.0, 1.0], + ) # Set to Asset asset_value = [2.0, 4.0, 6.0, 8.0, 10.0, 12.0] - proj_item.ext.projection.set_transform(asset_value, asset_no_prop) - self.assertNotEqual(proj_item.ext.projection.get_transform(asset_no_prop), - proj_item.ext.projection.get_transform()) - self.assertEqual(proj_item.ext.projection.get_transform(asset_no_prop), asset_value) + ProjectionExtension.ext(asset_no_prop).transform = asset_value + self.assertNotEqual( + ProjectionExtension.ext(asset_no_prop).transform, + ProjectionExtension.ext(proj_item).transform, + ) + self.assertEqual(ProjectionExtension.ext(asset_no_prop).transform, asset_value) # Validate proj_item.validate() diff --git a/tests/extensions/test_sar.py b/tests/extensions/test_sar.py index 86d7f8dc8..ae3920b6b 100644 --- a/tests/extensions/test_sar.py +++ b/tests/extensions/test_sar.py @@ -6,14 +6,17 @@ import pystac from pystac.extensions import sar +from pystac.extensions.sar import SarExtension def make_item() -> pystac.Item: - asset_id = 'my/items/2011' + asset_id = "my/items/2011" start = datetime.datetime(2020, 11, 7) - item = pystac.Item(id=asset_id, geometry=None, bbox=None, datetime=start, properties={}) + item = pystac.Item( + id=asset_id, geometry=None, bbox=None, datetime=start, properties={} + ) - item.ext.enable(pystac.Extensions.SAR) + SarExtension.add_to(item) return item @@ -21,36 +24,44 @@ class SarItemExtTest(unittest.TestCase): def setUp(self): super().setUp() self.item = make_item() - self.item.ext.enable(pystac.Extensions.SAR) def test_stac_extensions(self): - self.assertEqual([pystac.Extensions.SAR], self.item.stac_extensions) + self.assertTrue(SarExtension.has_extension(self.item)) def test_required(self): - mode: str = 'Nonesense mode' + mode: str = "Nonesense mode" frequency_band: sar.FrequencyBand = sar.FrequencyBand.P - polarizations: List[sar.Polarization] = [sar.Polarization.HV, sar.Polarization.VH] - product_type: str = 'Some product' - self.item.ext.sar.apply(mode, frequency_band, polarizations, product_type) - self.assertEqual(mode, self.item.ext.sar.instrument_mode) + polarizations: List[sar.Polarization] = [ + sar.Polarization.HV, + sar.Polarization.VH, + ] + product_type: str = "Some product" + + SarExtension.ext(self.item).apply( + mode, frequency_band, polarizations, product_type + ) + self.assertEqual(mode, SarExtension.ext(self.item).instrument_mode) self.assertIn(sar.INSTRUMENT_MODE, self.item.properties) - self.assertEqual(frequency_band, self.item.ext.sar.frequency_band) + self.assertEqual(frequency_band, SarExtension.ext(self.item).frequency_band) self.assertIn(sar.FREQUENCY_BAND, self.item.properties) - self.assertEqual(polarizations, self.item.ext.sar.polarizations) + self.assertEqual(polarizations, SarExtension.ext(self.item).polarizations) self.assertIn(sar.POLARIZATIONS, self.item.properties) - self.assertEqual(product_type, self.item.ext.sar.product_type) + self.assertEqual(product_type, SarExtension.ext(self.item).product_type) self.assertIn(sar.PRODUCT_TYPE, self.item.properties) self.item.validate() def test_all(self): - mode: str = 'WV' + mode: str = "WV" frequency_band: sar.FrequencyBand = sar.FrequencyBand.KA - polarizations: List[sar.Polarization] = [sar.Polarization.VV, sar.Polarization.HH] - product_type: str = 'Some product' + polarizations: List[sar.Polarization] = [ + sar.Polarization.VV, + sar.Polarization.HH, + ] + product_type: str = "Some product" center_frequency: float = 1.2 resolution_range: float = 3.1 resolution_azimuth: float = 4.1 @@ -61,49 +72,75 @@ def test_all(self): looks_equivalent_number: float = 9.1 observation_direction: sar.ObservationDirection = sar.ObservationDirection.LEFT - self.item.ext.sar.apply(mode, frequency_band, polarizations, product_type, center_frequency, - resolution_range, resolution_azimuth, pixel_spacing_range, - pixel_spacing_azimuth, looks_range, looks_azimuth, - looks_equivalent_number, observation_direction) - - self.assertEqual(center_frequency, self.item.ext.sar.center_frequency) + SarExtension.ext(self.item).apply( + mode, + frequency_band, + polarizations, + product_type, + center_frequency, + resolution_range, + resolution_azimuth, + pixel_spacing_range, + pixel_spacing_azimuth, + looks_range, + looks_azimuth, + looks_equivalent_number, + observation_direction, + ) + + self.assertEqual(center_frequency, SarExtension.ext(self.item).center_frequency) self.assertIn(sar.CENTER_FREQUENCY, self.item.properties) - self.assertEqual(resolution_range, self.item.ext.sar.resolution_range) + self.assertEqual(resolution_range, SarExtension.ext(self.item).resolution_range) self.assertIn(sar.RESOLUTION_RANGE, self.item.properties) - self.assertEqual(resolution_azimuth, self.item.ext.sar.resolution_azimuth) + self.assertEqual( + resolution_azimuth, SarExtension.ext(self.item).resolution_azimuth + ) self.assertIn(sar.RESOLUTION_AZIMUTH, self.item.properties) - self.assertEqual(pixel_spacing_range, self.item.ext.sar.pixel_spacing_range) + self.assertEqual( + pixel_spacing_range, SarExtension.ext(self.item).pixel_spacing_range + ) self.assertIn(sar.PIXEL_SPACING_RANGE, self.item.properties) - self.assertEqual(pixel_spacing_azimuth, self.item.ext.sar.pixel_spacing_azimuth) + self.assertEqual( + pixel_spacing_azimuth, SarExtension.ext(self.item).pixel_spacing_azimuth + ) self.assertIn(sar.PIXEL_SPACING_AZIMUTH, self.item.properties) - self.assertEqual(looks_range, self.item.ext.sar.looks_range) + self.assertEqual(looks_range, SarExtension.ext(self.item).looks_range) self.assertIn(sar.LOOKS_RANGE, self.item.properties) - self.assertEqual(looks_azimuth, self.item.ext.sar.looks_azimuth) + self.assertEqual(looks_azimuth, SarExtension.ext(self.item).looks_azimuth) self.assertIn(sar.LOOKS_AZIMUTH, self.item.properties) - self.assertEqual(looks_equivalent_number, self.item.ext.sar.looks_equivalent_number) + self.assertEqual( + looks_equivalent_number, SarExtension.ext(self.item).looks_equivalent_number + ) self.assertIn(sar.LOOKS_EQUIVALENT_NUMBER, self.item.properties) - self.assertEqual(observation_direction, self.item.ext.sar.observation_direction) + self.assertEqual( + observation_direction, SarExtension.ext(self.item).observation_direction + ) self.assertIn(sar.OBSERVATION_DIRECTION, self.item.properties) self.item.validate() def test_polarization_must_be_list(self): - mode: str = 'Nonesense mode' + mode: str = "Nonesense mode" frequency_band: sar.FrequencyBand = sar.FrequencyBand.P # Skip type hint as we are passing in an incorrect polarization. polarizations = sar.Polarization.HV - product_type: str = 'Some product' + product_type: str = "Some product" with self.assertRaises(pystac.STACError): - self.item.ext.sar.apply(mode, frequency_band, polarizations, product_type) + SarExtension.ext(self.item).apply( + mode, + frequency_band, + polarizations, # type:ignore + product_type, + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/extensions/test_sat.py b/tests/extensions/test_sat.py index 9484b184e..6831f2a7a 100644 --- a/tests/extensions/test_sat.py +++ b/tests/extensions/test_sat.py @@ -1,19 +1,23 @@ """Tests for pystac.extensions.sat.""" import datetime +from typing import Any, Dict import unittest import pystac from pystac.extensions import sat +from pystac.extensions.sat import SatExtension def make_item() -> pystac.Item: """Create basic test items that are only slightly different.""" - asset_id = 'an/asset' + asset_id = "an/asset" start = datetime.datetime(2018, 1, 2) - item = pystac.Item(id=asset_id, geometry=None, bbox=None, datetime=start, properties={}) + item = pystac.Item( + id=asset_id, geometry=None, bbox=None, datetime=start, properties={} + ) - item.ext.enable(pystac.Extensions.SAT) + SatExtension.add_to(item) return item @@ -23,109 +27,97 @@ def setUp(self): self.item = make_item() def test_stac_extensions(self): - self.assertEqual([pystac.Extensions.SAT], self.item.stac_extensions) + self.assertTrue(SatExtension.has_extension(self.item)) def test_no_args_fails(self): - with self.assertRaises(pystac.STACError): - self.item.ext.sat.apply() + SatExtension.ext(self.item).apply() + with self.assertRaises(pystac.STACValidationError): + self.item.validate() def test_orbit_state(self): orbit_state = sat.OrbitState.ASCENDING - self.item.ext.sat.apply(orbit_state) - self.assertEqual(orbit_state, self.item.ext.sat.orbit_state) + SatExtension.ext(self.item).apply(orbit_state) + self.assertEqual(orbit_state, SatExtension.ext(self.item).orbit_state) self.assertNotIn(sat.RELATIVE_ORBIT, self.item.properties) - self.assertFalse(self.item.ext.sat.relative_orbit) + self.assertFalse(SatExtension.ext(self.item).relative_orbit) self.item.validate() def test_relative_orbit(self): relative_orbit = 1234 - self.item.ext.sat.apply(None, relative_orbit) - self.assertEqual(relative_orbit, self.item.ext.sat.relative_orbit) + SatExtension.ext(self.item).apply(None, relative_orbit) + self.assertEqual(relative_orbit, SatExtension.ext(self.item).relative_orbit) self.assertNotIn(sat.ORBIT_STATE, self.item.properties) - self.assertFalse(self.item.ext.sat.orbit_state) + self.assertFalse(SatExtension.ext(self.item).orbit_state) self.item.validate() def test_relative_orbit_no_negative(self): negative_relative_orbit = -2 - with self.assertRaises(pystac.STACError): - self.item.ext.sat.apply(None, negative_relative_orbit) - - self.item.ext.sat.apply(None, 123) - with self.assertRaises(pystac.STACError): - self.item.ext.sat.relative_orbit = negative_relative_orbit + SatExtension.ext(self.item).apply(None, negative_relative_orbit) + with self.assertRaises(pystac.STACValidationError): + self.item.validate() def test_both(self): orbit_state = sat.OrbitState.DESCENDING relative_orbit = 4321 - self.item.ext.sat.apply(orbit_state, relative_orbit) - self.assertEqual(orbit_state, self.item.ext.sat.orbit_state) - self.assertEqual(relative_orbit, self.item.ext.sat.relative_orbit) + SatExtension.ext(self.item).apply(orbit_state, relative_orbit) + self.assertEqual(orbit_state, SatExtension.ext(self.item).orbit_state) + self.assertEqual(relative_orbit, SatExtension.ext(self.item).relative_orbit) self.item.validate() def test_modify(self): - self.item.ext.sat.apply(sat.OrbitState.DESCENDING, 999) + SatExtension.ext(self.item).apply(sat.OrbitState.DESCENDING, 999) orbit_state = sat.OrbitState.GEOSTATIONARY - self.item.ext.sat.orbit_state = orbit_state + SatExtension.ext(self.item).orbit_state = orbit_state relative_orbit = 1000 - self.item.ext.sat.relative_orbit = relative_orbit - self.assertEqual(orbit_state, self.item.ext.sat.orbit_state) - self.assertEqual(relative_orbit, self.item.ext.sat.relative_orbit) + SatExtension.ext(self.item).relative_orbit = relative_orbit + self.assertEqual(orbit_state, SatExtension.ext(self.item).orbit_state) + self.assertEqual(relative_orbit, SatExtension.ext(self.item).relative_orbit) self.item.validate() def test_from_dict(self): orbit_state = sat.OrbitState.GEOSTATIONARY relative_orbit = 1001 - d = { - 'type': 'Feature', - 'stac_version': '1.0.0-beta.2', - 'id': 'an/asset', - 'properties': { - 'sat:orbit_state': orbit_state.value, - 'sat:relative_orbit': relative_orbit, - 'datetime': '2018-01-02T00:00:00Z' + d: Dict[str, Any] = { + "type": "Feature", + "stac_version": "1.0.0-beta.2", + "id": "an/asset", + "properties": { + "sat:orbit_state": orbit_state.value, + "sat:relative_orbit": relative_orbit, + "datetime": "2018-01-02T00:00:00Z", }, - 'geometry': None, - 'links': [], - 'assets': {}, - 'stac_extensions': ['sat'] + "geometry": None, + "links": [], + "assets": {}, + "stac_extensions": ["sat"], } item = pystac.Item.from_dict(d) - self.assertEqual(orbit_state, item.ext.sat.orbit_state) - self.assertEqual(relative_orbit, item.ext.sat.relative_orbit) + self.assertEqual(orbit_state, SatExtension.ext(item).orbit_state) + self.assertEqual(relative_orbit, SatExtension.ext(item).relative_orbit) def test_to_from_dict(self): orbit_state = sat.OrbitState.GEOSTATIONARY relative_orbit = 1002 - self.item.ext.sat.apply(orbit_state, relative_orbit) + SatExtension.ext(self.item).apply(orbit_state, relative_orbit) d = self.item.to_dict() - self.assertEqual(orbit_state.value, d['properties'][sat.ORBIT_STATE]) - self.assertEqual(relative_orbit, d['properties'][sat.RELATIVE_ORBIT]) + self.assertEqual(orbit_state.value, d["properties"][sat.ORBIT_STATE]) + self.assertEqual(relative_orbit, d["properties"][sat.RELATIVE_ORBIT]) item = pystac.Item.from_dict(d) - self.assertEqual(orbit_state, item.ext.sat.orbit_state) - self.assertEqual(relative_orbit, item.ext.sat.relative_orbit) + self.assertEqual(orbit_state, SatExtension.ext(item).orbit_state) + self.assertEqual(relative_orbit, SatExtension.ext(item).relative_orbit) def test_clear_orbit_state(self): - self.item.ext.sat.apply(sat.OrbitState.DESCENDING, 999) + SatExtension.ext(self.item).apply(sat.OrbitState.DESCENDING, 999) - self.item.ext.sat.orbit_state = None - self.assertIsNone(self.item.ext.sat.orbit_state) + SatExtension.ext(self.item).orbit_state = None + self.assertIsNone(SatExtension.ext(self.item).orbit_state) self.item.validate() def test_clear_relative_orbit(self): - self.item.ext.sat.apply(sat.OrbitState.DESCENDING, 999) + SatExtension.ext(self.item).apply(sat.OrbitState.DESCENDING, 999) - self.item.ext.sat.relative_orbit = None - self.assertIsNone(self.item.ext.sat.relative_orbit) + SatExtension.ext(self.item).relative_orbit = None + self.assertIsNone(SatExtension.ext(self.item).relative_orbit) self.item.validate() - - def test_clear_orbit_state_fail(self): - self.item.ext.sat.apply(sat.OrbitState.DESCENDING) - with self.assertRaises(pystac.STACError): - self.item.ext.sat.orbit_state = None - - def test_clear_orbit_relative_orbit(self): - self.item.ext.sat.apply(None, 1) - with self.assertRaises(pystac.STACError): - self.item.ext.sat.relative_orbit = None diff --git a/tests/extensions/test_scientific.py b/tests/extensions/test_scientific.py index be32f7741..e0dc57cc9 100644 --- a/tests/extensions/test_scientific.py +++ b/tests/extensions/test_scientific.py @@ -5,49 +5,51 @@ import pystac from pystac.extensions import scientific +from pystac.extensions.scientific import ScientificExtension -URL_TEMPLATE = 'http://example.com/catalog/%s.json' +URL_TEMPLATE = "http://example.com/catalog/%s.json" -DOI_BASE_URL = 'https://doi.org/' +DOI_BASE_URL = "https://doi.org/" -DOI = '10.5061/dryad.s2v81.2' +DOI = "10.5061/dryad.s2v81.2" DOI_URL = DOI_BASE_URL + DOI -CITATION = 'Some citation string' +CITATION = "Some citation string" -PUB1_DOI = '10.1234/first' +PUB1_DOI = "10.1234/first" PUB1_DOI_URL = DOI_BASE_URL + PUB1_DOI -PUB2_DOI = '10.2345/second' +PUB2_DOI = "10.2345/second" PUB2_DOI_URL = DOI_BASE_URL + PUB2_DOI PUBLICATIONS = [ - scientific.Publication(PUB1_DOI, 'First citation.'), - scientific.Publication(PUB2_DOI, 'Second citation.') + scientific.Publication(PUB1_DOI, "First citation."), + scientific.Publication(PUB2_DOI, "Second citation."), ] def make_item() -> pystac.Item: - asset_id = 'USGS/GAP/CONUS/2011' + asset_id = "USGS/GAP/CONUS/2011" start = datetime.datetime(2011, 1, 2) - item = pystac.Item(id=asset_id, geometry=None, bbox=None, datetime=start, properties={}) + item = pystac.Item( + id=asset_id, geometry=None, bbox=None, datetime=start, properties={} + ) item.set_self_href(URL_TEMPLATE % 2011) - item.ext.enable(pystac.Extensions.SCIENTIFIC) + ScientificExtension.add_to(item) return item -class ScientificItemExtTest(unittest.TestCase): +class ItemScientificExtensionTest(unittest.TestCase): def setUp(self): super().setUp() self.item = make_item() - self.item.ext.enable(pystac.Extensions.SCIENTIFIC) def test_stac_extensions(self): - self.assertEqual([pystac.Extensions.SCIENTIFIC], self.item.stac_extensions) + self.assertTrue(ScientificExtension.has_extension(self.item)) def test_doi(self): - self.item.ext.scientific.apply(DOI) - self.assertEqual(DOI, self.item.ext.scientific.doi) + ScientificExtension.ext(self.item).apply(DOI) + self.assertEqual(DOI, ScientificExtension.ext(self.item).doi) self.assertIn(scientific.DOI, self.item.properties) link = self.item.get_links(scientific.CITE_AS)[0] self.assertEqual(DOI_URL, link.get_href()) @@ -56,29 +58,29 @@ def test_doi(self): # Check that setting the doi does not cause extra links. # Same doi. - self.item.ext.scientific.doi = DOI + ScientificExtension.ext(self.item).doi = DOI self.assertEqual(1, len(self.item.get_links(scientific.CITE_AS))) self.item.validate() # Different doi. - self.item.ext.scientific.doi = PUB1_DOI + ScientificExtension.ext(self.item).doi = PUB1_DOI self.assertEqual(1, len(self.item.get_links(scientific.CITE_AS))) link = self.item.get_links(scientific.CITE_AS)[0] self.assertEqual(PUB1_DOI_URL, link.get_href()) self.item.validate() def test_citation(self): - self.item.ext.scientific.apply(citation=CITATION) - self.assertEqual(CITATION, self.item.ext.scientific.citation) + ScientificExtension.ext(self.item).apply(citation=CITATION) + self.assertEqual(CITATION, ScientificExtension.ext(self.item).citation) self.assertIn(scientific.CITATION, self.item.properties) self.assertFalse(self.item.get_links(scientific.CITE_AS)) self.item.validate() def test_publications_one(self): publications = PUBLICATIONS[:1] - self.item.ext.scientific.apply(publications=publications) - self.assertEqual([1], [int('1')]) - self.assertEqual(publications, self.item.ext.scientific.publications) + ScientificExtension.ext(self.item).apply(publications=publications) + self.assertEqual([1], [int("1")]) + self.assertEqual(publications, ScientificExtension.ext(self.item).publications) self.assertIn(scientific.PUBLICATIONS, self.item.properties) links = self.item.get_links(scientific.CITE_AS) @@ -88,8 +90,8 @@ def test_publications_one(self): self.item.validate() def test_publications(self): - self.item.ext.scientific.apply(publications=PUBLICATIONS) - self.assertEqual(PUBLICATIONS, self.item.ext.scientific.publications) + ScientificExtension.ext(self.item).apply(publications=PUBLICATIONS) + self.assertEqual(PUBLICATIONS, ScientificExtension.ext(self.item).publications) self.assertIn(scientific.PUBLICATIONS, self.item.properties) links = self.item.get_links(scientific.CITE_AS) @@ -100,9 +102,9 @@ def test_publications(self): def test_remove_publication_one(self): publications = PUBLICATIONS[:1] - self.item.ext.scientific.apply(DOI, publications=publications) - self.item.ext.scientific.remove_publication(publications[0]) - self.assertFalse(self.item.ext.scientific.publications) + ScientificExtension.ext(self.item).apply(DOI, publications=publications) + ScientificExtension.ext(self.item).remove_publication(publications[0]) + self.assertFalse(ScientificExtension.ext(self.item).publications) links = self.item.get_links(scientific.CITE_AS) self.assertEqual(1, len(links)) self.assertEqual(DOI_URL, links[0].target) @@ -110,61 +112,65 @@ def test_remove_publication_one(self): def test_remove_all_publications_one(self): publications = PUBLICATIONS[:1] - self.item.ext.scientific.apply(DOI, publications=publications) - self.item.ext.scientific.remove_publication() - self.assertFalse(self.item.ext.scientific.publications) + ScientificExtension.ext(self.item).apply(DOI, publications=publications) + ScientificExtension.ext(self.item).remove_publication() + self.assertFalse(ScientificExtension.ext(self.item).publications) links = self.item.get_links(scientific.CITE_AS) self.assertEqual(1, len(links)) self.assertEqual(DOI_URL, links[0].target) self.item.validate() def test_remove_publication_forward(self): - self.item.ext.scientific.apply(DOI, publications=PUBLICATIONS) + ScientificExtension.ext(self.item).apply(DOI, publications=PUBLICATIONS) - self.item.ext.scientific.remove_publication(PUBLICATIONS[0]) - self.assertEqual([PUBLICATIONS[1]], self.item.ext.scientific.publications) + ScientificExtension.ext(self.item).remove_publication(PUBLICATIONS[0]) + self.assertEqual( + [PUBLICATIONS[1]], ScientificExtension.ext(self.item).publications + ) links = self.item.get_links(scientific.CITE_AS) self.assertEqual(2, len(links)) self.assertEqual(DOI_URL, links[0].target) self.assertEqual(PUB2_DOI_URL, links[1].target) self.item.validate() - self.item.ext.scientific.remove_publication(PUBLICATIONS[1]) - self.assertFalse(self.item.ext.scientific.publications) + ScientificExtension.ext(self.item).remove_publication(PUBLICATIONS[1]) + self.assertFalse(ScientificExtension.ext(self.item).publications) links = self.item.get_links(scientific.CITE_AS) self.assertEqual(1, len(links)) self.assertEqual(DOI_URL, links[0].target) self.item.validate() def test_remove_publication_reverse(self): - self.item.ext.scientific.apply(DOI, publications=PUBLICATIONS) + ScientificExtension.ext(self.item).apply(DOI, publications=PUBLICATIONS) - self.item.ext.scientific.remove_publication(PUBLICATIONS[1]) - self.assertEqual([PUBLICATIONS[0]], self.item.ext.scientific.publications) + ScientificExtension.ext(self.item).remove_publication(PUBLICATIONS[1]) + self.assertEqual( + [PUBLICATIONS[0]], ScientificExtension.ext(self.item).publications + ) links = self.item.get_links(scientific.CITE_AS) self.assertEqual(2, len(links)) self.assertEqual(PUB1_DOI_URL, links[1].target) self.item.validate() - self.item.ext.scientific.remove_publication(PUBLICATIONS[0]) + ScientificExtension.ext(self.item).remove_publication(PUBLICATIONS[0]) links = self.item.get_links(scientific.CITE_AS) self.assertEqual(1, len(links)) self.assertEqual(DOI_URL, links[0].target) self.item.validate() def test_remove_all_publications_with_some(self): - self.item.ext.scientific.apply(DOI, publications=PUBLICATIONS) - self.item.ext.scientific.remove_publication() - self.assertFalse(self.item.ext.scientific.publications) + ScientificExtension.ext(self.item).apply(DOI, publications=PUBLICATIONS) + ScientificExtension.ext(self.item).remove_publication() + self.assertFalse(ScientificExtension.ext(self.item).publications) links = self.item.get_links(scientific.CITE_AS) self.assertEqual(1, len(links)) self.assertEqual(DOI_URL, links[0].target) self.item.validate() def test_remove_all_publications_with_none(self): - self.item.ext.scientific.apply(DOI) - self.item.ext.scientific.remove_publication() - self.assertFalse(self.item.ext.scientific.publications) + ScientificExtension.ext(self.item).apply(DOI) + ScientificExtension.ext(self.item).remove_publication() + self.assertFalse(ScientificExtension.ext(self.item).publications) links = self.item.get_links(scientific.CITE_AS) self.assertEqual(1, len(links)) self.assertEqual(DOI_URL, links[0].target) @@ -172,32 +178,31 @@ def test_remove_all_publications_with_none(self): def make_collection() -> pystac.Collection: - asset_id = 'my/thing' + asset_id = "my/thing" start = datetime.datetime(2018, 8, 24) end = start + datetime.timedelta(5, 4, 3, 2, 1) - bboxes = [[-180, -90, 180, 90]] + bboxes = [[-180.0, -90.0, 180.0, 90.0]] spatial_extent = pystac.SpatialExtent(bboxes) temporal_extent = pystac.TemporalExtent([[start, end]]) extent = pystac.Extent(spatial_extent, temporal_extent) - collection = pystac.Collection(asset_id, 'desc', extent) + collection = pystac.Collection(asset_id, "desc", extent) collection.set_self_href(URL_TEMPLATE % 2019) - collection.ext.enable(pystac.Extensions.SCIENTIFIC) + ScientificExtension.add_to(collection) return collection -class ScientificCollectionExtTest(unittest.TestCase): +class CollectionScientificExtensionTest(unittest.TestCase): def setUp(self): super().setUp() self.collection = make_collection() - self.collection.ext.enable(pystac.Extensions.SCIENTIFIC) def test_stac_extensions(self): - self.assertEqual([pystac.Extensions.SCIENTIFIC], self.collection.stac_extensions) + self.assertTrue(ScientificExtension.has_extension(self.collection)) def test_doi(self): - self.collection.ext.scientific.apply(DOI) - self.assertEqual(DOI, self.collection.ext.scientific.doi) + ScientificExtension.ext(self.collection).apply(DOI) + self.assertEqual(DOI, ScientificExtension.ext(self.collection).doi) self.assertIn(scientific.DOI, self.collection.extra_fields) link = self.collection.get_links(scientific.CITE_AS)[0] self.assertEqual(DOI_URL, link.get_href()) @@ -206,28 +211,30 @@ def test_doi(self): # Check that setting the doi does not cause extra links. # Same doi. - self.collection.ext.scientific.doi = DOI + ScientificExtension.ext(self.collection).doi = DOI self.assertEqual(1, len(self.collection.get_links(scientific.CITE_AS))) self.collection.validate() # Different doi. - self.collection.ext.scientific.doi = PUB1_DOI + ScientificExtension.ext(self.collection).doi = PUB1_DOI self.assertEqual(1, len(self.collection.get_links(scientific.CITE_AS))) link = self.collection.get_links(scientific.CITE_AS)[0] self.assertEqual(PUB1_DOI_URL, link.get_href()) self.collection.validate() def test_citation(self): - self.collection.ext.scientific.apply(citation=CITATION) - self.assertEqual(CITATION, self.collection.ext.scientific.citation) + ScientificExtension.ext(self.collection).apply(citation=CITATION) + self.assertEqual(CITATION, ScientificExtension.ext(self.collection).citation) self.assertIn(scientific.CITATION, self.collection.extra_fields) self.assertFalse(self.collection.get_links(scientific.CITE_AS)) self.collection.validate() def test_publications_one(self): publications = PUBLICATIONS[:1] - self.collection.ext.scientific.apply(publications=publications) - self.assertEqual(publications, self.collection.ext.scientific.publications) + ScientificExtension.ext(self.collection).apply(publications=publications) + self.assertEqual( + publications, ScientificExtension.ext(self.collection).publications + ) self.assertIn(scientific.PUBLICATIONS, self.collection.extra_fields) links = self.collection.get_links(scientific.CITE_AS) @@ -238,8 +245,10 @@ def test_publications_one(self): self.collection.validate() def test_publications(self): - self.collection.ext.scientific.apply(publications=PUBLICATIONS) - self.assertEqual(PUBLICATIONS, self.collection.ext.scientific.publications) + ScientificExtension.ext(self.collection).apply(publications=PUBLICATIONS) + self.assertEqual( + PUBLICATIONS, ScientificExtension.ext(self.collection).publications + ) self.assertIn(scientific.PUBLICATIONS, self.collection.extra_fields) links = self.collection.get_links(scientific.CITE_AS) @@ -251,9 +260,9 @@ def test_publications(self): def test_remove_publication_one(self): publications = PUBLICATIONS[:1] - self.collection.ext.scientific.apply(DOI, publications=publications) - self.collection.ext.scientific.remove_publication(publications[0]) - self.assertFalse(self.collection.ext.scientific.publications) + ScientificExtension.ext(self.collection).apply(DOI, publications=publications) + ScientificExtension.ext(self.collection).remove_publication(publications[0]) + self.assertFalse(ScientificExtension.ext(self.collection).publications) links = self.collection.get_links(scientific.CITE_AS) self.assertEqual(1, len(links)) self.assertEqual(DOI_URL, links[0].target) @@ -261,66 +270,70 @@ def test_remove_publication_one(self): def test_remove_all_publications_one(self): publications = PUBLICATIONS[:1] - self.collection.ext.scientific.apply(DOI, publications=publications) - self.collection.ext.scientific.remove_publication() - self.assertFalse(self.collection.ext.scientific.publications) + ScientificExtension.ext(self.collection).apply(DOI, publications=publications) + ScientificExtension.ext(self.collection).remove_publication() + self.assertFalse(ScientificExtension.ext(self.collection).publications) links = self.collection.get_links(scientific.CITE_AS) self.assertEqual(1, len(links)) self.assertEqual(DOI_URL, links[0].target) self.collection.validate() def test_remove_publication_forward(self): - self.collection.ext.scientific.apply(DOI, publications=PUBLICATIONS) + ScientificExtension.ext(self.collection).apply(DOI, publications=PUBLICATIONS) - self.collection.ext.scientific.remove_publication(PUBLICATIONS[0]) - self.assertEqual([PUBLICATIONS[1]], self.collection.ext.scientific.publications) + ScientificExtension.ext(self.collection).remove_publication(PUBLICATIONS[0]) + self.assertEqual( + [PUBLICATIONS[1]], ScientificExtension.ext(self.collection).publications + ) links = self.collection.get_links(scientific.CITE_AS) self.assertEqual(2, len(links)) self.assertEqual(DOI_URL, links[0].target) self.assertEqual(PUB2_DOI_URL, links[1].target) self.collection.validate() - self.collection.ext.scientific.remove_publication(PUBLICATIONS[1]) - self.assertFalse(self.collection.ext.scientific.publications) + ScientificExtension.ext(self.collection).remove_publication(PUBLICATIONS[1]) + self.assertFalse(ScientificExtension.ext(self.collection).publications) links = self.collection.get_links(scientific.CITE_AS) self.assertEqual(1, len(links)) self.assertEqual(DOI_URL, links[0].target) self.collection.validate() def test_remove_publication_reverse(self): - self.collection.ext.scientific.apply(DOI, publications=PUBLICATIONS) + ScientificExtension.ext(self.collection).apply(DOI, publications=PUBLICATIONS) - self.collection.ext.scientific.remove_publication(PUBLICATIONS[1]) - self.assertEqual([PUBLICATIONS[0]], self.collection.ext.scientific.publications) + ScientificExtension.ext(self.collection).remove_publication(PUBLICATIONS[1]) + self.assertEqual( + [PUBLICATIONS[0]], ScientificExtension.ext(self.collection).publications + ) links = self.collection.get_links(scientific.CITE_AS) self.assertEqual(2, len(links)) self.assertEqual(PUB1_DOI_URL, links[1].target) self.collection.validate() - self.collection.ext.scientific.remove_publication(PUBLICATIONS[0]) + ScientificExtension.ext(self.collection).remove_publication(PUBLICATIONS[0]) links = self.collection.get_links(scientific.CITE_AS) self.assertEqual(1, len(links)) self.assertEqual(DOI_URL, links[0].target) self.collection.validate() def test_remove_all_publications_with_some(self): - self.collection.ext.scientific.apply(DOI, publications=PUBLICATIONS) - self.collection.ext.scientific.remove_publication() - self.assertFalse(self.collection.ext.scientific.publications) + ScientificExtension.ext(self.collection).apply(DOI, publications=PUBLICATIONS) + ScientificExtension.ext(self.collection).remove_publication() + self.assertFalse(ScientificExtension.ext(self.collection).publications) links = self.collection.get_links(scientific.CITE_AS) self.assertEqual(1, len(links)) self.assertEqual(DOI_URL, links[0].target) self.collection.validate() def test_remove_all_publications_with_none(self): - self.collection.ext.scientific.apply(DOI) - self.collection.ext.scientific.remove_publication() - self.assertFalse(self.collection.ext.scientific.publications) + ScientificExtension.ext(self.collection).apply(DOI) + ScientificExtension.ext(self.collection).remove_publication() + self.assertFalse(ScientificExtension.ext(self.collection).publications) links = self.collection.get_links(scientific.CITE_AS) self.assertEqual(1, len(links)) self.assertEqual(DOI_URL, links[0].target) self.collection.validate() -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/extensions/test_single_file_stac.py b/tests/extensions/test_single_file_stac.py deleted file mode 100644 index 7ffcea05f..000000000 --- a/tests/extensions/test_single_file_stac.py +++ /dev/null @@ -1,56 +0,0 @@ -import os -import unittest -from tempfile import TemporaryDirectory -import json - -import pystac -from pystac.extensions.single_file_stac import create_single_file_stac -from tests.utils import TestCases - - -class SingleFileSTACTest(unittest.TestCase): - def setUp(self): - self.EXAMPLE_SINGLE_FILE = TestCases.get_path( - 'data-files/examples/1.0.0-beta.2/' - 'extensions/single-file-stac/examples/example-search.json') - with open(TestCases.get_path(self.EXAMPLE_SINGLE_FILE)) as f: - self.EXAMPLE_SF_DICT = json.load(f) - - def test_read_single_file_stac(self): - cat = pystac.read_file(self.EXAMPLE_SINGLE_FILE) - - cat.validate() - - features = cat.ext['single-file-stac'].features - self.assertEqual(len(features), 2) - - self.assertEqual(features[0].ext.view.sun_azimuth, 152.63804142) - - collections = cat.ext['single-file-stac'].collections - - self.assertEqual(len(collections), 1) - self.assertEqual(collections[0].license, "PDDL-1.0") - - def test_create_single_file_stac(self): - cat = TestCases.test_case_1() - sfs = create_single_file_stac(TestCases.test_case_1()) - - with TemporaryDirectory() as tmp_dir: - path = os.path.join(tmp_dir, 'single_file_stac.json') - pystac.write_file(sfs, include_self_link=False, dest_href=path) - - sfs_read = pystac.read_file(path) - - sfs_read.validate() - - self.assertTrue(sfs_read.ext.implements('single-file-stac')) - - read_fids = set([f.id for f in sfs_read.ext['single-file-stac'].features]) - expected_fids = set([f.id for f in cat.get_all_items()]) - - self.assertEqual(read_fids, expected_fids) - - read_col_ids = set([col.id for col in sfs_read.ext['single-file-stac'].collections]) - expected_col_ids = set(['area-1-1', 'area-1-2', 'area-2-1', 'area-2-2']) - - self.assertEqual(read_col_ids, expected_col_ids) diff --git a/tests/extensions/test_timestamps.py b/tests/extensions/test_timestamps.py index 7f484e477..dad6dff3f 100644 --- a/tests/extensions/test_timestamps.py +++ b/tests/extensions/test_timestamps.py @@ -1,55 +1,61 @@ import json -import pystac import unittest from datetime import datetime -from pystac import (Extensions, Item) -from pystac.extensions import ExtensionError -from pystac.utils import (str_to_datetime, datetime_to_str) -from tests.utils import (TestCases, test_to_from_dict) +import pystac +from pystac.extensions.timestamps import TimestampsExtension +from pystac.utils import get_opt, str_to_datetime, datetime_to_str +from tests.utils import TestCases, test_to_from_dict class TimestampsTest(unittest.TestCase): def setUp(self): self.maxDiff = None - self.example_uri = TestCases.get_path('data-files/timestamps/example-landsat8.json') + self.example_uri = TestCases.get_path( + "data-files/timestamps/example-landsat8.json" + ) with open(self.example_uri) as f: self.item_dict = json.load(f) self.sample_datetime_str = "2020-01-01T00:00:00Z" self.sample_datetime = str_to_datetime(self.sample_datetime_str) def test_to_from_dict(self): - test_to_from_dict(self, Item, self.item_dict) + test_to_from_dict(self, pystac.Item, self.item_dict) def test_apply(self): - item = next(TestCases.test_case_2().get_all_items()) - with self.assertRaises(ExtensionError): - item.ext.timestamps + item = next(iter(TestCases.test_case_2().get_all_items())) + self.assertFalse(TimestampsExtension.has_extension(item)) - item.ext.enable(Extensions.TIMESTAMPS) - self.assertIn(Extensions.TIMESTAMPS, item.stac_extensions) - item.ext.timestamps.apply(published=str_to_datetime("2020-01-03T06:45:55Z"), - expires=str_to_datetime("2020-02-03T06:45:55Z"), - unpublished=str_to_datetime("2020-03-03T06:45:55Z")) + TimestampsExtension.add_to(item) + self.assertTrue(TimestampsExtension.has_extension(item)) + TimestampsExtension.ext(item).apply( + published=str_to_datetime("2020-01-03T06:45:55Z"), + expires=str_to_datetime("2020-02-03T06:45:55Z"), + unpublished=str_to_datetime("2020-03-03T06:45:55Z"), + ) for d in [ - item.ext.timestamps.published, item.ext.timestamps.expires, - item.ext.timestamps.unpublished + TimestampsExtension.ext(item).published, + TimestampsExtension.ext(item).expires, + TimestampsExtension.ext(item).unpublished, ]: self.assertIsInstance(d, datetime) - for p in ('published', 'expires', 'unpublished'): + for p in ("published", "expires", "unpublished"): self.assertIsInstance(item.properties[p], str) published_str = "2020-04-03T06:45:55Z" - item.ext.timestamps.apply(published=str_to_datetime(published_str)) - self.assertIsInstance(item.ext.timestamps.published, datetime) - self.assertEqual(item.properties['published'], published_str) + TimestampsExtension.ext(item).apply(published=str_to_datetime(published_str)) + self.assertIsInstance(TimestampsExtension.ext(item).published, datetime) + self.assertEqual(item.properties["published"], published_str) - for d in [item.ext.timestamps.expires, item.ext.timestamps.unpublished]: + for d in [ + TimestampsExtension.ext(item).expires, + TimestampsExtension.ext(item).unpublished, + ]: self.assertIsNone(d) - for p in ('expires', 'unpublished'): + for p in ("expires", "unpublished"): self.assertNotIn(p, item.properties) def test_validate_timestamps(self): @@ -57,94 +63,125 @@ def test_validate_timestamps(self): item.validate() def test_expires(self): - timestamps_item = pystac.read_file(self.example_uri) + timestamps_item = pystac.Item.from_file(self.example_uri) # Get self.assertIn("expires", timestamps_item.properties) - timestamps_expires = timestamps_item.ext.timestamps.expires + timestamps_expires = TimestampsExtension.ext(timestamps_item).expires self.assertIsInstance(timestamps_expires, datetime) - self.assertEqual(datetime_to_str(timestamps_expires), timestamps_item.properties['expires']) + self.assertEqual( + datetime_to_str(get_opt(timestamps_expires)), + timestamps_item.properties["expires"], + ) # Set - timestamps_item.ext.timestamps.expires = self.sample_datetime - self.assertEqual(self.sample_datetime_str, timestamps_item.properties['expires']) + TimestampsExtension.ext(timestamps_item).expires = self.sample_datetime + self.assertEqual( + self.sample_datetime_str, timestamps_item.properties["expires"] + ) # Get from Asset - asset_no_prop = timestamps_item.assets['red'] - asset_prop = timestamps_item.assets['blue'] - self.assertEqual(timestamps_item.ext.timestamps.get_expires(asset_no_prop), - timestamps_item.ext.timestamps.get_expires()) - self.assertEqual(timestamps_item.ext.timestamps.get_expires(asset_prop), - str_to_datetime("2018-12-02T00:00:00Z")) + asset_no_prop = timestamps_item.assets["red"] + asset_prop = timestamps_item.assets["blue"] + self.assertEqual( + TimestampsExtension.ext(asset_no_prop).expires, + TimestampsExtension.ext(timestamps_item).expires, + ) + self.assertEqual( + TimestampsExtension.ext(asset_prop).expires, + str_to_datetime("2018-12-02T00:00:00Z"), + ) # # Set to Asset asset_value = str_to_datetime("2019-02-02T00:00:00Z") - timestamps_item.ext.timestamps.set_expires(asset_value, asset_no_prop) - self.assertNotEqual(timestamps_item.ext.timestamps.get_expires(asset_no_prop), - timestamps_item.ext.timestamps.get_expires()) - self.assertEqual(timestamps_item.ext.timestamps.get_expires(asset_no_prop), asset_value) + TimestampsExtension.ext(asset_no_prop).expires = asset_value + self.assertNotEqual( + TimestampsExtension.ext(asset_no_prop).expires, + TimestampsExtension.ext(timestamps_item).expires, + ) + self.assertEqual(TimestampsExtension.ext(asset_no_prop).expires, asset_value) # Validate timestamps_item.validate() def test_published(self): - timestamps_item = pystac.read_file(self.example_uri) + timestamps_item = pystac.Item.from_file(self.example_uri) # Get self.assertIn("published", timestamps_item.properties) - timestamps_published = timestamps_item.ext.timestamps.published + timestamps_published = TimestampsExtension.ext(timestamps_item).published self.assertIsInstance(timestamps_published, datetime) - self.assertEqual(datetime_to_str(timestamps_published), - timestamps_item.properties['published']) + self.assertEqual( + datetime_to_str(get_opt(timestamps_published)), + timestamps_item.properties["published"], + ) # Set - timestamps_item.ext.timestamps.published = self.sample_datetime - self.assertEqual(self.sample_datetime_str, timestamps_item.properties['published']) + TimestampsExtension.ext(timestamps_item).published = self.sample_datetime + self.assertEqual( + self.sample_datetime_str, timestamps_item.properties["published"] + ) # Get from Asset - asset_no_prop = timestamps_item.assets['red'] - asset_prop = timestamps_item.assets['blue'] - self.assertEqual(timestamps_item.ext.timestamps.get_published(asset_no_prop), - timestamps_item.ext.timestamps.get_published()) - self.assertEqual(timestamps_item.ext.timestamps.get_published(asset_prop), - str_to_datetime("2018-11-02T00:00:00Z")) + asset_no_prop = timestamps_item.assets["red"] + asset_prop = timestamps_item.assets["blue"] + self.assertEqual( + TimestampsExtension.ext(asset_no_prop).published, + TimestampsExtension.ext(timestamps_item).published, + ) + self.assertEqual( + TimestampsExtension.ext(asset_prop).published, + str_to_datetime("2018-11-02T00:00:00Z"), + ) # # Set to Asset asset_value = str_to_datetime("2019-02-02T00:00:00Z") - timestamps_item.ext.timestamps.set_published(asset_value, asset_no_prop) - self.assertNotEqual(timestamps_item.ext.timestamps.get_published(asset_no_prop), - timestamps_item.ext.timestamps.get_published()) - self.assertEqual(timestamps_item.ext.timestamps.get_published(asset_no_prop), asset_value) + TimestampsExtension.ext(asset_no_prop).published = asset_value + self.assertNotEqual( + TimestampsExtension.ext(asset_no_prop).published, + TimestampsExtension.ext(timestamps_item).published, + ) + self.assertEqual(TimestampsExtension.ext(asset_no_prop).published, asset_value) # Validate timestamps_item.validate() def test_unpublished(self): - timestamps_item = pystac.read_file(self.example_uri) + timestamps_item = pystac.Item.from_file(self.example_uri) # Get self.assertNotIn("unpublished", timestamps_item.properties) - timestamps_unpublished = timestamps_item.ext.timestamps.unpublished + timestamps_unpublished = TimestampsExtension.ext(timestamps_item).unpublished self.assertIsNone(timestamps_unpublished, datetime) # Set - timestamps_item.ext.timestamps.unpublished = self.sample_datetime - self.assertEqual(self.sample_datetime_str, timestamps_item.properties['unpublished']) + TimestampsExtension.ext(timestamps_item).unpublished = self.sample_datetime + self.assertEqual( + self.sample_datetime_str, timestamps_item.properties["unpublished"] + ) # Get from Asset - asset_no_prop = timestamps_item.assets['red'] - asset_prop = timestamps_item.assets['blue'] - self.assertEqual(timestamps_item.ext.timestamps.get_unpublished(asset_no_prop), - timestamps_item.ext.timestamps.get_unpublished()) - self.assertEqual(timestamps_item.ext.timestamps.get_unpublished(asset_prop), - str_to_datetime("2019-01-02T00:00:00Z")) + asset_no_prop = timestamps_item.assets["red"] + asset_prop = timestamps_item.assets["blue"] + self.assertEqual( + TimestampsExtension.ext(asset_no_prop).unpublished, + TimestampsExtension.ext(timestamps_item).unpublished, + ) + self.assertEqual( + TimestampsExtension.ext(asset_prop).unpublished, + str_to_datetime("2019-01-02T00:00:00Z"), + ) # Set to Asset asset_value = str_to_datetime("2019-02-02T00:00:00Z") - timestamps_item.ext.timestamps.set_unpublished(asset_value, asset_no_prop) - self.assertNotEqual(timestamps_item.ext.timestamps.get_unpublished(asset_no_prop), - timestamps_item.ext.timestamps.get_unpublished()) - self.assertEqual(timestamps_item.ext.timestamps.get_unpublished(asset_no_prop), asset_value) + TimestampsExtension.ext(asset_no_prop).unpublished = asset_value + self.assertNotEqual( + TimestampsExtension.ext(asset_no_prop).unpublished, + TimestampsExtension.ext(timestamps_item).unpublished, + ) + self.assertEqual( + TimestampsExtension.ext(asset_no_prop).unpublished, asset_value + ) # Validate timestamps_item.validate() diff --git a/tests/extensions/test_version.py b/tests/extensions/test_version.py index a0068e492..f036260e3 100644 --- a/tests/extensions/test_version.py +++ b/tests/extensions/test_version.py @@ -5,66 +5,67 @@ import pystac from pystac.extensions import version +from pystac.extensions.version import VersionExtension from tests.utils import TestCases -URL_TEMPLATE: str = 'http://example.com/catalog/%s.json' +URL_TEMPLATE: str = "http://example.com/catalog/%s.json" def make_item(year: int) -> pystac.Item: """Create basic test items that are only slightly different.""" - asset_id = f'USGS/GAP/CONUS/{year}' + asset_id = f"USGS/GAP/CONUS/{year}" start = datetime.datetime(year, 1, 2) - item = pystac.Item(id=asset_id, geometry=None, bbox=None, datetime=start, properties={}) + item = pystac.Item( + id=asset_id, geometry=None, bbox=None, datetime=start, properties={} + ) item.set_self_href(URL_TEMPLATE % year) - item.ext.enable(pystac.Extensions.VERSION) + VersionExtension.add_to(item) return item -class VersionItemExtTest(unittest.TestCase): - version: str = '1.2.3' +class ItemVersionExtensionTest(unittest.TestCase): + version: str = "1.2.3" def setUp(self): super().setUp() self.item = make_item(2011) - self.item.ext.enable(pystac.Extensions.VERSION) - def test_stac_extensions(self): - self.assertEqual([pystac.Extensions.VERSION], self.item.stac_extensions) + self.assertTrue(VersionExtension.has_extension(self.item)) def test_add_version(self): - self.item.ext.version.apply(self.version) - self.assertEqual(self.version, self.item.ext.version.version) + VersionExtension.ext(self.item).apply(self.version) + self.assertEqual(self.version, VersionExtension.ext(self.item).version) self.assertNotIn(version.DEPRECATED, self.item.properties) - self.assertFalse(self.item.ext.version.deprecated) + self.assertFalse(VersionExtension.ext(self.item).deprecated) self.item.validate() def test_version_in_properties(self): - self.item.ext.version.apply(self.version, deprecated=True) + VersionExtension.ext(self.item).apply(self.version, deprecated=True) self.assertIn(version.VERSION, self.item.properties) self.assertIn(version.DEPRECATED, self.item.properties) self.item.validate() def test_add_not_deprecated_version(self): - self.item.ext.version.apply(self.version, deprecated=False) + VersionExtension.ext(self.item).apply(self.version, deprecated=False) self.assertIn(version.DEPRECATED, self.item.properties) - self.assertFalse(self.item.ext.version.deprecated) + self.assertFalse(VersionExtension.ext(self.item).deprecated) self.item.validate() def test_add_deprecated_version(self): - self.item.ext.version.apply(self.version, deprecated=True) + VersionExtension.ext(self.item).apply(self.version, deprecated=True) self.assertIn(version.DEPRECATED, self.item.properties) - self.assertTrue(self.item.ext.version.deprecated) + self.assertTrue(VersionExtension.ext(self.item).deprecated) self.item.validate() def test_latest(self): year = 2013 latest = make_item(year) - self.item.ext.version.apply(self.version, latest=latest) - latest_result = self.item.ext.version.latest + VersionExtension.ext(self.item).apply(self.version, latest=latest) + latest_result = VersionExtension.ext(self.item).latest self.assertIs(latest, latest_result) expected_href = URL_TEMPLATE % year @@ -75,8 +76,8 @@ def test_latest(self): def test_predecessor(self): year = 2010 predecessor = make_item(year) - self.item.ext.version.apply(self.version, predecessor=predecessor) - predecessor_result = self.item.ext.version.predecessor + VersionExtension.ext(self.item).apply(self.version, predecessor=predecessor) + predecessor_result = VersionExtension.ext(self.item).predecessor self.assertIs(predecessor, predecessor_result) expected_href = URL_TEMPLATE % year @@ -87,8 +88,8 @@ def test_predecessor(self): def test_successor(self): year = 2012 successor = make_item(year) - self.item.ext.version.apply(self.version, successor=successor) - successor_result = self.item.ext.version.successor + VersionExtension.ext(self.item).apply(self.version, successor=successor) + successor_result = VersionExtension.ext(self.item).successor self.assertIs(successor, successor_result) expected_href = URL_TEMPLATE % year @@ -97,7 +98,7 @@ def test_successor(self): self.item.validate() def test_fail_validate(self): - with self.assertRaises(pystac.validation.STACValidationError): + with self.assertRaises(pystac.STACValidationError): self.item.validate() def test_all_links(self): @@ -105,30 +106,35 @@ def test_all_links(self): latest = make_item(2013) predecessor = make_item(2010) successor = make_item(2012) - self.item.ext.version.apply(self.version, deprecated, latest, predecessor, successor) + VersionExtension.ext(self.item).apply( + self.version, deprecated, latest, predecessor, successor + ) self.item.validate() def test_full_copy(self): cat = TestCases.test_case_1() # Fetch two items from the catalog - item1 = cat.get_item('area-1-1-imagery', recursive=True) - item2 = cat.get_item('area-2-2-imagery', recursive=True) + item1 = cat.get_item("area-1-1-imagery", recursive=True) + item2 = cat.get_item("area-2-2-imagery", recursive=True) + + assert item1 is not None + assert item2 is not None # Enable the version extension on each, and link them # as if they are different versions of the same Item - item1.ext.enable(pystac.Extensions.VERSION) - item2.ext.enable(pystac.Extensions.VERSION) + VersionExtension.add_to(item1) + VersionExtension.add_to(item2) - item1.ext.version.apply(version='2.0', predecessor=item2) - item2.ext.version.apply(version='1.0', successor=item1, latest=item1) + VersionExtension.ext(item1).apply(version="2.0", predecessor=item2) + VersionExtension.ext(item2).apply(version="1.0", successor=item1, latest=item1) # Make a full copy of the catalog cat_copy = cat.full_copy() # Retrieve the copied version of the items - item1_copy = cat_copy.get_item('area-1-1-imagery', recursive=True) - item2_copy = cat_copy.get_item('area-2-2-imagery', recursive=True) + item1_copy = cat_copy.get_item("area-1-1-imagery", recursive=True) + item2_copy = cat_copy.get_item("area-2-2-imagery", recursive=True) # Check to see if the version links point to the instances of the # item objects as they should. @@ -145,34 +151,38 @@ def test_setting_none_clears_link(self): latest = make_item(2013) predecessor = make_item(2010) successor = make_item(2012) - self.item.ext.version.apply(self.version, deprecated, latest, predecessor, successor) + VersionExtension.ext(self.item).apply( + self.version, deprecated, latest, predecessor, successor + ) - self.item.ext.version.latest = None + VersionExtension.ext(self.item).latest = None links = self.item.get_links(version.LATEST) self.assertEqual(0, len(links)) - self.assertIsNone(self.item.ext.version.latest) + self.assertIsNone(VersionExtension.ext(self.item).latest) - self.item.ext.version.predecessor = None + VersionExtension.ext(self.item).predecessor = None links = self.item.get_links(version.PREDECESSOR) self.assertEqual(0, len(links)) - self.assertIsNone(self.item.ext.version.predecessor) + self.assertIsNone(VersionExtension.ext(self.item).predecessor) - self.item.ext.version.successor = None + VersionExtension.ext(self.item).successor = None links = self.item.get_links(version.SUCCESSOR) self.assertEqual(0, len(links)) - self.assertIsNone(self.item.ext.version.successor) + self.assertIsNone(VersionExtension.ext(self.item).successor) def test_multiple_link_setting(self): deprecated = False latest1 = make_item(2013) predecessor1 = make_item(2010) successor1 = make_item(2012) - self.item.ext.version.apply(self.version, deprecated, latest1, predecessor1, successor1) + VersionExtension.ext(self.item).apply( + self.version, deprecated, latest1, predecessor1, successor1 + ) year = 2015 latest2 = make_item(year) expected_href = URL_TEMPLATE % year - self.item.ext.version.latest = latest2 + VersionExtension.ext(self.item).latest = latest2 links = self.item.get_links(version.LATEST) self.assertEqual(1, len(links)) self.assertEqual(expected_href, links[0].get_href()) @@ -180,7 +190,7 @@ def test_multiple_link_setting(self): year = 2009 predecessor2 = make_item(year) expected_href = URL_TEMPLATE % year - self.item.ext.version.predecessor = predecessor2 + VersionExtension.ext(self.item).predecessor = predecessor2 links = self.item.get_links(version.PREDECESSOR) self.assertEqual(1, len(links)) self.assertEqual(expected_href, links[0].get_href()) @@ -188,69 +198,69 @@ def test_multiple_link_setting(self): year = 2014 successor2 = make_item(year) expected_href = URL_TEMPLATE % year - self.item.ext.version.successor = successor2 + VersionExtension.ext(self.item).successor = successor2 links = self.item.get_links(version.SUCCESSOR) self.assertEqual(1, len(links)) self.assertEqual(expected_href, links[0].get_href()) def make_collection(year: int) -> pystac.Collection: - asset_id = f'my/collection/of/things/{year}' + asset_id = f"my/collection/of/things/{year}" start = datetime.datetime(2014, 8, 10) end = datetime.datetime(year, 1, 3, 4, 5) - bboxes = [[-180, -90, 180, 90]] + bboxes = [[-180.0, -90.0, 180.0, 90.0]] spatial_extent = pystac.SpatialExtent(bboxes) temporal_extent = pystac.TemporalExtent([[start, end]]) extent = pystac.Extent(spatial_extent, temporal_extent) - collection = pystac.Collection(asset_id, 'desc', extent) + collection = pystac.Collection(asset_id, "desc", extent) collection.set_self_href(URL_TEMPLATE % year) - collection.ext.enable(pystac.Extensions.VERSION) + VersionExtension.add_to(collection) return collection -class VersionCollectionExtTest(unittest.TestCase): - version: str = '1.2.3' +class CollectionVersionExtensionTest(unittest.TestCase): + version: str = "1.2.3" def setUp(self): super().setUp() self.collection = make_collection(2011) def test_stac_extensions(self): - self.assertEqual([pystac.Extensions.VERSION], self.collection.stac_extensions) + self.assertTrue(VersionExtension.has_extension(self.collection)) def test_add_version(self): - self.collection.ext.version.apply(self.version) - self.assertEqual(self.version, self.collection.ext.version.version) + VersionExtension.ext(self.collection).apply(self.version) + self.assertEqual(self.version, VersionExtension.ext(self.collection).version) self.assertNotIn(version.DEPRECATED, self.collection.extra_fields) - self.assertFalse(self.collection.ext.version.deprecated) + self.assertFalse(VersionExtension.ext(self.collection).deprecated) self.collection.validate() def test_version_deprecated(self): - self.collection.ext.version.apply(self.version, deprecated=True) + VersionExtension.ext(self.collection).apply(self.version, deprecated=True) self.assertIn(version.VERSION, self.collection.extra_fields) self.assertIn(version.DEPRECATED, self.collection.extra_fields) self.collection.validate() def test_add_not_deprecated_version(self): - self.collection.ext.version.apply(self.version, deprecated=False) + VersionExtension.ext(self.collection).apply(self.version, deprecated=False) self.assertIn(version.DEPRECATED, self.collection.extra_fields) - self.assertFalse(self.collection.ext.version.deprecated) + self.assertFalse(VersionExtension.ext(self.collection).deprecated) self.collection.validate() def test_add_deprecated_version(self): - self.collection.ext.version.apply(self.version, deprecated=True) + VersionExtension.ext(self.collection).apply(self.version, deprecated=True) self.assertIn(version.DEPRECATED, self.collection.extra_fields) - self.assertTrue(self.collection.ext.version.deprecated) + self.assertTrue(VersionExtension.ext(self.collection).deprecated) self.collection.validate() def test_latest(self): year = 2013 latest = make_collection(year) - self.collection.ext.version.apply(self.version, latest=latest) - latest_result = self.collection.ext.version.latest + VersionExtension.ext(self.collection).apply(self.version, latest=latest) + latest_result = VersionExtension.ext(self.collection).latest self.assertIs(latest, latest_result) expected_href = URL_TEMPLATE % year @@ -261,8 +271,10 @@ def test_latest(self): def test_predecessor(self): year = 2010 predecessor = make_collection(year) - self.collection.ext.version.apply(self.version, predecessor=predecessor) - predecessor_result = self.collection.ext.version.predecessor + VersionExtension.ext(self.collection).apply( + self.version, predecessor=predecessor + ) + predecessor_result = VersionExtension.ext(self.collection).predecessor self.assertIs(predecessor, predecessor_result) expected_href = URL_TEMPLATE % year @@ -273,8 +285,8 @@ def test_predecessor(self): def test_successor(self): year = 2012 successor = make_collection(year) - self.collection.ext.version.apply(self.version, successor=successor) - successor_result = self.collection.ext.version.successor + VersionExtension.ext(self.collection).apply(self.version, successor=successor) + successor_result = VersionExtension.ext(self.collection).successor self.assertIs(successor, successor_result) expected_href = URL_TEMPLATE % year @@ -283,7 +295,7 @@ def test_successor(self): self.collection.validate() def test_fail_validate(self): - with self.assertRaises(pystac.validation.STACValidationError): + with self.assertRaises(pystac.STACValidationError): self.collection.validate() def test_validate_all(self): @@ -291,30 +303,34 @@ def test_validate_all(self): latest = make_collection(2013) predecessor = make_collection(2010) successor = make_collection(2012) - self.collection.ext.version.apply(self.version, deprecated, latest, predecessor, successor) + VersionExtension.ext(self.collection).apply( + self.version, deprecated, latest, predecessor, successor + ) self.collection.validate() def test_full_copy(self): cat = TestCases.test_case_1() # Fetch two collections from the catalog - col1 = cat.get_child('area-1-1', recursive=True) - col2 = cat.get_child('area-2-2', recursive=True) + col1 = cat.get_child("area-1-1", recursive=True) + assert isinstance(col1, pystac.Collection) + col2 = cat.get_child("area-2-2", recursive=True) + assert isinstance(col2, pystac.Collection) # Enable the version extension on each, and link them # as if they are different versions of the same Collection - col1.ext.enable(pystac.Extensions.VERSION) - col2.ext.enable(pystac.Extensions.VERSION) + VersionExtension.add_to(col1) + VersionExtension.add_to(col2) - col1.ext.version.apply(version='2.0', predecessor=col2) - col2.ext.version.apply(version='1.0', successor=col1, latest=col1) + VersionExtension.ext(col1).apply(version="2.0", predecessor=col2) + VersionExtension.ext(col2).apply(version="1.0", successor=col1, latest=col1) # Make a full copy of the catalog cat_copy = cat.full_copy() # Retrieve the copied version of the items - col1_copy = cat_copy.get_child('area-1-1', recursive=True) - col2_copy = cat_copy.get_child('area-2-2', recursive=True) + col1_copy = cat_copy.get_child("area-1-1", recursive=True) + col2_copy = cat_copy.get_child("area-2-2", recursive=True) # Check to see if the version links point to the instances of the # col objects as they should. @@ -331,35 +347,38 @@ def test_setting_none_clears_link(self): latest = make_collection(2013) predecessor = make_collection(2010) successor = make_collection(2012) - self.collection.ext.version.apply(self.version, deprecated, latest, predecessor, successor) + VersionExtension.ext(self.collection).apply( + self.version, deprecated, latest, predecessor, successor + ) - self.collection.ext.version.latest = None + VersionExtension.ext(self.collection).latest = None links = self.collection.get_links(version.LATEST) self.assertEqual(0, len(links)) - self.assertIsNone(self.collection.ext.version.latest) + self.assertIsNone(VersionExtension.ext(self.collection).latest) - self.collection.ext.version.predecessor = None + VersionExtension.ext(self.collection).predecessor = None links = self.collection.get_links(version.PREDECESSOR) self.assertEqual(0, len(links)) - self.assertIsNone(self.collection.ext.version.predecessor) + self.assertIsNone(VersionExtension.ext(self.collection).predecessor) - self.collection.ext.version.successor = None + VersionExtension.ext(self.collection).successor = None links = self.collection.get_links(version.SUCCESSOR) self.assertEqual(0, len(links)) - self.assertIsNone(self.collection.ext.version.successor) + self.assertIsNone(VersionExtension.ext(self.collection).successor) def test_multiple_link_setting(self): deprecated = False latest1 = make_collection(2013) predecessor1 = make_collection(2010) successor1 = make_collection(2012) - self.collection.ext.version.apply(self.version, deprecated, latest1, predecessor1, - successor1) + VersionExtension.ext(self.collection).apply( + self.version, deprecated, latest1, predecessor1, successor1 + ) year = 2015 latest2 = make_collection(year) expected_href = URL_TEMPLATE % year - self.collection.ext.version.latest = latest2 + VersionExtension.ext(self.collection).latest = latest2 links = self.collection.get_links(version.LATEST) self.assertEqual(1, len(links)) self.assertEqual(expected_href, links[0].get_href()) @@ -367,7 +386,7 @@ def test_multiple_link_setting(self): year = 2009 predecessor2 = make_collection(year) expected_href = URL_TEMPLATE % year - self.collection.ext.version.predecessor = predecessor2 + VersionExtension.ext(self.collection).predecessor = predecessor2 links = self.collection.get_links(version.PREDECESSOR) self.assertEqual(1, len(links)) self.assertEqual(expected_href, links[0].get_href()) @@ -375,11 +394,11 @@ def test_multiple_link_setting(self): year = 2014 successor2 = make_collection(year) expected_href = URL_TEMPLATE % year - self.collection.ext.version.successor = successor2 + VersionExtension.ext(self.collection).successor = successor2 links = self.collection.get_links(version.SUCCESSOR) self.assertEqual(1, len(links)) self.assertEqual(expected_href, links[0].get_href()) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/extensions/test_view.py b/tests/extensions/test_view.py index 24030899f..ee96a7107 100644 --- a/tests/extensions/test_view.py +++ b/tests/extensions/test_view.py @@ -2,201 +2,213 @@ import unittest import pystac -from pystac.extensions import ExtensionError -from pystac import (Item, Extensions) -from tests.utils import (TestCases, test_to_from_dict) +from pystac.extensions.view import ViewExtension +from tests.utils import TestCases, test_to_from_dict class ViewTest(unittest.TestCase): def setUp(self): self.maxDiff = None - self.example_uri = TestCases.get_path('data-files/view/example-landsat8.json') + self.example_uri = TestCases.get_path("data-files/view/example-landsat8.json") def test_to_from_dict(self): with open(self.example_uri) as f: d = json.load(f) - test_to_from_dict(self, Item, d) + test_to_from_dict(self, pystac.Item, d) def test_apply(self): - item = next(TestCases.test_case_2().get_all_items()) - with self.assertRaises(ExtensionError): - item.ext.view - - item.ext.enable(Extensions.VIEW) - item.ext.view.apply(off_nadir=1.0, - incidence_angle=2.0, - azimuth=3.0, - sun_azimuth=2.0, - sun_elevation=1.0) - - def test_apply_one(self): - item = next(TestCases.test_case_2().get_all_items()) - with self.assertRaises(ExtensionError): - item.ext.view - - item.ext.enable(Extensions.VIEW) - item.ext.view.apply(off_nadir=1.0) - - @unittest.expectedFailure - def test_apply_none(self): - item = next(TestCases.test_case_2().get_all_items()) - with self.assertRaises(ExtensionError): - item.ext.view - - item.ext.enable(Extensions.VIEW) - item.ext.view.apply( - off_nadir=None, - incidence_angle=None, - azimuth=None, - sun_azimuth=None, - sun_elevation=None, + item = next(iter(TestCases.test_case_2().get_all_items())) + self.assertFalse(ViewExtension.has_extension(item)) + + ViewExtension.add_to(item) + ViewExtension.ext(item).apply( + off_nadir=1.0, + incidence_angle=2.0, + azimuth=3.0, + sun_azimuth=4.0, + sun_elevation=5.0, ) + self.assertEqual(ViewExtension.ext(item).off_nadir, 1.0) + self.assertEqual(ViewExtension.ext(item).incidence_angle, 2.0) + self.assertEqual(ViewExtension.ext(item).azimuth, 3.0) + self.assertEqual(ViewExtension.ext(item).sun_azimuth, 4.0) + self.assertEqual(ViewExtension.ext(item).sun_elevation, 5.0) + def test_validate_view(self): - item = pystac.read_file(self.example_uri) + item = pystac.Item.from_file(self.example_uri) + self.assertTrue(ViewExtension.has_extension(item)) item.validate() def test_off_nadir(self): - view_item = pystac.read_file(self.example_uri) + view_item = pystac.Item.from_file(self.example_uri) # Get self.assertIn("view:off_nadir", view_item.properties) - view_off_nadir = view_item.ext.view.off_nadir - self.assertEqual(view_off_nadir, view_item.properties['view:off_nadir']) + view_off_nadir = ViewExtension.ext(view_item).off_nadir + self.assertEqual(view_off_nadir, view_item.properties["view:off_nadir"]) # Set - view_item.ext.view.off_nadir = view_off_nadir + 10 - self.assertEqual(view_off_nadir + 10, view_item.properties['view:off_nadir']) + ViewExtension.ext(view_item).off_nadir = view_off_nadir + 10 + self.assertEqual(view_off_nadir + 10, view_item.properties["view:off_nadir"]) # Get from Asset - asset_no_prop = view_item.assets['blue'] - asset_prop = view_item.assets['red'] - self.assertEqual(view_item.ext.view.get_off_nadir(asset_no_prop), - view_item.ext.view.get_off_nadir()) - self.assertEqual(view_item.ext.view.get_off_nadir(asset_prop), 3.0) + asset_no_prop = view_item.assets["blue"] + asset_prop = view_item.assets["red"] + self.assertEqual( + ViewExtension.ext(asset_no_prop).off_nadir, + ViewExtension.ext(view_item).off_nadir, + ) + self.assertEqual(ViewExtension.ext(asset_prop).off_nadir, 3.0) # Set to Asset asset_value = 13.0 - view_item.ext.view.set_off_nadir(asset_value, asset_no_prop) - self.assertNotEqual(view_item.ext.view.get_off_nadir(asset_no_prop), - view_item.ext.view.get_off_nadir()) - self.assertEqual(view_item.ext.view.get_off_nadir(asset_no_prop), asset_value) + ViewExtension.ext(asset_no_prop).off_nadir = asset_value + self.assertNotEqual( + ViewExtension.ext(asset_no_prop).off_nadir, + ViewExtension.ext(view_item).off_nadir, + ) + self.assertEqual(ViewExtension.ext(asset_no_prop).off_nadir, asset_value) # Validate view_item.validate() def test_incidence_angle(self): - view_item = pystac.read_file(self.example_uri) + view_item = pystac.Item.from_file(self.example_uri) # Get self.assertIn("view:incidence_angle", view_item.properties) - view_incidence_angle = view_item.ext.view.incidence_angle - self.assertEqual(view_incidence_angle, view_item.properties['view:incidence_angle']) + view_incidence_angle = ViewExtension.ext(view_item).incidence_angle + self.assertEqual( + view_incidence_angle, view_item.properties["view:incidence_angle"] + ) # Set - view_item.ext.view.incidence_angle = view_incidence_angle + 10 - self.assertEqual(view_incidence_angle + 10, view_item.properties['view:incidence_angle']) + ViewExtension.ext(view_item).incidence_angle = view_incidence_angle + 10 + self.assertEqual( + view_incidence_angle + 10, view_item.properties["view:incidence_angle"] + ) # Get from Asset - asset_no_prop = view_item.assets['blue'] - asset_prop = view_item.assets['red'] - self.assertEqual(view_item.ext.view.get_incidence_angle(asset_no_prop), - view_item.ext.view.get_incidence_angle()) - self.assertEqual(view_item.ext.view.get_incidence_angle(asset_prop), 4.0) + asset_no_prop = view_item.assets["blue"] + asset_prop = view_item.assets["red"] + self.assertEqual( + ViewExtension.ext(asset_no_prop).incidence_angle, + ViewExtension.ext(view_item).incidence_angle, + ) + self.assertEqual(ViewExtension.ext(asset_prop).incidence_angle, 4.0) # Set to Asset asset_value = 14.0 - view_item.ext.view.set_incidence_angle(asset_value, asset_no_prop) - self.assertNotEqual(view_item.ext.view.get_incidence_angle(asset_no_prop), - view_item.ext.view.get_incidence_angle()) - self.assertEqual(view_item.ext.view.get_incidence_angle(asset_no_prop), asset_value) + ViewExtension.ext(asset_no_prop).incidence_angle = asset_value + self.assertNotEqual( + ViewExtension.ext(asset_no_prop).incidence_angle, + ViewExtension.ext(view_item).incidence_angle, + ) + self.assertEqual(ViewExtension.ext(asset_no_prop).incidence_angle, asset_value) # Validate view_item.validate() def test_azimuth(self): - view_item = pystac.read_file(self.example_uri) + view_item = pystac.Item.from_file(self.example_uri) # Get self.assertIn("view:azimuth", view_item.properties) - view_azimuth = view_item.ext.view.azimuth - self.assertEqual(view_azimuth, view_item.properties['view:azimuth']) + view_azimuth = ViewExtension.ext(view_item).azimuth + self.assertEqual(view_azimuth, view_item.properties["view:azimuth"]) # Set - view_item.ext.view.azimuth = view_azimuth + 100 - self.assertEqual(view_azimuth + 100, view_item.properties['view:azimuth']) + ViewExtension.ext(view_item).azimuth = view_azimuth + 100 + self.assertEqual(view_azimuth + 100, view_item.properties["view:azimuth"]) # Get from Asset - asset_no_prop = view_item.assets['blue'] - asset_prop = view_item.assets['red'] - self.assertEqual(view_item.ext.view.get_azimuth(asset_no_prop), - view_item.ext.view.get_azimuth()) - self.assertEqual(view_item.ext.view.get_azimuth(asset_prop), 5.0) + asset_no_prop = view_item.assets["blue"] + asset_prop = view_item.assets["red"] + self.assertEqual( + ViewExtension.ext(asset_no_prop).azimuth, + ViewExtension.ext(view_item).azimuth, + ) + self.assertEqual(ViewExtension.ext(asset_prop).azimuth, 5.0) # Set to Asset asset_value = 15.0 - view_item.ext.view.set_azimuth(asset_value, asset_no_prop) - self.assertNotEqual(view_item.ext.view.get_azimuth(asset_no_prop), - view_item.ext.view.get_azimuth()) - self.assertEqual(view_item.ext.view.get_azimuth(asset_no_prop), asset_value) + ViewExtension.ext(asset_no_prop).azimuth = asset_value + self.assertNotEqual( + ViewExtension.ext(asset_no_prop).azimuth, + ViewExtension.ext(view_item).azimuth, + ) + self.assertEqual(ViewExtension.ext(asset_no_prop).azimuth, asset_value) # Validate view_item.validate() def test_sun_azimuth(self): - view_item = pystac.read_file(self.example_uri) + view_item = pystac.Item.from_file(self.example_uri) # Get self.assertIn("view:sun_azimuth", view_item.properties) - view_sun_azimuth = view_item.ext.view.sun_azimuth - self.assertEqual(view_sun_azimuth, view_item.properties['view:sun_azimuth']) + view_sun_azimuth = ViewExtension.ext(view_item).sun_azimuth + self.assertEqual(view_sun_azimuth, view_item.properties["view:sun_azimuth"]) # Set - view_item.ext.view.sun_azimuth = view_sun_azimuth + 100 - self.assertEqual(view_sun_azimuth + 100, view_item.properties['view:sun_azimuth']) + ViewExtension.ext(view_item).sun_azimuth = view_sun_azimuth + 100 + self.assertEqual( + view_sun_azimuth + 100, view_item.properties["view:sun_azimuth"] + ) # Get from Asset - asset_no_prop = view_item.assets['blue'] - asset_prop = view_item.assets['red'] - self.assertEqual(view_item.ext.view.get_sun_azimuth(asset_no_prop), - view_item.ext.view.get_sun_azimuth()) - self.assertEqual(view_item.ext.view.get_sun_azimuth(asset_prop), 1.0) + asset_no_prop = view_item.assets["blue"] + asset_prop = view_item.assets["red"] + self.assertEqual( + ViewExtension.ext(asset_no_prop).sun_azimuth, + ViewExtension.ext(view_item).sun_azimuth, + ) + self.assertEqual(ViewExtension.ext(asset_prop).sun_azimuth, 1.0) # Set to Asset asset_value = 11.0 - view_item.ext.view.set_sun_azimuth(asset_value, asset_no_prop) - self.assertNotEqual(view_item.ext.view.get_sun_azimuth(asset_no_prop), - view_item.ext.view.get_sun_azimuth()) - self.assertEqual(view_item.ext.view.get_sun_azimuth(asset_no_prop), asset_value) + ViewExtension.ext(asset_no_prop).sun_azimuth = asset_value + self.assertNotEqual( + ViewExtension.ext(asset_no_prop).sun_azimuth, + ViewExtension.ext(view_item).sun_azimuth, + ) + self.assertEqual(ViewExtension.ext(asset_no_prop).sun_azimuth, asset_value) # Validate view_item.validate() def test_sun_elevation(self): - view_item = pystac.read_file(self.example_uri) + view_item = pystac.Item.from_file(self.example_uri) # Get self.assertIn("view:sun_elevation", view_item.properties) - view_sun_elevation = view_item.ext.view.sun_elevation - self.assertEqual(view_sun_elevation, view_item.properties['view:sun_elevation']) + view_sun_elevation = ViewExtension.ext(view_item).sun_elevation + self.assertEqual(view_sun_elevation, view_item.properties["view:sun_elevation"]) # Set - view_item.ext.view.sun_elevation = view_sun_elevation + 10 - self.assertEqual(view_sun_elevation + 10, view_item.properties['view:sun_elevation']) + ViewExtension.ext(view_item).sun_elevation = view_sun_elevation + 10 + self.assertEqual( + view_sun_elevation + 10, view_item.properties["view:sun_elevation"] + ) # Get from Asset - asset_no_prop = view_item.assets['blue'] - asset_prop = view_item.assets['red'] - self.assertEqual(view_item.ext.view.get_sun_elevation(asset_no_prop), - view_item.ext.view.get_sun_elevation()) - self.assertEqual(view_item.ext.view.get_sun_elevation(asset_prop), 2.0) + asset_no_prop = view_item.assets["blue"] + asset_prop = view_item.assets["red"] + self.assertEqual( + ViewExtension.ext(asset_no_prop).sun_elevation, + ViewExtension.ext(view_item).sun_elevation, + ) + self.assertEqual(ViewExtension.ext(asset_prop).sun_elevation, 2.0) # Set to Asset asset_value = 12.0 - view_item.ext.view.set_sun_elevation(asset_value, asset_no_prop) - self.assertNotEqual(view_item.ext.view.get_sun_elevation(asset_no_prop), - view_item.ext.view.get_sun_elevation()) - self.assertEqual(view_item.ext.view.get_sun_elevation(asset_no_prop), asset_value) + ViewExtension.ext(asset_no_prop).sun_elevation = asset_value + self.assertNotEqual( + ViewExtension.ext(asset_no_prop).sun_elevation, + ViewExtension.ext(view_item).sun_elevation, + ) + self.assertEqual(ViewExtension.ext(asset_no_prop).sun_elevation, asset_value) # Validate view_item.validate() diff --git a/tests/serialization/test_identify.py b/tests/serialization/test_identify.py index e854d90b6..97c1e6436 100644 --- a/tests/serialization/test_identify.py +++ b/tests/serialization/test_identify.py @@ -1,11 +1,14 @@ import unittest from urllib.error import HTTPError -from pystac import STAC_IO +import pystac from pystac.cache import CollectionCache -from pystac.serialization import (identify_stac_object, identify_stac_object_type, - merge_common_properties, STACObjectType) -from pystac.serialization.identify import (STACVersionRange, STACVersionID) +from pystac.serialization import ( + identify_stac_object, + identify_stac_object_type, + merge_common_properties, +) +from pystac.serialization.identify import STACVersionRange, STACVersionID from tests.utils import TestCases @@ -17,54 +20,59 @@ def setUp(self): def test_identify(self): collection_cache = CollectionCache() for example in self.examples: - path = example['path'] - d = STAC_IO.read_json(path) - if identify_stac_object_type(d) == STACObjectType.ITEM: - try: - merge_common_properties(d, json_href=path, collection_cache=collection_cache) - except HTTPError: - pass + with self.subTest(example.path): + path = example.path + d = pystac.StacIO.default().read_json(path) + if identify_stac_object_type(d) == pystac.STACObjectType.ITEM: + try: + merge_common_properties( + d, json_href=path, collection_cache=collection_cache + ) + except HTTPError: + pass - actual = identify_stac_object(d) - # Explicitly cover __repr__ functions in tests - str_info = str(actual) - self.assertIsInstance(str_info, str) + actual = identify_stac_object(d) + # Explicitly cover __repr__ functions in tests + str_info = str(actual) + self.assertIsInstance(str_info, str) - msg = 'Failed {}:'.format(path) + msg = "Failed {}:".format(path) - self.assertEqual(actual.object_type, example['object_type'], msg=msg) - version_contained_in_range = actual.version_range.contains(example['stac_version']) - self.assertTrue(version_contained_in_range, msg=msg) - self.assertEqual(set(actual.common_extensions), - set(example['common_extensions']), - msg=msg) - self.assertEqual(set(actual.custom_extensions), - set(example['custom_extensions']), - msg=msg) + self.assertEqual(actual.object_type, example.object_type, msg=msg) + version_contained_in_range = actual.version_range.contains( + example.stac_version + ) + self.assertTrue(version_contained_in_range, msg=msg) + self.assertEqual( + set(actual.extensions), set(example.extensions), msg=msg + ) class VersionTest(unittest.TestCase): def test_version_ordering(self): - self.assertEqual(STACVersionID('0.9.0'), STACVersionID('0.9.0')) - self.assertFalse(STACVersionID('0.9.0') < STACVersionID('0.9.0')) - self.assertFalse(STACVersionID('0.9.0') != STACVersionID('0.9.0')) - self.assertFalse(STACVersionID('0.9.0') > STACVersionID('0.9.0')) - self.assertTrue(STACVersionID('1.0.0-beta.2') < '1.0.0') - self.assertTrue(STACVersionID('0.9.1') > '0.9.0') - self.assertFalse(STACVersionID('0.9.0') > '0.9.0') - self.assertTrue(STACVersionID('0.9.0') <= '0.9.0') - self.assertTrue(STACVersionID('1.0.0-beta.1') <= STACVersionID('1.0.0-beta.2')) - self.assertFalse(STACVersionID('1.0.0') < STACVersionID('1.0.0-beta.2')) + self.assertEqual(STACVersionID("0.9.0"), STACVersionID("0.9.0")) + self.assertFalse(STACVersionID("0.9.0") < STACVersionID("0.9.0")) + self.assertFalse(STACVersionID("0.9.0") != STACVersionID("0.9.0")) + self.assertFalse(STACVersionID("0.9.0") > STACVersionID("0.9.0")) + self.assertTrue(STACVersionID("1.0.0-beta.2") < "1.0.0") + self.assertTrue(STACVersionID("0.9.1") > "0.9.0") # type:ignore + self.assertFalse(STACVersionID("0.9.0") > "0.9.0") # type:ignore + self.assertTrue(STACVersionID("0.9.0") <= "0.9.0") # type:ignore + self.assertTrue( + STACVersionID("1.0.0-beta.1") + <= STACVersionID("1.0.0-beta.2") # type:ignore + ) + self.assertFalse(STACVersionID("1.0.0") < STACVersionID("1.0.0-beta.2")) def test_version_range_ordering(self): - version_range = STACVersionRange('0.9.0', '1.0.0-beta.2') + version_range = STACVersionRange("0.9.0", "1.0.0-beta.2") self.assertIsInstance(str(version_range), str) - self.assertTrue(version_range.contains('1.0.0-beta.1')) - self.assertFalse(version_range.contains('1.0.0')) - self.assertTrue(version_range.is_later_than('0.8.9')) + self.assertTrue(version_range.contains("1.0.0-beta.1")) + self.assertFalse(version_range.contains("1.0.0")) + self.assertTrue(version_range.is_later_than("0.8.9")) - version_range = STACVersionRange('0.9.0', '1.0.0-beta.1') - self.assertFalse(version_range.contains('1.0.0-beta.2')) + version_range = STACVersionRange("0.9.0", "1.0.0-beta.1") + self.assertFalse(version_range.contains("1.0.0-beta.2")) - version_range = STACVersionRange(min_version='0.6.0-rc1', max_version='0.9.0') - self.assertTrue(version_range.contains('0.9.0')) + version_range = STACVersionRange(min_version="0.6.0-rc1", max_version="0.9.0") + self.assertTrue(version_range.contains("0.9.0")) diff --git a/tests/serialization/test_migrate.py b/tests/serialization/test_migrate.py index 56f9aa05d..c4c9ed6f9 100644 --- a/tests/serialization/test_migrate.py +++ b/tests/serialization/test_migrate.py @@ -1,10 +1,15 @@ +from pystac.extensions.item_assets import ItemAssetsExtension +from pystac.extensions.view import ViewExtension import unittest import pystac -from pystac import (STAC_IO, STACObject) from pystac.cache import CollectionCache -from pystac.serialization import (identify_stac_object, identify_stac_object_type, - merge_common_properties, migrate_to_latest, STACObjectType) +from pystac.serialization import ( + identify_stac_object, + identify_stac_object_type, + merge_common_properties, + migrate_to_latest, +) from pystac.utils import str_to_datetime from tests.utils import TestCases @@ -17,51 +22,70 @@ def setUp(self): def test_migrate(self): collection_cache = CollectionCache() for example in self.examples: - with self.subTest(example['path']): - path = example['path'] + with self.subTest(example.path): + path = example.path - d = STAC_IO.read_json(path) - if identify_stac_object_type(d) == STACObjectType.ITEM: - merge_common_properties(d, json_href=path, collection_cache=collection_cache) + d = pystac.StacIO.default().read_json(path) + if identify_stac_object_type(d) == pystac.STACObjectType.ITEM: + merge_common_properties( + d, json_href=path, collection_cache=collection_cache + ) info = identify_stac_object(d) - migrated_d, info = migrate_to_latest(d, info) + migrated_d = migrate_to_latest(d, info) migrated_info = identify_stac_object(migrated_d) self.assertEqual(migrated_info.object_type, info.object_type) - self.assertEqual(migrated_info.version_range.latest_valid_version(), - pystac.get_stac_version()) - self.assertEqual(set(migrated_info.common_extensions), set(info.common_extensions)) - self.assertEqual(set(migrated_info.custom_extensions), set(info.custom_extensions)) + self.assertEqual( + migrated_info.version_range.latest_valid_version(), + pystac.get_stac_version(), + ) + + # Ensure all stac_extensions are schema URIs + for e_id in migrated_d["stac_extensions"]: + self.assertTrue( + e_id.endswith(".json"), f"{e_id} is not a JSON schema URI" + ) # Test that PySTAC can read it without errors. - if info.object_type != STACObjectType.ITEMCOLLECTION: - self.assertIsInstance(STAC_IO.stac_object_from_dict(migrated_d, href=path), - STACObject) + if info.object_type != pystac.STACObjectType.ITEMCOLLECTION: + self.assertIsInstance( + pystac.read_dict(migrated_d, href=path), pystac.STACObject + ) def test_migrates_removed_extension(self): - item = pystac.read_file( - TestCases.get_path('data-files/examples/0.7.0/extensions/sar/' - 'examples/sentinel1.json')) - self.assertFalse('dtr' in item.stac_extensions) - self.assertEqual(item.common_metadata.start_datetime, - str_to_datetime("2018-11-03T23:58:55.121559Z")) + item = pystac.Item.from_file( + TestCases.get_path( + "data-files/examples/0.7.0/extensions/sar/" "examples/sentinel1.json" + ) + ) + self.assertFalse("dtr" in item.stac_extensions) + self.assertEqual( + item.common_metadata.start_datetime, + str_to_datetime("2018-11-03T23:58:55.121559Z"), + ) def test_migrates_added_extension(self): - item = pystac.read_file( - TestCases.get_path('data-files/examples/0.8.1/item-spec/' - 'examples/planet-sample.json')) - self.assertTrue('view' in item.stac_extensions) - self.assertEqual(item.ext.view.sun_azimuth, 101.8) - self.assertEqual(item.ext.view.sun_elevation, 58.8) - self.assertEqual(item.ext.view.off_nadir, 1) + item = pystac.Item.from_file( + TestCases.get_path( + "data-files/examples/0.8.1/item-spec/" "examples/planet-sample.json" + ) + ) + self.assertTrue(ViewExtension.has_extension(item)) + view_ext = ViewExtension.ext(item) + self.assertEqual(view_ext.sun_azimuth, 101.8) + self.assertEqual(view_ext.sun_elevation, 58.8) + self.assertEqual(view_ext.off_nadir, 1) def test_migrates_renamed_extension(self): - collection = pystac.read_file( - TestCases.get_path('data-files/examples/0.9.0/extensions/asset/' - 'examples/example-landsat8.json')) + collection = pystac.Collection.from_file( + TestCases.get_path( + "data-files/examples/0.9.0/extensions/asset/" + "examples/example-landsat8.json" + ) + ) - self.assertIn('item-assets', collection.stac_extensions) - self.assertIn('item_assets', collection.extra_fields) + self.assertTrue(ItemAssetsExtension.has_extension(collection)) + self.assertIn("item_assets", collection.extra_fields) diff --git a/tests/test_cache.py b/tests/test_cache.py index 798ad4692..1fcc75965 100644 --- a/tests/test_cache.py +++ b/tests/test_cache.py @@ -1,15 +1,22 @@ +from typing import Any, Dict +from pystac.utils import get_opt import unittest import pystac -from pystac.cache import (ResolvedObjectCache, ResolvedObjectCollectionCache) +from pystac.cache import ResolvedObjectCache, ResolvedObjectCollectionCache from tests.utils import TestCases -def create_catalog(suffix, include_href=True): +def create_catalog(suffix: Any, include_href: bool = True) -> pystac.Catalog: return pystac.Catalog( - id='test {}'.format(suffix), - description='test desc {}'.format(suffix), - href=('http://example.com/catalog_{}.json'.format(suffix) if include_href else None)) + id="test {}".format(suffix), + description="test desc {}".format(suffix), + href=( + "http://example.com/catalog_{}.json".format(suffix) + if include_href + else None + ), + ) class ResolvedObjectCacheTest(unittest.TestCase): @@ -44,29 +51,39 @@ def test_merge(self): identical_cat1 = create_catalog(1, include_href=False) identical_cat2 = create_catalog(2) - cached_ids_1 = {cat1.id: cat1} - cached_hrefs_1 = {cat2.get_self_href(): cat2} - cached_ids_2 = {cat3.id: cat3, cat1.id: identical_cat1} - cached_hrefs_2 = {cat4.get_self_href(): cat4, cat2.get_self_href(): identical_cat2} - cache1 = ResolvedObjectCollectionCache(ResolvedObjectCache(), - cached_ids=cached_ids_1, - cached_hrefs=cached_hrefs_1) - cache2 = ResolvedObjectCollectionCache(ResolvedObjectCache(), - cached_ids=cached_ids_2, - cached_hrefs=cached_hrefs_2) - - merged = ResolvedObjectCollectionCache.merge(ResolvedObjectCache(), cache1, cache2) - - self.assertEqual(set(merged.cached_ids.keys()), set([cat.id for cat in [cat1, cat3]])) + cached_ids_1: Dict[str, Any] = {cat1.id: cat1} + cached_hrefs_1: Dict[str, Any] = {get_opt(cat2.get_self_href()): cat2} + cached_ids_2: Dict[str, Any] = {cat3.id: cat3, cat1.id: identical_cat1} + cached_hrefs_2: Dict[str, Any] = { + get_opt(cat4.get_self_href()): cat4, + get_opt(cat2.get_self_href()): identical_cat2, + } + cache1 = ResolvedObjectCollectionCache( + ResolvedObjectCache(), cached_ids=cached_ids_1, cached_hrefs=cached_hrefs_1 + ) + cache2 = ResolvedObjectCollectionCache( + ResolvedObjectCache(), cached_ids=cached_ids_2, cached_hrefs=cached_hrefs_2 + ) + + merged = ResolvedObjectCollectionCache.merge( + ResolvedObjectCache(), cache1, cache2 + ) + + self.assertEqual( + set(merged.cached_ids.keys()), set([cat.id for cat in [cat1, cat3]]) + ) self.assertIs(merged.get_by_id(cat1.id), cat1) - self.assertEqual(set(merged.cached_hrefs.keys()), - set([cat.get_self_href() for cat in [cat2, cat4]])) - self.assertIs(merged.get_by_href(cat2.get_self_href()), cat2) + self.assertEqual( + set(merged.cached_hrefs.keys()), + set([cat.get_self_href() for cat in [cat2, cat4]]), + ) + self.assertIs(merged.get_by_href(get_opt(cat2.get_self_href())), cat2) def test_cache(self): cache = ResolvedObjectCache().as_collection_cache() collection = TestCases.test_case_8() collection_json = collection.to_dict() cache.cache(collection_json, collection.get_self_href()) - - self.assertEqual(cache.get_by_id(collection.id)['id'], collection.id) + cached = cache.get_by_id(collection.id) + assert isinstance(cached, dict) + self.assertEqual(cached["id"], collection.id) diff --git a/tests/test_catalog.py b/tests/test_catalog.py index d5b9293ed..d7ad5a3a8 100644 --- a/tests/test_catalog.py +++ b/tests/test_catalog.py @@ -1,17 +1,24 @@ import os import json +from typing import Any, Dict, List, Tuple, Union, cast import unittest from tempfile import TemporaryDirectory from datetime import datetime from collections import defaultdict import pystac -from pystac import (Catalog, Collection, CatalogType, Item, Asset, MediaType, Extensions, - HIERARCHICAL_LINKS) -from pystac.extensions.label import LabelClasses -from pystac.validation import STACValidationError +from pystac import ( + Catalog, + Collection, + CatalogType, + Item, + Asset, + MediaType, + HIERARCHICAL_LINKS, +) +from pystac.extensions.label import LabelClasses, LabelExtension, LabelType from pystac.utils import is_absolute_href -from tests.utils import (TestCases, RANDOM_GEOM, RANDOM_BBOX, MockStacIO) +from tests.utils import TestCases, ARBITRARY_GEOM, ARBITRARY_BBOX, MockStacIO class CatalogTypeTest(unittest.TestCase): @@ -19,7 +26,9 @@ def test_determine_type_for_absolute_published(self): cat = TestCases.test_case_1() with TemporaryDirectory() as tmp_dir: cat.normalize_and_save(tmp_dir, catalog_type=CatalogType.ABSOLUTE_PUBLISHED) - cat_json = pystac.STAC_IO.read_json(os.path.join(tmp_dir, 'catalog.json')) + cat_json = pystac.StacIO.default().read_json( + os.path.join(tmp_dir, "catalog.json") + ) catalog_type = CatalogType.determine_type(cat_json) self.assertEqual(catalog_type, CatalogType.ABSOLUTE_PUBLISHED) @@ -28,22 +37,25 @@ def test_determine_type_for_relative_published(self): cat = TestCases.test_case_2() with TemporaryDirectory() as tmp_dir: cat.normalize_and_save(tmp_dir, catalog_type=CatalogType.RELATIVE_PUBLISHED) - cat_json = pystac.STAC_IO.read_json(os.path.join(tmp_dir, 'catalog.json')) + cat_json = pystac.StacIO.default().read_json( + os.path.join(tmp_dir, "catalog.json") + ) catalog_type = CatalogType.determine_type(cat_json) self.assertEqual(catalog_type, CatalogType.RELATIVE_PUBLISHED) def test_determine_type_for_self_contained(self): - cat_json = pystac.STAC_IO.read_json( - TestCases.get_path('data-files/catalogs/test-case-1/catalog.json')) + cat_json = pystac.StacIO.default().read_json( + TestCases.get_path("data-files/catalogs/test-case-1/catalog.json") + ) catalog_type = CatalogType.determine_type(cat_json) self.assertEqual(catalog_type, CatalogType.SELF_CONTAINED) def test_determine_type_for_unknown(self): - catalog = Catalog(id='test', description='test desc') - subcat = Catalog(id='subcat', description='subcat desc') + catalog = Catalog(id="test", description="test desc") + subcat = Catalog(id="subcat", description="subcat desc") catalog.add_child(subcat) - catalog.normalize_hrefs('http://example.com') + catalog.normalize_hrefs("http://example.com") d = catalog.to_dict(include_self_link=False) self.assertIsNone(CatalogType.determine_type(d)) @@ -52,12 +64,14 @@ def test_determine_type_for_unknown(self): class CatalogTest(unittest.TestCase): def test_create_and_read(self): with TemporaryDirectory() as tmp_dir: - cat_dir = os.path.join(tmp_dir, 'catalog') + cat_dir = os.path.join(tmp_dir, "catalog") catalog = TestCases.test_case_1() - catalog.normalize_and_save(cat_dir, catalog_type=CatalogType.ABSOLUTE_PUBLISHED) + catalog.normalize_and_save( + cat_dir, catalog_type=CatalogType.ABSOLUTE_PUBLISHED + ) - read_catalog = Catalog.from_file('{}/catalog.json'.format(cat_dir)) + read_catalog = Catalog.from_file("{}/catalog.json".format(cat_dir)) collections = catalog.get_children() self.assertEqual(len(list(collections)), 2) @@ -69,82 +83,90 @@ def test_create_and_read(self): def test_read_remote(self): # TODO: Move this URL to the main stac-spec repo once the example JSON is fixed. catalog_url = ( - 'https://raw.githubusercontent.com/lossyrob/stac-spec/0.9.0/pystac-upgrade-fixes' - '/extensions/label/examples/multidataset/catalog.json') + "https://raw.githubusercontent.com/lossyrob/stac-spec/" + "0.9.0/pystac-upgrade-fixes" + "/extensions/label/examples/multidataset/catalog.json" + ) cat = Catalog.from_file(catalog_url) - zanzibar = cat.get_child('zanzibar-collection') + zanzibar = cat.get_child("zanzibar-collection") self.assertEqual(len(list(zanzibar.get_items())), 2) def test_clear_items_removes_from_cache(self): - catalog = Catalog(id='test', description='test') - subcat = Catalog(id='subcat', description='test') + catalog = Catalog(id="test", description="test") + subcat = Catalog(id="subcat", description="test") catalog.add_child(subcat) - item = Item(id='test-item', - geometry=RANDOM_GEOM, - bbox=RANDOM_BBOX, - datetime=datetime.utcnow(), - properties={'key': 'one'}) + item = Item( + id="test-item", + geometry=ARBITRARY_GEOM, + bbox=ARBITRARY_BBOX, + datetime=datetime.utcnow(), + properties={"key": "one"}, + ) subcat.add_item(item) items = list(catalog.get_all_items()) self.assertEqual(len(items), 1) - self.assertEqual(items[0].properties['key'], 'one') + self.assertEqual(items[0].properties["key"], "one") subcat.clear_items() - item = Item(id='test-item', - geometry=RANDOM_GEOM, - bbox=RANDOM_BBOX, - datetime=datetime.utcnow(), - properties={'key': 'two'}) + item = Item( + id="test-item", + geometry=ARBITRARY_GEOM, + bbox=ARBITRARY_BBOX, + datetime=datetime.utcnow(), + properties={"key": "two"}, + ) subcat.add_item(item) items = list(catalog.get_all_items()) self.assertEqual(len(items), 1) - self.assertEqual(items[0].properties['key'], 'two') - - subcat.remove_item('test-item') - item = Item(id='test-item', - geometry=RANDOM_GEOM, - bbox=RANDOM_BBOX, - datetime=datetime.utcnow(), - properties={'key': 'three'}) + self.assertEqual(items[0].properties["key"], "two") + + subcat.remove_item("test-item") + item = Item( + id="test-item", + geometry=ARBITRARY_GEOM, + bbox=ARBITRARY_BBOX, + datetime=datetime.utcnow(), + properties={"key": "three"}, + ) subcat.add_item(item) items = list(catalog.get_all_items()) self.assertEqual(len(items), 1) - self.assertEqual(items[0].properties['key'], 'three') + self.assertEqual(items[0].properties["key"], "three") def test_clear_children_removes_from_cache(self): - catalog = Catalog(id='test', description='test') - subcat = Catalog(id='subcat', description='test') + catalog = Catalog(id="test", description="test") + subcat = Catalog(id="subcat", description="test") catalog.add_child(subcat) children = list(catalog.get_children()) self.assertEqual(len(children), 1) - self.assertEqual(children[0].description, 'test') + self.assertEqual(children[0].description, "test") catalog.clear_children() - subcat = Catalog(id='subcat', description='test2') + subcat = Catalog(id="subcat", description="test2") catalog.add_child(subcat) children = list(catalog.get_children()) self.assertEqual(len(children), 1) - self.assertEqual(children[0].description, 'test2') + self.assertEqual(children[0].description, "test2") - catalog.remove_child('subcat') - subcat = Catalog(id='subcat', description='test3') + catalog.remove_child("subcat") + subcat = Catalog(id="subcat", description="test3") catalog.add_child(subcat) children = list(catalog.get_children()) self.assertEqual(len(children), 1) - self.assertEqual(children[0].description, 'test3') + self.assertEqual(children[0].description, "test3") def test_clear_children_sets_parent_and_root_to_None(self): - catalog = Catalog(id='test', description='test') - subcat1 = Catalog(id='subcat', description='test') - subcat2 = Catalog(id='subcat2', description='test2') + catalog = Catalog(id="test", description="test") + subcat1 = Catalog(id="subcat", description="test") + subcat2 = Catalog(id="subcat2", description="test2") catalog.add_children([subcat1, subcat2]) self.assertIsNotNone(subcat1.get_parent()) @@ -164,24 +186,24 @@ def test_clear_children_sets_parent_and_root_to_None(self): def test_add_child_throws_if_item(self): cat = TestCases.test_case_1() - item = next(cat.get_all_items()) + item = next(iter(cat.get_all_items())) with self.assertRaises(pystac.STACError): - cat.add_child(item) + cat.add_child(item) # type:ignore def test_add_item_throws_if_child(self): cat = TestCases.test_case_1() - child = next(cat.get_children()) + child = next(iter(cat.get_children())) with self.assertRaises(pystac.STACError): - cat.add_item(child) + cat.add_item(child) # type:ignore def test_get_child_returns_none_if_not_found(self): cat = TestCases.test_case_1() - child = cat.get_child('thisshouldnotbeachildid', recursive=True) + child = cat.get_child("thisshouldnotbeachildid", recursive=True) self.assertIsNone(child) def test_get_item_returns_none_if_not_found(self): cat = TestCases.test_case_1() - item = cat.get_item('thisshouldnotbeanitemid', recursive=True) + item = cat.get_item("thisshouldnotbeanitemid", recursive=True) self.assertIsNone(item) def test_sets_catalog_type(self): @@ -190,18 +212,24 @@ def test_sets_catalog_type(self): self.assertEqual(cat.catalog_type, CatalogType.SELF_CONTAINED) def test_walk_iterates_correctly(self): - def test_catalog(cat): + def test_catalog(cat: Catalog): expected_catalog_iterations = 1 actual_catalog_iterations = 0 - with self.subTest(title='Testing catalog {}'.format(cat.id)): + with self.subTest(title="Testing catalog {}".format(cat.id)): for root, children, items in cat.walk(): actual_catalog_iterations += 1 expected_catalog_iterations += len(list(root.get_children())) - self.assertEqual(set([c.id for c in root.get_children()]), - set([c.id for c in children]), 'Children unequal') - self.assertEqual(set([c.id for c in root.get_items()]), - set([c.id for c in items]), 'Items unequal') + self.assertEqual( + set([c.id for c in root.get_children()]), + set([c.id for c in children]), + "Children unequal", + ) + self.assertEqual( + set([c.id for c in root.get_items()]), + set([c.id for c in items]), + "Items unequal", + ) self.assertEqual(actual_catalog_iterations, expected_catalog_iterations) @@ -212,8 +240,8 @@ def test_clone_generates_correct_links(self): catalogs = TestCases.all_test_catalogs() for catalog in catalogs: - expected_link_types_to_counts = {} - actual_link_types_to_counts = {} + expected_link_types_to_counts: Any = {} + actual_link_types_to_counts: Any = {} for root, _, items in catalog.walk(): expected_link_types_to_counts[root.id] = defaultdict(int) @@ -233,8 +261,10 @@ def test_clone_generates_correct_links(self): for link in item.get_links(): actual_link_types_to_counts[item.id][link.rel] += 1 - self.assertEqual(set(expected_link_types_to_counts.keys()), - set(actual_link_types_to_counts.keys())) + self.assertEqual( + set(expected_link_types_to_counts.keys()), + set(actual_link_types_to_counts.keys()), + ) for obj_id in actual_link_types_to_counts: expected_counts = expected_link_types_to_counts[obj_id] @@ -242,19 +272,22 @@ def test_clone_generates_correct_links(self): self.assertEqual(set(expected_counts.keys()), set(actual_counts.keys())) for rel in expected_counts: self.assertEqual( - actual_counts[rel], expected_counts[rel], - 'Clone of {} has {} {} links, original has {}'.format( - obj_id, actual_counts[rel], rel, expected_counts[rel])) + actual_counts[rel], + expected_counts[rel], + "Clone of {} has {} {} links, original has {}".format( + obj_id, actual_counts[rel], rel, expected_counts[rel] + ), + ) def test_save_uses_previous_catalog_type(self): catalog = TestCases.test_case_1() assert catalog.catalog_type == CatalogType.SELF_CONTAINED with TemporaryDirectory() as tmp_dir: catalog.normalize_hrefs(tmp_dir) - href = catalog.get_self_href() + href = catalog.self_href catalog.save() - cat2 = pystac.read_file(href) + cat2 = pystac.Catalog.from_file(href) self.assertEqual(cat2.catalog_type, CatalogType.SELF_CONTAINED) def test_clone_uses_previous_catalog_type(self): @@ -265,50 +298,59 @@ def test_clone_uses_previous_catalog_type(self): def test_normalize_hrefs_sets_all_hrefs(self): catalog = TestCases.test_case_1() - catalog.normalize_hrefs('http://example.com') + catalog.normalize_hrefs("http://example.com") for root, _, items in catalog.walk(): - self.assertTrue(root.get_self_href().startswith('http://example.com')) + self.assertTrue(root.get_self_href().startswith("http://example.com")) for link in root.links: if link.is_resolved(): - target_href = link.target.get_self_href() + target_href = cast(pystac.STACObject, link.target).self_href else: - target_href = link.get_absolute_href() + target_href = link.absolute_href self.assertTrue( - 'http://example.com' in target_href, - '[{}] {} does not contain "{}"'.format(link.rel, target_href, - 'http://example.com')) + "http://example.com" in target_href, + '[{}] {} does not contain "{}"'.format( + link.rel, target_href, "http://example.com" + ), + ) for item in items: - self.assertIn('http://example.com', item.get_self_href()) + self.assertIn("http://example.com", item.self_href) def test_normalize_hrefs_makes_absolute_href(self): catalog = TestCases.test_case_1() - catalog.normalize_hrefs('./relativepath') - abspath = os.path.abspath('./relativepath') + catalog.normalize_hrefs("./relativepath") + abspath = os.path.abspath("./relativepath") self.assertTrue(catalog.get_self_href().startswith(abspath)) def test_normalize_href_works_with_label_source_links(self): catalog = TestCases.test_case_1() - catalog.normalize_hrefs('http://example.com') - item = catalog.get_item('area-1-1-labels', recursive=True) - source = next(item.ext.label.get_sources()) + catalog.normalize_hrefs("http://example.com") + item = catalog.get_item("area-1-1-labels", recursive=True) + assert item is not None + source = next(iter(LabelExtension.ext(item).get_sources())) self.assertEqual( source.get_self_href(), - "http://example.com/country-1/area-1-1/area-1-1-imagery/area-1-1-imagery.json") + "http://example.com/country-1/area-1-1/" + "area-1-1-imagery/area-1-1-imagery.json", + ) def test_generate_subcatalogs_works_with_custom_properties(self): catalog = TestCases.test_case_8() - defaults = {'pl:item_type': 'PlanetScope'} - catalog.generate_subcatalogs('${year}/${month}/${pl:item_type}', defaults=defaults) + defaults = {"pl:item_type": "PlanetScope"} + catalog.generate_subcatalogs( + "${year}/${month}/${pl:item_type}", defaults=defaults + ) - month_cat = catalog.get_child('8', recursive=True) + month_cat = catalog.get_child("8", recursive=True) type_cats = set([cat.id for cat in month_cat.get_children()]) - self.assertEqual(type_cats, set(['PSScene4Band', 'SkySatScene', 'PlanetScope'])) + self.assertEqual(type_cats, set(["PSScene4Band", "SkySatScene", "PlanetScope"])) def test_generate_subcatalogs_does_not_change_item_count(self): catalog = TestCases.test_case_7() - item_counts = {cat.id: len(list(cat.get_all_items())) for cat in catalog.get_children()} + item_counts = { + cat.id: len(list(cat.get_all_items())) for cat in catalog.get_children() + } catalog.generate_subcatalogs("${year}/${day}") @@ -316,74 +358,89 @@ def test_generate_subcatalogs_does_not_change_item_count(self): catalog.normalize_hrefs(tmp_dir) catalog.save(pystac.CatalogType.SELF_CONTAINED) - cat2 = pystac.read_file(os.path.join(tmp_dir, 'catalog.json')) + cat2 = pystac.Catalog.from_file(os.path.join(tmp_dir, "catalog.json")) for child in cat2.get_children(): actual = len(list(child.get_all_items())) expected = item_counts[child.id] - self.assertEqual(actual, expected, msg=" for child '{}'".format(child.id)) + self.assertEqual( + actual, expected, msg=" for child '{}'".format(child.id) + ) def test_generate_subcatalogs_can_be_applied_multiple_times(self): catalog = TestCases.test_case_8() - _ = catalog.generate_subcatalogs('${year}/${month}') - catalog.normalize_hrefs('/tmp') - expected_hrefs = {item.id: item.get_self_href() for item in catalog.get_all_items()} + _ = catalog.generate_subcatalogs("${year}/${month}") + catalog.normalize_hrefs("/tmp") + expected_hrefs = { + item.id: item.get_self_href() for item in catalog.get_all_items() + } - result = catalog.generate_subcatalogs('${year}/${month}') + result = catalog.generate_subcatalogs("${year}/${month}") self.assertEqual(len(result), 0) - catalog.normalize_hrefs('/tmp') + catalog.normalize_hrefs("/tmp") for item in catalog.get_all_items(): - self.assertEqual(item.get_self_href(), - expected_hrefs[item.id], - msg=" for item '{}'".format(item.id)) + self.assertEqual( + item.get_self_href(), + expected_hrefs[item.id], + msg=" for item '{}'".format(item.id), + ) def test_generate_subcatalogs_works_after_adding_more_items(self): - catalog = Catalog(id='test', description='Test') - properties = dict(property1='A', property2=1) + catalog = Catalog(id="test", description="Test") + properties = dict(property1="A", property2=1) catalog.add_item( - Item(id='item1', - geometry=RANDOM_GEOM, - bbox=RANDOM_BBOX, - datetime=datetime.utcnow(), - properties=properties)) - catalog.generate_subcatalogs('${property1}/${property2}') + Item( + id="item1", + geometry=ARBITRARY_GEOM, + bbox=ARBITRARY_BBOX, + datetime=datetime.utcnow(), + properties=properties, + ) + ) + catalog.generate_subcatalogs("${property1}/${property2}") catalog.add_item( - Item(id='item2', - geometry=RANDOM_GEOM, - bbox=RANDOM_BBOX, - datetime=datetime.utcnow(), - properties=properties)) - catalog.generate_subcatalogs('${property1}/${property2}') - - catalog.normalize_hrefs('/tmp') - item1_parent = catalog.get_item('item1', recursive=True).get_parent() - item2_parent = catalog.get_item('item2', recursive=True).get_parent() + Item( + id="item2", + geometry=ARBITRARY_GEOM, + bbox=ARBITRARY_BBOX, + datetime=datetime.utcnow(), + properties=properties, + ) + ) + catalog.generate_subcatalogs("${property1}/${property2}") + + catalog.normalize_hrefs("/tmp") + item1_parent = catalog.get_item("item1", recursive=True).get_parent() + item2_parent = catalog.get_item("item2", recursive=True).get_parent() self.assertEqual(item1_parent.get_self_href(), item2_parent.get_self_href()) def test_generate_subcatalogs_works_for_branched_subcatalogs(self): - catalog = Catalog(id='test', description='Test') + catalog = Catalog(id="test", description="Test") item_properties = [ - dict(property1='A', property2=1, property3='i'), # add 3 subcats - dict(property1='A', property2=1, property3='j'), # add 1 more - dict(property1='A', property2=2, property3='i'), # add 2 more - dict(property1='B', property2=1, property3='i'), # add 3 more + dict(property1="A", property2=1, property3="i"), # add 3 subcats + dict(property1="A", property2=1, property3="j"), # add 1 more + dict(property1="A", property2=2, property3="i"), # add 2 more + dict(property1="B", property2=1, property3="i"), # add 3 more ] for ni, properties in enumerate(item_properties): catalog.add_item( - Item(id='item{}'.format(ni), - geometry=RANDOM_GEOM, - bbox=RANDOM_BBOX, - datetime=datetime.utcnow(), - properties=properties)) - result = catalog.generate_subcatalogs('${property1}/${property2}/${property3}') + Item( + id="item{}".format(ni), + geometry=ARBITRARY_GEOM, + bbox=ARBITRARY_BBOX, + datetime=datetime.utcnow(), + properties=properties, + ) + ) + result = catalog.generate_subcatalogs("${property1}/${property2}/${property3}") self.assertEqual(len(result), 9) actual_subcats = set([cat.id for cat in result]) - expected_subcats = {'A', 'B', '1', '2', 'i', 'j'} + expected_subcats = {"A", "B", "1", "2", "i", "j"} self.assertSetEqual(actual_subcats, expected_subcats) def test_generate_subcatalogs_works_for_subcatalogs_with_same_ids(self): - catalog = Catalog(id='test', description='Test') + catalog = Catalog(id="test", description="Test") item_properties = [ dict(property1=1, property2=1), # add 2 subcats dict(property1=1, property2=2), # add 1 more @@ -392,24 +449,27 @@ def test_generate_subcatalogs_works_for_subcatalogs_with_same_ids(self): ] for ni, properties in enumerate(item_properties): catalog.add_item( - Item(id='item{}'.format(ni), - geometry=RANDOM_GEOM, - bbox=RANDOM_BBOX, - datetime=datetime.utcnow(), - properties=properties)) - result = catalog.generate_subcatalogs('${property1}/${property2}') + Item( + id="item{}".format(ni), + geometry=ARBITRARY_GEOM, + bbox=ARBITRARY_BBOX, + datetime=datetime.utcnow(), + properties=properties, + ) + ) + result = catalog.generate_subcatalogs("${property1}/${property2}") self.assertEqual(len(result), 6) - catalog.normalize_hrefs('/') + catalog.normalize_hrefs("/") for item in catalog.get_all_items(): - parent_href = item.get_parent().get_self_href() + parent_href = item.get_parent().self_href path_to_parent, _ = os.path.split(parent_href) - subcats = [el for el in path_to_parent.split('/') if el] + subcats = [el for el in path_to_parent.split("/") if el] self.assertEqual(len(subcats), 2, msg=" for item '{}'".format(item.id)) def test_map_items(self): - def item_mapper(item): - item.properties['ITEM_MAPPER'] = 'YEP' + def item_mapper(item: pystac.Item) -> pystac.Item: + item.properties["ITEM_MAPPER"] = "YEP" return item with TemporaryDirectory() as tmp_dir: @@ -417,23 +477,23 @@ def item_mapper(item): new_cat = catalog.map_items(item_mapper) - new_cat.normalize_hrefs(os.path.join(tmp_dir, 'cat')) + new_cat.normalize_hrefs(os.path.join(tmp_dir, "cat")) new_cat.save(catalog_type=CatalogType.ABSOLUTE_PUBLISHED) - result_cat = Catalog.from_file(os.path.join(tmp_dir, 'cat', 'catalog.json')) + result_cat = Catalog.from_file(os.path.join(tmp_dir, "cat", "catalog.json")) for item in result_cat.get_all_items(): - self.assertTrue('ITEM_MAPPER' in item.properties) + self.assertTrue("ITEM_MAPPER" in item.properties) for item in catalog.get_all_items(): - self.assertFalse('ITEM_MAPPER' in item.properties) + self.assertFalse("ITEM_MAPPER" in item.properties) def test_map_items_multiple(self): - def item_mapper(item): + def item_mapper(item: pystac.Item) -> List[pystac.Item]: item2 = item.clone() - item2.id = item2.id + '_2' - item.properties['ITEM_MAPPER_1'] = 'YEP' - item2.properties['ITEM_MAPPER_2'] = 'YEP' + item2.id = item2.id + "_2" + item.properties["ITEM_MAPPER_1"] = "YEP" + item2.properties["ITEM_MAPPER_2"] = "YEP" return [item, item2] with TemporaryDirectory() as tmp_dir: @@ -442,72 +502,85 @@ def item_mapper(item): new_cat = catalog.map_items(item_mapper) - new_cat.normalize_hrefs(os.path.join(tmp_dir, 'cat')) + new_cat.normalize_hrefs(os.path.join(tmp_dir, "cat")) new_cat.save(catalog_type=CatalogType.ABSOLUTE_PUBLISHED) - result_cat = Catalog.from_file(os.path.join(tmp_dir, 'cat', 'catalog.json')) + result_cat = Catalog.from_file(os.path.join(tmp_dir, "cat", "catalog.json")) result_items = result_cat.get_all_items() self.assertEqual(len(list(catalog_items)) * 2, len(list(result_items))) ones, twos = 0, 0 for item in result_items: - self.assertTrue(('ITEM_MAPPER_1' in item.properties) - or ('ITEM_MAPPER_2' in item.properties)) - if 'ITEM_MAPPER_1' in item.properties: + self.assertTrue( + ("ITEM_MAPPER_1" in item.properties) + or ("ITEM_MAPPER_2" in item.properties) + ) + if "ITEM_MAPPER_1" in item.properties: ones += 1 - if 'ITEM_MAPPER_2' in item.properties: + if "ITEM_MAPPER_2" in item.properties: twos += 1 self.assertEqual(ones, twos) for item in catalog.get_all_items(): - self.assertFalse(('ITEM_MAPPER_1' in item.properties) - or ('ITEM_MAPPER_2' in item.properties)) + self.assertFalse( + ("ITEM_MAPPER_1" in item.properties) + or ("ITEM_MAPPER_2" in item.properties) + ) def test_map_items_multiple_2(self): - catalog = Catalog(id='test-1', description='Test1') - item1 = Item(id='item1', - geometry=RANDOM_GEOM, - bbox=RANDOM_BBOX, - datetime=datetime.utcnow(), - properties={}) - item1.add_asset('ortho', Asset(href='/some/ortho.tif')) + catalog = Catalog(id="test-1", description="Test1") + item1 = Item( + id="item1", + geometry=ARBITRARY_GEOM, + bbox=ARBITRARY_BBOX, + datetime=datetime.utcnow(), + properties={}, + ) + item1.add_asset("ortho", Asset(href="/some/ortho.tif")) catalog.add_item(item1) - kitten = Catalog(id='test-kitten', description='A cuter version of catalog') + kitten = Catalog(id="test-kitten", description="A cuter version of catalog") catalog.add_child(kitten) - item2 = Item(id='item2', - geometry=RANDOM_GEOM, - bbox=RANDOM_BBOX, - datetime=datetime.utcnow(), - properties={}) - item2.add_asset('ortho', Asset(href='/some/other/ortho.tif')) + item2 = Item( + id="item2", + geometry=ARBITRARY_GEOM, + bbox=ARBITRARY_BBOX, + datetime=datetime.utcnow(), + properties={}, + ) + item2.add_asset("ortho", Asset(href="/some/other/ortho.tif")) kitten.add_item(item2) - def modify_item_title(item): - item.title = 'Some new title' + def modify_item_title(item: pystac.Item) -> pystac.Item: + item.properties["title"] = "Some title" return item - def create_label_item(item): + def create_label_item(item: pystac.Item) -> List[pystac.Item]: # Assumes the GEOJSON labels are in the # same location as the image - img_href = item.assets['ortho'].href - label_href = '{}.geojson'.format(os.path.splitext(img_href)[0]) - label_item = Item(id='Labels', - geometry=item.geometry, - bbox=item.bbox, - datetime=datetime.utcnow(), - properties={}) - label_item.ext.enable(Extensions.LABEL) - label_ext = label_item.ext.label + img_href = item.assets["ortho"].href + label_href = "{}.geojson".format(os.path.splitext(img_href)[0]) + label_item = Item( + id="Labels", + geometry=item.geometry, + bbox=item.bbox, + datetime=datetime.utcnow(), + properties={}, + ) + LabelExtension(label_item).add_to(label_item) + label_ext = LabelExtension.ext(label_item) label_ext.apply( - label_description='labels', - label_type='vector', - label_properties=['label'], - label_classes=[LabelClasses.create(classes=['one', 'two'], name='label')], - label_tasks=['classification']) - label_ext.add_source(item, assets=['ortho']) + label_description="labels", + label_type=LabelType.VECTOR, + label_properties=["label"], + label_classes=[ + LabelClasses.create(classes=["one", "two"], name="label") + ], + label_tasks=["classification"], + ) + label_ext.add_source(item, assets=["ortho"]) label_ext.add_geojson_labels(label_href) return [item, label_item] @@ -520,11 +593,11 @@ def create_label_item(item): self.assertTrue(len(list(items)) == 4) def test_map_assets_single(self): - changed_asset = 'd43bead8-e3f8-4c51-95d6-e24e750a402b' + changed_asset = "d43bead8-e3f8-4c51-95d6-e24e750a402b" - def asset_mapper(key, asset): + def asset_mapper(key: str, asset: pystac.Asset) -> pystac.Asset: if key == changed_asset: - asset.title = 'NEW TITLE' + asset.title = "NEW TITLE" return asset @@ -533,29 +606,31 @@ def asset_mapper(key, asset): new_cat = catalog.map_assets(asset_mapper) - new_cat.normalize_hrefs(os.path.join(tmp_dir, 'cat')) + new_cat.normalize_hrefs(os.path.join(tmp_dir, "cat")) new_cat.save(catalog_type=CatalogType.ABSOLUTE_PUBLISHED) - result_cat = Catalog.from_file(os.path.join(tmp_dir, 'cat', 'catalog.json')) + result_cat = Catalog.from_file(os.path.join(tmp_dir, "cat", "catalog.json")) found = False for item in result_cat.get_all_items(): for key, asset in item.assets.items(): if key == changed_asset: found = True - self.assertEqual(asset.title, 'NEW TITLE') + self.assertEqual(asset.title, "NEW TITLE") else: - self.assertNotEqual(asset.title, 'NEW TITLE') + self.assertNotEqual(asset.title, "NEW TITLE") self.assertTrue(found) def test_map_assets_tup(self): - changed_assets = [] + changed_assets: List[str] = [] - def asset_mapper(key, asset): - if 'geotiff' in asset.media_type: - asset.title = 'NEW TITLE' + def asset_mapper( + key: str, asset: pystac.Asset + ) -> Union[pystac.Asset, Tuple[str, pystac.Asset]]: + if asset.media_type and "geotiff" in asset.media_type: + asset.title = "NEW TITLE" changed_assets.append(key) - return ('{}-modified'.format(key), asset) + return ("{}-modified".format(key), asset) else: return asset @@ -564,21 +639,21 @@ def asset_mapper(key, asset): new_cat = catalog.map_assets(asset_mapper) - new_cat.normalize_hrefs(os.path.join(tmp_dir, 'cat')) + new_cat.normalize_hrefs(os.path.join(tmp_dir, "cat")) new_cat.save(catalog_type=CatalogType.ABSOLUTE_PUBLISHED) - result_cat = Catalog.from_file(os.path.join(tmp_dir, 'cat', 'catalog.json')) + result_cat = Catalog.from_file(os.path.join(tmp_dir, "cat", "catalog.json")) found = False not_found = False for item in result_cat.get_all_items(): for key, asset in item.assets.items(): - if key.replace('-modified', '') in changed_assets: + if key.replace("-modified", "") in changed_assets: found = True - self.assertEqual(asset.title, 'NEW TITLE') + self.assertEqual(asset.title, "NEW TITLE") else: not_found = True - self.assertNotEqual(asset.title, 'NEW TITLE') + self.assertNotEqual(asset.title, "NEW TITLE") self.assertTrue(found) self.assertTrue(not_found) @@ -586,14 +661,16 @@ def asset_mapper(key, asset): def test_map_assets_multi(self): changed_assets = [] - def asset_mapper(key, asset): - if 'geotiff' in asset.media_type: + def asset_mapper( + key: str, asset: pystac.Asset + ) -> Union[pystac.Asset, Dict[str, pystac.Asset]]: + if asset.media_type and "geotiff" in asset.media_type: changed_assets.append(key) mod1 = asset.clone() - mod1.title = 'NEW TITLE 1' + mod1.title = "NEW TITLE 1" mod2 = asset.clone() - mod2.title = 'NEW TITLE 2' - return {'{}-mod-1'.format(key): mod1, '{}-mod-2'.format(key): mod2} + mod2.title = "NEW TITLE 2" + return {"{}-mod-1".format(key): mod1, "{}-mod-2".format(key): mod2} else: return asset @@ -602,25 +679,25 @@ def asset_mapper(key, asset): new_cat = catalog.map_assets(asset_mapper) - new_cat.normalize_hrefs(os.path.join(tmp_dir, 'cat')) + new_cat.normalize_hrefs(os.path.join(tmp_dir, "cat")) new_cat.save(catalog_type=CatalogType.ABSOLUTE_PUBLISHED) - result_cat = Catalog.from_file(os.path.join(tmp_dir, 'cat', 'catalog.json')) + result_cat = Catalog.from_file(os.path.join(tmp_dir, "cat", "catalog.json")) found1 = False found2 = False not_found = False for item in result_cat.get_all_items(): for key, asset in item.assets.items(): - if key.replace('-mod-1', '') in changed_assets: + if key.replace("-mod-1", "") in changed_assets: found1 = True - self.assertEqual(asset.title, 'NEW TITLE 1') - elif key.replace('-mod-2', '') in changed_assets: + self.assertEqual(asset.title, "NEW TITLE 1") + elif key.replace("-mod-2", "") in changed_assets: found2 = True - self.assertEqual(asset.title, 'NEW TITLE 2') + self.assertEqual(asset.title, "NEW TITLE 2") else: not_found = True - self.assertNotEqual(asset.title, 'NEW TITLE') + self.assertNotEqual(asset.title, "NEW TITLE") self.assertTrue(found1) self.assertTrue(found2) @@ -629,15 +706,15 @@ def asset_mapper(key, asset): def test_make_all_asset_hrefs_absolute(self): cat = TestCases.test_case_2() cat.make_all_asset_hrefs_absolute() - item = cat.get_item('cf73ec1a-d790-4b59-b077-e101738571ed', recursive=True) + item = cat.get_item("cf73ec1a-d790-4b59-b077-e101738571ed", recursive=True) - href = item.assets['cf73ec1a-d790-4b59-b077-e101738571ed'].href + href = item.assets["cf73ec1a-d790-4b59-b077-e101738571ed"].href self.assertTrue(is_absolute_href(href)) def test_make_all_asset_hrefs_relative(self): cat = TestCases.test_case_2() - item = cat.get_item('cf73ec1a-d790-4b59-b077-e101738571ed', recursive=True) - asset = item.assets['cf73ec1a-d790-4b59-b077-e101738571ed'] + item = cat.get_item("cf73ec1a-d790-4b59-b077-e101738571ed", recursive=True) + asset = item.assets["cf73ec1a-d790-4b59-b077-e101738571ed"] original_href = asset.href cat.make_all_asset_hrefs_absolute() @@ -649,23 +726,23 @@ def test_make_all_asset_hrefs_relative(self): self.assertEqual(asset.href, original_href) def test_make_all_links_relative_or_absolute(self): - def check_all_relative(cat): + def check_all_relative(cat: Catalog): for root, catalogs, items in cat.walk(): for link in root.links: if link.rel in HIERARCHICAL_LINKS: - self.assertFalse(is_absolute_href(link.get_href())) + self.assertFalse(is_absolute_href(link.href)) for item in items: for link in item.links: if link.rel in HIERARCHICAL_LINKS: - self.assertFalse(is_absolute_href(link.get_href())) + self.assertFalse(is_absolute_href(link.href)) - def check_all_absolute(cat): + def check_all_absolute(cat: Catalog): for root, catalogs, items in cat.walk(): for link in root.links: - self.assertTrue(is_absolute_href(link.get_href())) + self.assertTrue(is_absolute_href(link.href)) for item in items: for link in item.links: - self.assertTrue(is_absolute_href(link.get_href())) + self.assertTrue(is_absolute_href(link.href)) test_cases = TestCases.all_test_catalogs() @@ -681,52 +758,52 @@ def check_all_absolute(cat): def test_full_copy_and_normalize_works_with_created_stac(self): cat = TestCases.test_case_3() cat_copy = cat.full_copy() - cat_copy.normalize_hrefs('http://example.com') + cat_copy.normalize_hrefs("http://example.com") for root, catalogs, items in cat_copy.walk(): for link in root.links: - if link.rel != 'self': + if link.rel != "self": self.assertIsNot(link.target, None) for item in items: for link in item.links: - if link.rel != 'self': + if link.rel != "self": self.assertIsNot(link.get_href(), None) def test_extra_fields(self): catalog = TestCases.test_case_1() - catalog.extra_fields['type'] = 'FeatureCollection' + catalog.extra_fields["type"] = "FeatureCollection" with TemporaryDirectory() as tmp_dir: - p = os.path.join(tmp_dir, 'catalog.json') + p = os.path.join(tmp_dir, "catalog.json") catalog.save_object(include_self_link=False, dest_href=p) with open(p) as f: cat_json = json.load(f) - self.assertTrue('type' in cat_json) - self.assertEqual(cat_json['type'], 'FeatureCollection') + self.assertTrue("type" in cat_json) + self.assertEqual(cat_json["type"], "FeatureCollection") - read_cat = pystac.read_file(p) - self.assertTrue('type' in read_cat.extra_fields) - self.assertEqual(read_cat.extra_fields['type'], 'FeatureCollection') + read_cat = pystac.Catalog.from_file(p) + self.assertTrue("type" in read_cat.extra_fields) + self.assertEqual(read_cat.extra_fields["type"], "FeatureCollection") def test_validate_all(self): for cat in TestCases.all_test_catalogs(): with self.subTest(cat.id): # If hrefs are not set, it will fail validation. if cat.get_self_href() is None: - cat.normalize_hrefs('/tmp') + cat.normalize_hrefs("/tmp") cat.validate_all() # Make one invalid, write it off, read it in, ensure it throws cat = TestCases.test_case_1() - item = cat.get_item('area-1-1-labels', recursive=True) - item.geometry = {'type': 'INVALID', 'coordinates': 'NONE'} + item = cat.get_item("area-1-1-labels", recursive=True) + item.geometry = {"type": "INVALID", "coordinates": "NONE"} with TemporaryDirectory() as tmp_dir: cat.normalize_hrefs(tmp_dir) cat.save(catalog_type=pystac.CatalogType.SELF_CONTAINED) - cat2 = pystac.read_file(os.path.join(tmp_dir, 'catalog.json')) + cat2 = pystac.Catalog.from_file(os.path.join(tmp_dir, "catalog.json")) - with self.assertRaises(STACValidationError): + with self.assertRaises(pystac.STACValidationError): cat2.validate_all() def test_set_hrefs_manually(self): @@ -748,59 +825,72 @@ def test_set_hrefs_manually(self): if parent is None: root_dir = tmp_dir else: - d = os.path.dirname(parent.get_self_href()) + d = os.path.dirname(parent.self_href) root_dir = os.path.join(d, root.id) root_href = os.path.join(root_dir, root.DEFAULT_FILE_NAME) root.set_self_href(root_href) # Set each item's HREF based on it's datetime for item in items: - item_href = '{}/{}-{}/{}.json'.format(root_dir, item.datetime.year, - item.datetime.month, item.id) + item_href = "{}/{}-{}/{}.json".format( + root_dir, item.datetime.year, item.datetime.month, item.id + ) item.set_self_href(item_href) catalog.save(catalog_type=CatalogType.SELF_CONTAINED) - read_catalog = Catalog.from_file(os.path.join(tmp_dir, 'catalog.json')) + read_catalog = Catalog.from_file(os.path.join(tmp_dir, "catalog.json")) for root, _, items in read_catalog.walk(): parent = root.get_parent() if parent is None: - self.assertEqual(root.get_self_href(), os.path.join(tmp_dir, 'catalog.json')) + self.assertEqual( + root.get_self_href(), os.path.join(tmp_dir, "catalog.json") + ) else: - d = os.path.dirname(parent.get_self_href()) - self.assertEqual(root.get_self_href(), - os.path.join(d, root.id, root.DEFAULT_FILE_NAME)) + d = os.path.dirname(parent.self_href) + self.assertEqual( + root.get_self_href(), + os.path.join(d, root.id, root.DEFAULT_FILE_NAME), + ) for item in items: - end = '{}-{}/{}.json'.format(item.datetime.year, item.datetime.month, item.id) + end = "{}-{}/{}.json".format( + item.datetime.year, item.datetime.month, item.id + ) self.assertTrue(item.get_self_href().endswith(end)) def test_collections_cache_correctly(self): catalogs = TestCases.all_test_catalogs() + mock_io = MockStacIO() for cat in catalogs: - with MockStacIO() as mock_io: - expected_collection_reads = set([]) - for root, children, items in cat.walk(): - if isinstance(root, Collection) and root != cat: - expected_collection_reads.add(root.get_self_href()) - - # Iterate over items to make sure they are read - self.assertNotEqual(list(items), None) - - call_uris = [ - call[0][0] for call in mock_io.read_text_method.call_args_list - if call[0][0] in expected_collection_reads - ] - - for collection_uri in expected_collection_reads: - calls = len([x for x in call_uris if x == collection_uri]) - self.assertEqual( - calls, 1, - '{} was read {} times instead of once!'.format(collection_uri, calls)) + cat._stac_io = mock_io + expected_collection_reads = set([]) + for root, _, items in cat.walk(): + if isinstance(root, Collection) and root != cat: + expected_collection_reads.add(root.get_self_href()) + + # Iterate over items to make sure they are read + self.assertNotEqual(list(items), None) + + call_uris: List[Any] = [ + call[0][0] + for call in mock_io.mock.read_text.call_args_list + if call[0][0] in expected_collection_reads + ] + + for collection_uri in expected_collection_reads: + calls = len([x for x in call_uris if x == collection_uri]) + self.assertEqual( + calls, + 1, + "{} was read {} times instead of once!".format( + collection_uri, calls + ), + ) def test_reading_iterating_and_writing_works_as_expected(self): - """ Test case to cover issue #88 """ - stac_uri = 'tests/data-files/catalogs/test-case-6/catalog.json' + """Test case to cover issue #88""" + stac_uri = "tests/data-files/catalogs/test-case-6/catalog.json" cat = Catalog.from_file(stac_uri) # Iterate over the items. This was causing failure in @@ -809,12 +899,12 @@ def test_reading_iterating_and_writing_works_as_expected(self): pass with TemporaryDirectory() as tmp_dir: - new_stac_uri = os.path.join(tmp_dir, 'test-case-6') + new_stac_uri = os.path.join(tmp_dir, "test-case-6") cat.normalize_hrefs(new_stac_uri) cat.save(catalog_type=CatalogType.SELF_CONTAINED) # Open the local copy and iterate over it. - cat2 = Catalog.from_file(os.path.join(new_stac_uri, 'catalog.json')) + cat2 = Catalog.from_file(os.path.join(new_stac_uri, "catalog.json")) for item in cat2.get_all_items(): # Iterate again over the items. This would fail in #88 @@ -834,7 +924,9 @@ def test_resolve_planet(self): def test_handles_children_with_same_id(self): # This catalog has the root and child collection share an ID. - cat = pystac.read_file(TestCases.get_path('data-files/invalid/shared-id/catalog.json')) + cat = pystac.Catalog.from_file( + TestCases.get_path("data-files/invalid/shared-id/catalog.json") + ) items = list(cat.get_all_items()) self.assertEqual(len(items), 1) @@ -849,20 +941,22 @@ def test_catalog_with_href_caches_by_href(self): class FullCopyTest(unittest.TestCase): - def check_link(self, link, tag): + def check_link(self, link: pystac.Link, tag: str): if link.is_resolved(): - target_href = link.target.get_self_href() + target_href: str = cast(pystac.STACObject, link.target).self_href else: - target_href = link.target - self.assertTrue(tag in target_href, - '[{}] {} does not contain "{}"'.format(link.rel, target_href, tag)) + target_href = str(link.target) + self.assertTrue( + tag in target_href, + '[{}] {} does not contain "{}"'.format(link.rel, target_href, tag), + ) - def check_item(self, item, tag): + def check_item(self, item: Item, tag: str): for link in item.links: self.check_link(link, tag) - def check_catalog(self, c, tag): - self.assertEqual(len(c.get_links('root')), 1) + def check_catalog(self, c: Catalog, tag: str): + self.assertEqual(len(c.get_links("root")), 1) for link in c.links: self.check_link(link, tag) @@ -875,87 +969,105 @@ def check_catalog(self, c, tag): def test_full_copy_1(self): with TemporaryDirectory() as tmp_dir: - cat = Catalog(id='test', description='test catalog') + cat = Catalog(id="test", description="test catalog") - item = Item(id='test_item', - geometry=RANDOM_GEOM, - bbox=RANDOM_BBOX, - datetime=datetime.utcnow(), - properties={}) + item = Item( + id="test_item", + geometry=ARBITRARY_GEOM, + bbox=ARBITRARY_BBOX, + datetime=datetime.utcnow(), + properties={}, + ) cat.add_item(item) - cat.normalize_hrefs(os.path.join(tmp_dir, 'catalog-full-copy-1-source')) + cat.normalize_hrefs(os.path.join(tmp_dir, "catalog-full-copy-1-source")) cat2 = cat.full_copy() - cat2.normalize_hrefs(os.path.join(tmp_dir, 'catalog-full-copy-1-dest')) + cat2.normalize_hrefs(os.path.join(tmp_dir, "catalog-full-copy-1-dest")) - self.check_catalog(cat, 'source') - self.check_catalog(cat2, 'dest') + self.check_catalog(cat, "source") + self.check_catalog(cat2, "dest") def test_full_copy_2(self): with TemporaryDirectory() as tmp_dir: - cat = Catalog(id='test', description='test catalog') - image_item = Item(id='Imagery', - geometry=RANDOM_GEOM, - bbox=RANDOM_BBOX, - datetime=datetime.utcnow(), - properties={}) - for key in ['ortho', 'dsm']: + cat = Catalog(id="test", description="test catalog") + image_item = Item( + id="Imagery", + geometry=ARBITRARY_GEOM, + bbox=ARBITRARY_BBOX, + datetime=datetime.utcnow(), + properties={}, + ) + for key in ["ortho", "dsm"]: image_item.add_asset( - key, Asset(href='some/{}.tif'.format(key), media_type=MediaType.GEOTIFF)) - - label_item = Item(id='Labels', - geometry=RANDOM_GEOM, - bbox=RANDOM_BBOX, - datetime=datetime.utcnow(), - properties={}, - stac_extensions=[Extensions.LABEL]) - label_ext = label_item.ext.label + key, + Asset(href="some/{}.tif".format(key), media_type=MediaType.GEOTIFF), + ) + + label_item = Item( + id="Labels", + geometry=ARBITRARY_GEOM, + bbox=ARBITRARY_BBOX, + datetime=datetime.utcnow(), + properties={}, + ) + LabelExtension.add_to(label_item) + label_ext = LabelExtension.ext(label_item) label_ext.apply( - label_description='labels', - label_type='vector', - label_properties=['label'], - label_classes=[LabelClasses.create(classes=['one', 'two'], name='label')], - label_tasks=['classification']) - label_ext.add_source(image_item, assets=['ortho']) + label_description="labels", + label_type=LabelType.VECTOR, + label_properties=["label"], + label_classes=[ + LabelClasses.create(classes=["one", "two"], name="label") + ], + label_tasks=["classification"], + ) + label_ext.add_source(image_item, assets=["ortho"]) cat.add_items([image_item, label_item]) - cat.normalize_hrefs(os.path.join(tmp_dir, 'catalog-full-copy-2-source')) + cat.normalize_hrefs(os.path.join(tmp_dir, "catalog-full-copy-2-source")) cat.save(catalog_type=CatalogType.ABSOLUTE_PUBLISHED) cat2 = cat.full_copy() - cat2.normalize_hrefs(os.path.join(tmp_dir, 'catalog-full-copy-2-dest')) + cat2.normalize_hrefs(os.path.join(tmp_dir, "catalog-full-copy-2-dest")) cat2.save(catalog_type=CatalogType.ABSOLUTE_PUBLISHED) - self.check_catalog(cat, 'source') - self.check_catalog(cat2, 'dest') + self.check_catalog(cat, "source") + self.check_catalog(cat2, "dest") def test_full_copy_3(self): with TemporaryDirectory() as tmp_dir: root_cat = TestCases.test_case_1() - root_cat.normalize_hrefs(os.path.join(tmp_dir, 'catalog-full-copy-3-source')) + root_cat.normalize_hrefs( + os.path.join(tmp_dir, "catalog-full-copy-3-source") + ) root_cat.save(catalog_type=CatalogType.ABSOLUTE_PUBLISHED) cat2 = root_cat.full_copy() - cat2.normalize_hrefs(os.path.join(tmp_dir, 'catalog-full-copy-3-dest')) + cat2.normalize_hrefs(os.path.join(tmp_dir, "catalog-full-copy-3-dest")) cat2.save(catalog_type=CatalogType.ABSOLUTE_PUBLISHED) - self.check_catalog(root_cat, 'source') - self.check_catalog(cat2, 'dest') + self.check_catalog(root_cat, "source") + self.check_catalog(cat2, "dest") def test_full_copy_4(self): with TemporaryDirectory() as tmp_dir: root_cat = TestCases.test_case_2() - root_cat.normalize_hrefs(os.path.join(tmp_dir, 'catalog-full-copy-4-source')) + root_cat.normalize_hrefs( + os.path.join(tmp_dir, "catalog-full-copy-4-source") + ) root_cat.save(catalog_type=CatalogType.ABSOLUTE_PUBLISHED) cat2 = root_cat.full_copy() - cat2.normalize_hrefs(os.path.join(tmp_dir, 'catalog-full-copy-4-dest')) + cat2.normalize_hrefs(os.path.join(tmp_dir, "catalog-full-copy-4-dest")) cat2.save(catalog_type=CatalogType.ABSOLUTE_PUBLISHED) - self.check_catalog(root_cat, 'source') - self.check_catalog(cat2, 'dest') + self.check_catalog(root_cat, "source") + self.check_catalog(cat2, "dest") # Check that the relative asset link was saved correctly in the copy. - item = cat2.get_item('cf73ec1a-d790-4b59-b077-e101738571ed', recursive=True) + item = cat2.get_item("cf73ec1a-d790-4b59-b077-e101738571ed", recursive=True) - href = item.assets['cf73ec1a-d790-4b59-b077-e101738571ed'].get_absolute_href() + href = item.assets[ + "cf73ec1a-d790-4b59-b077-e101738571ed" + ].get_absolute_href() + assert href is not None self.assertTrue(os.path.exists(href)) diff --git a/tests/test_collection.py b/tests/test_collection.py index 80a5519fd..3ae88ef2c 100644 --- a/tests/test_collection.py +++ b/tests/test_collection.py @@ -6,19 +6,18 @@ from dateutil import tz import pystac +from pystac.extensions.eo import EOExtension from pystac.validation import validate_dict -from pystac.serialization.identify import STACObjectType -from pystac import (Collection, Item, Extent, SpatialExtent, TemporalExtent, CatalogType) -from pystac.extensions.eo import Band +from pystac import Collection, Item, Extent, SpatialExtent, TemporalExtent, CatalogType from pystac.utils import datetime_to_str -from tests.utils import (TestCases, RANDOM_GEOM, RANDOM_BBOX) +from tests.utils import TestCases, ARBITRARY_GEOM, ARBITRARY_BBOX TEST_DATETIME = datetime(2020, 3, 14, 16, 32) class CollectionTest(unittest.TestCase): def test_spatial_extent_from_coordinates(self): - extent = SpatialExtent.from_coordinates(RANDOM_GEOM['coordinates']) + extent = SpatialExtent.from_coordinates(ARBITRARY_GEOM["coordinates"]) self.assertEqual(len(extent.bboxes), 1) bbox = extent.bboxes[0] @@ -26,71 +25,11 @@ def test_spatial_extent_from_coordinates(self): for x in bbox: self.assertTrue(type(x) is float) - def test_eo_items_are_heritable(self): - item1 = Item(id='test-item-1', - geometry=RANDOM_GEOM, - bbox=RANDOM_BBOX, - datetime=TEST_DATETIME, - properties={'key': 'one'}, - stac_extensions=['eo', 'commons']) - - item2 = Item(id='test-item-2', - geometry=RANDOM_GEOM, - bbox=RANDOM_BBOX, - datetime=TEST_DATETIME, - properties={'key': 'two'}, - stac_extensions=['eo', 'commons']) - - wv3_bands = [ - Band.create(name='Coastal', description='Coastal: 400 - 450 nm', common_name='coastal'), - Band.create(name='Blue', description='Blue: 450 - 510 nm', common_name='blue'), - Band.create(name='Green', description='Green: 510 - 580 nm', common_name='green'), - Band.create(name='Yellow', description='Yellow: 585 - 625 nm', common_name='yellow'), - Band.create(name='Red', description='Red: 630 - 690 nm', common_name='red'), - Band.create(name='Red Edge', - description='Red Edge: 705 - 745 nm', - common_name='rededge'), - Band.create(name='Near-IR1', description='Near-IR1: 770 - 895 nm', common_name='nir08'), - Band.create(name='Near-IR2', description='Near-IR2: 860 - 1040 nm', common_name='nir09') - ] - - spatial_extent = SpatialExtent(bboxes=[RANDOM_BBOX]) - temporal_extent = TemporalExtent(intervals=[[item1.datetime, None]]) - - collection_extent = Extent(spatial=spatial_extent, temporal=temporal_extent) - - common_properties = { - 'eo:bands': [b.to_dict() for b in wv3_bands], - 'gsd': 0.3, - 'eo:platform': 'Maxar', - 'eo:instrument': 'WorldView3' - } - - collection = Collection(id='test', - description='test', - extent=collection_extent, - properties=common_properties, - stac_extensions=['commons'], - license='CC-BY-SA-4.0') - - collection.add_items([item1, item2]) - - with TemporaryDirectory() as tmp_dir: - collection.normalize_hrefs(tmp_dir) - collection.save(catalog_type=CatalogType.SELF_CONTAINED) - - read_col = Collection.from_file('{}/collection.json'.format(tmp_dir)) - items = list(read_col.get_all_items()) - - self.assertEqual(len(items), 2) - self.assertTrue(items[0].ext.implements('eo')) - self.assertTrue(items[1].ext.implements('eo')) - def test_read_eo_items_are_heritable(self): cat = TestCases.test_case_5() - item = next(cat.get_all_items()) + item = next(iter(cat.get_all_items())) - self.assertTrue(item.ext.implements('eo')) + self.assertTrue(EOExtension.has_extension(item)) def test_save_uses_previous_catalog_type(self): collection = TestCases.test_case_8() @@ -98,10 +37,10 @@ def test_save_uses_previous_catalog_type(self): self.assertEqual(collection.catalog_type, CatalogType.SELF_CONTAINED) with TemporaryDirectory() as tmp_dir: collection.normalize_hrefs(tmp_dir) - href = collection.get_self_href() + href = collection.self_href collection.save() - collection2 = pystac.read_file(href) + collection2 = pystac.Collection.from_file(href) self.assertEqual(collection2.catalog_type, CatalogType.SELF_CONTAINED) def test_clone_uses_previous_catalog_type(self): @@ -112,80 +51,88 @@ def test_clone_uses_previous_catalog_type(self): def test_multiple_extents(self): cat1 = TestCases.test_case_1() - col1 = cat1.get_child('country-1').get_child('area-1-1') + col1 = cat1.get_child("country-1").get_child("area-1-1") col1.validate() self.assertIsInstance(col1, Collection) - validate_dict(col1.to_dict(), STACObjectType.COLLECTION) + validate_dict(col1.to_dict(), pystac.STACObjectType.COLLECTION) - multi_ext_uri = TestCases.get_path('data-files/collections/multi-extent.json') + multi_ext_uri = TestCases.get_path("data-files/collections/multi-extent.json") with open(multi_ext_uri) as f: multi_ext_dict = json.load(f) - validate_dict(multi_ext_dict, STACObjectType.COLLECTION) + validate_dict(multi_ext_dict, pystac.STACObjectType.COLLECTION) self.assertIsInstance(Collection.from_dict(multi_ext_dict), Collection) multi_ext_col = Collection.from_file(multi_ext_uri) multi_ext_col.validate() ext = multi_ext_col.extent - extent_dict = multi_ext_dict['extent'] + extent_dict = multi_ext_dict["extent"] self.assertIsInstance(ext, Extent) self.assertIsInstance(ext.spatial.bboxes[0], list) self.assertEqual(len(ext.spatial.bboxes), 2) self.assertDictEqual(ext.to_dict(), extent_dict) cloned_ext = ext.clone() - self.assertDictEqual(cloned_ext.to_dict(), multi_ext_dict['extent']) + self.assertDictEqual(cloned_ext.to_dict(), multi_ext_dict["extent"]) def test_extra_fields(self): catalog = TestCases.test_case_2() - collection = catalog.get_child('1a8c1632-fa91-4a62-b33e-3a87c2ebdf16') + collection = catalog.get_child("1a8c1632-fa91-4a62-b33e-3a87c2ebdf16") - collection.extra_fields['test'] = 'extra' + collection.extra_fields["test"] = "extra" with TemporaryDirectory() as tmp_dir: - p = os.path.join(tmp_dir, 'collection.json') + p = os.path.join(tmp_dir, "collection.json") collection.save_object(include_self_link=False, dest_href=p) with open(p) as f: col_json = json.load(f) - self.assertTrue('test' in col_json) - self.assertEqual(col_json['test'], 'extra') + self.assertTrue("test" in col_json) + self.assertEqual(col_json["test"], "extra") - read_col = pystac.read_file(p) - self.assertTrue('test' in read_col.extra_fields) - self.assertEqual(read_col.extra_fields['test'], 'extra') + read_col = pystac.Collection.from_file(p) + self.assertTrue("test" in read_col.extra_fields) + self.assertEqual(read_col.extra_fields["test"], "extra") def test_update_extents(self): catalog = TestCases.test_case_2() - base_collection = catalog.get_child('1a8c1632-fa91-4a62-b33e-3a87c2ebdf16') + base_collection = catalog.get_child("1a8c1632-fa91-4a62-b33e-3a87c2ebdf16") + assert isinstance(base_collection, Collection) base_extent = base_collection.extent collection = base_collection.clone() - item1 = Item(id='test-item-1', - geometry=RANDOM_GEOM, - bbox=[-180, -90, 180, 90], - datetime=TEST_DATETIME, - properties={'key': 'one'}, - stac_extensions=['eo', 'commons']) - - item2 = Item(id='test-item-1', - geometry=RANDOM_GEOM, - bbox=[-180, -90, 180, 90], - datetime=None, - properties={ - 'start_datetime': datetime_to_str(datetime(2000, 1, 1, 12, 0, 0, 0)), - 'end_datetime': datetime_to_str(datetime(2000, 2, 1, 12, 0, 0, 0)) - }, - stac_extensions=['eo', 'commons']) + item1 = Item( + id="test-item-1", + geometry=ARBITRARY_GEOM, + bbox=[-180, -90, 180, 90], + datetime=TEST_DATETIME, + properties={"key": "one"}, + stac_extensions=["eo", "commons"], + ) + + item2 = Item( + id="test-item-1", + geometry=ARBITRARY_GEOM, + bbox=[-180, -90, 180, 90], + datetime=None, + properties={ + "start_datetime": datetime_to_str(datetime(2000, 1, 1, 12, 0, 0, 0)), + "end_datetime": datetime_to_str(datetime(2000, 2, 1, 12, 0, 0, 0)), + }, + stac_extensions=["eo", "commons"], + ) collection.add_item(item1) collection.update_extent_from_items() self.assertEqual([[-180, -90, 180, 90]], collection.extent.spatial.bboxes) - self.assertEqual(len(base_extent.spatial.bboxes[0]), - len(collection.extent.spatial.bboxes[0])) + self.assertEqual( + len(base_extent.spatial.bboxes[0]), len(collection.extent.spatial.bboxes[0]) + ) - self.assertNotEqual(base_extent.temporal.intervals, collection.extent.temporal.intervals) - collection.remove_item('test-item-1') + self.assertNotEqual( + base_extent.temporal.intervals, collection.extent.temporal.intervals + ) + collection.remove_item("test-item-1") collection.update_extent_from_items() self.assertNotEqual([[-180, -90, 180, 90]], collection.extent.spatial.bboxes) collection.add_item(item2) @@ -193,32 +140,31 @@ def test_update_extents(self): collection.update_extent_from_items() self.assertEqual( - [[item2.common_metadata.start_datetime, base_extent.temporal.intervals[0][1]]], - collection.extent.temporal.intervals) + [ + [ + item2.common_metadata.start_datetime, + base_extent.temporal.intervals[0][1], + ] + ], + collection.extent.temporal.intervals, + ) def test_supplying_href_in_init_does_not_fail(self): test_href = "http://example.com/collection.json" - spatial_extent = SpatialExtent(bboxes=[RANDOM_BBOX]) + spatial_extent = SpatialExtent(bboxes=[ARBITRARY_BBOX]) temporal_extent = TemporalExtent(intervals=[[TEST_DATETIME, None]]) collection_extent = Extent(spatial=spatial_extent, temporal=temporal_extent) - collection = Collection(id='test', - description='test desc', - extent=collection_extent, - properties={}, - href=test_href) + collection = Collection( + id="test", description="test desc", extent=collection_extent, href=test_href + ) self.assertEqual(collection.get_self_href(), test_href) - def test_reading_0_8_1_collection_as_catalog_throws_correct_exception(self): - cat = pystac.Catalog.from_file( - TestCases.get_path('data-files/examples/hand-0.8.1/collection.json')) - with self.assertRaises(ValueError): - list(cat.get_all_items()) - def test_collection_with_href_caches_by_href(self): - collection = pystac.read_file( - TestCases.get_path('data-files/examples/hand-0.8.1/collection.json')) + collection = pystac.Collection.from_file( + TestCases.get_path("data-files/examples/hand-0.8.1/collection.json") + ) cache = collection._resolved_objects # Since all of our STAC objects have HREFs, everything should be @@ -231,45 +177,57 @@ def test_spatial_allows_single_bbox(self): temporal_extent = TemporalExtent(intervals=[[TEST_DATETIME, None]]) # Pass in a single BBOX - spatial_extent = SpatialExtent(bboxes=RANDOM_BBOX) + spatial_extent = SpatialExtent(bboxes=ARBITRARY_BBOX) collection_extent = Extent(spatial=spatial_extent, temporal=temporal_extent) - collection = Collection(id='test', description='test desc', extent=collection_extent) + collection = Collection( + id="test", description="test desc", extent=collection_extent + ) # HREF required by validation - collection.set_self_href('https://example.com/collection.json') + collection.set_self_href("https://example.com/collection.json") collection.validate() def test_from_items(self): - item1 = Item(id='test-item-1', - geometry=RANDOM_GEOM, - bbox=[-10, -20, 0, -10], - datetime=datetime(2000, 2, 1, 12, 0, 0, 0, tzinfo=tz.UTC), - properties={}) - - item2 = Item(id='test-item-2', - geometry=RANDOM_GEOM, - bbox=[0, -9, 10, 1], - datetime=None, - properties={ - 'start_datetime': - datetime_to_str(datetime(2000, 1, 1, 12, 0, 0, 0, tzinfo=tz.UTC)), - 'end_datetime': - datetime_to_str(datetime(2000, 7, 1, 12, 0, 0, 0, tzinfo=tz.UTC)) - }) - - item3 = Item(id='test-item-2', - geometry=RANDOM_GEOM, - bbox=[-5, -20, 5, 0], - datetime=None, - properties={ - 'start_datetime': - datetime_to_str(datetime(2000, 12, 1, 12, 0, 0, 0, tzinfo=tz.UTC)), - 'end_datetime': - datetime_to_str(datetime(2001, 1, 1, 12, 0, 0, 0, tzinfo=tz.UTC), ) - }) + item1 = Item( + id="test-item-1", + geometry=ARBITRARY_GEOM, + bbox=[-10, -20, 0, -10], + datetime=datetime(2000, 2, 1, 12, 0, 0, 0, tzinfo=tz.UTC), + properties={}, + ) + + item2 = Item( + id="test-item-2", + geometry=ARBITRARY_GEOM, + bbox=[0, -9, 10, 1], + datetime=None, + properties={ + "start_datetime": datetime_to_str( + datetime(2000, 1, 1, 12, 0, 0, 0, tzinfo=tz.UTC) + ), + "end_datetime": datetime_to_str( + datetime(2000, 7, 1, 12, 0, 0, 0, tzinfo=tz.UTC) + ), + }, + ) + + item3 = Item( + id="test-item-2", + geometry=ARBITRARY_GEOM, + bbox=[-5, -20, 5, 0], + datetime=None, + properties={ + "start_datetime": datetime_to_str( + datetime(2000, 12, 1, 12, 0, 0, 0, tzinfo=tz.UTC) + ), + "end_datetime": datetime_to_str( + datetime(2001, 1, 1, 12, 0, 0, 0, tzinfo=tz.UTC), + ), + }, + ) extent = Extent.from_items([item1, item2, item3]) diff --git a/tests/test_item.py b/tests/test_item.py index c309adca0..2e38bfcf0 100644 --- a/tests/test_item.py +++ b/tests/test_item.py @@ -1,21 +1,22 @@ import os from datetime import datetime import json +from typing import Any, Dict, List import unittest from tempfile import TemporaryDirectory import pystac from pystac import Asset, Item, Provider from pystac.validation import validate_dict +import pystac.serialization.common_properties from pystac.item import CommonMetadata -from pystac.utils import (str_to_datetime, is_absolute_href) -from pystac.serialization.identify import STACObjectType -from tests.utils import (TestCases, test_to_from_dict) +from pystac.utils import datetime_to_str, get_opt, str_to_datetime, is_absolute_href +from tests.utils import TestCases, test_to_from_dict class ItemTest(unittest.TestCase): def get_example_item_dict(self): - m = TestCases.get_path('data-files/item/sample-item.json') + m = TestCases.get_path("data-files/item/sample-item.json") with open(m) as f: item_dict = json.load(f) return item_dict @@ -29,20 +30,26 @@ def test_to_from_dict(self): item = Item.from_dict(item_dict) self.assertEqual( item.get_self_href(), - 'http://cool-sat.com/catalog/CS3-20160503_132130_04/CS3-20160503_132130_04.json') + ( + "http://cool-sat.com/catalog/CS3-20160503_132130_04/" + "CS3-20160503_132130_04.json" + ), + ) # test asset creation additional field(s) - self.assertEqual(item.assets['analytic'].properties['product'], - 'http://cool-sat.com/catalog/products/analytic.json') - self.assertEqual(len(item.assets['thumbnail'].properties), 0) + self.assertEqual( + item.assets["analytic"].properties["product"], + "http://cool-sat.com/catalog/products/analytic.json", + ) + self.assertEqual(len(item.assets["thumbnail"].properties), 0) - def test_set_self_href_doesnt_break_asset_hrefs(self): + def test_set_self_href_does_not_break_asset_hrefs(self): cat = TestCases.test_case_2() for item in cat.get_all_items(): for asset in item.assets.values(): if is_absolute_href(asset.href): - asset.href = (f'./{os.path.basename(asset.href)}') - item.set_self_href('http://example.com/item.json') + asset.href = f"./{os.path.basename(asset.href)}" + item.set_self_href("http://example.com/item.json") for asset in item.assets.values(): self.assertTrue(is_absolute_href(asset.href)) @@ -51,7 +58,7 @@ def test_set_self_href_none_ignores_relative_asset_hrefs(self): for item in cat.get_all_items(): for asset in item.assets.values(): if is_absolute_href(asset.href): - asset.href = (f'./{os.path.basename(asset.href)}') + asset.href = f"./{os.path.basename(asset.href)}" item.set_self_href(None) for asset in item.assets.values(): self.assertFalse(is_absolute_href(asset.href)) @@ -59,32 +66,37 @@ def test_set_self_href_none_ignores_relative_asset_hrefs(self): def test_asset_absolute_href(self): item_dict = self.get_example_item_dict() item = Item.from_dict(item_dict) - rel_asset = Asset('./data.geojson') + rel_asset = Asset("./data.geojson") rel_asset.set_owner(item) - expected_href = 'http://cool-sat.com/catalog/CS3-20160503_132130_04/data.geojson' + expected_href = ( + "http://cool-sat.com/catalog/CS3-20160503_132130_04/data.geojson" + ) actual_href = rel_asset.get_absolute_href() self.assertEqual(expected_href, actual_href) def test_extra_fields(self): - item = pystac.read_file(TestCases.get_path('data-files/item/sample-item.json')) + item = pystac.Item.from_file( + TestCases.get_path("data-files/item/sample-item.json") + ) - item.extra_fields['test'] = 'extra' + item.extra_fields["test"] = "extra" with TemporaryDirectory() as tmp_dir: - p = os.path.join(tmp_dir, 'item.json') + p = os.path.join(tmp_dir, "item.json") item.save_object(include_self_link=False, dest_href=p) with open(p) as f: item_json = json.load(f) - self.assertTrue('test' in item_json) - self.assertEqual(item_json['test'], 'extra') + self.assertTrue("test" in item_json) + self.assertEqual(item_json["test"], "extra") - read_item = pystac.read_file(p) - self.assertTrue('test' in read_item.extra_fields) - self.assertEqual(read_item.extra_fields['test'], 'extra') + read_item = pystac.Item.from_file(p) + self.assertTrue("test" in read_item.extra_fields) + self.assertEqual(read_item.extra_fields["test"], "extra") def test_clearing_collection(self): - collection = TestCases.test_case_4().get_child('acc') - item = next(collection.get_all_items()) + collection = TestCases.test_case_4().get_child("acc") + assert isinstance(collection, pystac.Collection) + item = next(iter(collection.get_all_items())) self.assertEqual(item.collection_id, collection.id) item.set_collection(None) self.assertIsNone(item.collection_id) @@ -98,87 +110,112 @@ def test_datetime_ISO8601_format(self): item = Item.from_dict(item_dict) - formatted_time = item.to_dict()['properties']['datetime'] + formatted_time = item.to_dict()["properties"]["datetime"] - self.assertEqual('2016-05-03T13:22:30.040000Z', formatted_time) + self.assertEqual("2016-05-03T13:22:30.040000Z", formatted_time) def test_null_datetime(self): - item = pystac.read_file(TestCases.get_path('data-files/item/sample-item.json')) + item = pystac.Item.from_file( + TestCases.get_path("data-files/item/sample-item.json") + ) with self.assertRaises(pystac.STACError): - Item('test', geometry=item.geometry, bbox=item.bbox, datetime=None, properties={}) - - null_dt_item = Item('test', - geometry=item.geometry, - bbox=item.bbox, - datetime=None, - properties={ - 'start_datetime': pystac.utils.datetime_to_str(item.datetime), - 'end_datetime': pystac.utils.datetime_to_str(item.datetime) - }) + Item( + "test", + geometry=item.geometry, + bbox=item.bbox, + datetime=None, + properties={}, + ) + + null_dt_item = Item( + "test", + geometry=item.geometry, + bbox=item.bbox, + datetime=None, + properties={ + "start_datetime": datetime_to_str(get_opt(item.datetime)), + "end_datetime": datetime_to_str(get_opt(item.datetime)), + }, + ) null_dt_item.validate() def test_get_set_asset_datetime(self): - item = pystac.read_file( - TestCases.get_path('data-files/item/sample-item-asset-properties.json')) + item = pystac.Item.from_file( + TestCases.get_path("data-files/item/sample-item-asset-properties.json") + ) item_datetime = item.datetime # No property on asset - self.assertEqual(item.get_datetime(item.assets['thumbnail']), item.datetime) + self.assertEqual(item.get_datetime(item.assets["thumbnail"]), item.datetime) # Property on asset - self.assertNotEqual(item.get_datetime(item.assets['analytic']), item.datetime) - self.assertEqual(item.get_datetime(item.assets['analytic']), - str_to_datetime("2017-05-03T13:22:30.040Z")) + self.assertNotEqual(item.get_datetime(item.assets["analytic"]), item.datetime) + self.assertEqual( + item.get_datetime(item.assets["analytic"]), + str_to_datetime("2017-05-03T13:22:30.040Z"), + ) - item.set_datetime(str_to_datetime("2018-05-03T13:22:30.040Z"), item.assets['thumbnail']) + item.set_datetime( + str_to_datetime("2018-05-03T13:22:30.040Z"), item.assets["thumbnail"] + ) self.assertEqual(item.get_datetime(), item_datetime) - self.assertEqual(item.get_datetime(item.assets['thumbnail']), - str_to_datetime("2018-05-03T13:22:30.040Z")) + self.assertEqual( + item.get_datetime(item.assets["thumbnail"]), + str_to_datetime("2018-05-03T13:22:30.040Z"), + ) def test_read_eo_item_owns_asset(self): - item = next(x for x in TestCases.test_case_1().get_all_items() if isinstance(x, Item)) + item = next( + x for x in TestCases.test_case_1().get_all_items() if isinstance(x, Item) + ) assert len(item.assets) > 0 for asset_key in item.assets: self.assertEqual(item.assets[asset_key].owner, item) def test_self_contained_item(self): item_dict = self.get_example_item_dict() - item_dict['links'] = [link for link in item_dict['links'] if link['rel'] == 'self'] + item_dict["links"] = [ + link for link in item_dict["links"] if link["rel"] == "self" + ] item = Item.from_dict(item_dict) self.assertIsInstance(item, Item) self.assertEqual(len(item.links), 1) def test_null_geometry(self): m = TestCases.get_path( - 'data-files/examples/1.0.0-beta.2/item-spec/examples/null-geom-item.json') + "data-files/examples/1.0.0-beta.2/item-spec/examples/null-geom-item.json" + ) with open(m) as f: item_dict = json.load(f) - validate_dict(item_dict, STACObjectType.ITEM) + validate_dict(item_dict, pystac.STACObjectType.ITEM) item = Item.from_dict(item_dict) self.assertIsInstance(item, Item) item.validate() item_dict = item.to_dict() - self.assertIsNone(item_dict['geometry']) + self.assertIsNone(item_dict["geometry"]) with self.assertRaises(KeyError): - item_dict['bbox'] + item_dict["bbox"] def test_0_9_item_with_no_extensions_does_not_read_collection_data(self): - item_json = pystac.STAC_IO.read_json( - TestCases.get_path('data-files/examples/hand-0.9.0/010100/010100.json')) - assert item_json.get('stac_extensions') is None - assert item_json.get('stac_version') == '0.9.0' - - did_merge = pystac.serialization.common_properties.merge_common_properties(item_json) + item_json = pystac.StacIO.default().read_json( + TestCases.get_path("data-files/examples/hand-0.9.0/010100/010100.json") + ) + assert item_json.get("stac_extensions") is None + assert item_json.get("stac_version") == "0.9.0" + + did_merge = pystac.serialization.common_properties.merge_common_properties( + item_json + ) self.assertFalse(did_merge) def test_clone_sets_asset_owner(self): cat = TestCases.test_case_2() - item = next(cat.get_all_items()) + item = next(iter(cat.get_all_items())) original_asset = list(item.assets.values())[0] assert original_asset.owner is item @@ -188,7 +225,7 @@ def test_clone_sets_asset_owner(self): def test_make_asset_href_relative_is_noop_on_relative_hrefs(self): cat = TestCases.test_case_2() - item = next(cat.get_all_items()) + item = next(iter(cat.get_all_items())) asset = list(item.assets.values())[0] assert not is_absolute_href(asset.href) original_href = asset.get_absolute_href() @@ -200,30 +237,32 @@ def test_make_asset_href_relative_is_noop_on_relative_hrefs(self): class CommonMetadataTest(unittest.TestCase): def setUp(self): self.URI_1 = TestCases.get_path( - 'data-files/examples/1.0.0-beta.2/item-spec/examples/datetimerange.json') + "data-files/examples/1.0.0-beta.2/item-spec/examples/datetimerange.json" + ) self.ITEM_1 = Item.from_file(self.URI_1) self.URI_2 = TestCases.get_path( - 'data-files/examples/1.0.0-beta.2/item-spec/examples/sample-full.json') + "data-files/examples/1.0.0-beta.2/item-spec/examples/sample-full.json" + ) self.ITEM_2 = Item.from_file(self.URI_2) - self.EXAMPLE_CM_DICT = { - 'start_datetime': - '2020-05-21T16:42:24.896Z', - 'platform': - 'example platform', - 'providers': [{ - 'name': 'example provider', - 'roles': ['example roll'], - 'url': 'https://example-provider.com/' - }] + self.EXAMPLE_CM_DICT: Dict[str, Any] = { + "start_datetime": "2020-05-21T16:42:24.896Z", + "platform": "example platform", + "providers": [ + { + "name": "example provider", + "roles": ["example roll"], + "url": "https://example-provider.com/", + } + ], } def test_datetimes(self): # save dict of original item to check that `common_metadata` # method doesn't mutate self.item_1 before = self.ITEM_1.clone().to_dict() - start_datetime_str = self.ITEM_1.properties['start_datetime'] + start_datetime_str = self.ITEM_1.properties["start_datetime"] self.assertIsInstance(start_datetime_str, str) common_metadata = self.ITEM_1.common_metadata @@ -240,12 +279,12 @@ def test_common_metadata_start_datetime(self): example_datetime_dt = str_to_datetime(example_datetime_str) self.assertEqual(x.common_metadata.start_datetime, start_datetime_dt) - self.assertEqual(x.properties['start_datetime'], start_datetime_str) + self.assertEqual(x.properties["start_datetime"], start_datetime_str) x.common_metadata.start_datetime = example_datetime_dt self.assertEqual(x.common_metadata.start_datetime, example_datetime_dt) - self.assertEqual(x.properties['start_datetime'], example_datetime_str) + self.assertEqual(x.properties["start_datetime"], example_datetime_str) def test_common_metadata_end_datetime(self): x = self.ITEM_1.clone() @@ -255,12 +294,12 @@ def test_common_metadata_end_datetime(self): example_datetime_dt = str_to_datetime(example_datetime_str) self.assertEqual(x.common_metadata.end_datetime, end_datetime_dt) - self.assertEqual(x.properties['end_datetime'], end_datetime_str) + self.assertEqual(x.properties["end_datetime"], end_datetime_str) x.common_metadata.end_datetime = example_datetime_dt self.assertEqual(x.common_metadata.end_datetime, example_datetime_dt) - self.assertEqual(x.properties['end_datetime'], example_datetime_str) + self.assertEqual(x.properties["end_datetime"], example_datetime_str) def test_common_metadata_created(self): x = self.ITEM_2.clone() @@ -270,12 +309,12 @@ def test_common_metadata_created(self): example_datetime_dt = str_to_datetime(example_datetime_str) self.assertEqual(x.common_metadata.created, created_dt) - self.assertEqual(x.properties['created'], created_str) + self.assertEqual(x.properties["created"], created_str) x.common_metadata.created = example_datetime_dt self.assertEqual(x.common_metadata.created, example_datetime_dt) - self.assertEqual(x.properties['created'], example_datetime_str) + self.assertEqual(x.properties["created"], example_datetime_str) def test_common_metadata_updated(self): x = self.ITEM_2.clone() @@ -285,42 +324,49 @@ def test_common_metadata_updated(self): example_datetime_dt = str_to_datetime(example_datetime_str) self.assertEqual(x.common_metadata.updated, updated_dt) - self.assertEqual(x.properties['updated'], updated_str) + self.assertEqual(x.properties["updated"], updated_str) x.common_metadata.updated = example_datetime_dt self.assertEqual(x.common_metadata.updated, example_datetime_dt) - self.assertEqual(x.properties['updated'], example_datetime_str) + self.assertEqual(x.properties["updated"], example_datetime_str) def test_common_metadata_providers(self): x = self.ITEM_2.clone() - providers_dict_list = [{ - "name": "CoolSat", - "roles": ["producer", "licensor"], - "url": "https://cool-sat.com/" - }] + providers_dict_list: List[Dict[str, Any]] = [ + { + "name": "CoolSat", + "roles": ["producer", "licensor"], + "url": "https://cool-sat.com/", + } + ] providers_object_list = [Provider.from_dict(d) for d in providers_dict_list] - example_providers_dict_list = [{ - "name": "ExampleProvider_1", - "roles": ["example_role_1", "example_role_2"], - "url": "https://exampleprovider1.com/" - }, { - "name": "ExampleProvider_2", - "roles": ["example_role_1", "example_role_2"], - "url": "https://exampleprovider2.com/" - }] - example_providers_object_list = [Provider.from_dict(d) for d in example_providers_dict_list] + example_providers_dict_list: List[Dict[str, Any]] = [ + { + "name": "ExampleProvider_1", + "roles": ["example_role_1", "example_role_2"], + "url": "https://exampleprovider1.com/", + }, + { + "name": "ExampleProvider_2", + "roles": ["example_role_1", "example_role_2"], + "url": "https://exampleprovider2.com/", + }, + ] + example_providers_object_list = [ + Provider.from_dict(d) for d in example_providers_dict_list + ] - for i in range(len(x.common_metadata.providers)): - p1 = x.common_metadata.providers[i] + for i in range(len(get_opt(x.common_metadata.providers))): + p1 = get_opt(x.common_metadata.providers)[i] p2 = providers_object_list[i] self.assertIsInstance(p1, Provider) self.assertIsInstance(p2, Provider) self.assertDictEqual(p1.to_dict(), p2.to_dict()) - pd1 = x.properties['providers'][i] + pd1 = x.properties["providers"][i] pd2 = providers_dict_list[i] self.assertIsInstance(pd1, dict) self.assertIsInstance(pd2, dict) @@ -335,7 +381,7 @@ def test_common_metadata_providers(self): self.assertIsInstance(p2, Provider) self.assertDictEqual(p1.to_dict(), p2.to_dict()) - pd1 = x.properties['providers'][i] + pd1 = x.properties["providers"][i] pd2 = example_providers_dict_list[i] self.assertIsInstance(pd1, dict) self.assertIsInstance(pd2, dict) @@ -350,14 +396,14 @@ def test_common_metadata_basics(self): self.assertEqual(x.common_metadata.title, title) x.common_metadata.title = example_title self.assertEqual(x.common_metadata.title, example_title) - self.assertEqual(x.properties['title'], example_title) + self.assertEqual(x.properties["title"], example_title) # Description example_description = "example description" self.assertIsNone(x.common_metadata.description) x.common_metadata.description = example_description self.assertEqual(x.common_metadata.description, example_description) - self.assertEqual(x.properties['description'], example_description) + self.assertEqual(x.properties["description"], example_description) # License license = "PDDL-1.0" @@ -365,7 +411,7 @@ def test_common_metadata_basics(self): self.assertEqual(x.common_metadata.license, license) x.common_metadata.license = example_license self.assertEqual(x.common_metadata.license, example_license) - self.assertEqual(x.properties['license'], example_license) + self.assertEqual(x.properties["license"], example_license) # Platform platform = "coolsat2" @@ -373,29 +419,29 @@ def test_common_metadata_basics(self): self.assertEqual(x.common_metadata.platform, platform) x.common_metadata.platform = example_platform self.assertEqual(x.common_metadata.platform, example_platform) - self.assertEqual(x.properties['platform'], example_platform) + self.assertEqual(x.properties["platform"], example_platform) # Instruments instruments = ["cool_sensor_v1"] example_instruments = ["example instrument 1", "example instrument 2"] - self.assertListEqual(x.common_metadata.instruments, instruments) + self.assertListEqual(x.common_metadata.instruments or [], instruments) x.common_metadata.instruments = example_instruments self.assertListEqual(x.common_metadata.instruments, example_instruments) - self.assertListEqual(x.properties['instruments'], example_instruments) + self.assertListEqual(x.properties["instruments"], example_instruments) # Constellation example_constellation = "example constellation" self.assertIsNone(x.common_metadata.constellation) x.common_metadata.constellation = example_constellation self.assertEqual(x.common_metadata.constellation, example_constellation) - self.assertEqual(x.properties['constellation'], example_constellation) + self.assertEqual(x.properties["constellation"], example_constellation) # Mission example_mission = "example mission" self.assertIsNone(x.common_metadata.mission) x.common_metadata.mission = example_mission self.assertEqual(x.common_metadata.mission, example_mission) - self.assertEqual(x.properties['mission'], example_mission) + self.assertEqual(x.properties["mission"], example_mission) # GSD gsd = 0.512 @@ -403,252 +449,269 @@ def test_common_metadata_basics(self): self.assertEqual(x.common_metadata.gsd, gsd) x.common_metadata.gsd = example_gsd self.assertEqual(x.common_metadata.gsd, example_gsd) - self.assertEqual(x.properties['gsd'], example_gsd) + self.assertEqual(x.properties["gsd"], example_gsd) def test_asset_start_datetime(self): - item = pystac.read_file( - TestCases.get_path('data-files/item/sample-item-asset-properties.json')) + item = pystac.Item.from_file( + TestCases.get_path("data-files/item/sample-item-asset-properties.json") + ) cm = item.common_metadata item_value = cm.start_datetime a2_known_value = str_to_datetime("2017-05-01T13:22:30.040Z") # Get - a1_value = cm.get_start_datetime(item.assets['analytic']) - a2_value = cm.get_start_datetime(item.assets['thumbnail']) + a1_value = cm.get_start_datetime(item.assets["analytic"]) + a2_value = cm.get_start_datetime(item.assets["thumbnail"]) self.assertEqual(a1_value, item_value) self.assertNotEqual(a2_value, item_value) self.assertEqual(a2_value, a2_known_value) # Set set_value = str_to_datetime("2014-05-01T13:22:30.040Z") - cm.set_start_datetime(set_value, item.assets['analytic']) - new_a1_value = cm.get_start_datetime(item.assets['analytic']) + cm.set_start_datetime(set_value, item.assets["analytic"]) + new_a1_value = cm.get_start_datetime(item.assets["analytic"]) self.assertEqual(new_a1_value, set_value) self.assertEqual(cm.start_datetime, item_value) def test_asset_end_datetime(self): - item = pystac.read_file( - TestCases.get_path('data-files/item/sample-item-asset-properties.json')) + item = pystac.Item.from_file( + TestCases.get_path("data-files/item/sample-item-asset-properties.json") + ) cm = item.common_metadata item_value = cm.end_datetime a2_known_value = str_to_datetime("2017-05-02T13:22:30.040Z") # Get - a1_value = cm.get_end_datetime(item.assets['analytic']) - a2_value = cm.get_end_datetime(item.assets['thumbnail']) + a1_value = cm.get_end_datetime(item.assets["analytic"]) + a2_value = cm.get_end_datetime(item.assets["thumbnail"]) self.assertEqual(a1_value, item_value) self.assertNotEqual(a2_value, item_value) self.assertEqual(a2_value, a2_known_value) # Set set_value = str_to_datetime("2014-05-01T13:22:30.040Z") - cm.set_end_datetime(set_value, item.assets['analytic']) - new_a1_value = cm.get_end_datetime(item.assets['analytic']) + cm.set_end_datetime(set_value, item.assets["analytic"]) + new_a1_value = cm.get_end_datetime(item.assets["analytic"]) self.assertEqual(new_a1_value, set_value) self.assertEqual(cm.end_datetime, item_value) def test_asset_license(self): - item = pystac.read_file( - TestCases.get_path('data-files/item/sample-item-asset-properties.json')) + item = pystac.Item.from_file( + TestCases.get_path("data-files/item/sample-item-asset-properties.json") + ) cm = item.common_metadata item_value = cm.license - a2_known_value = 'CC-BY-4.0' + a2_known_value = "CC-BY-4.0" # Get - a1_value = cm.get_license(item.assets['analytic']) - a2_value = cm.get_license(item.assets['thumbnail']) + a1_value = cm.get_license(item.assets["analytic"]) + a2_value = cm.get_license(item.assets["thumbnail"]) self.assertEqual(a1_value, item_value) self.assertNotEqual(a2_value, item_value) self.assertEqual(a2_value, a2_known_value) # Set - set_value = 'various' - cm.set_license(set_value, item.assets['analytic']) - new_a1_value = cm.get_license(item.assets['analytic']) + set_value = "various" + cm.set_license(set_value, item.assets["analytic"]) + new_a1_value = cm.get_license(item.assets["analytic"]) self.assertEqual(new_a1_value, set_value) self.assertEqual(cm.license, item_value) def test_asset_providers(self): - item = pystac.read_file( - TestCases.get_path('data-files/item/sample-item-asset-properties.json')) + item = pystac.Item.from_file( + TestCases.get_path("data-files/item/sample-item-asset-properties.json") + ) cm = item.common_metadata - item_value = cm.providers + item_value = get_opt(cm.providers) a2_known_value = [ - pystac.Provider(name="USGS", - url="https://landsat.usgs.gov/", - roles=["producer", "licensor"]) + pystac.Provider( + name="USGS", + url="https://landsat.usgs.gov/", + roles=["producer", "licensor"], + ) ] # Get - a1_value = cm.get_providers(item.assets['analytic']) - a2_value = cm.get_providers(item.assets['thumbnail']) + a1_value: List[Provider] = get_opt(cm.get_providers(item.assets["analytic"])) + a2_value: List[Provider] = get_opt(cm.get_providers(item.assets["thumbnail"])) self.assertEqual(a1_value[0].to_dict(), item_value[0].to_dict()) self.assertNotEqual(a2_value[0].to_dict(), item_value[0].to_dict()) self.assertEqual(a2_value[0].to_dict(), a2_known_value[0].to_dict()) # Set set_value = [ - pystac.Provider(name="John Snow", url="https://cholera.com/", roles=["producer"]) + pystac.Provider( + name="John Snow", url="https://cholera.com/", roles=["producer"] + ) ] - cm.set_providers(set_value, item.assets['analytic']) - new_a1_value = cm.get_providers(item.assets['analytic']) + cm.set_providers(set_value, item.assets["analytic"]) + new_a1_value: List[Provider] = get_opt( + cm.get_providers(item.assets["analytic"]) + ) self.assertEqual(new_a1_value[0].to_dict(), set_value[0].to_dict()) - self.assertEqual(cm.providers[0].to_dict(), item_value[0].to_dict()) + self.assertEqual(get_opt(cm.providers)[0].to_dict(), item_value[0].to_dict()) def test_asset_platform(self): - item = pystac.read_file( - TestCases.get_path('data-files/item/sample-item-asset-properties.json')) + item = pystac.Item.from_file( + TestCases.get_path("data-files/item/sample-item-asset-properties.json") + ) cm = item.common_metadata item_value = cm.platform - a2_known_value = 'shoes' + a2_known_value = "shoes" # Get - a1_value = cm.get_platform(item.assets['analytic']) - a2_value = cm.get_platform(item.assets['thumbnail']) + a1_value = cm.get_platform(item.assets["analytic"]) + a2_value = cm.get_platform(item.assets["thumbnail"]) self.assertEqual(a1_value, item_value) self.assertNotEqual(a2_value, item_value) self.assertEqual(a2_value, a2_known_value) # Set - set_value = 'brick' - cm.set_platform(set_value, item.assets['analytic']) - new_a1_value = cm.get_platform(item.assets['analytic']) + set_value = "brick" + cm.set_platform(set_value, item.assets["analytic"]) + new_a1_value = cm.get_platform(item.assets["analytic"]) self.assertEqual(new_a1_value, set_value) self.assertEqual(cm.platform, item_value) def test_asset_instruments(self): - item = pystac.read_file( - TestCases.get_path('data-files/item/sample-item-asset-properties.json')) + item = pystac.Item.from_file( + TestCases.get_path("data-files/item/sample-item-asset-properties.json") + ) cm = item.common_metadata item_value = cm.instruments a2_known_value = ["caliper"] # Get - a1_value = cm.get_instruments(item.assets['analytic']) - a2_value = cm.get_instruments(item.assets['thumbnail']) + a1_value = cm.get_instruments(item.assets["analytic"]) + a2_value = cm.get_instruments(item.assets["thumbnail"]) self.assertEqual(a1_value, item_value) self.assertNotEqual(a2_value, item_value) self.assertEqual(a2_value, a2_known_value) # Set set_value = ["horns"] - cm.set_instruments(set_value, item.assets['analytic']) - new_a1_value = cm.get_instruments(item.assets['analytic']) + cm.set_instruments(set_value, item.assets["analytic"]) + new_a1_value = cm.get_instruments(item.assets["analytic"]) self.assertEqual(new_a1_value, set_value) self.assertEqual(cm.instruments, item_value) def test_asset_constellation(self): - item = pystac.read_file( - TestCases.get_path('data-files/item/sample-item-asset-properties.json')) + item = pystac.Item.from_file( + TestCases.get_path("data-files/item/sample-item-asset-properties.json") + ) cm = item.common_metadata item_value = cm.constellation - a2_known_value = 'little dipper' + a2_known_value = "little dipper" # Get - a1_value = cm.get_constellation(item.assets['analytic']) - a2_value = cm.get_constellation(item.assets['thumbnail']) + a1_value = cm.get_constellation(item.assets["analytic"]) + a2_value = cm.get_constellation(item.assets["thumbnail"]) self.assertEqual(a1_value, item_value) self.assertNotEqual(a2_value, item_value) self.assertEqual(a2_value, a2_known_value) # Set - set_value = 'orion' - cm.set_constellation(set_value, item.assets['analytic']) - new_a1_value = cm.get_constellation(item.assets['analytic']) + set_value = "orion" + cm.set_constellation(set_value, item.assets["analytic"]) + new_a1_value = cm.get_constellation(item.assets["analytic"]) self.assertEqual(new_a1_value, set_value) self.assertEqual(cm.constellation, item_value) def test_asset_mission(self): - item = pystac.read_file( - TestCases.get_path('data-files/item/sample-item-asset-properties.json')) + item = pystac.Item.from_file( + TestCases.get_path("data-files/item/sample-item-asset-properties.json") + ) cm = item.common_metadata item_value = cm.mission - a2_known_value = 'possible' + a2_known_value = "possible" # Get - a1_value = cm.get_mission(item.assets['analytic']) - a2_value = cm.get_mission(item.assets['thumbnail']) + a1_value = cm.get_mission(item.assets["analytic"]) + a2_value = cm.get_mission(item.assets["thumbnail"]) self.assertEqual(a1_value, item_value) self.assertNotEqual(a2_value, item_value) self.assertEqual(a2_value, a2_known_value) # Set - set_value = 'critical' - cm.set_mission(set_value, item.assets['analytic']) - new_a1_value = cm.get_mission(item.assets['analytic']) + set_value = "critical" + cm.set_mission(set_value, item.assets["analytic"]) + new_a1_value = cm.get_mission(item.assets["analytic"]) self.assertEqual(new_a1_value, set_value) self.assertEqual(cm.mission, item_value) def test_asset_gsd(self): - item = pystac.read_file( - TestCases.get_path('data-files/item/sample-item-asset-properties.json')) + item = pystac.Item.from_file( + TestCases.get_path("data-files/item/sample-item-asset-properties.json") + ) cm = item.common_metadata item_value = cm.gsd a2_known_value = 40 # Get - a1_value = cm.get_gsd(item.assets['analytic']) - a2_value = cm.get_gsd(item.assets['thumbnail']) + a1_value = cm.get_gsd(item.assets["analytic"]) + a2_value = cm.get_gsd(item.assets["thumbnail"]) self.assertEqual(a1_value, item_value) self.assertNotEqual(a2_value, item_value) self.assertEqual(a2_value, a2_known_value) # Set set_value = 100 - cm.set_gsd(set_value, item.assets['analytic']) - new_a1_value = cm.get_gsd(item.assets['analytic']) + cm.set_gsd(set_value, item.assets["analytic"]) + new_a1_value = cm.get_gsd(item.assets["analytic"]) self.assertEqual(new_a1_value, set_value) self.assertEqual(cm.gsd, item_value) def test_asset_created(self): - item = pystac.read_file( - TestCases.get_path('data-files/item/sample-item-asset-properties.json')) + item = pystac.Item.from_file( + TestCases.get_path("data-files/item/sample-item-asset-properties.json") + ) cm = item.common_metadata item_value = cm.created a2_known_value = str_to_datetime("2017-05-17T13:22:30.040Z") # Get - a1_value = cm.get_created(item.assets['analytic']) - a2_value = cm.get_created(item.assets['thumbnail']) + a1_value = cm.get_created(item.assets["analytic"]) + a2_value = cm.get_created(item.assets["thumbnail"]) self.assertEqual(a1_value, item_value) self.assertNotEqual(a2_value, item_value) self.assertEqual(a2_value, a2_known_value) # Set set_value = str_to_datetime("2014-05-17T13:22:30.040Z") - cm.set_created(set_value, item.assets['analytic']) - new_a1_value = cm.get_created(item.assets['analytic']) + cm.set_created(set_value, item.assets["analytic"]) + new_a1_value = cm.get_created(item.assets["analytic"]) self.assertEqual(new_a1_value, set_value) self.assertEqual(cm.created, item_value) def test_asset_updated(self): - item = pystac.read_file( - TestCases.get_path('data-files/item/sample-item-asset-properties.json')) + item = pystac.Item.from_file( + TestCases.get_path("data-files/item/sample-item-asset-properties.json") + ) cm = item.common_metadata item_value = cm.updated a2_known_value = str_to_datetime("2017-05-18T13:22:30.040Z") # Get - a1_value = cm.get_updated(item.assets['analytic']) - a2_value = cm.get_updated(item.assets['thumbnail']) + a1_value = cm.get_updated(item.assets["analytic"]) + a2_value = cm.get_updated(item.assets["thumbnail"]) self.assertEqual(a1_value, item_value) self.assertNotEqual(a2_value, item_value) self.assertEqual(a2_value, a2_known_value) # Set set_value = str_to_datetime("2014-05-18T13:22:30.040Z") - cm.set_updated(set_value, item.assets['analytic']) - new_a1_value = cm.get_updated(item.assets['analytic']) + cm.set_updated(set_value, item.assets["analytic"]) + new_a1_value = cm.get_updated(item.assets["analytic"]) self.assertEqual(new_a1_value, set_value) self.assertEqual(cm.updated, item_value) diff --git a/tests/test_layout.py b/tests/test_layout.py index c8995589c..3ed7e2815 100644 --- a/tests/test_layout.py +++ b/tests/test_layout.py @@ -1,11 +1,18 @@ -from datetime import (datetime, timedelta) +from datetime import datetime, timedelta import os +from typing import Callable +from pystac.collection import Collection import unittest import pystac -from pystac.layout import (LayoutTemplate, CustomLayoutStrategy, TemplateLayoutStrategy, - BestPracticesLayoutStrategy, TemplateError) -from tests.utils import (TestCases, RANDOM_GEOM, RANDOM_BBOX) +from pystac.layout import ( + LayoutTemplate, + CustomLayoutStrategy, + TemplateLayoutStrategy, + BestPracticesLayoutStrategy, + TemplateError, +) +from tests.utils import TestCases, ARBITRARY_GEOM, ARBITRARY_BBOX class LayoutTemplateTest(unittest.TestCase): @@ -13,79 +20,83 @@ def test_templates_item_datetime(self): year = 2020 month = 11 day = 3 - date = '2020-11-03' + date = "2020-11-03" dt = datetime(year, month, day, 18, 30) - template = LayoutTemplate('${year}/${month}/${day}/${date}/item.json') + template = LayoutTemplate("${year}/${month}/${day}/${date}/item.json") - item = pystac.Item('test', - geometry=RANDOM_GEOM, - bbox=RANDOM_BBOX, - datetime=dt, - properties={}) + item = pystac.Item( + "test", + geometry=ARBITRARY_GEOM, + bbox=ARBITRARY_BBOX, + datetime=dt, + properties={}, + ) parts = template.get_template_values(item) - self.assertEqual(set(parts), set(['year', 'month', 'day', 'date'])) + self.assertEqual(set(parts), set(["year", "month", "day", "date"])) - self.assertEqual(parts['year'], year) - self.assertEqual(parts['month'], month) - self.assertEqual(parts['day'], day) - self.assertEqual(parts['date'], date) + self.assertEqual(parts["year"], year) + self.assertEqual(parts["month"], month) + self.assertEqual(parts["day"], day) + self.assertEqual(parts["date"], date) path = template.substitute(item) - self.assertEqual(path, '2020/11/3/2020-11-03/item.json') + self.assertEqual(path, "2020/11/3/2020-11-03/item.json") def test_templates_item_start_datetime(self): year = 2020 month = 11 day = 3 - date = '2020-11-03' + date = "2020-11-03" dt = datetime(year, month, day, 18, 30) - template = LayoutTemplate('${year}/${month}/${day}/${date}/item.json') + template = LayoutTemplate("${year}/${month}/${day}/${date}/item.json") - item = pystac.Item('test', - geometry=RANDOM_GEOM, - bbox=RANDOM_BBOX, - datetime=None, - properties={ - 'start_datetime': dt.isoformat(), - 'end_datetime': (dt + timedelta(days=1)).isoformat() - }) + item = pystac.Item( + "test", + geometry=ARBITRARY_GEOM, + bbox=ARBITRARY_BBOX, + datetime=None, + properties={ + "start_datetime": dt.isoformat(), + "end_datetime": (dt + timedelta(days=1)).isoformat(), + }, + ) parts = template.get_template_values(item) - self.assertEqual(set(parts), set(['year', 'month', 'day', 'date'])) + self.assertEqual(set(parts), set(["year", "month", "day", "date"])) - self.assertEqual(parts['year'], year) - self.assertEqual(parts['month'], month) - self.assertEqual(parts['day'], day) - self.assertEqual(parts['date'], date) + self.assertEqual(parts["year"], year) + self.assertEqual(parts["month"], month) + self.assertEqual(parts["day"], day) + self.assertEqual(parts["date"], date) path = template.substitute(item) - self.assertEqual(path, '2020/11/3/2020-11-03/item.json') + self.assertEqual(path, "2020/11/3/2020-11-03/item.json") def test_templates_item_collection(self): - template = LayoutTemplate('${collection}/item.json') + template = LayoutTemplate("${collection}/item.json") - collection = TestCases.test_case_4().get_child('acc') - item = next(collection.get_all_items()) + collection = TestCases.test_case_4().get_child("acc") + item = next(iter(collection.get_all_items())) assert item.collection_id is not None parts = template.get_template_values(item) self.assertEqual(len(parts), 1) - self.assertIn('collection', parts) - self.assertEqual(parts['collection'], item.collection_id) + self.assertIn("collection", parts) + self.assertEqual(parts["collection"], item.collection_id) path = template.substitute(item) - self.assertEqual(path, '{}/item.json'.format(item.collection_id)) + self.assertEqual(path, "{}/item.json".format(item.collection_id)) def test_throws_for_no_collection(self): - template = LayoutTemplate('${collection}/item.json') + template = LayoutTemplate("${collection}/item.json") - collection = TestCases.test_case_4().get_child('acc') - item = next(collection.get_all_items()) + collection = TestCases.test_case_4().get_child("acc") + item = next(iter(collection.get_all_items())) item.set_collection(None) assert item.collection_id is None @@ -95,230 +106,267 @@ def test_throws_for_no_collection(self): def test_nested_properties(self): dt = datetime(2020, 11, 3, 18, 30) - template = LayoutTemplate('${test.prop}/${ext:extra.test.prop}/item.json') - - item = pystac.Item('test', - geometry=RANDOM_GEOM, - bbox=RANDOM_BBOX, - datetime=dt, - properties={'test': { - 'prop': 4326 - }}, - extra_fields={'ext:extra': { - 'test': { - 'prop': 3857 - } - }}) + template = LayoutTemplate("${test.prop}/${ext:extra.test.prop}/item.json") + + item = pystac.Item( + "test", + geometry=ARBITRARY_GEOM, + bbox=ARBITRARY_BBOX, + datetime=dt, + properties={"test": {"prop": 4326}}, + extra_fields={"ext:extra": {"test": {"prop": 3857}}}, + ) parts = template.get_template_values(item) - self.assertEqual(set(parts), set(['test.prop', 'ext:extra.test.prop'])) + self.assertEqual(set(parts), set(["test.prop", "ext:extra.test.prop"])) - self.assertEqual(parts['test.prop'], 4326) - self.assertEqual(parts['ext:extra.test.prop'], 3857) + self.assertEqual(parts["test.prop"], 4326) + self.assertEqual(parts["ext:extra.test.prop"], 3857) path = template.substitute(item) - self.assertEqual(path, '4326/3857/item.json') + self.assertEqual(path, "4326/3857/item.json") def test_substitute_with_colon_properties(self): dt = datetime(2020, 11, 3, 18, 30) - template = LayoutTemplate('${ext:prop}/item.json') + template = LayoutTemplate("${ext:prop}/item.json") - item = pystac.Item('test', - geometry=RANDOM_GEOM, - bbox=RANDOM_BBOX, - datetime=dt, - properties={'ext:prop': 1}) + item = pystac.Item( + "test", + geometry=ARBITRARY_GEOM, + bbox=ARBITRARY_BBOX, + datetime=dt, + properties={"ext:prop": 1}, + ) path = template.substitute(item) self.assertEqual(path, "1/item.json") def test_defaults(self): - template = LayoutTemplate('${doesnotexist}/collection.json', - defaults={'doesnotexist': 'yes'}) + template = LayoutTemplate( + "${doesnotexist}/collection.json", defaults={"doesnotexist": "yes"} + ) - collection = TestCases.test_case_4().get_child('acc') - collection.properties = {'up': 'down'} - collection.extra_fields = {'one': 'two'} - path = template.substitute(collection) + catalog = TestCases.test_case_4().get_child("acc") + assert catalog is not None + catalog.extra_fields = {"one": "two"} + path = template.substitute(catalog) - self.assertEqual(path, 'yes/collection.json') + self.assertEqual(path, "yes/collection.json") def test_docstring_examples(self): - item = pystac.read_file( + item = pystac.Item.from_file( TestCases.get_path( - "data-files/examples/1.0.0-beta.2/item-spec/examples/landsat8-sample.json")) + "data-files/examples/1.0.0-beta.2/item-spec/" + "examples/landsat8-sample.json" + ) + ) item.common_metadata.license = "CC-BY-3.0" # Uses the year, month and day of the item template1 = LayoutTemplate("${year}/${month}/${day}") path1 = template1.substitute(item) - self.assertEqual(path1, '2014/6/2') + self.assertEqual(path1, "2014/6/2") # Uses a custom extension properties found on in the item properties. template2 = LayoutTemplate("${landsat:path}/${landsat:row}") path2 = template2.substitute(item) - self.assertEqual(path2, '107/18') + self.assertEqual(path2, "107/18") # Uses the collection ID and a common metadata property for an item. template3 = LayoutTemplate("${collection}/${common_metadata.license}") path3 = template3.substitute(item) - self.assertEqual(path3, 'landsat-8-l1/CC-BY-3.0') + self.assertEqual(path3, "landsat-8-l1/CC-BY-3.0") class CustomLayoutStrategyTest(unittest.TestCase): - def get_custom_catalog_func(self): - def fn(cat, parent_dir, is_root): - return os.path.join(parent_dir, 'cat/{}/{}.json'.format(is_root, cat.id)) + def get_custom_catalog_func(self) -> Callable[[pystac.Catalog, str, bool], str]: + def fn(cat: pystac.Catalog, parent_dir: str, is_root: bool): + return os.path.join(parent_dir, "cat/{}/{}.json".format(is_root, cat.id)) return fn - def get_custom_collection_func(self): - def fn(col, parent_dir, is_root): - return os.path.join(parent_dir, 'col/{}/{}.json'.format(is_root, col.id)) + def get_custom_collection_func( + self, + ) -> Callable[[pystac.Collection, str, bool], str]: + def fn(col: pystac.Collection, parent_dir: str, is_root: bool): + return os.path.join(parent_dir, "col/{}/{}.json".format(is_root, col.id)) return fn - def get_custom_item_func(self): - def fn(item, parent_dir): - return os.path.join(parent_dir, 'item/{}.json'.format(item.id)) + def get_custom_item_func(self) -> Callable[[pystac.Item, str], str]: + def fn(item: pystac.Item, parent_dir: str): + return os.path.join(parent_dir, "item/{}.json".format(item.id)) return fn def test_produces_layout_for_catalog(self): strategy = CustomLayoutStrategy(catalog_func=self.get_custom_catalog_func()) - cat = pystac.Catalog(id='test', description='test desc') - href = strategy.get_href(cat, parent_dir='http://example.com', is_root=True) - self.assertEqual(href, 'http://example.com/cat/True/test.json') + cat = pystac.Catalog(id="test", description="test desc") + href = strategy.get_href(cat, parent_dir="http://example.com", is_root=True) + self.assertEqual(href, "http://example.com/cat/True/test.json") def test_produces_fallback_layout_for_catalog(self): fallback = BestPracticesLayoutStrategy() - strategy = CustomLayoutStrategy(collection_func=self.get_custom_collection_func(), - item_func=self.get_custom_item_func(), - fallback_strategy=fallback) - cat = pystac.Catalog(id='test', description='test desc') - href = strategy.get_href(cat, parent_dir='http://example.com') - expected = fallback.get_href(cat, parent_dir='http://example.com') + strategy = CustomLayoutStrategy( + collection_func=self.get_custom_collection_func(), + item_func=self.get_custom_item_func(), + fallback_strategy=fallback, + ) + cat = pystac.Catalog(id="test", description="test desc") + href = strategy.get_href(cat, parent_dir="http://example.com") + expected = fallback.get_href(cat, parent_dir="http://example.com") self.assertEqual(href, expected) def test_produces_layout_for_collection(self): - strategy = CustomLayoutStrategy(collection_func=self.get_custom_collection_func()) + strategy = CustomLayoutStrategy( + collection_func=self.get_custom_collection_func() + ) collection = TestCases.test_case_8() - href = strategy.get_href(collection, parent_dir='http://example.com') - self.assertEqual(href, 'http://example.com/col/False/{}.json'.format(collection.id)) + href = strategy.get_href(collection, parent_dir="http://example.com") + self.assertEqual( + href, "http://example.com/col/False/{}.json".format(collection.id) + ) def test_produces_fallback_layout_for_collection(self): fallback = BestPracticesLayoutStrategy() - strategy = CustomLayoutStrategy(catalog_func=self.get_custom_catalog_func(), - item_func=self.get_custom_item_func(), - fallback_strategy=fallback) + strategy = CustomLayoutStrategy( + catalog_func=self.get_custom_catalog_func(), + item_func=self.get_custom_item_func(), + fallback_strategy=fallback, + ) collection = TestCases.test_case_8() - href = strategy.get_href(collection, parent_dir='http://example.com') - expected = fallback.get_href(collection, parent_dir='http://example.com') + href = strategy.get_href(collection, parent_dir="http://example.com") + expected = fallback.get_href(collection, parent_dir="http://example.com") self.assertEqual(href, expected) def test_produces_layout_for_item(self): strategy = CustomLayoutStrategy(item_func=self.get_custom_item_func()) collection = TestCases.test_case_8() - item = next(collection.get_all_items()) - href = strategy.get_href(item, parent_dir='http://example.com') - self.assertEqual(href, 'http://example.com/item/{}.json'.format(item.id)) + item = next(iter(collection.get_all_items())) + href = strategy.get_href(item, parent_dir="http://example.com") + self.assertEqual(href, "http://example.com/item/{}.json".format(item.id)) def test_produces_fallback_layout_for_item(self): fallback = BestPracticesLayoutStrategy() - strategy = CustomLayoutStrategy(catalog_func=self.get_custom_item_func(), - collection_func=self.get_custom_collection_func(), - fallback_strategy=fallback) + strategy = CustomLayoutStrategy( + catalog_func=self.get_custom_catalog_func(), + collection_func=self.get_custom_collection_func(), + fallback_strategy=fallback, + ) collection = TestCases.test_case_8() - item = next(collection.get_all_items()) - href = strategy.get_href(item, parent_dir='http://example.com') - expected = fallback.get_href(item, parent_dir='http://example.com') + item = next(iter(collection.get_all_items())) + href = strategy.get_href(item, parent_dir="http://example.com") + expected = fallback.get_href(item, parent_dir="http://example.com") self.assertEqual(href, expected) class TemplateLayoutStrategyTest(unittest.TestCase): - TEST_CATALOG_TEMPLATE = 'cat/${id}/${description}' - TEST_COLLECTION_TEMPLATE = 'col/${id}/${license}' - TEST_ITEM_TEMPLATE = 'item/${collection}/${id}.json' + TEST_CATALOG_TEMPLATE = "cat/${id}/${description}" + TEST_COLLECTION_TEMPLATE = "col/${id}/${license}" + TEST_ITEM_TEMPLATE = "item/${collection}/${id}.json" + + def _get_collection(self) -> Collection: + result = TestCases.test_case_4().get_child("acc") + assert isinstance(result, Collection) + return result def test_produces_layout_for_catalog(self): strategy = TemplateLayoutStrategy(catalog_template=self.TEST_CATALOG_TEMPLATE) - cat = pystac.Catalog(id='test', description='test-desc') - href = strategy.get_href(cat, parent_dir='http://example.com') - self.assertEqual(href, 'http://example.com/cat/test/test-desc/catalog.json') + cat = pystac.Catalog(id="test", description="test-desc") + href = strategy.get_href(cat, parent_dir="http://example.com") + self.assertEqual(href, "http://example.com/cat/test/test-desc/catalog.json") def test_produces_layout_for_catalog_with_filename(self): - template = 'cat/${id}/${description}/${id}.json' + template = "cat/${id}/${description}/${id}.json" strategy = TemplateLayoutStrategy(catalog_template=template) - cat = pystac.Catalog(id='test', description='test-desc') - href = strategy.get_href(cat, parent_dir='http://example.com') - self.assertEqual(href, 'http://example.com/cat/test/test-desc/test.json') + cat = pystac.Catalog(id="test", description="test-desc") + href = strategy.get_href(cat, parent_dir="http://example.com") + self.assertEqual(href, "http://example.com/cat/test/test-desc/test.json") def test_produces_fallback_layout_for_catalog(self): fallback = BestPracticesLayoutStrategy() - strategy = TemplateLayoutStrategy(collection_template=self.TEST_COLLECTION_TEMPLATE, - item_template=self.TEST_ITEM_TEMPLATE, - fallback_strategy=fallback) - cat = pystac.Catalog(id='test', description='test desc') - href = strategy.get_href(cat, parent_dir='http://example.com') - expected = fallback.get_href(cat, parent_dir='http://example.com') + strategy = TemplateLayoutStrategy( + collection_template=self.TEST_COLLECTION_TEMPLATE, + item_template=self.TEST_ITEM_TEMPLATE, + fallback_strategy=fallback, + ) + cat = pystac.Catalog(id="test", description="test desc") + href = strategy.get_href(cat, parent_dir="http://example.com") + expected = fallback.get_href(cat, parent_dir="http://example.com") self.assertEqual(href, expected) def test_produces_layout_for_collection(self): - strategy = TemplateLayoutStrategy(collection_template=self.TEST_COLLECTION_TEMPLATE) - collection = TestCases.test_case_4().get_child('acc') - href = strategy.get_href(collection, parent_dir='http://example.com') + strategy = TemplateLayoutStrategy( + collection_template=self.TEST_COLLECTION_TEMPLATE + ) + collection = self._get_collection() + href = strategy.get_href(collection, parent_dir="http://example.com") self.assertEqual( href, - 'http://example.com/col/{}/{}/collection.json'.format(collection.id, - collection.license)) + "http://example.com/col/{}/{}/collection.json".format( + collection.id, collection.license + ), + ) def test_produces_layout_for_collection_with_filename(self): - template = 'col/${id}/${license}/col.json' + template = "col/${id}/${license}/col.json" strategy = TemplateLayoutStrategy(collection_template=template) - collection = TestCases.test_case_4().get_child('acc') - href = strategy.get_href(collection, parent_dir='http://example.com') + collection = self._get_collection() + href = strategy.get_href(collection, parent_dir="http://example.com") self.assertEqual( - href, 'http://example.com/col/{}/{}/col.json'.format(collection.id, collection.license)) + href, + "http://example.com/col/{}/{}/col.json".format( + collection.id, collection.license + ), + ) def test_produces_fallback_layout_for_collection(self): fallback = BestPracticesLayoutStrategy() - strategy = TemplateLayoutStrategy(catalog_template=self.TEST_CATALOG_TEMPLATE, - item_template=self.TEST_ITEM_TEMPLATE, - fallback_strategy=fallback) - collection = TestCases.test_case_4().get_child('acc') - href = strategy.get_href(collection, parent_dir='http://example.com') - expected = fallback.get_href(collection, parent_dir='http://example.com') + strategy = TemplateLayoutStrategy( + catalog_template=self.TEST_CATALOG_TEMPLATE, + item_template=self.TEST_ITEM_TEMPLATE, + fallback_strategy=fallback, + ) + collection = self._get_collection() + href = strategy.get_href(collection, parent_dir="http://example.com") + expected = fallback.get_href(collection, parent_dir="http://example.com") self.assertEqual(href, expected) def test_produces_layout_for_item(self): strategy = TemplateLayoutStrategy(item_template=self.TEST_ITEM_TEMPLATE) - collection = TestCases.test_case_4().get_child('acc') - item = next(collection.get_all_items()) - href = strategy.get_href(item, parent_dir='http://example.com') - self.assertEqual(href, - 'http://example.com/item/{}/{}.json'.format(item.collection_id, item.id)) + collection = self._get_collection() + item = next(iter(collection.get_all_items())) + href = strategy.get_href(item, parent_dir="http://example.com") + self.assertEqual( + href, + "http://example.com/item/{}/{}.json".format(item.collection_id, item.id), + ) def test_produces_layout_for_item_without_filename(self): - template = 'item/${collection}' + template = "item/${collection}" strategy = TemplateLayoutStrategy(item_template=template) - collection = TestCases.test_case_4().get_child('acc') - item = next(collection.get_all_items()) - href = strategy.get_href(item, parent_dir='http://example.com') - self.assertEqual(href, - 'http://example.com/item/{}/{}.json'.format(item.collection_id, item.id)) + collection = self._get_collection() + item = next(iter(collection.get_all_items())) + href = strategy.get_href(item, parent_dir="http://example.com") + self.assertEqual( + href, + "http://example.com/item/{}/{}.json".format(item.collection_id, item.id), + ) def test_produces_fallback_layout_for_item(self): fallback = BestPracticesLayoutStrategy() - strategy = TemplateLayoutStrategy(catalog_template=self.TEST_CATALOG_TEMPLATE, - collection_template=self.TEST_COLLECTION_TEMPLATE, - fallback_strategy=fallback) - collection = TestCases.test_case_4().get_child('acc') - item = next(collection.get_all_items()) - href = strategy.get_href(item, parent_dir='http://example.com') - expected = fallback.get_href(item, parent_dir='http://example.com') + strategy = TemplateLayoutStrategy( + catalog_template=self.TEST_CATALOG_TEMPLATE, + collection_template=self.TEST_COLLECTION_TEMPLATE, + fallback_strategy=fallback, + ) + collection = self._get_collection() + item = next(iter(collection.get_all_items())) + href = strategy.get_href(item, parent_dir="http://example.com") + expected = fallback.get_href(item, parent_dir="http://example.com") self.assertEqual(href, expected) @@ -327,28 +375,34 @@ def setUp(self): self.strategy = BestPracticesLayoutStrategy() def test_produces_layout_for_root_catalog(self): - cat = pystac.Catalog(id='test', description='test desc') - href = self.strategy.get_href(cat, parent_dir='http://example.com', is_root=True) - self.assertEqual(href, 'http://example.com/catalog.json') + cat = pystac.Catalog(id="test", description="test desc") + href = self.strategy.get_href( + cat, parent_dir="http://example.com", is_root=True + ) + self.assertEqual(href, "http://example.com/catalog.json") def test_produces_layout_for_child_catalog(self): - cat = pystac.Catalog(id='test', description='test desc') - href = self.strategy.get_href(cat, parent_dir='http://example.com') - self.assertEqual(href, 'http://example.com/test/catalog.json') + cat = pystac.Catalog(id="test", description="test desc") + href = self.strategy.get_href(cat, parent_dir="http://example.com") + self.assertEqual(href, "http://example.com/test/catalog.json") def test_produces_layout_for_root_collection(self): collection = TestCases.test_case_8() - href = self.strategy.get_href(collection, parent_dir='http://example.com', is_root=True) - self.assertEqual(href, 'http://example.com/collection.json') + href = self.strategy.get_href( + collection, parent_dir="http://example.com", is_root=True + ) + self.assertEqual(href, "http://example.com/collection.json") def test_produces_layout_for_child_collection(self): collection = TestCases.test_case_8() - href = self.strategy.get_href(collection, parent_dir='http://example.com') - self.assertEqual(href, 'http://example.com/{}/collection.json'.format(collection.id)) + href = self.strategy.get_href(collection, parent_dir="http://example.com") + self.assertEqual( + href, "http://example.com/{}/collection.json".format(collection.id) + ) def test_produces_layout_for_item(self): collection = TestCases.test_case_8() - item = next(collection.get_all_items()) - href = self.strategy.get_href(item, parent_dir='http://example.com') - expected = 'http://example.com/{}/{}.json'.format(item.id, item.id) + item = next(iter(collection.get_all_items())) + href = self.strategy.get_href(item, parent_dir="http://example.com") + expected = "http://example.com/{}/{}.json".format(item.id, item.id) self.assertEqual(href, expected) diff --git a/tests/test_link.py b/tests/test_link.py index e9db74802..d916f1f07 100644 --- a/tests/test_link.py +++ b/tests/test_link.py @@ -2,6 +2,7 @@ import unittest import pystac +from tests.utils.test_cases import ARBITRARY_EXTENT TEST_DATETIME: datetime.datetime = datetime.datetime(2020, 3, 14, 16, 32) @@ -10,25 +11,27 @@ class LinkTest(unittest.TestCase): item: pystac.Item def setUp(self): - self.item = pystac.Item(id='test-item', - geometry=None, - bbox=None, - datetime=TEST_DATETIME, - properties={}) + self.item = pystac.Item( + id="test-item", + geometry=None, + bbox=None, + datetime=TEST_DATETIME, + properties={}, + ) def test_minimal(self): - rel = 'my rel' - target = 'https://example.com/a/b' + rel = "my rel" + target = "https://example.com/a/b" link = pystac.Link(rel, target) self.assertEqual(target, link.get_href()) self.assertEqual(target, link.get_absolute_href()) - expected_repr = f'' + expected_repr = f"" self.assertEqual(expected_repr, link.__repr__()) self.assertFalse(link.is_resolved()) - expected_dict = {'rel': rel, 'href': target} + expected_dict = {"rel": rel, "href": target} self.assertEqual(expected_dict, link.to_dict()) # Run the same tests on the clone. @@ -44,8 +47,6 @@ def test_minimal(self): # Try the modification methods. self.assertIsNone(link.owner) - link.set_owner(1) # A junk value. - self.assertEqual(1, link.owner) link.set_owner(None) self.assertIsNone(link.owner) @@ -53,79 +54,60 @@ def test_minimal(self): self.assertEqual(self.item, link.owner) def test_relative(self): - rel = 'my rel' - target = '../elsewhere' - mime_type = 'example/stac_thing' - link = pystac.Link(rel, target, mime_type, 'a title', properties={'a': 'b'}) + rel = "my rel" + target = "../elsewhere" + mime_type = "example/stac_thing" + link = pystac.Link(rel, target, mime_type, "a title", properties={"a": "b"}) expected_dict = { - 'rel': rel, - 'href': target, - 'type': 'example/stac_thing', - 'title': 'a title', - 'a': 'b' + "rel": rel, + "href": target, + "type": "example/stac_thing", + "title": "a title", + "a": "b", } self.assertEqual(expected_dict, link.to_dict()) def test_link_does_not_fail_if_href_is_none(self): """Test to ensure get_href does not fail when the href is None.""" - catalog = pystac.Catalog(id='test', description='test desc') + catalog = pystac.Catalog(id="test", description="test desc") catalog.add_item(self.item) - catalog.set_self_href('/some/href') + catalog.set_self_href("/some/href") - link = catalog.get_single_link('item') + link = catalog.get_single_link("item") self.assertIsNone(link.get_href()) def test_resolve_stac_object_no_root_and_target_is_item(self): - link = pystac.Link('my rel', target=self.item) + link = pystac.Link("my rel", target=self.item) link.resolve_stac_object() class StaticLinkTest(unittest.TestCase): def test_from_dict_round_trip(self): test_cases = [ - { - 'rel': '', - 'href': '' - }, # Not valid, but works. - { - 'rel': 'r', - 'href': 't' - }, - { - 'rel': 'r', - 'href': '/t' - }, - { - 'rel': 'r', - 'href': 't', - 'type': 'a/b', - 'title': 't', - 'c': 'd', - 1: 2 - }, + {"rel": "", "href": ""}, # Not valid, but works. + {"rel": "r", "href": "t"}, + {"rel": "r", "href": "/t"}, + {"rel": "r", "href": "t", "type": "a/b", "title": "t", "c": "d", 1: 2}, # Special case. - { - 'rel': 'self', - 'href': 't' - }, + {"rel": "self", "href": "t"}, ] for d in test_cases: d2 = pystac.Link.from_dict(d).to_dict() self.assertEqual(d, d2) def test_from_dict_failures(self): - for d in [{}, {'href': 't'}, {'rel': 'r'}]: + for d in [{}, {"href": "t"}, {"rel": "r"}]: with self.assertRaises(KeyError): pystac.Link.from_dict(d) def test_collection(self): - c = pystac.Collection('collection id', 'desc', extent=None) + c = pystac.Collection("collection id", "desc", extent=ARBITRARY_EXTENT) link = pystac.Link.collection(c) - expected = {'rel': 'collection', 'href': None, 'type': 'application/json'} + expected = {"rel": "collection", "href": None, "type": "application/json"} self.assertEqual(expected, link.to_dict()) def test_child(self): - c = pystac.Collection('collection id', 'desc', extent=None) + c = pystac.Collection("collection id", "desc", extent=ARBITRARY_EXTENT) link = pystac.Link.child(c) - expected = {'rel': 'child', 'href': None, 'type': 'application/json'} + expected = {"rel": "child", "href": None, "type": "application/json"} self.assertEqual(expected, link.to_dict()) diff --git a/tests/test_stac_io.py b/tests/test_stac_io.py new file mode 100644 index 000000000..b744ca4ee --- /dev/null +++ b/tests/test_stac_io.py @@ -0,0 +1,20 @@ +import unittest +import warnings + +from pystac.stac_io import STAC_IO +from tests.utils import TestCases + + +class StacIOTest(unittest.TestCase): + def test_stac_io_issues_warnings(self): + with warnings.catch_warnings(record=True) as w: + # Cause all warnings to always be triggered. + warnings.simplefilter("always") + # Trigger a warning. + STAC_IO.read_text( + TestCases.get_path("data-files/collections/multi-extent.json") + ) + + # Verify some things + self.assertEqual(len(w), 1) + self.assertTrue(issubclass(w[-1].category, DeprecationWarning)) diff --git a/tests/test_utils.py b/tests/test_utils.py index 4a314995f..639df2a35 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -6,26 +6,41 @@ from pystac import utils -from pystac.utils import (make_relative_href, make_absolute_href, is_absolute_href) +from pystac.utils import make_relative_href, make_absolute_href, is_absolute_href class UtilsTest(unittest.TestCase): def test_make_relative_href(self): # Test cases of (source_href, start_href, expected) test_cases = [ - ('/a/b/c/d/catalog.json', '/a/b/c/catalog.json', './d/catalog.json'), - ('/a/b/catalog.json', '/a/b/c/catalog.json', '../catalog.json'), - ('/a/catalog.json', '/a/b/c/catalog.json', '../../catalog.json'), - ('http://stacspec.org/a/b/c/d/catalog.json', 'http://stacspec.org/a/b/c/catalog.json', - './d/catalog.json'), - ('http://stacspec.org/a/b/catalog.json', 'http://stacspec.org/a/b/c/catalog.json', - '../catalog.json'), - ('http://stacspec.org/a/catalog.json', 'http://stacspec.org/a/b/c/catalog.json', - '../../catalog.json'), - ('http://stacspec.org/a/catalog.json', 'http://cogeo.org/a/b/c/catalog.json', - 'http://stacspec.org/a/catalog.json'), - ('http://stacspec.org/a/catalog.json', 'https://stacspec.org/a/b/c/catalog.json', - 'http://stacspec.org/a/catalog.json') + ("/a/b/c/d/catalog.json", "/a/b/c/catalog.json", "./d/catalog.json"), + ("/a/b/catalog.json", "/a/b/c/catalog.json", "../catalog.json"), + ("/a/catalog.json", "/a/b/c/catalog.json", "../../catalog.json"), + ( + "http://stacspec.org/a/b/c/d/catalog.json", + "http://stacspec.org/a/b/c/catalog.json", + "./d/catalog.json", + ), + ( + "http://stacspec.org/a/b/catalog.json", + "http://stacspec.org/a/b/c/catalog.json", + "../catalog.json", + ), + ( + "http://stacspec.org/a/catalog.json", + "http://stacspec.org/a/b/c/catalog.json", + "../../catalog.json", + ), + ( + "http://stacspec.org/a/catalog.json", + "http://cogeo.org/a/b/c/catalog.json", + "http://stacspec.org/a/catalog.json", + ), + ( + "http://stacspec.org/a/catalog.json", + "https://stacspec.org/a/b/c/catalog.json", + "http://stacspec.org/a/catalog.json", + ), ] for source_href, start_href, expected in test_cases: @@ -37,21 +52,48 @@ def test_make_relative_href_windows(self): try: # Test cases of (source_href, start_href, expected) test_cases = [ - ('C:\\a\\b\\c\\d\\catalog.json', 'C:\\a\\b\\c\\catalog.json', '.\\d\\catalog.json'), - ('C:\\a\\b\\catalog.json', 'C:\\a\\b\\c\\catalog.json', '..\\catalog.json'), - ('C:\\a\\catalog.json', 'C:\\a\\b\\c\\catalog.json', '..\\..\\catalog.json'), - ('a\\b\\c\\catalog.json', 'a\\b\\catalog.json', '.\\c\\catalog.json'), - ('a\\b\\catalog.json', 'a\\b\\c\\catalog.json', '..\\catalog.json'), - ('http://stacspec.org/a/b/c/d/catalog.json', - 'http://stacspec.org/a/b/c/catalog.json', './d/catalog.json'), - ('http://stacspec.org/a/b/catalog.json', 'http://stacspec.org/a/b/c/catalog.json', - '../catalog.json'), - ('http://stacspec.org/a/catalog.json', 'http://stacspec.org/a/b/c/catalog.json', - '../../catalog.json'), - ('http://stacspec.org/a/catalog.json', 'http://cogeo.org/a/b/c/catalog.json', - 'http://stacspec.org/a/catalog.json'), - ('http://stacspec.org/a/catalog.json', 'https://stacspec.org/a/b/c/catalog.json', - 'http://stacspec.org/a/catalog.json') + ( + "C:\\a\\b\\c\\d\\catalog.json", + "C:\\a\\b\\c\\catalog.json", + ".\\d\\catalog.json", + ), + ( + "C:\\a\\b\\catalog.json", + "C:\\a\\b\\c\\catalog.json", + "..\\catalog.json", + ), + ( + "C:\\a\\catalog.json", + "C:\\a\\b\\c\\catalog.json", + "..\\..\\catalog.json", + ), + ("a\\b\\c\\catalog.json", "a\\b\\catalog.json", ".\\c\\catalog.json"), + ("a\\b\\catalog.json", "a\\b\\c\\catalog.json", "..\\catalog.json"), + ( + "http://stacspec.org/a/b/c/d/catalog.json", + "http://stacspec.org/a/b/c/catalog.json", + "./d/catalog.json", + ), + ( + "http://stacspec.org/a/b/catalog.json", + "http://stacspec.org/a/b/c/catalog.json", + "../catalog.json", + ), + ( + "http://stacspec.org/a/catalog.json", + "http://stacspec.org/a/b/c/catalog.json", + "../../catalog.json", + ), + ( + "http://stacspec.org/a/catalog.json", + "http://cogeo.org/a/b/c/catalog.json", + "http://stacspec.org/a/catalog.json", + ), + ( + "http://stacspec.org/a/catalog.json", + "https://stacspec.org/a/b/c/catalog.json", + "http://stacspec.org/a/catalog.json", + ), ] for source_href, start_href, expected in test_cases: @@ -62,27 +104,41 @@ def test_make_relative_href_windows(self): def test_make_absolute_href(self): # Test cases of (source_href, start_href, expected) - test_cases = [('item.json', '/a/b/c/catalog.json', '/a/b/c/item.json'), - ('./item.json', '/a/b/c/catalog.json', '/a/b/c/item.json'), - ('./z/item.json', '/a/b/c/catalog.json', '/a/b/c/z/item.json'), - ('../item.json', '/a/b/c/catalog.json', '/a/b/item.json'), - ('item.json', 'https://stacspec.org/a/b/c/catalog.json', - 'https://stacspec.org/a/b/c/item.json'), - ('./item.json', 'https://stacspec.org/a/b/c/catalog.json', - 'https://stacspec.org/a/b/c/item.json'), - ('./z/item.json', 'https://stacspec.org/a/b/c/catalog.json', - 'https://stacspec.org/a/b/c/z/item.json'), - ('../item.json', 'https://stacspec.org/a/b/c/catalog.json', - 'https://stacspec.org/a/b/item.json')] + test_cases = [ + ("item.json", "/a/b/c/catalog.json", "/a/b/c/item.json"), + ("./item.json", "/a/b/c/catalog.json", "/a/b/c/item.json"), + ("./z/item.json", "/a/b/c/catalog.json", "/a/b/c/z/item.json"), + ("../item.json", "/a/b/c/catalog.json", "/a/b/item.json"), + ( + "item.json", + "https://stacspec.org/a/b/c/catalog.json", + "https://stacspec.org/a/b/c/item.json", + ), + ( + "./item.json", + "https://stacspec.org/a/b/c/catalog.json", + "https://stacspec.org/a/b/c/item.json", + ), + ( + "./z/item.json", + "https://stacspec.org/a/b/c/catalog.json", + "https://stacspec.org/a/b/c/z/item.json", + ), + ( + "../item.json", + "https://stacspec.org/a/b/c/catalog.json", + "https://stacspec.org/a/b/item.json", + ), + ] for source_href, start_href, expected in test_cases: actual = make_absolute_href(source_href, start_href) self.assertEqual(actual, expected) def test_make_absolute_href_on_vsitar(self): - rel_path = 'some/item.json' - cat_path = '/vsitar//tmp/catalog.tar/catalog.json' - expected = '/vsitar//tmp/catalog.tar/some/item.json' + rel_path = "some/item.json" + cat_path = "/vsitar//tmp/catalog.tar/catalog.json" + expected = "/vsitar//tmp/catalog.tar/some/item.json" self.assertEqual(expected, make_absolute_href(rel_path, cat_path)) @@ -90,19 +146,36 @@ def test_make_absolute_href_windows(self): utils._pathlib = ntpath try: # Test cases of (source_href, start_href, expected) - test_cases = [('item.json', 'C:\\a\\b\\c\\catalog.json', 'c:\\a\\b\\c\\item.json'), - ('.\\item.json', 'C:\\a\\b\\c\\catalog.json', 'c:\\a\\b\\c\\item.json'), - ('.\\z\\item.json', 'Z:\\a\\b\\c\\catalog.json', - 'z:\\a\\b\\c\\z\\item.json'), - ('..\\item.json', 'a:\\a\\b\\c\\catalog.json', 'a:\\a\\b\\item.json'), - ('item.json', 'HTTPS://stacspec.org/a/b/c/catalog.json', - 'https://stacspec.org/a/b/c/item.json'), - ('./item.json', 'https://stacspec.org/a/b/c/catalog.json', - 'https://stacspec.org/a/b/c/item.json'), - ('./z/item.json', 'https://stacspec.org/a/b/c/catalog.json', - 'https://stacspec.org/a/b/c/z/item.json'), - ('../item.json', 'https://stacspec.org/a/b/c/catalog.json', - 'https://stacspec.org/a/b/item.json')] + test_cases = [ + ("item.json", "C:\\a\\b\\c\\catalog.json", "c:\\a\\b\\c\\item.json"), + (".\\item.json", "C:\\a\\b\\c\\catalog.json", "c:\\a\\b\\c\\item.json"), + ( + ".\\z\\item.json", + "Z:\\a\\b\\c\\catalog.json", + "z:\\a\\b\\c\\z\\item.json", + ), + ("..\\item.json", "a:\\a\\b\\c\\catalog.json", "a:\\a\\b\\item.json"), + ( + "item.json", + "HTTPS://stacspec.org/a/b/c/catalog.json", + "https://stacspec.org/a/b/c/item.json", + ), + ( + "./item.json", + "https://stacspec.org/a/b/c/catalog.json", + "https://stacspec.org/a/b/c/item.json", + ), + ( + "./z/item.json", + "https://stacspec.org/a/b/c/catalog.json", + "https://stacspec.org/a/b/c/z/item.json", + ), + ( + "../item.json", + "https://stacspec.org/a/b/c/catalog.json", + "https://stacspec.org/a/b/item.json", + ), + ] for source_href, start_href, expected in test_cases: actual = make_absolute_href(source_href, start_href) @@ -112,8 +185,13 @@ def test_make_absolute_href_windows(self): def test_is_absolute_href(self): # Test cases of (href, expected) - test_cases = [('item.json', False), ('./item.json', False), ('../item.json', False), - ('/item.json', True), ('http://stacspec.org/item.json', True)] + test_cases = [ + ("item.json", False), + ("./item.json", False), + ("../item.json", False), + ("/item.json", True), + ("http://stacspec.org/item.json", True), + ] for href, expected in test_cases: actual = is_absolute_href(href) @@ -124,8 +202,13 @@ def test_is_absolute_href_windows(self): try: # Test cases of (href, expected) - test_cases = [('item.json', False), ('.\\item.json', False), ('..\\item.json', False), - ('c:\\item.json', True), ('http://stacspec.org/item.json', True)] + test_cases = [ + ("item.json", False), + (".\\item.json", False), + ("..\\item.json", False), + ("c:\\item.json", True), + ("http://stacspec.org/item.json", True), + ] for href, expected in test_cases: actual = is_absolute_href(href) @@ -135,11 +218,21 @@ def test_is_absolute_href_windows(self): def test_datetime_to_str(self): cases = ( - ('timezone naive, assume utc', datetime(2000, 1, 1), '2000-01-01T00:00:00Z'), - ('timezone aware, utc', datetime(2000, 1, 1, - tzinfo=timezone.utc), '2000-01-01T00:00:00Z'), - ('timezone aware, utc -7', datetime(2000, 1, 1, tzinfo=timezone(timedelta(hours=-7))), - '2000-01-01T00:00:00-07:00'), + ( + "timezone naive, assume utc", + datetime(2000, 1, 1), + "2000-01-01T00:00:00Z", + ), + ( + "timezone aware, utc", + datetime(2000, 1, 1, tzinfo=timezone.utc), + "2000-01-01T00:00:00Z", + ), + ( + "timezone aware, utc -7", + datetime(2000, 1, 1, tzinfo=timezone(timedelta(hours=-7))), + "2000-01-01T00:00:00-07:00", + ), ) for title, dt, expected in cases: @@ -149,9 +242,9 @@ def test_datetime_to_str(self): def test_geojson_bbox(self): # Use sample Geojson from https://en.wikipedia.org/wiki/GeoJSON - with open('tests/data-files/geojson/sample.geojson') as sample_geojson: + with open("tests/data-files/geojson/sample.geojson") as sample_geojson: all_features = json.load(sample_geojson) - geom_dicts = [f['geometry'] for f in all_features['features']] + geom_dicts = [f["geometry"] for f in all_features["features"]] for geom in geom_dicts: got = utils.geometry_to_bbox(geom) self.assertNotEqual(got, None) diff --git a/tests/test_version.py b/tests/test_version.py index 89d26f088..cc48ff1b7 100644 --- a/tests/test_version.py +++ b/tests/test_version.py @@ -6,31 +6,28 @@ class VersionTest(unittest.TestCase): + def setUp(self): + self._prev_env_version = os.environ.get("PYSTAC_STAC_VERSION_OVERRIDE") + self._prev_version = pystac.get_stac_version() + + def tearDown(self): + if self._prev_env_version is None: + os.environ.pop("PYSTAC_STAC_VERSION_OVERRIDE", None) + else: + os.environ["PYSTAC_STAC_VERSION_OVERRIDE"] = self._prev_env_version + pystac.set_stac_version(None) + def test_override_stac_version_with_environ(self): - version = os.environ.get('PYSTAC_STAC_VERSION_OVERRIDE') - try: - override_version = '1.0.0-gamma.2' - os.environ['PYSTAC_STAC_VERSION_OVERRIDE'] = override_version - cat = TestCases.test_case_1() - d = cat.to_dict() - self.assertEqual(d['stac_version'], override_version) - finally: - if version is None: - del os.environ['PYSTAC_STAC_VERSION_OVERRIDE'] - else: - os.environ['PYSTAC_STAC_VERSION_OVERRIDE'] = version + override_version = "1.0.0-gamma.2" + os.environ["PYSTAC_STAC_VERSION_OVERRIDE"] = override_version + cat = TestCases.test_case_1() + d = cat.to_dict() + self.assertEqual(d["stac_version"], override_version) def test_override_stac_version_with_call(self): - version = pystac.get_stac_version() - try: - override_version = '1.0.0-delta.2' - pystac.set_stac_version(override_version) - cat = TestCases.test_case_1() - d = cat.to_dict() - self.assertEqual(d['stac_version'], override_version) - finally: - if version == pystac.version.STACVersion.DEFAULT_STAC_VERSION: - pystac.set_stac_version(None) - else: - pystac.set_stac_version(version) + override_version = "1.0.0-delta.2" + pystac.set_stac_version(override_version) + cat = TestCases.test_case_1() + d = cat.to_dict() + self.assertEqual(d["stac_version"], override_version) diff --git a/tests/test_writing.py b/tests/test_writing.py index d5ac1d311..508896280 100644 --- a/tests/test_writing.py +++ b/tests/test_writing.py @@ -2,8 +2,7 @@ from tempfile import TemporaryDirectory import pystac -from pystac import (STAC_IO, STACObject, Collection, CatalogType, HIERARCHICAL_LINKS) -from pystac.serialization import (STACObjectType) +from pystac import Collection, CatalogType, HIERARCHICAL_LINKS from pystac.utils import is_absolute_href, make_absolute_href, make_relative_href from pystac.validation import validate_dict @@ -14,7 +13,8 @@ class STACWritingTest(unittest.TestCase): """Tests writing STACs, using JSON Schema validation, and ensure that links are correctly set to relative or absolute. """ - def validate_catalog(self, catalog): + + def validate_catalog(self, catalog: pystac.Catalog): catalog.validate() validated_count = 1 @@ -27,12 +27,12 @@ def validate_catalog(self, catalog): return validated_count - def validate_file(self, path, object_type): - d = STAC_IO.read_json(path) - return validate_dict(d, object_type) + def validate_file(self, path: str, object_type: str): + d = pystac.StacIO.default().read_json(path) + return validate_dict(d, pystac.STACObjectType(object_type)) - def validate_link_types(self, root_href, catalog_type): - def validate_asset_href_type(item, item_href, link_type): + def validate_link_types(self, root_href: str, catalog_type: pystac.CatalogType): + def validate_asset_href_type(item: pystac.Item, item_href: str): for asset in item.assets.values(): if not is_absolute_href(asset.href): is_valid = not is_absolute_href(asset.href) @@ -44,76 +44,91 @@ def validate_asset_href_type(item, item_href, link_type): else: self.assertTrue(is_valid) - def validate_item_link_type(href, link_type, should_include_self): - item_dict = STAC_IO.read_json(href) - item = STACObject.from_file(href) - rel_links = HIERARCHICAL_LINKS + pystac.STAC_EXTENSIONS.get_extended_object_links(item) + def validate_item_link_type( + href: str, link_type: str, should_include_self: bool + ): + item_dict = pystac.StacIO.default().read_json(href) + item = pystac.Item.from_file(href) + rel_links = ( + HIERARCHICAL_LINKS + + pystac.EXTENSION_HOOKS.get_extended_object_links(item) + ) for link in item.get_links(): - if not link.rel == 'self': - if link_type == 'RELATIVE' and link.rel in rel_links: - self.assertFalse(is_absolute_href(link.get_href())) + if not link.rel == "self": + if link_type == "RELATIVE" and link.rel in rel_links: + self.assertFalse(is_absolute_href(link.href)) else: - self.assertTrue(is_absolute_href(link.get_href())) + self.assertTrue(is_absolute_href(link.href)) - validate_asset_href_type(item, href, link_type) + validate_asset_href_type(item, href) - rels = set([link['rel'] for link in item_dict['links']]) - self.assertEqual('self' in rels, should_include_self) + rels = set([link["rel"] for link in item_dict["links"]]) + self.assertEqual("self" in rels, should_include_self) - def validate_catalog_link_type(href, link_type, should_include_self): - cat_dict = STAC_IO.read_json(href) - cat = STACObject.from_file(href) + def validate_catalog_link_type( + href: str, link_type: str, should_include_self: bool + ): + cat_dict = pystac.StacIO.default().read_json(href) + cat = pystac.Catalog.from_file(href) - rels = set([link['rel'] for link in cat_dict['links']]) - self.assertEqual('self' in rels, should_include_self) + rels = set([link["rel"] for link in cat_dict["links"]]) + self.assertEqual("self" in rels, should_include_self) for child_link in cat.get_child_links(): - child_href = make_absolute_href(child_link.target, href) - validate_catalog_link_type(child_href, link_type, - catalog_type == CatalogType.ABSOLUTE_PUBLISHED) + child_href = make_absolute_href(child_link.href, href) + validate_catalog_link_type( + child_href, + link_type, + catalog_type == CatalogType.ABSOLUTE_PUBLISHED, + ) for item_link in cat.get_item_links(): - item_href = make_absolute_href(item_link.target, href) - validate_item_link_type(item_href, link_type, - catalog_type == CatalogType.ABSOLUTE_PUBLISHED) + item_href = make_absolute_href(item_link.href, href) + validate_item_link_type( + item_href, link_type, catalog_type == CatalogType.ABSOLUTE_PUBLISHED + ) - link_type = 'RELATIVE' + link_type = "RELATIVE" if catalog_type == CatalogType.ABSOLUTE_PUBLISHED: - link_type = 'ABSOLUTE' + link_type = "ABSOLUTE" root_should_include_href = catalog_type in [ - CatalogType.ABSOLUTE_PUBLISHED, CatalogType.RELATIVE_PUBLISHED + CatalogType.ABSOLUTE_PUBLISHED, + CatalogType.RELATIVE_PUBLISHED, ] validate_catalog_link_type(root_href, link_type, root_should_include_href) - def do_test(self, catalog, catalog_type): + def do_test(self, catalog: pystac.Catalog, catalog_type: pystac.CatalogType): with TemporaryDirectory() as tmp_dir: catalog.normalize_hrefs(tmp_dir) self.validate_catalog(catalog) catalog.save(catalog_type=catalog_type) - root_href = catalog.get_self_href() + root_href = catalog.self_href self.validate_link_types(root_href, catalog_type) - for parent, children, items in catalog.walk(): + for parent, _, items in catalog.walk(): if issubclass(type(parent), Collection): - stac_object_type = STACObjectType.COLLECTION + stac_object_type = pystac.STACObjectType.COLLECTION else: - stac_object_type = STACObjectType.CATALOG - self.validate_file(parent.get_self_href(), stac_object_type) + stac_object_type = pystac.STACObjectType.CATALOG + self.validate_file(parent.self_href, stac_object_type) for item in items: - self.validate_file(item.get_self_href(), STACObjectType.ITEM) + self.validate_file(item.self_href, pystac.STACObjectType.ITEM) def test_testcases(self): for catalog in TestCases.all_test_catalogs(): catalog = catalog.full_copy() ctypes = [ - CatalogType.ABSOLUTE_PUBLISHED, CatalogType.RELATIVE_PUBLISHED, - CatalogType.SELF_CONTAINED + CatalogType.ABSOLUTE_PUBLISHED, + CatalogType.RELATIVE_PUBLISHED, + CatalogType.SELF_CONTAINED, ] for catalog_type in ctypes: - with self.subTest(title='Catalog {} [{}]'.format(catalog.id, catalog_type)): + with self.subTest( + title="Catalog {} [{}]".format(catalog.id, catalog_type) + ): self.do_test(catalog, catalog_type) diff --git a/tests/utils/__init__.py b/tests/utils/__init__.py index 055bc6acb..0502b15eb 100644 --- a/tests/utils/__init__.py +++ b/tests/utils/__init__.py @@ -1,16 +1,28 @@ # flake8: noqa -from tests.utils.test_cases import (TestCases, RANDOM_GEOM, RANDOM_BBOX, RANDOM_EXTENT) +from typing import Any, Dict, Type +import unittest +from tests.utils.test_cases import ( + TestCases, # type:ignore + ARBITRARY_GEOM, # type:ignore + ARBITRARY_BBOX, # type:ignore + ARBITRARY_EXTENT, # type:ignore +) from copy import deepcopy from datetime import datetime from dateutil.parser import parse -from tests.utils.stac_io_mock import MockStacIO +import pystac +from tests.utils.stac_io_mock import MockStacIO # type:ignore -def test_to_from_dict(test_class, stac_object_class, d): - def _parse_times(a_dict): +def test_to_from_dict( + test_class: unittest.TestCase, + stac_object_class: Type[pystac.STACObject], + d: Dict[str, Any], +) -> None: + def _parse_times(a_dict: Dict[str, Any]) -> None: for k, v in a_dict.items(): if isinstance(v, dict): _parse_times(v) @@ -19,7 +31,7 @@ def _parse_times(a_dict): if isinstance(vv, dict): _parse_times(vv) else: - if k == 'datetime': + if k == "datetime": if not isinstance(v, datetime): a_dict[k] = parse(v) a_dict[k] = a_dict[k].replace(microsecond=0) diff --git a/tests/utils/stac_io_mock.py b/tests/utils/stac_io_mock.py index 2ea87ce26..57904df5c 100644 --- a/tests/utils/stac_io_mock.py +++ b/tests/utils/stac_io_mock.py @@ -1,40 +1,25 @@ +from typing import Any, Union from unittest.mock import Mock -from pystac.stac_io import STAC_IO +import pystac -class MockStacIO: +class MockStacIO(pystac.StacIO): """Creates a mock that records STAC_IO calls for testing and allows clients to replace STAC_IO functionality, all within a context scope. """ - def __init__(self, read_text_method=None, write_text_method=None): - self.read_text_method = read_text_method - self.write_text_method = write_text_method - def __enter__(self): - mock = Mock() - self.old_read_text_method = STAC_IO.read_text_method - self.old_write_text_method = STAC_IO.write_text_method + def __init__(self): + self.mock = Mock() - def read_text_method(uri): - mock.read_text_method(uri) - if self.read_text_method: - return self.read_text_method(uri) - else: - return self.old_read_text_method(uri) + def read_text( + self, source: Union[str, pystac.Link], *args: Any, **kwargs: Any + ) -> str: + self.mock.read_text(source) + return pystac.StacIO.default().read_text(source) - def write_text_method(uri, txt): - mock.write_text_method(uri, txt) - if self.write_text_method: - return self.write_text_method(uri, txt) - else: - return self.old_write_text_method(uri, txt) - - STAC_IO.read_text_method = read_text_method - STAC_IO.write_text_method = write_text_method - - return mock - - def __exit__(self, type, value, traceback): - STAC_IO.read_text_method = self.old_read_text_method - STAC_IO.write_text_method = self.old_write_text_method + def write_text( + self, dest: Union[str, pystac.Link], txt: str, *args: Any, **kwargs: Any + ) -> None: + self.mock.write_text(dest, txt) + pystac.StacIO.default().write_text(dest, txt) diff --git a/tests/utils/test_cases.py b/tests/utils/test_cases.py index b5b2591a8..4faae0f6c 100644 --- a/tests/utils/test_cases.py +++ b/tests/utils/test_cases.py @@ -1,96 +1,134 @@ import os from datetime import datetime import csv +from typing import Any, Dict, List import pystac -from pystac import (Catalog, Item, Asset, Extent, TemporalExtent, SpatialExtent, MediaType, - Extensions) -from pystac.extensions.label import (LabelOverview, LabelClasses, LabelCount) +from pystac import ( + Catalog, + Collection, + Item, + Asset, + Extent, + TemporalExtent, + SpatialExtent, + MediaType, +) +from pystac.extensions.label import ( + LabelExtension, + LabelOverview, + LabelClasses, + LabelCount, + LabelType, +) TEST_LABEL_CATALOG = { - 'country-1': { - 'area-1-1': { - 'dsm': 'area-1-1_dsm.tif', - 'ortho': 'area-1-1_ortho.tif', - 'labels': 'area-1-1_labels.geojson' + "country-1": { + "area-1-1": { + "dsm": "area-1-1_dsm.tif", + "ortho": "area-1-1_ortho.tif", + "labels": "area-1-1_labels.geojson", + }, + "area-1-2": { + "dsm": "area-1-2_dsm.tif", + "ortho": "area-1-2_ortho.tif", + "labels": "area-1-2_labels.geojson", }, - 'area-1-2': { - 'dsm': 'area-1-2_dsm.tif', - 'ortho': 'area-1-2_ortho.tif', - 'labels': 'area-1-2_labels.geojson' - } }, - 'country-2': { - 'area-2-1': { - 'dsm': 'area-2-1_dsm.tif', - 'ortho': 'area-2-1_ortho.tif', - 'labels': 'area-2-1_labels.geojson' + "country-2": { + "area-2-1": { + "dsm": "area-2-1_dsm.tif", + "ortho": "area-2-1_ortho.tif", + "labels": "area-2-1_labels.geojson", + }, + "area-2-2": { + "dsm": "area-2-2_dsm.tif", + "ortho": "area-2-2_ortho.tif", + "labels": "area-2-2_labels.geojson", }, - 'area-2-2': { - 'dsm': 'area-2-2_dsm.tif', - 'ortho': 'area-2-2_ortho.tif', - 'labels': 'area-2-2_labels.geojson' - } - } + }, } -RANDOM_GEOM = { - "type": - "Polygon", - "coordinates": [[[-2.5048828125, 3.8916575492899987], [-1.9610595703125, 3.8916575492899987], - [-1.9610595703125, 4.275202171119132], [-2.5048828125, 4.275202171119132], - [-2.5048828125, 3.8916575492899987]]] +ARBITRARY_GEOM: Dict[str, Any] = { + "type": "Polygon", + "coordinates": [ + [ + [-2.5048828125, 3.8916575492899987], + [-1.9610595703125, 3.8916575492899987], + [-1.9610595703125, 4.275202171119132], + [-2.5048828125, 4.275202171119132], + [-2.5048828125, 3.8916575492899987], + ] + ], } -RANDOM_BBOX = [ - RANDOM_GEOM['coordinates'][0][0][0], RANDOM_GEOM['coordinates'][0][0][1], - RANDOM_GEOM['coordinates'][0][1][0], RANDOM_GEOM['coordinates'][0][1][1] +ARBITRARY_BBOX: List[float] = [ + ARBITRARY_GEOM["coordinates"][0][0][0], + ARBITRARY_GEOM["coordinates"][0][0][1], + ARBITRARY_GEOM["coordinates"][0][1][0], + ARBITRARY_GEOM["coordinates"][0][1][1], ] -RANDOM_EXTENT = Extent(spatial=SpatialExtent.from_coordinates(RANDOM_GEOM['coordinates']), - temporal=TemporalExtent.from_now()) # noqa: E126 +ARBITRARY_EXTENT = Extent( + spatial=SpatialExtent.from_coordinates(ARBITRARY_GEOM["coordinates"]), + temporal=TemporalExtent.from_now(), +) # noqa: E126 + + +class ExampleInfo: + def __init__( + self, + path: str, + object_type: pystac.STACObjectType, + stac_version: str, + extensions: List[str], + valid: bool, + ) -> None: + self.path = path + self.object_type = object_type + self.stac_version = stac_version + self.extensions = extensions + self.valid = valid class TestCases: @staticmethod - def get_path(rel_path): - return os.path.abspath(os.path.join(os.path.dirname(__file__), '..', rel_path)) + def get_path(rel_path: str) -> str: + return os.path.abspath(os.path.join(os.path.dirname(__file__), "..", rel_path)) @staticmethod - def get_examples_info(): - examples = [] + def get_examples_info() -> List[ExampleInfo]: + examples: List[ExampleInfo] = [] - info_path = TestCases.get_path('data-files/examples/example-info.csv') - with open(TestCases.get_path('data-files/examples/example-info.csv')) as f: + info_path = TestCases.get_path("data-files/examples/example-info.csv") + with open(TestCases.get_path("data-files/examples/example-info.csv")) as f: for row in csv.reader(f): path = os.path.abspath(os.path.join(os.path.dirname(info_path), row[0])) object_type = row[1] stac_version = row[2] - common_extensions = [] + extensions: List[str] = [] if row[3]: - common_extensions = row[3].split('|') - custom_extensions = [] - if row[4]: - custom_extensions = row[4].split('|') + extensions = row[3].split("|") valid = True - if len(row) > 5: + if len(row) > 4: # The 5th column will be "INVALID" if the example # shouldn't pass validation - valid = row[5] != 'INVALID' - - examples.append({ - 'path': path, - 'object_type': object_type, - 'stac_version': stac_version, - 'common_extensions': common_extensions, - 'custom_extensions': custom_extensions, - 'valid': valid - }) + valid = row[4] != "INVALID" + + examples.append( + ExampleInfo( + path=path, + object_type=pystac.STACObjectType(object_type), + stac_version=stac_version, + extensions=extensions, + valid=valid, + ) + ) return examples @staticmethod - def all_test_catalogs(): + def all_test_catalogs() -> List[Catalog]: return [ TestCases.test_case_1(), TestCases.test_case_2(), @@ -98,51 +136,66 @@ def all_test_catalogs(): TestCases.test_case_4(), TestCases.test_case_5(), TestCases.test_case_7(), - TestCases.test_case_8() + TestCases.test_case_8(), ] @staticmethod - def test_case_1(): - return Catalog.from_file(TestCases.get_path('data-files/catalogs/test-case-1/catalog.json')) + def test_case_1() -> Catalog: + return Catalog.from_file( + TestCases.get_path("data-files/catalogs/test-case-1/catalog.json") + ) @staticmethod - def test_case_2(): - return Catalog.from_file(TestCases.get_path('data-files/catalogs/test-case-2/catalog.json')) + def test_case_2() -> Catalog: + return Catalog.from_file( + TestCases.get_path("data-files/catalogs/test-case-2/catalog.json") + ) @staticmethod - def test_case_3(): - root_cat = Catalog(id='test3', description='test case 3 catalog', title='test case 3 title') - - image_item = Item(id='imagery-item', - geometry=RANDOM_GEOM, - bbox=RANDOM_BBOX, - datetime=datetime.utcnow(), - properties={}) - - image_item.add_asset('ortho', Asset(href='some/geotiff.tiff', media_type=MediaType.GEOTIFF)) + def test_case_3() -> Catalog: + root_cat = Catalog( + id="test3", description="test case 3 catalog", title="test case 3 title" + ) + + image_item = Item( + id="imagery-item", + geometry=ARBITRARY_GEOM, + bbox=ARBITRARY_BBOX, + datetime=datetime.utcnow(), + properties={}, + ) + + image_item.add_asset( + "ortho", Asset(href="some/geotiff.tiff", media_type=MediaType.GEOTIFF) + ) overviews = [ - LabelOverview.create('label', - counts=[LabelCount.create('one', 1), - LabelCount.create('two', 2)]) + LabelOverview.create( + "label", + counts=[LabelCount.create("one", 1), LabelCount.create("two", 2)], + ) ] - label_item = Item(id='label-items', - geometry=RANDOM_GEOM, - bbox=RANDOM_BBOX, - datetime=datetime.utcnow(), - properties={}) - - label_item.ext.enable(Extensions.LABEL) - label_item.ext.label.apply( - label_description='ML Labels', - label_type='vector', - label_properties=['label'], - label_classes=[LabelClasses.create(classes=['one', 'two'], name='label')], - label_tasks=['classification'], - label_methods=['manual'], - label_overviews=overviews) - label_item.ext.label.add_source(image_item, assets=['ortho']) + label_item = Item( + id="label-items", + geometry=ARBITRARY_GEOM, + bbox=ARBITRARY_BBOX, + datetime=datetime.utcnow(), + properties={}, + ) + + LabelExtension.add_to(label_item) + label_ext = LabelExtension.ext(label_item) + label_ext.apply( + label_description="ML Labels", + label_type=LabelType.VECTOR, + label_properties=["label"], + label_classes=[LabelClasses.create(classes=["one", "two"], name="label")], + label_tasks=["classification"], + label_methods=["manual"], + label_overviews=overviews, + ) + label_ext.add_source(image_item, assets=["ortho"]) root_cat.add_item(image_item) root_cat.add_item(label_item) @@ -154,29 +207,37 @@ def test_case_4(): """Test case that is based on a local copy of the Tier 1 dataset from DrivenData's OpenCities AI Challenge. See: https://www.drivendata.org/competitions/60/building-segmentation-disaster-resilience - """ - return Catalog.from_file(TestCases.get_path('data-files/catalogs/test-case-4/catalog.json')) + """ # noqa + return Catalog.from_file( + TestCases.get_path("data-files/catalogs/test-case-4/catalog.json") + ) @staticmethod def test_case_5(): """Based on a subset of https://cbers.stac.cloud/""" - return Catalog.from_file(TestCases.get_path('data-files/catalogs/test-case-5/catalog.json')) + return Catalog.from_file( + TestCases.get_path("data-files/catalogs/test-case-5/catalog.json") + ) @staticmethod def test_case_6(): """Based on a subset of CBERS, contains a root and 4 empty children""" return Catalog.from_file( - TestCases.get_path('data-files/catalogs/cbers-partial/catalog.json')) + TestCases.get_path("data-files/catalogs/cbers-partial/catalog.json") + ) @staticmethod def test_case_7(): """Test case 4 as STAC version 0.8.1""" return Catalog.from_file( - TestCases.get_path('data-files/catalogs/label_catalog_0_8_1/catalog.json')) + TestCases.get_path("data-files/catalogs/label_catalog-v0.8.1/catalog.json") + ) @staticmethod - def test_case_8(): + def test_case_8() -> Collection: """Planet disaster data example catalog, 1.0.0-beta.2""" - return pystac.read_file( - TestCases.get_path('data-files/catalogs/' - 'planet-example-1.0.0-beta.2/collection.json')) + return Collection.from_file( + TestCases.get_path( + "data-files/catalogs/" "planet-example-v1.0.0-beta.2/collection.json" + ) + ) diff --git a/tests/validation/test_schema_uri_map.py b/tests/validation/test_schema_uri_map.py index 285942da7..dd6954a7a 100644 --- a/tests/validation/test_schema_uri_map.py +++ b/tests/validation/test_schema_uri_map.py @@ -5,10 +5,12 @@ class SchemaUriMapTest(unittest.TestCase): - def test_gets_extension_for_old_version(self): + def test_gets_schema_uri_for_old_version(self): d = DefaultSchemaUriMap() - uri = d.get_extension_schema_uri('asset', pystac.STACObjectType.COLLECTION, '0.8.0') + uri = d.get_object_schema_uri(pystac.STACObjectType.ITEM, "0.8.0") self.assertEqual( - uri, 'https://raw.githubusercontent.com/radiantearth/stac-spec/v0.8.0/' - 'extensions/asset/json-schema/schema.json') + uri, + "https://raw.githubusercontent.com/radiantearth/stac-spec/v0.8.0/" + "item-spec/json-schema/item.json", + ) diff --git a/tests/validation/test_validate.py b/tests/validation/test_validate.py index 8b11ae193..12b8d33cb 100644 --- a/tests/validation/test_validate.py +++ b/tests/validation/test_validate.py @@ -1,6 +1,8 @@ from datetime import datetime import json import os +from typing import Any, Dict +from pystac.utils import get_opt import shutil import unittest from tempfile import TemporaryDirectory @@ -8,106 +10,118 @@ import jsonschema import pystac +import pystac.validation +from pystac.cache import CollectionCache from pystac.serialization.common_properties import merge_common_properties -from pystac.validation import STACValidationError from tests.utils import TestCases class ValidateTest(unittest.TestCase): def test_validate_current_version(self): catalog = pystac.read_file( - TestCases.get_path('data-files/catalogs/test-case-1/' - 'catalog.json')) + TestCases.get_path("data-files/catalogs/test-case-1/" "catalog.json") + ) catalog.validate() collection = pystac.read_file( - TestCases.get_path('data-files/catalogs/test-case-1/' - '/country-1/area-1-1/' - 'collection.json')) + TestCases.get_path( + "data-files/catalogs/test-case-1/" + "/country-1/area-1-1/" + "collection.json" + ) + ) collection.validate() - item = pystac.read_file(TestCases.get_path('data-files/item/sample-item.json')) + item = pystac.read_file(TestCases.get_path("data-files/item/sample-item.json")) item.validate() def test_validate_examples(self): for example in TestCases.get_examples_info(): - stac_version = example['stac_version'] - path = example['path'] - valid = example['valid'] + with self.subTest(example.path): + stac_version = example.stac_version + path = example.path + valid = example.valid - if stac_version < '0.8': - with open(path) as f: - stac_json = json.load(f) - - self.assertEqual(len(pystac.validation.validate_dict(stac_json)), 0) - else: - with self.subTest(path): + if stac_version < "0.8": with open(path) as f: stac_json = json.load(f) - # Check if common properties need to be merged - if stac_version < '1.0': - if example['object_type'] == pystac.STACObjectType.ITEM: - collection_cache = pystac.cache.CollectionCache() - merge_common_properties(stac_json, collection_cache, path) - - if valid: - pystac.validation.validate_dict(stac_json) - else: - with self.assertRaises(STACValidationError): - try: - pystac.validation.validate_dict(stac_json) - except STACValidationError as e: - self.assertIsInstance(e.source, jsonschema.ValidationError) - raise e + self.assertEqual(len(pystac.validation.validate_dict(stac_json)), 0) + else: + with self.subTest(path): + with open(path) as f: + stac_json = json.load(f) + + # Check if common properties need to be merged + if stac_version < "1.0": + if example.object_type == pystac.STACObjectType.ITEM: + collection_cache = CollectionCache() + merge_common_properties( + stac_json, collection_cache, path + ) + + if valid: + pystac.validation.validate_dict(stac_json) + else: + with self.assertRaises(pystac.STACValidationError): + try: + pystac.validation.validate_dict(stac_json) + except pystac.STACValidationError as e: + self.assertIsInstance( + e.source, jsonschema.ValidationError + ) + raise e def test_validate_error_contains_href(self): # Test that the exception message contains the HREF of the object if available. cat = TestCases.test_case_1() - item = cat.get_item('area-1-1-labels', recursive=True) + item = cat.get_item("area-1-1-labels", recursive=True) assert item.get_self_href() is not None - item.geometry = {'type': 'INVALID'} + item.geometry = {"type": "INVALID"} - with self.assertRaises(STACValidationError): + with self.assertRaises(pystac.STACValidationError): try: item.validate() - except STACValidationError as e: - self.assertTrue(item.get_self_href() in str(e)) + except pystac.STACValidationError as e: + self.assertTrue(get_opt(item.get_self_href()) in str(e)) raise e def test_validate_all(self): for test_case in TestCases.all_test_catalogs(): - catalog_href = TestCases.test_case_7().get_self_href() - stac_dict = pystac.STAC_IO.read_json(catalog_href) + catalog_href = test_case.get_self_href() + if catalog_href is not None: + stac_dict = pystac.StacIO.default().read_json(catalog_href) - pystac.validation.validate_all(stac_dict, catalog_href) + pystac.validation.validate_all(stac_dict, catalog_href) - # Modify a 0.8.1 collection in a catalog to be invalid with a since-renamed extension - # and make sure it catches the validation error. + # Modify a 0.8.1 collection in a catalog to be invalid with a + # since-renamed extension and make sure it catches the validation error. with TemporaryDirectory() as tmp_dir: - dst_dir = os.path.join(tmp_dir, 'catalog') + dst_dir = os.path.join(tmp_dir, "catalog") # Copy test case 7 to the temporary directory - catalog_href = TestCases.test_case_7().get_self_href() + catalog_href = get_opt(TestCases.test_case_7().get_self_href()) shutil.copytree(os.path.dirname(catalog_href), dst_dir) - new_cat_href = os.path.join(dst_dir, 'catalog.json') + new_cat_href = os.path.join(dst_dir, "catalog.json") # Make sure it's valid before modification - pystac.validation.validate_all(pystac.STAC_IO.read_json(new_cat_href), new_cat_href) + pystac.validation.validate_all( + pystac.StacIO.default().read_json(new_cat_href), new_cat_href + ) # Modify a contained collection to add an extension for which the # collection is invalid. - with open(os.path.join(dst_dir, 'acc/collection.json')) as f: + with open(os.path.join(dst_dir, "acc/collection.json")) as f: col = json.load(f) - col['stac_extensions'] = ['asset'] - with open(os.path.join(dst_dir, 'acc/collection.json'), 'w') as f: + col["stac_extensions"] = ["asset"] + with open(os.path.join(dst_dir, "acc/collection.json"), "w") as f: json.dump(col, f) - stac_dict = pystac.STAC_IO.read_json(new_cat_href) + stac_dict = pystac.StacIO.default().read_json(new_cat_href) - with self.assertRaises(STACValidationError): + with self.assertRaises(pystac.STACValidationError): pystac.validation.validate_all(stac_dict, new_cat_href) def test_validates_geojson_with_tuple_coordinates(self): @@ -116,18 +130,27 @@ def test_validates_geojson_with_tuple_coordinates(self): which can be produced by shapely, then the geometry still passses validation. """ - geom = { - 'type': - 'Polygon', + geom: Dict[str, Any] = { + "type": "Polygon", # Last , is required to ensure tuple creation. - 'coordinates': (((-115.305, 36.126), (-115.305, 36.128), (-115.307, 36.128), - (-115.307, 36.126), (-115.305, 36.126)), ) + "coordinates": ( + ( + (-115.305, 36.126), + (-115.305, 36.128), + (-115.307, 36.128), + (-115.307, 36.126), + (-115.305, 36.126), + ), + ), } - item = pystac.Item(id='test-item', - geometry=geom, - bbox=[-115.308, 36.126, -115.305, 36.129], - datetime=datetime.utcnow(), - properties={}) + item = pystac.Item( + id="test-item", + geometry=geom, + bbox=[-115.308, 36.126, -115.305, 36.129], + datetime=datetime.utcnow(), + properties={}, + ) - self.assertIsNone(item.validate()) + # Should not raise. + item.validate()