Conversation
|
Excellent idea! |
Cleans-up, Docstringfies Better to_dict, color parser, and post_inits Removes duplicate docstring
…MADA-project/climada_python into feature/option-appraisal-dataclasses
MeasureConfig dataclasses for serializable measure configuration.MeasureConfig dataclasses for serializable measure configuration.
|
Question: Should measures (defined by Currently, they are specific (thus configs require you to provide I see how you could want modifications of impact function to be for multiple hazards Any opinion on that? |
|
This PR is officially open for review! Review is advised after #1274 is merged. Actual changes to be reviewed are in:
|
Good question. I would then to keep it hazard type specific. But maybe best is to ask core users of the model :). |
…e/option-appraisal-dataclasses
This reverts commit 775c621.
peanutfun
left a comment
There was a problem hiding this comment.
I reviewed mostly on a technical level. Very nice code quality overall, nice class structure! I found a few issues. Sorry for the brevity 😬 ✌️
| if defined_field.default_factory is not field().default_factory: | ||
| default = defined_field.default_factory() |
There was a problem hiding this comment.
Needs from dataclasses import MISSING:
| if defined_field.default_factory is not field().default_factory: | |
| default = defined_field.default_factory() | |
| if default is MISSING: | |
| default = defined_field.default_factory() |
See https://docs.python.org/3/library/dataclasses.html#dataclasses.MISSING and https://docs.python.org/3/library/dataclasses.html#dataclasses.Field:
default, default_factory, init, repr, hash, compare, metadata, and kw_only have the identical meaning and values as they do in the field() function.
| be instantiated directly. | ||
| """ | ||
|
|
||
| def _filter_out_default_fields(self): |
There was a problem hiding this comment.
| def _filter_out_default_fields(self): | |
| def _filter_out_default_fields(self) -> dict[str, Any]: |
|
|
||
|
|
||
| @dataclass | ||
| class _ModifierConfig(ABC): |
There was a problem hiding this comment.
You do not define abstract methods, so you can omit deriving from ABC:
| class _ModifierConfig(ABC): | |
| class _ModifierConfig: |
Also, why private? Just exclude from all?
| non_defaults.pop("haz_type") | ||
| return non_defaults, defaults | ||
|
|
||
| def to_dict(self): |
There was a problem hiding this comment.
Judging from its name, I would not expect such a method to omit default values. Even if this is never used, maybe add a parameter?
| def to_dict(self): | |
| def to_dict(self, omit_default : bool = True) -> dict[str, Any]: |
| filtered = dict( | ||
| filter(lambda k: k[0] in [f.name for f in fields(cls)], to_filter.items()) | ||
| ) | ||
| return filtered |
There was a problem hiding this comment.
Dict comprehension is easier to read. Also, I am not sure if the list comprehension is evaluated once or each time the lambda runs.
| filtered = dict( | |
| filter(lambda k: k[0] in [f.name for f in fields(cls)], to_filter.items()) | |
| ) | |
| return filtered | |
| fields = [f.name for f in fields(cls)] | |
| return {key: val for key, val in to_filter.items() if key in fields} |
| freq : str, optional | ||
| Pandas offset alias defining the period length (e.g. ``"Y"`` for | ||
| yearly, ``"M"`` for monthly). Default is ``"Y"``. |
There was a problem hiding this comment.
Not sure exactly how these values are used, but Y and M are deprecated as frequencies. You need to also specify start or end, like YS or ME, see https://pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html#offset-aliases
| Destination file path. Will be created or overwritten. | ||
| """ | ||
|
|
||
| import yaml |
There was a problem hiding this comment.
Need to add a dependency, preferably ruamel.yaml. Why no top-level import?
| ``measures``. | ||
| """ | ||
|
|
||
| import yaml |
| def test_modifier_config_filter_dict_to_fields_filters_extra_keys(): | ||
| d = {"haz_type": "TC", "impf_mdd_mult": 0.5, "not_a_field": 123} | ||
| filtered = ImpfsetModifierConfig._filter_dict_to_fields(d) | ||
| assert "not_a_field" not in filtered | ||
| assert "haz_type" in filtered | ||
| assert "impf_mdd_mult" in filtered | ||
| assert filtered["haz_type"] == "TC" | ||
| assert filtered["impf_mdd_mult"] == 0.5 |
There was a problem hiding this comment.
Private methods are private also in the context of tests. Unit tests should not call private methods. A linter will also complain. Private methods must be implicitly tested via calling public methods.
| # --------------------------------------------------------------------------- | ||
| # ImpfsetModifierConfig | ||
| # --------------------------------------------------------------------------- |
There was a problem hiding this comment.
Create a class to group tests? Would make test names shorter. Pytest creates a sub-suite, grouping the tests accordingly:
class TestImpfsetModifierConfig:
def test_defaults(self):
...
def test_from_dict_roundtrip(self):
...
Changes proposed in this PR:
This PR introduces a new module defining a family of dataclasses that encode adaptation measure parameters in a serializable, declarative form. This is a preparatory step for the broader
Measure/MeasureSetrework.The objective is to retain the possibility to define measures from modifiers in addition to the upcoming system that will use python functions directly, and provide a (better) user interface for this.
no existing code is changed.
New dataclasses:
MeasureConfigtop-level configuration for a single measure, aggregating all modifier configs below.ImpfsetModifierConfigparameters for modifying impact functions (intensity, MDD, PAA scaling, optional replacement)HazardModifierConfigparameters for modifying hazard (intensity scaling, frequency cutoff, optional replacement)ExposuresModifierConfigparameters for modifying exposures (impact function remapping, zeroing regions, optional replacement)CostIncomeConfigserializable representation of cost/income cash flow parametersAll configs inherit from the abstract
_ModifierConfigbase, which provides sharedto_dict/from_dictand a__repr__that highlights non-default fields.MeasureConfigsupports full serialization to/from dict, YAML, and legacy Excel rows (from_row), which will serve as the migration path for the existing file-based I/O inMeasureSet.PR Author Checklist
develop)PR Reviewer Checklist