Skip to content

feat: revamp config loading - #156

Draft
tobiasdiez wants to merge 3 commits into
mainfrom
config
Draft

feat: revamp config loading#156
tobiasdiez wants to merge 3 commits into
mainfrom
config

Conversation

@tobiasdiez

@tobiasdiez tobiasdiez commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Migrate from seperate per-model config files to more comprehensive config files that can be layered.

In particular:

  • Replaced YAML config files with a single TOML configuration that has shared base settings plus per-material overrides. (No strong opinion about using toml, but its the 'pythonic' config format and Python has bultin support for reading such files)
  • Added a config loader that deep-merges across multiple config layers, and then afterwards folds the model section over the base config.
  • Slightly reworked the CLI runner to use Typer in order to support repeated --config options for layered overrides and --model to specify what model to run.
    Using typer it was then also easly to add an interactive prompt when no arguments are provided to make Bennet happy.

Fixes https://github.com/pik-piam/industry_issues/issues/11.

Possible follow-ups:

  • The paths in the visualization and exports section are material-specific but actually follow the same pattern. We could remove those seperate config options by either using placeholders (eg figures_path = "data/%model%/output/figures) or use a non-configurable convention about the folder structure.
  • Make it possible to run multiple material models (at the moment either all or a single one can be selected)

Comment thread pyproject.toml
]

requires-python = ">= 3.10"
requires-python = ">= 3.12"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Python 3.12 is needed for built-in toml loader and using the type alias keyword. There are other workarounds, but the Python upgrade was the easiest. The change is aligned with https://scientific-python.org/specs/spec-0000/, but not sure what Python version convention you guys want to follow.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fine for me!

@tobiasdiez

Copy link
Copy Markdown
Contributor Author

This is a draft for now as I still want to double-check that the config is effectively the same and the model runs result in the same output.

Early feedback, especially about the new default.toml config is nonetheless appreciated.

@leonieschweiger

Copy link
Copy Markdown
Collaborator

Looks good to me, thanks Tobias!
We could probably declutter the default.toml a bit by agreeing on a visualization and export set for all materials that we would like to plot/export regularly in the team, then the material-specific sections could be shortened and this would be the standard config to run in order to check changes for all materials. In addition, everyone could have their own .toml with user-specific settings (e.g. for me, plotting plastics in more detail).

@JakobBD JakobBD left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great stuff, so helpful!!!
Thanks, it's greatly appreciated.

I have commented the point on yaml (Leonie and Bennet, please comment!), and a few nit-picky points of personal preference, and a few suggestions for further improvements.

CEMENT = "cement"


def get_model_classes():

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For lazy loading, we could have this function take the model name as an argument, and only import the needed model? Maybe in a match/case?

Comment thread remind_mfa_cement.py
@@ -1,7 +1,7 @@
# %%
from remind_mfa.common.helpers import ModelNames

@JakobBD JakobBD Jul 20, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While we're at it, this file could be deleted, along with those for the other materials.

Comment thread run_remind_mfa.py
selected_models = list(ModelNames) if selection == "all" else [selection]

for model in selected_models:
model_config = load_config(config_names, model)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's currently no option to specify a config path other than cwd/config, and no option to give paths to individual config files.

I find that behaviour fine when prompting for config files, but at least I would find it more intuituve if

uv run run_remind_mfa.py --config config/default.yaml would not return an error.

Personally, I would change the behaviour such that --config always expects the full (relative) path, while prompting looks in the config folder (could even be relative to the repo instead of cwd).

I see the downside of having to give the full path several times for several config files, but the only use case for that right now is running on the cluster for input data generation.

Comment thread run_remind_mfa.py
import logging
import yaml
import sys
from typing import Annotated, Literal

@JakobBD JakobBD Jul 20, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While we're at it, rename file to remind_mfa.py? wdyt?

Comment thread run_remind_mfa.py
def init_model(cfg: dict) -> CommonModel:
"""Choose MFA subclass and return an initialized instance."""
@app.command()
def main(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To make that more convenient, you could add a (boolean) --remind-input option, which sets all the others (config files, materials, later also scenarios).

Comment thread run_remind_mfa.py
Comment on lines +25 to +26
configure_logger()
selected_models = list(ModelNames) if selection == "all" else [selection]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would move these two lines to main(), and pass selected_models to run_remind_mfa, only calling it models there.

Comment thread config/default.toml Outdated
@@ -0,0 +1,116 @@
[base.input]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed, I would personally prefer switching back to yaml - my apologies for the miscommunication and the resulting back and forth, that was my fault!

For our deep hierarchy and nesting (I count up to 6 levels), I find the yaml indentation much easier to read than the toml dot notation. For me that outweighs toml files being somewhat more pythonic.

I don't want to decide this alone. @leonieschweiger and @bennet21 - What do you think?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also find the yaml indentation more clear and intuitive. If the advantages of toml are not big (which I cannot judge myself), I would also be in favour of keeping yaml, but I think I could adjust to both :)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JakobBD We discussed this a bit. There is no strong preference from our side to either option. Yaml has the advantage of being familiar, toml that it optionally allows to extract groups of keys to a table. We discussed that eg sankey under visualization might be better as a table/indented subgroup, while the single-value options like extrapolation.do_visualize feel cleaner in the toml dot notation than with forced indention in yaml.

toml does allow indentation, and that would be our proposal (see last commit) but going back to yaml is definitely also a fine option for us.

Comment thread pyproject.toml
]

requires-python = ">= 3.10"
requires-python = ">= 3.12"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fine for me!

@JakobBD

JakobBD commented Jul 20, 2026

Copy link
Copy Markdown
Collaborator

We could probably declutter the default.toml a bit by agreeing on a visualization and export set for all materials that we would like to plot/export regularly in the team

I agree! @leonieschweiger could you make a suggestion?

In addition, everyone could have their own .toml with user-specific settings (e.g. for me, plotting plastics in more detail).

I like the idea! We could add the folder to .gitignore, and except default.yaml and cluster.yaml?

Comment thread config/default.toml
consumption.per_capita = true
trade.do_visualize = true
sankey.do_visualize = true
sankey.plotter_args.slice_dict.e = "C"

@JakobBD JakobBD Jul 22, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
sankey.plotter_args.slice_dict.e = "C"
sankey.plotter_args.slice_dict = {"t": 2050, "e": "C"}

Comment thread config/default.toml
Comment thread config/default.toml
consumption.do_visualize = false
consumption.per_capita = false
sankey.do_visualize = false
sankey.plotter_args.slice_dict.t = 2050

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
sankey.plotter_args.slice_dict.t = 2050
sankey.plotter_args.slice_dict = {"t": 2050}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants