Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/sqlalchemy/orm/decl_api.py: 40%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

440 statements  

1# orm/decl_api.py 

2# Copyright (C) 2005-2025 the SQLAlchemy authors and contributors 

3# <see AUTHORS file> 

4# 

5# This module is part of SQLAlchemy and is released under 

6# the MIT License: https://www.opensource.org/licenses/mit-license.php 

7 

8"""Public API functions and helpers for declarative.""" 

9 

10from __future__ import annotations 

11 

12import re 

13import typing 

14from typing import Any 

15from typing import Callable 

16from typing import ClassVar 

17from typing import Dict 

18from typing import FrozenSet 

19from typing import Generic 

20from typing import Iterable 

21from typing import Iterator 

22from typing import Mapping 

23from typing import Optional 

24from typing import overload 

25from typing import Set 

26from typing import Tuple 

27from typing import Type 

28from typing import TYPE_CHECKING 

29from typing import TypeVar 

30from typing import Union 

31import weakref 

32 

33from . import attributes 

34from . import clsregistry 

35from . import instrumentation 

36from . import interfaces 

37from . import mapperlib 

38from ._orm_constructors import composite 

39from ._orm_constructors import deferred 

40from ._orm_constructors import mapped_column 

41from ._orm_constructors import relationship 

42from ._orm_constructors import synonym 

43from .attributes import InstrumentedAttribute 

44from .base import _inspect_mapped_class 

45from .base import _is_mapped_class 

46from .base import Mapped 

47from .base import ORMDescriptor 

48from .decl_base import _add_attribute 

49from .decl_base import _as_declarative 

50from .decl_base import _ClassScanMapperConfig 

51from .decl_base import _declarative_constructor 

52from .decl_base import _DeferredMapperConfig 

53from .decl_base import _del_attribute 

54from .decl_base import _mapper 

55from .descriptor_props import Composite 

56from .descriptor_props import Synonym 

57from .descriptor_props import Synonym as _orm_synonym 

58from .mapper import Mapper 

59from .properties import MappedColumn 

60from .relationships import RelationshipProperty 

61from .state import InstanceState 

62from .. import exc 

63from .. import inspection 

64from .. import util 

65from ..sql import sqltypes 

66from ..sql.base import _NoArg 

67from ..sql.elements import SQLCoreOperations 

68from ..sql.schema import MetaData 

69from ..sql.selectable import FromClause 

70from ..util import hybridmethod 

71from ..util import hybridproperty 

72from ..util import typing as compat_typing 

73from ..util.typing import CallableReference 

74from ..util.typing import de_optionalize_union_types 

75from ..util.typing import is_generic 

76from ..util.typing import is_literal 

77from ..util.typing import Literal 

78from ..util.typing import LITERAL_TYPES 

79from ..util.typing import Self 

80 

81if TYPE_CHECKING: 

82 from ._typing import _O 

83 from ._typing import _RegistryType 

84 from .instrumentation import ClassManager 

85 from .interfaces import _DataclassArguments 

86 from .interfaces import MapperProperty 

87 from .state import InstanceState # noqa 

88 from ..sql._typing import _TypeEngineArgument 

89 from ..sql.type_api import _MatchedOnType 

90 

91_T = TypeVar("_T", bound=Any) 

92 

93_TT = TypeVar("_TT", bound=Any) 

94 

95# it's not clear how to have Annotated, Union objects etc. as keys here 

96# from a typing perspective so just leave it open ended for now 

97_TypeAnnotationMapType = Mapping[Any, "_TypeEngineArgument[Any]"] 

98_MutableTypeAnnotationMapType = Dict[Any, "_TypeEngineArgument[Any]"] 

99 

100_DeclaredAttrDecorated = Callable[ 

101 ..., Union[Mapped[_T], ORMDescriptor[_T], SQLCoreOperations[_T]] 

102] 

103 

104 

105def has_inherited_table(cls: Type[_O]) -> bool: 

106 """Given a class, return True if any of the classes it inherits from has a 

107 mapped table, otherwise return False. 

108 

109 This is used in declarative mixins to build attributes that behave 

110 differently for the base class vs. a subclass in an inheritance 

111 hierarchy. 

112 

113 .. seealso:: 

114 

115 :ref:`decl_mixin_inheritance` 

116 

117 """ 

118 for class_ in cls.__mro__[1:]: 

119 if getattr(class_, "__table__", None) is not None: 

120 return True 

121 return False 

122 

123 

124class _DynamicAttributesType(type): 

125 def __setattr__(cls, key: str, value: Any) -> None: 

126 if "__mapper__" in cls.__dict__: 

127 _add_attribute(cls, key, value) 

128 else: 

129 type.__setattr__(cls, key, value) 

130 

131 def __delattr__(cls, key: str) -> None: 

132 if "__mapper__" in cls.__dict__: 

133 _del_attribute(cls, key) 

134 else: 

135 type.__delattr__(cls, key) 

136 

137 

138class DeclarativeAttributeIntercept( 

139 _DynamicAttributesType, 

140 # Inspectable is used only by the mypy plugin 

141 inspection.Inspectable[Mapper[Any]], 

142): 

143 """Metaclass that may be used in conjunction with the 

144 :class:`_orm.DeclarativeBase` class to support addition of class 

145 attributes dynamically. 

146 

147 """ 

148 

149 

150@compat_typing.dataclass_transform( 

151 field_specifiers=( 

152 MappedColumn, 

153 RelationshipProperty, 

154 Composite, 

155 Synonym, 

156 mapped_column, 

157 relationship, 

158 composite, 

159 synonym, 

160 deferred, 

161 ), 

162) 

163class DCTransformDeclarative(DeclarativeAttributeIntercept): 

164 """metaclass that includes @dataclass_transforms""" 

165 

166 

167class DeclarativeMeta(DeclarativeAttributeIntercept): 

168 metadata: MetaData 

169 registry: RegistryType 

170 

171 def __init__( 

172 cls, classname: Any, bases: Any, dict_: Any, **kw: Any 

173 ) -> None: 

174 # use cls.__dict__, which can be modified by an 

175 # __init_subclass__() method (#7900) 

176 dict_ = cls.__dict__ 

177 

178 # early-consume registry from the initial declarative base, 

179 # assign privately to not conflict with subclass attributes named 

180 # "registry" 

181 reg = getattr(cls, "_sa_registry", None) 

182 if reg is None: 

183 reg = dict_.get("registry", None) 

184 if not isinstance(reg, registry): 

185 raise exc.InvalidRequestError( 

186 "Declarative base class has no 'registry' attribute, " 

187 "or registry is not a sqlalchemy.orm.registry() object" 

188 ) 

189 else: 

190 cls._sa_registry = reg 

191 

192 if not cls.__dict__.get("__abstract__", False): 

193 _as_declarative(reg, cls, dict_) 

194 type.__init__(cls, classname, bases, dict_) 

195 

196 

197def synonym_for( 

198 name: str, map_column: bool = False 

199) -> Callable[[Callable[..., Any]], Synonym[Any]]: 

200 """Decorator that produces an :func:`_orm.synonym` 

201 attribute in conjunction with a Python descriptor. 

202 

203 The function being decorated is passed to :func:`_orm.synonym` as the 

204 :paramref:`.orm.synonym.descriptor` parameter:: 

205 

206 class MyClass(Base): 

207 __tablename__ = "my_table" 

208 

209 id = Column(Integer, primary_key=True) 

210 _job_status = Column("job_status", String(50)) 

211 

212 @synonym_for("job_status") 

213 @property 

214 def job_status(self): 

215 return "Status: %s" % self._job_status 

216 

217 The :ref:`hybrid properties <mapper_hybrids>` feature of SQLAlchemy 

218 is typically preferred instead of synonyms, which is a more legacy 

219 feature. 

220 

221 .. seealso:: 

222 

223 :ref:`synonyms` - Overview of synonyms 

224 

225 :func:`_orm.synonym` - the mapper-level function 

226 

227 :ref:`mapper_hybrids` - The Hybrid Attribute extension provides an 

228 updated approach to augmenting attribute behavior more flexibly than 

229 can be achieved with synonyms. 

230 

231 """ 

232 

233 def decorate(fn: Callable[..., Any]) -> Synonym[Any]: 

234 return _orm_synonym(name, map_column=map_column, descriptor=fn) 

235 

236 return decorate 

237 

238 

239class _declared_attr_common: 

240 def __init__( 

241 self, 

242 fn: Callable[..., Any], 

243 cascading: bool = False, 

244 quiet: bool = False, 

245 ): 

246 # suppport 

247 # @declared_attr 

248 # @classmethod 

249 # def foo(cls) -> Mapped[thing]: 

250 # ... 

