Skip to content

Commit c4a2653

Browse files
committed
fix: preserve metaclasses and __registry_key__ in rebuild_with_none_defaults
1 parent 58644f6 commit c4a2653

2 files changed

Lines changed: 22 additions & 2 deletions

File tree

src/objectstate/lazy_factory.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,10 @@ def rebuild_with_none_defaults(
9999
namespace = {}
100100
for key, value in cls.__dict__.items():
101101
if key.startswith('__') and key.endswith('__'):
102-
continue # Skip dunders (make_dataclass will generate them)
102+
# Skip most dunders (make_dataclass will generate them)
103+
# BUT preserve __registry_key__ for AutoRegisterMeta
104+
if key != '__registry_key__':
105+
continue
103106
if key == '__dataclass_fields__':
104107
continue # Will be regenerated
105108
namespace[key] = value
@@ -114,6 +117,9 @@ def rebuild_with_none_defaults(
114117
for b in cls.__mro__[1:]
115118
)
116119

120+
# Get the original metaclass to preserve it
121+
orig_metaclass = type(cls)
122+
117123
# Create new class
118124
new_cls = make_dataclass(
119125
new_name or cls.__name__,
@@ -128,6 +134,18 @@ def rebuild_with_none_defaults(
128134
if new_name is None:
129135
new_cls.__qualname__ = cls.__qualname__
130136

137+
# Preserve original metaclass if it's not just type
138+
# This is critical for AutoRegisterMeta and other custom metaclasses
139+
if orig_metaclass is not type:
140+
# Re-create the class with the original metaclass
141+
# We need to do this because make_dataclass doesn't accept metaclass parameter
142+
# But we must NOT re-apply @dataclass since make_dataclass already did that
143+
new_cls = orig_metaclass(
144+
new_cls.__name__,
145+
new_cls.__bases__,
146+
dict(new_cls.__dict__),
147+
)
148+
131149
return new_cls
132150

133151

src/objectstate/object_state.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2876,14 +2876,16 @@ def _extract_all_parameters_flat(self, obj: Any, prefix: str = '', exclude_param
28762876
exclude_params: List of top-level parameter names to exclude
28772877
"""
28782878
exclude_params = exclude_params or []
2879-
2879+
28802880
obj_type = type(obj)
28812881
is_function = obj_type.__name__ == 'function'
28822882

28832883
# Delegate signature default extraction to python_introspect (it must derive
28842884
# defaults from the type/signature and avoid instance attribute reads).
28852885
param_info = self._analyze_parameters(obj, exclude_params if not prefix else [])
28862886

2887+
logger.debug(f"🔧 _extract_all_parameters_flat: obj_type={obj_type.__name__}, prefix={prefix!r}, param_info keys={list(param_info.keys())}")
2888+
28872889
for param_name, info in param_info.items():
28882890
# Skip excluded parameters (only at top level)
28892891
if not prefix and param_name in exclude_params:

0 commit comments

Comments
 (0)