Forbid Computed var shadowing (#3843)
This commit is contained in:
parent
a5c73ad8e5
commit
d672c643b3
@ -477,7 +477,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|||||||
cls._check_overridden_methods()
|
cls._check_overridden_methods()
|
||||||
|
|
||||||
# Computed vars should not shadow builtin state props.
|
# Computed vars should not shadow builtin state props.
|
||||||
cls._check_overriden_basevars()
|
cls._check_overridden_basevars()
|
||||||
|
|
||||||
# Reset subclass tracking for this class.
|
# Reset subclass tracking for this class.
|
||||||
cls.class_subclasses = set()
|
cls.class_subclasses = set()
|
||||||
@ -505,6 +505,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|||||||
|
|
||||||
# Get computed vars.
|
# Get computed vars.
|
||||||
computed_vars = cls._get_computed_vars()
|
computed_vars = cls._get_computed_vars()
|
||||||
|
cls._check_overridden_computed_vars()
|
||||||
|
|
||||||
new_backend_vars = {
|
new_backend_vars = {
|
||||||
name: value
|
name: value
|
||||||
@ -718,7 +719,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _check_overriden_basevars(cls):
|
def _check_overridden_basevars(cls):
|
||||||
"""Check for shadow base vars and raise error if any.
|
"""Check for shadow base vars and raise error if any.
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
@ -730,6 +731,22 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|||||||
f"The computed var name `{computed_var_._var_name}` shadows a base var in {cls.__module__}.{cls.__name__}; use a different name instead"
|
f"The computed var name `{computed_var_._var_name}` shadows a base var in {cls.__module__}.{cls.__name__}; use a different name instead"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _check_overridden_computed_vars(cls) -> None:
|
||||||
|
"""Check for shadow computed vars and raise error if any.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
NameError: When a computed var shadows another.
|
||||||
|
"""
|
||||||
|
for name, cv in cls.__dict__.items():
|
||||||
|
if not isinstance(cv, (ComputedVar, ImmutableComputedVar)):
|
||||||
|
continue
|
||||||
|
name = cv._var_name
|
||||||
|
if name in cls.inherited_vars or name in cls.inherited_backend_vars:
|
||||||
|
raise NameError(
|
||||||
|
f"The computed var name `{cv._var_name}` shadows a var in {cls.__module__}.{cls.__name__}; use a different name instead"
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_skip_vars(cls) -> set[str]:
|
def get_skip_vars(cls) -> set[str]:
|
||||||
"""Get the vars to skip when serializing.
|
"""Get the vars to skip when serializing.
|
||||||
|
@ -79,6 +79,11 @@ def ChildState(ParentState, TestObj):
|
|||||||
class ChildState(ParentState):
|
class ChildState(ParentState):
|
||||||
@immutable_computed_var
|
@immutable_computed_var
|
||||||
def var_without_annotation(self):
|
def var_without_annotation(self):
|
||||||
|
"""This shadows ParentState.var_without_annotation.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
TestObj: Test object.
|
||||||
|
"""
|
||||||
return TestObj
|
return TestObj
|
||||||
|
|
||||||
return ChildState
|
return ChildState
|
||||||
@ -89,6 +94,11 @@ def GrandChildState(ChildState, TestObj):
|
|||||||
class GrandChildState(ChildState):
|
class GrandChildState(ChildState):
|
||||||
@immutable_computed_var
|
@immutable_computed_var
|
||||||
def var_without_annotation(self):
|
def var_without_annotation(self):
|
||||||
|
"""This shadows ChildState.var_without_annotation.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
TestObj: Test object.
|
||||||
|
"""
|
||||||
return TestObj
|
return TestObj
|
||||||
|
|
||||||
return GrandChildState
|
return GrandChildState
|
||||||
@ -738,8 +748,6 @@ def test_var_unsupported_indexing_dicts(var, index):
|
|||||||
"fixture",
|
"fixture",
|
||||||
[
|
[
|
||||||
"ParentState",
|
"ParentState",
|
||||||
"ChildState",
|
|
||||||
"GrandChildState",
|
|
||||||
"StateWithAnyVar",
|
"StateWithAnyVar",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@ -761,6 +769,26 @@ def test_computed_var_without_annotation_error(request, fixture):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"fixture",
|
||||||
|
[
|
||||||
|
"ChildState",
|
||||||
|
"GrandChildState",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_shadow_computed_var_error(request: pytest.FixtureRequest, fixture: str):
|
||||||
|
"""Test that a name error is thrown when an attribute of a computed var is
|
||||||
|
shadowed by another attribute.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
request: Fixture Request.
|
||||||
|
fixture: The state fixture.
|
||||||
|
"""
|
||||||
|
with pytest.raises(NameError):
|
||||||
|
state = request.getfixturevalue(fixture)
|
||||||
|
state.var_without_annotation.foo
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"fixture",
|
"fixture",
|
||||||
[
|
[
|
||||||
|
Loading…
Reference in New Issue
Block a user