251 # which seems to help typing tools interpret the fn as a classmethod 

252 # for situations where needed 

253 if isinstance(fn, classmethod): 

254 fn = fn.__func__ 

255 

256 self.fget = fn 

257 self._cascading = cascading 

258 self._quiet = quiet 

259 self.__doc__ = fn.__doc__ 

260 

261 def _collect_return_annotation(self) -> Optional[Type[Any]]: 

262 return util.get_annotations(self.fget).get("return") 

263 

264 def __get__(self, instance: Optional[object], owner: Any) -> Any: 

265 # the declared_attr needs to make use of a cache that exists 

266 # for the span of the declarative scan_attributes() phase. 

267 # to achieve this we look at the class manager that's configured. 

268 

269 # note this method should not be called outside of the declarative 

270 # setup phase 

271 

272 cls = owner 

273 manager = attributes.opt_manager_of_class(cls) 

274 if manager is None: 

275 if not re.match(r"^__.+__$", self.fget.__name__): 

276 # if there is no manager at all, then this class hasn't been 

277 # run through declarative or mapper() at all, emit a warning. 

278 util.warn( 

279 "Unmanaged access of declarative attribute %s from " 

280 "non-mapped class %s" % (self.fget.__name__, cls.__name__) 

281 ) 

282 return self.fget(cls) 

283 elif manager.is_mapped: 

284 # the class is mapped, which means we're outside of the declarative 

285 # scan setup, just run the function. 

286 return self.fget(cls) 

287 

288 # here, we are inside of the declarative scan. use the registry 

289 # that is tracking the values of these attributes. 

290 declarative_scan = manager.declarative_scan() 

291 

292 # assert that we are in fact in the declarative scan 

293 assert declarative_scan is not None 

294 

295 reg = declarative_scan.declared_attr_reg 

296 

297 if self in reg: 

298 return reg[self] 

299 else: 

300 reg[self] = obj = self.fget(cls) 

301 return obj 

302 

303 

304class _declared_directive(_declared_attr_common, Generic[_T]): 

305 # see mapping_api.rst for docstring 

306 

307 if typing.TYPE_CHECKING: 

308 

309 def __init__( 

310 self, 

311 fn: Callable[..., _T], 

312 cascading: bool = False, 

313 ): ... 

314 

315 def __get__(self, instance: Optional[object], owner: Any) -> _T: ... 

316 

317 def __set__(self, instance: Any, value: Any) -> None: ... 

318 

319 def __delete__(self, instance: Any) -> None: ... 

320 

321 def __call__(self, fn: Callable[..., _TT]) -> _declared_directive[_TT]: 

322 # extensive fooling of mypy underway... 

323 ... 

324 

325 

326class declared_attr(interfaces._MappedAttribute[_T], _declared_attr_common): 

327 """Mark a class-level method as representing the definition of 

328 a mapped property or Declarative directive. 

329 

330 :class:`_orm.declared_attr` is typically applied as a decorator to a class 

331 level method, turning the attribute into a scalar-like property that can be 

332 invoked from the uninstantiated class. The Declarative mapping process 

333 looks for these :class:`_orm.declared_attr` callables as it scans classes, 

334 and assumes any attribute marked with :class:`_orm.declared_attr` will be a 

335 callable that will produce an object specific to the Declarative mapping or 

336 table configuration. 

337 

338 :class:`_orm.declared_attr` is usually applicable to 

339 :ref:`mixins <orm_mixins_toplevel>`, to define relationships that are to be 

340 applied to different implementors of the class. It may also be used to 

341 define dynamically generated column expressions and other Declarative 

342 attributes. 

343 

344 Example:: 

345 

346 class ProvidesUserMixin: 

347 "A mixin that adds a 'user' relationship to classes." 

348 

349 user_id: Mapped[int] = mapped_column(ForeignKey("user_table.id")) 

350 

351 @declared_attr 

352 def user(cls) -> Mapped["User"]: 

353 return relationship("User") 

354 

355 When used with Declarative directives such as ``__tablename__``, the 

356 :meth:`_orm.declared_attr.directive` modifier may be used which indicates 

357 to :pep:`484` typing tools that the given method is not dealing with 

358 :class:`_orm.Mapped` attributes:: 

359 

360 class CreateTableName: 

361 @declared_attr.directive 

362 def __tablename__(cls) -> str: 

363 return cls.__name__.lower() 

364 

365 :class:`_orm.declared_attr` can also be applied directly to mapped 

366 classes, to allow for attributes that dynamically configure themselves 

367 on subclasses when using mapped inheritance schemes. Below 

368 illustrates :class:`_orm.declared_attr` to create a dynamic scheme 

369 for generating the :paramref:`_orm.Mapper.polymorphic_identity` parameter 

370 for subclasses:: 

371 

372 class Employee(Base): 

373 __tablename__ = "employee" 

374 

375 id: Mapped[int] = mapped_column(primary_key=True) 

376 type: Mapped[str] = mapped_column(String(50)) 

377 

378 @declared_attr.directive 

379 def __mapper_args__(cls) -> Dict[str, Any]: 

380 if cls.__name__ == "Employee": 

381 return { 

382 "polymorphic_on": cls.type, 

383 "polymorphic_identity": "Employee", 

384 } 

385 else: 

386 return {"polymorphic_identity": cls.__name__} 

387 

388 

389 class Engineer(Employee): 

390 pass 

391 

392 :class:`_orm.declared_attr` supports decorating functions that are 

393 explicitly decorated with ``@classmethod``. This is never necessary from a 

394 runtime perspective, however may be needed in order to support :pep:`484` 

395 typing tools that don't otherwise recognize the decorated function as 

396 having class-level behaviors for the ``cls`` parameter:: 

397 

398 class SomethingMixin: 

399 x: Mapped[int] 

400 y: Mapped[int] 

401 

402 @declared_attr 

403 @classmethod 

404 def x_plus_y(cls) -> Mapped[int]: 

405 return column_property(cls.x + cls.y) 

406 

407 .. versionadded:: 2.0 - :class:`_orm.declared_attr` can accommodate a 

408 function decorated with ``@classmethod`` to help with :pep:`484` 

409 integration where needed. 

410 

411 

412 .. seealso:: 

413 

414 :ref:`orm_mixins_toplevel` - Declarative Mixin documentation with 

415 background on use patterns for :class:`_orm.declared_attr`. 

416 

417 """ # noqa: E501 

418 

419 if typing.TYPE_CHECKING: 

420 

421 def __init__( 

422 self, 

423 fn: _DeclaredAttrDecorated[_T], 

424 cascading: bool = False, 

425 ): ... 

426 

427 def __set__(self, instance: Any, value: Any) -> None: ... 

428 

429 def __delete__(self, instance: Any) -> None: ... 

430 

431 # this is the Mapped[] API where at class descriptor get time we want 

432 # the type checker to see InstrumentedAttribute[_T]. However the 

433 # callable function prior to mapping in fact calls the given 

434 # declarative function that does not return InstrumentedAttribute 

435 @overload 

436 def __get__( 

437 self, instance: None, owner: Any 

438 ) -> InstrumentedAttribute[_T]: ... 

439 

440 @overload 

441 def __get__(self, instance: object, owner: Any) -> _T: ... 

442 

443 def __get__( 

444 self, instance: Optional[object], owner: Any 

445 ) -> Union[InstrumentedAttribute[_T], _T]: ... 

446 

447 @hybridmethod 

448 def _stateful(cls, **kw: Any) -> _stateful_declared_attr[_T]: 

449 return _stateful_declared_attr(**kw) 

450 

451 @hybridproperty 

452 def directive(cls) -> _declared_directive[Any]: 

453 # see mapping_api.rst for docstring 

454 return _declared_directive # type: ignore 

455 

456 @hybridproperty 

457 def cascading(cls) -> _stateful_declared_attr[_T]: 

458 # see mapping_api.rst for docstring 

459 return cls._stateful(cascading=True) 

460 

461 

462class _stateful_declared_attr(declared_attr[_T]): 

463 kw: Dict[str, Any] 

464 

465 def __init__(self, **kw: Any): 

466 self.kw = kw 

467 

468 @hybridmethod 

469 def _stateful(self, **kw: Any) -> _stateful_declared_attr[_T]: 

470 new_kw = self.kw.copy() 

471 new_kw.update(kw) 

472 return _stateful_declared_attr(**new_kw) 

473 

474 def __call__(self, fn: _DeclaredAttrDecorated[_T]) -> declared_attr[_T]: 

475 return declared_attr(fn, **self.kw) 

476 

477 

478@util.deprecated( 

479 "2.1", 

480 "The declarative_mixin decorator was used only by the now removed " 

481 "mypy plugin so it has no longer any use and can be safely removed.", 

482) 

