Coverage for /home/jenkins/workspace/NDS/Zserio/NDS_ZSERIO-linux-build/compiler/extensions/python/runtime/src/zserio/typeinfo.py: 100%

118 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2023-12-13 15:12 +0000

1""" 

2The module contains classes for type info. 

3""" 

4 

5import typing 

6import enum 

7 

8class TypeInfo: 

9 """ 

10 Type info class which provides information about generated types. 

11 """ 

12 

13 def __init__(self, schema_name: str, py_type: typing.Type, *, 

14 attributes: typing.Dict['TypeAttribute', typing.Any] = None): 

15 """ 

16 Type info constructor. 

17 

18 :param schema_name: Zserio schema full type name. 

19 :param py_type: Reference to the generated type. 

20 :param attributes: List of type attributes. 

21 """ 

22 

23 self._schema_name = schema_name 

24 self._py_type = py_type 

25 self._attributes = attributes if attributes is not None else {} 

26 

27 @property 

28 def schema_name(self) -> str: 

29 """ 

30 Returns the full type name as is defined in Zserio schema. 

31 

32 :returns: Zserio schema full type name. 

33 """ 

34 

35 return self._schema_name 

36 

37 @property 

38 def py_type(self) -> typing.Type: 

39 """ 

40 Gets Python type generated for this Zserio type. 

41 

42 :returns: Python type. 

43 """ 

44 

45 return self._py_type 

46 

47 @property 

48 def attributes(self) -> typing.Dict['TypeAttribute', typing.Any]: 

49 """ 

50 Gets dictionary with type attributes. 

51 

52 Attribute is a an arbitrary value which type is given by the key, which is TypeAttribute enumeration. 

53 

54 * `(TypeAttribute.UNDERLYING_TYPE, TypeInfo(...))` 

55 

56 * denotes that the type has an underlying type (e.g. enum or bitmask), 

57 the value is a TypeInfo of the underlying type 

58 

59 * `(TypeAttribute.UNDERLYING_TYPE_ARGUMENTS, [lambda: 5])` 

60 

61 * keeps type arguments of the underlying type when it is a dynamic bit field, 

62 the value is a lambda function which returns the argument constant value 

63 

64 * `(TypeAttribute.ENUM_ITEMS, [ItemInfo(...), ItemInfo(...), ...])` 

65 

66 * denotes that the type is an enumeration, the value contains list of enum items ItemInfo 

67 

68 * `(TypeAttribute.BITMASK_VALUES, [ItemInfo(...), ItemInfo(...), ...])` 

69 

70 * denotes that the type is a bitmask, the value contains list of bitmask values ItemInfo 

71 

72 * `(TypeAttribute.FIELDS, [MemberInfo(...), MemberInfo(...), ...])` 

73 

74 * denotes that the type is a compound type, the value contains list of fields MemberInfo, 

75 the attribute is present even for empty compounds and then it contains the empty list 

76 

77 * `(TypeAttribute.PARAMETERS, [MemberInfo(...), MemberInfo(...), ...])` 

78 

79 * denotes that the compound type is parameterized type, the value contains non-empty list of 

80 parameters MemberInfo, for non-parameterized types the attribute is not present 

81 

82 * `(TypeAttribute.FUNCTIONS, [MemberInfo(...), MemberInfo(...), ...])` 

83 

84 * denotes that the compound type has functions, the value contains non-empty list of functions 

85 MemberInfo, for compounds without functions the attribute is not present 

86 

87 * `(TypeAttribute.SELECTOR, None`) `(TypeAttribute.SELECTOR, lambda self: self.param1)` 

88 

89 * denotes that the type is either a union (when the value is None) or choice when the 

90 value contains the selector expression as a lambda function taking single parent argument 

91 

92 * `(TypeAttribute.CASES, [CaseInfo(...), CaseInfo(...), ...])` 

93 

94 * denotes that the type is a choice, the value contains list of CaseInfo for each choice case 

95 * note that the TypeAttribute.FIELDS attribute is present also in choices 

96 

97 * `(TypeAttribute.TEMPLATE_NAME, 'TemplatedStructure')` 

98 

99 * denotes that the type is a template instantiation, the value contains the template name 

100 

101 * `(TypeAttribute.TEMPLATE_ARGUMENTS, [test.TemplateArg.type_info(), ...])` 

102 

103 * present when the type is a template instantiation, the value contains list of template arguments 

104 TypeInfo 

105 

106 * `(TypeAttribute.COLUMNS, [MemberInfo(...), MemberInfo(...), ...])` 

107 

108 * denotes that the type is a SQL table, the value contains list of columns MemberInfo 

109 

110 * `(TypeAttribute.TABLES, [MemberInfo(...), MemberInfo(...), ...])` 

111 

112 * denotes that the type is a SQL database, the value contain list of tables MemberInfo 

113 

114 * `(TypeAttribute.SQL_CONSTRAINT, 'PRIMARY KEY(columnA)')` 

115 

116 * denotes that the SQL table contains a SQL constraint 

117 

118 * `(TypeAttribute.VIRTUAL_TABLE_USING, 'fts4')` 

119 

120 * denotes that the SQL table is a virtual table, the value contains the used virtual table module 

121 

122 * `(TypeAttribute.WITHOUT_ROWID, None)` 

123 

124 * denotes that the SQL table is a WITHOUT ROWID table, the value is always None 

125 

126 * `(TypeAttribute.MESSAGES, [MemberInfo(...), MemberInfo(...), ...])` 

127 

128 * denotes that the type is a pub-sub, the value contains list of messages MemberInfo 

129 

130 * `(TypeAttribute.METHODS, [MemberInfo(...), MemberInfo(...), ...])` 

131 

132 * denotes that the type is a service, the value contains list of methods MemberInfo 

133 

134 :returns Type attributes. 

135 """ 

