Skip to content

feat(flepimop2-op_system): adopt ModuleBase 0.3.0 API#142

Draft
jc-macdonald wants to merge 1 commit into
mainfrom
feat/141-flepimop2-modulebase
Draft

feat(flepimop2-op_system): adopt ModuleBase 0.3.0 API#142
jc-macdonald wants to merge 1 commit into
mainfrom
feat/141-flepimop2-modulebase

Conversation

@jc-macdonald
Copy link
Copy Markdown
Collaborator

Closes #141.

  • Declare module as an explicit Literal["flepimop2.system.op_system"] field instead of using the module="..." class-keyword shortcut.
  • Switch the connector's model_config to extra="forbid".
  • Add real class docstring (drop # noqa: D101).
  • Bump version to 0.3.0 and floor flepimop2 to >=0.3.0.dev0.
  • Add regression tests for ModuleBase.patch REPLACE-mode recompile, type-mismatch guard, the explicit module Literal field, and the extra=\"forbid\" constraint.
  • Update README with compatibility note and 0.3.0 changelog.

Closes #141.

- Declare `module` as an explicit `Literal["flepimop2.system.op_system"]`
  field instead of using the `module="..."` class-keyword shortcut.
- Switch the connector's `model_config` to `extra="forbid"`.
- Add real class docstring (drop `# noqa: D101`).
- Bump version to 0.3.0 and floor `flepimop2` to `>=0.3.0.dev0`.
- Add regression tests for `ModuleBase.patch` REPLACE-mode recompile,
  type-mismatch guard, the explicit `module` Literal field, and the
  `extra=\"forbid\"` constraint.
- Update README with compatibility note and 0.3.0 changelog.
@jc-macdonald jc-macdonald self-assigned this May 20, 2026
Copy link
Copy Markdown
Collaborator

@TimothyWillard TimothyWillard left a comment

Choose a reason for hiding this comment

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

I've made a few notes where I saw some things.

However, bigger picture, what's the plan here? Is this a running PR that you'll keep up to date as flepimop2 v0.3 is developed or are you planning on not doing a release of op_system and this connector until flepimop2 v0.3 is released? I just want to make sure that we're in a position where releases to op_system could be made (say additional as needed features for SMH) and I think tying op_system to an unreleased version of flepimop2 makes this challenging with trunk development. Also want to make sure reviewer time is used effectively, if the plan is to just keep this as a running branch then I think I'd rather wait to look at it until after flepimop2 v0.3 is released.

Comment on lines +73 to +88
class OpSystemSystem(SystemABC):
"""flepimop2 System adapter that compiles an inline ``op_system`` spec.

The ``module`` discriminator is declared explicitly as a
``Literal[...]`` field per the
``flepimop2`` module-authoring guide; this is equivalent to the
``module="..."`` class-keyword shortcut but makes the field visible
to static analyzers and to direct readers of the class.

The compiled RHS is built once during pydantic validation in
:meth:`model_post_init` and exposed through :meth:`step` /
:meth:`bind`. The connector accepts no extra top-level fields
(``extra="forbid"``); unknown keys must live inside ``spec`` itself.
"""

module: Literal["flepimop2.system.op_system"] = "flepimop2.system.op_system"
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
class OpSystemSystem(SystemABC):
"""flepimop2 System adapter that compiles an inline ``op_system`` spec.
The ``module`` discriminator is declared explicitly as a
``Literal[...]`` field per the
``flepimop2`` module-authoring guide; this is equivalent to the
``module="..."`` class-keyword shortcut but makes the field visible
to static analyzers and to direct readers of the class.
The compiled RHS is built once during pydantic validation in
:meth:`model_post_init` and exposed through :meth:`step` /
:meth:`bind`. The connector accepts no extra top-level fields
(``extra="forbid"``); unknown keys must live inside ``spec`` itself.
"""
module: Literal["flepimop2.system.op_system"] = "flepimop2.system.op_system"
class OpSystemSystem(SystemABC, module="op_system"):
"""flepimop2 System adapter that compiles an inline ``op_system`` spec.
The ``module`` discriminator is declared explicitly as a
``Literal[...]`` field per the
``flepimop2`` module-authoring guide; this is equivalent to the
``module="..."`` class-keyword shortcut but makes the field visible
to static analyzers and to direct readers of the class.
The compiled RHS is built once during pydantic validation in
:meth:`model_post_init` and exposed through :meth:`step` /
:meth:`bind`. The connector accepts no extra top-level fields
(``extra="forbid"``); unknown keys must live inside ``spec`` itself.
"""

https://accidda.github.io/flepimop2/0.3/development/creating-an-external-provider-package/#step-4-implement-the-npzbackend-class

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.

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.

Bit odd to explicitly reference in the public documentation why implemented a particular way. Implementation details make sense as internal comments, not public API.

Comment on lines +614 to +618
def test_patch_type_mismatch_raises(sir_spec: dict[str, object]) -> None:
"""Patching against a non-matching concrete type raises ``TypeError``."""
sys = OpSystemSystem(spec=sir_spec)
with pytest.raises(TypeError, match="module patching requires matching"):
sys.patch("not a module", conflict=PatchConflictMode.REPLACE) # type: ignore[arg-type]
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 don't think you need to test this, this is getting at the behavior of flepimop2 since OpSystemSystem does not override the patch method.

Comment on lines -79 to +96
model_config = ConfigDict(extra="allow")
model_config = ConfigDict(extra="forbid")
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.

Hmm, this might be something to think about more on the flepimop2 side. I didn't realize that the default is extra="ignore", https://pydantic.dev/docs/validation/latest/api/pydantic/config/#pydantic.config.ConfigDict.extra. Is there a strong advantage for extra="forbid" over extra="ignore"? I guess it makes it less likely for users to accidentally specify a configuration file incorrectly, but it will be more strict. Also not sure of knock on effects.

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.

the default was set to extra ignore assuming people would have custom fields we wouldn't know about. Might make sense to go back to forbid, but offer a class option akin to "module"?

Copy link
Copy Markdown
Member

@pearsonca pearsonca left a comment

Choose a reason for hiding this comment

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

Minor notes.

Comment on lines +73 to +88
class OpSystemSystem(SystemABC):
"""flepimop2 System adapter that compiles an inline ``op_system`` spec.

The ``module`` discriminator is declared explicitly as a
``Literal[...]`` field per the
``flepimop2`` module-authoring guide; this is equivalent to the
``module="..."`` class-keyword shortcut but makes the field visible
to static analyzers and to direct readers of the class.

The compiled RHS is built once during pydantic validation in
:meth:`model_post_init` and exposed through :meth:`step` /
:meth:`bind`. The connector accepts no extra top-level fields
(``extra="forbid"``); unknown keys must live inside ``spec`` itself.
"""

module: Literal["flepimop2.system.op_system"] = "flepimop2.system.op_system"
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.

Bit odd to explicitly reference in the public documentation why implemented a particular way. Implementation details make sense as internal comments, not public API.

Comment on lines -79 to +96
model_config = ConfigDict(extra="allow")
model_config = ConfigDict(extra="forbid")
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.

the default was set to extra ignore assuming people would have custom fields we wouldn't know about. Might make sense to go back to forbid, but offer a class option akin to "module"?

@jc-macdonald jc-macdonald marked this pull request as draft May 21, 2026 15:39
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.

flepimop2-op_system: track flepimop2 main (ModuleBase consolidation, .patch, patch CLI); bump pin and release 0.3.0

3 participants