483def declarative_mixin(cls: Type[_T]) -> Type[_T]: 

484 """Mark a class as providing the feature of "declarative mixin". 

485 

486 E.g.:: 

487 

488 from sqlalchemy.orm import declared_attr 

489 from sqlalchemy.orm import declarative_mixin 

490 

491 

492 @declarative_mixin 

493 class MyMixin: 

494 

495 @declared_attr 

496 def __tablename__(cls): 

497 return cls.__name__.lower() 

498 

499 __table_args__ = {"mysql_engine": "InnoDB"} 

500 __mapper_args__ = {"always_refresh": True} 

501 

502 id = Column(Integer, primary_key=True) 

503 

504 

505 class MyModel(MyMixin, Base): 

506 name = Column(String(1000)) 

507 

508 The :func:`_orm.declarative_mixin` decorator currently does not modify 

509 the given class in any way; it's current purpose is strictly to assist 

510 the Mypy plugin in being able to identify 

511 SQLAlchemy declarative mixin classes when no other context is present. 

512 

513 .. versionadded:: 1.4.6 

514 

515 .. seealso:: 

516 

517 :ref:`orm_mixins_toplevel` 

518 

519 """ # noqa: E501 

520 

521 return cls 

522 

523 

524def _setup_declarative_base(cls: Type[Any]) -> None: 

525 if "metadata" in cls.__dict__: 

526 metadata = cls.__dict__["metadata"] 

527 else: 

528 metadata = None 

529 

530 if "type_annotation_map" in cls.__dict__: 

531 type_annotation_map = cls.__dict__["type_annotation_map"] 

532 else: 

533 type_annotation_map = None 

534 

535 reg = cls.__dict__.get("registry", None) 

536 if reg is not None: 

537 if not isinstance(reg, registry): 

538 raise exc.InvalidRequestError( 

539 "Declarative base class has a 'registry' attribute that is " 

540 "not an instance of sqlalchemy.orm.registry()" 

541 ) 

542 elif type_annotation_map is not None: 

543 raise exc.InvalidRequestError( 

544 "Declarative base class has both a 'registry' attribute and a " 

545 "type_annotation_map entry. Per-base type_annotation_maps " 

546 "are not supported. Please apply the type_annotation_map " 

547 "to this registry directly." 

548 ) 

549 

550 else: 

551 reg = registry( 

552 metadata=metadata, type_annotation_map=type_annotation_map 

553 ) 

554 cls.registry = reg 

555 

556 cls._sa_registry = reg 

557 

558 if "metadata" not in cls.__dict__: 

559 cls.metadata = cls.registry.metadata 

560 

561 if getattr(cls, "__init__", object.__init__) is object.__init__: 

562 cls.__init__ = cls.registry.constructor 

563 

564 

565class MappedAsDataclass(metaclass=DCTransformDeclarative): 

566 """Mixin class to indicate when mapping this class, also convert it to be 

567 a dataclass. 

568 

569 .. seealso:: 

570 

571 :ref:`orm_declarative_native_dataclasses` - complete background 

572 on SQLAlchemy native dataclass mapping 

573 

574 .. versionadded:: 2.0 

575 

576 """ 

577 

578 def __init_subclass__( 

579 cls, 

580 init: Union[_NoArg, bool] = _NoArg.NO_ARG, 

581 repr: Union[_NoArg, bool] = _NoArg.NO_ARG, # noqa: A002 

582 eq: Union[_NoArg, bool] = _NoArg.NO_ARG, 

583 order: Union[_NoArg, bool] = _NoArg.NO_ARG, 

584 unsafe_hash: Union[_NoArg, bool] = _NoArg.NO_ARG, 

585 match_args: Union[_NoArg, bool] = _NoArg.NO_ARG, 

586 kw_only: Union[_NoArg, bool] = _NoArg.NO_ARG, 

587 dataclass_callable: Union[ 

588 _NoArg, Callable[..., Type[Any]] 

589 ] = _NoArg.NO_ARG, 

590 **kw: Any, 

591 ) -> None: 

592 apply_dc_transforms: _DataclassArguments = { 

593 "init": init, 

594 "repr": repr, 

595 "eq": eq, 

596 "order": order, 

597 "unsafe_hash": unsafe_hash, 

598 "match_args": match_args, 

599 "kw_only": kw_only, 

600 "dataclass_callable": dataclass_callable, 

601 } 

602 current_transforms: _DataclassArguments 

603 

604 if hasattr(cls, "_sa_apply_dc_transforms"): 

605 current = cls._sa_apply_dc_transforms 

606 

607 _ClassScanMapperConfig._assert_dc_arguments(current) 

608 

609 cls._sa_apply_dc_transforms = current_transforms = { # type: ignore # noqa: E501 

610 k: current.get(k, _NoArg.NO_ARG) if v is _NoArg.NO_ARG else v 

611 for k, v in apply_dc_transforms.items() 

612 } 

613 else: 

614 cls._sa_apply_dc_transforms = current_transforms = ( 

615 apply_dc_transforms 

616 ) 

617 

618 super().__init_subclass__(**kw) 

619 

620 if not _is_mapped_class(cls): 

621 new_anno = ( 

622 _ClassScanMapperConfig._update_annotations_for_non_mapped_class 

623 )(cls) 

624 _ClassScanMapperConfig._apply_dataclasses_to_any_class( 

625 current_transforms, cls, new_anno 

626 ) 

627 

628 

629class DeclarativeBase( 

630 # Inspectable is used only by the mypy plugin 

631 inspection.Inspectable[InstanceState[Any]], 

632 metaclass=DeclarativeAttributeIntercept, 

633): 

634 """Base class used for declarative class definitions. 

635 

636 The :class:`_orm.DeclarativeBase` allows for the creation of new 

637 declarative bases in such a way that is compatible with type checkers:: 

638 

639 

640 from sqlalchemy.orm import DeclarativeBase 

641 

642 

643 class Base(DeclarativeBase): 

644 pass 

645 

646 The above ``Base`` class is now usable as the base for new declarative 

647 mappings. The superclass makes use of the ``__init_subclass__()`` 

648 method to set up new classes and metaclasses aren't used. 

649 

650 When first used, the :class:`_orm.DeclarativeBase` class instantiates a new 

651 :class:`_orm.registry` to be used with the base, assuming one was not 

652 provided explicitly. The :class:`_orm.DeclarativeBase` class supports 

653 class-level attributes which act as parameters for the construction of this 

654 registry; such as to indicate a specific :class:`_schema.MetaData` 

655 collection as well as a specific value for 

656 :paramref:`_orm.registry.type_annotation_map`:: 

657 

658 from typing import Annotated 

659 

660 from sqlalchemy import BigInteger 

661 from sqlalchemy import MetaData 

662 from sqlalchemy import String 

663 from sqlalchemy.orm import DeclarativeBase 

664 

665 bigint = Annotated[int, "bigint"] 

666 my_metadata = MetaData() 

667 

668 

669 class Base(DeclarativeBase): 

670 metadata = my_metadata 

671 type_annotation_map = { 

672 str: String().with_variant(String(255), "mysql", "mariadb"), 

673 bigint: BigInteger(), 

674 } 

675 

676 Class-level attributes which may be specified include: 

677 

678 :param metadata: optional :class:`_schema.MetaData` collection. 

679 If a :class:`_orm.registry` is constructed automatically, this 

680 :class:`_schema.MetaData` collection will be used to construct it. 

681 Otherwise, the local :class:`_schema.MetaData` collection will supercede 

682 that used by an existing :class:`_orm.registry` passed using the 

683 :paramref:`_orm.DeclarativeBase.registry` parameter. 

684 :param type_annotation_map: optional type annotation map that will be 

685 passed to the :class:`_orm.registry` as 

686 :paramref:`_orm.registry.type_annotation_map`. 

687 :param registry: supply a pre-existing :class:`_orm.registry` directly. 

688 

689 .. versionadded:: 2.0 Added :class:`.DeclarativeBase`, so that declarative 

690 base classes may be constructed in such a way that is also recognized 

691 by :pep:`484` type checkers. As a result, :class:`.DeclarativeBase` 

692 and other subclassing-oriented APIs should be seen as 

693 superseding previous "class returned by a function" APIs, namely 

694 :func:`_orm.declarative_base` and :meth:`_orm.registry.generate_base`, 

695 where the base class returned cannot be recognized by type checkers 

696 without using plugins. 

697 

698 **__init__ behavior** 

699 

700 In a plain Python class, the base-most ``__init__()`` method in the class 

701 hierarchy is ``object.__init__()``, which accepts no arguments. However, 

702 when the :class:`_orm.DeclarativeBase` subclass is first declared, the 

703 class is given an ``__init__()`` method that links to the 

704 :paramref:`_orm.registry.constructor` constructor function, if no 

705 ``__init__()`` method is already present; this is the usual declarative 

706 constructor that will assign keyword arguments as attributes on the 

707 instance, assuming those attributes are established at the class level 

708 (i.e. are mapped, or are linked to a descriptor). This constructor is 

709 **never accessed by a mapped class without being called explicitly via 

710 super()**, as mapped classes are themselves given an ``__init__()`` method 

711 directly which calls :paramref:`_orm.registry.constructor`, so in the 

712 default case works independently of what the base-most ``__init__()`` 

713 method does. 

714 

715 .. versionchanged:: 2.0.1 :class:`_orm.DeclarativeBase` has a default 

716 constructor that links to :paramref:`_orm.registry.constructor` by 

717 default, so that calls to ``super().__init__()`` can access this 

718 constructor. Previously, due to an implementation mistake, this default 

719 constructor was missing, and calling ``super().__init__()`` would invoke 

720 ``object.__init__()``. 

721 

722 The :class:`_orm.DeclarativeBase` subclass may also declare an explicit 

723 ``__init__()`` method which will replace the use of the 

724 :paramref:`_orm.registry.constructor` function at this level:: 

725 

726 class Base(DeclarativeBase): 

727 def __init__(self, id=None): 

728 self.id = id 

729 

730 Mapped classes still will not invoke this constructor implicitly; it 

731 remains only accessible by calling ``super().__init__()``:: 

732 

733 class MyClass(Base): 

734 def __init__(self, id=None, name=None): 

735 self.name = name 

736 super().__init__(id=id) 

737 

738 Note that this is a different behavior from what functions like the legacy 

739 :func:`_orm.declarative_base` would do; the base created by those functions 

740 would always install :paramref:`_orm.registry.constructor` for 

741 ``__init__()``. 

742 

743 

744 """ 

