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 .. legacy:: This api is considered legacy and will be deprecated in the next 

516 SQLAlchemy version. 

517 

518 .. seealso:: 

519 

520 :ref:`orm_mixins_toplevel` 

521 

522 :ref:`mypy_declarative_mixins` - in the 

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

524 

525 """ # noqa: E501 

526 

527 return cls 

528 

529 

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

531 if "metadata" in cls.__dict__: 

532 metadata = cls.__dict__["metadata"] 

533 else: 

534 metadata = None 

535 

536 if "type_annotation_map" in cls.__dict__: 

537 type_annotation_map = cls.__dict__["type_annotation_map"] 

538 else: 

539 type_annotation_map = None 

540 

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

542 if reg is not None: 

543 if not isinstance(reg, registry): 

544 raise exc.InvalidRequestError( 

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

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

547 ) 

548 elif type_annotation_map is not None: 

549 raise exc.InvalidRequestError( 

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

551 "type_annotation_map entry. Per-base type_annotation_maps " 

552 "are not supported. Please apply the type_annotation_map " 

553 "to this registry directly." 

554 ) 

555 

556 else: 

557 reg = registry( 

558 metadata=metadata, type_annotation_map=type_annotation_map 

559 ) 

560 cls.registry = reg 

561 

562 cls._sa_registry = reg 

563 

564 if "metadata" not in cls.__dict__: 

565 cls.metadata = cls.registry.metadata 

566 

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

568 cls.__init__ = cls.registry.constructor 

569 

570 

571class MappedAsDataclass(metaclass=DCTransformDeclarative): 

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

573 a dataclass. 

574 

575 .. seealso:: 

576 

577 :ref:`orm_declarative_native_dataclasses` - complete background 

578 on SQLAlchemy native dataclass mapping 

579 

580 .. versionadded:: 2.0 

581 

582 """ 

583 

584 def __init_subclass__( 

585 cls, 

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

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

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

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

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

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

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

593 dataclass_callable: Union[ 

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

595 ] = _NoArg.NO_ARG, 

596 **kw: Any, 

597 ) -> None: 

598 apply_dc_transforms: _DataclassArguments = { 

599 "init": init, 

600 "repr": repr, 

601 "eq": eq, 

602 "order": order, 

603 "unsafe_hash": unsafe_hash, 

604 "match_args": match_args, 

605 "kw_only": kw_only, 

606 "dataclass_callable": dataclass_callable, 

607 } 

608 

609 current_transforms: _DataclassArguments 

610 

611 if hasattr(cls, "_sa_apply_dc_transforms"): 

612 current = cls._sa_apply_dc_transforms 

613 

614 _ClassScanMapperConfig._assert_dc_arguments(current) 

615 

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

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

618 for k, v in apply_dc_transforms.items() 

619 } 

620 else: 

621 cls._sa_apply_dc_transforms = current_transforms = ( 

622 apply_dc_transforms 

623 ) 

624 

625 super().__init_subclass__(**kw) 

626 

627 if not _is_mapped_class(cls): 

628 new_anno = ( 

629 _ClassScanMapperConfig._update_annotations_for_non_mapped_class 

630 )(cls) 

631 _ClassScanMapperConfig._apply_dataclasses_to_any_class( 

632 current_transforms, cls, new_anno 

633 ) 

634 

635 

636class DeclarativeBase( 

637 # Inspectable is used only by the mypy plugin 

638 inspection.Inspectable[InstanceState[Any]], 

639 metaclass=DeclarativeAttributeIntercept, 

640): 

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

642 

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

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

645 

646 

647 from sqlalchemy.orm import DeclarativeBase 

648 

649 

650 class Base(DeclarativeBase): 

651 pass 

652 

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

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

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

656 

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

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

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

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

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

662 collection as well as a specific value for 

663 :paramref:`_orm.registry.type_annotation_map`:: 

664 

665 from typing_extensions import Annotated 

666 

667 from sqlalchemy import BigInteger 

