Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ibtracs initial implementation #32

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 56 additions & 15 deletions pystac_monty/extension.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ class MontyImpactExposureCategory(StringEnum):
HOUSEHOLDS = "households"


class MontyImpactExposureCatgoryLabel(Mapping):
class MontyImpactExposureCatgoryLabel(Mapping[MontyImpactExposureCategory, str]):
def __init__(self) -> None:
self._data = {
MontyImpactExposureCategory.ALL_PEOPLE: "People (All Demographics)",
Expand Down Expand Up @@ -173,7 +173,7 @@ def __getitem__(self, key: MontyImpactExposureCategory) -> str:
def __len__(self) -> int:
return len(self._data)

def __iter__(self) -> Iterator:
def __iter__(self) -> Iterator[MontyImpactExposureCategory]:
return iter(self._data)


Expand Down Expand Up @@ -208,7 +208,7 @@ class MontyImpactType(StringEnum):
HIGHEST_RISK = "highest_risk"


class MontyImpactTypeLabel(Mapping):
class MontyImpactTypeLabel(Mapping[MontyImpactType, str]):
def __init__(self) -> None:
self._data = {
MontyImpactType.UNSPECIFIED: "Unspecified",
Expand Down Expand Up @@ -247,7 +247,7 @@ def __getitem__(self, key: MontyImpactType) -> str:
def __len__(self) -> int:
return len(self._data)

def __iter__(self) -> Iterator:
def __iter__(self) -> Iterator[MontyImpactType]:
return iter(self._data)


Expand All @@ -266,6 +266,7 @@ def __init__(
severity_unit: str | None = None,
severity_label: str | None = None,
estimate_type: MontyEstimateType | None = None,
**kwargs: Any,
) -> None:
self.properties = {}
self.cluster = cluster
Expand All @@ -278,6 +279,10 @@ def __init__(
if estimate_type:
self.estimate_type = estimate_type

# Add any additional properties
for key, value in kwargs.items():
self.properties[key] = value

@property
def cluster(self) -> str:
"""The cluster of the hazard."""
Expand Down Expand Up @@ -334,7 +339,33 @@ def to_dict(self) -> dict[str, Any]:
def from_dict(d: dict[str, Any]) -> HazardDetail:
cluster: str = get_required(d.get(HAZDET_CLUSTER_PROP), "hazard_detail", HAZDET_CLUSTER_PROP)

return HazardDetail(cluster)
# Extract standard properties
severity_value = d.get(HAZDET_SEV_VALUE_PROP)
severity_unit = d.get(HAZDET_SEV_UNIT_PROP)
severity_label = d.get(HAZDET_SEV_LABEL_PROP)
estimate_type = d.get(HAZDET_ESTIMATE_TYPE_PROP)

# Create the HazardDetail with standard properties
hazard_detail = HazardDetail(
cluster=cluster,
severity_value=severity_value,
severity_unit=severity_unit,
severity_label=severity_label,
estimate_type=estimate_type,
)

# Add any additional properties
for key, value in d.items():
if key not in [
HAZDET_CLUSTER_PROP,
HAZDET_SEV_VALUE_PROP,
HAZDET_SEV_UNIT_PROP,
HAZDET_SEV_LABEL_PROP,
HAZDET_ESTIMATE_TYPE_PROP,
]:
hazard_detail.properties[key] = value

return hazard_detail


class ImpactDetail(ABC):
Expand All @@ -351,7 +382,7 @@ def __init__(
type: MontyImpactType,
value: float,
unit: str | None = None,
estimate_type: MontyEstimateType = None,
estimate_type: MontyEstimateType | None = None,
) -> None:
self.properties = {}
self.category = category
Expand Down Expand Up @@ -424,11 +455,20 @@ def to_dict(self) -> dict[str, Any]:

@staticmethod
def from_dict(d: dict[str, Any]) -> ImpactDetail:
category: str = get_required(d.get(IMPDET_CATEGORY_PROP), "impact_detail", IMPDET_CATEGORY_PROP)
type: str = get_required(d.get(IMPDET_TYPE_PROP), "impact_detail", IMPDET_TYPE_PROP)
category_str: str = get_required(d.get(IMPDET_CATEGORY_PROP), "impact_detail", IMPDET_CATEGORY_PROP)
type_str: str = get_required(d.get(IMPDET_TYPE_PROP), "impact_detail", IMPDET_TYPE_PROP)
value: float = get_required(d.get(IMPDET_VALUE_PROP), "impact_detail", IMPDET_VALUE_PROP)

return ImpactDetail(category, type, value)
# Convert strings to enum values
category = MontyImpactExposureCategory(category_str)
impact_type = MontyImpactType(type_str)

# Get optional properties
unit = d.get(IMPDET_UNIT_PROP)
estimate_type_str = d.get(IMPDET_ESTIMATE_TYPE_PROP)
estimate_type = MontyEstimateType(estimate_type_str) if estimate_type_str else None

return ImpactDetail(category, impact_type, value, unit, estimate_type)


class MontyExtension(
Expand Down Expand Up @@ -486,8 +526,8 @@ def correlation_id(self, v: str) -> None:
self._set_property(ITEM_CORR_ID_PROP, v)

def compute_and_set_correlation_id(self, hazard_profiles: HazardProfiles = MontyHazardProfiles()) -> None:
# if the object is an Item, we can generate the correlation id
if isinstance(self.item, pystac.Item):
# if the object is an ItemMontyExtension, we can generate the correlation id
if hasattr(self, "item") and isinstance(self.item, pystac.Item):
self.correlation_id = self.pairing.generate_correlation_id(self.item, hazard_profiles)
else:
raise ValueError("Correlation ID can only be computed for Items")
Expand Down Expand Up @@ -520,7 +560,7 @@ def hazard_codes(self, v: list[str] | None) -> None:
@property
def hazard_detail(self) -> HazardDetail | None:
"""The details of the hazard."""
result = map_opt(self._get_property(ITEM_HAZARD_DETAIL_PROP, dict), HazardDetail)
result = map_opt(HazardDetail.from_dict, self._get_property(ITEM_HAZARD_DETAIL_PROP, dict))
return result

@hazard_detail.setter
Expand All @@ -530,7 +570,7 @@ def hazard_detail(self, v: HazardDetail | None) -> None:
@property
def impact_detail(self) -> ImpactDetail | None:
"""The details of the impact."""
result = map_opt(self._get_property(ITEM_IMPACT_DETAIL_PROP, dict), ImpactDetail)
result = map_opt(ImpactDetail.from_dict, self._get_property(ITEM_IMPACT_DETAIL_PROP, dict))
return result

@impact_detail.setter
Expand All @@ -540,7 +580,7 @@ def impact_detail(self, v: ImpactDetail | None) -> None:
@property
def episode_number(self) -> int:
"""The episode number."""
return self.properties.get(ITEM_EPISODE_NUMBER_PROP, 0)
return self.properties.get(ITEM_EPISODE_NUMBER_PROP, 0) or 0

@episode_number.setter
def episode_number(self, v: int) -> None:
Expand Down Expand Up @@ -576,7 +616,8 @@ def ext(cls, obj: T, add_if_missing: bool = False) -> MontyExtension[T]:

@staticmethod
def enable_extension() -> None:
pystac.extensions.ext.ItemExt.monty = property(lambda self: MontyExtension.ext(self))
# Add monty property to ItemExt
setattr(pystac.extensions.ext.ItemExt, "monty", property(lambda self: MontyExtension.ext(self)))


class CollectionMontyExtension(MontyExtension[pystac.Collection]):
Expand Down
Loading