Skip to content

fix(python): correct type dispatch in infer_field for custom classes#3432

Open
SURYAS1306 wants to merge 5 commits intoapache:mainfrom
SURYAS1306:fix-type-dispatch
Open

fix(python): correct type dispatch in infer_field for custom classes#3432
SURYAS1306 wants to merge 5 commits intoapache:mainfrom
SURYAS1306:fix-type-dispatch

Conversation

@SURYAS1306
Copy link

Why?

The current type dispatch logic in infer_field incorrectly treats certain user-defined classes as built-in types due to insufficient origin/type checks.
This leads to incorrect field inference and causes Python serialization tests to fail.

What does this PR do?

This PR refines the type dispatch logic in infer_field to properly distinguish between:

  • Built-in primitives and standard library types
  • Collection types (list, dict, set)
  • User-defined classes

User-defined classes are now correctly routed through visit_customized, while primitives and supported types continue to use visit_other.

All existing Python tests pass after this fix.

Related issues

None.

Does this PR introduce any user-facing change?

No.

  • Does this PR introduce any public API change?
  • Does this PR introduce any binary protocol compatibility change?

Benchmark

Not applicable - this change does not impact performance.

@chaokunyang
Copy link
Collaborator

@SURYAS1306 Could you add tests for cases which type inference goes wrong?

self.y = "hello"

# Should not raise TypeError and must be treated as STRUCT
assert _infer_field("", Empty).type.id == TypeId.STRUCT
Copy link
Collaborator

@chaokunyang chaokunyang Feb 28, 2026

Choose a reason for hiding this comment

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

This may be wrong, only dataclass should be taken as struct. The current struct seiralizer is DataclassSerializer and it only support dataclass too

@SURYAS1306
Copy link
Author

Hi @chaokunyang,
Thanks for the clarification. I’ve updated the tests to align with the dataclass-only STRUCT behavior and removed the incorrect unannotated class case.

Please let me know if you’d like additional edge cases to be covered.

@@ -249,11 +249,17 @@ def infer_field(field_name, type_, visitor: TypeVisitor, types_path=None):
else:
raise TypeError(f"Collection types should be {list, dict} instead of {type_}")
else:
if is_function(origin) or not hasattr(origin, "__annotations__"):
if is_function(origin):
Copy link
Collaborator

Choose a reason for hiding this comment

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

So I do not understand, what does this fix exactly?

Copy link
Author

@SURYAS1306 SURYAS1306 Feb 28, 2026

Choose a reason for hiding this comment

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

Previously, types without __annotations__ (including non-dataclass classes) were being routed through the same branch as functions due to the or not hasattr(origin, "__annotations__") condition.

This caused incorrect type dispatch for custom classes.

By removing the not hasattr(origin, "__annotations__") check, only actual functions are handled in that branch, and class types now follow the intended dispatch path.

Please let me know if I should clarify this further in the PR description.

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.

2 participants