From 958f589a9bf0cfe03e154b884982b57e626abda8 Mon Sep 17 00:00:00 2001 From: spjuhel Date: Wed, 11 Feb 2026 17:46:51 +0100 Subject: [PATCH 1/8] Better type hints --- .../entity/impact_funcs/impact_func_set.py | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/climada/entity/impact_funcs/impact_func_set.py b/climada/entity/impact_funcs/impact_func_set.py index 030f73f2be..a67d589114 100755 --- a/climada/entity/impact_funcs/impact_func_set.py +++ b/climada/entity/impact_funcs/impact_func_set.py @@ -24,7 +24,7 @@ import copy import logging from itertools import repeat -from typing import Iterable, Optional +from typing import Dict, Iterable, Optional, Union, overload import matplotlib.pyplot as plt import numpy as np @@ -173,7 +173,23 @@ def remove_func(self, haz_type=None, fun_id=None): else: self._data = dict() - def get_func(self, haz_type=None, fun_id=None): + @overload + def get_func(self, haz_type: str, fun_id: int) -> ImpactFunc: ... + + @overload + def get_func(self, haz_type: str, fun_id: None = None) -> list[ImpactFunc]: ... + + @overload + def get_func(self, haz_type: None, fun_id: int) -> list[ImpactFunc]: ... + + @overload + def get_func( + self, haz_type: None = None, fun_id: None = None + ) -> Dict[str, Dict[int, ImpactFunc]]: ... + + def get_func( + self, haz_type: Optional[str] = None, fun_id: Optional[int] = None + ) -> Union[ImpactFunc, list[ImpactFunc], Dict[str, Dict[int, ImpactFunc]]]: """Get ImpactFunc(s) of input hazard type and/or id. If no input provided, all impact functions are returned. From 0ab9a4bac08c5068e3d045a6220f938e98a46a6f Mon Sep 17 00:00:00 2001 From: spjuhel Date: Thu, 12 Feb 2026 11:25:30 +0100 Subject: [PATCH 2/8] lost commit --- climada/entity/impact_funcs/impact_func_set.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/climada/entity/impact_funcs/impact_func_set.py b/climada/entity/impact_funcs/impact_func_set.py index a67d589114..a10a9964ca 100755 --- a/climada/entity/impact_funcs/impact_func_set.py +++ b/climada/entity/impact_funcs/impact_func_set.py @@ -119,7 +119,7 @@ def clear(self): """Reinitialize attributes.""" self._data = dict() # {hazard_type : {id:ImpactFunc}} - def append(self, func): + def append(self, func: ImpactFunc): """Append a ImpactFunc. Overwrite existing if same id and haz_type. Parameters @@ -141,7 +141,7 @@ def append(self, func): self._data[func.haz_type] = dict() self._data[func.haz_type][func.id] = func - def remove_func(self, haz_type=None, fun_id=None): + def remove_func(self, haz_type: str = None, fun_id: str | int = None): """Remove impact function(s) with provided hazard type and/or id. If no input provided, all impact functions are removed. @@ -225,7 +225,7 @@ def get_func( else: return self._data - def get_hazard_types(self, fun_id=None): + def get_hazard_types(self, fun_id: str | int) -> list[str]: """Get impact functions hazard types contained for the id provided. Return all hazard types if no input id. @@ -247,7 +247,7 @@ def get_hazard_types(self, fun_id=None): haz_types.append(vul_haz) return haz_types - def get_ids(self, haz_type=None): + def get_ids(self, haz_type: str = None) -> list[int | str]: """Get impact functions ids contained for the hazard type provided. Return all ids for each hazard type if no input hazard type. @@ -272,7 +272,7 @@ def get_ids(self, haz_type=None): except KeyError: return list() - def size(self, haz_type=None, fun_id=None): + def size(self, haz_type: str = None, fun_id: str | int = None) -> int: """Get number of impact functions contained with input hazard type and /or id. If no input provided, get total number of impact functions. @@ -316,7 +316,7 @@ def check(self): ) vul.check() - def extend(self, impact_funcs): + def extend(self, impact_funcs: ImpactFuncSet): """Append impact functions of input ImpactFuncSet to current ImpactFuncSet. Overwrite ImpactFunc if same id and haz_type. @@ -339,7 +339,7 @@ def extend(self, impact_funcs): for _, vul in vul_dict.items(): self.append(vul) - def plot(self, haz_type=None, fun_id=None, axis=None, **kwargs): + def plot(self, haz_type: str = None, fun_id: str | int = None, axis=None, **kwargs): """Plot impact functions of selected hazard (all if not provided) and selected function id (all if not provided). From afc99be2dc8005a811677885f6ca4e6eedbcaed8 Mon Sep 17 00:00:00 2001 From: spjuhel Date: Thu, 12 Feb 2026 11:27:20 +0100 Subject: [PATCH 3/8] CHANGELOG --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a50687cb23..ae9b568374 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ Code freeze date: YYYY-MM-DD ### Added +- Better type hints and overloads signatures for ImpactFuncSet [#1250](https://github.com/CLIMADA-project/climada_python/pull/1250) + ### Changed - Updated Impact Calculation Tutorial (`doc.climada_engine_Impact.ipynb`) [#1095](https://github.com/CLIMADA-project/climada_python/pull/1095). From 703e74fda0188b833c20820b77bdfb67a5a8d249 Mon Sep 17 00:00:00 2001 From: spjuhel Date: Thu, 12 Feb 2026 11:47:33 +0100 Subject: [PATCH 4/8] Remaining type hints improvements --- climada/entity/impact_funcs/base.py | 8 ++-- .../entity/impact_funcs/impact_func_set.py | 37 ++++++++++++++----- 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/climada/entity/impact_funcs/base.py b/climada/entity/impact_funcs/base.py index c51540d573..3642eed7a8 100644 --- a/climada/entity/impact_funcs/base.py +++ b/climada/entity/impact_funcs/base.py @@ -189,7 +189,7 @@ def from_step_impf( haz_type: str, mdd: tuple[float, float] = (0, 1), paa: tuple[float, float] = (1, 1), - impf_id: int = 1, + impf_id: int | str = 1, **kwargs, ): """Step function type impact function. @@ -207,7 +207,7 @@ def from_step_impf( (min, max) mdd values. The default is (0, 1) paa: tuple(float, float) (min, max) paa values. The default is (1, 1) - impf_id : int, optional, default=1 + impf_id : int|str, optional, default=1 impact function id kwargs : keyword arguments passed to ImpactFunc() @@ -250,7 +250,7 @@ def from_sigmoid_impf( k: float, x0: float, haz_type: str, - impf_id: int = 1, + impf_id: int | str = 1, **kwargs, ): r"""Sigmoid type impact function hinging on three parameter. @@ -320,7 +320,7 @@ def from_poly_s_shape( scale: float, exponent: float, haz_type: str, - impf_id: int = 1, + impf_id: int | str = 1, **kwargs, ): r"""S-shape polynomial impact function hinging on four parameter. diff --git a/climada/entity/impact_funcs/impact_func_set.py b/climada/entity/impact_funcs/impact_func_set.py index a10a9964ca..6349f1eb96 100755 --- a/climada/entity/impact_funcs/impact_func_set.py +++ b/climada/entity/impact_funcs/impact_func_set.py @@ -141,7 +141,9 @@ def append(self, func: ImpactFunc): self._data[func.haz_type] = dict() self._data[func.haz_type][func.id] = func - def remove_func(self, haz_type: str = None, fun_id: str | int = None): + def remove_func( + self, haz_type: Optional[str] = None, fun_id: Optional[str | int] = None + ): """Remove impact function(s) with provided hazard type and/or id. If no input provided, all impact functions are removed. @@ -174,13 +176,13 @@ def remove_func(self, haz_type: str = None, fun_id: str | int = None): self._data = dict() @overload - def get_func(self, haz_type: str, fun_id: int) -> ImpactFunc: ... + def get_func(self, haz_type: str, fun_id: int | str) -> ImpactFunc: ... @overload def get_func(self, haz_type: str, fun_id: None = None) -> list[ImpactFunc]: ... @overload - def get_func(self, haz_type: None, fun_id: int) -> list[ImpactFunc]: ... + def get_func(self, haz_type: None, fun_id: int | str) -> list[ImpactFunc]: ... @overload def get_func( @@ -188,7 +190,7 @@ def get_func( ) -> Dict[str, Dict[int, ImpactFunc]]: ... def get_func( - self, haz_type: Optional[str] = None, fun_id: Optional[int] = None + self, haz_type: Optional[str] = None, fun_id: Optional[int | str] = None ) -> Union[ImpactFunc, list[ImpactFunc], Dict[str, Dict[int, ImpactFunc]]]: """Get ImpactFunc(s) of input hazard type and/or id. If no input provided, all impact functions are returned. @@ -225,7 +227,7 @@ def get_func( else: return self._data - def get_hazard_types(self, fun_id: str | int) -> list[str]: + def get_hazard_types(self, fun_id: Optional[str | int]) -> list[str]: """Get impact functions hazard types contained for the id provided. Return all hazard types if no input id. @@ -247,7 +249,15 @@ def get_hazard_types(self, fun_id: str | int) -> list[str]: haz_types.append(vul_haz) return haz_types - def get_ids(self, haz_type: str = None) -> list[int | str]: + @overload + def get_ids(self, haz_type: None = None) -> dict[str, list[str | int]]: ... + + @overload + def get_ids(self, haz_type: str) -> list[int | str]: ... + + def get_ids( + self, haz_type: Optional[str] = None + ) -> dict[str, list[str | int]] | list[int | str]: """Get impact functions ids contained for the hazard type provided. Return all ids for each hazard type if no input hazard type. @@ -272,7 +282,9 @@ def get_ids(self, haz_type: str = None) -> list[int | str]: except KeyError: return list() - def size(self, haz_type: str = None, fun_id: str | int = None) -> int: + def size( + self, haz_type: Optional[str] = None, fun_id: Optional[str | int] = None + ) -> int: """Get number of impact functions contained with input hazard type and /or id. If no input provided, get total number of impact functions. @@ -295,6 +307,7 @@ def size(self, haz_type: str = None, fun_id: str | int = None) -> int: return 1 if (haz_type is not None) or (fun_id is not None): return len(self.get_func(haz_type, fun_id)) + return sum(len(vul_list) for vul_list in self.get_ids().values()) def check(self): @@ -316,7 +329,7 @@ def check(self): ) vul.check() - def extend(self, impact_funcs: ImpactFuncSet): + def extend(self, impact_funcs: "ImpactFuncSet"): """Append impact functions of input ImpactFuncSet to current ImpactFuncSet. Overwrite ImpactFunc if same id and haz_type. @@ -339,7 +352,13 @@ def extend(self, impact_funcs: ImpactFuncSet): for _, vul in vul_dict.items(): self.append(vul) - def plot(self, haz_type: str = None, fun_id: str | int = None, axis=None, **kwargs): + def plot( + self, + haz_type: Optional[str] = None, + fun_id: Optional[str | int] = None, + axis=None, + **kwargs, + ): """Plot impact functions of selected hazard (all if not provided) and selected function id (all if not provided). From 2b035a09fc2af52e02752c5d744853201020b54c Mon Sep 17 00:00:00 2001 From: spjuhel Date: Thu, 12 Feb 2026 11:55:08 +0100 Subject: [PATCH 5/8] Remaining error in hint --- climada/entity/impact_funcs/impact_func_set.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/climada/entity/impact_funcs/impact_func_set.py b/climada/entity/impact_funcs/impact_func_set.py index 6349f1eb96..962f718405 100755 --- a/climada/entity/impact_funcs/impact_func_set.py +++ b/climada/entity/impact_funcs/impact_func_set.py @@ -187,11 +187,13 @@ def get_func(self, haz_type: None, fun_id: int | str) -> list[ImpactFunc]: ... @overload def get_func( self, haz_type: None = None, fun_id: None = None - ) -> Dict[str, Dict[int, ImpactFunc]]: ... + ) -> Dict[str, Dict[Union[int, str], ImpactFunc]]: ... def get_func( self, haz_type: Optional[str] = None, fun_id: Optional[int | str] = None - ) -> Union[ImpactFunc, list[ImpactFunc], Dict[str, Dict[int, ImpactFunc]]]: + ) -> Union[ + ImpactFunc, list[ImpactFunc], Dict[str, Dict[Union[int, str], ImpactFunc]] + ]: """Get ImpactFunc(s) of input hazard type and/or id. If no input provided, all impact functions are returned. From b04dc1f4310b56f1398cd986861cc549850b1afd Mon Sep 17 00:00:00 2001 From: spjuhel Date: Thu, 12 Feb 2026 13:11:03 +0100 Subject: [PATCH 6/8] Oupsi --- climada/entity/impact_funcs/impact_func_set.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/climada/entity/impact_funcs/impact_func_set.py b/climada/entity/impact_funcs/impact_func_set.py index 962f718405..fefbd54737 100755 --- a/climada/entity/impact_funcs/impact_func_set.py +++ b/climada/entity/impact_funcs/impact_func_set.py @@ -229,7 +229,7 @@ def get_func( else: return self._data - def get_hazard_types(self, fun_id: Optional[str | int]) -> list[str]: + def get_hazard_types(self, fun_id: Optional[str | int] = None) -> list[str]: """Get impact functions hazard types contained for the id provided. Return all hazard types if no input id. From 6b62ad8fe6df71d167e7384d69d05c31201d2402 Mon Sep 17 00:00:00 2001 From: Lukas Riedel <34276446+peanutfun@users.noreply.github.com> Date: Fri, 13 Feb 2026 12:21:43 +0100 Subject: [PATCH 7/8] Reorder overloads, as order matters --- climada/entity/impact_funcs/impact_func_set.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/climada/entity/impact_funcs/impact_func_set.py b/climada/entity/impact_funcs/impact_func_set.py index fefbd54737..2a0a357fae 100755 --- a/climada/entity/impact_funcs/impact_func_set.py +++ b/climada/entity/impact_funcs/impact_func_set.py @@ -176,18 +176,22 @@ def remove_func( self._data = dict() @overload - def get_func(self, haz_type: str, fun_id: int | str) -> ImpactFunc: ... + def get_func( + self, haz_type: None = None, fun_id: None = None + ) -> Dict[str, Dict[Union[int, str], ImpactFunc]]: ... @overload - def get_func(self, haz_type: str, fun_id: None = None) -> list[ImpactFunc]: ... + def get_func( + self, haz_type: None = ..., fun_id: int | str = ... + ) -> list[ImpactFunc]: ... @overload - def get_func(self, haz_type: None, fun_id: int | str) -> list[ImpactFunc]: ... + def get_func( + self, haz_type: str = ..., fun_id: None = None + ) -> list[ImpactFunc]: ... @overload - def get_func( - self, haz_type: None = None, fun_id: None = None - ) -> Dict[str, Dict[Union[int, str], ImpactFunc]]: ... + def get_func(self, haz_type: str = ..., fun_id: int | str = ...) -> ImpactFunc: ... def get_func( self, haz_type: Optional[str] = None, fun_id: Optional[int | str] = None From 8731d072fd8a8536ee79377f9f9564a57042e12a Mon Sep 17 00:00:00 2001 From: spjuhel Date: Fri, 13 Feb 2026 15:43:59 +0100 Subject: [PATCH 8/8] fix Dict --- climada/entity/impact_funcs/impact_func_set.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/climada/entity/impact_funcs/impact_func_set.py b/climada/entity/impact_funcs/impact_func_set.py index 2a0a357fae..b6f4cf73d7 100755 --- a/climada/entity/impact_funcs/impact_func_set.py +++ b/climada/entity/impact_funcs/impact_func_set.py @@ -24,7 +24,7 @@ import copy import logging from itertools import repeat -from typing import Dict, Iterable, Optional, Union, overload +from typing import Iterable, Optional, Union, overload import matplotlib.pyplot as plt import numpy as np @@ -178,7 +178,7 @@ def remove_func( @overload def get_func( self, haz_type: None = None, fun_id: None = None - ) -> Dict[str, Dict[Union[int, str], ImpactFunc]]: ... + ) -> dict[str, dict[Union[int, str], ImpactFunc]]: ... @overload def get_func( @@ -196,7 +196,7 @@ def get_func(self, haz_type: str = ..., fun_id: int | str = ...) -> ImpactFunc: def get_func( self, haz_type: Optional[str] = None, fun_id: Optional[int | str] = None ) -> Union[ - ImpactFunc, list[ImpactFunc], Dict[str, Dict[Union[int, str], ImpactFunc]] + ImpactFunc, list[ImpactFunc], dict[str, dict[Union[int, str], ImpactFunc]] ]: """Get ImpactFunc(s) of input hazard type and/or id. If no input provided, all impact functions are returned.