diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2021-04-21 10:39:09 -0400 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2021-04-21 10:42:21 -0400 |
| commit | ed3f2c617239668d74ad3d86aeda0ca2030a5933 (patch) | |
| tree | 2c1d1881c6b2d0d9c74d41362960e575ec0c404a /lib/sqlalchemy | |
| parent | 368086e9fc49c7a1ca972480e0134d8e7a9f0544 (diff) | |
| download | sqlalchemy-ed3f2c617239668d74ad3d86aeda0ca2030a5933.tar.gz | |
Limit dc field logic to only fields that are definitely dc
Fixed regression where recent changes to support Python dataclasses had the
inadvertent effect that an ORM mapped class could not successfully override
the ``__new__()`` method.
In this case the "__new__" method comes out as staticmethod in
cls.__dict__ vs. a function in the metaclass dict_, so comparing
using identity fails. I was hoping not to have too much
"dataclass" hardcoded, the logic here if it were generalized
to other attribute declaration systems there
would still have a flag that indicates an attribute is part of
the "special declaration system".
Fixes: #6331
Change-Id: Ia28a44fb57c668fa2fc5cd1ff38fd511f2c747e6
Diffstat (limited to 'lib/sqlalchemy')
| -rw-r--r-- | lib/sqlalchemy/orm/decl_base.py | 16 |
1 files changed, 9 insertions, 7 deletions
diff --git a/lib/sqlalchemy/orm/decl_base.py b/lib/sqlalchemy/orm/decl_base.py index 5a5d98a95..b3444f26f 100644 --- a/lib/sqlalchemy/orm/decl_base.py +++ b/lib/sqlalchemy/orm/decl_base.py @@ -410,7 +410,7 @@ class _ClassScanMapperConfig(_MapperConfig): def local_attributes_for_class(): for name, obj in vars(cls).items(): - yield name, obj + yield name, obj, False else: field_names = set() @@ -421,10 +421,10 @@ class _ClassScanMapperConfig(_MapperConfig): field_names.add(field.name) yield field.name, _as_dc_declaredattr( field.metadata, sa_dataclass_metadata_key - ) + ), True for name, obj in vars(cls).items(): if name not in field_names: - yield name, obj + yield name, obj, False return local_attributes_for_class @@ -455,7 +455,7 @@ class _ClassScanMapperConfig(_MapperConfig): local_attributes_for_class, attribute_is_overridden ) - for name, obj in local_attributes_for_class(): + for name, obj, is_dataclass in local_attributes_for_class(): if name == "__mapper_args__": check_decl = _check_declared_props_nocascade( obj, name, cls @@ -567,15 +567,17 @@ class _ClassScanMapperConfig(_MapperConfig): # however, check for some more common mistakes else: self._warn_for_decl_attributes(base, name, obj) - elif name not in dict_ or dict_[name] is not obj: + elif is_dataclass and ( + name not in dict_ or dict_[name] is not obj + ): # here, we are definitely looking at the target class # and not a superclass. this is currently a # dataclass-only path. if the name is only # a dataclass field and isn't in local cls.__dict__, # put the object there. - # assert that the dataclass-enabled resolver agrees # with what we are seeing + assert not attribute_is_overridden(name, obj) if _is_declarative_props(obj): @@ -607,7 +609,7 @@ class _ClassScanMapperConfig(_MapperConfig): column_copies = self.column_copies # copy mixin columns to the mapped class - for name, obj in attributes_for_class(): + for name, obj, is_dataclass in attributes_for_class(): if isinstance(obj, Column): if attribute_is_overridden(name, obj): # if column has been overridden |
