Skip to content

Fix PEtab v2 extension config model - #506

Merged
dweindl merged 6 commits into
PEtab-dev:mainfrom
dweindl:fix/v2-extension-config
Aug 11, 2026
Merged

Fix PEtab v2 extension config model#506
dweindl merged 6 commits into
PEtab-dev:mainfrom
dweindl:fix/v2-extension-config

Conversation

@dweindl

@dweindl dweindl commented Aug 10, 2026

Copy link
Copy Markdown
Member

Summary

  • ProblemConfig.extensions was typed as list[ExtensionConfig] | dict, but only the dict branch was ever used/supported downstream (Fix petab.v2.core.ProblemConfig.extensions #474).
  • The extension config models didn't match the v2 schema: neither ExtensionConfig nor SciMLConfig had the schema-mandated required field, and the generic ExtensionConfig wrongly nested extra keys under a config field instead of allowing them directly alongside version/required. As a result, writing a problem with a sciml extension to YAML and reading it back failed schema validation.
  • Added a shared ExtensionConfig base (version, required, arbitrary extra fields allowed) in petab/v2/extensions/__init__.py; SciMLConfig now subclasses it (required defaults to True, since a SciML hybrid model is virtually always load-bearing for the problem's interpretation).
  • ProblemConfig.extensions is now dict[str, ExtensionConfig] (using SerializeAsAny so subclass-specific fields survive serialization).
  • Fixed a broken import in SciMLConfig.to_yaml() that made it crash unconditionally.
  • Problem.validate() still only warns about unsupported extensions — rejecting a problem based on an extension's required flag is left to consumers (e.g. simulators) that actually interpret the extension mathematically; libpetab-python itself doesn't.

Closes #474

Test plan

  • python -m pytest tests/v2/ — 106 passed, 1 skipped
  • pre-commit run --all-files on changed files — ruff/ruff-format clean
  • Added regression test round-tripping a sciml-extension problem through ProblemConfig.to_yaml() + schema validation
  • Added tests for generic (non-sciml) extension parsing, rejection of non-dict extensions, and unsupported-extension warning severity

🤖 Generated with Claude Code

ProblemConfig.extensions was typed as `list[ExtensionConfig] | dict`,
but only the dict branch was ever used or supported downstream. On
top of that, the extension config models didn't match the v2 schema:
neither ExtensionConfig nor SciMLConfig had the schema-mandated
`required` field, and the generic ExtensionConfig wrongly nested
extra keys under a `config` field instead of allowing them directly.
Writing a problem with a `sciml` extension to YAML and reading it
back therefore failed schema validation.

- Add a shared `ExtensionConfig` base (version, required, extra
  fields allowed) in petab/v2/extensions/__init__.py, and make
  SciMLConfig subclass it (required defaults to True, since a
  SciML hybrid model is virtually always load-bearing).
- Type `ProblemConfig.extensions` as `dict[str, ExtensionConfig]`
  with `SerializeAsAny` so subclass fields survive serialization.
- Fix a broken import in SciMLConfig.to_yaml() that made it crash
  unconditionally.
- Problem.validate() still only warns about unsupported extensions
  (rejecting based on `required` is left to consumers like
  simulators that actually interpret the extension mathematically).

Closes PEtab-dev#474

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@codecov-commenter

codecov-commenter commented Aug 10, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 75.54%. Comparing base (2fd38a7) to head (d826906).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #506      +/-   ##
==========================================
+ Coverage   75.30%   75.54%   +0.23%     
==========================================
  Files          64       65       +1     
  Lines        7353     7359       +6     
  Branches     1327     1325       -2     
==========================================
+ Hits         5537     5559      +22     
+ Misses       1310     1296      -14     
+ Partials      506      504       -2     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@dweindl
dweindl marked this pull request as ready for review August 10, 2026 10:00
@dweindl
dweindl requested a review from a team as a code owner August 10, 2026 10:00
@dweindl
dweindl requested review from BSnelling and dilpath August 10, 2026 10:00
Comment thread petab/v2/core.py Outdated

@dilpath dilpath left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks!

Comment thread petab/v2/extensions/sciml.py Outdated
Comment thread petab/v2/core.py
Comment thread petab/v2/core.py Outdated
Comment on lines +2556 to +2569
parsed_extensions = {}
for ext_name, ext_config in v.items():
if ext_name == C.EXT_ID_SCIML:
parsed_extensions[ext_name] = (
ext_config
if isinstance(ext_config, SciMLConfig)
else SciMLConfig(**ext_config)
)
else:
parsed_extensions[ext_name] = (
ext_config
if isinstance(ext_config, ExtensionConfig)
else ExtensionConfig(**ext_config)
)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Hm, could all of this be moved to a function inside petab.v2.extensions so that there is no explicit dependency on specific extensions here?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Moved.

Comment thread tests/v2/test_sciml.py
"""The `sciml` extension config, once written to YAML via
`ProblemConfig.to_yaml()`, is schema-valid and can be read back.
"""
from petab.v1.yaml import load_yaml, validate_yaml_syntax

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Strange to see petab.v1 here but fine if intended.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I am fine with moving them to a common module, but not in this PR.

dweindl and others added 4 commits August 11, 2026 16:22
Co-authored-by: Dilan Pathirana <59329744+dilpath@users.noreply.github.com>
- Revert extensions field_validator to raise ValueError instead of
  TypeError: pydantic only converts ValueError/AssertionError raised
  in a validator into a ValidationError, not TypeError, so the
  TypeError variant broke test_problem_config_extensions_rejects_non_dict
  in CI.
- Move the per-extension-ID config dispatch (sciml vs. generic) out
  of ProblemConfig._parse_extensions into
  petab.v2.extensions.parse_extension_config, so core.py no longer
  needs to import SciMLConfig or check C.EXT_ID_SCIML directly.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@dweindl
dweindl merged commit 73b680c into PEtab-dev:main Aug 11, 2026
7 checks passed
@dweindl
dweindl deleted the fix/v2-extension-config branch August 11, 2026 20:05
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.

Fix petab.v2.core.ProblemConfig.extensions

4 participants