745 

746 if typing.TYPE_CHECKING: 

747 

748 def _sa_inspect_type(self) -> Mapper[Self]: ... 

749 

750 def _sa_inspect_instance(self) -> InstanceState[Self]: ... 

751 

752 _sa_registry: ClassVar[_RegistryType] 

753 

754 registry: ClassVar[_RegistryType] 

755 """Refers to the :class:`_orm.registry` in use where new 

756 :class:`_orm.Mapper` objects will be associated.""" 

757 

758 metadata: ClassVar[MetaData] 

759 """Refers to the :class:`_schema.MetaData` collection that will be used 

760 for new :class:`_schema.Table` objects. 

761 

762 .. seealso:: 

763 

764 :ref:`orm_declarative_metadata` 

765 

766 """ 

767 

768 __name__: ClassVar[str] 

769 

770 # this ideally should be Mapper[Self], but mypy as of 1.4.1 does not 

771 # like it, and breaks the declared_attr_one test. Pyright/pylance is 

772 # ok with it. 

773 __mapper__: ClassVar[Mapper[Any]] 

774 """The :class:`_orm.Mapper` object to which a particular class is 

775 mapped. 

776 

777 May also be acquired using :func:`_sa.inspect`, e.g. 

778 ``inspect(klass)``. 

779 

780 """ 

781 

782 __table__: ClassVar[FromClause] 

783 """The :class:`_sql.FromClause` to which a particular subclass is 

784 mapped. 

785 

786 This is usually an instance of :class:`_schema.Table` but may also 

787 refer to other kinds of :class:`_sql.FromClause` such as 

788 :class:`_sql.Subquery`, depending on how the class is mapped. 

789 

790 .. seealso:: 

791 

792 :ref:`orm_declarative_metadata` 

793 

794 """ 

795 

796 # pyright/pylance do not consider a classmethod a ClassVar so use Any 

797 # https://github.com/microsoft/pylance-release/issues/3484 

798 __tablename__: Any 

799 """String name to assign to the generated 

800 :class:`_schema.Table` object, if not specified directly via 

801 :attr:`_orm.DeclarativeBase.__table__`. 

802 

803 .. seealso:: 

804 

805 :ref:`orm_declarative_table` 

806 

807 """ 

808 

809 __mapper_args__: Any 

810 """Dictionary of arguments which will be passed to the 

811 :class:`_orm.Mapper` constructor. 

812 

813 .. seealso:: 

814 

815 :ref:`orm_declarative_mapper_options` 

816 

817 """ 

818 

819 __table_args__: Any 

820 """A dictionary or tuple of arguments that will be passed to the 

821 :class:`_schema.Table` constructor. See 

822 :ref:`orm_declarative_table_configuration` 

823 for background on the specific structure of this collection. 

824 

825 .. seealso:: 

826 

827 :ref:`orm_declarative_table_configuration` 

828 

829 """ 

830 

831 def __init__(self, **kw: Any): ... 

832 

833 def __init_subclass__(cls, **kw: Any) -> None: 

834 if DeclarativeBase in cls.__bases__: 

835 _check_not_declarative(cls, DeclarativeBase) 

836 _setup_declarative_base(cls) 

837 else: 

838 _as_declarative(cls._sa_registry, cls, cls.__dict__) 

839 super().__init_subclass__(**kw) 

840 

841 

842def _check_not_declarative(cls: Type[Any], base: Type[Any]) -> None: 

843 cls_dict = cls.__dict__ 

844 if ( 

845 "__table__" in cls_dict 

846 and not ( 

847 callable(cls_dict["__table__"]) 

848 or hasattr(cls_dict["__table__"], "__get__") 

849 ) 

850 ) or isinstance(cls_dict.get("__tablename__", None), str): 

851 raise exc.InvalidRequestError( 

852 f"Cannot use {base.__name__!r} directly as a declarative base " 

853 "class. Create a Base by creating a subclass of it." 

854 ) 

855 

856 

857class DeclarativeBaseNoMeta( 

858 # Inspectable is used only by the mypy plugin 

859 inspection.Inspectable[InstanceState[Any]] 

860): 

861 """Same as :class:`_orm.DeclarativeBase`, but does not use a metaclass 

862 to intercept new attributes. 

863 

864 The :class:`_orm.DeclarativeBaseNoMeta` base may be used when use of 

865 custom metaclasses is desirable. 

866 

867 .. versionadded:: 2.0 

868 

869 

870 """ 

871 

872 _sa_registry: ClassVar[_RegistryType] 

873 

874 registry: ClassVar[_RegistryType] 

875 """Refers to the :class:`_orm.registry` in use where new 

876 :class:`_orm.Mapper` objects will be associated.""" 

877 

878 metadata: ClassVar[MetaData] 

879 """Refers to the :class:`_schema.MetaData` collection that will be used 

880 for new :class:`_schema.Table` objects. 

881 

882 .. seealso:: 

883 

884 :ref:`orm_declarative_metadata` 

885 

886 """ 

887 

888 # this ideally should be Mapper[Self], but mypy as of 1.4.1 does not 

889 # like it, and breaks the declared_attr_one test. Pyright/pylance is 

890 # ok with it. 

891 __mapper__: ClassVar[Mapper[Any]] 

892 """The :class:`_orm.Mapper` object to which a particular class is 

893 mapped. 

894 

895 May also be acquired using :func:`_sa.inspect`, e.g. 

896 ``inspect(klass)``. 

897 

898 """ 

899 

900 __table__: Optional[FromClause] 

901 """The :class:`_sql.FromClause` to which a particular subclass is 

902 mapped. 

903 

904 This is usually an instance of :class:`_schema.Table` but may also 

905 refer to other kinds of :class:`_sql.FromClause` such as 

906 :class:`_sql.Subquery`, depending on how the class is mapped. 

907 

908 .. seealso:: 

909 

910 :ref:`orm_declarative_metadata` 

911 

912 """ 

913 

914 if typing.TYPE_CHECKING: 

915 

916 def _sa_inspect_type(self) -> Mapper[Self]: ... 

917 

918 def _sa_inspect_instance(self) -> InstanceState[Self]: ... 

919 

920 __tablename__: Any 

921 """String name to assign to the generated 

922 :class:`_schema.Table` object, if not specified directly via 

923 :attr:`_orm.DeclarativeBase.__table__`. 

924 

925 .. seealso:: 

926 

927 :ref:`orm_declarative_table` 

928 

929 """ 

930 

931 __mapper_args__: Any 

932 """Dictionary of arguments which will be passed to the 

933 :class:`_orm.Mapper` constructor. 

934 

935 .. seealso:: 

936 

937 :ref:`orm_declarative_mapper_options` 

938 

939 """ 

940 

941 __table_args__: Any 

942 """A dictionary or tuple of arguments that will be passed to the 

943 :class:`_schema.Table` constructor. See 

944 :ref:`orm_declarative_table_configuration` 

945 for background on the specific structure of this collection. 

946 

947 .. seealso:: 

948 

949 :ref:`orm_declarative_table_configuration` 

950 

951 """ 

