diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2022-07-15 12:25:22 -0400 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2022-07-15 12:37:06 -0400 |
commit | 0aa56cd729407dff1d96c61432b6f3a2a7124d39 (patch) | |
tree | 4cda2e1335d2a942632428cb93810a05d4606f1c /lib/sqlalchemy/orm/decl_base.py | |
parent | a0597341195ba7445ef1e9c69092e3bd29427aec (diff) | |
download | sqlalchemy-0aa56cd729407dff1d96c61432b6f3a2a7124d39.tar.gz |
make anno-only Mapped[] column available for mixins
Documentation is relying on the recently improved
behavior of produce_column_copies() to make sure everything is
available on cls for a declared_attr. therefore for anno-only
attribute, we also need to generate the mapped_column() up front
before scan is called.
noticed in pylance, allow @declared_attr to recognize
@classmethod also which allows letting typing tools know
something is explicitly a classmethod
Change-Id: I07ff1a642a75679f685914a33c674807929f4918
Diffstat (limited to 'lib/sqlalchemy/orm/decl_base.py')
-rw-r--r-- | lib/sqlalchemy/orm/decl_base.py | 48 |
1 files changed, 26 insertions, 22 deletions
diff --git a/lib/sqlalchemy/orm/decl_base.py b/lib/sqlalchemy/orm/decl_base.py index 62251fa2b..108027dd5 100644 --- a/lib/sqlalchemy/orm/decl_base.py +++ b/lib/sqlalchemy/orm/decl_base.py @@ -737,6 +737,7 @@ class _ClassScanMapperConfig(_MapperConfig): locally_collected_columns = self._produce_column_copies( local_attributes_for_class, attribute_is_overridden, + fixed_table, ) else: locally_collected_columns = {} @@ -828,9 +829,7 @@ class _ClassScanMapperConfig(_MapperConfig): # acting like that for now. if isinstance(obj, (Column, MappedColumn)): - self._collect_annotation( - name, annotation, is_dataclass_field, True, obj - ) + self._collect_annotation(name, annotation, True, obj) # already copied columns to the mapped class. continue elif isinstance(obj, MapperProperty): @@ -913,23 +912,18 @@ class _ClassScanMapperConfig(_MapperConfig): self._collect_annotation( name, obj._collect_return_annotation(), - False, True, obj, ) elif _is_mapped_annotation(annotation, cls): - generated_obj = self._collect_annotation( - name, annotation, is_dataclass_field, True, obj - ) - if obj is None: - if not fixed_table: - collected_attributes[name] = ( - generated_obj - if generated_obj is not None - else MappedColumn() - ) - else: - collected_attributes[name] = obj + # Mapped annotation without any object. + # product_column_copies should have handled this. + # if future support for other MapperProperty, + # then test if this name is already handled and + # otherwise proceed to generate. + if not fixed_table: + assert name in collected_attributes + continue else: # here, the attribute is some other kind of # property that we assume is not part of the @@ -953,12 +947,10 @@ class _ClassScanMapperConfig(_MapperConfig): obj = obj.fget() collected_attributes[name] = obj - self._collect_annotation( - name, annotation, True, False, obj - ) + self._collect_annotation(name, annotation, False, obj) else: generated_obj = self._collect_annotation( - name, annotation, False, None, obj + name, annotation, None, obj ) if ( obj is None @@ -1060,7 +1052,6 @@ class _ClassScanMapperConfig(_MapperConfig): self, name: str, raw_annotation: _AnnotationScanType, - is_dataclass: bool, expect_mapped: Optional[bool], attr_value: Any, ) -> Any: @@ -1128,6 +1119,7 @@ class _ClassScanMapperConfig(_MapperConfig): [], Iterable[Tuple[str, Any, Any, bool]] ], attribute_is_overridden: Callable[[str, Any], bool], + fixed_table: bool, ) -> Dict[str, Union[Column[Any], MappedColumn[Any]]]: cls = self.cls dict_ = self.clsdict_view @@ -1136,7 +1128,19 @@ class _ClassScanMapperConfig(_MapperConfig): # copy mixin columns to the mapped class for name, obj, annotation, is_dataclass in attributes_for_class(): - if isinstance(obj, (Column, MappedColumn)): + if ( + not fixed_table + and obj is None + and _is_mapped_annotation(annotation, cls) + ): + obj = self._collect_annotation(name, annotation, True, obj) + if obj is None: + obj = MappedColumn() + + locally_collected_attributes[name] = obj + setattr(cls, name, obj) + + elif isinstance(obj, (Column, MappedColumn)): if attribute_is_overridden(name, obj): # if column has been overridden # (like by the InstrumentedAttribute of the |