668 from sqlalchemy import MetaData 

669 from sqlalchemy import String 

670 from sqlalchemy.orm import DeclarativeBase 

671 

672 bigint = Annotated[int, "bigint"] 

673 my_metadata = MetaData() 

674 

675 

676 class Base(DeclarativeBase): 

677 metadata = my_metadata 

678 type_annotation_map = { 

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

680 bigint: BigInteger(), 

681 } 

682 

683 Class-level attributes which may be specified include: 

684 

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

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

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

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

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

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

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

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

693 :paramref:`_orm.registry.type_annotation_map`. 

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

695 

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

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

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

699 and other subclassing-oriented APIs should be seen as 

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

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

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

703 without using plugins. 

704 

705 **__init__ behavior** 

706 

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

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

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

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

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

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

713 constructor that will assign keyword arguments as attributes on the 

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

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

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

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

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

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

720 method does. 

721 

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

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

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

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

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

727 ``object.__init__()``. 

728 

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

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

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

732 

733 class Base(DeclarativeBase): 

734 def __init__(self, id=None): 

735 self.id = id 

736 

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

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

739 

740 class MyClass(Base): 

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

742 self.name = name 

743 super().__init__(id=id) 

744 

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

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

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

748 ``__init__()``. 

749 

750 

751 """ 

752 

753 if typing.TYPE_CHECKING: 

754 

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

756 

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

758 

759 _sa_registry: ClassVar[_RegistryType] 

760 

761 registry: ClassVar[_RegistryType] 

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

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

764 

765 metadata: ClassVar[MetaData] 

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

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

768 

769 .. seealso:: 

770 

771 :ref:`orm_declarative_metadata` 

772 

773 """ 

774 

775 __name__: ClassVar[str] 

776 

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

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

779 # ok with it. 

780 __mapper__: ClassVar[Mapper[Any]] 

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

782 mapped. 

783 

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

785 ``inspect(klass)``. 

786 

787 """ 

788 

789 __table__: ClassVar[FromClause] 

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

791 mapped. 

792 

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

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

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

796 

797 .. seealso:: 

798 

799 :ref:`orm_declarative_metadata` 

800 

801 """ 

802 

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

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

805 __tablename__: Any 

806 """String name to assign to the generated 

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

808 :attr:`_orm.DeclarativeBase.__table__`. 

809 

810 .. seealso:: 

811 

812 :ref:`orm_declarative_table` 

813 

814 """ 

815 

816 __mapper_args__: Any 

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

818 :class:`_orm.Mapper` constructor. 

819 

820 .. seealso:: 

821 

822 :ref:`orm_declarative_mapper_options` 

823 

824 """ 

825 

826 __table_args__: Any 

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

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

829 :ref:`orm_declarative_table_configuration` 

830 for background on the specific structure of this collection. 

831 

832 .. seealso:: 

833 

834 :ref:`orm_declarative_table_configuration` 

835 

836 """ 

837 

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

839 

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

841 if DeclarativeBase in cls.__bases__: 

842 _check_not_declarative(cls, DeclarativeBase) 

843 _setup_declarative_base(cls) 

844 else: 

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

846 super().__init_subclass__(**kw) 

847 

848 

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

850 cls_dict = cls.__dict__ 