952 

953 def __init__(self, **kw: Any): ... 

954 

955 def __init_subclass__(cls, **kw: Any) -> None: 

956 if DeclarativeBaseNoMeta in cls.__bases__: 

957 _check_not_declarative(cls, DeclarativeBaseNoMeta) 

958 _setup_declarative_base(cls) 

959 else: 

960 _as_declarative(cls._sa_registry, cls, cls.__dict__) 

961 super().__init_subclass__(**kw) 

962 

963 

964def add_mapped_attribute( 

965 target: Type[_O], key: str, attr: MapperProperty[Any] 

966) -> None: 

967 """Add a new mapped attribute to an ORM mapped class. 

968 

969 E.g.:: 

970 

971 add_mapped_attribute(User, "addresses", relationship(Address)) 

972 

973 This may be used for ORM mappings that aren't using a declarative 

974 metaclass that intercepts attribute set operations. 

975 

976 .. versionadded:: 2.0 

977 

978 

979 """ 

980 _add_attribute(target, key, attr) 

981 

982 

983def declarative_base( 

984 *, 

985 metadata: Optional[MetaData] = None, 

986 mapper: Optional[Callable[..., Mapper[Any]]] = None, 

987 cls: Type[Any] = object, 

988 name: str = "Base", 

989 class_registry: Optional[clsregistry._ClsRegistryType] = None, 

990 type_annotation_map: Optional[_TypeAnnotationMapType] = None, 

991 constructor: Callable[..., None] = _declarative_constructor, 

992 metaclass: Type[Any] = DeclarativeMeta, 

993) -> Any: 

994 r"""Construct a base class for declarative class definitions. 

995 

996 The new base class will be given a metaclass that produces 

997 appropriate :class:`~sqlalchemy.schema.Table` objects and makes 

998 the appropriate :class:`_orm.Mapper` calls based on the 

999 information provided declaratively in the class and any subclasses 

1000 of the class. 

1001 

1002 .. versionchanged:: 2.0 Note that the :func:`_orm.declarative_base` 

1003 function is superseded by the new :class:`_orm.DeclarativeBase` class, 

1004 which generates a new "base" class using subclassing, rather than 

1005 return value of a function. This allows an approach that is compatible 

1006 with :pep:`484` typing tools. 

1007 

1008 The :func:`_orm.declarative_base` function is a shorthand version 

1009 of using the :meth:`_orm.registry.generate_base` 

1010 method. That is, the following:: 

1011 

1012 from sqlalchemy.orm import declarative_base 

1013 

1014 Base = declarative_base() 

1015 

1016 Is equivalent to:: 

1017 

1018 from sqlalchemy.orm import registry 

1019 

1020 mapper_registry = registry() 

1021 Base = mapper_registry.generate_base() 

1022 

1023 See the docstring for :class:`_orm.registry` 

1024 and :meth:`_orm.registry.generate_base` 

1025 for more details. 

1026 

1027 .. versionchanged:: 1.4 The :func:`_orm.declarative_base` 

1028 function is now a specialization of the more generic 

1029 :class:`_orm.registry` class. The function also moves to the 

1030 ``sqlalchemy.orm`` package from the ``declarative.ext`` package. 

1031 

1032 

1033 :param metadata: 

1034 An optional :class:`~sqlalchemy.schema.MetaData` instance. All 

1035 :class:`~sqlalchemy.schema.Table` objects implicitly declared by 

1036 subclasses of the base will share this MetaData. A MetaData instance 

1037 will be created if none is provided. The 

1038 :class:`~sqlalchemy.schema.MetaData` instance will be available via the 

1039 ``metadata`` attribute of the generated declarative base class. 

1040 

1041 :param mapper: 

1042 An optional callable, defaults to :class:`_orm.Mapper`. Will 

1043 be used to map subclasses to their Tables. 

1044 

1045 :param cls: 

1046 Defaults to :class:`object`. A type to use as the base for the generated 

1047 declarative base class. May be a class or tuple of classes. 

1048 

1049 :param name: 

1050 Defaults to ``Base``. The display name for the generated 

1051 class. Customizing this is not required, but can improve clarity in 

1052 tracebacks and debugging. 

1053 

1054 :param constructor: 

1055 Specify the implementation for the ``__init__`` function on a mapped 

1056 class that has no ``__init__`` of its own. Defaults to an 

1057 implementation that assigns \**kwargs for declared 

1058 fields and relationships to an instance. If ``None`` is supplied, 

1059 no __init__ will be provided and construction will fall back to 

1060 cls.__init__ by way of the normal Python semantics. 

1061 

1062 :param class_registry: optional dictionary that will serve as the 

1063 registry of class names-> mapped classes when string names 

1064 are used to identify classes inside of :func:`_orm.relationship` 

1065 and others. Allows two or more declarative base classes 

1066 to share the same registry of class names for simplified 

1067 inter-base relationships. 

1068 

1069 :param type_annotation_map: optional dictionary of Python types to 

1070 SQLAlchemy :class:`_types.TypeEngine` classes or instances. This 

1071 is used exclusively by the :class:`_orm.MappedColumn` construct 

1072 to produce column types based on annotations within the 

1073 :class:`_orm.Mapped` type. 

1074 

1075 

1076 .. versionadded:: 2.0 

1077 

1078 .. seealso:: 

1079 

1080 :ref:`orm_declarative_mapped_column_type_map` 

1081 

1082 :param metaclass: 

1083 Defaults to :class:`.DeclarativeMeta`. A metaclass or __metaclass__ 

1084 compatible callable to use as the meta type of the generated 

1085 declarative base class. 

1086 

1087 .. seealso:: 

1088 

1089 :class:`_orm.registry` 

1090 

1091 """ 

1092 

1093 return registry( 

1094 metadata=metadata, 

1095 class_registry=class_registry, 

1096 constructor=constructor, 

1097 type_annotation_map=type_annotation_map, 

1098 ).generate_base( 

1099 mapper=mapper, 

1100 cls=cls, 

1101 name=name, 

1102 metaclass=metaclass, 

1103 ) 

1104 

1105 

1106class registry: 

1107 """Generalized registry for mapping classes. 

1108 

1109 The :class:`_orm.registry` serves as the basis for maintaining a collection 

1110 of mappings, and provides configurational hooks used to map classes. 

1111 

1112 The three general kinds of mappings supported are Declarative Base, 

1113 Declarative Decorator, and Imperative Mapping. All of these mapping 

1114 styles may be used interchangeably: 

1115 

1116 * :meth:`_orm.registry.generate_base` returns a new declarative base 

1117 class, and is the underlying implementation of the 

1118 :func:`_orm.declarative_base` function. 

1119 

1120 * :meth:`_orm.registry.mapped` provides a class decorator that will 

1121 apply declarative mapping to a class without the use of a declarative 

1122 base class. 

1123 

1124 * :meth:`_orm.registry.map_imperatively` will produce a 

1125 :class:`_orm.Mapper` for a class without scanning the class for 

1126 declarative class attributes. This method suits the use case historically 

1127 provided by the ``sqlalchemy.orm.mapper()`` classical mapping function, 

1128 which is removed as of SQLAlchemy 2.0. 

1129 

1130 .. versionadded:: 1.4 

1131 

1132 .. seealso:: 

1133 

1134 :ref:`orm_mapping_classes_toplevel` - overview of class mapping 

1135 styles. 

1136 

1137 """ 

1138 

1139 _class_registry: clsregistry._ClsRegistryType 

1140 _managers: weakref.WeakKeyDictionary[ClassManager[Any], Literal[True]] 

1141 metadata: MetaData 

1142 constructor: CallableReference[Callable[..., None]] 

1143 type_annotation_map: _MutableTypeAnnotationMapType 

1144 _dependents: Set[_RegistryType] 

1145 _dependencies: Set[_RegistryType] 

1146 _new_mappers: bool 

1147 

1148 def __init__( 

1149 self, 

1150 *, 

1151 metadata: Optional[MetaData] = None, 

1152 class_registry: Optional[clsregistry._ClsRegistryType] = None, 

1153 type_annotation_map: Optional[_TypeAnnotationMapType] = None, 

1154 constructor: Callable[..., None] = _declarative_constructor, 

1155 ): 

1156 r"""Construct a new :class:`_orm.registry` 

1157 

1158 :param metadata: 

1159 An optional :class:`_schema.MetaData` instance. All 

1160 :class:`_schema.Table` objects generated using declarative 

1161 table mapping will make use of this :class:`_schema.MetaData` 

1162 collection. If this argument is left at its default of ``None``, 

1163 a blank :class:`_schema.MetaData` collection is created. 

1164 

1165 :param constructor: 

1166 Specify the implementation for the ``__init__`` function on a mapped 

1167 class that has no ``__init__`` of its own. Defaults to an 

1168 implementation that assigns \**kwargs for declared 

1169 fields and relationships to an instance. If ``None`` is supplied, 

1170 no __init__ will be provided and construction will fall back to 

1171 cls.__init__ by way of the normal Python semantics. 

1172 

1173 :param class_registry: optional dictionary that will serve as the 

1174 registry of class names-> mapped classes when string names 

1175 are used to identify classes inside of :func:`_orm.relationship` 

1176 and others. Allows two or more declarative base classes 

1177 to share the same registry of class names for simplified 

1178 inter-base relationships. 

1179 

1180 :param type_annotation_map: optional dictionary of Python types to 

1181 SQLAlchemy :class:`_types.TypeEngine` classes or instances. 

1182 The provided dict will update the default type mapping. This 

1183 is used exclusively by the :class:`_orm.MappedColumn` construct 

1184 to produce column types based on annotations within the 

1185 :class:`_orm.Mapped` type. 

1186 

1187 .. versionadded:: 2.0 

1188 

1189 .. seealso:: 

1190 

1191 :ref:`orm_declarative_mapped_column_type_map` 

1192 

1193 

1194 """ 

1195 lcl_metadata = metadata or MetaData() 

1196 

1197 if class_registry is None: 

1198 class_registry = weakref.WeakValueDictionary() 

1199 

1200 self._class_registry = class_registry 

1201 self._managers = weakref.WeakKeyDictionary() 

1202 self.metadata = lcl_metadata 

1203 self.constructor = constructor 

1204 self.type_annotation_map = {} 

1205 if type_annotation_map is not None: 

1206 self.update_type_annotation_map(type_annotation_map) 

1207 self._dependents = set() 

1208 self._dependencies = set() 

1209 

1210 self._new_mappers = False 

1211 

1212 with mapperlib._CONFIGURE_MUTEX: 

1213 mapperlib._mapper_registries[self] = True 

1214 

1215 def update_type_annotation_map( 

1216 self, 

1217 type_annotation_map: _TypeAnnotationMapType, 

1218 ) -> None: 

1219 """update the :paramref:`_orm.registry.type_annotation_map` with new 

1220 values.""" 

1221 

1222 self.type_annotation_map.update( 

1223 { 

1224 de_optionalize_union_types(typ): sqltype 

1225 for typ, sqltype in type_annotation_map.items() 

1226 } 

1227 ) 

1228 

1229 def _resolve_type( 

1230 self, python_type: _MatchedOnType 

1231 ) -> Optional[sqltypes.TypeEngine[Any]]: 

1232 python_type_type: Type[Any] 

1233 search: Iterable[Tuple[_MatchedOnType, Type[Any]]] 

1234 

1235 if is_generic(python_type): 

1236 if is_literal(python_type): 

1237 python_type_type = python_type # type: ignore[assignment] 

1238 

1239 search = ( 

1240 (python_type, python_type_type), 

1241 *((lt, python_type_type) for lt in LITERAL_TYPES), 

1242 ) 

1243 else: 

1244 python_type_type = python_type.__origin__ 

1245 search = ((python_type, python_type_type),) 

1246 elif isinstance(python_type, type): 

1247 python_type_type = python_type 

1248 search = ((pt, pt) for pt in python_type_type.__mro__) 

1249 else: 

1250 python_type_type = python_type # type: ignore[assignment] 

1251 search = ((python_type, python_type_type),) 

1252 

1253 for pt, flattened in search: 

1254 # we search through full __mro__ for types. however... 

1255 sql_type = self.type_annotation_map.get(pt) 

1256 if sql_type is None: 

1257 sql_type = sqltypes._type_map_get(pt) # type: ignore # noqa: E501 

1258 

1259 if sql_type is not None: 

1260 sql_type_inst = sqltypes.to_instance(sql_type) 

1261 

1262 # ... this additional step will reject most 

1263 # type -> supertype matches, such as if we had 

1264 # a MyInt(int) subclass. note also we pass NewType() 

1265 # here directly; these always have to be in the 

1266 # type_annotation_map to be useful 

1267 resolved_sql_type = sql_type_inst._resolve_for_python_type( 

1268 python_type_type, 

1269 pt, 

1270 flattened, 

1271 ) 

1272 if resolved_sql_type is not None: 

1273 return resolved_sql_type 

1274 

1275 return None 

1276 

1277 @property 

1278 def mappers(self) -> FrozenSet[Mapper[Any]]: 

1279 """read only collection of all :class:`_orm.Mapper` objects.""" 

1280 

1281 return frozenset(manager.mapper for manager in self._managers) 

1282 

1283 def _set_depends_on(self, registry: RegistryType) -> None: 

1284 if registry is self: 

1285 return 

1286 registry._dependents.add(self) 

1287 self._dependencies.add(registry) 

1288 

1289 def _flag_new_mapper(self, mapper: Mapper[Any]) -> None: 

1290 mapper._ready_for_configure = True 

1291 if self._new_mappers: 

1292 return 

1293 

1294 for reg in self._recurse_with_dependents({self}): 

1295 reg._new_mappers = True 

1296 

1297 @classmethod 

1298 def _recurse_with_dependents( 

1299 cls, registries: Set[RegistryType] 

1300 ) -> Iterator[RegistryType]: 

1301 todo = registries 

1302 done = set() 

1303 while todo: 

1304 reg = todo.pop() 

1305 done.add(reg) 

1306 

1307 # if yielding would remove dependents, make sure we have 

1308 # them before 

1309 todo.update(reg._dependents.difference(done)) 

1310 yield reg 

1311 

1312 # if yielding would add dependents, make sure we have them 

1313 # after 

1314 todo.update(reg._dependents.difference(done)) 

1315 

1316 @classmethod 

1317 def _recurse_with_dependencies( 

1318 cls, registries: Set[RegistryType] 

1319 ) -> Iterator[RegistryType]: 

1320 todo = registries 

1321 done = set() 

1322 while todo: 

1323 reg = todo.pop() 

1324 done.add(reg) 

1325 

1326 # if yielding would remove dependencies, make sure we have 

1327 # them before 

1328 todo.update(reg._dependencies.difference(done)) 

1329 

1330 yield reg 

1331 

1332 # if yielding would remove dependencies, make sure we have 

1333 # them before 

1334 todo.update(reg._dependencies.difference(done)) 

1335 

1336 def _mappers_to_configure(self) -> Iterator[Mapper[Any]]: 

1337 return ( 

1338 manager.mapper 

1339 for manager in list(self._managers) 

1340 if manager.is_mapped 

1341 and not manager.mapper.configured 

1342 and manager.mapper._ready_for_configure 

1343 ) 

1344 

1345 def _dispose_cls(self, cls: Type[_O]) -> None: 

1346 clsregistry._remove_class(cls.__name__, cls, self._class_registry) 

1347 

1348 def _add_manager(self, manager: ClassManager[Any]) -> None: 

1349 self._managers[manager] = True 

1350 if manager.is_mapped: 

1351 raise exc.ArgumentError( 

1352 "Class '%s' already has a primary mapper defined. " 

1353 % manager.class_ 

1354 ) 

1355 assert manager.registry is None 

1356 manager.registry = self 

1357 

1358 def configure(self, cascade: bool = False) -> None: 

1359 """Configure all as-yet unconfigured mappers in this 

1360 :class:`_orm.registry`. 

1361 

1362 The configure step is used to reconcile and initialize the 

1363 :func:`_orm.relationship` linkages between mapped classes, as well as 

1364 to invoke configuration events such as the 

1365 :meth:`_orm.MapperEvents.before_configured` and 

1366 :meth:`_orm.MapperEvents.after_configured`, which may be used by ORM 

1367 extensions or user-defined extension hooks. 

1368 

1369 If one or more mappers in this registry contain 

1370 :func:`_orm.relationship` constructs that refer to mapped classes in 

1371 other registries, this registry is said to be *dependent* on those 

1372 registries. In order to configure those dependent registries 

1373 automatically, the :paramref:`_orm.registry.configure.cascade` flag 

1374 should be set to ``True``. Otherwise, if they are not configured, an 

1375 exception will be raised. The rationale behind this behavior is to 

1376 allow an application to programmatically invoke configuration of 

1377 registries while controlling whether or not the process implicitly 

1378 reaches other registries. 

1379 

1380 As an alternative to invoking :meth:`_orm.registry.configure`, the ORM 

1381 function :func:`_orm.configure_mappers` function may be used to ensure 

1382 configuration is complete for all :class:`_orm.registry` objects in 

1383 memory. This is generally simpler to use and also predates the usage of 

1384 :class:`_orm.registry` objects overall. However, this function will 

1385 impact all mappings throughout the running Python process and may be 

1386 more memory/time consuming for an application that has many registries 

1387 in use for different purposes that may not be needed immediately. 

1388 

1389 .. seealso:: 

1390 

1391 :func:`_orm.configure_mappers` 

1392 

1393 

1394 .. versionadded:: 1.4.0b2 

1395 

1396 """ 

1397 mapperlib._configure_registries({self}, cascade=cascade) 

1398 

1399 def dispose(self, cascade: bool = False) -> None: 

1400 """Dispose of all mappers in this :class:`_orm.registry`. 

1401 

1402 After invocation, all the classes that were mapped within this registry 

1403 will no longer have class instrumentation associated with them. This 

1404 method is the per-:class:`_orm.registry` analogue to the 

1405 application-wide :func:`_orm.clear_mappers` function. 

1406 

1407 If this registry contains mappers that are dependencies of other 

1408 registries, typically via :func:`_orm.relationship` links, then those 

1409 registries must be disposed as well. When such registries exist in 

1410 relation to this one, their :meth:`_orm.registry.dispose` method will 

1411 also be called, if the :paramref:`_orm.registry.dispose.cascade` flag 

1412 is set to ``True``; otherwise, an error is raised if those registries 

1413 were not already disposed. 

1414 

1415 .. versionadded:: 1.4.0b2 

1416 

1417 .. seealso:: 

1418 

1419 :func:`_orm.clear_mappers` 

1420 

1421 """ 

1422 

1423 mapperlib._dispose_registries({self}, cascade=cascade) 

1424 

1425 def _dispose_manager_and_mapper(self, manager: ClassManager[Any]) -> None: 

1426 if "mapper" in manager.__dict__: 

1427 mapper = manager.mapper 

1428 

1429 mapper._set_dispose_flags() 

1430 

1431 class_ = manager.class_ 

1432 self._dispose_cls(class_) 

1433 instrumentation._instrumentation_factory.unregister(class_) 

1434 

1435 def generate_base( 

1436 self, 

1437 mapper: Optional[Callable[..., Mapper[Any]]] = None, 

1438 cls: Type[Any] = object, 

1439 name: str = "Base", 

1440 metaclass: Type[Any] = DeclarativeMeta, 

1441 ) -> Any: 

1442 """Generate a declarative base class. 

1443 

1444 Classes that inherit from the returned class object will be 

1445 automatically mapped using declarative mapping. 

1446 

1447 E.g.:: 

1448 

1449 from sqlalchemy.orm import registry 

1450 

1451 mapper_registry = registry() 

1452 

1453 Base = mapper_registry.generate_base() 

1454 

1455 

1456 class MyClass(Base): 

1457 __tablename__ = "my_table" 

1458 id = Column(Integer, primary_key=True) 

1459 

1460 The above dynamically generated class is equivalent to the 

1461 non-dynamic example below:: 

1462 

1463 from sqlalchemy.orm import registry 

1464 from sqlalchemy.orm.decl_api import DeclarativeMeta 

1465 

1466 mapper_registry = registry() 

1467 

1468 

1469 class Base(metaclass=DeclarativeMeta): 

1470 __abstract__ = True 

1471 registry = mapper_registry 

1472 metadata = mapper_registry.metadata 

1473 

1474 __init__ = mapper_registry.constructor 

1475 

1476 .. versionchanged:: 2.0 Note that the 

1477 :meth:`_orm.registry.generate_base` method is superseded by the new 

1478 :class:`_orm.DeclarativeBase` class, which generates a new "base" 

1479 class using subclassing, rather than return value of a function. 

1480 This allows an approach that is compatible with :pep:`484` typing 

1481 tools. 

1482 

1483 The :meth:`_orm.registry.generate_base` method provides the 

1484 implementation for the :func:`_orm.declarative_base` function, which 

1485 creates the :class:`_orm.registry` and base class all at once. 

1486 

1487 See the section :ref:`orm_declarative_mapping` for background and 

1488 examples. 

1489 

1490 :param mapper: 

1491 An optional callable, defaults to :class:`_orm.Mapper`. 

1492 This function is used to generate new :class:`_orm.Mapper` objects. 

1493 

1494 :param cls: 

1495 Defaults to :class:`object`. A type to use as the base for the 

1496 generated declarative base class. May be a class or tuple of classes. 

1497 

1498 :param name: 

1499 Defaults to ``Base``. The display name for the generated 

1500 class. Customizing this is not required, but can improve clarity in 

1501 tracebacks and debugging. 

1502 

1503 :param metaclass: 

1504 Defaults to :class:`.DeclarativeMeta`. A metaclass or __metaclass__ 

1505 compatible callable to use as the meta type of the generated 

1506 declarative base class. 

1507 

1508 .. seealso:: 

1509 

1510 :ref:`orm_declarative_mapping` 

1511 

1512 :func:`_orm.declarative_base` 

1513 

1514 """ 

1515 metadata = self.metadata 

1516 

1517 bases = not isinstance(cls, tuple) and (cls,) or cls 

1518 

1519 class_dict: Dict[str, Any] = dict(registry=self, metadata=metadata) 

1520 if isinstance(cls, type): 

1521 class_dict["__doc__"] = cls.__doc__ 

1522 

1523 if self.constructor is not None: 

1524 class_dict["__init__"] = self.constructor 

1525 

1526 class_dict["__abstract__"] = True 

1527 if mapper: 

1528 class_dict["__mapper_cls__"] = mapper 

1529 

1530 if hasattr(cls, "__class_getitem__"): 

1531 

1532 def __class_getitem__(cls: Type[_T], key: Any) -> Type[_T]: 

1533 # allow generic classes in py3.9+ 

1534 return cls 

1535 

1536 class_dict["__class_getitem__"] = __class_getitem__ 

1537 

1538 return metaclass(name, bases, class_dict) 

1539 

1540 @compat_typing.dataclass_transform( 

1541 field_specifiers=( 

1542 MappedColumn, 

1543 RelationshipProperty, 

1544 Composite, 

1545 Synonym, 

1546 mapped_column, 

1547 relationship, 

1548 composite, 

1549 synonym, 

1550 deferred, 

1551 ), 

1552 ) 

1553 @overload 

1554 def mapped_as_dataclass(self, __cls: Type[_O], /) -> Type[_O]: ... 

1555 

1556 @overload 

1557 def mapped_as_dataclass( 

1558 self, 

1559 __cls: Literal[None] = ..., 

1560 /, 

1561 *, 

1562 init: Union[_NoArg, bool] = ..., 

1563 repr: Union[_NoArg, bool] = ..., # noqa: A002 

1564 eq: Union[_NoArg, bool] = ..., 

1565 order: Union[_NoArg, bool] = ..., 

1566 unsafe_hash: Union[_NoArg, bool] = ..., 

1567 match_args: Union[_NoArg, bool] = ..., 

1568 kw_only: Union[_NoArg, bool] = ..., 

1569 dataclass_callable: Union[_NoArg, Callable[..., Type[Any]]] = ..., 

1570 ) -> Callable[[Type[_O]], Type[_O]]: ... 

1571 

1572 def mapped_as_dataclass( 

1573 self, 

1574 __cls: Optional[Type[_O]] = None, 

1575 /, 

1576 *, 

1577 init: Union[_NoArg, bool] = _NoArg.NO_ARG, 

1578 repr: Union[_NoArg, bool] = _NoArg.NO_ARG, # noqa: A002 

1579 eq: Union[_NoArg, bool] = _NoArg.NO_ARG, 

1580 order: Union[_NoArg, bool] = _NoArg.NO_ARG, 

1581 unsafe_hash: Union[_NoArg, bool] = _NoArg.NO_ARG, 

1582 match_args: Union[_NoArg, bool] = _NoArg.NO_ARG, 

1583 kw_only: Union[_NoArg, bool] = _NoArg.NO_ARG, 

1584 dataclass_callable: Union[ 

1585 _NoArg, Callable[..., Type[Any]] 

1586 ] = _NoArg.NO_ARG, 

1587 ) -> Union[Type[_O], Callable[[Type[_O]], Type[_O]]]: 

1588 """Class decorator that will apply the Declarative mapping process 

1589 to a given class, and additionally convert the class to be a 

1590 Python dataclass. 

1591 

1592 .. seealso:: 

1593 

1594 :ref:`orm_declarative_native_dataclasses` - complete background 

1595 on SQLAlchemy native dataclass mapping 

1596 

1597 

1598 .. versionadded:: 2.0 

1599 

1600 

1601 """ 

1602 

1603 def decorate(cls: Type[_O]) -> Type[_O]: 

1604 apply_dc_transforms: _DataclassArguments = { 

1605 "init": init, 

1606 "repr": repr, 

1607 "eq": eq, 

1608 "order": order, 

1609 "unsafe_hash": unsafe_hash, 

1610 "match_args": match_args, 

1611 "kw_only": kw_only, 

1612 "dataclass_callable": dataclass_callable, 

1613 } 

1614 

1615 setattr(cls, "_sa_apply_dc_transforms", apply_dc_transforms) 

1616 _as_declarative(self, cls, cls.__dict__) 

1617 return cls 

1618 

1619 if __cls: 

1620 return decorate(__cls) 

1621 else: 

1622 return decorate 

1623 

1624 def mapped(self, cls: Type[_O]) -> Type[_O]: 

1625 """Class decorator that will apply the Declarative mapping process 

1626 to a given class. 

1627 

1628 E.g.:: 

1629 

1630 from sqlalchemy.orm import registry 

1631 

1632 mapper_registry = registry() 

1633 

1634 

1635 @mapper_registry.mapped 

1636 class Foo: 

1637 __tablename__ = "some_table" 

1638 

1639 id = Column(Integer, primary_key=True) 

1640 name = Column(String) 

1641 

1642 See the section :ref:`orm_declarative_mapping` for complete 

1643 details and examples. 

1644 

1645 :param cls: class to be mapped. 

1646 

1647 :return: the class that was passed. 

1648 

1649 .. seealso:: 

1650 

1651 :ref:`orm_declarative_mapping` 

1652 

1653 :meth:`_orm.registry.generate_base` - generates a base class 

1654 that will apply Declarative mapping to subclasses automatically 

1655 using a Python metaclass. 

1656 

1657 .. seealso:: 

1658 

1659 :meth:`_orm.registry.mapped_as_dataclass` 

1660 

1661 """ 

1662 _as_declarative(self, cls, cls.__dict__) 

1663 return cls 

1664 

1665 def as_declarative_base(self, **kw: Any) -> Callable[[Type[_T]], Type[_T]]: 

1666 """ 

1667 Class decorator which will invoke 

1668 :meth:`_orm.registry.generate_base` 

1669 for a given base class. 

1670 

1671 E.g.:: 

1672 

1673 from sqlalchemy.orm import registry 

1674 

1675 mapper_registry = registry() 

1676 

1677 

1678 @mapper_registry.as_declarative_base() 

1679 class Base: 

1680 @declared_attr 

1681 def __tablename__(cls): 

1682 return cls.__name__.lower() 

1683 

1684 id = Column(Integer, primary_key=True) 

1685 

1686 

1687 class MyMappedClass(Base): ... 

1688 

1689 All keyword arguments passed to 

1690 :meth:`_orm.registry.as_declarative_base` are passed 

1691 along to :meth:`_orm.registry.generate_base`. 

1692 

1693 """ 

1694 

1695 def decorate(cls: Type[_T]) -> Type[_T]: 

1696 kw["cls"] = cls 

1697 kw["name"] = cls.__name__ 

1698 return self.generate_base(**kw) # type: ignore 

1699 

1700 return decorate 

1701 

1702 def map_declaratively(self, cls: Type[_O]) -> Mapper[_O]: 

1703 """Map a class declaratively. 

1704 

1705 In this form of mapping, the class is scanned for mapping information, 

1706 including for columns to be associated with a table, and/or an 

1707 actual table object. 

1708 

1709 Returns the :class:`_orm.Mapper` object. 

1710 

1711 E.g.:: 

1712 

1713 from sqlalchemy.orm import registry 

1714 

1715 mapper_registry = registry() 

1716 

1717 

1718 class Foo: 

1719 __tablename__ = "some_table" 

1720 

1721 id = Column(Integer, primary_key=True) 

1722 name = Column(String) 

1723 

1724 

1725 mapper = mapper_registry.map_declaratively(Foo) 

1726 

1727 This function is more conveniently invoked indirectly via either the 

1728 :meth:`_orm.registry.mapped` class decorator or by subclassing a 

1729 declarative metaclass generated from 

1730 :meth:`_orm.registry.generate_base`. 

1731 

1732 See the section :ref:`orm_declarative_mapping` for complete 

1733 details and examples. 

1734 

1735 :param cls: class to be mapped. 

1736 

1737 :return: a :class:`_orm.Mapper` object. 

1738 

1739 .. seealso:: 

1740 

1741 :ref:`orm_declarative_mapping` 

1742 

1743 :meth:`_orm.registry.mapped` - more common decorator interface 

1744 to this function. 

1745 

1746 :meth:`_orm.registry.map_imperatively` 

1747 

1748 """ 

1749 _as_declarative(self, cls, cls.__dict__) 

1750 return cls.__mapper__ # type: ignore 

1751 

1752 def map_imperatively( 

1753 self, 

1754 class_: Type[_O], 

1755 local_table: Optional[FromClause] = None, 

1756 **kw: Any, 

1757 ) -> Mapper[_O]: 

1758 r"""Map a class imperatively. 

1759 

1760 In this form of mapping, the class is not scanned for any mapping 

1761 information. Instead, all mapping constructs are passed as 

1762 arguments. 

1763 

1764 This method is intended to be fully equivalent to the now-removed 

1765 SQLAlchemy ``mapper()`` function, except that it's in terms of 

1766 a particular registry. 

1767 

1768 E.g.:: 

1769 

1770 from sqlalchemy.orm import registry 

1771 

1772 mapper_registry = registry() 

1773 

1774 my_table = Table( 

1775 "my_table", 

1776 mapper_registry.metadata, 

1777 Column("id", Integer, primary_key=True), 

1778 ) 

1779 

1780 

1781 class MyClass: 

1782 pass 

1783 

1784 

1785 mapper_registry.map_imperatively(MyClass, my_table) 

1786 

1787 See the section :ref:`orm_imperative_mapping` for complete background 

1788 and usage examples. 

1789 

1790 :param class\_: The class to be mapped. Corresponds to the 

1791 :paramref:`_orm.Mapper.class_` parameter. 

1792 

1793 :param local_table: the :class:`_schema.Table` or other 

1794 :class:`_sql.FromClause` object that is the subject of the mapping. 

1795 Corresponds to the 

1796 :paramref:`_orm.Mapper.local_table` parameter. 

1797 

1798 :param \**kw: all other keyword arguments are passed to the 

1799 :class:`_orm.Mapper` constructor directly. 

1800 

1801 .. seealso:: 

1802 

1803 :ref:`orm_imperative_mapping` 

1804 

1805 :ref:`orm_declarative_mapping` 

1806 

1807 """ 

1808 return _mapper(self, class_, local_table, kw) 

1809 

1810 

1811RegistryType = registry 

1812 

1813if not TYPE_CHECKING: 

1814 # allow for runtime type resolution of ``ClassVar[_RegistryType]`` 

1815 _RegistryType = registry # noqa 

1816 

1817 

1818def as_declarative(**kw: Any) -> Callable[[Type[_T]], Type[_T]]: 

1819 """ 

1820 Class decorator which will adapt a given class into a 

1821 :func:`_orm.declarative_base`. 

1822 

1823 This function makes use of the :meth:`_orm.registry.as_declarative_base` 

1824 method, by first creating a :class:`_orm.registry` automatically 

1825 and then invoking the decorator. 

1826 

1827 E.g.:: 

1828 

1829 from sqlalchemy.orm import as_declarative 

1830 

1831 

1832 @as_declarative() 

1833 class Base: 

1834 @declared_attr 

1835 def __tablename__(cls): 

1836 return cls.__name__.lower() 

1837 

1838 id = Column(Integer, primary_key=True) 

1839 

1840 

1841 class MyMappedClass(Base): ... 

1842 

1843 .. seealso:: 

1844 

1845 :meth:`_orm.registry.as_declarative_base` 

1846 

1847 """ 

1848 metadata, class_registry = ( 

1849 kw.pop("metadata", None), 

1850 kw.pop("class_registry", None), 

1851 ) 

1852 

1853 return registry( 

1854 metadata=metadata, class_registry=class_registry 

1855 ).as_declarative_base(**kw) 

1856 

1857 

1858@inspection._inspects( 

1859 DeclarativeMeta, DeclarativeBase, DeclarativeAttributeIntercept 

1860) 

1861def _inspect_decl_meta(cls: Type[Any]) -> Optional[Mapper[Any]]: 

1862 mp: Optional[Mapper[Any]] = _inspect_mapped_class(cls) 

1863 if mp is None: 

1864 if _DeferredMapperConfig.has_cls(cls): 

1865 _DeferredMapperConfig.raise_unmapped_for_cls(cls) 

1866 return mp