136 

137 return self._attributes 

138 

139class RecursiveTypeInfo: 

140 """ 

141 Type info for recursive types used as a wrapper around generated static type_info method to prevent 

142 infinite recursion in type info definition. 

143 """ 

144 

145 def __init__(self, type_info_func : typing.Callable[[], TypeInfo]): 

146 """ 

147 Constructor. 

148 

149 :param type_info_func: Generated static type_info method to wrap. 

150 """ 

151 

152 self._type_info_func = type_info_func 

153 self._type_info = None 

154 

155 @property 

156 def schema_name(self) -> str: 

157 """ 

158 See :py:attr:`TypeInfo.schema_name`. 

159 """ 

160 

161 return self._get_type_info().schema_name 

162 

163 @property 

164 def py_type(self) -> typing.Type: 

165 """ 

166 See :py:attr:`TypeInfo.py_type`. 

167 """ 

168 

169 return self._get_type_info().py_type 

170 

171 @property 

172 def attributes(self) -> typing.Dict['TypeAttribute', typing.Any]: 

173 """ 

174 See :py:attr:`TypeInfo.attributes`. 

175 """ 

176 

177 return self._get_type_info().attributes 

178 

179 def _get_type_info(self): 

180 if self._type_info is None: 

181 self._type_info = self._type_info_func() 

182 return self._type_info 

183 

184class TypeAttribute(enum.Enum): 

185 """ 

186 Type attribute type to be used in TypeInfo. 

187 

188 Determines type of the second element in the attribute tuple returned in attributes list from TypeInfo. 

189 """ 

190 

191 UNDERLYING_TYPE = enum.auto() 

192 UNDERLYING_TYPE_ARGUMENTS = enum.auto() 

193 ENUM_ITEMS = enum.auto() 

194 BITMASK_VALUES = enum.auto() 

195 FIELDS = enum.auto() 

196 PARAMETERS = enum.auto() 

197 FUNCTIONS = enum.auto() 

198 SELECTOR = enum.auto() 

199 CASES = enum.auto() 

200 TEMPLATE_NAME = enum.auto() 

201 TEMPLATE_ARGUMENTS= enum.auto() 

202 COLUMNS = enum.auto() 

203 TABLES = enum.auto() 

204 SQL_CONSTRAINT = enum.auto() 

205 VIRTUAL_TABLE_USING = enum.auto() 

206 WITHOUT_ROWID = enum.auto() 

207 MESSAGES = enum.auto() 

208 METHODS = enum.auto() 

209 

210class MemberInfo: 

211 """ 

212 Member info class which provides information about members of compound types. 

213 """ 

214 

215 def __init__(self, schema_name: str, typeinfo: typing.Union[TypeInfo, RecursiveTypeInfo], *, 

216 attributes: typing.Dict['MemberAttribute', typing.Any] = None): 

217 """ 

218 Member info constructor. 

219 

220 :param schema_name: Name of the member as is defined in Zserio schema. 

221 :param type_info: Type info of the member. 

222 :param attributes: List of member attributes. 

223 """ 

224 

225 self._schema_name = schema_name 

226 self._type_info = typeinfo 

227 self._attributes = attributes if attributes is not None else {} 

228 

229 @property 

230 def schema_name(self) -> str: 

231 """ 

232 Gets name of the member as is defined in Zserio schema. 

233 

234 :returns: Member name in Zserio schema. 

235 """ 

236 

237 return self._schema_name 

238 

239 @property 

