Coverage for /home/runner/work/zserio/zserio/compiler/extensions/python/runtime/src/zserio/typeinfo.py: 100%
118 statements
« prev ^ index » next coverage.py v6.5.0, created at 2024-07-18 11:41 +0000
« prev ^ index » next coverage.py v6.5.0, created at 2024-07-18 11:41 +0000
1"""
2The module contains classes for type info.
3"""
5import typing
6import enum
9class TypeInfo:
10 """
11 Type info class which provides information about generated types.
12 """
14 def __init__(
15 self,
16 schema_name: str,
17 py_type: typing.Type,
18 *,
19 attributes: typing.Dict["TypeAttribute", typing.Any] = None
20 ):
21 """
22 Type info constructor.
24 :param schema_name: Zserio schema full type name.
25 :param py_type: Reference to the generated type.
26 :param attributes: List of type attributes.
27 """
29 self._schema_name = schema_name
30 self._py_type = py_type
31 self._attributes = attributes if attributes is not None else {}
33 @property
34 def schema_name(self) -> str:
35 """
36 Returns the full type name as is defined in Zserio schema.
38 :returns: Zserio schema full type name.
39 """
41 return self._schema_name
43 @property
44 def py_type(self) -> typing.Type:
45 """
46 Gets Python type generated for this Zserio type.
48 :returns: Python type.
49 """
51 return self._py_type
53 @property
54 def attributes(self) -> typing.Dict["TypeAttribute", typing.Any]:
55 """
56 Gets dictionary with type attributes.
58 Attribute is a an arbitrary value which type is given by the key, which is TypeAttribute enumeration.
60 * `(TypeAttribute.UNDERLYING_TYPE, TypeInfo(...))`
62 * denotes that the type has an underlying type (e.g. enum or bitmask),
63 the value is a TypeInfo of the underlying type
65 * `(TypeAttribute.UNDERLYING_TYPE_ARGUMENTS, [lambda: 5])`
67 * keeps type arguments of the underlying type when it is a dynamic bit field,
68 the value is a lambda function which returns the argument constant value
70 * `(TypeAttribute.ENUM_ITEMS, [ItemInfo(...), ItemInfo(...), ...])`
72 * denotes that the type is an enumeration, the value contains list of enum items ItemInfo
74 * `(TypeAttribute.BITMASK_VALUES, [ItemInfo(...), ItemInfo(...), ...])`
76 * denotes that the type is a bitmask, the value contains list of bitmask values ItemInfo
78 * `(TypeAttribute.FIELDS, [MemberInfo(...), MemberInfo(...), ...])`
80 * denotes that the type is a compound type, the value contains list of fields MemberInfo,
81 the attribute is present even for empty compounds and then it contains the empty list
83 * `(TypeAttribute.PARAMETERS, [MemberInfo(...), MemberInfo(...), ...])`
85 * denotes that the compound type is parameterized type, the value contains non-empty list of
86 parameters MemberInfo, for non-parameterized types the attribute is not present
88 * `(TypeAttribute.FUNCTIONS, [MemberInfo(...), MemberInfo(...), ...])`
90 * denotes that the compound type has functions, the value contains non-empty list of functions
91 MemberInfo, for compounds without functions the attribute is not present
93 * `(TypeAttribute.SELECTOR, None`) `(TypeAttribute.SELECTOR, lambda self: self.param1)`
95 * denotes that the type is either a union (when the value is None) or choice when the
96 value contains the selector expression as a lambda function taking single parent argument
98 * `(TypeAttribute.CASES, [CaseInfo(...), CaseInfo(...), ...])`
100 * denotes that the type is a choice, the value contains list of CaseInfo for each choice case
101 * note that the TypeAttribute.FIELDS attribute is present also in choices
103 * `(TypeAttribute.TEMPLATE_NAME, 'TemplatedStructure')`
105 * denotes that the type is a template instantiation, the value contains the template name
107 * `(TypeAttribute.TEMPLATE_ARGUMENTS, [test.TemplateArg.type_info(), ...])`
109 * present when the type is a template instantiation, the value contains list of template arguments
110 TypeInfo
112 * `(TypeAttribute.COLUMNS, [MemberInfo(...), MemberInfo(...), ...])`
114 * denotes that the type is a SQL table, the value contains list of columns MemberInfo
116 * `(TypeAttribute.TABLES, [MemberInfo(...), MemberInfo(...), ...])`
118 * denotes that the type is a SQL database, the value contain list of tables MemberInfo
120 * `(TypeAttribute.SQL_CONSTRAINT, 'PRIMARY KEY(columnA)')`
122 * denotes that the SQL table contains a SQL constraint
124 * `(TypeAttribute.VIRTUAL_TABLE_USING, 'fts4')`
126 * denotes that the SQL table is a virtual table, the value contains the used virtual table module
128 * `(TypeAttribute.WITHOUT_ROWID, None)`
130 * denotes that the SQL table is a WITHOUT ROWID table, the value is always None
132 * `(TypeAttribute.MESSAGES, [MemberInfo(...), MemberInfo(...), ...])`
134 * denotes that the type is a pub-sub, the value contains list of messages MemberInfo
136 * `(TypeAttribute.METHODS, [MemberInfo(...), MemberInfo(...), ...])`
138 * denotes that the type is a service, the value contains list of methods MemberInfo
140 :returns Type attributes.
141 """
143 return self._attributes
146class RecursiveTypeInfo:
147 """
148 Type info for recursive types used as a wrapper around generated static type_info method to prevent
149 infinite recursion in type info definition.
150 """
152 def __init__(self, type_info_func: typing.Callable[[], TypeInfo]):
153 """
154 Constructor.
156 :param type_info_func: Generated static type_info method to wrap.
157 """
159 self._type_info_func = type_info_func
160 self._type_info = None
162 @property
163 def schema_name(self) -> str:
164 """
165 See :py:attr:`TypeInfo.schema_name`.
166 """
168 return self._get_type_info().schema_name
170 @property
171 def py_type(self) -> typing.Type:
172 """
173 See :py:attr:`TypeInfo.py_type`.
174 """
176 return self._get_type_info().py_type
178 @property
179 def attributes(self) -> typing.Dict["TypeAttribute", typing.Any]:
180 """
181 See :py:attr:`TypeInfo.attributes`.
182 """
184 return self._get_type_info().attributes
186 def _get_type_info(self):
187 if self._type_info is None:
188 self._type_info = self._type_info_func()
189 return self._type_info
192class TypeAttribute(enum.Enum):
193 """
194 Type attribute type to be used in TypeInfo.
196 Determines type of the second element in the attribute tuple returned in attributes list from TypeInfo.
197 """
199 UNDERLYING_TYPE = enum.auto()
200 UNDERLYING_TYPE_ARGUMENTS = enum.auto()
201 ENUM_ITEMS = enum.auto()
202 BITMASK_VALUES = enum.auto()
203 FIELDS = enum.auto()
204 PARAMETERS = enum.auto()
205 FUNCTIONS = enum.auto()
206 SELECTOR = enum.auto()
207 CASES = enum.auto()
208 TEMPLATE_NAME = enum.auto()
209 TEMPLATE_ARGUMENTS = enum.auto()
210 COLUMNS = enum.auto()
211 TABLES = enum.auto()
212 SQL_CONSTRAINT = enum.auto()
213 VIRTUAL_TABLE_USING = enum.auto()
214 WITHOUT_ROWID = enum.auto()
215 MESSAGES = enum.auto()
216 METHODS = enum.auto()
219class MemberInfo:
220 """
221 Member info class which provides information about members of compound types.
222 """
224 def __init__(
225 self,
226 schema_name: str,
227 typeinfo: typing.Union[TypeInfo, RecursiveTypeInfo],
228 *,
229 attributes: typing.Dict["MemberAttribute", typing.Any] = None
230 ):
231 """
232 Member info constructor.
234 :param schema_name: Name of the member as is defined in Zserio schema.
235 :param type_info: Type info of the member.
236 :param attributes: List of member attributes.
237 """
239 self._schema_name = schema_name
240 self._type_info = typeinfo
241 self._attributes = attributes if attributes is not None else {}
243 @property
244 def schema_name(self) -> str:
245 """
246 Gets name of the member as is defined in Zserio schema.
248 :returns: Member name in Zserio schema.
249 """
251 return self._schema_name
253 @property
254 def type_info(self) -> typing.Union[TypeInfo, RecursiveTypeInfo]:
255 """
256 Gets type info of this member.
258 :returns: Type info.
259 """
261 return self._type_info
263 @property
264 def attributes(self) -> typing.Dict["MemberAttribute", typing.Any]:
265 """
266 Gets dictionary with member attributes.
268 Attribute is a an arbitrary value which type is given by the key, which is MemberAttribute enumeration.
269 All expressions are stored as strings.
271 **Possible attributes:**
273 * `(MemberAttribute.PROPERTY_NAME, 'field1')`
275 * contains name of the property generated in Python
277 * `(MemberAttribute.TYPE_ARGUMENTS, [(lambda self, zserio_index: self.field1), ...])`
279 * for compound type members, keeps type arguments for parameterized types or dynamic bit fields,
280 the value contains list of lambda functions evaluating particular arguments expression,
281 where the lambdas take parent and an element index (which can be None if not used) as arguments
283 * for members of sql tables, keeps type arguments for columns, the value contains list of
284 lambdas where the lambdas take either single explicit parameter argument for explicit parameters or
285 single 'self' argument, which is an object providing property-like getters for column names
286 used in expressions
288 * `(MemberAttribute.EXTENDED, None)`
290 * denotes that the member field is extended, the value is always None
292 * `(MemberAttribute.ALIGN, lambda: 8)`
294 * denotes that the member field has an alignment, the value is a lambda function which returns the
295 alignment constant value
297 * `(MemberAttribute.OFFSET, lambda self: self.offset_field)`
299 * denotes that the member field has an offset, the value contains the offset expression
300 as a lambda function taking single parent argument
302 * `(MemberAttribute.INITIALIZER, lambda: 10)`
304 * denotes that the member field has an initializer, the value is a lambda function which returns the
305 the initializer constant value
307 * `(MemberAttribute.OPTIONAL, None)`, `(MemberAttribute.OPTIONAL, lambda self: self.field1 != 0)`
309 * denotes that the member is an optional, when the value is None, then it's an auto optional,
310 otherwise it contains the optional clause as a lambda function taking single parent argument
312 * `(MemberAttribute.IS_USED_INDICATOR_NAME, 'is_field_used)`
314 * if the member is an optional, the value contains the "is_used" indicator name generated in Python
316 * `(MemberAttribute.IS_SET_INDICATOR_NAME, 'is_field_set)`
318 * if the member is an optional, the value contains the "is_set" indicator name generated in Python
320 * `(MemberAttribute.CONSTRAINT, lambda self: field > 10)`
322 * denotes that the member has a constraint, the value contains the constraint expression
323 as a lambda function taking single parent argument
325 * `(MemberAttribute.FUNCTION_NAME, 'function_name')`
327 * keeps the generated function name
329 * `MemberAttribute.FUNCTION_RESULT, lambda self: self.field1 + 5)`
331 * keeps the result expression of a function as a lambda function taking single parent argument
333 * `(MemberAttribute.ARRAY_LENGTH, None)`, `(MemberAttribute.ARRAY_LENGTH, lambda self: self.field1 + 1)`
335 * denotes that the member is an array, when the value is None, then it's an auto array,
336 otherwise it contains the length expression as a lambda function taking single parent argument
338 * `(MemberAttribute.IMPLICIT, None)`
340 * denotes that the member is an implicit array, the value is always None
342 * `(MemberAttribute.PACKED, None)`
344 * denotes that the member is a packed array, the value is always None
346 * `(MemberAttribute.SQL_TYPE_NAME, 'INTEGER')`
348 * keeps SQLite type name used for this column
350 * `(MemberAttribute.SQL_CONSTRAINT, 'PRIMARY KEY NOT NULL')`
352 * denotes that the member has a SQL constraint
354 * `(MemberAttribute.VIRTUAL, None)`
356 * denotes that the column in a SQL table is virtual
358 * `(MemberAttribute.TOPIC, 'topic/definition')`
360 * keeps the topic definition of a pub-sub message
362 * `(MemberAttribute.PUBLISH, 'publish_message_name')`
364 * denotes that the pub-sub message is published, the value contains the publishing method name
366 * `(MemberAttribute.SUBSCRIBE, 'subscribe_message_name')`
368 * denotes that the pub-sub message is subscribed, the value contains the subscribing method name
370 * `(MemberAttribute.CLIENT_METHOD_NAME, 'client_method_name')`
372 * keeps the name of the method in the generated Client class
374 * `(MemberAttribute.REQUEST_TYPE, request_type.type_info())`
376 * keeps the request type TypeInfo, note that response type is in the method TypeInfo
378 :returns: Member attributes.
379 """
381 return self._attributes
384class MemberAttribute(enum.Enum):
385 """
386 Member attribute type to be used in MemberInfo.
388 Determines type of the second element in the attribute tuple returned in attributes list from MemberInfo.
389 """
391 PROPERTY_NAME = enum.auto()
392 TYPE_ARGUMENTS = enum.auto()
393 EXTENDED = enum.auto()
394 ALIGN = enum.auto()
395 OFFSET = enum.auto()
396 INITIALIZER = enum.auto()
397 OPTIONAL = enum.auto()
398 IS_USED_INDICATOR_NAME = enum.auto()
399 IS_SET_INDICATOR_NAME = enum.auto()
400 CONSTRAINT = enum.auto()
401 FUNCTION_NAME = enum.auto()
402 FUNCTION_RESULT = enum.auto()
403 ARRAY_LENGTH = enum.auto()
404 IMPLICIT = enum.auto()
405 PACKED = enum.auto()
406 SQL_TYPE_NAME = enum.auto()
407 SQL_CONSTRAINT = enum.auto()
408 VIRTUAL = enum.auto()
409 TOPIC = enum.auto()
410 PUBLISH = enum.auto()
411 SUBSCRIBE = enum.auto()
412 CLIENT_METHOD_NAME = enum.auto()
413 REQUEST_TYPE = enum.auto()
416class CaseInfo:
417 """
418 Case info class which provides information about choice cases in generated choices.
419 """
421 def __init__(
422 self,
423 case_expressions: typing.List[typing.Any],
424 field: typing.Optional[MemberInfo],
425 ):
426 """
427 Constructor.
429 :param case_expressions: List of case expression in the choice case. When empty, it's a default case.
430 :param field: Field associated with the choice case, can be empty.
431 """
433 self._case_expressions = case_expressions
434 self._field = field
436 @property
437 def case_expressions(self) -> typing.List[typing.Any]:
438 """
439 Gets case expressions in the choice case. An empty list denotes the default case.
441 :returns: List of case expressions as evaluated constant values.
442 """
444 return self._case_expressions
446 @property
447 def field(self) -> typing.Optional[MemberInfo]:
448 """
449 Gets field associated with the choice case. Can be empty.
451 :returns: Field MemberInfo.
452 """
454 return self._field
457class ItemInfo:
458 """
459 Item info class which provides information about items of generated enumerable types.
460 """
462 def __init__(
463 self,
464 schema_name: str,
465 py_item: typing.Any,
466 is_deprecated: bool,
467 is_removed: bool,
468 ):
469 """
470 Constructor.
472 :param schema_name: Name of the item as is defined in Zserio schema.
473 :param py_item: Reference to the generated item.
474 """
476 self._schema_name = schema_name
477 self._py_item = py_item
478 self._is_deprecated = is_deprecated
479 self._is_removed = is_removed
481 @property
482 def schema_name(self) -> str:
483 """
484 Gets name of the item as is defined in Zserio schema.
486 :returns: Item name in Zserio schema.
487 """
489 return self._schema_name
491 @property
492 def py_item(self) -> typing.Any:
493 """
494 Gets reference to the item generated in Python.
496 :returns: Python item.
497 """
499 return self._py_item
501 @property
502 def is_deprecated(self) -> bool:
503 """
504 Gets flag whether the item is deprecated.
506 :returns: True when the item is deprecated, false otherwise.
507 """
509 return self._is_deprecated
511 @property
512 def is_removed(self) -> bool:
513 """
514 Gets flag whether the item is removed.
516 :returns: True when the item is removed, false otherwise.
517 """
519 return self._is_removed