@@ -141,6 +141,41 @@ def test_tuple_instance_model_info(self, mapper):
141141 assert len (info .split ("\n " )) == len (mapper .info .split ("\n " ))
142142
143143
144+ def test_parameterization_cache_does_not_leak_into_instance ():
145+ """Regression: ``parameterization`` is cached in
146+ ``self.__dict__["_parameterization_cache"]`` so that
147+ ``Collection._instance_for_arguments`` and ``ModelInstance.dict``
148+ (which skip underscore-prefixed keys) do not propagate the cached
149+ string onto the constructed instance. A plain
150+ ``functools.cached_property`` would write to ``__dict__["parameterization"]``
151+ without an underscore, leaking the string into ``ModelInstance.dict``
152+ and downstream JAX pytree flattening — see commit 4564ae9a1."""
153+
154+ model = af .Collection (gaussian = af .Model (af .ex .Gaussian ))
155+
156+ # Touch model.info → exercises the same propagation path that every
157+ # workspace script hits at construction time.
158+ _ = model .info
159+ _ = model .parameterization # second access uses the cache
160+
161+ # The cache must live behind an underscore key on the model.
162+ assert "_parameterization_cache" in model .__dict__
163+ assert "parameterization" not in model .__dict__
164+
165+ instance = model .instance_from_prior_medians ()
166+
167+ # Neither the cached key nor the public name may appear on the
168+ # constructed instance.
169+ assert "parameterization" not in instance .__dict__
170+ assert "_parameterization_cache" not in instance .__dict__
171+ assert "parameterization" not in instance .dict
172+ assert "_parameterization_cache" not in instance .dict
173+
174+ # The instance must yield only model components when iterated.
175+ for child in instance :
176+ assert not isinstance (child , str )
177+
178+
144179def test_integer_attributes ():
145180 model = af .Model (af .ex .Gaussian )
146181
0 commit comments