240 def type_info(self) -> typing.Union[TypeInfo, RecursiveTypeInfo]: 

241 """ 

242 Gets type info of this member. 

243 

244 :returns: Type info. 

245 """ 

246 

247 return self._type_info 

248 

249 @property 

250 def attributes(self) -> typing.Dict['MemberAttribute', typing.Any]: 

251 """ 

252 Gets dictionary with member attributes. 

253 

254 Attribute is a an arbitrary value which type is given by the key, which is MemberAttribute enumeration. 

255 All expressions are stored as strings. 

256 

257 **Possible attributes:** 

258 

259 * `(MemberAttribute.PROPERTY_NAME, 'field1')` 

260 

261 * contains name of the property generated in Python 

262 

263 * `(MemberAttribute.TYPE_ARGUMENTS, [(lambda self, zserio_index: self.field1), ...])` 

264 

265 * for compound type members, keeps type arguments for parameterized types or dynamic bit fields, 

266 the value contains list of lambda functions evaluating particular arguments expression, 

267 where the lambdas take parent and an element index (which can be None if not used) as arguments 

268 

269 * for members of sql tables, keeps type arguments for columns, the value contains list of 

270 lambdas where the lambdas take either single explicit parameter argument for explicit parameters or 

271 single 'self' argument, which is an object providing property-like getters for column names 

272 used in expressions 

273 

274 * `(MemberAttribute.EXTENDED, None)` 

275 

276 * denotes that the member field is extended, the value is always None 

277 

278 * `(MemberAttribute.ALIGN, lambda: 8)` 

279 

280 * denotes that the member field has an alignment, the value is a lambda function which returns the 

281 alignment constant value 

282 

283 * `(MemberAttribute.OFFSET, lambda self: self.offset_field)` 

284 

285 * denotes that the member field has an offset, the value contains the offset expression 

286 as a lambda function taking single parent argument 

287 

288 * `(MemberAttribute.INITIALIZER, lambda: 10)` 

289 

290 * denotes that the member field has an initializer, the value is a lambda function which returns the 

291 the initializer constant value 

292 

293 * `(MemberAttribute.OPTIONAL, None)`, `(MemberAttribute.OPTIONAL, lambda self: self.field1 != 0)` 

294 

295 * denotes that the member is an optional, when the value is None, then it's an auto optional, 

296 otherwise it contains the optional clause as a lambda function taking single parent argument 

297 

298 * `(MemberAttribute.IS_USED_INDICATOR_NAME, 'is_field_used)` 

299 

300 * if the member is an optional, the value contains the "is_used" indicator name generated in Python 

301 

302 * `(MemberAttribute.IS_SET_INDICATOR_NAME, 'is_field_set)` 

303 

304 * if the member is an optional, the value contains the "is_set" indicator name generated in Python 

305 

306 * `(MemberAttribute.CONSTRAINT, lambda self: field > 10)` 

307 

308 * denotes that the member has a constraint, the value contains the constraint expression 

309 as a lambda function taking single parent argument 

310 

311 * `(MemberAttribute.FUNCTION_NAME, 'function_name')` 

312 

313 * keeps the generated function name 

314 

315 * `MemberAttribute.FUNCTION_RESULT, lambda self: self.field1 + 5)` 

316 

317 * keeps the result expression of a function as a lambda function taking single parent argument 

318 

319 * `(MemberAttribute.ARRAY_LENGTH, None)`, `(MemberAttribute.ARRAY_LENGTH, lambda self: self.field1 + 1)` 

320 

321 * denotes that the member is an array, when the value is None, then it's an auto array, 

322 otherwise it contains the length expression as a lambda function taking single parent argument 

323 

324 * `(MemberAttribute.IMPLICIT, None)` 

325 

326 * denotes that the member is an implicit array, the value is always None 

327 

328 * `(MemberAttribute.PACKED, None)` 

329 

330 * denotes that the member is a packed array, the value is always None 

331 

332 * `(MemberAttribute.SQL_TYPE_NAME, 'INTEGER')` 

333 

334 * keeps SQLite type name used for this column 

335 

336 * `(MemberAttribute.SQL_CONSTRAINT, 'PRIMARY KEY NOT NULL')` 

337 

338 * denotes that the member has a SQL constraint 

339 

340 * `(MemberAttribute.VIRTUAL, None)` 

341 

342 * denotes that the column in a SQL table is virtual 

343 

344 * `(MemberAttribute.TOPIC, 'topic/definition')` 

345 

346 * keeps the topic definition of a pub-sub message 

347 

348 * `(MemberAttribute.PUBLISH, 'publish_message_name')` 

349 

350 * denotes that the pub-sub message is published, the value contains the publishing method name 

351 

352 * `(MemberAttribute.SUBSCRIBE, 'subscribe_message_name')` 

353 

354 * denotes that the pub-sub message is subscribed, the value contains the subscribing method name 

355 

356 * `(MemberAttribute.CLIENT_METHOD_NAME, 'client_method_name')` 

357 

358 * keeps the name of the method in the generated Client class 

359 

360 * `(MemberAttribute.REQUEST_TYPE, request_type.type_info())` 

361 

362 * keeps the request type TypeInfo, note that response type is in the method TypeInfo 

363 

364 :returns: Member attributes. 

365 """ 

