(
table_columns_cls: type[TypedColumns],
)
| 246 | |
| 247 | @util.preload_module("sqlalchemy.sql.schema") |
| 248 | def _extract_columns_from_class( |
| 249 | table_columns_cls: type[TypedColumns], |
| 250 | ) -> list[Column[Any]]: |
| 251 | columns: dict[str, Column[Any]] = {} |
| 252 | |
| 253 | Column = util.preloaded.sql_schema.Column |
| 254 | NULL_UNSPECIFIED = util.preloaded.sql_schema.NULL_UNSPECIFIED |
| 255 | |
| 256 | for base in table_columns_cls.__mro__[::-1]: |
| 257 | if base in TypedColumns.__mro__: |
| 258 | continue |
| 259 | |
| 260 | # _ClassScanAbstractConfig._cls_attr_resolver |
| 261 | cls_annotations = util.get_annotations(base) |
| 262 | cls_vars = vars(base) |
| 263 | items = [ |
| 264 | (n, cls_vars.get(n), cls_annotations.get(n)) |
| 265 | for n in util.merge_lists_w_ordering( |
| 266 | list(cls_vars), list(cls_annotations) |
| 267 | ) |
| 268 | if not dunders_re.match(n) |
| 269 | ] |
| 270 | # -- |
| 271 | for name, obj, annotation in items: |
| 272 | if obj is None: |
| 273 | assert annotation is not None |
| 274 | # no attribute, just annotation |
| 275 | extracted_type = _collect_annotation( |
| 276 | table_columns_cls, name, base.__module__, annotation |
| 277 | ) |
| 278 | if extracted_type is _NoArg.NO_ARG: |
| 279 | raise ArgumentError( |
| 280 | "No type information could be extracted from " |
| 281 | f"annotation {annotation} for attribute " |
| 282 | f"'{base.__name__}.{name}'" |
| 283 | ) |
| 284 | sqltype = _get_sqltype(extracted_type) |
| 285 | if sqltype is None: |
| 286 | raise ArgumentError( |
| 287 | f"Could not find a SQL type for type {extracted_type} " |
| 288 | f"obtained from annotation {annotation} in " |
| 289 | f"attribute '{base.__name__}.{name}'" |
| 290 | ) |
| 291 | columns[name] = Column( |
| 292 | name, |
| 293 | sqltype, |
| 294 | nullable=sa_typing.includes_none(extracted_type), |
| 295 | ) |
| 296 | elif isinstance(obj, Column): |
| 297 | # has attribute attribute |
| 298 | # _DeclarativeMapperConfig._produce_column_copies |
| 299 | # as with orm this case is not supported |
| 300 | for fk in obj.foreign_keys: |
| 301 | if ( |
| 302 | fk._table_column is not None |
| 303 | and fk._table_column.table is None |
| 304 | ): |
| 305 | raise InvalidRequestError( |
no test coverage detected