851 if ( 

852 "__table__" in cls_dict 

853 and not ( 

854 callable(cls_dict["__table__"]) 

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

856 ) 

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

858 raise exc.InvalidRequestError( 

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

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

861 ) 

862 

863 

864class DeclarativeBaseNoMeta( 

865 # Inspectable is used only by the mypy plugin 

866 inspection.Inspectable[InstanceState[Any]] 

867): 

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

869 to intercept new attributes. 

870 

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

872 custom metaclasses is desirable. 

873 

874 .. versionadded:: 2.0 

875 

876 

877 """ 

878 

879 _sa_registry: ClassVar[_RegistryType] 

880 

881 registry: ClassVar[_RegistryType] 

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

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

884 

885 metadata: ClassVar[MetaData] 

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

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

888 

889 .. seealso:: 

890 

891 :ref:`orm_declarative_metadata` 

892 

893 """ 

894 

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

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

897 # ok with it. 

898 __mapper__: ClassVar[Mapper[Any]] 

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

900 mapped. 

901 

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

903 ``inspect(klass)``. 

904 

905 """ 

906 

907 __table__: Optional[FromClause] 

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

909 mapped. 

910 

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

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

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

914 

915 .. seealso:: 

916 

917 :ref:`orm_declarative_metadata` 

918 

919 """ 

920 

921 if typing.TYPE_CHECKING: 

922 

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

924 

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

926 

927 __tablename__: Any 

928 """String name to assign to the generated 

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

930 :attr:`_orm.DeclarativeBase.__table__`. 

931 

932 .. seealso:: 

933 

934 :ref:`orm_declarative_table` 

935 

936 """ 

937 

938 __mapper_args__: Any 

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

940 :class:`_orm.Mapper` constructor. 

941 

942 .. seealso:: 

943 

944 :ref:`orm_declarative_mapper_options` 

945 

946 """ 

947 

948 __table_args__: Any 

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

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

951 :ref:`orm_declarative_table_configuration` 

952 for background on the specific structure of this collection. 

953 

954 .. seealso:: 

955 

956 :ref:`orm_declarative_table_configuration` 

957 

958 """ 

959 

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

961 

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

963 if DeclarativeBaseNoMeta in cls.__bases__: 

964 _check_not_declarative(cls, DeclarativeBaseNoMeta) 

965 _setup_declarative_base(cls) 

966 else: 

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

968 super().__init_subclass__(**kw) 

969 

970 

971def add_mapped_attribute( 

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

973) -> None: 

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

975 

976 E.g.:: 

977 

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

979 

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

981 metaclass that intercepts attribute set operations. 

982 

983 .. versionadded:: 2.0 

984 

985 

986 """ 

987 _add_attribute(target, key, attr) 

988 

989 

990def declarative_base( 

991 *, 

992 metadata: Optional[MetaData] = None, 

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

994 cls: Type[Any] = object, 

995 name: str = "Base", 

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

997 type_annotation_map: Optional[_TypeAnnotationMapType] = None, 

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

999 metaclass: Type[Any] = DeclarativeMeta, 

1000) -> Any: 

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

1002 

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

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

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

1006 information provided declaratively in the class and any subclasses 

1007 of the class. 

1008 

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

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

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

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

1013 with :pep:`484` typing tools. 

1014 

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

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

1017 method. That is, the following:: 

1018 

1019 from sqlalchemy.orm import declarative_base 

1020 

1021 Base = declarative_base() 

1022 

1023 Is equivalent to:: 

1024 

1025 from sqlalchemy.orm import registry 

1026 

1027 mapper_registry = registry() 

1028 Base = mapper_registry.generate_base() 

1029 

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

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

1032 for more details. 

1033 

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

1035 function is now a specialization of the more generic 

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

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

1038 

1039 

1040 :param metadata: 

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

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

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

1044 will be created if none is provided. The 

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

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

1047 

1048 :param mapper: 

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

1050 be used to map subclasses to their Tables. 

1051 

1052 :param cls: 

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

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

1055 

1056 :param name: 

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

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

1059 tracebacks and debugging. 

1060 

1061 :param constructor: 

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

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

1064 implementation that assigns \**kwargs for declared 

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

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

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

1068 

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

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

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

1072 and others. Allows two or more declarative base classes 

1073 to share the same registry of class names for simplified 

1074 inter-base relationships. 

1075 

1076 :param type_annotation_map: optional dictionary of Python types to 

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

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

1079 to produce column types based on annotations within the 

1080 :class:`_orm.Mapped` type. 

1081 

1082 

1083 .. versionadded:: 2.0 

1084 

1085 .. seealso:: 

1086 

1087 :ref:`orm_declarative_mapped_column_type_map` 

1088 

1089 :param metaclass: 

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

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

1092 declarative base class. 

1093 

1094 .. seealso:: 

1095 

1096 :class:`_orm.registry` 

1097 

1098 """ 

1099 

1100 return registry( 

1101 metadata=metadata, 

1102 class_registry=class_registry, 

1103 constructor=constructor, 

1104 type_annotation_map=type_annotation_map, 

1105 ).generate_base( 

1106 mapper=mapper, 

1107 cls=cls, 

1108 name=name, 

1109 metaclass=metaclass, 

1110 ) 

1111 

1112 

1113class registry: 

1114 """Generalized registry for mapping classes. 

1115 

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

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

1118 

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

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

1121 styles may be used interchangeably: 

1122 

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

1124 class, and is the underlying implementation of the 

1125 :func:`_orm.declarative_base` function. 

1126 

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

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

1129 base class. 

1130 

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

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

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

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

1135 which is removed as of SQLAlchemy 2.0. 

1136 

1137 .. versionadded:: 1.4 

1138 

1139 .. seealso:: 

1140 

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

1142 styles. 

1143 

1144 """ 

1145 

1146 _class_registry: clsregistry._ClsRegistryType 

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

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

1149 metadata: MetaData 

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

1151 type_annotation_map: _MutableTypeAnnotationMapType 

1152 _dependents: Set[_RegistryType] 

1153 _dependencies: Set[_RegistryType] 

1154 _new_mappers: bool 

1155 

1156 def __init__( 

1157 self, 

1158 *, 

1159 metadata: Optional[MetaData] = None, 

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

1161 type_annotation_map: Optional[_TypeAnnotationMapType] = None, 

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

1163 ): 

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

1165 

1166 :param metadata: 

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

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

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

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

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

1172 

1173 :param constructor: 

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

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

1176 implementation that assigns \**kwargs for declared 

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

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

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

1180 

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

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

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

1184 and others. Allows two or more declarative base classes 

1185 to share the same registry of class names for simplified 

1186 inter-base relationships. 

1187 

1188 :param type_annotation_map: optional dictionary of Python types to 

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

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

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

1192 to produce column types based on annotations within the 

1193 :class:`_orm.Mapped` type. 

1194 

1195 .. versionadded:: 2.0 

1196 

1197 .. seealso:: 

1198 

1199 :ref:`orm_declarative_mapped_column_type_map` 

1200 

1201 

1202 """ 

1203 lcl_metadata = metadata or MetaData() 

1204 

1205 if class_registry is None: 

1206 class_registry = weakref.WeakValueDictionary() 

1207 

1208 self._class_registry = class_registry 

1209 self._managers = weakref.WeakKeyDictionary() 

1210 self._non_primary_mappers = weakref.WeakKeyDictionary() 

1211 self.metadata = lcl_metadata 

1212 self.constructor = constructor 

1213 self.type_annotation_map = {} 

1214 if type_annotation_map is not None: 

1215 self.update_type_annotation_map(type_annotation_map) 

1216 self._dependents = set() 

1217 self._dependencies = set() 

1218 

1219 self._new_mappers = False 

1220 

1221 with mapperlib._CONFIGURE_MUTEX: 

1222 mapperlib._mapper_registries[self] = True 

1223 

1224 def update_type_annotation_map( 

1225 self, 

1226 type_annotation_map: _TypeAnnotationMapType, 

1227 ) -> None: 

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

1229 values.""" 

1230 

1231 self.type_annotation_map.update( 

1232 { 

1233 de_optionalize_union_types(typ): sqltype 

1234 for typ, sqltype in type_annotation_map.items() 

1235 } 

1236 ) 

1237 

1238 def _resolve_type( 

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

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

1241 python_type_type: Type[Any] 

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

1243 

1244 if is_generic(python_type): 

1245 if is_literal(python_type): 

1246 python_type_type = python_type # type: ignore[assignment] 

1247 

1248 search = ( 

1249 (python_type, python_type_type), 

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

1251 ) 

1252 else: 

1253 python_type_type = python_type.__origin__ 

1254 search = ((python_type, python_type_type),) 

1255 elif isinstance(python_type, type): 

1256 python_type_type = python_type 

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

1258 else: 

1259 python_type_type = python_type # type: ignore[assignment] 

1260 search = ((python_type, python_type_type),) 

1261 

1262 for pt, flattened in search: 

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

1264 sql_type = self.type_annotation_map.get(pt) 

1265 if sql_type is None: 

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

1267 

1268 if sql_type is not None: 

1269 sql_type_inst = sqltypes.to_instance(sql_type) 

1270 

1271 # ... this additional step will reject most 

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

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

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

1275 # type_annotation_map to be useful 

1276 resolved_sql_type = sql_type_inst._resolve_for_python_type( 

1277 python_type_type, 

1278 pt, 

1279 flattened, 

1280 ) 

1281 if resolved_sql_type is not None: 

1282 return resolved_sql_type 

1283 

1284 # 2.0 fallbacks 

1285 if _do_fallbacks: 

1286 python_type_to_check: Any = None 

1287 kind = None 

1288 if is_pep695(python_type): 

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

1290 python_type_to_check = python_type 

1291 while is_pep695(python_type_to_check): 

1292 python_type_to_check = python_type_to_check.__value__ 

1293 python_type_to_check = de_optionalize_union_types( 

1294 python_type_to_check 

1295 ) 

1296 kind = "TypeAliasType" 

1297 if is_newtype(python_type): 

1298 python_type_to_check = flatten_newtype(python_type) 

1299 kind = "NewType" 

1300 

1301 if python_type_to_check is not None: 

1302 res_after_fallback = self._resolve_type( 

1303 python_type_to_check, False 

1304 ) 

1305 if res_after_fallback is not None: 

1306 assert kind is not None 

1307 warn_deprecated( 

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

1309 "its resolved value without matching it in the " 

1310 "type_annotation_map is deprecated; add this type to " 

1311 "the type_annotation_map to allow it to match " 

1312 "explicitly.", 

1313 "2.0", 

1314 ) 

1315 return res_after_fallback 

1316 

1317 return None 

1318 

1319 @property 

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

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

1322 

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

1324 self._non_primary_mappers 

1325 ) 

1326 

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

1328 if registry is self: 

1329 return 

1330 registry._dependents.add(self) 

1331 self._dependencies.add(registry) 

1332 

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

1334 mapper._ready_for_configure = True 

1335 if self._new_mappers: 

1336 return 

1337 

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

1339 reg._new_mappers = True 

1340 

1341 @classmethod 

1342 def _recurse_with_dependents( 

1343 cls, registries: Set[RegistryType] 

1344 ) -> Iterator[RegistryType]: 

1345 todo = registries 

1346 done = set() 

1347 while todo: 

1348 reg = todo.pop() 

1349 done.add(reg) 

1350 

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

1352 # them before 

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

1354 yield reg 

1355 

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

1357 # after 

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

1359 

1360 @classmethod 

1361 def _recurse_with_dependencies( 

1362 cls, registries: Set[RegistryType] 

1363 ) -> Iterator[RegistryType]: 

1364 todo = registries 

1365 done = set() 

1366 while todo: 

1367 reg = todo.pop() 

1368 done.add(reg) 

1369 

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

1371 # them before 

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

1373 

1374 yield reg 

1375 

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

1377 # them before 

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

1379 

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

1381 return itertools.chain( 

1382 ( 

1383 manager.mapper 

1384 for manager in list(self._managers) 

1385 if manager.is_mapped 

1386 and not manager.mapper.configured 

1387 and manager.mapper._ready_for_configure 

1388 ), 

1389 ( 

1390 npm 

1391 for npm in list(self._non_primary_mappers) 

1392 if not npm.configured and npm._ready_for_configure 

1393 ), 

1394 ) 

1395 

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

1397 self._non_primary_mappers[np_mapper] = True 

1398 

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

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

1401 

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

1403 self._managers[manager] = True 

1404 if manager.is_mapped: 

1405 raise exc.ArgumentError( 

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

1407 % manager.class_ 

1408 ) 

1409 assert manager.registry is None 

1410 manager.registry = self 

1411 

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

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

1414 :class:`_orm.registry`. 

1415 

1416 The configure step is used to reconcile and initialize the 

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

1418 to invoke configuration events such as the 

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

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

1421 extensions or user-defined extension hooks. 

1422 

1423 If one or more mappers in this registry contain 

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

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

1426 registries. In order to configure those dependent registries 

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

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

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

1430 allow an application to programmatically invoke configuration of 

1431 registries while controlling whether or not the process implicitly 

1432 reaches other registries. 

1433 

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

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

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

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

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

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

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

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

1442 

1443 .. seealso:: 

1444 

1445 :func:`_orm.configure_mappers` 

1446 

1447 

1448 .. versionadded:: 1.4.0b2 

1449 

1450 """ 

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

1452 

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

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

1455 

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

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

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

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

1460 

1461 If this registry contains mappers that are dependencies of other 

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

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

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

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

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

1467 were not already disposed. 

1468 

1469 .. versionadded:: 1.4.0b2 

1470 

1471 .. seealso:: 

1472 

1473 :func:`_orm.clear_mappers` 

1474 

1475 """ 

1476 

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

1478 

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

1480 if "mapper" in manager.__dict__: 

1481 mapper = manager.mapper 

1482 

1483 mapper._set_dispose_flags() 

1484 

1485 class_ = manager.class_ 

1486 self._dispose_cls(class_) 

1487 instrumentation._instrumentation_factory.unregister(class_) 

1488 

1489 def generate_base( 

1490 self, 

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

1492 cls: Type[Any] = object, 

1493 name: str = "Base", 

1494 metaclass: Type[Any] = DeclarativeMeta, 

1495 ) -> Any: 

1496 """Generate a declarative base class. 

1497 

1498 Classes that inherit from the returned class object will be 

1499 automatically mapped using declarative mapping. 

1500 

1501 E.g.:: 

1502 

1503 from sqlalchemy.orm import registry 

1504 

1505 mapper_registry = registry() 

1506 

1507 Base = mapper_registry.generate_base() 

1508 

1509 

1510 class MyClass(Base): 

1511 __tablename__ = "my_table" 

1512 id = Column(Integer, primary_key=True) 

1513 

1514 The above dynamically generated class is equivalent to the 

1515 non-dynamic example below:: 

1516 

1517 from sqlalchemy.orm import registry 

1518 from sqlalchemy.orm.decl_api import DeclarativeMeta 

1519 

1520 mapper_registry = registry() 

1521 

1522 

1523 class Base(metaclass=DeclarativeMeta): 

1524 __abstract__ = True 

1525 registry = mapper_registry 

1526 metadata = mapper_registry.metadata 

1527 

1528 __init__ = mapper_registry.constructor 

1529 

1530 .. versionchanged:: 2.0 Note that the 

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

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

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

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

1535 tools. 

1536 

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

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

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

1540 

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

1542 examples. 

1543 

1544 :param mapper: 

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

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

1547 

1548 :param cls: 

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

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

1551 

1552 :param name: 

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

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

1555 tracebacks and debugging. 

1556 

1557 :param metaclass: 

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

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

1560 declarative base class. 

1561 

1562 .. seealso:: 

1563 

1564 :ref:`orm_declarative_mapping` 

1565 

1566 :func:`_orm.declarative_base` 

1567 

1568 """ 

1569 metadata = self.metadata 

1570 

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

1572 

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

1574 if isinstance(cls, type): 

1575 class_dict["__doc__"] = cls.__doc__ 

1576 

1577 if self.constructor is not None: 

1578 class_dict["__init__"] = self.constructor 

1579 

1580 class_dict["__abstract__"] = True 

1581 if mapper: 

1582 class_dict["__mapper_cls__"] = mapper 

1583 

1584 if hasattr(cls, "__class_getitem__"): 

1585 

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

1587 # allow generic classes in py3.9+ 

1588 return cls 

1589 

1590 class_dict["__class_getitem__"] = __class_getitem__ 

1591 

1592 return metaclass(name, bases, class_dict) 

1593 

1594 @compat_typing.dataclass_transform( 

1595 field_specifiers=( 

1596 MappedColumn, 

1597 RelationshipProperty, 

1598 Composite, 

1599 Synonym, 

1600 mapped_column, 

1601 relationship, 

1602 composite, 

1603 synonym, 

1604 deferred, 

1605 ), 

1606 ) 

1607 @overload 

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

1609 

1610 @overload 

1611 def mapped_as_dataclass( 

1612 self, 

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

1614 *, 

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

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

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

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

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

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

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

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

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

1624 

1625 def mapped_as_dataclass( 

1626 self, 

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

1628 *, 

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

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

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

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

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

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

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

1636 dataclass_callable: Union[ 

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

1638 ] = _NoArg.NO_ARG, 

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

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

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

1642 Python dataclass. 

1643 

1644 .. seealso:: 

1645 

1646 :ref:`orm_declarative_native_dataclasses` - complete background 

1647 on SQLAlchemy native dataclass mapping 

1648 

1649 

1650 .. versionadded:: 2.0 

1651 

1652 

1653 """ 

1654 

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

1656 setattr( 

1657 cls, 

1658 "_sa_apply_dc_transforms", 

1659 { 

1660 "init": init, 

1661 "repr": repr, 

1662 "eq": eq, 

1663 "order": order, 

1664 "unsafe_hash": unsafe_hash, 

1665 "match_args": match_args, 

1666 "kw_only": kw_only, 

1667 "dataclass_callable": dataclass_callable, 

1668 }, 

1669 ) 

1670 _as_declarative(self, cls, cls.__dict__) 

1671 return cls 

1672 

1673 if __cls: 

1674 return decorate(__cls) 

1675 else: 

1676 return decorate 

1677 

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

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

1680 to a given class. 

1681 

1682 E.g.:: 

1683 

1684 from sqlalchemy.orm import registry 

1685 

1686 mapper_registry = registry() 

1687 

1688 

1689 @mapper_registry.mapped 

1690 class Foo: 

1691 __tablename__ = "some_table" 

1692 

1693 id = Column(Integer, primary_key=True) 

1694 name = Column(String) 

1695 

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

1697 details and examples. 

1698 

1699 :param cls: class to be mapped. 

1700 

1701 :return: the class that was passed. 

1702 

1703 .. seealso:: 

1704 

1705 :ref:`orm_declarative_mapping` 

1706 

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

1708 that will apply Declarative mapping to subclasses automatically 

1709 using a Python metaclass. 

1710 

1711 .. seealso:: 

1712 

1713 :meth:`_orm.registry.mapped_as_dataclass` 

1714 

1715 """ 

1716 _as_declarative(self, cls, cls.__dict__) 

1717 return cls 

1718 

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

1720 """ 

1721 Class decorator which will invoke 

1722 :meth:`_orm.registry.generate_base` 

1723 for a given base class. 

1724 

1725 E.g.:: 

1726 

1727 from sqlalchemy.orm import registry 

1728 

1729 mapper_registry = registry() 

1730 

1731 

1732 @mapper_registry.as_declarative_base() 

1733 class Base: 

1734 @declared_attr 

1735 def __tablename__(cls): 

1736 return cls.__name__.lower() 

1737 

1738 id = Column(Integer, primary_key=True) 

1739 

1740 

1741 class MyMappedClass(Base): ... 

1742 

1743 All keyword arguments passed to 

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

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

1746 

1747 """ 

1748 

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

1750 kw["cls"] = cls 

1751 kw["name"] = cls.__name__ 

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

1753 

1754 return decorate 

1755 

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

1757 """Map a class declaratively. 

1758 

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

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

1761 actual table object. 

1762 

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

1764 

1765 E.g.:: 

1766 

1767 from sqlalchemy.orm import registry 

1768 

1769 mapper_registry = registry() 

1770 

1771 

1772 class Foo: 

1773 __tablename__ = "some_table" 

1774 

1775 id = Column(Integer, primary_key=True) 

1776 name = Column(String) 

1777 

1778 

1779 mapper = mapper_registry.map_declaratively(Foo) 

1780 

1781 This function is more conveniently invoked indirectly via either the 

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

1783 declarative metaclass generated from 

1784 :meth:`_orm.registry.generate_base`. 

1785 

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

1787 details and examples. 

1788 

1789 :param cls: class to be mapped. 

1790 

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

1792 

1793 .. seealso:: 

1794 

1795 :ref:`orm_declarative_mapping` 

1796 

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

1798 to this function. 

1799 

1800 :meth:`_orm.registry.map_imperatively` 

1801 

1802 """ 

1803 _as_declarative(self, cls, cls.__dict__) 

1804 return cls.__mapper__ # type: ignore 

1805 

1806 def map_imperatively( 

1807 self, 

1808 class_: Type[_O], 

1809 local_table: Optional[FromClause] = None, 

1810 **kw: Any, 

1811 ) -> Mapper[_O]: 

1812 r"""Map a class imperatively. 

1813 

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

1815 information. Instead, all mapping constructs are passed as 

1816 arguments. 

1817 

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

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

1820 a particular registry. 

1821 

1822 E.g.:: 

1823 

1824 from sqlalchemy.orm import registry 

1825 

1826 mapper_registry = registry() 

1827 

1828 my_table = Table( 

1829 "my_table", 

1830 mapper_registry.metadata, 

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

1832 ) 

1833 

1834 

1835 class MyClass: 

1836 pass 

1837 

1838 

1839 mapper_registry.map_imperatively(MyClass, my_table) 

1840 

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

1842 and usage examples. 

1843 

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

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

1846 

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

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

1849 Corresponds to the 

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

1851 

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

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

1854 

1855 .. seealso:: 

1856 

1857 :ref:`orm_imperative_mapping` 

1858 

1859 :ref:`orm_declarative_mapping` 

1860 

1861 """ 

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

1863 

1864 

1865RegistryType = registry 

1866 

1867if not TYPE_CHECKING: 

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

1869 _RegistryType = registry # noqa 

1870 

1871 

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

1873 """ 

1874 Class decorator which will adapt a given class into a 

1875 :func:`_orm.declarative_base`. 

1876 

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

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

1879 and then invoking the decorator. 

1880 

1881 E.g.:: 

1882 

1883 from sqlalchemy.orm import as_declarative 

1884 

1885 

1886 @as_declarative() 

1887 class Base: 

1888 @declared_attr 

1889 def __tablename__(cls): 

1890 return cls.__name__.lower() 

1891 

1892 id = Column(Integer, primary_key=True) 

1893 

1894 

1895 class MyMappedClass(Base): ... 

1896 

1897 .. seealso:: 

1898 

1899 :meth:`_orm.registry.as_declarative_base` 

1900 

1901 """ 

1902 metadata, class_registry = ( 

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

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

1905 ) 

1906 

1907 return registry( 

1908 metadata=metadata, class_registry=class_registry 

1909 ).as_declarative_base(**kw) 

1910 

1911 

1912@inspection._inspects( 

1913 DeclarativeMeta, DeclarativeBase, DeclarativeAttributeIntercept 

1914) 

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

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

1917 if mp is None: 

1918 if _DeferredMapperConfig.has_cls(cls): 

1919 _DeferredMapperConfig.raise_unmapped_for_cls(cls) 

1920 return mp