Source code for pystac.common_metadata
from __future__ import annotations
from datetime import datetime
from typing import TYPE_CHECKING, Any, Optional, TypeVar, cast
import pystac
from pystac import utils
from pystac.errors import STACError
if TYPE_CHECKING:
from pystac.asset import Asset
from pystac.item import Item
from pystac.provider import Provider
P = TypeVar("P")
[docs]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
this item and are optional
Args:
properties : Dictionary of attributes that is the Item's properties
"""
object: Asset | Item
"""The object from which common metadata is obtained."""
def __init__(self, object: Asset | Item):
self.object = object
def _set_field(self, prop_name: str, v: Any | None) -> None:
if hasattr(self.object, prop_name):
setattr(self.object, prop_name, v)
elif hasattr(self.object, "properties"):
item = cast(pystac.Item, self.object)
if v is None:
item.properties.pop(prop_name, None)
else:
item.properties[prop_name] = v
elif hasattr(self.object, "extra_fields") and isinstance(
self.object.extra_fields, dict
):
if v is None:
self.object.extra_fields.pop(prop_name, None)
else:
self.object.extra_fields[prop_name] = v
else:
raise pystac.STACError(f"Cannot set field {prop_name} on {self}.")
def _get_field(self, prop_name: str, _typ: type[P]) -> P | None:
if hasattr(self.object, prop_name):
return cast(Optional[P], getattr(self.object, prop_name))
elif hasattr(self.object, "properties"):
item = cast(pystac.Item, self.object)
return item.properties.get(prop_name)
elif hasattr(self.object, "extra_fields") and isinstance(
self.object.extra_fields, dict
):
return self.object.extra_fields.get(prop_name)
else:
raise STACError(f"Cannot get field {prop_name} from {self}.")
# Basics
@property
def title(self) -> str | None:
"""Gets or set the object's title."""
return self._get_field("title", str)
@title.setter
def title(self, v: str | None) -> None:
self._set_field("title", v)
@property
def description(self) -> str | None:
"""Gets or set the object's description."""
return self._get_field("description", str)
@description.setter
def description(self, v: str | None) -> None:
self._set_field("description", v)
# Date and Time Range
@property
def start_datetime(self) -> datetime | None:
"""Get or set the object's start_datetime."""
return utils.map_opt(
utils.str_to_datetime, self._get_field("start_datetime", str)
)
@start_datetime.setter
def start_datetime(self, v: datetime | None) -> None:
self._set_field("start_datetime", utils.map_opt(utils.datetime_to_str, v))
@property
def end_datetime(self) -> datetime | None:
"""Get or set the item's end_datetime."""
return utils.map_opt(
utils.str_to_datetime, self._get_field("end_datetime", str)
)
@end_datetime.setter
def end_datetime(self, v: datetime | None) -> None:
self._set_field("end_datetime", utils.map_opt(utils.datetime_to_str, v))
# License
@property
def license(self) -> str | None:
"""Get or set the current license."""
return self._get_field("license", str)
@license.setter
def license(self, v: str | None) -> None:
self._set_field("license", v)
# Providers
@property
def providers(self) -> list[Provider] | None:
"""Get or set a list of the object's providers."""
return utils.map_opt(
lambda providers: [pystac.Provider.from_dict(d) for d in providers],
self._get_field("providers", list[dict[str, Any]]),
)
@providers.setter
def providers(self, v: list[Provider] | None) -> None:
self._set_field(
"providers",
utils.map_opt(lambda providers: [p.to_dict() for p in providers], v),
)
# Instrument
@property
def platform(self) -> str | None:
"""Gets or set the object's platform attribute."""
return self._get_field("platform", str)
@platform.setter
def platform(self, v: str | None) -> None:
self._set_field("platform", v)
@property
def instruments(self) -> list[str] | None:
"""Gets or sets the names of the instruments used."""
return self._get_field("instruments", list[str])
@instruments.setter
def instruments(self, v: list[str] | None) -> None:
self._set_field("instruments", v)
@property
def constellation(self) -> str | None:
"""Gets or set the name of the constellation associate with an object."""
return self._get_field("constellation", str)
@constellation.setter
def constellation(self, v: str | None) -> None:
self._set_field("constellation", v)
@property
def mission(self) -> str | None:
"""Gets or set the name of the mission associated with an object."""
return self._get_field("mission", str)
@mission.setter
def mission(self, v: str | None) -> None:
self._set_field("mission", v)
@property
def gsd(self) -> float | None:
"""Gets or sets the Ground Sample Distance at the sensor."""
return self._get_field("gsd", float)
@gsd.setter
def gsd(self, v: float | None) -> None:
self._set_field("gsd", v)
# Metadata
@property
def created(self) -> datetime | None:
"""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.
Note:
``created`` has a different meaning depending on the type of STAC object.
On an :class:`~pystac.Item`, it refers to the creation time of the
metadata. On an :class:`~pystac.Asset`, it refers to the creation time of
the actual data linked to in :attr:`Asset.href <pystac.Asset.href`.
"""
return utils.map_opt(utils.str_to_datetime, self._get_field("created", str))
@created.setter
def created(self, v: datetime | None) -> None:
self._set_field("created", utils.map_opt(utils.datetime_to_str, v))
@property
def updated(self) -> datetime | None:
"""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:
``updated`` has a different meaning depending on the type of STAC object.
On an :class:`~pystac.Item`, it refers to the update time of the
metadata. On an :class:`~pystac.Asset`, it refers to the update time of
the actual data linked to in :attr:`Asset.href <pystac.Asset.href`.
"""
return utils.map_opt(utils.str_to_datetime, self._get_field("updated", str))
@updated.setter
def updated(self, v: datetime | None) -> None:
self._set_field("updated", utils.map_opt(utils.datetime_to_str, v))