Skip to content

feat(data): carry the concrete type inside serialized external distortion parameters - #180

Merged
janickm merged 1 commit into
NVIDIA:mainfrom
janickm:dev/janickm/external-distortion-discriminator
Sep 10, 2026
Merged

feat(data): carry the concrete type inside serialized external distortion parameters#180
janickm merged 1 commit into
NVIDIA:mainfrom
janickm:dev/janickm/external-distortion-discriminator

Conversation

@janickm

@janickm janickm commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator

Follow-up to #179, which introduced the ExternalDistortionParameters base but had to leave CameraModelParameters.external_distortion_parameters naming the concrete union. This removes that compromise.

Why the field could not name the abstract base

dataclasses_json reconstructs whatever type a field is annotated with, and the serialized form carried no discriminator: the type was written beside the camera parameters by encode_camera_model_parameters, not inside the nested object. Confirmed directly:

>>> camera.to_dict()["external_distortion_parameters"].keys()
['horizontal_poly', 'horizontal_poly_inverse', 'reference_poly', 'vertical_poly', 'vertical_poly_inverse']

With a single-member union that resolves by luck. Against the abstract base, from_dict builds the base itself, which is a runtime fault rather than a typing one — it surfaced downstream as TypeError: Unsupported external distortion type <class '...ExternalDistortionParameters'>, only at the point of use.

What changes

The serialized form becomes a discriminated union: the concrete type() is written inside the object under EXTERNAL_DISTORTION_TYPE_KEY, and the field's decoder dispatches on it through a registry that out-of-tree parameter types join via register_external_distortion_parameters, mirroring the model-side registry added in #179.

The field is then declared against ExternalDistortionParameters, and the four get_parameters casts name it too.

Compatibility

Both directions hold, and each is covered by a test rather than assumed:

case behaviour
payload predating the nested key decodes as bivariate-windshield — unambiguous, it was the only concrete type
previous encoded layout (type beside the camera parameters) decode_camera_model_parameters migrates it into the nested object
reader predating this change, reading data written by it still resolves the concrete type: encode_ keeps writing the camera-level type
reader predating this change, seeing the added nested key ignores it (verified against the published wheel)

The camera-level type is therefore written twice for now. That is deliberate and commented; it can be dropped once no reader predating this change remains, and doing so would be the only breaking step — so it is not taken here.

Scope

This widens a field that callers read, so downstream consumers passing it to concretely-typed APIs need updating in step with the release. The remaining read positions (decode_* return types and the parameter accessors in the compat layers) are deliberately left for a separate change, so this one stays a self-contained format change.

Verified: 33/33 tests on 3.8 and 3.11 with --nocache_test_results, ty aspect clean, //:format.check clean.

@janickm
janickm marked this pull request as draft September 9, 2026 14:38
@copy-pr-bot

copy-pr-bot Bot commented Sep 9, 2026

Copy link
Copy Markdown

Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually.

Contributors can view more details about this message here.

Comment thread ncore/impl/data/types.py
@janickm
janickm force-pushed the dev/janickm/external-distortion-discriminator branch from 4f1d40a to bc0be82 Compare September 10, 2026 12:14
@janickm
janickm marked this pull request as ready for review September 10, 2026 12:15
@janickm janickm self-assigned this Sep 10, 2026
…tion parameters

`CameraModelParameters.external_distortion_parameters` had to name the concrete union rather than
the abstract `ExternalDistortionParameters` base, because `dataclasses_json` reconstructs whatever
type a field is annotated with and the serialized form carried no discriminator: the type was
stored beside the camera parameters by `encode_camera_model_parameters`, not inside the nested
object. With a single-member union that resolves by luck; against the abstract base it built the
base itself, which is a runtime fault rather than a typing one.

Make the serialized form a discriminated union. The concrete `type()` is written inside the
object under `EXTERNAL_DISTORTION_TYPE_KEY`, and the field's decoder dispatches on it through a
registry that out-of-tree parameter types can join via `register_external_distortion_parameters`,
mirroring the model-side registry. The field is then declared against the abstract base, and the
four `get_parameters` casts name it too.

Compatibility holds both ways, and both directions are covered by tests rather than assumed:

- Payloads predating the nested key decode as bivariate-windshield, which is unambiguous because
  it was the only concrete type at the time.
- `decode_camera_model_parameters` migrates the old camera-level type into the nested object, so
  the previous encoded layout keeps working.
- `encode_camera_model_parameters` still writes the camera-level type, so readers predating this
  change resolve the concrete type from data written by it. That can go once no such reader
  remains.
- A reader predating this change tolerates the added key, verified against the published wheel.

Note this widens a field that callers *read*. Downstream consumers passing it to concretely-typed
APIs need updating in step with the release.

(cherry picked from commit 4f1d40a)
@janickm
janickm force-pushed the dev/janickm/external-distortion-discriminator branch from bc0be82 to ea503e5 Compare September 10, 2026 12:28
@janickm
janickm enabled auto-merge September 10, 2026 12:31
@janickm
janickm added this pull request to the merge queue Sep 10, 2026
Merged via the queue into NVIDIA:main with commit d59ba59 Sep 10, 2026
5 checks passed
@janickm
janickm deleted the dev/janickm/external-distortion-discriminator branch September 10, 2026 12:52
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.

1 participant