Skip to content

fix: Use a class-level default set after the parameters were looked up - #1219

Open
syahra712 wants to merge 4 commits into
holoviz:mainfrom
syahra712:fix/class-default-after-lookup
Open

syahra712 wants to merge 4 commits into
holoviz:mainfrom
syahra712:fix/class-default-after-lookup

Conversation

@syahra712

Copy link
Copy Markdown

Fixes #1218

Setting a class-level default on a subclass, e.g. Looked.d = {'x': 1}, copies the inherited Parameter into the subclass in ParameterizedMetaclass.__setattr__. If Looked.param[...] had been called before, _cls_parameters was already cached. That cache, including params_to_deepcopy, still held the superclass Parameter. So for instantiate=True parameters, new instances deep-copied the old default.

When the copy is made, this clears the cached class parameters of the class and its subclasses (through descendents), so they are rebuilt on the next lookup. A subclass that had also been looked up would otherwise keep the stale Parameter too. add_parameter clears the cache the same way.

The new test covers the issue example plus a cached sub-subclass, and fails without the change. The full test suite passes locally (1787 passed).

Setting a class default on a subclass copies the inherited Parameter into it,
but the cached class parameters of the subclass (and of its own subclasses)
still pointed to the superclass Parameter, so instantiate=True parameters were
deep-copied from the old default. Clear those caches when the copy is made.
@codecov

codecov Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 89.49%. Comparing base (a45813b) to head (f93c679).
⚠️ Report is 9 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1219      +/-   ##
==========================================
+ Coverage   89.25%   89.49%   +0.23%     
==========================================
  Files           9        9              
  Lines        6517     6674     +157     
==========================================
+ Hits         5817     5973     +156     
- Misses        700      701       +1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Comment thread param/parameterized.py Outdated
Comment on lines +5335 to +5338
# The cached class parameters of mcs and its subclasses may
# still point to the superclass Parameter that was just copied.
for cls in descendents(t.cast("type[t.Any]", mcs)):
cls._param__private.params.clear()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Do we need to clear the whole cache or can we just clear the cache entry for the overridden parameter?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Good point, we don't need to. Each subclass's cache only holds a stale entry for this one name, and only where it still resolves to the inherited Parameter. So now only that entry is swapped for the new copy, and params_to_deepcopy / params_to_ref / params_with_default_factory are reset to None, which _cls_parameters already rebuilds on the next lookup. Subclasses that define their own p keep their entry untouched, and I added that case to the test.

This branch has not been deployed

No deployments
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.

Class-level default for an instantiated parameter is ignored after cls.param[name] is accessed

2 participants