[REF-2302] When a Var points to a model, prefer access to model fields. (#2893)
* When a Var points to a model, prefer access to model fields. When a Var points to a model, and fields of the model share the same name as Var operations, access to the model fields is now preferred to avoid having Var operation names shadow model fields. Since most Var operations do not actually work against Models, this does not really block any functionality. * Special case for ComputedVar needing to internally access fget Since fget is a "slot" on property, normal __getattribute__ access cannot find it. * Workaround https://github.com/python/cpython/issues/88459 In python 3.9 and 3.10, the `isinstance(list[...], type)` returns True, but it's not a valid class for use in issubclass
This commit is contained in:
parent
b788890696
commit
b23859a45d
@ -202,7 +202,7 @@ def get_attribute_access_type(cls: GenericType, name: str) -> GenericType | None
|
||||
attr.remote_attr.key, # type: ignore[attr-defined]
|
||||
)
|
||||
]
|
||||
elif isinstance(cls, type) and issubclass(cls, Model):
|
||||
elif isinstance(cls, type) and not is_generic_alias(cls) and issubclass(cls, Model):
|
||||
# Check in the annotations directly (for sqlmodel.Relationship)
|
||||
hints = get_type_hints(cls)
|
||||
if name in hints:
|
||||
|
@ -677,6 +677,33 @@ class Var:
|
||||
_var_is_string=False,
|
||||
)
|
||||
|
||||
def __getattribute__(self, name: str) -> Any:
|
||||
"""Get a var attribute.
|
||||
|
||||
Args:
|
||||
name: The name of the attribute.
|
||||
|
||||
Returns:
|
||||
The var attribute.
|
||||
|
||||
Raises:
|
||||
AttributeError: If the attribute cannot be found, or if __getattr__ fallback should be used.
|
||||
"""
|
||||
try:
|
||||
var_attribute = super().__getattribute__(name)
|
||||
if not name.startswith("_"):
|
||||
# Check if the attribute should be accessed through the Var instead of
|
||||
# accessing one of the Var operations
|
||||
type_ = types.get_attribute_access_type(
|
||||
super().__getattribute__("_var_type"), name
|
||||
)
|
||||
if type_ is not None:
|
||||
raise AttributeError(f"{name} is being accessed through the Var.")
|
||||
# Return the attribute as-is.
|
||||
return var_attribute
|
||||
except AttributeError:
|
||||
raise # fall back to __getattr__ anyway
|
||||
|
||||
def __getattr__(self, name: str) -> Var:
|
||||
"""Get a var attribute.
|
||||
|
||||
@ -1891,8 +1918,9 @@ class ComputedVar(Var, property):
|
||||
"""
|
||||
d = set()
|
||||
if obj is None:
|
||||
if self.fget is not None:
|
||||
obj = cast(FunctionType, self.fget)
|
||||
fget = property.__getattribute__(self, "fget")
|
||||
if fget is not None:
|
||||
obj = cast(FunctionType, fget)
|
||||
else:
|
||||
return set()
|
||||
with contextlib.suppress(AttributeError):
|
||||
@ -1976,7 +2004,7 @@ class ComputedVar(Var, property):
|
||||
Returns:
|
||||
The type of the var.
|
||||
"""
|
||||
hints = get_type_hints(self.fget)
|
||||
hints = get_type_hints(property.__getattribute__(self, "fget"))
|
||||
if "return" in hints:
|
||||
return hints["return"]
|
||||
return Any
|
||||
|
Loading…
Reference in New Issue
Block a user