Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/sqlalchemy/inspection.py: 69%

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

70 statements  

1# inspection.py 

2# Copyright (C) 2005-2026 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"""The inspection module provides the :func:`_sa.inspect` function, 

9which delivers runtime information about a wide variety 

10of SQLAlchemy objects, both within the Core as well as the 

11ORM. 

12 

13The :func:`_sa.inspect` function is the entry point to SQLAlchemy's 

14public API for viewing the configuration and construction 

15of in-memory objects. Depending on the type of object 

16passed to :func:`_sa.inspect`, the return value will either be 

17a related object which provides a known interface, or in many 

18cases it will return the object itself. 

19 

20The rationale for :func:`_sa.inspect` is twofold. One is that 

21it replaces the need to be aware of a large variety of "information 

22getting" functions in SQLAlchemy, such as 

23:meth:`_reflection.Inspector.from_engine` (deprecated in 1.4), 

24:func:`.orm.attributes.instance_state`, :func:`_orm.class_mapper`, 

25and others. The other is that the return value of :func:`_sa.inspect` 

26is guaranteed to obey a documented API, thus allowing third party 

27tools which build on top of SQLAlchemy configurations to be constructed 

28in a forwards-compatible way. 

29 

30""" 

31 

32from __future__ import annotations 

33 

34from typing import Any 

35from typing import Callable 

36from typing import Dict 

37from typing import Generic 

38from typing import Literal 

39from typing import Optional 

40from typing import overload 

41from typing import Protocol 

42from typing import Type 

43from typing import TypeVar 

44from typing import Union 

45 

46from . import exc 

47 

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

49_TCov = TypeVar("_TCov", bound=Any, covariant=True) 

50_F = TypeVar("_F", bound=Callable[..., Any]) 

51 

52_IN = TypeVar("_IN", bound=Any) 

53 

54_registrars: Dict[type, Union[Literal[True], Callable[[Any], Any]]] = {} 

55 

56 

57class Inspectable(Generic[_T]): 

58 """define a class as inspectable. 

59 

60 This allows typing to set up a linkage between an object that 

61 can be inspected and the type of inspection it returns. 

62 

63 Unfortunately we cannot at the moment get all classes that are 

64 returned by inspection to suit this interface as we get into 

65 MRO issues. 

66 

67 """ 

68 

69 __slots__ = () 

70 

71 

72class _InspectableTypeProtocol(Protocol[_TCov]): 

73 """a protocol defining a method that's used when a type (ie the class 

74 itself) is passed to inspect(). 

75 

76 """ 

77 

78 def _sa_inspect_type(self) -> _TCov: ... 

79 

80 

81class _InspectableProtocol(Protocol[_TCov]): 

82 """a protocol defining a method that's used when an instance is 

83 passed to inspect(). 

84 

85 """ 

86 

87 def _sa_inspect_instance(self) -> _TCov: ... 

88 

89 

90@overload 

91def inspect( 

92 subject: Type[_InspectableTypeProtocol[_IN]], raiseerr: bool = True 

93) -> _IN: ... 

94 

95 

96@overload 

97def inspect( 

98 subject: _InspectableProtocol[_IN], raiseerr: bool = True 

99) -> _IN: ... 

100 

101 

102@overload 

103def inspect(subject: Inspectable[_IN], raiseerr: bool = True) -> _IN: ... 

104 

105 

106@overload 

107def inspect(subject: Any, raiseerr: Literal[False] = ...) -> Optional[Any]: ... 

108 

109 

110@overload 

111def inspect(subject: Any, raiseerr: bool = True) -> Any: ... 

112 

113 

114def inspect(subject: Any, raiseerr: bool = True) -> Any: 

115 """Produce an inspection object for the given target. 

116 

117 The returned value in some cases may be the 

118 same object as the one given, such as if a 

119 :class:`_orm.Mapper` object is passed. In other 

120 cases, it will be an instance of the registered 

121 inspection type for the given object, such as 

122 if an :class:`_engine.Engine` is passed, an 

123 :class:`_reflection.Inspector` object is returned. 

124 

125 :param subject: the subject to be inspected. 

126 :param raiseerr: When ``True``, if the given subject 

127 does not 

128 correspond to a known SQLAlchemy inspected type, 

129 :class:`sqlalchemy.exc.NoInspectionAvailable` 

130 is raised. If ``False``, ``None`` is returned. 

131 

132 """ 

133 type_ = type(subject) 

134 for cls in type_.__mro__: 

135 if cls in _registrars: 

136 reg = _registrars.get(cls, None) 

137 if reg is None: 

138 continue 

139 elif reg is True: 

140 return subject 

141 ret = reg(subject) 

142 if ret is not None: 

143 return ret 

144 else: 

145 reg = ret = None 

146 

147 if raiseerr and (reg is None or ret is None): 

148 raise exc.NoInspectionAvailable( 

149 "No inspection system is " 

150 "available for object of type %s" % type_ 

151 ) 

152 return ret 

153 

154 

155def _inspects( 

156 *types: Type[Any], 

157) -> Callable[[_F], _F]: 

158 def decorate(fn_or_cls: _F) -> _F: 

159 for type_ in types: 

160 if type_ in _registrars: 

161 existing = _registrars[type_] 

162 existing_name = getattr(existing, "__name__", None) 

163 existing_module = getattr(existing, "__module__", None) 

164 

165 # allow a new version of the same function or class, that is, 

166 # a module reload; compare name/module attributes because 

167 # classes may define custom __eq__ behavior. 

168 if ( 

169 existing_name != fn_or_cls.__name__ 

170 or existing_module != fn_or_cls.__module__ 

171 ): 

172 raise AssertionError( 

173 "Type %s is already registered" % type_ 

174 ) 

175 _registrars[type_] = fn_or_cls 

176 return fn_or_cls 

177 

178 return decorate 

179 

180 

181_TT = TypeVar("_TT", bound="Type[Any]") 

182 

183 

184def _self_inspects(cls: _TT) -> _TT: 

185 if cls in _registrars: 

186 raise AssertionError("Type %s is already registered" % cls) 

187 _registrars[cls] = True 

188 return cls