Skip to content

Allow replacing unused auto-created converters#4

Closed
mdepinet wants to merge 2 commits into
mainfrom
mike/claude-auto-converter-replacement
Closed

Allow replacing unused auto-created converters#4
mdepinet wants to merge 2 commits into
mainfrom
mike/claude-auto-converter-replacement

Conversation

@mdepinet

Copy link
Copy Markdown
Contributor

Summary

When get_converter() auto-creates a converter for a type pair, it now uses _AutoConverter (an internal subclass) that tracks whether convert() has been called. A ProtoConverter subclass registered later can replace an unused _AutoConverter, eliminating class-definition ordering constraints in most cases.

This was the main friction point during the Fixie migration — parent converters had to be defined after all their leaf converters so that auto-resolution would find the registered subclasses. With this change, definition order is irrelevant for auto-convertible subtypes as long as all subclasses are defined before the first convert() call. Subtypes that cannot be auto-converted (e.g. field names differ between source and destination) still need their custom converter defined before the parent.

Invariant preserved: once a converter has been used (convert() called), it's locked in and replacement raises RuntimeError. This ensures convert() behavior doesn't change after first use.

Unhandled field errors are still caught at construction time. If a nested type genuinely can't be auto-converted, auto-creation fails with NotImplementedError when the parent registers — exactly as before. The only thing that changes is: if auto-creation succeeds, the result can be replaced by a subclass later.

Test plan

  • just — 41 passed, pyright/ruff/deptry clean
  • New test: test_replace_unused_auto_converter — verifies replacement succeeds
  • New test: test_replace_used_auto_converter_fails — verifies used converters are locked

🤖 Generated with Claude Code

Mike Depinet (using Claude) and others added 2 commits April 16, 2026 09:39
When get_converter() auto-creates a converter for a type pair, it now
uses _AutoConverter (an internal subclass) that tracks whether convert()
has been called. A ProtoConverter subclass registered later can replace
an unused _AutoConverter, eliminating class-definition ordering
constraints in most cases.

Once an _AutoConverter has been used (convert() called), it's locked in
and replacement raises RuntimeError — preserving the invariant that
convert() behavior doesn't change after first use.

Ordering still matters when a nested type can't be auto-converted (e.g.
field names differ) — the custom subclass must be defined before the
parent tries to auto-resolve it.

Bump to 1.0.2.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
_AutoConverter.convert() now checks the registry and delegates to the
replacement if it's been replaced. This ensures parent closures that
captured the _AutoConverter instance use the latest registered
converter, not the stale auto-created one.

Added test verifying that nested conversions through a parent use a
replacement subclass, not the original auto-converter.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@mdepinet

Copy link
Copy Markdown
Contributor Author

Closing per review feedback — the strict ordering rule is simpler, more predictable under schema evolution, and already necessary for non-auto-convertible subtypes. The partial relaxation adds complexity without meaningful benefit since real codebases adopt leaf-first ordering anyway.

@mdepinet mdepinet closed this Apr 16, 2026
@mdepinet
mdepinet deleted the mike/claude-auto-converter-replacement branch April 16, 2026 18:11
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