diff options
| author | Václav Klusák <vaclav.klusak@maptiler.com> | 2020-08-17 11:58:56 -0400 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2020-09-01 10:59:07 -0400 |
| commit | f806491fca4b08623d7fcffc375bd5cbe3790e5f (patch) | |
| tree | 09d3eb22bc2e179ab4caf4e8e4caa59bfab46928 /lib/sqlalchemy | |
| parent | ed5e015ef48ab7ce0950c0eac69b7aa4ad256ca5 (diff) | |
| download | sqlalchemy-f806491fca4b08623d7fcffc375bd5cbe3790e5f.tar.gz | |
Add support for classical mapping of dataclasses
Added support for direct mapping of Python classes that are defined using
the Python ``dataclasses`` decorator. See the section
:ref:`mapping_dataclasses` for background. Pull request courtesy Václav
Klusák.
Fixes: #5027
Closes: #5516
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/5516
Pull-request-sha: bb48c63d1561ca48c954ad9f84a3eb2646571115
Change-Id: Ie33db2aae4adeeb5d99633fe926b9c30bab0b885
Diffstat (limited to 'lib/sqlalchemy')
| -rw-r--r-- | lib/sqlalchemy/orm/descriptor_props.py | 2 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/mapper.py | 24 | ||||
| -rw-r--r-- | lib/sqlalchemy/testing/requirements.py | 4 |
3 files changed, 25 insertions, 5 deletions
diff --git a/lib/sqlalchemy/orm/descriptor_props.py b/lib/sqlalchemy/orm/descriptor_props.py index 39cf86e34..c2efa24a1 100644 --- a/lib/sqlalchemy/orm/descriptor_props.py +++ b/lib/sqlalchemy/orm/descriptor_props.py @@ -56,7 +56,7 @@ class DescriptorProperty(MapperProperty): if self.descriptor is None: desc = getattr(mapper.class_, self.key, None) - if mapper._is_userland_descriptor(desc): + if mapper._is_userland_descriptor(self.key, desc): self.descriptor = desc if self.descriptor is None: diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py index 446f6790e..755d4afc7 100644 --- a/lib/sqlalchemy/orm/mapper.py +++ b/lib/sqlalchemy/orm/mapper.py @@ -56,6 +56,12 @@ from ..sql import util as sql_util from ..sql import visitors from ..util import HasMemoized +try: + import dataclasses +except ImportError: + # The dataclasses module was added in Python 3.7 + dataclasses = None + _mapper_registry = weakref.WeakKeyDictionary() _already_compiling = False @@ -2632,7 +2638,7 @@ class Mapper( return result - def _is_userland_descriptor(self, obj): + def _is_userland_descriptor(self, assigned_name, obj): if isinstance( obj, ( @@ -2643,7 +2649,14 @@ class Mapper( ): return False else: - return True + return assigned_name not in self._dataclass_fields + + @HasMemoized.memoized_attribute + def _dataclass_fields(self): + if dataclasses is None or not dataclasses.is_dataclass(self.class_): + return frozenset() + + return {field.name for field in dataclasses.fields(self.class_)} def _should_exclude(self, name, assigned_name, local, column): """determine whether a particular property should be implicitly @@ -2656,16 +2669,19 @@ class Mapper( # check for class-bound attributes and/or descriptors, # either local or from an inherited class + # ignore dataclass field default values if local: if self.class_.__dict__.get( assigned_name, None ) is not None and self._is_userland_descriptor( - self.class_.__dict__[assigned_name] + assigned_name, self.class_.__dict__[assigned_name] ): return True else: attr = self.class_manager._get_class_attr_mro(assigned_name, None) - if attr is not None and self._is_userland_descriptor(attr): + if attr is not None and self._is_userland_descriptor( + assigned_name, attr + ): return True if ( diff --git a/lib/sqlalchemy/testing/requirements.py b/lib/sqlalchemy/testing/requirements.py index 9b8caac2e..4114137d4 100644 --- a/lib/sqlalchemy/testing/requirements.py +++ b/lib/sqlalchemy/testing/requirements.py @@ -1143,6 +1143,10 @@ class SuiteRequirements(Requirements): ) @property + def dataclasses(self): + return self.python37 + + @property def cpython(self): return exclusions.only_if( lambda: util.cpython, "cPython interpreter needed" |
