add an attribute to an existing declarative class. This runs through the logic to determine MapperProperty, adds it to the Mapper, adds a column to the mapped Table, etc.
(
cls: Type[Any], key: str, value: MapperProperty[Any]
)
| 2102 | |
| 2103 | |
| 2104 | def _add_attribute( |
| 2105 | cls: Type[Any], key: str, value: MapperProperty[Any] |
| 2106 | ) -> None: |
| 2107 | """add an attribute to an existing declarative class. |
| 2108 | |
| 2109 | This runs through the logic to determine MapperProperty, |
| 2110 | adds it to the Mapper, adds a column to the mapped Table, etc. |
| 2111 | |
| 2112 | """ |
| 2113 | |
| 2114 | if "__mapper__" in cls.__dict__: |
| 2115 | mapped_cls = cast("MappedClassProtocol[Any]", cls) |
| 2116 | |
| 2117 | def _table_or_raise(mc: MappedClassProtocol[Any]) -> Table: |
| 2118 | if isinstance(mc.__table__, Table): |
| 2119 | return mc.__table__ |
| 2120 | raise exc.InvalidRequestError( |
| 2121 | f"Cannot add a new attribute to mapped class {mc.__name__!r} " |
| 2122 | "because it's not mapped against a table." |
| 2123 | ) |
| 2124 | |
| 2125 | if isinstance(value, Column): |
| 2126 | _undefer_column_name(key, value) |
| 2127 | _table_or_raise(mapped_cls).append_column( |
| 2128 | value, replace_existing=True |
| 2129 | ) |
| 2130 | mapped_cls.__mapper__.add_property(key, value) |
| 2131 | elif isinstance(value, _MapsColumns): |
| 2132 | mp = value.mapper_property_to_assign |
| 2133 | for col, _ in value.columns_to_assign: |
| 2134 | _undefer_column_name(key, col) |
| 2135 | _table_or_raise(mapped_cls).append_column( |
| 2136 | col, replace_existing=True |
| 2137 | ) |
| 2138 | if not mp: |
| 2139 | mapped_cls.__mapper__.add_property(key, col) |
| 2140 | if mp: |
| 2141 | mapped_cls.__mapper__.add_property(key, mp) |
| 2142 | elif isinstance(value, MapperProperty): |
| 2143 | mapped_cls.__mapper__.add_property(key, value) |
| 2144 | elif isinstance(value, QueryableAttribute) and value.key != key: |
| 2145 | # detect a QueryableAttribute that's already mapped being |
| 2146 | # assigned elsewhere in userland, turn into a synonym() |
| 2147 | value = SynonymProperty(value.key) |
| 2148 | mapped_cls.__mapper__.add_property(key, value) |
| 2149 | else: |
| 2150 | type.__setattr__(cls, key, value) |
| 2151 | mapped_cls.__mapper__._expire_memoizations() |
| 2152 | else: |
| 2153 | type.__setattr__(cls, key, value) |
| 2154 | |
| 2155 | |
| 2156 | def _del_attribute(cls: Type[Any], key: str) -> None: |
no test coverage detected