Skip to content

Commit

Permalink
Merge pull request #139 from azavea/feature/rde/validation
Browse files Browse the repository at this point in the history
Implement validation
  • Loading branch information
lossyrob authored Aug 14, 2020
2 parents faa4174 + 2167a47 commit 7d50977
Show file tree
Hide file tree
Showing 39 changed files with 965 additions and 361 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
- Add support for Item Asset properties ([#127](https://github.com/azavea/pystac/pull/127))
- Added support for dynamically changing the STAC version via `pystac.set_stac_version` and `pystac.get_stac_version` ([#130](https://github.com/azavea/pystac/pull/130))
- Added support for prerelease versions in version comparisions for the `pystac.serialization.identify` package ([#138](https://github.com/azavea/pystac/pull/138))
- Added validation for PySTAC STACObjects as well as arbitrary STAC JSON ([#139](https://github.com/azavea/pystac/pull/139))
- Added the ability to read HTTP and HTTPS uris by default ([#139](https://github.com/azavea/pystac/pull/139))

### Changed

Expand Down
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ PySTAC can be installed from pip or the source repository.
> pip install pystac
```

if you'd like to enable the validation feature utilizing the [jsonschema](https://pypi.org/project/jsonschema/) project, install with the optional `validation` requirements:


```bash
> pip install pystac[validation]
```

From source repository:

```bash
Expand Down
77 changes: 54 additions & 23 deletions docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ STACObject is the base class for :class:`Catalog <pystac.Catalog>`, :class:`Coll
:inherited-members:
:undoc-members:

.. autoclass:: pystac.STACObjectType
:members:
:undoc-members:


Catalog Spec
------------
Expand Down Expand Up @@ -294,45 +298,72 @@ Serialization
PySTAC includes a ``pystac.serialization`` package for serialization concerns that
are used internally, but may also be useful to external tools.

merge_common_properties
~~~~~~~~~~~~~~~~~~~~~~~
Identification
~~~~~~~~~~~~~~

.. automodule:: pystac.serialization
:members: merge_common_properties
:members: identify_stac_object

indentify_stac_object
~~~~~~~~~~~~~~~~~~~~~
.. autoclass:: pystac.serialization.STACJSONDescription
:members:
:undoc-members:

.. automodule:: pystac.serialization
:members: identify_stac_object
.. autoclass:: pystac.serialization.STACVersionRange
:members:
:undoc-members:

.. autoclass:: pystac.serialization.STACVersionID
:members:
:undoc-members:


Migration
~~~~~~~~~

.. automodule:: pystac.serialization.migrate
:members: migrate_to_latest

indentify_stac_object_type
~~~~~~~~~~~~~~~~~~~~~~~~~~
Common Properties
~~~~~~~~~~~~~~~~~

.. automodule:: pystac.serialization
:members: identify_stac_object_type
:members: merge_common_properties


STACJSONDescription
~~~~~~~~~~~~~~~~~~~
Validation
----------

.. autoclass:: pystac.serialization.STACJSONDescription
:members:
:undoc-members:
pystac.validation
~~~~~~~~~~~~~~~~~

STACVersionRange
~~~~~~~~~~~~~~~~
PySTAC includes a ``pystac.validation`` package for validating STAC objects, including
from PySTAC objects and directly from JSON.

.. autoclass:: pystac.serialization.STACVersionRange
.. automodule:: pystac.validation
:members: validate, validate_dict, set_validator, STACValidationError

STACValidator
~~~~~~~~~~~~~

.. autoclass:: pystac.validation.STACValidator
:members:
:undoc-members:

STACObjectType
~~~~~~~~~~~~~~
.. autoclass:: pystac.validation.JsonSchemaSTACValidator
:members:

SchemaUriMap
~~~~~~~~~~~~

A ``SchemaMapUri`` defines methods for mapping STAC versions, object types and extension ids to
schema URIs. A default implementation is included that uses known locations; however users
can provide their own schema URI maps in a :class:`~pystac.validation.JsonSchemaSTACValidator`
to modify the URIs used.

.. autoclass:: pystac.serialization.STACObjectType
.. autoclass:: pystac.validation.SchemaUriMap
:members:

.. autoclass:: pystac.validation.schema_uri_map.DefaultSchemaUriMap
:members:
:undoc-members:


PySTAC Internal Classes
Expand Down
55 changes: 53 additions & 2 deletions docs/concepts.rst
Original file line number Diff line number Diff line change
Expand Up @@ -220,11 +220,62 @@ If you are only going to read from another source, e.g. HTTP, you could only rep
STAC_IO.read_text_method = my_read_method
Validation
==========

PySTAC includes validation functionality that allows users to validate PySTAC objects as well JSON-encoded STAC objects from STAC versions `0.8.0` and later.

Enabling validation
-------------------

To enable the validation feature you'll need to have installed PySTAC with the optional dependency via:

.. code-block:: bash
> pip install pystac[validation]
This installs the ``jsonschema`` package which is used with the default validator. If you
define your own validation class as described below, you are not required to have this
extra dependency.

Validating PySTAC objects
-------------------------

You can validate any :class:`~pystac.Catalog`, :class:`~pystac.Collection` or :class:`~pystac.Item` by calling the :meth:`~pystac.STACObject.validate` method:

.. code-block:: python
item.validate()
This will validate against the latest set of JSON schemas hosted at https://schemas.stacspec.org, including any extensions that the object extends. If there are validation errors, a :class:`~pystac.validation.STACValidationError` will be raised.

Validating STAC JSON
--------------------

You can validate STAC JSON represented as a ``dict`` using the :meth:`pystac.validation.validate_json` method:

.. code-block:: python
import json
from pystac.validation import validate_json
with open('/path/to/item.json') as f:
js = json.load(f)
validate_json(js)
Using your own validator
------------------------

By default PySTAC uses the :class:`~pystac.validation.JsonSchemaSTACValidator` implementation for validation. Users can define their own implementations of :class:`~pystac.validation.STACValidator` and register it with pystac using :meth:`pystac.validation.set_validator`.

The :class:`~pystac.validation.JsonSchemaSTACValidator` takes a :class:`~pystac.validation.SchemaUriMap`, which by default uses the :class:`~pystac.validation.schema_uri_map.DefaultSchemaUriMap`. If desirable, users cn create their own implementation of :class:`~pystac.validation.SchemaUriMap` and register a new instance of :class:`~pystac.validation.JsonSchemaSTACValidator` using that schema map with :meth:`pystac.validation.set_validator`.


Extensions
==========

Accessing Extension functionality
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
---------------------------------

All STAC objects are accessed through ``Catalog``, ``Collection`` and ``Item``, and all extension functionality
is accessed through the ``ext`` property on those objects. For instance, to access the band information
Expand Down Expand Up @@ -277,7 +328,7 @@ If you attempt to retrieve an extension wrapper for an extension that the object
throw a `pystac.extensions.ExtensionError`.

Enabling an extension
~~~~~~~~~~~~~~~~~~~~~
---------------------

You'll need to enable an extension on an object before using it. For example, if you are creating an Item and want to
apply the label extension, you can do so in two ways.
Expand Down
67 changes: 67 additions & 0 deletions docs/quickstart.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,73 @@
" print(' Assets: {}'.format(item.assets))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Validating\n",
"\n",
"If we have `jsonschema` installed, either manually or via installing PySTAC with the optional validation dependencies installed:\n",
"\n",
"```\n",
"> pip install pystac[validation]\n",
"```\n",
"\n",
"we can validate our STAC objects to ensure we didn't set any properties that break the spec:"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {},
"outputs": [],
"source": [
"for root, _, items in local_root_2.walk():\n",
" root.validate()\n",
" for item in items:\n",
" item.validate()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If we have set something wrong, we'll get a `STACValidationException` when we validate:"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {},
"outputs": [
{
"ename": "STACValidationError",
"evalue": "Validation failed against schema at https://schemas.stacspec.org/v1.0.0-beta.2/item-spec/json-schema/item.json for STAC ITEM",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mValidationError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m~/proj/stac/pystac/venv/lib/python3.6/site-packages/pystac-0.5.0rc1-py3.6.egg/pystac/validation/stac_validator.py\u001b[0m in \u001b[0;36mvalidate_core\u001b[0;34m(self, stac_dict, stac_object_type, stac_version)\u001b[0m\n\u001b[1;32m 131\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 132\u001b[0;31m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_validate_from_uri\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mstac_dict\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mschema_uri\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 133\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mschema_uri\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m~/proj/stac/pystac/venv/lib/python3.6/site-packages/pystac-0.5.0rc1-py3.6.egg/pystac/validation/stac_validator.py\u001b[0m in \u001b[0;36m_validate_from_uri\u001b[0;34m(self, stac_dict, schema_uri)\u001b[0m\n\u001b[1;32m 105\u001b[0m \u001b[0mschema\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mresolver\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_schema_from_uri\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mschema_uri\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 106\u001b[0;31m \u001b[0mjsonschema\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvalidate\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0minstance\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mstac_dict\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mschema\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mschema\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mresolver\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mresolver\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 107\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0muri\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mresolver\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mstore\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m~/proj/stac/pystac/venv/lib/python3.6/site-packages/jsonschema/validators.py\u001b[0m in \u001b[0;36mvalidate\u001b[0;34m(instance, schema, cls, *args, **kwargs)\u001b[0m\n\u001b[1;32m 933\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0merror\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 934\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0merror\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 935\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;31mValidationError\u001b[0m: 'Not a valid bbox' is not of type 'number'\n\nFailed validating 'type' in schema[0]['properties']['bbox']['items']:\n {'type': 'number'}\n\nOn instance['bbox'][0]:\n 'Not a valid bbox'",
"\nThe above exception was the direct cause of the following exception:\n",
"\u001b[0;31mSTACValidationError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-22-09a436f4856e>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0mitem\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnext\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlocal_root_2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_all_items\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0mitem\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mbbox\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m'Not a valid bbox'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0mitem\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvalidate\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;32m~/proj/stac/pystac/venv/lib/python3.6/site-packages/pystac-0.5.0rc1-py3.6.egg/pystac/stac_object.py\u001b[0m in \u001b[0;36mvalidate\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 232\u001b[0m \u001b[0mstac_object_type\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mSTAC_OBJECT_TYPE\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 233\u001b[0m \u001b[0mstac_version\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mpystac\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_stac_version\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 234\u001b[0;31m extensions=self.stac_extensions)\n\u001b[0m\u001b[1;32m 235\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 236\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mget_root\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m~/proj/stac/pystac/venv/lib/python3.6/site-packages/pystac-0.5.0rc1-py3.6.egg/pystac/validation/__init__.py\u001b[0m in \u001b[0;36mvalidate\u001b[0;34m(stac_dict, stac_object_type, stac_version, extensions)\u001b[0m\n\u001b[1;32m 71\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 72\u001b[0m return RegisteredValidator.get_validator().validate(stac_dict, stac_object_type, stac_version,\n\u001b[0;32m---> 73\u001b[0;31m extensions)\n\u001b[0m\u001b[1;32m 74\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 75\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m~/proj/stac/pystac/venv/lib/python3.6/site-packages/pystac-0.5.0rc1-py3.6.egg/pystac/validation/stac_validator.py\u001b[0m in \u001b[0;36mvalidate\u001b[0;34m(self, stac_dict, stac_object_type, stac_version, extensions)\u001b[0m\n\u001b[1;32m 64\u001b[0m \"\"\"\n\u001b[1;32m 65\u001b[0m \u001b[0mresults\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 66\u001b[0;31m \u001b[0mcore_result\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvalidate_core\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mstac_dict\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstac_object_type\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstac_version\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 67\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mcore_result\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 68\u001b[0m \u001b[0mresults\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcore_result\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m~/proj/stac/pystac/venv/lib/python3.6/site-packages/pystac-0.5.0rc1-py3.6.egg/pystac/validation/stac_validator.py\u001b[0m in \u001b[0;36mvalidate_core\u001b[0;34m(self, stac_dict, stac_object_type, stac_version)\u001b[0m\n\u001b[1;32m 135\u001b[0m msg = 'Validation failed against schema at {} for STAC {}'.format(\n\u001b[1;32m 136\u001b[0m schema_uri, stac_object_type)\n\u001b[0;32m--> 137\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mSTACValidationError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmsg\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0msource\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0me\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0me\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 138\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 139\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mvalidate_extension\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstac_dict\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstac_object_type\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstac_version\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mextension_id\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;31mSTACValidationError\u001b[0m: Validation failed against schema at https://schemas.stacspec.org/v1.0.0-beta.2/item-spec/json-schema/item.json for STAC ITEM"
]
}
],
"source": [
"item = next(local_root_2.get_all_items())\n",
"item.bbox = ['Not a valid bbox']\n",
"item.validate()"
]
},
{
"cell_type": "code",
"execution_count": null,
Expand Down
6 changes: 4 additions & 2 deletions pystac/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,16 @@ class STACError(Exception):
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
from pystac.stac_object import (STACObject, STACObjectType)
from pystac.media_type import MediaType
from pystac.link import (Link, LinkType)
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 (STACObjectType, stac_object_from_dict)
from pystac.serialization import stac_object_from_dict

import pystac.validation

STAC_IO.stac_object_from_dict = stac_object_from_dict

Expand Down
7 changes: 5 additions & 2 deletions pystac/catalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ class Catalog(STACObject):
all links associated with this Catalog.
"""

STAC_OBJECT_TYPE = pystac.STACObjectType.CATALOG

DEFAULT_FILE_NAME = "catalog.json"
"""Default file name that will be given to this STAC object in a cononical format."""
def __init__(self,
Expand All @@ -75,15 +77,16 @@ def __init__(self,
stac_extensions=None,
extra_fields=None,
href=None):
super().__init__(stac_extensions)

self.id = id
self.description = description
self.title = title
self.stac_extensions = stac_extensions
if extra_fields is None:
self.extra_fields = {}
else:
self.extra_fields = extra_fields
self.links = []

self.add_link(Link.root(self))

if href is not None:
Expand Down
5 changes: 4 additions & 1 deletion pystac/collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import dateutil.parser
from copy import (copy, deepcopy)

from pystac import STACError
from pystac import (STACError, STACObjectType)
from pystac.catalog import Catalog
from pystac.link import Link
from pystac.utils import datetime_to_str
Expand Down Expand Up @@ -52,6 +52,9 @@ class Collection(Catalog):
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,
Expand Down
8 changes: 6 additions & 2 deletions pystac/extensions/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,19 @@ class ExtensionError(Exception):

class Extensions:
"""Enumerates the IDs of common extensions."""
ASSETS = 'asset'
CHECKSUM = 'checksum'
COLLECTION_ASSETS = 'collection-assets'
DATACUBE = 'datacube'
DATETIME_RANGE = 'datetime-range'
EO = 'eo'
ITEM_ASSETS = 'item-assets'
LABEL = 'label'
POINTCLOUD = 'pointcloud'
PROJECTION = 'projection'
SAR = 'sar'
SATELLITE = 'satellite'
SCIENTIFIC = 'scientific'
SINGLE_FILE_STAC = 'single-file-stac'
TILED_ASSETS = 'tiled-assets'
TIMESTAMPS = 'timestamps'
VERSION = 'version'
VIEW = 'view'
Loading

0 comments on commit 7d50977

Please sign in to comment.