aboutsummaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
authorRichard Henderson <richard.henderson@linaro.org>2024-04-24 09:23:33 -0700
committerRichard Henderson <richard.henderson@linaro.org>2024-04-24 09:23:33 -0700
commitbffc14efd9219bc11fed568f1dbd70f03be3103a (patch)
treec6e3f41b40e79bd5692974e0d642bb2e71dda6ed /scripts
parent1e0a7549e1f93112a2c0c08d95eb16b604d32cca (diff)
parent060b5a9323e5f49c5edcb77c42e231065bbcc42e (diff)
downloadqemu-bffc14efd9219bc11fed568f1dbd70f03be3103a.zip
qemu-bffc14efd9219bc11fed568f1dbd70f03be3103a.tar.gz
qemu-bffc14efd9219bc11fed568f1dbd70f03be3103a.tar.bz2
Merge tag 'pull-qapi-2024-04-24' of https://repo.or.cz/qemu/armbru into staging
QAPI patches patches for 2024-04-24 # -----BEGIN PGP SIGNATURE----- # # iQJGBAABCAAwFiEENUvIs9frKmtoZ05fOHC0AOuRhlMFAmYovX4SHGFybWJydUBy # ZWRoYXQuY29tAAoJEDhwtADrkYZT0RQP/1R1oOSdfWmiSR5gdW+IDE88VrjNY+Md # lZJ7dTtbIDbwABP6s7/wGIxlc4bf6lwIwhWNnfOa+y71jJ/u9aX2Q6D8wHY5lQnu # b8jhzoP3UyB+LQV5TTX1nTqTaO72Bj0pxw/0/DeKCzg7kgjys06a1Ln9P0oyWs6x # li/Cs133wPtZ5rISqif5yOmssber0h2D584k5MN2VK7eaGidLioQQIRmSDikPE6Z # TpnOEqySInIFhPJmm77il19ZDpCrgdCoD7lXoqX1C6XScYz7dU+m/TaToFk1lECw # VstR2SJT39TzbOLdis1O5/vsLP0QfciMRQbUktSrf4jQHumrkSa/OE6xKwJC3x82 # axJWc+BygcosylKc5CYVzwSlHugHw6Lf39qui//yzi5CXakzO6owKX7Q8AcH3PPy # 6thncy0dvw1ggq/BZGYhjyG+6MXBCWipPGVXFp9Gf2cAayTALhwyNtPvDNX57fzT # UZA/fa+/Wc9xZv1YAnxLaKyo4o65YWXVnq1eHXV17ny08BzZNYOC2ZuXim+rMThM # lxzcrTkrMLgsGXetp59uhZw9JRnVvaxLqNXfC2bwpoRzXzuifvnPithl6nkSm1YB # TvHGZZdO3B498kOW6947KrMVFh3t4aNWkdbOyetAMECy71H3Q4CTHYGFa5TzXT9O # Rjz31NYdVNBE # =uyfg # -----END PGP SIGNATURE----- # gpg: Signature made Wed 24 Apr 2024 01:06:22 AM PDT # gpg: using RSA key 354BC8B3D7EB2A6B68674E5F3870B400EB918653 # gpg: issuer "armbru@redhat.com" # gpg: Good signature from "Markus Armbruster <armbru@redhat.com>" [undefined] # gpg: aka "Markus Armbruster <armbru@pond.sub.org>" [undefined] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 354B C8B3 D7EB 2A6B 6867 4E5F 3870 B400 EB91 8653 * tag 'pull-qapi-2024-04-24' of https://repo.or.cz/qemu/armbru: (25 commits) qapi: Dumb down QAPISchema.lookup_entity() qapi: Tighten check whether implicit object type already exists qapi/schema: remove unnecessary asserts qapi/schema: turn on mypy strictness qapi/schema: add type hints qapi/parser.py: assert member.info is present in connect_member qapi/parser: demote QAPIExpression to Dict[str, Any] qapi/schema: assert inner type of QAPISchemaVariants in check_clash() qapi/schema: fix typing for QAPISchemaVariants.tag_member qapi/schema: Don't initialize "members" with `None` qapi/schema: add _check_complete flag qapi/schema: assert info is present when necessary qapi/schema: fix QAPISchemaArrayType.check's call to resolve_type qapi: Assert built-in types exist qapi/schema: assert resolve_type has 'info' and 'what' args on error qapi/schema: add type narrowing to lookup_type() qapi/schema: adjust type narrowing for mypy's benefit qapi/schema: make c_type() and json_type() abstract methods qapi/schema: declare type for QAPISchemaArrayType.element_type qapi/schema: declare type for QAPISchemaObjectTypeMember.type ... Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Diffstat (limited to 'scripts')
-rw-r--r--scripts/qapi/introspect.py8
-rw-r--r--scripts/qapi/mypy.ini5
-rw-r--r--scripts/qapi/parser.py7
-rw-r--r--scripts/qapi/pylintrc11
-rw-r--r--scripts/qapi/schema.py792
5 files changed, 536 insertions, 287 deletions
diff --git a/scripts/qapi/introspect.py b/scripts/qapi/introspect.py
index 67c7d89..4679b1b 100644
--- a/scripts/qapi/introspect.py
+++ b/scripts/qapi/introspect.py
@@ -227,10 +227,14 @@ const QLitObject %(c_name)s = %(c_string)s;
# Map the various integer types to plain int
if typ.json_type() == 'int':
- typ = self._schema.lookup_type('int')
+ type_int = self._schema.lookup_type('int')
+ assert type_int
+ typ = type_int
elif (isinstance(typ, QAPISchemaArrayType) and
typ.element_type.json_type() == 'int'):
- typ = self._schema.lookup_type('intList')
+ type_intList = self._schema.lookup_type('intList')
+ assert type_intList
+ typ = type_intList
# Add type to work queue if new
if typ not in self._used_types:
self._used_types.append(typ)
diff --git a/scripts/qapi/mypy.ini b/scripts/qapi/mypy.ini
index 56e0dfb..8109470 100644
--- a/scripts/qapi/mypy.ini
+++ b/scripts/qapi/mypy.ini
@@ -2,8 +2,3 @@
strict = True
disallow_untyped_calls = False
python_version = 3.8
-
-[mypy-qapi.schema]
-disallow_untyped_defs = False
-disallow_incomplete_defs = False
-check_untyped_defs = False
diff --git a/scripts/qapi/parser.py b/scripts/qapi/parser.py
index d8f7606..7b13a58 100644
--- a/scripts/qapi/parser.py
+++ b/scripts/qapi/parser.py
@@ -19,6 +19,7 @@ import os
import re
from typing import (
TYPE_CHECKING,
+ Any,
Dict,
List,
Mapping,
@@ -43,7 +44,7 @@ if TYPE_CHECKING:
_ExprValue = Union[List[object], Dict[str, object], str, bool]
-class QAPIExpression(Dict[str, object]):
+class QAPIExpression(Dict[str, Any]):
# pylint: disable=too-few-public-methods
def __init__(self,
data: Mapping[str, object],
@@ -607,6 +608,7 @@ class QAPIDoc:
"""
class Section:
+ # pylint: disable=too-few-public-methods
def __init__(self, info: QAPISourceInfo,
tag: Optional[str] = None):
# section source info, i.e. where it begins
@@ -705,6 +707,7 @@ class QAPIDoc:
def connect_member(self, member: 'QAPISchemaMember') -> None:
if member.name not in self.args:
+ assert member.info
if self.symbol not in member.info.pragma.documentation_exceptions:
raise QAPISemError(member.info,
"%s '%s' lacks documentation"
@@ -733,7 +736,7 @@ class QAPIDoc:
"'Returns' section is only valid for commands")
if self.errors:
raise QAPISemError(
- self.returns.info,
+ self.errors.info,
"'Errors' section is only valid for commands")
def check(self) -> None:
diff --git a/scripts/qapi/pylintrc b/scripts/qapi/pylintrc
index 90546df..c028a1f 100644
--- a/scripts/qapi/pylintrc
+++ b/scripts/qapi/pylintrc
@@ -1,10 +1,5 @@
[MASTER]
-# Add files or directories matching the regex patterns to the ignore list.
-# The regex matches against base names, not paths.
-ignore-patterns=schema.py,
-
-
[MESSAGES CONTROL]
# Disable the message, report, category or checker with the given id(s). You
@@ -16,13 +11,13 @@ ignore-patterns=schema.py,
# --enable=similarities". If you want to run only the classes checker, but have
# no Warning level messages displayed, use "--disable=all --enable=classes
# --disable=W".
-disable=fixme,
+disable=consider-using-f-string,
+ fixme,
missing-docstring,
too-many-arguments,
too-many-branches,
- too-many-statements,
too-many-instance-attributes,
- consider-using-f-string,
+ too-many-statements,
useless-option-value,
[REPORTS]
diff --git a/scripts/qapi/schema.py b/scripts/qapi/schema.py
index 8ba5665..5924947 100644
--- a/scripts/qapi/schema.py
+++ b/scripts/qapi/schema.py
@@ -12,12 +12,25 @@
# This work is licensed under the terms of the GNU GPL, version 2.
# See the COPYING file in the top-level directory.
+# pylint: disable=too-many-lines
+
# TODO catching name collisions in generated code would be nice
+from __future__ import annotations
+
+from abc import ABC, abstractmethod
from collections import OrderedDict
import os
import re
-from typing import List, Optional
+from typing import (
+ Any,
+ Callable,
+ Dict,
+ List,
+ Optional,
+ Union,
+ cast,
+)
from .common import (
POINTER_SUFFIX,
@@ -29,140 +42,230 @@ from .common import (
)
from .error import QAPIError, QAPISemError, QAPISourceError
from .expr import check_exprs
-from .parser import QAPIExpression, QAPISchemaParser
+from .parser import QAPIDoc, QAPIExpression, QAPISchemaParser
+from .source import QAPISourceInfo
class QAPISchemaIfCond:
- def __init__(self, ifcond=None):
+ def __init__(
+ self,
+ ifcond: Optional[Union[str, Dict[str, object]]] = None,
+ ) -> None:
self.ifcond = ifcond
- def _cgen(self):
+ def _cgen(self) -> str:
return cgen_ifcond(self.ifcond)
- def gen_if(self):
+ def gen_if(self) -> str:
return gen_if(self._cgen())
- def gen_endif(self):
+ def gen_endif(self) -> str:
return gen_endif(self._cgen())
- def docgen(self):
+ def docgen(self) -> str:
return docgen_ifcond(self.ifcond)
- def is_present(self):
+ def is_present(self) -> bool:
return bool(self.ifcond)
class QAPISchemaEntity:
- meta: Optional[str] = None
-
- def __init__(self, name: str, info, doc, ifcond=None, features=None):
- assert name is None or isinstance(name, str)
- for f in features or []:
- assert isinstance(f, QAPISchemaFeature)
- f.set_defined_in(name)
- self.name = name
- self._module = None
+ """
+ A schema entity.
+
+ This is either a directive, such as include, or a definition.
+ The latter uses sub-class `QAPISchemaDefinition`.
+ """
+ def __init__(self, info: Optional[QAPISourceInfo]):
+ self._module: Optional[QAPISchemaModule] = None
# For explicitly defined entities, info points to the (explicit)
# definition. For builtins (and their arrays), info is None.
# For implicitly defined entities, info points to a place that
# triggered the implicit definition (there may be more than one
# such place).
self.info = info
+ self._checked = False
+
+ def __repr__(self) -> str:
+ return "<%s at 0x%x>" % (type(self).__name__, id(self))
+
+ def check(self, schema: QAPISchema) -> None:
+ # pylint: disable=unused-argument
+ self._checked = True
+
+ def connect_doc(self, doc: Optional[QAPIDoc] = None) -> None:
+ pass
+
+ def _set_module(
+ self, schema: QAPISchema, info: Optional[QAPISourceInfo]
+ ) -> None:
+ assert self._checked
+ fname = info.fname if info else QAPISchemaModule.BUILTIN_MODULE_NAME
+ self._module = schema.module_by_fname(fname)
+ self._module.add_entity(self)
+
+ def set_module(self, schema: QAPISchema) -> None:
+ self._set_module(schema, self.info)
+
+ def visit(self, visitor: QAPISchemaVisitor) -> None:
+ # pylint: disable=unused-argument
+ assert self._checked
+
+
+class QAPISchemaDefinition(QAPISchemaEntity):
+ meta: str
+
+ def __init__(
+ self,
+ name: str,
+ info: Optional[QAPISourceInfo],
+ doc: Optional[QAPIDoc],
+ ifcond: Optional[QAPISchemaIfCond] = None,
+ features: Optional[List[QAPISchemaFeature]] = None,
+ ):
+ super().__init__(info)
+ for f in features or []:
+ f.set_defined_in(name)
+ self.name = name
self.doc = doc
self._ifcond = ifcond or QAPISchemaIfCond()
self.features = features or []
- self._checked = False
- def __repr__(self):
- if self.name is None:
- return "<%s at 0x%x>" % (type(self).__name__, id(self))
+ def __repr__(self) -> str:
return "<%s:%s at 0x%x>" % (type(self).__name__, self.name,
id(self))
- def c_name(self):
+ def c_name(self) -> str:
return c_name(self.name)
- def check(self, schema):
+ def check(self, schema: QAPISchema) -> None:
assert not self._checked
- seen = {}
+ super().check(schema)
+ seen: Dict[str, QAPISchemaMember] = {}
for f in self.features:
f.check_clash(self.info, seen)
- self._checked = True
- def connect_doc(self, doc=None):
+ def connect_doc(self, doc: Optional[QAPIDoc] = None) -> None:
+ super().connect_doc(doc)
doc = doc or self.doc
if doc:
for f in self.features:
doc.connect_feature(f)
- def _set_module(self, schema, info):
- assert self._checked
- fname = info.fname if info else QAPISchemaModule.BUILTIN_MODULE_NAME
- self._module = schema.module_by_fname(fname)
- self._module.add_entity(self)
-
- def set_module(self, schema):
- self._set_module(schema, self.info)
-
@property
- def ifcond(self):
+ def ifcond(self) -> QAPISchemaIfCond:
assert self._checked
return self._ifcond
- def is_implicit(self):
+ def is_implicit(self) -> bool:
return not self.info
- def visit(self, visitor):
- assert self._checked
-
- def describe(self):
- assert self.meta
+ def describe(self) -> str:
return "%s '%s'" % (self.meta, self.name)
class QAPISchemaVisitor:
- def visit_begin(self, schema):
+ def visit_begin(self, schema: QAPISchema) -> None:
pass
- def visit_end(self):
+ def visit_end(self) -> None:
pass
- def visit_module(self, name):
+ def visit_module(self, name: str) -> None:
pass
- def visit_needed(self, entity):
+ def visit_needed(self, entity: QAPISchemaEntity) -> bool:
+ # pylint: disable=unused-argument
# Default to visiting everything
return True
- def visit_include(self, name, info):
+ def visit_include(self, name: str, info: Optional[QAPISourceInfo]) -> None:
pass
- def visit_builtin_type(self, name, info, json_type):
+ def visit_builtin_type(
+ self, name: str, info: Optional[QAPISourceInfo], json_type: str
+ ) -> None:
pass
- def visit_enum_type(self, name, info, ifcond, features, members, prefix):
+ def visit_enum_type(
+ self,
+ name: str,
+ info: Optional[QAPISourceInfo],
+ ifcond: QAPISchemaIfCond,
+ features: List[QAPISchemaFeature],
+ members: List[QAPISchemaEnumMember],
+ prefix: Optional[str],
+ ) -> None:
pass
- def visit_array_type(self, name, info, ifcond, element_type):
+ def visit_array_type(
+ self,
+ name: str,
+ info: Optional[QAPISourceInfo],
+ ifcond: QAPISchemaIfCond,
+ element_type: QAPISchemaType,
+ ) -> None:
pass
- def visit_object_type(self, name, info, ifcond, features,
- base, members, variants):
+ def visit_object_type(
+ self,
+ name: str,
+ info: Optional[QAPISourceInfo],
+ ifcond: QAPISchemaIfCond,
+ features: List[QAPISchemaFeature],
+ base: Optional[QAPISchemaObjectType],
+ members: List[QAPISchemaObjectTypeMember],
+ variants: Optional[QAPISchemaVariants],
+ ) -> None:
pass
- def visit_object_type_flat(self, name, info, ifcond, features,
- members, variants):
+ def visit_object_type_flat(
+ self,
+ name: str,
+ info: Optional[QAPISourceInfo],
+ ifcond: QAPISchemaIfCond,
+ features: List[QAPISchemaFeature],
+ members: List[QAPISchemaObjectTypeMember],
+ variants: Optional[QAPISchemaVariants],
+ ) -> None:
pass
- def visit_alternate_type(self, name, info, ifcond, features, variants):
+ def visit_alternate_type(
+ self,
+ name: str,
+ info: Optional[QAPISourceInfo],
+ ifcond: QAPISchemaIfCond,
+ features: List[QAPISchemaFeature],
+ variants: QAPISchemaVariants,
+ ) -> None:
pass
- def visit_command(self, name, info, ifcond, features,
- arg_type, ret_type, gen, success_response, boxed,
- allow_oob, allow_preconfig, coroutine):
+ def visit_command(
+ self,
+ name: str,
+ info: Optional[QAPISourceInfo],
+ ifcond: QAPISchemaIfCond,
+ features: List[QAPISchemaFeature],
+ arg_type: Optional[QAPISchemaObjectType],
+ ret_type: Optional[QAPISchemaType],
+ gen: bool,
+ success_response: bool,
+ boxed: bool,
+ allow_oob: bool,
+ allow_preconfig: bool,
+ coroutine: bool,
+ ) -> None:
pass
- def visit_event(self, name, info, ifcond, features, arg_type, boxed):
+ def visit_event(
+ self,
+ name: str,
+ info: Optional[QAPISourceInfo],
+ ifcond: QAPISchemaIfCond,
+ features: List[QAPISchemaFeature],
+ arg_type: Optional[QAPISchemaObjectType],
+ boxed: bool,
+ ) -> None:
pass
@@ -170,9 +273,9 @@ class QAPISchemaModule:
BUILTIN_MODULE_NAME = './builtin'
- def __init__(self, name):
+ def __init__(self, name: str):
self.name = name
- self._entity_list = []
+ self._entity_list: List[QAPISchemaEntity] = []
@staticmethod
def is_system_module(name: str) -> bool:
@@ -201,10 +304,10 @@ class QAPISchemaModule:
"""
return name == cls.BUILTIN_MODULE_NAME
- def add_entity(self, ent):
+ def add_entity(self, ent: QAPISchemaEntity) -> None:
self._entity_list.append(ent)
- def visit(self, visitor):
+ def visit(self, visitor: QAPISchemaVisitor) -> None:
visitor.visit_module(self.name)
for entity in self._entity_list:
if visitor.visit_needed(entity):
@@ -212,33 +315,35 @@ class QAPISchemaModule:
class QAPISchemaInclude(QAPISchemaEntity):
- def __init__(self, sub_module, info):
- super().__init__(None, info, None)
+ def __init__(self, sub_module: QAPISchemaModule, info: QAPISourceInfo):
+ super().__init__(info)
self._sub_module = sub_module
- def visit(self, visitor):
+ def visit(self, visitor: QAPISchemaVisitor) -> None:
super().visit(visitor)
visitor.visit_include(self._sub_module.name, self.info)
-class QAPISchemaType(QAPISchemaEntity):
+class QAPISchemaType(QAPISchemaDefinition, ABC):
# Return the C type for common use.
# For the types we commonly box, this is a pointer type.
- def c_type(self):
+ @abstractmethod
+ def c_type(self) -> str:
pass
# Return the C type to be used in a parameter list.
- def c_param_type(self):
+ def c_param_type(self) -> str:
return self.c_type()
# Return the C type to be used where we suppress boxing.
- def c_unboxed_type(self):
+ def c_unboxed_type(self) -> str:
return self.c_type()
- def json_type(self):
+ @abstractmethod
+ def json_type(self) -> str:
pass
- def alternate_qtype(self):
+ def alternate_qtype(self) -> Optional[str]:
json2qtype = {
'null': 'QTYPE_QNULL',
'string': 'QTYPE_QSTRING',
@@ -250,17 +355,17 @@ class QAPISchemaType(QAPISchemaEntity):
}
return json2qtype.get(self.json_type())
- def doc_type(self):
+ def doc_type(self) -> Optional[str]:
if self.is_implicit():
return None
return self.name
- def need_has_if_optional(self):
+ def need_has_if_optional(self) -> bool:
# When FOO is a pointer, has_FOO == !!FOO, i.e. has_FOO is redundant.
# Except for arrays; see QAPISchemaArrayType.need_has_if_optional().
return not self.c_type().endswith(POINTER_SUFFIX)
- def check(self, schema):
+ def check(self, schema: QAPISchema) -> None:
super().check(schema)
for feat in self.features:
if feat.is_special():
@@ -268,40 +373,38 @@ class QAPISchemaType(QAPISchemaEntity):
self.info,
f"feature '{feat.name}' is not supported for types")
- def describe(self):
- assert self.meta
+ def describe(self) -> str:
return "%s type '%s'" % (self.meta, self.name)
class QAPISchemaBuiltinType(QAPISchemaType):
meta = 'built-in'
- def __init__(self, name, json_type, c_type):
+ def __init__(self, name: str, json_type: str, c_type: str):
super().__init__(name, None, None)
- assert not c_type or isinstance(c_type, str)
assert json_type in ('string', 'number', 'int', 'boolean', 'null',
'value')
self._json_type_name = json_type
self._c_type_name = c_type
- def c_name(self):
+ def c_name(self) -> str:
return self.name
- def c_type(self):
+ def c_type(self) -> str:
return self._c_type_name
- def c_param_type(self):
+ def c_param_type(self) -> str:
if self.name == 'str':
return 'const ' + self._c_type_name
return self._c_type_name
- def json_type(self):
+ def json_type(self) -> str:
return self._json_type_name
- def doc_type(self):
+ def doc_type(self) -> str:
return self.json_type()
- def visit(self, visitor):
+ def visit(self, visitor: QAPISchemaVisitor) -> None:
super().visit(visitor)
visitor.visit_builtin_type(self.name, self.info, self.json_type())
@@ -309,41 +412,48 @@ class QAPISchemaBuiltinType(QAPISchemaType):
class QAPISchemaEnumType(QAPISchemaType):
meta = 'enum'
- def __init__(self, name, info, doc, ifcond, features, members, prefix):
+ def __init__(
+ self,
+ name: str,
+ info: Optional[QAPISourceInfo],
+ doc: Optional[QAPIDoc],
+ ifcond: Optional[QAPISchemaIfCond],
+ features: Optional[List[QAPISchemaFeature]],
+ members: List[QAPISchemaEnumMember],
+ prefix: Optional[str],
+ ):
super().__init__(name, info, doc, ifcond, features)
for m in members:
- assert isinstance(m, QAPISchemaEnumMember)
m.set_defined_in(name)
- assert prefix is None or isinstance(prefix, str)
self.members = members
self.prefix = prefix
- def check(self, schema):
+ def check(self, schema: QAPISchema) -> None:
super().check(schema)
- seen = {}
+ seen: Dict[str, QAPISchemaMember] = {}
for m in self.members:
m.check_clash(self.info, seen)
- def connect_doc(self, doc=None):
+ def connect_doc(self, doc: Optional[QAPIDoc] = None) -> None:
super().connect_doc(doc)
doc = doc or self.doc
for m in self.members:
m.connect_doc(doc)
- def is_implicit(self):
+ def is_implicit(self) -> bool:
# See QAPISchema._def_predefineds()
return self.name == 'QType'
- def c_type(self):
+ def c_type(self) -> str:
return c_name(self.name)
- def member_names(self):
+ def member_names(self) -> List[str]:
return [m.name for m in self.members]
- def json_type(self):
+ def json_type(self) -> str:
return 'string'
- def visit(self, visitor):
+ def visit(self, visitor: QAPISchemaVisitor) -> None:
super().visit(visitor)
visitor.visit_enum_type(
self.name, self.info, self.ifcond, self.features,
@@ -353,82 +463,89 @@ class QAPISchemaEnumType(QAPISchemaType):
class QAPISchemaArrayType(QAPISchemaType):
meta = 'array'
- def __init__(self, name, info, element_type):
+ def __init__(
+ self, name: str, info: Optional[QAPISourceInfo], element_type: str
+ ):
super().__init__(name, info, None)
- assert isinstance(element_type, str)
self._element_type_name = element_type
- self.element_type = None
+ self.element_type: QAPISchemaType
- def need_has_if_optional(self):
+ def need_has_if_optional(self) -> bool:
# When FOO is an array, we still need has_FOO to distinguish
# absent (!has_FOO) from present and empty (has_FOO && !FOO).
return True
- def check(self, schema):
+ def check(self, schema: QAPISchema) -> None:
super().check(schema)
self.element_type = schema.resolve_type(
self._element_type_name, self.info,
- self.info and self.info.defn_meta)
+ self.info.defn_meta if self.info else None)
assert not isinstance(self.element_type, QAPISchemaArrayType)
- def set_module(self, schema):
+ def set_module(self, schema: QAPISchema) -> None:
self._set_module(schema, self.element_type.info)
@property
- def ifcond(self):
+ def ifcond(self) -> QAPISchemaIfCond:
assert self._checked
return self.element_type.ifcond
- def is_implicit(self):
+ def is_implicit(self) -> bool:
return True
- def c_type(self):
+ def c_type(self) -> str:
return c_name(self.name) + POINTER_SUFFIX
- def json_type(self):
+ def json_type(self) -> str:
return 'array'
- def doc_type(self):
+ def doc_type(self) -> Optional[str]:
elt_doc_type = self.element_type.doc_type()
if not elt_doc_type:
return None
return 'array of ' + elt_doc_type
- def visit(self, visitor):
+ def visit(self, visitor: QAPISchemaVisitor) -> None:
super().visit(visitor)
visitor.visit_array_type(self.name, self.info, self.ifcond,
self.element_type)
- def describe(self):
- assert self.meta
+ def describe(self) -> str:
return "%s type ['%s']" % (self.meta, self._element_type_name)
class QAPISchemaObjectType(QAPISchemaType):
- def __init__(self, name, info, doc, ifcond, features,
- base, local_members, variants):
+ def __init__(
+ self,
+ name: str,
+ info: Optional[QAPISourceInfo],
+ doc: Optional[QAPIDoc],
+ ifcond: Optional[QAPISchemaIfCond],
+ features: Optional[List[QAPISchemaFeature]],
+ base: Optional[str],
+ local_members: List[QAPISchemaObjectTypeMember],
+ variants: Optional[QAPISchemaVariants],
+ ):
# struct has local_members, optional base, and no variants
# union has base, variants, and no local_members
super().__init__(name, info, doc, ifcond, features)
self.meta = 'union' if variants else 'struct'
- assert base is None or isinstance(base, str)
for m in local_members:
- assert isinstance(m, QAPISchemaObjectTypeMember)
m.set_defined_in(name)
if variants is not None:
- assert isinstance(variants, QAPISchemaVariants)
variants.set_defined_in(name)
self._base_name = base
self.base = None
self.local_members = local_members
self.variants = variants
- self.members = None
+ self.members: List[QAPISchemaObjectTypeMember]
+ self._check_complete = False
- def check(self, schema):
+ def check(self, schema: QAPISchema) -> None:
# This calls another type T's .check() exactly when the C
# struct emitted by gen_object() contains that T's C struct
# (pointers don't count).
- if self.members is not None:
+ if self._check_complete:
# A previous .check() completed: nothing to do
return
if self._checked:
@@ -437,7 +554,7 @@ class QAPISchemaObjectType(QAPISchemaType):
"object %s contains itself" % self.name)
super().check(schema)
- assert self._checked and self.members is None
+ assert self._checked and not self._check_complete
seen = OrderedDict()
if self._base_name:
@@ -454,25 +571,34 @@ class QAPISchemaObjectType(QAPISchemaType):
for m in self.local_members:
m.check(schema)
m.check_clash(self.info, seen)
- members = seen.values()
+
+ # self.check_clash() works in terms of the supertype, but
+ # self.members is declared List[QAPISchemaObjectTypeMember].
+ # Cast down to the subtype.
+ members = cast(List[QAPISchemaObjectTypeMember], list(seen.values()))
if self.variants:
self.variants.check(schema, seen)
self.variants.check_clash(self.info, seen)
- self.members = members # mark completed
+ self.members = members
+ self._check_complete = True # mark completed
# Check that the members of this type do not cause duplicate JSON members,
# and update seen to track the members seen so far. Report any errors
# on behalf of info, which is not necessarily self.info
- def check_clash(self, info, seen):
+ def check_clash(
+ self,
+ info: Optional[QAPISourceInfo],
+ seen: Dict[str, QAPISchemaMember],
+ ) -> None:
assert self._checked
for m in self.members:
m.check_clash(info, seen)
if self.variants:
self.variants.check_clash(info, seen)
- def connect_doc(self, doc=None):
+ def connect_doc(self, doc: Optional[QAPIDoc] = None) -> None:
super().connect_doc(doc)
doc = doc or self.doc
if self.base and self.base.is_implicit():
@@ -480,34 +606,32 @@ class QAPISchemaObjectType(QAPISchemaType):
for m in self.local_members:
m.connect_doc(doc)
- def is_implicit(self):
+ def is_implicit(self) -> bool:
# See QAPISchema._make_implicit_object_type(), as well as
# _def_predefineds()
return self.name.startswith('q_')
- def is_empty(self):
- assert self.members is not None
+ def is_empty(self) -> bool:
return not self.members and not self.variants
- def has_conditional_members(self):
- assert self.members is not None
+ def has_conditional_members(self) -> bool:
return any(m.ifcond.is_present() for m in self.members)
- def c_name(self):
+ def c_name(self) -> str:
assert self.name != 'q_empty'
return super().c_name()
- def c_type(self):
+ def c_type(self) -> str:
assert not self.is_implicit()
return c_name(self.name) + POINTER_SUFFIX
- def c_unboxed_type(self):
+ def c_unboxed_type(self) -> str:
return c_name(self.name)
- def json_type(self):
+ def json_type(self) -> str:
return 'object'
- def visit(self, visitor):
+ def visit(self, visitor: QAPISchemaVisitor) -> None:
super().visit(visitor)
visitor.visit_object_type(
self.name, self.info, self.ifcond, self.features,
@@ -520,15 +644,22 @@ class QAPISchemaObjectType(QAPISchemaType):
class QAPISchemaAlternateType(QAPISchemaType):
meta = 'alternate'
- def __init__(self, name, info, doc, ifcond, features, variants):
+ def __init__(
+ self,
+ name: str,
+ info: QAPISourceInfo,
+ doc: Optional[QAPIDoc],
+ ifcond: Optional[QAPISchemaIfCond],
+ features: List[QAPISchemaFeature],
+ variants: QAPISchemaVariants,
+ ):
super().__init__(name, info, doc, ifcond, features)
- assert isinstance(variants, QAPISchemaVariants)
assert variants.tag_member
variants.set_defined_in(name)
variants.tag_member.set_defined_in(self.name)
self.variants = variants
- def check(self, schema):
+ def check(self, schema: QAPISchema) -> None:
super().check(schema)
self.variants.tag_member.check(schema)
# Not calling self.variants.check_clash(), because there's nothing
@@ -536,8 +667,8 @@ class QAPISchemaAlternateType(QAPISchemaType):
self.variants.check(schema, {})
# Alternate branch names have no relation to the tag enum values;
# so we have to check for potential name collisions ourselves.
- seen = {}
- types_seen = {}
+ seen: Dict[str, QAPISchemaMember] = {}
+ types_seen: Dict[str, str] = {}
for v in self.variants.variants:
v.check_clash(self.info, seen)
qtype = v.type.alternate_qtype()
@@ -566,55 +697,75 @@ class QAPISchemaAlternateType(QAPISchemaType):
% (v.describe(self.info), types_seen[qt]))
types_seen[qt] = v.name
- def connect_doc(self, doc=None):
+ def connect_doc(self, doc: Optional[QAPIDoc] = None) -> None:
super().connect_doc(doc)
doc = doc or self.doc
for v in self.variants.variants:
v.connect_doc(doc)
- def c_type(self):
+ def c_type(self) -> str:
return c_name(self.name) + POINTER_SUFFIX
- def json_type(self):
+ def json_type(self) -> str:
return 'value'
- def visit(self, visitor):
+ def visit(self, visitor: QAPISchemaVisitor) -> None:
super().visit(visitor)
visitor.visit_alternate_type(
self.name, self.info, self.ifcond, self.features, self.variants)
class QAPISchemaVariants:
- def __init__(self, tag_name, info, tag_member, variants):
+ def __init__(
+ self,
+ tag_name: Optional[str],
+ info: QAPISourceInfo,
+ tag_member: Optional[QAPISchemaObjectTypeMember],
+ variants: List[QAPISchemaVariant],
+ ):
# Unions pass tag_name but not tag_member.
# Alternates pass tag_member but not tag_name.
# After check(), tag_member is always set.
assert bool(tag_member) != bool(tag_name)
assert (isinstance(tag_name, str) or
isinstance(tag_member, QAPISchemaObjectTypeMember))
- for v in variants:
- assert isinstance(v, QAPISchemaVariant)
self._tag_name = tag_name
self.info = info
- self.tag_member = tag_member
+ self._tag_member = tag_member
self.variants = variants
- def set_defined_in(self, name):
+ @property
+ def tag_member(self) -> QAPISchemaObjectTypeMember:
+ if self._tag_member is None:
+ raise RuntimeError(
+ "QAPISchemaVariants has no tag_member property until "
+ "after check() has been run."
+ )
+ return self._tag_member
+
+ def set_defined_in(self, name: str) -> None:
for v in self.variants:
v.set_defined_in(name)
- def check(self, schema, seen):
+ def check(
+ self, schema: QAPISchema, seen: Dict[str, QAPISchemaMember]
+ ) -> None:
if self._tag_name: # union
- self.tag_member = seen.get(c_name(self._tag_name))
+ # We need to narrow the member type:
+ tmp = seen.get(c_name(self._tag_name))
+ assert tmp is None or isinstance(tmp, QAPISchemaObjectTypeMember)
+ self._tag_member = tmp
+
base = "'base'"
# Pointing to the base type when not implicit would be
# nice, but we don't know it here
- if not self.tag_member or self._tag_name != self.tag_member.name:
+ if not self._tag_member or self._tag_name != self._tag_member.name:
raise QAPISemError(
self.info,
"discriminator '%s' is not a member of %s"
% (self._tag_name, base))
# Here we do:
+ assert self.tag_member.defined_in
base_type = schema.lookup_type(self.tag_member.defined_in)
assert base_type
if not base_type.is_implicit():
@@ -635,11 +786,13 @@ class QAPISchemaVariants:
"discriminator member '%s' of %s must not be conditional"
% (self._tag_name, base))
else: # alternate
+ assert self._tag_member
assert isinstance(self.tag_member.type, QAPISchemaEnumType)
assert not self.tag_member.optional
assert not self.tag_member.ifcond.is_present()
if self._tag_name: # union
# branches that are not explicitly covered get an empty type
+ assert self.tag_member.defined_in
cases = {v.name for v in self.variants}
for m in self.tag_member.type.members:
if m.name not in cases:
@@ -666,10 +819,17 @@ class QAPISchemaVariants:
% (v.describe(self.info), v.type.describe()))
v.type.check(schema)
- def check_clash(self, info, seen):
+ def check_clash(
+ self,
+ info: Optional[QAPISourceInfo],
+ seen: Dict[str, QAPISchemaMember],
+ ) -> None:
for v in self.variants:
# Reset seen map for each variant, since qapi names from one
- # branch do not affect another branch
+ # branch do not affect another branch.
+ #
+ # v.type's typing is enforced in check() above.
+ assert isinstance(v.type, QAPISchemaObjectType)
v.type.check_clash(info, dict(seen))
@@ -677,18 +837,26 @@ class QAPISchemaMember:
""" Represents object members, enum members and features """
role = 'member'
- def __init__(self, name, info, ifcond=None):
- assert isinstance(name, str)
+ def __init__(
+ self,
+ name: str,
+ info: Optional[QAPISourceInfo],
+ ifcond: Optional[QAPISchemaIfCond] = None,
+ ):
self.name = name
self.info = info
self.ifcond = ifcond or QAPISchemaIfCond()
- self.defined_in = None
+ self.defined_in: Optional[str] = None
- def set_defined_in(self, name):
+ def set_defined_in(self, name: str) -> None:
assert not self.defined_in
self.defined_in = name
- def check_clash(self, info, seen):
+ def check_clash(
+ self,
+ info: Optional[QAPISourceInfo],
+ seen: Dict[str, QAPISchemaMember],
+ ) -> None:
cname = c_name(self.name)
if cname in seen:
raise QAPISemError(
@@ -697,11 +865,11 @@ class QAPISchemaMember:
% (self.describe(info), seen[cname].describe(info)))
seen[cname] = self
- def connect_doc(self, doc):
+ def connect_doc(self, doc: Optional[QAPIDoc]) -> None:
if doc:
doc.connect_member(self)
- def describe(self, info):
+ def describe(self, info: Optional[QAPISourceInfo]) -> str:
role = self.role
meta = 'type'
defined_in = self.defined_in
@@ -724,6 +892,7 @@ class QAPISchemaMember:
else:
assert False
+ assert info is not None
if defined_in != info.defn_name:
return "%s '%s' of %s '%s'" % (role, self.name, meta, defined_in)
return "%s '%s'" % (role, self.name)
@@ -732,14 +901,19 @@ class QAPISchemaMember:
class QAPISchemaEnumMember(QAPISchemaMember):
role = 'value'
- def __init__(self, name, info, ifcond=None, features=None):
+ def __init__(
+ self,
+ name: str,
+ info: Optional[QAPISourceInfo],
+ ifcond: Optional[QAPISchemaIfCond] = None,
+ features: Optional[List[QAPISchemaFeature]] = None,
+ ):
super().__init__(name, info, ifcond)
for f in features or []:
- assert isinstance(f, QAPISchemaFeature)
f.set_defined_in(name)
self.features = features or []
- def connect_doc(self, doc):
+ def connect_doc(self, doc: Optional[QAPIDoc]) -> None:
super().connect_doc(doc)
if doc:
for f in self.features:
@@ -749,36 +923,40 @@ class QAPISchemaEnumMember(QAPISchemaMember):
class QAPISchemaFeature(QAPISchemaMember):
role = 'feature'
- def is_special(self):
+ def is_special(self) -> bool:
return self.name in ('deprecated', 'unstable')
class QAPISchemaObjectTypeMember(QAPISchemaMember):
- def __init__(self, name, info, typ, optional, ifcond=None, features=None):
+ def __init__(
+ self,
+ name: str,
+ info: QAPISourceInfo,
+ typ: str,
+ optional: bool,
+ ifcond: Optional[QAPISchemaIfCond] = None,
+ features: Optional[List[QAPISchemaFeature]] = None,
+ ):
super().__init__(name, info, ifcond)
- assert isinstance(typ, str)
- assert isinstance(optional, bool)
for f in features or []:
- assert isinstance(f, QAPISchemaFeature)
f.set_defined_in(name)
self._type_name = typ
- self.type = None
+ self.type: QAPISchemaType # set during check()
self.optional = optional
self.features = features or []
- def need_has(self):
- assert self.type
+ def need_has(self) -> bool:
return self.optional and self.type.need_has_if_optional()
- def check(self, schema):
+ def check(self, schema: QAPISchema) -> None:
assert self.defined_in
self.type = schema.resolve_type(self._type_name, self.info,
self.describe)
- seen = {}
+ seen: Dict[str, QAPISchemaMember] = {}
for f in self.features:
f.check_clash(self.info, seen)
- def connect_doc(self, doc):
+ def connect_doc(self, doc: Optional[QAPIDoc]) -> None:
super().connect_doc(doc)
if doc:
for f in self.features:
@@ -788,24 +966,40 @@ class QAPISchemaObjectTypeMember(QAPISchemaMember):
class QAPISchemaVariant(QAPISchemaObjectTypeMember):
role = 'branch'
- def __init__(self, name, info, typ, ifcond=None):
+ def __init__(
+ self,
+ name: str,
+ info: QAPISourceInfo,
+ typ: str,
+ ifcond: QAPISchemaIfCond,
+ ):
super().__init__(name, info, typ, False, ifcond)
-class QAPISchemaCommand(QAPISchemaEntity):
+class QAPISchemaCommand(QAPISchemaDefinition):
meta = 'command'
- def __init__(self, name, info, doc, ifcond, features,
- arg_type, ret_type,
- gen, success_response, boxed, allow_oob, allow_preconfig,
- coroutine):
+ def __init__(
+ self,
+ name: str,
+ info: QAPISourceInfo,
+ doc: Optional[QAPIDoc],
+ ifcond: QAPISchemaIfCond,
+ features: List[QAPISchemaFeature],
+ arg_type: Optional[str],
+ ret_type: Optional[str],
+ gen: bool,
+ success_response: bool,
+ boxed: bool,
+ allow_oob: bool,
+ allow_preconfig: bool,
+ coroutine: bool,
+ ):
super().__init__(name, info, doc, ifcond, features)
- assert not arg_type or isinstance(arg_type, str)
- assert not ret_type or isinstance(ret_type, str)
self._arg_type_name = arg_type
- self.arg_type = None
+ self.arg_type: Optional[QAPISchemaObjectType] = None
self._ret_type_name = ret_type
- self.ret_type = None
+ self.ret_type: Optional[QAPISchemaType] = None
self.gen = gen
self.success_response = success_response
self.boxed = boxed
@@ -813,16 +1007,18 @@ class QAPISchemaCommand(QAPISchemaEntity):
self.allow_preconfig = allow_preconfig
self.coroutine = coroutine
- def check(self, schema):
+ def check(self, schema: QAPISchema) -> None:
+ assert self.info is not None
super().check(schema)
if self._arg_type_name:
- self.arg_type = schema.resolve_type(
+ arg_type = schema.resolve_type(
self._arg_type_name, self.info, "command's 'data'")
- if not isinstance(self.arg_type, QAPISchemaObjectType):
+ if not isinstance(arg_type, QAPISchemaObjectType):
raise QAPISemError(
self.info,
"command's 'data' cannot take %s"
- % self.arg_type.describe())
+ % arg_type.describe())
+ self.arg_type = arg_type
if self.arg_type.variants and not self.boxed:
raise QAPISemError(
self.info,
@@ -839,22 +1035,21 @@ class QAPISchemaCommand(QAPISchemaEntity):
if self.name not in self.info.pragma.command_returns_exceptions:
typ = self.ret_type
if isinstance(typ, QAPISchemaArrayType):
- typ = self.ret_type.element_type
- assert typ
+ typ = typ.element_type
if not isinstance(typ, QAPISchemaObjectType):
raise QAPISemError(
self.info,
"command's 'returns' cannot take %s"
% self.ret_type.describe())
- def connect_doc(self, doc=None):
+ def connect_doc(self, doc: Optional[QAPIDoc] = None) -> None:
super().connect_doc(doc)
doc = doc or self.doc
if doc:
if self.arg_type and self.arg_type.is_implicit():
self.arg_type.connect_doc(doc)
- def visit(self, visitor):
+ def visit(self, visitor: QAPISchemaVisitor) -> None:
super().visit(visitor)
visitor.visit_command(
self.name, self.info, self.ifcond, self.features,
@@ -863,26 +1058,35 @@ class QAPISchemaCommand(QAPISchemaEntity):
self.coroutine)
-class QAPISchemaEvent(QAPISchemaEntity):
+class QAPISchemaEvent(QAPISchemaDefinition):
meta = 'event'
- def __init__(self, name, info, doc, ifcond, features, arg_type, boxed):
+ def __init__(
+ self,
+ name: str,
+ info: QAPISourceInfo,
+ doc: Optional[QAPIDoc],
+ ifcond: QAPISchemaIfCond,
+ features: List[QAPISchemaFeature],
+ arg_type: Optional[str],
+ boxed: bool,
+ ):
super().__init__(name, info, doc, ifcond, features)
- assert not arg_type or isinstance(arg_type, str)
self._arg_type_name = arg_type
- self.arg_type = None
+ self.arg_type: Optional[QAPISchemaObjectType] = None
self.boxed = boxed
- def check(self, schema):
+ def check(self, schema: QAPISchema) -> None:
super().check(schema)
if self._arg_type_name:
- self.arg_type = schema.resolve_type(
+ typ = schema.resolve_type(
self._arg_type_name, self.info, "event's 'data'")
- if not isinstance(self.arg_type, QAPISchemaObjectType):
+ if not isinstance(typ, QAPISchemaObjectType):
raise QAPISemError(
self.info,
"event's 'data' cannot take %s"
- % self.arg_type.describe())
+ % typ.describe())
+ self.arg_type = typ
if self.arg_type.variants and not self.boxed:
raise QAPISemError(
self.info,
@@ -894,14 +1098,14 @@ class QAPISchemaEvent(QAPISchemaEntity):
self.info,
"conditional event arguments require 'boxed': true")
- def connect_doc(self, doc=None):
+ def connect_doc(self, doc: Optional[QAPIDoc] = None) -> None:
super().connect_doc(doc)
doc = doc or self.doc
if doc:
if self.arg_type and self.arg_type.is_implicit():
self.arg_type.connect_doc(doc)
- def visit(self, visitor):
+ def visit(self, visitor: QAPISchemaVisitor) -> None:
super().visit(visitor)
visitor.visit_event(
self.name, self.info, self.ifcond, self.features,
@@ -909,7 +1113,7 @@ class QAPISchemaEvent(QAPISchemaEntity):
class QAPISchema:
- def __init__(self, fname):
+ def __init__(self, fname: str):
self.fname = fname
try:
@@ -921,9 +1125,9 @@ class QAPISchema:
exprs = check_exprs(parser.exprs)
self.docs = parser.docs
- self._entity_list = []
- self._entity_dict = {}
- self._module_dict = OrderedDict()
+ self._entity_list: List[QAPISchemaEntity] = []
+ self._entity_dict: Dict[str, QAPISchemaDefinition] = {}
+ self._module_dict: Dict[str, QAPISchemaModule] = OrderedDict()
self._schema_dir = os.path.dirname(fname)
self._make_module(QAPISchemaModule.BUILTIN_MODULE_NAME)
self._make_module(fname)
@@ -933,37 +1137,44 @@ class QAPISchema:
self._def_exprs(exprs)
self.check()
- def _def_entity(self, ent):
- # Only the predefined types are allowed to not have info
- assert ent.info or self._predefining
+ def _def_entity(self, ent: QAPISchemaEntity) -> None:
self._entity_list.append(ent)
- if ent.name is None:
- return
+
+ def _def_definition(self, defn: QAPISchemaDefinition) -> None:
+ # Only the predefined types are allowed to not have info
+ assert defn.info or self._predefining
+ self._def_entity(defn)
# TODO reject names that differ only in '_' vs. '.' vs. '-',
# because they're liable to clash in generated C.
- other_ent = self._entity_dict.get(ent.name)
- if other_ent:
- if other_ent.info:
- where = QAPISourceError(other_ent.info, "previous definition")
+ other_defn = self._entity_dict.get(defn.name)
+ if other_defn:
+ if other_defn.info:
+ where = QAPISourceError(other_defn.info, "previous definition")
raise QAPISemError(
- ent.info,
- "'%s' is already defined\n%s" % (ent.name, where))
+ defn.info,
+ "'%s' is already defined\n%s" % (defn.name, where))
raise QAPISemError(
- ent.info, "%s is already defined" % other_ent.describe())
- self._entity_dict[ent.name] = ent
-
- def lookup_entity(self, name, typ=None):
- ent = self._entity_dict.get(name)
- if typ and not isinstance(ent, typ):
- return None
- return ent
-
- def lookup_type(self, name):
- return self.lookup_entity(name, QAPISchemaType)
-
- def resolve_type(self, name, info, what):
+ defn.info, "%s is already defined" % other_defn.describe())
+ self._entity_dict[defn.name] = defn
+
+ def lookup_entity(self,name: str) -> Optional[QAPISchemaEntity]:
+ return self._entity_dict.get(name)
+
+ def lookup_type(self, name: str) -> Optional[QAPISchemaType]:
+ typ = self.lookup_entity(name)
+ if isinstance(typ, QAPISchemaType):
+ return typ
+ return None
+
+ def resolve_type(
+ self,
+ name: str,
+ info: Optional[QAPISourceInfo],
+ what: Union[None, str, Callable[[QAPISourceInfo], str]],
+ ) -> QAPISchemaType:
typ = self.lookup_type(name)
if not typ:
+ assert info and what # built-in types must not fail lookup
if callable(what):
what = what(info)
raise QAPISemError(
@@ -975,31 +1186,33 @@ class QAPISchema:
return fname
return os.path.relpath(fname, self._schema_dir)
- def _make_module(self, fname):
+ def _make_module(self, fname: str) -> QAPISchemaModule:
name = self._module_name(fname)
if name not in self._module_dict:
self._module_dict[name] = QAPISchemaModule(name)
return self._module_dict[name]
- def module_by_fname(self, fname):
+ def module_by_fname(self, fname: str) -> QAPISchemaModule:
name = self._module_name(fname)
return self._module_dict[name]
- def _def_include(self, expr: QAPIExpression):
+ def _def_include(self, expr: QAPIExpression) -> None:
include = expr['include']
assert expr.doc is None
self._def_entity(
QAPISchemaInclude(self._make_module(include), expr.info))
- def _def_builtin_type(self, name, json_type, c_type):
- self._def_entity(QAPISchemaBuiltinType(name, json_type, c_type))
+ def _def_builtin_type(
+ self, name: str, json_type: str, c_type: str
+ ) -> None:
+ self._def_definition(QAPISchemaBuiltinType(name, json_type, c_type))
# Instantiating only the arrays that are actually used would
# be nice, but we can't as long as their generated code
# (qapi-builtin-types.[ch]) may be shared by some other
# schema.
self._make_array_type(name, None)
- def _def_predefineds(self):
+ def _def_predefineds(self) -> None:
for t in [('str', 'string', 'char' + POINTER_SUFFIX),
('number', 'number', 'double'),
('int', 'int', 'int64_t'),
@@ -1018,67 +1231,97 @@ class QAPISchema:
self._def_builtin_type(*t)
self.the_empty_object_type = QAPISchemaObjectType(
'q_empty', None, None, None, None, None, [], None)
- self._def_entity(self.the_empty_object_type)
+ self._def_definition(self.the_empty_object_type)
qtypes = ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist',
'qbool']
qtype_values = self._make_enum_members(
[{'name': n} for n in qtypes], None)
- self._def_entity(QAPISchemaEnumType('QType', None, None, None, None,
- qtype_values, 'QTYPE'))
+ self._def_definition(QAPISchemaEnumType(
+ 'QType', None, None, None, None, qtype_values, 'QTYPE'))
- def _make_features(self, features, info):
+ def _make_features(
+ self,
+ features: Optional[List[Dict[str, Any]]],
+ info: Optional[QAPISourceInfo],
+ ) -> List[QAPISchemaFeature]:
if features is None:
return []
return [QAPISchemaFeature(f['name'], info,
QAPISchemaIfCond(f.get('if')))
for f in features]
- def _make_enum_member(self, name, ifcond, features, info):
+ def _make_enum_member(
+ self,
+ name: str,
+ ifcond: Optional[Union[str, Dict[str, Any]]],
+ features: Optional[List[Dict[str, Any]]],
+ info: Optional[QAPISourceInfo],
+ ) -> QAPISchemaEnumMember:
return QAPISchemaEnumMember(name, info,
QAPISchemaIfCond(ifcond),
self._make_features(features, info))
- def _make_enum_members(self, values, info):
+ def _make_enum_members(
+ self, values: List[Dict[str, Any]], info: Optional[QAPISourceInfo]
+ ) -> List[QAPISchemaEnumMember]:
return [self._make_enum_member(v['name'], v.get('if'),
v.get('features'), info)
for v in values]
- def _make_array_type(self, element_type, info):
+ def _make_array_type(
+ self, element_type: str, info: Optional[QAPISourceInfo]
+ ) -> str:
name = element_type + 'List' # reserved by check_defn_name_str()
if not self.lookup_type(name):
- self._def_entity(QAPISchemaArrayType(name, info, element_type))
+ self._def_definition(QAPISchemaArrayType(
+ name, info, element_type))
return name
- def _make_implicit_object_type(self, name, info, ifcond, role, members):
+ def _make_implicit_object_type(
+ self,
+ name: str,
+ info: QAPISourceInfo,
+ ifcond: QAPISchemaIfCond,
+ role: str,
+ members: List[QAPISchemaObjectTypeMember],
+ ) -> Optional[str]:
if not members:
return None
# See also QAPISchemaObjectTypeMember.describe()
name = 'q_obj_%s-%s' % (name, role)
- typ = self.lookup_entity(name, QAPISchemaObjectType)
+ typ = self.lookup_entity(name)
if typ:
+ assert(isinstance(typ, QAPISchemaObjectType))
# The implicit object type has multiple users. This can
# only be a duplicate definition, which will be flagged
# later.
pass
else:
- self._def_entity(QAPISchemaObjectType(
+ self._def_definition(QAPISchemaObjectType(
name, info, None, ifcond, None, None, members, None))
return name
- def _def_enum_type(self, expr: QAPIExpression):
+ def _def_enum_type(self, expr: QAPIExpression) -> None:
name = expr['enum']
data = expr['data']
prefix = expr.get('prefix')
ifcond = QAPISchemaIfCond(expr.get('if'))
info = expr.info
features = self._make_features(expr.get('features'), info)
- self._def_entity(QAPISchemaEnumType(
+ self._def_definition(QAPISchemaEnumType(
name, info, expr.doc, ifcond, features,
self._make_enum_members(data, info), prefix))
- def _make_member(self, name, typ, ifcond, features, info):
+ def _make_member(
+ self,
+ name: str,
+ typ: Union[List[str], str],
+ ifcond: QAPISchemaIfCond,
+ features: Optional[List[Dict[str, Any]]],
+ info: QAPISourceInfo,
+ ) -> QAPISchemaObjectTypeMember:
optional = False
if name.startswith('*'):
name = name[1:]
@@ -1089,31 +1332,41 @@ class QAPISchema:
return QAPISchemaObjectTypeMember(name, info, typ, optional, ifcond,
self._make_features(features, info))
- def _make_members(self, data, info):
+ def _make_members(
+ self,
+ data: Dict[str, Any],
+ info: QAPISourceInfo,
+ ) -> List[QAPISchemaObjectTypeMember]:
return [self._make_member(key, value['type'],
QAPISchemaIfCond(value.get('if')),
value.get('features'), info)
for (key, value) in data.items()]
- def _def_struct_type(self, expr: QAPIExpression):
+ def _def_struct_type(self, expr: QAPIExpression) -> None:
name = expr['struct']
base = expr.get('base')
data = expr['data']
info = expr.info
ifcond = QAPISchemaIfCond(expr.get('if'))
features = self._make_features(expr.get('features'), info)
- self._def_entity(QAPISchemaObjectType(
+ self._def_definition(QAPISchemaObjectType(
name, info, expr.doc, ifcond, features, base,
self._make_members(data, info),
None))
- def _make_variant(self, case, typ, ifcond, info):
+ def _make_variant(
+ self,
+ case: str,
+ typ: str,
+ ifcond: QAPISchemaIfCond,
+ info: QAPISourceInfo,
+ ) -> QAPISchemaVariant:
if isinstance(typ, list):
assert len(typ) == 1
typ = self._make_array_type(typ[0], info)
return QAPISchemaVariant(case, info, typ, ifcond)
- def _def_union_type(self, expr: QAPIExpression):
+ def _def_union_type(self, expr: QAPIExpression) -> None:
name = expr['union']
base = expr['base']
tag_name = expr['discriminator']
@@ -1132,13 +1385,13 @@ class QAPISchema:
info)
for (key, value) in data.items()]
members: List[QAPISchemaObjectTypeMember] = []
- self._def_entity(
+ self._def_definition(
QAPISchemaObjectType(name, info, expr.doc, ifcond, features,
base, members,
QAPISchemaVariants(
tag_name, info, None, variants)))
- def _def_alternate_type(self, expr: QAPIExpression):
+ def _def_alternate_type(self, expr: QAPIExpression) -> None:
name = expr['alternate']
data = expr['data']
assert isinstance(data, dict)
@@ -1151,12 +1404,12 @@ class QAPISchema:
info)
for (key, value) in data.items()]
tag_member = QAPISchemaObjectTypeMember('type', info, 'QType', False)
- self._def_entity(
+ self._def_definition(
QAPISchemaAlternateType(
name, info, expr.doc, ifcond, features,
QAPISchemaVariants(None, info, tag_member, variants)))
- def _def_command(self, expr: QAPIExpression):
+ def _def_command(self, expr: QAPIExpression) -> None:
name = expr['command']
data = expr.get('data')
rets = expr.get('returns')
@@ -1176,13 +1429,12 @@ class QAPISchema:
if isinstance(rets, list):
assert len(rets) == 1
rets = self._make_array_type(rets[0], info)
- self._def_entity(QAPISchemaCommand(name, info, expr.doc, ifcond,
- features, data, rets,
- gen, success_response,
- boxed, allow_oob, allow_preconfig,
- coroutine))
+ self._def_definition(
+ QAPISchemaCommand(name, info, expr.doc, ifcond, features, data,
+ rets, gen, success_response, boxed, allow_oob,
+ allow_preconfig, coroutine))
- def _def_event(self, expr: QAPIExpression):
+ def _def_event(self, expr: QAPIExpression) -> None:
name = expr['event']
data = expr.get('data')
boxed = expr.get('boxed', False)
@@ -1193,10 +1445,10 @@ class QAPISchema:
data = self._make_implicit_object_type(
name, info, ifcond,
'arg', self._make_members(data, info))
- self._def_entity(QAPISchemaEvent(name, info, expr.doc, ifcond,
- features, data, boxed))
+ self._def_definition(QAPISchemaEvent(name, info, expr.doc, ifcond,
+ features, data, boxed))
- def _def_exprs(self, exprs):
+ def _def_exprs(self, exprs: List[QAPIExpression]) -> None:
for expr in exprs:
if 'enum' in expr:
self._def_enum_type(expr)
@@ -1215,7 +1467,7 @@ class QAPISchema:
else:
assert False
- def check(self):
+ def check(self) -> None:
for ent in self._entity_list:
ent.check(self)
ent.connect_doc()
@@ -1224,7 +1476,7 @@ class QAPISchema:
for doc in self.docs:
doc.check()
- def visit(self, visitor):
+ def visit(self, visitor: QAPISchemaVisitor) -> None:
visitor.visit_begin(self)
for mod in self._module_dict.values():
mod.visit(visitor)