366 

367 return self._attributes 

368 

369class MemberAttribute(enum.Enum): 

370 """ 

371 Member attribute type to be used in MemberInfo. 

372 

373 Determines type of the second element in the attribute tuple returned in attributes list from MemberInfo. 

374 """ 

375 

376 PROPERTY_NAME = enum.auto() 

377 TYPE_ARGUMENTS = enum.auto() 

378 EXTENDED = enum.auto() 

379 ALIGN = enum.auto() 

380 OFFSET = enum.auto() 

381 INITIALIZER = enum.auto() 

382 OPTIONAL = enum.auto() 

383 IS_USED_INDICATOR_NAME = enum.auto() 

384 IS_SET_INDICATOR_NAME = enum.auto() 

385 CONSTRAINT = enum.auto() 

386 FUNCTION_NAME = enum.auto() 

387 FUNCTION_RESULT = enum.auto() 

388 ARRAY_LENGTH = enum.auto() 

389 IMPLICIT = enum.auto() 

390 PACKED = enum.auto() 

391 SQL_TYPE_NAME = enum.auto() 

392 SQL_CONSTRAINT = enum.auto() 

393 VIRTUAL = enum.auto() 

394 TOPIC = enum.auto() 

395 PUBLISH = enum.auto() 

396 SUBSCRIBE = enum.auto() 

397 CLIENT_METHOD_NAME = enum.auto() 

398 REQUEST_TYPE = enum.auto() 

399 

400class CaseInfo: 

401 """ 

402 Case info class which provides information about choice cases in generated choices. 

403 """ 

404 

405 def __init__(self, case_expressions: typing.List[typing.Any], field: typing.Optional[MemberInfo]): 

406 """ 

407 Constructor. 

408 

409 :param case_expressions: List of case expression in the choice case. When empty, it's a default case. 

410 :param field: Field associated with the choice case, can be empty. 

411 """ 

412 

413 self._case_expressions = case_expressions 

414 self._field = field 

415 

416 @property 

417 def case_expressions(self) -> typing.List[typing.Any]: 

418 """ 

419 Gets case expressions in the choice case. An empty list denotes the default case. 

420 

421 :returns: List of case expressions as evaluated constant values. 

422 """ 

423 

424 return self._case_expressions 

425 

426 @property 

427 def field(self) -> typing.Optional[MemberInfo]: 

428 """ 

429 Gets field associated with the choice case. Can be empty. 

430 

431 :returns: Field MemberInfo. 

432 """ 

433 

434 return self._field 

435 

436 

437class ItemInfo: 

438 """ 

439 Item info class which provides information about items of generated enumerable types. 

440 """ 

441 

442 def __init__(self, schema_name: str, py_item: typing.Any, is_deprecated: bool, is_removed: bool): 

443 """ 

444 Constructor. 

445 

446 :param schema_name: Name of the item as is defined in Zserio schema. 

447 :param py_item: Reference to the generated item. 

448 """ 

449 

450 self._schema_name = schema_name 

451 self._py_item = py_item 

452 self._is_deprecated = is_deprecated 

453 self._is_removed = is_removed 

454 

455 @property 

456 def schema_name(self) -> str: 

457 """ 

458 Gets name of the item as is defined in Zserio schema. 

459 

460 :returns: Item name in Zserio schema. 

461 """ 

462 

463 return self._schema_name 

464 

465 @property 

466 def py_item(self) -> typing.Any: 

467 """ 

468 Gets reference to the item generated in Python. 

469 

470 :returns: Python item. 

471 """ 

472 

473 return self._py_item 

474 

475 @property 

476 def is_deprecated(self) -> bool: 

477 """ 

478 Gets flag whether the item is deprecated. 

479 

480 :returns: True when the item is deprecated, false otherwise. 

481 """ 

482 

483 return self._is_deprecated 

484 

485 @property 

486 def is_removed(self) -> bool: 

487 """ 

488 Gets flag whether the item is removed. 

489 

490 :returns: True when the item is removed, false otherwise. 

491 """ 

492 

493 return self._is_removed