Skip to content

feat: allow invalid output fields to be dropped instead of raising#248

Open
haneug wants to merge 2 commits into
faccts:mainfrom
haneug:feature/pydantic-greedy
Open

feat: allow invalid output fields to be dropped instead of raising#248
haneug wants to merge 2 commits into
faccts:mainfrom
haneug:feature/pydantic-greedy

Conversation

@haneug

@haneug haneug commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Closes Issues

Closes None

Description

  • Adds an optional keyword strict=True to Output.__init__() and to Output.parse() which allows to drop the fields where Pydantic validation fail when it is set to False. This way we do not switch the current behavior but have the option for a less strict output generation.

Release Notes

(Project adheres to Keep a Changelog; Every entry should start in upper-case and end with (#<pr-id>); Remove sections that don't apply)

Added

  • Output.parse(), Output.parse_property(), Output.parse_gbw(), and Output.__init__() now accept a strict parameter (default True). When set to False, output fields that fail Pydantic validation are silently set to None and a UserWarning is emitted instead of raising a ValidationError.

@haneug haneug self-assigned this Jun 2, 2026
@haneug haneug added enhancement New feature or request side output Concerning parsing ORCA output labels Jun 2, 2026
@haneug haneug marked this pull request as ready for review June 3, 2026 08:05
@haneug haneug requested a review from a team as a code owner June 3, 2026 08:05

@timmyte timmyte left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for adding this feature. That's a very good idea.

It would be great if you could generally document your code more extensively, as it does introduce new concepts, which are not trivial.

What is not clear to me: You are saying, that in non-strict mode invalid keys are set to None? But what if their default value is not None?

return handler(data)
except ValidationError as e:
# > Default is strict is set to True and the error is just raised
if (info.context or {}).get("strict", True):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

  1. Please add comments, why are you even looking for strict here.
    Please explain that you are looking for the method parameter.
  2. I would also add strict as class variable, instead of hard-coding the default here.
    So the expression turns into:
(info.context or {}).get("strict", cls.strict)

if (info.context or {}).get("strict", True):
raise
if not isinstance(data, dict):
raise

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why is the exception also raise under this condition? Please extend the code documentation here.

raise
if not isinstance(data, dict):
raise
bad_keys = {str(error["loc"][0]) for error in e.errors() if error["loc"]}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

What are bad_keys? Please add comment describing the need to check this condition here as well.

bad_keys = {str(error["loc"][0]) for error in e.errors() if error["loc"]}
if not bad_keys:
raise
cleaned = {k: v for k, v in data.items() if str(k) not in bad_keys}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

What is cleaned?
Please add comments.

result = handler(cleaned) # re-raises if required fields are missing
warnings.warn(
f"{cls.__name__}: dropped fields due to validation errors: {bad_keys}",
stacklevel=2,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why explicitly stacklevel=2?
Please document this in the code.

Comment thread src/opi/output/core.py
Comment on lines +128 to +131
strict: bool, default: True
If True, a ValidationError is raised when any field in the parsed output cannot be validated.
If False, fields that fail validation are silently set to None and a UserWarning is emitted.
Only takes effect when `parse=True`; otherwise pass `strict` directly to `Output.parse()`.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
strict: bool, default: True
If True, a ValidationError is raised when any field in the parsed output cannot be validated.
If False, fields that fail validation are silently set to None and a UserWarning is emitted.
Only takes effect when `parse=True`; otherwise pass `strict` directly to `Output.parse()`.
strict: bool, default: True
If `True`, a `ValidationError` is raised when any field in the parsed output cannot be validated.
If `False`, fields that fail validation are silently set to `None` and a `UserWarning` is emitted.
Only takes effect when `parse=True`; otherwise pass `strict` directly to `Output.parse()`.

Comment thread src/opi/output/core.py
Comment on lines +194 to +196
strict: bool, default: True
If True, a ValidationError is raised when any field in the parsed output cannot be validated.
If False, fields that fail validation are silently set to None and a UserWarning is emitted.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
strict: bool, default: True
If True, a ValidationError is raised when any field in the parsed output cannot be validated.
If False, fields that fail validation are silently set to None and a UserWarning is emitted.
strict: bool, default: True
If `True`, a `ValidationError` is raised when any field in the parsed output cannot be validated.
If `False`, fields that fail validation are silently set to `None` and a `UserWarning` is emitted.

Comment thread src/opi/output/core.py
Comment on lines +229 to +230
If True, a ValidationError is raised when any field cannot be validated.
If False, fields that fail validation are set to None and a UserWarning is emitted.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
If True, a ValidationError is raised when any field cannot be validated.
If False, fields that fail validation are set to None and a UserWarning is emitted.
If `True`, a `ValidationError` is raised when any field cannot be validated.
If `False`, fields that fail validation are set to `None` and a `UserWarning` is emitted.

Comment thread src/opi/output/core.py
Comment on lines +260 to +261
If True, a ValidationError is raised when any field cannot be validated.
If False, fields that fail validation are set to None and a UserWarning is emitted.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
If True, a ValidationError is raised when any field cannot be validated.
If False, fields that fail validation are set to None and a UserWarning is emitted.
If `True`, a `ValidationError` is raised when any field cannot be validated.
If `False`, fields that fail validation are set to `None` and a `UserWarning` is emitted.

assert result.calculation_info is not None
assert result.calculation_info.charge is None
assert result.calculation_info.mult == 1
assert any("charge" in str(w.message) for w in caught)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Please document the test mechanism with charge more extensively. It's not trivial. Thanks!

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

Labels

enhancement New feature or request side output Concerning parsing ORCA output

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants