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

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

465 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 itertools 

13import re 

14import typing 

15from typing import Any 

16from typing import Callable 

17from typing import ClassVar 

18from typing import Dict 

19from typing import FrozenSet 

20from typing import Generic 

21from typing import Iterable 

22from typing import Iterator 

23from typing import Mapping 

24from typing import Optional 

25from typing import overload 

26from typing import Set 

27from typing import Tuple 

28from typing import Type 

29from typing import TYPE_CHECKING 

30from typing import TypeVar 

31from typing import Union 

32import weakref 

33 

34from . import attributes 

35from . import clsregistry 

36from . import instrumentation 

37from . import interfaces 

38from . import mapperlib 

39from ._orm_constructors import composite 

40from ._orm_constructors import deferred 

41from ._orm_constructors import mapped_column 

42from ._orm_constructors import relationship 

43from ._orm_constructors import synonym 

44from .attributes import InstrumentedAttribute 

45from .base import _inspect_mapped_class 

46from .base import _is_mapped_class 

47from .base import Mapped 

48from .base import ORMDescriptor 

49from .decl_base import _add_attribute 

50from .decl_base import _as_declarative 

51from .decl_base import _ClassScanMapperConfig 

52from .decl_base import _declarative_constructor 

53from .decl_base import _DeferredMapperConfig 

54from .decl_base import _del_attribute 

55from .decl_base import _mapper 

56from .descriptor_props import Composite 

57from .descriptor_props import Synonym 

58from .descriptor_props import Synonym as _orm_synonym 

59from .mapper import Mapper 

60from .properties import MappedColumn 

61from .relationships import RelationshipProperty 

62from .state import InstanceState 

63from .. import exc 

64from .. import inspection 

65from .. import util 

66from ..sql import sqltypes 

67from ..sql.base import _NoArg 

68from ..sql.elements import SQLCoreOperations 

69from ..sql.schema import MetaData 

70from ..sql.selectable import FromClause 

71from ..util import hybridmethod 

72from ..util import hybridproperty 

73from ..util import typing as compat_typing 

74from ..util import warn_deprecated 

75from ..util.typing import CallableReference 

76from ..util.typing import de_optionalize_union_types 

77from ..util.typing import flatten_newtype 

78from ..util.typing import is_generic 

79from ..util.typing import is_literal 

80from ..util.typing import is_newtype 

81from ..util.typing import is_pep695 

82from ..util.typing import Literal 

83from ..util.typing import LITERAL_TYPES 

84from ..util.typing import Self 

85 

86if TYPE_CHECKING: 

87 from ._typing import _O 

88 from ._typing import _RegistryType 

89 from .decl_base import _DataclassArguments 

90 from .instrumentation import ClassManager 

91 from .interfaces import MapperProperty 

92 from .state import InstanceState # noqa 

93 from ..sql._typing import _TypeEngineArgument 

94 from ..sql.type_api import _MatchedOnType 

95 

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

97 

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

99 

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

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

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

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

104 

105_DeclaredAttrDecorated = Callable[ 

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

107] 

108 

109 

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

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

112 mapped table, otherwise return False. 

113 

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

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

116 hierarchy. 

117 

118 .. seealso:: 

119 

120 :ref:`decl_mixin_inheritance` 

121 

122 """ 

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

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

125 return True 

126 return False 

127 

128 

129class _DynamicAttributesType(type): 

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

131 if "__mapper__" in cls.__dict__: 

132 _add_attribute(cls, key, value) 

133 else: 

134 type.__setattr__(cls, key, value) 

135 

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

137 if "__mapper__" in cls.__dict__: 

138 _del_attribute(cls, key) 

139 else: 

140 type.__delattr__(cls, key) 

141 

142 

143class DeclarativeAttributeIntercept( 

144 _DynamicAttributesType, 

145 # Inspectable is used only by the mypy plugin 

146 inspection.Inspectable[Mapper[Any]], 

147): 

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

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

150 attributes dynamically. 

151 

152 """ 

153 

154 

155@compat_typing.dataclass_transform( 

156 field_specifiers=( 

157 MappedColumn, 

158 RelationshipProperty, 

159 Composite, 

160 Synonym, 

161 mapped_column, 

162 relationship, 

163 composite, 

164 synonym, 

165 deferred, 

166 ), 

167) 

168class DCTransformDeclarative(DeclarativeAttributeIntercept): 

169 """metaclass that includes @dataclass_transforms""" 

170 

171 

172class DeclarativeMeta(DeclarativeAttributeIntercept): 

173 metadata: MetaData 

174 registry: RegistryType 

175 

176 def __init__( 

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

178 ) -> None: 

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

180 # __init_subclass__() method (#7900) 

181 dict_ = cls.__dict__ 

182 

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

184 # assign privately to not conflict with subclass attributes named 

185 # "registry" 

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

187 if reg is None: 

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

189 if not isinstance(reg, registry): 

190 raise exc.InvalidRequestError( 

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

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

193 ) 

194 else: 

195 cls._sa_registry = reg 

196 

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

198 _as_declarative(reg, cls, dict_) 

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

200 

201 

202def synonym_for( 

203 name: str, map_column: bool = False 

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

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

206 attribute in conjunction with a Python descriptor. 

207 

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

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

210 

211 class MyClass(Base): 

212 __tablename__ = "my_table" 

213 

214 id = Column(Integer, primary_key=True) 

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

216 

217 @synonym_for("job_status") 

218 @property 

219 def job_status(self): 

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

221 

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

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

224 feature. 

225 

226 .. seealso:: 

227 

228 :ref:`synonyms` - Overview of synonyms 

229 

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

231 

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

233 updated approach to augmenting attribute behavior more flexibly than 

234 can be achieved with synonyms. 

235 

236 """ 

237 

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

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

240 

241 return decorate 

242 

243 

244class _declared_attr_common: 

245 def __init__( 

246 self, 

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

248 cascading: bool = False, 

249 quiet: bool = False, 

250 ): 

251 # suppport 

252 # @declared_attr 

253 # @classmethod 

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

255 # ... 

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

257 # for situations where needed 

258 if isinstance(fn, classmethod): 

259 fn = fn.__func__ 

260 

261 self.fget = fn 

262 self._cascading = cascading 

263 self._quiet = quiet 

264 self.__doc__ = fn.__doc__ 

265 

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

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

268 

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

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

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

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

273 

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

275 # setup phase 

276 

277 cls = owner 

278 manager = attributes.opt_manager_of_class(cls) 

279 if manager is None: 

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

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

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

283 util.warn( 

284 "Unmanaged access of declarative attribute %s from " 

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

286 ) 

287 return self.fget(cls) 

288 elif manager.is_mapped: 

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

290 # scan setup, just run the function. 

291 return self.fget(cls) 

292 

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

294 # that is tracking the values of these attributes. 

295 declarative_scan = manager.declarative_scan() 

296 

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

298 assert declarative_scan is not None 

299 

300 reg = declarative_scan.declared_attr_reg 

301 

302 if self in reg: 

303 return reg[self] 

304 else: 

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

306 return obj 

307 

308 

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

310 # see mapping_api.rst for docstring 

311 

312 if typing.TYPE_CHECKING: 

313 

314 def __init__( 

315 self, 

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

317 cascading: bool = False, 

318 ): ... 

319 

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

321 

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

323 

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

325 

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

327 # extensive fooling of mypy underway... 

328 ... 

329 

330 

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

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

333 a mapped property or Declarative directive. 

334 

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

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

337 invoked from the uninstantiated class. The Declarative mapping process 

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

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

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

341 table configuration. 

342 

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

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

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

346 define dynamically generated column expressions and other Declarative 

347 attributes. 

348 

349 Example:: 

350 

351 class ProvidesUserMixin: 

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

353 

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

355 

356 @declared_attr 

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

358 return relationship("User") 

359 

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

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

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

363 :class:`_orm.Mapped` attributes:: 

364 

365 class CreateTableName: 

366 @declared_attr.directive 

367 def __tablename__(cls) -> str: 

368 return cls.__name__.lower() 

369 

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

371 classes, to allow for attributes that dynamically configure themselves 

372 on subclasses when using mapped inheritance schemes. Below 

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

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

375 for subclasses:: 

376 

377 class Employee(Base): 

378 __tablename__ = "employee" 

379 

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

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

382 

383 @declared_attr.directive 

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

385 if cls.__name__ == "Employee": 

386 return { 

387 "polymorphic_on": cls.type, 

388 "polymorphic_identity": "Employee", 

389 } 

390 else: 

391 return {"polymorphic_identity": cls.__name__} 

392 

393 

394 class Engineer(Employee): 

395 pass 

396 

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

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

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

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

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

402 

403 class SomethingMixin: 

404 x: Mapped[int] 

405 y: Mapped[int] 

406 

407 @declared_attr 

408 @classmethod 

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

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

411 

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

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

414 integration where needed. 

415 

416 

417 .. seealso:: 

418 

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

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

421 

422 """ # noqa: E501 

423 

424 if typing.TYPE_CHECKING: 

425 

426 def __init__( 

427 self, 

428 fn: _DeclaredAttrDecorated[_T], 

429 cascading: bool = False, 

430 ): ... 

431 

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

433 

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

435 

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

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

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

439 # declarative function that does not return InstrumentedAttribute 

440 @overload 

441 def __get__( 

442 self, instance: None, owner: Any 

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

444 

445 @overload 

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

447 

448 def __get__( 

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

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

451 

452 @hybridmethod 

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

454 return _stateful_declared_attr(**kw) 

455 

456 @hybridproperty 

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

458 # see mapping_api.rst for docstring 

459 return _declared_directive # type: ignore 

460 

461 @hybridproperty 

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

463 # see mapping_api.rst for docstring 

464 return cls._stateful(cascading=True) 

465 

466 

467class _stateful_declared_attr(declared_attr[_T]): 

468 kw: Dict[str, Any] 

469 

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

471 self.kw = kw 

472 

473 @hybridmethod 

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

475 new_kw = self.kw.copy() 

476 new_kw.update(kw) 

477 return _stateful_declared_attr(**new_kw) 

478 

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

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

481 

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 :ref:`Mypy plugin <mypy_toplevel>` 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 :ref:`mypy_declarative_mixins` - in the 

520 :ref:`Mypy plugin documentation <mypy_toplevel>` 

521 

522 """ # noqa: E501 

523 

524 return cls 

525 

526 

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

528 if "metadata" in cls.__dict__: 

529 metadata = cls.__dict__["metadata"] 

530 else: 

531 metadata = None 

532 

533 if "type_annotation_map" in cls.__dict__: 

534 type_annotation_map = cls.__dict__["type_annotation_map"] 

535 else: 

536 type_annotation_map = None 

537 

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

539 if reg is not None: 

540 if not isinstance(reg, registry): 

541 raise exc.InvalidRequestError( 

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

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

544 ) 

545 elif type_annotation_map is not None: 

546 raise exc.InvalidRequestError( 

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

548 "type_annotation_map entry. Per-base type_annotation_maps " 

549 "are not supported. Please apply the type_annotation_map " 

550 "to this registry directly." 

551 ) 

552 

553 else: 

554 reg = registry( 

555 metadata=metadata, type_annotation_map=type_annotation_map 

556 ) 

557 cls.registry = reg 

558 

559 cls._sa_registry = reg 

560 

561 if "metadata" not in cls.__dict__: 

562 cls.metadata = cls.registry.metadata 

563 

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

565 cls.__init__ = cls.registry.constructor 

566 

567 

568class MappedAsDataclass(metaclass=DCTransformDeclarative): 

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

570 a dataclass. 

571 

572 .. seealso:: 

573 

574 :ref:`orm_declarative_native_dataclasses` - complete background 

575 on SQLAlchemy native dataclass mapping 

576 

577 .. versionadded:: 2.0 

578 

579 """ 

580 

581 def __init_subclass__( 

582 cls, 

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

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

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

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

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

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

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

590 dataclass_callable: Union[ 

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

592 ] = _NoArg.NO_ARG, 

593 **kw: Any, 

594 ) -> None: 

595 apply_dc_transforms: _DataclassArguments = { 

596 "init": init, 

597 "repr": repr, 

598 "eq": eq, 

599 "order": order, 

600 "unsafe_hash": unsafe_hash, 

601 "match_args": match_args, 

602 "kw_only": kw_only, 

603 "dataclass_callable": dataclass_callable, 

604 } 

605 

606 current_transforms: _DataclassArguments 

607 

608 if hasattr(cls, "_sa_apply_dc_transforms"): 

609 current = cls._sa_apply_dc_transforms 

610 

611 _ClassScanMapperConfig._assert_dc_arguments(current) 

612 

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

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

615 for k, v in apply_dc_transforms.items() 

616 } 

617 else: 

618 cls._sa_apply_dc_transforms = current_transforms = ( 

619 apply_dc_transforms 

620 ) 

621 

622 super().__init_subclass__(**kw) 

623 

624 if not _is_mapped_class(cls): 

625 new_anno = ( 

626 _ClassScanMapperConfig._update_annotations_for_non_mapped_class 

627 )(cls) 

628 _ClassScanMapperConfig._apply_dataclasses_to_any_class( 

629 current_transforms, cls, new_anno 

630 ) 

631 

632 

633class DeclarativeBase( 

634 # Inspectable is used only by the mypy plugin 

635 inspection.Inspectable[InstanceState[Any]], 

636 metaclass=DeclarativeAttributeIntercept, 

637): 

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

639 

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

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

642 

643 

644 from sqlalchemy.orm import DeclarativeBase 

645 

646 

647 class Base(DeclarativeBase): 

648 pass 

649 

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

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

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

653 

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

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

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

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

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

659 collection as well as a specific value for 

660 :paramref:`_orm.registry.type_annotation_map`:: 

661 

662 from typing_extensions import Annotated 

663 

664 from sqlalchemy import BigInteger 

665 from sqlalchemy import MetaData 

666 from sqlalchemy import String 

667 from sqlalchemy.orm import DeclarativeBase 

668 

669 bigint = Annotated[int, "bigint"] 

670 my_metadata = MetaData() 

671 

672 

673 class Base(DeclarativeBase): 

674 metadata = my_metadata 

675 type_annotation_map = { 

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

677 bigint: BigInteger(), 

678 } 

679 

680 Class-level attributes which may be specified include: 

681 

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

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

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

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

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

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

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

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

690 :paramref:`_orm.registry.type_annotation_map`. 

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

692 

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

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

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

696 and other subclassing-oriented APIs should be seen as 

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

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

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

700 without using plugins. 

701 

702 **__init__ behavior** 

703 

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

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

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

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

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

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

710 constructor that will assign keyword arguments as attributes on the 

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

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

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

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

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

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

717 method does. 

718 

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

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

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

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

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

724 ``object.__init__()``. 

725 

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

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

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

729 

730 class Base(DeclarativeBase): 

731 def __init__(self, id=None): 

732 self.id = id 

733 

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

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

736 

737 class MyClass(Base): 

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

739 self.name = name 

740 super().__init__(id=id) 

741 

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

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

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

745 ``__init__()``. 

746 

747 

748 """ 

749 

750 if typing.TYPE_CHECKING: 

751 

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

753 

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

755 

756 _sa_registry: ClassVar[_RegistryType] 

757 

758 registry: ClassVar[_RegistryType] 

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

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

761 

762 metadata: ClassVar[MetaData] 

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

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

765 

766 .. seealso:: 

767 

768 :ref:`orm_declarative_metadata` 

769 

770 """ 

771 

772 __name__: ClassVar[str] 

773 

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

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

776 # ok with it. 

777 __mapper__: ClassVar[Mapper[Any]] 

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

779 mapped. 

780 

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

782 ``inspect(klass)``. 

783 

784 """ 

785 

786 __table__: ClassVar[FromClause] 

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

788 mapped. 

789 

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

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

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

793 

794 .. seealso:: 

795 

796 :ref:`orm_declarative_metadata` 

797 

798 """ 

799 

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

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

802 __tablename__: Any 

803 """String name to assign to the generated 

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

805 :attr:`_orm.DeclarativeBase.__table__`. 

806 

807 .. seealso:: 

808 

809 :ref:`orm_declarative_table` 

810 

811 """ 

812 

813 __mapper_args__: Any 

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

815 :class:`_orm.Mapper` constructor. 

816 

817 .. seealso:: 

818 

819 :ref:`orm_declarative_mapper_options` 

820 

821 """ 

822 

823 __table_args__: Any 

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

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

826 :ref:`orm_declarative_table_configuration` 

827 for background on the specific structure of this collection. 

828 

829 .. seealso:: 

830 

831 :ref:`orm_declarative_table_configuration` 

832 

833 """ 

834 

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

836 

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

838 if DeclarativeBase in cls.__bases__: 

839 _check_not_declarative(cls, DeclarativeBase) 

840 _setup_declarative_base(cls) 

841 else: 

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

843 super().__init_subclass__(**kw) 

844 

845 

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

847 cls_dict = cls.__dict__ 

848 if ( 

849 "__table__" in cls_dict 

850 and not ( 

851 callable(cls_dict["__table__"]) 

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

853 ) 

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

855 raise exc.InvalidRequestError( 

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

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

858 ) 

859 

860 

861class DeclarativeBaseNoMeta( 

862 # Inspectable is used only by the mypy plugin 

863 inspection.Inspectable[InstanceState[Any]] 

864): 

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

866 to intercept new attributes. 

867 

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

869 custom metaclasses is desirable. 

870 

871 .. versionadded:: 2.0 

872 

873 

874 """ 

875 

876 _sa_registry: ClassVar[_RegistryType] 

877 

878 registry: ClassVar[_RegistryType] 

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

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

881 

882 metadata: ClassVar[MetaData] 

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

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

885 

886 .. seealso:: 

887 

888 :ref:`orm_declarative_metadata` 

889 

890 """ 

891 

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

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

894 # ok with it. 

895 __mapper__: ClassVar[Mapper[Any]] 

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

897 mapped. 

898 

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

900 ``inspect(klass)``. 

901 

902 """ 

903 

904 __table__: Optional[FromClause] 

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

906 mapped. 

907 

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

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

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

911 

912 .. seealso:: 

913 

914 :ref:`orm_declarative_metadata` 

915 

916 """ 

917 

918 if typing.TYPE_CHECKING: 

919 

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

921 

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

923 

924 __tablename__: Any 

925 """String name to assign to the generated 

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

927 :attr:`_orm.DeclarativeBase.__table__`. 

928 

929 .. seealso:: 

930 

931 :ref:`orm_declarative_table` 

932 

933 """ 

934 

935 __mapper_args__: Any 

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

937 :class:`_orm.Mapper` constructor. 

938 

939 .. seealso:: 

940 

941 :ref:`orm_declarative_mapper_options` 

942 

943 """ 

944 

945 __table_args__: Any 

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

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

948 :ref:`orm_declarative_table_configuration` 

949 for background on the specific structure of this collection. 

950 

951 .. seealso:: 

952 

953 :ref:`orm_declarative_table_configuration` 

954 

955 """ 

956 

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

958 

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

960 if DeclarativeBaseNoMeta in cls.__bases__: 

961 _check_not_declarative(cls, DeclarativeBaseNoMeta) 

962 _setup_declarative_base(cls) 

963 else: 

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

965 super().__init_subclass__(**kw) 

966 

967 

968def add_mapped_attribute( 

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

970) -> None: 

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

972 

973 E.g.:: 

974 

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

976 

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

978 metaclass that intercepts attribute set operations. 

979 

980 .. versionadded:: 2.0 

981 

982 

983 """ 

984 _add_attribute(target, key, attr) 

985 

986 

987def declarative_base( 

988 *, 

989 metadata: Optional[MetaData] = None, 

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

991 cls: Type[Any] = object, 

992 name: str = "Base", 

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

994 type_annotation_map: Optional[_TypeAnnotationMapType] = None, 

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

996 metaclass: Type[Any] = DeclarativeMeta, 

997) -> Any: 

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

999 

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

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

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

1003 information provided declaratively in the class and any subclasses 

1004 of the class. 

1005 

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

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

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

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

1010 with :pep:`484` typing tools. 

1011 

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

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

1014 method. That is, the following:: 

1015 

1016 from sqlalchemy.orm import declarative_base 

1017 

1018 Base = declarative_base() 

1019 

1020 Is equivalent to:: 

1021 

1022 from sqlalchemy.orm import registry 

1023 

1024 mapper_registry = registry() 

1025 Base = mapper_registry.generate_base() 

1026 

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

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

1029 for more details. 

1030 

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

1032 function is now a specialization of the more generic 

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

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

1035 

1036 

1037 :param metadata: 

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

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

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

1041 will be created if none is provided. The 

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

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

1044 

1045 :param mapper: 

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

1047 be used to map subclasses to their Tables. 

1048 

1049 :param cls: 

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

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

1052 

1053 :param name: 

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

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

1056 tracebacks and debugging. 

1057 

1058 :param constructor: 

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

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

1061 implementation that assigns \**kwargs for declared 

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

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

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

1065 

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

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

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

1069 and others. Allows two or more declarative base classes 

1070 to share the same registry of class names for simplified 

1071 inter-base relationships. 

1072 

1073 :param type_annotation_map: optional dictionary of Python types to 

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

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

1076 to produce column types based on annotations within the 

1077 :class:`_orm.Mapped` type. 

1078 

1079 

1080 .. versionadded:: 2.0 

1081 

1082 .. seealso:: 

1083 

1084 :ref:`orm_declarative_mapped_column_type_map` 

1085 

1086 :param metaclass: 

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

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

1089 declarative base class. 

1090 

1091 .. seealso:: 

1092 

1093 :class:`_orm.registry` 

1094 

1095 """ 

1096 

1097 return registry( 

1098 metadata=metadata, 

1099 class_registry=class_registry, 

1100 constructor=constructor, 

1101 type_annotation_map=type_annotation_map, 

1102 ).generate_base( 

1103 mapper=mapper, 

1104 cls=cls, 

1105 name=name, 

1106 metaclass=metaclass, 

1107 ) 

1108 

1109 

1110class registry: 

1111 """Generalized registry for mapping classes. 

1112 

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

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

1115 

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

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

1118 styles may be used interchangeably: 

1119 

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

1121 class, and is the underlying implementation of the 

1122 :func:`_orm.declarative_base` function. 

1123 

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

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

1126 base class. 

1127 

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

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

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

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

1132 which is removed as of SQLAlchemy 2.0. 

1133 

1134 .. versionadded:: 1.4 

1135 

1136 .. seealso:: 

1137 

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

1139 styles. 

1140 

1141 """ 

1142 

1143 _class_registry: clsregistry._ClsRegistryType 

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

1145 _non_primary_mappers: weakref.WeakKeyDictionary[Mapper[Any], Literal[True]] 

1146 metadata: MetaData 

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

1148 type_annotation_map: _MutableTypeAnnotationMapType 

1149 _dependents: Set[_RegistryType] 

1150 _dependencies: Set[_RegistryType] 

1151 _new_mappers: bool 

1152 

1153 def __init__( 

1154 self, 

1155 *, 

1156 metadata: Optional[MetaData] = None, 

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

1158 type_annotation_map: Optional[_TypeAnnotationMapType] = None, 

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

1160 ): 

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

1162 

1163 :param metadata: 

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

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

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

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

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

1169 

1170 :param constructor: 

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

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

1173 implementation that assigns \**kwargs for declared 

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

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

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

1177 

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

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

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

1181 and others. Allows two or more declarative base classes 

1182 to share the same registry of class names for simplified 

1183 inter-base relationships. 

1184 

1185 :param type_annotation_map: optional dictionary of Python types to 

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

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

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

1189 to produce column types based on annotations within the 

1190 :class:`_orm.Mapped` type. 

1191 

1192 .. versionadded:: 2.0 

1193 

1194 .. seealso:: 

1195 

1196 :ref:`orm_declarative_mapped_column_type_map` 

1197 

1198 

1199 """ 

1200 lcl_metadata = metadata or MetaData() 

1201 

1202 if class_registry is None: 

1203 class_registry = weakref.WeakValueDictionary() 

1204 

1205 self._class_registry = class_registry 

1206 self._managers = weakref.WeakKeyDictionary() 

1207 self._non_primary_mappers = weakref.WeakKeyDictionary() 

1208 self.metadata = lcl_metadata 

1209 self.constructor = constructor 

1210 self.type_annotation_map = {} 

1211 if type_annotation_map is not None: 

1212 self.update_type_annotation_map(type_annotation_map) 

1213 self._dependents = set() 

1214 self._dependencies = set() 

1215 

1216 self._new_mappers = False 

1217 

1218 with mapperlib._CONFIGURE_MUTEX: 

1219 mapperlib._mapper_registries[self] = True 

1220 

1221 def update_type_annotation_map( 

1222 self, 

1223 type_annotation_map: _TypeAnnotationMapType, 

1224 ) -> None: 

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

1226 values.""" 

1227 

1228 self.type_annotation_map.update( 

1229 { 

1230 de_optionalize_union_types(typ): sqltype 

1231 for typ, sqltype in type_annotation_map.items() 

1232 } 

1233 ) 

1234 

1235 def _resolve_type( 

1236 self, python_type: _MatchedOnType, _do_fallbacks: bool = True 

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

1238 python_type_type: Type[Any] 

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

1240 

1241 if is_generic(python_type): 

1242 if is_literal(python_type): 

1243 python_type_type = python_type # type: ignore[assignment] 

1244 

1245 search = ( 

1246 (python_type, python_type_type), 

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

1248 ) 

1249 else: 

1250 python_type_type = python_type.__origin__ 

1251 search = ((python_type, python_type_type),) 

1252 elif isinstance(python_type, type): 

1253 python_type_type = python_type 

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

1255 else: 

1256 python_type_type = python_type # type: ignore[assignment] 

1257 search = ((python_type, python_type_type),) 

1258 

1259 for pt, flattened in search: 

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

1261 sql_type = self.type_annotation_map.get(pt) 

1262 if sql_type is None: 

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

1264 

1265 if sql_type is not None: 

1266 sql_type_inst = sqltypes.to_instance(sql_type) 

1267 

1268 # ... this additional step will reject most 

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

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

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

1272 # type_annotation_map to be useful 

1273 resolved_sql_type = sql_type_inst._resolve_for_python_type( 

1274 python_type_type, 

1275 pt, 

1276 flattened, 

1277 ) 

1278 if resolved_sql_type is not None: 

1279 return resolved_sql_type 

1280 

1281 # 2.0 fallbacks 

1282 if _do_fallbacks: 

1283 python_type_to_check: Any = None 

1284 kind = None 

1285 if is_pep695(python_type): 

1286 # NOTE: assume there aren't type alias types of new types. 

1287 python_type_to_check = python_type 

1288 while is_pep695(python_type_to_check): 

1289 python_type_to_check = python_type_to_check.__value__ 

1290 python_type_to_check = de_optionalize_union_types( 

1291 python_type_to_check 

1292 ) 

1293 kind = "TypeAliasType" 

1294 if is_newtype(python_type): 

1295 python_type_to_check = flatten_newtype(python_type) 

1296 kind = "NewType" 

1297 

1298 if python_type_to_check is not None: 

1299 res_after_fallback = self._resolve_type( 

1300 python_type_to_check, False 

1301 ) 

1302 if res_after_fallback is not None: 

1303 assert kind is not None 

1304 warn_deprecated( 

1305 f"Matching the provided {kind} '{python_type}' on " 

1306 "its resolved value without matching it in the " 

1307 "type_annotation_map is deprecated; add this type to " 

1308 "the type_annotation_map to allow it to match " 

1309 "explicitly.", 

1310 "2.0", 

1311 ) 

1312 return res_after_fallback 

1313 

1314 return None 

1315 

1316 @property 

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

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

1319 

1320 return frozenset(manager.mapper for manager in self._managers).union( 

1321 self._non_primary_mappers 

1322 ) 

1323 

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

1325 if registry is self: 

1326 return 

1327 registry._dependents.add(self) 

1328 self._dependencies.add(registry) 

1329 

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

1331 mapper._ready_for_configure = True 

1332 if self._new_mappers: 

1333 return 

1334 

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

1336 reg._new_mappers = True 

1337 

1338 @classmethod 

1339 def _recurse_with_dependents( 

1340 cls, registries: Set[RegistryType] 

1341 ) -> Iterator[RegistryType]: 

1342 todo = registries 

1343 done = set() 

1344 while todo: 

1345 reg = todo.pop() 

1346 done.add(reg) 

1347 

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

1349 # them before 

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

1351 yield reg 

1352 

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

1354 # after 

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

1356 

1357 @classmethod 

1358 def _recurse_with_dependencies( 

1359 cls, registries: Set[RegistryType] 

1360 ) -> Iterator[RegistryType]: 

1361 todo = registries 

1362 done = set() 

1363 while todo: 

1364 reg = todo.pop() 

1365 done.add(reg) 

1366 

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

1368 # them before 

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

1370 

1371 yield reg 

1372 

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

1374 # them before 

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

1376 

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

1378 return itertools.chain( 

1379 ( 

1380 manager.mapper 

1381 for manager in list(self._managers) 

1382 if manager.is_mapped 

1383 and not manager.mapper.configured 

1384 and manager.mapper._ready_for_configure 

1385 ), 

1386 ( 

1387 npm 

1388 for npm in list(self._non_primary_mappers) 

1389 if not npm.configured and npm._ready_for_configure 

1390 ), 

1391 ) 

1392 

1393 def _add_non_primary_mapper(self, np_mapper: Mapper[Any]) -> None: 

1394 self._non_primary_mappers[np_mapper] = True 

1395 

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

1397 clsregistry.remove_class(cls.__name__, cls, self._class_registry) 

1398 

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

1400 self._managers[manager] = True 

1401 if manager.is_mapped: 

1402 raise exc.ArgumentError( 

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

1404 % manager.class_ 

1405 ) 

1406 assert manager.registry is None 

1407 manager.registry = self 

1408 

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

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

1411 :class:`_orm.registry`. 

1412 

1413 The configure step is used to reconcile and initialize the 

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

1415 to invoke configuration events such as the 

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

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

1418 extensions or user-defined extension hooks. 

1419 

1420 If one or more mappers in this registry contain 

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

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

1423 registries. In order to configure those dependent registries 

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

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

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

1427 allow an application to programmatically invoke configuration of 

1428 registries while controlling whether or not the process implicitly 

1429 reaches other registries. 

1430 

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

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

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

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

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

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

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

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

1439 

1440 .. seealso:: 

1441 

1442 :func:`_orm.configure_mappers` 

1443 

1444 

1445 .. versionadded:: 1.4.0b2 

1446 

1447 """ 

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

1449 

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

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

1452 

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

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

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

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

1457 

1458 If this registry contains mappers that are dependencies of other 

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

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

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

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

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

1464 were not already disposed. 

1465 

1466 .. versionadded:: 1.4.0b2 

1467 

1468 .. seealso:: 

1469 

1470 :func:`_orm.clear_mappers` 

1471 

1472 """ 

1473 

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

1475 

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

1477 if "mapper" in manager.__dict__: 

1478 mapper = manager.mapper 

1479 

1480 mapper._set_dispose_flags() 

1481 

1482 class_ = manager.class_ 

1483 self._dispose_cls(class_) 

1484 instrumentation._instrumentation_factory.unregister(class_) 

1485 

1486 def generate_base( 

1487 self, 

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

1489 cls: Type[Any] = object, 

1490 name: str = "Base", 

1491 metaclass: Type[Any] = DeclarativeMeta, 

1492 ) -> Any: 

1493 """Generate a declarative base class. 

1494 

1495 Classes that inherit from the returned class object will be 

1496 automatically mapped using declarative mapping. 

1497 

1498 E.g.:: 

1499 

1500 from sqlalchemy.orm import registry 

1501 

1502 mapper_registry = registry() 

1503 

1504 Base = mapper_registry.generate_base() 

1505 

1506 

1507 class MyClass(Base): 

1508 __tablename__ = "my_table" 

1509 id = Column(Integer, primary_key=True) 

1510 

1511 The above dynamically generated class is equivalent to the 

1512 non-dynamic example below:: 

1513 

1514 from sqlalchemy.orm import registry 

1515 from sqlalchemy.orm.decl_api import DeclarativeMeta 

1516 

1517 mapper_registry = registry() 

1518 

1519 

1520 class Base(metaclass=DeclarativeMeta): 

1521 __abstract__ = True 

1522 registry = mapper_registry 

1523 metadata = mapper_registry.metadata 

1524 

1525 __init__ = mapper_registry.constructor 

1526 

1527 .. versionchanged:: 2.0 Note that the 

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

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

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

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

1532 tools. 

1533 

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

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

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

1537 

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

1539 examples. 

1540 

1541 :param mapper: 

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

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

1544 

1545 :param cls: 

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

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

1548 

1549 :param name: 

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

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

1552 tracebacks and debugging. 

1553 

1554 :param metaclass: 

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

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

1557 declarative base class. 

1558 

1559 .. seealso:: 

1560 

1561 :ref:`orm_declarative_mapping` 

1562 

1563 :func:`_orm.declarative_base` 

1564 

1565 """ 

1566 metadata = self.metadata 

1567 

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

1569 

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

1571 if isinstance(cls, type): 

1572 class_dict["__doc__"] = cls.__doc__ 

1573 

1574 if self.constructor is not None: 

1575 class_dict["__init__"] = self.constructor 

1576 

1577 class_dict["__abstract__"] = True 

1578 if mapper: 

1579 class_dict["__mapper_cls__"] = mapper 

1580 

1581 if hasattr(cls, "__class_getitem__"): 

1582 

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

1584 # allow generic classes in py3.9+ 

1585 return cls 

1586 

1587 class_dict["__class_getitem__"] = __class_getitem__ 

1588 

1589 return metaclass(name, bases, class_dict) 

1590 

1591 @compat_typing.dataclass_transform( 

1592 field_specifiers=( 

1593 MappedColumn, 

1594 RelationshipProperty, 

1595 Composite, 

1596 Synonym, 

1597 mapped_column, 

1598 relationship, 

1599 composite, 

1600 synonym, 

1601 deferred, 

1602 ), 

1603 ) 

1604 @overload 

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

1606 

1607 @overload 

1608 def mapped_as_dataclass( 

1609 self, 

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

1611 *, 

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

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

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

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

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

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

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

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

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

1621 

1622 def mapped_as_dataclass( 

1623 self, 

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

1625 *, 

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

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

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

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

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

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

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

1633 dataclass_callable: Union[ 

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

1635 ] = _NoArg.NO_ARG, 

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

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

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

1639 Python dataclass. 

1640 

1641 .. seealso:: 

1642 

1643 :ref:`orm_declarative_native_dataclasses` - complete background 

1644 on SQLAlchemy native dataclass mapping 

1645 

1646 

1647 .. versionadded:: 2.0 

1648 

1649 

1650 """ 

1651 

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

1653 setattr( 

1654 cls, 

1655 "_sa_apply_dc_transforms", 

1656 { 

1657 "init": init, 

1658 "repr": repr, 

1659 "eq": eq, 

1660 "order": order, 

1661 "unsafe_hash": unsafe_hash, 

1662 "match_args": match_args, 

1663 "kw_only": kw_only, 

1664 "dataclass_callable": dataclass_callable, 

1665 }, 

1666 ) 

1667 _as_declarative(self, cls, cls.__dict__) 

1668 return cls 

1669 

1670 if __cls: 

1671 return decorate(__cls) 

1672 else: 

1673 return decorate 

1674 

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

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

1677 to a given class. 

1678 

1679 E.g.:: 

1680 

1681 from sqlalchemy.orm import registry 

1682 

1683 mapper_registry = registry() 

1684 

1685 

1686 @mapper_registry.mapped 

1687 class Foo: 

1688 __tablename__ = "some_table" 

1689 

1690 id = Column(Integer, primary_key=True) 

1691 name = Column(String) 

1692 

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

1694 details and examples. 

1695 

1696 :param cls: class to be mapped. 

1697 

1698 :return: the class that was passed. 

1699 

1700 .. seealso:: 

1701 

1702 :ref:`orm_declarative_mapping` 

1703 

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

1705 that will apply Declarative mapping to subclasses automatically 

1706 using a Python metaclass. 

1707 

1708 .. seealso:: 

1709 

1710 :meth:`_orm.registry.mapped_as_dataclass` 

1711 

1712 """ 

1713 _as_declarative(self, cls, cls.__dict__) 

1714 return cls 

1715 

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

1717 """ 

1718 Class decorator which will invoke 

1719 :meth:`_orm.registry.generate_base` 

1720 for a given base class. 

1721 

1722 E.g.:: 

1723 

1724 from sqlalchemy.orm import registry 

1725 

1726 mapper_registry = registry() 

1727 

1728 

1729 @mapper_registry.as_declarative_base() 

1730 class Base: 

1731 @declared_attr 

1732 def __tablename__(cls): 

1733 return cls.__name__.lower() 

1734 

1735 id = Column(Integer, primary_key=True) 

1736 

1737 

1738 class MyMappedClass(Base): ... 

1739 

1740 All keyword arguments passed to 

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

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

1743 

1744 """ 

1745 

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

1747 kw["cls"] = cls 

1748 kw["name"] = cls.__name__ 

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

1750 

1751 return decorate 

1752 

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

1754 """Map a class declaratively. 

1755 

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

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

1758 actual table object. 

1759 

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

1761 

1762 E.g.:: 

1763 

1764 from sqlalchemy.orm import registry 

1765 

1766 mapper_registry = registry() 

1767 

1768 

1769 class Foo: 

1770 __tablename__ = "some_table" 

1771 

1772 id = Column(Integer, primary_key=True) 

1773 name = Column(String) 

1774 

1775 

1776 mapper = mapper_registry.map_declaratively(Foo) 

1777 

1778 This function is more conveniently invoked indirectly via either the 

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

1780 declarative metaclass generated from 

1781 :meth:`_orm.registry.generate_base`. 

1782 

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

1784 details and examples. 

1785 

1786 :param cls: class to be mapped. 

1787 

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

1789 

1790 .. seealso:: 

1791 

1792 :ref:`orm_declarative_mapping` 

1793 

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

1795 to this function. 

1796 

1797 :meth:`_orm.registry.map_imperatively` 

1798 

1799 """ 

1800 _as_declarative(self, cls, cls.__dict__) 

1801 return cls.__mapper__ # type: ignore 

1802 

1803 def map_imperatively( 

1804 self, 

1805 class_: Type[_O], 

1806 local_table: Optional[FromClause] = None, 

1807 **kw: Any, 

1808 ) -> Mapper[_O]: 

1809 r"""Map a class imperatively. 

1810 

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

1812 information. Instead, all mapping constructs are passed as 

1813 arguments. 

1814 

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

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

1817 a particular registry. 

1818 

1819 E.g.:: 

1820 

1821 from sqlalchemy.orm import registry 

1822 

1823 mapper_registry = registry() 

1824 

1825 my_table = Table( 

1826 "my_table", 

1827 mapper_registry.metadata, 

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

1829 ) 

1830 

1831 

1832 class MyClass: 

1833 pass 

1834 

1835 

1836 mapper_registry.map_imperatively(MyClass, my_table) 

1837 

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

1839 and usage examples. 

1840 

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

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

1843 

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

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

1846 Corresponds to the 

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

1848 

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

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

1851 

1852 .. seealso:: 

1853 

1854 :ref:`orm_imperative_mapping` 

1855 

1856 :ref:`orm_declarative_mapping` 

1857 

1858 """ 

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

1860 

1861 

1862RegistryType = registry 

1863 

1864if not TYPE_CHECKING: 

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

1866 _RegistryType = registry # noqa 

1867 

1868 

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

1870 """ 

1871 Class decorator which will adapt a given class into a 

1872 :func:`_orm.declarative_base`. 

1873 

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

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

1876 and then invoking the decorator. 

1877 

1878 E.g.:: 

1879 

1880 from sqlalchemy.orm import as_declarative 

1881 

1882 

1883 @as_declarative() 

1884 class Base: 

1885 @declared_attr 

1886 def __tablename__(cls): 

1887 return cls.__name__.lower() 

1888 

1889 id = Column(Integer, primary_key=True) 

1890 

1891 

1892 class MyMappedClass(Base): ... 

1893 

1894 .. seealso:: 

1895 

1896 :meth:`_orm.registry.as_declarative_base` 

1897 

1898 """ 

1899 metadata, class_registry = ( 

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

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

1902 ) 

1903 

1904 return registry( 

1905 metadata=metadata, class_registry=class_registry 

1906 ).as_declarative_base(**kw) 

1907 

1908 

1909@inspection._inspects( 

1910 DeclarativeMeta, DeclarativeBase, DeclarativeAttributeIntercept 

1911) 

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

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

1914 if mp is None: 

1915 if _DeferredMapperConfig.has_cls(cls): 

1916 _DeferredMapperConfig.raise_unmapped_for_cls(cls) 

1917 return mp