Ejemplo n.º 1
0
    def test_gets_schema_uri_for_old_version(self) -> None:
        d = DefaultSchemaUriMap()
        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/"
            "item-spec/json-schema/item.json",
        )
Ejemplo n.º 2
0
    def __init__(self, schema_uri_map=None):
        if jsonschema is None:
            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 = {}
Ejemplo n.º 3
0
    def test_gets_extension_for_old_version(self):
        d = DefaultSchemaUriMap()
        uri = d.get_extension_schema_uri('asset',
                                         pystac.STACObjectType.COLLECTION,
                                         '0.8.0')

        self.assertEqual(
            uri,
            'https://raw.githubusercontent.com/radiantearth/stac-spec/v0.8.0/'
            'extensions/asset/json-schema/schema.json')
Ejemplo n.º 4
0
class JsonSchemaSTACValidator(STACValidator):
    """Validate STAC based on JSON Schemas.

    This validator uses JSON schemas, read from URIs provided by a
    :class:`~pystac.validation.SchemaUriMap`, to validate STAC core
    objects and extensions.

    Args:
        schema_uri_map (SchemaUriMap): The SchemaUriMap that defines where
            the validator will retrieve the JSON schemas for validation.
            Defautls to an instance of
            :class:`~pystac.validation.schema_uri_map.DefaultSchemaUriMap`

    Note:
    This class requires the ``jsonschema`` library to be installed.
    """
    def __init__(self, schema_uri_map=None):
        if jsonschema is None:
            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 = {}

    def get_schema_from_uri(self, schema_uri):
        if schema_uri not in self.schema_cache:
            s = json.loads(STAC_IO.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)

        return (schema, resolver)

    def _validate_from_uri(self, stac_dict, schema_uri):
        schema, resolver = self.get_schema_from_uri(schema_uri)
        jsonschema.validate(instance=stac_dict,
                            schema=schema,
                            resolver=resolver)
        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)
        if href is not None:
            s += 'at {} '.format(href)
        if stac_id is not None:
            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):
        """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_version (str): The version of STAC to validate the object against.
            href (str): Optional HREF of the STAC object being validated.

        Returns:
           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)

        if schema_uri is None:
            return None

        try:
            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):
        """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_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.

        Returns:
           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)

        if schema_uri is None:
            return None

        try:
            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
Ejemplo n.º 5
0
class JsonSchemaSTACValidator(STACValidator):
    """Validate STAC based on JSON Schemas.

    This validator uses JSON schemas, read from URIs provided by a
    :class:`~pystac.validation.SchemaUriMap`, to validate STAC core
    objects and extensions.

    Args:
        schema_uri_map : The SchemaUriMap that defines where
            the validator will retrieve the JSON schemas for validation.
            Defaults to an instance of
            :class:`~pystac.validation.schema_uri_map.DefaultSchemaUriMap`

    Note:
    This class requires the ``jsonschema`` library to be installed.
    """

    schema_uri_map: SchemaUriMap
    schema_cache: Dict[str, Dict[str, Any]]

    def __init__(self, schema_uri_map: Optional[SchemaUriMap] = None) -> None:
        if jsonschema is None:
            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 = {}

    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(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)

        return schema, resolver

    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)
        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: 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)
        if stac_id is not None:
            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: 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 : Dictionary that is the STAC json of the object.
            stac_object_type : The stac object type of the object encoded in
                stac_dict. One of :class:`~pystac.STACObjectType`.
            stac_version : The version of STAC to validate the object against.
            href : Optional HREF of the STAC object being validated.

        Returns:
           str: URI for the JSON schema that was validated against, or None if
               no validation occurred.
        """
        schema_uri = self.schema_uri_map.get_object_schema_uri(
            stac_object_type, stac_version)

        if schema_uri is None:
            return None

        try:
            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 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 : Dictionary that is the STAC json of the object.
            stac_object_type : The stac object type of the object encoded in
                stac_dict. One of :class:`~pystac.STACObjectType`.
            stac_version : The version of STAC to validate the object against.
            extension_id : The extension ID to validate against.
            href : Optional HREF of the STAC object being validated.

        Returns:
           str: URI for the JSON schema that was validated against, or None if
               no validation occurred.
        """
        schema_uri = extension_id

        if schema_uri is None:
            return None

        try:
            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 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