Skip to content

Commit fd27ec3

Browse files
Merge pull request #32 from IFRCGo/ibtracs
ibtracs initial implementation
2 parents 5da4fb8 + 610d8d2 commit fd27ec3

35 files changed

+3802
-135560
lines changed

pystac_monty/HazardProfiles.csv

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,3 +201,5 @@ SO0008,Financial shock,hazsoceco,haztypesoc,OT,
201201
,Explosion (Miscellaneous),haztechindfail,haztypetech,AC,tec-mis-exp-exp
202202
,Sudden Subsidence,hazgeoother,haztypegeohaz,OT,nat-geo-mmd-sub
203203
,Landslide,hazgeoother,haztypegeohaz,LS,nat-hyd-mmw-lan
204+
,Fire (Miscellaneous),haztechindfail,haztypetech,OT,tec-mis-fir-fir
205+
,Collapse (Industrial),haztechstrfail,haztypetech,AC,tec-ind-col-col

pystac_monty/extension.py

Lines changed: 56 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ class MontyImpactExposureCategory(StringEnum):
124124
HOUSEHOLDS = "households"
125125

126126

127-
class MontyImpactExposureCatgoryLabel(Mapping):
127+
class MontyImpactExposureCatgoryLabel(Mapping[MontyImpactExposureCategory, str]):
128128
def __init__(self) -> None:
129129
self._data = {
130130
MontyImpactExposureCategory.ALL_PEOPLE: "People (All Demographics)",
@@ -173,7 +173,7 @@ def __getitem__(self, key: MontyImpactExposureCategory) -> str:
173173
def __len__(self) -> int:
174174
return len(self._data)
175175

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

179179

@@ -208,7 +208,7 @@ class MontyImpactType(StringEnum):
208208
HIGHEST_RISK = "highest_risk"
209209

210210

211-
class MontyImpactTypeLabel(Mapping):
211+
class MontyImpactTypeLabel(Mapping[MontyImpactType, str]):
212212
def __init__(self) -> None:
213213
self._data = {
214214
MontyImpactType.UNSPECIFIED: "Unspecified",
@@ -247,7 +247,7 @@ def __getitem__(self, key: MontyImpactType) -> str:
247247
def __len__(self) -> int:
248248
return len(self._data)
249249

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

253253

@@ -266,6 +266,7 @@ def __init__(
266266
severity_unit: str | None = None,
267267
severity_label: str | None = None,
268268
estimate_type: MontyEstimateType | None = None,
269+
**kwargs: Any,
269270
) -> None:
270271
self.properties = {}
271272
self.cluster = cluster
@@ -278,6 +279,10 @@ def __init__(
278279
if estimate_type:
279280
self.estimate_type = estimate_type
280281

282+
# Add any additional properties
283+
for key, value in kwargs.items():
284+
self.properties[key] = value
285+
281286
@property
282287
def cluster(self) -> str:
283288
"""The cluster of the hazard."""
@@ -334,7 +339,33 @@ def to_dict(self) -> dict[str, Any]:
334339
def from_dict(d: dict[str, Any]) -> HazardDetail:
335340
cluster: str = get_required(d.get(HAZDET_CLUSTER_PROP), "hazard_detail", HAZDET_CLUSTER_PROP)
336341

337-
return HazardDetail(cluster)
342+
# Extract standard properties
343+
severity_value = d.get(HAZDET_SEV_VALUE_PROP)
344+
severity_unit = d.get(HAZDET_SEV_UNIT_PROP)
345+
severity_label = d.get(HAZDET_SEV_LABEL_PROP)
346+
estimate_type = d.get(HAZDET_ESTIMATE_TYPE_PROP)
347+
348+
# Create the HazardDetail with standard properties
349+
hazard_detail = HazardDetail(
350+
cluster=cluster,
351+
severity_value=severity_value,
352+
severity_unit=severity_unit,
353+
severity_label=severity_label,
354+
estimate_type=estimate_type,
355+
)
356+
357+
# Add any additional properties
358+
for key, value in d.items():
359+
if key not in [
360+
HAZDET_CLUSTER_PROP,
361+
HAZDET_SEV_VALUE_PROP,
362+
HAZDET_SEV_UNIT_PROP,
363+
HAZDET_SEV_LABEL_PROP,
364+
HAZDET_ESTIMATE_TYPE_PROP,
365+
]:
366+
hazard_detail.properties[key] = value
367+
368+
return hazard_detail
338369

339370

340371
class ImpactDetail(ABC):
@@ -351,7 +382,7 @@ def __init__(
351382
type: MontyImpactType,
352383
value: float,
353384
unit: str | None = None,
354-
estimate_type: MontyEstimateType = None,
385+
estimate_type: MontyEstimateType | None = None,
355386
) -> None:
356387
self.properties = {}
357388
self.category = category
@@ -424,11 +455,20 @@ def to_dict(self) -> dict[str, Any]:
424455

425456
@staticmethod
426457
def from_dict(d: dict[str, Any]) -> ImpactDetail:
427-
category: str = get_required(d.get(IMPDET_CATEGORY_PROP), "impact_detail", IMPDET_CATEGORY_PROP)
428-
type: str = get_required(d.get(IMPDET_TYPE_PROP), "impact_detail", IMPDET_TYPE_PROP)
458+
category_str: str = get_required(d.get(IMPDET_CATEGORY_PROP), "impact_detail", IMPDET_CATEGORY_PROP)
459+
type_str: str = get_required(d.get(IMPDET_TYPE_PROP), "impact_detail", IMPDET_TYPE_PROP)
429460
value: float = get_required(d.get(IMPDET_VALUE_PROP), "impact_detail", IMPDET_VALUE_PROP)
430461

431-
return ImpactDetail(category, type, value)
462+
# Convert strings to enum values
463+
category = MontyImpactExposureCategory(category_str)
464+
impact_type = MontyImpactType(type_str)
465+
466+
# Get optional properties
467+
unit = d.get(IMPDET_UNIT_PROP)
468+
estimate_type_str = d.get(IMPDET_ESTIMATE_TYPE_PROP)
469+
estimate_type = MontyEstimateType(estimate_type_str) if estimate_type_str else None
470+
471+
return ImpactDetail(category, impact_type, value, unit, estimate_type)
432472

433473

434474
class MontyExtension(
@@ -486,8 +526,8 @@ def correlation_id(self, v: str) -> None:
486526
self._set_property(ITEM_CORR_ID_PROP, v)
487527

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

526566
@hazard_detail.setter
@@ -530,7 +570,7 @@ def hazard_detail(self, v: HazardDetail | None) -> None:
530570
@property
531571
def impact_detail(self) -> ImpactDetail | None:
532572
"""The details of the impact."""
533-
result = map_opt(self._get_property(ITEM_IMPACT_DETAIL_PROP, dict), ImpactDetail)
573+
result = map_opt(ImpactDetail.from_dict, self._get_property(ITEM_IMPACT_DETAIL_PROP, dict))
534574
return result
535575

536576
@impact_detail.setter
@@ -540,7 +580,7 @@ def impact_detail(self, v: ImpactDetail | None) -> None:
540580
@property
541581
def episode_number(self) -> int:
542582
"""The episode number."""
543-
return self.properties.get(ITEM_EPISODE_NUMBER_PROP, 0)
583+
return self.properties.get(ITEM_EPISODE_NUMBER_PROP, 0) or 0
544584

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

577617
@staticmethod
578618
def enable_extension() -> None:
579-
pystac.extensions.ext.ItemExt.monty = property(lambda self: MontyExtension.ext(self))
619+
# Add monty property to ItemExt
620+
setattr(pystac.extensions.ext.ItemExt, "monty", property(lambda self: MontyExtension.ext(self)))
580621

581622

582623
class CollectionMontyExtension(MontyExtension[pystac.Collection]):

0 commit comments

Comments
 (0)