Coverage for src/typedal/types.py: 100%

76 statements  

« prev     ^ index     » next       coverage.py v7.5.1, created at 2024-08-05 19:10 +0200

1""" 

2Stuff to make mypy happy. 

3""" 

4 

5import typing 

6from datetime import datetime 

7from typing import Any, Optional, TypedDict 

8 

9from pydal.adapters.base import BaseAdapter 

10from pydal.helpers.classes import OpRow as _OpRow 

11from pydal.helpers.classes import Reference as _Reference 

12from pydal.objects import Expression as _Expression 

13from pydal.objects import Field as _Field 

14from pydal.objects import Query as _Query 

15from pydal.objects import Rows as _Rows 

16from pydal.objects import Set as _Set 

17from pydal.objects import Table as _Table 

18from pydal.validators import Validator as _Validator 

19from typing_extensions import NotRequired 

20 

21if typing.TYPE_CHECKING: 

22 from .core import TypedField 

23 

24AnyDict: typing.TypeAlias = dict[str, Any] 

25 

26 

27class Query(_Query): # type: ignore 

28 """ 

29 Pydal Query object. 

30 

31 Makes mypy happy. 

32 """ 

33 

34 

35class Expression(_Expression): # type: ignore 

36 """ 

37 Pydal Expression object. 

38 

39 Make mypy happy. 

40 """ 

41 

42 

43class Set(_Set): # type: ignore 

44 """ 

45 Pydal Set object. 

46 

47 Make mypy happy. 

48 """ 

49 

50 

51if typing.TYPE_CHECKING: 

52 

53 class OpRow: 

54 """ 

55 Pydal OpRow object for typing (otherwise mypy thinks it's Any). 

56 

57 Make mypy happy. 

58 """ 

59 

60 def __getitem__(self, item: str) -> typing.Any: 

61 """ 

62 Dict [] get notation. 

63 """ 

64 

65 def __setitem__(self, key: str, value: typing.Any) -> None: 

66 """ 

67 Dict [] set notation. 

68 """ 

69 

70 # ... and more methods 

71 

72else: 

73 

74 class OpRow(_OpRow): # type: ignore 

75 """ 

76 Pydal OpRow object at runtime just uses pydal's version. 

77 

78 Make mypy happy. 

79 """ 

80 

81 

82class Reference(_Reference): # type: ignore 

83 """ 

84 Pydal Reference object. 

85 

86 Make mypy happy. 

87 """ 

88 

89 

90class Field(_Field): # type: ignore 

91 """ 

92 Pydal Field object. 

93 

94 Make mypy happy. 

95 """ 

96 

97 

98class Rows(_Rows): # type: ignore 

99 """ 

100 Pydal Rows object. 

101 

102 Make mypy happy. 

103 """ 

104 

105 def column(self, column: typing.Any = None) -> list[typing.Any]: 

106 """ 

107 Get a list of all values in a specific column. 

108 

109 Example: 

110 rows.column('name') -> ['Name 1', 'Name 2', ...] 

111 """ 

112 return [r[str(column) if column else self.colnames[0]] for r in self] 

113 

114 

115class Validator(_Validator): # type: ignore 

116 """ 

117 Pydal Validator object. 

118 

119 Make mypy happy. 

120 """ 

121 

122 

123class _Types: 

124 """ 

125 Internal type storage for stuff that mypy otherwise won't understand. 

126 """ 

127 

128 NONETYPE = type(None) 

129 

130 

131class Pagination(TypedDict): 

132 """ 

133 Pagination key of a paginate dict has these items. 

134 """ 

135 

136 total_items: int 

137 current_page: int 

138 per_page: int 

139 total_pages: int 

140 has_next_page: bool 

141 has_prev_page: bool 

142 next_page: Optional[int] 

143 prev_page: Optional[int] 

144 

145 

146class PaginateDict(TypedDict): 

147 """ 

148 Result of PaginatedRows.as_dict(). 

149 """ 

150 

151 data: dict[int, AnyDict] 

152 pagination: Pagination 

153 

154 

155class CacheMetadata(TypedDict): 

156 """ 

157 Used by query builder metadata in the 'cache' key. 

158 """ 

159 

160 enabled: bool 

161 depends_on: list[Any] 

162 key: NotRequired[str | None] 

163 status: NotRequired[str | None] 

164 expires_at: NotRequired[datetime | None] 

165 cached_at: NotRequired[datetime | None] 

166 

167 

168class PaginationMetadata(TypedDict): 

169 """ 

170 Used by query builder metadata in the 'pagination' key. 

171 """ 

172 

173 limit: int 

174 current_page: int 

175 max_page: int 

176 rows: int 

177 min_max: tuple[int, int] 

178 

179 

180class TableProtocol(typing.Protocol): # pragma: no cover 

181 """ 

182 Make mypy happy. 

183 """ 

184 

185 id: "TypedField[int]" 

186 

187 def __getitem__(self, item: str) -> Field: 

188 """ 

189 Tell mypy a Table supports dictionary notation for columns. 

190 """ 

191 

192 

193class Table(_Table, TableProtocol): # type: ignore 

194 """ 

195 Make mypy happy. 

196 """ 

197 

198 

199class CacheFn(typing.Protocol): 

200 """ 

201 The cache model (e.g. cache.ram) accepts these parameters (all filled by dfeault). 

202 """ 

203 

204 def __call__( 

205 self: BaseAdapter, 

206 sql: str = "", 

207 fields: typing.Iterable[str] = (), 

208 attributes: typing.Iterable[str] = (), 

209 colnames: typing.Iterable[str] = (), 

210 ) -> Rows: 

211 """ 

212 Only used for type-hinting. 

213 """ 

214 

215 

216# CacheFn = typing.Callable[[], Rows] 

217CacheModel = typing.Callable[[str, CacheFn, int], Rows] 

218CacheTuple = tuple[CacheModel, int] 

219 

220 

221class SelectKwargs(typing.TypedDict, total=False): 

222 """ 

223 Possible keyword arguments for .select(). 

224 """ 

225 

226 join: Optional[list[Expression]] 

227 left: Optional[list[Expression]] 

228 orderby: Optional[Expression | str | Table] 

229 limitby: Optional[tuple[int, int]] 

230 distinct: bool | Field | Expression 

231 orderby_on_limitby: bool 

232 cacheable: bool 

233 cache: CacheTuple 

234 

235 

236class Metadata(TypedDict): 

237 """ 

238 Loosely structured metadata used by Query Builder. 

239 """ 

240 

241 cache: NotRequired[CacheMetadata] 

242 pagination: NotRequired[PaginationMetadata] 

243 

244 query: NotRequired[Query | str | None] 

245 ids: NotRequired[str] 

246 

247 final_query: NotRequired[Query | str | None] 

248 final_args: NotRequired[list[Any]] 

249 final_kwargs: NotRequired[SelectKwargs] 

250 relationships: NotRequired[set[str]] 

251 

252 sql: NotRequired[str]