QAPI patches patches for 2023-02-23
-----BEGIN PGP SIGNATURE----- iQJGBAABCAAwFiEENUvIs9frKmtoZ05fOHC0AOuRhlMFAmP3VikSHGFybWJydUBy ZWRoYXQuY29tAAoJEDhwtADrkYZTf98P/1tf2tPnWL0QpGXqGOq/iy2cFhcoco06 30t4JzTZGMZv8aUBRzlnhNgp+C7uMnXxuO7DeVN/K8VCvRfGXYz1HYFJ0NWhhMz6 RULvVncJ7m9vFykmu3iibxvjyH6uj0R5xJ8ZNIrySLTCu+58voDF/IbZ0ep3v5nX 1AV1ljL9taxg2SrQ53Whbet9zfgXVFnV5wLKkLOqLGvviO2OBPG7rrtQaEX2jrsa SdTiOdBk1IMvG3FT6cVx3bM3kQd15UwfcJsdIYpB7QBZNoqgiyfMPsNr8HzpZlJn KOe3qWVFWHGMWY4MtQ1j9Ph44RPrJybvPQRMDNB3CiDYEtBWsth0fZxhw9T/tKca 5KgJaxecB3UsXFUBWhmvhkw+hwG+cDWHtiYZSb9AX4cqvPid1UdLnSQFWgHFGX+2 ok0Q7gy9jYEpteVbIM8kQG0TF7xnZlv99uDK8b4MAH33roXwy70vffxpRGnngNyH IcLvzmDqRlrlzdvUi8Uro22VmUAUqSQKxKYt9yBJcEUV9NLi8E6g+Hcrvt7YNF9V jcVub4aIawEZCvnPCpOgzHD9p26ofwb2WQ245/5kzMUVi2pBYsHH6hJj7WdMPixS r24Ykgo4sxujW4pVy45lXzpA8uKWELCp9iKUOO6hvdoJEybVDMj9zcVn70cJgDrE RUle5av0n8XR =XV0D -----END PGP SIGNATURE----- Merge tag 'pull-qapi-2023-02-23' of https://repo.or.cz/qemu/armbru into staging QAPI patches patches for 2023-02-23 # -----BEGIN PGP SIGNATURE----- # # iQJGBAABCAAwFiEENUvIs9frKmtoZ05fOHC0AOuRhlMFAmP3VikSHGFybWJydUBy # ZWRoYXQuY29tAAoJEDhwtADrkYZTf98P/1tf2tPnWL0QpGXqGOq/iy2cFhcoco06 # 30t4JzTZGMZv8aUBRzlnhNgp+C7uMnXxuO7DeVN/K8VCvRfGXYz1HYFJ0NWhhMz6 # RULvVncJ7m9vFykmu3iibxvjyH6uj0R5xJ8ZNIrySLTCu+58voDF/IbZ0ep3v5nX # 1AV1ljL9taxg2SrQ53Whbet9zfgXVFnV5wLKkLOqLGvviO2OBPG7rrtQaEX2jrsa # SdTiOdBk1IMvG3FT6cVx3bM3kQd15UwfcJsdIYpB7QBZNoqgiyfMPsNr8HzpZlJn # KOe3qWVFWHGMWY4MtQ1j9Ph44RPrJybvPQRMDNB3CiDYEtBWsth0fZxhw9T/tKca # 5KgJaxecB3UsXFUBWhmvhkw+hwG+cDWHtiYZSb9AX4cqvPid1UdLnSQFWgHFGX+2 # ok0Q7gy9jYEpteVbIM8kQG0TF7xnZlv99uDK8b4MAH33roXwy70vffxpRGnngNyH # IcLvzmDqRlrlzdvUi8Uro22VmUAUqSQKxKYt9yBJcEUV9NLi8E6g+Hcrvt7YNF9V # jcVub4aIawEZCvnPCpOgzHD9p26ofwb2WQ245/5kzMUVi2pBYsHH6hJj7WdMPixS # r24Ykgo4sxujW4pVy45lXzpA8uKWELCp9iKUOO6hvdoJEybVDMj9zcVn70cJgDrE # RUle5av0n8XR # =XV0D # -----END PGP SIGNATURE----- # gpg: Signature made Thu 23 Feb 2023 12:03:53 GMT # gpg: using RSA key 354BC8B3D7EB2A6B68674E5F3870B400EB918653 # gpg: issuer "armbru@redhat.com" # gpg: Good signature from "Markus Armbruster <armbru@redhat.com>" [full] # gpg: aka "Markus Armbruster <armbru@pond.sub.org>" [full] # Primary key fingerprint: 354B C8B3 D7EB 2A6B 6867 4E5F 3870 B400 EB91 8653 * tag 'pull-qapi-2023-02-23' of https://repo.or.cz/qemu/armbru: qapi: remove JSON value FIXME qapi: remove _JSONObject qapi/parser: add QAPIExpression type qapi: Add minor typing workaround for 3.6 qapi: update pylint configuration qapi: Update flake8 config docs/devel/qapi-code-gen: Fix a missing 'may', clarify SchemaInfo docs/devel/qapi-code-gen: Belatedly update features documentation Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
569346ad0a
@ -685,9 +685,10 @@ change in the QMP syntax (usually by allowing values or operations
|
||||
that previously resulted in an error). QMP clients may still need to
|
||||
know whether the extension is available.
|
||||
|
||||
For this purpose, a list of features can be specified for a command or
|
||||
struct type. Each list member can either be ``{ 'name': STRING, '*if':
|
||||
COND }``, or STRING, which is shorthand for ``{ 'name': STRING }``.
|
||||
For this purpose, a list of features can be specified for definitions,
|
||||
enumeration values, and struct members. Each feature list member can
|
||||
either be ``{ 'name': STRING, '*if': COND }``, or STRING, which is
|
||||
shorthand for ``{ 'name': STRING }``.
|
||||
|
||||
The optional 'if' member specifies a conditional. See `Configuring
|
||||
the schema`_ below for more on this.
|
||||
@ -817,8 +818,8 @@ member 'bar' ::
|
||||
|
||||
A union's discriminator may not be conditional.
|
||||
|
||||
Likewise, individual enumeration values be conditional. This requires
|
||||
the longhand form of ENUM-VALUE_.
|
||||
Likewise, individual enumeration values may be conditional. This
|
||||
requires the longhand form of ENUM-VALUE_.
|
||||
|
||||
Example: an enum type with unconditional value 'foo' and conditional
|
||||
value 'bar' ::
|
||||
@ -1157,9 +1158,8 @@ Example: the SchemaInfo for EVENT_C from section Events_ ::
|
||||
Type "q_obj-EVENT_C-arg" is an implicitly defined object type with
|
||||
the two members from the event's definition.
|
||||
|
||||
The SchemaInfo for struct and union types has meta-type "object".
|
||||
|
||||
The SchemaInfo for a struct type has variant member "members".
|
||||
The SchemaInfo for struct and union types has meta-type "object" and
|
||||
variant member "members".
|
||||
|
||||
The SchemaInfo for a union type additionally has variant members "tag"
|
||||
and "variants".
|
||||
|
@ -1,2 +1,3 @@
|
||||
[flake8]
|
||||
extend-ignore = E722 # Prefer pylint's bare-except checks to flake8's
|
||||
# Prefer pylint's bare-except checks to flake8's
|
||||
extend-ignore = E722
|
||||
|
@ -33,7 +33,6 @@ structures and contextual semantic validation.
|
||||
|
||||
import re
|
||||
from typing import (
|
||||
Collection,
|
||||
Dict,
|
||||
Iterable,
|
||||
List,
|
||||
@ -44,18 +43,10 @@ from typing import (
|
||||
|
||||
from .common import c_name
|
||||
from .error import QAPISemError
|
||||
from .parser import QAPIDoc
|
||||
from .parser import QAPIExpression
|
||||
from .source import QAPISourceInfo
|
||||
|
||||
|
||||
# Deserialized JSON objects as returned by the parser.
|
||||
# The values of this mapping are not necessary to exhaustively type
|
||||
# here (and also not practical as long as mypy lacks recursive
|
||||
# types), because the purpose of this module is to interrogate that
|
||||
# type.
|
||||
_JSONObject = Dict[str, object]
|
||||
|
||||
|
||||
# See check_name_str(), below.
|
||||
valid_name = re.compile(r'(__[a-z0-9.-]+_)?'
|
||||
r'(x-)?'
|
||||
@ -192,11 +183,11 @@ def check_defn_name_str(name: str, info: QAPISourceInfo, meta: str) -> None:
|
||||
info, "%s name should not end in 'List'" % meta)
|
||||
|
||||
|
||||
def check_keys(value: _JSONObject,
|
||||
def check_keys(value: Dict[str, object],
|
||||
info: QAPISourceInfo,
|
||||
source: str,
|
||||
required: Collection[str],
|
||||
optional: Collection[str]) -> None:
|
||||
required: List[str],
|
||||
optional: List[str]) -> None:
|
||||
"""
|
||||
Ensure that a dict has a specific set of keys.
|
||||
|
||||
@ -229,12 +220,11 @@ def check_keys(value: _JSONObject,
|
||||
pprint(unknown), pprint(allowed)))
|
||||
|
||||
|
||||
def check_flags(expr: _JSONObject, info: QAPISourceInfo) -> None:
|
||||
def check_flags(expr: QAPIExpression) -> None:
|
||||
"""
|
||||
Ensure flag members (if present) have valid values.
|
||||
|
||||
:param expr: The expression to validate.
|
||||
:param info: QAPI schema source file information.
|
||||
|
||||
:raise QAPISemError:
|
||||
When certain flags have an invalid value, or when
|
||||
@ -243,21 +233,22 @@ def check_flags(expr: _JSONObject, info: QAPISourceInfo) -> None:
|
||||
for key in ('gen', 'success-response'):
|
||||
if key in expr and expr[key] is not False:
|
||||
raise QAPISemError(
|
||||
info, "flag '%s' may only use false value" % key)
|
||||
expr.info, "flag '%s' may only use false value" % key)
|
||||
for key in ('boxed', 'allow-oob', 'allow-preconfig', 'coroutine'):
|
||||
if key in expr and expr[key] is not True:
|
||||
raise QAPISemError(
|
||||
info, "flag '%s' may only use true value" % key)
|
||||
expr.info, "flag '%s' may only use true value" % key)
|
||||
if 'allow-oob' in expr and 'coroutine' in expr:
|
||||
# This is not necessarily a fundamental incompatibility, but
|
||||
# we don't have a use case and the desired semantics isn't
|
||||
# obvious. The simplest solution is to forbid it until we get
|
||||
# a use case for it.
|
||||
raise QAPISemError(info, "flags 'allow-oob' and 'coroutine' "
|
||||
"are incompatible")
|
||||
raise QAPISemError(
|
||||
expr.info, "flags 'allow-oob' and 'coroutine' are incompatible")
|
||||
|
||||
|
||||
def check_if(expr: _JSONObject, info: QAPISourceInfo, source: str) -> None:
|
||||
def check_if(expr: Dict[str, object],
|
||||
info: QAPISourceInfo, source: str) -> None:
|
||||
"""
|
||||
Validate the ``if`` member of an object.
|
||||
|
||||
@ -447,12 +438,11 @@ def check_features(features: Optional[object],
|
||||
check_if(feat, info, source)
|
||||
|
||||
|
||||
def check_enum(expr: _JSONObject, info: QAPISourceInfo) -> None:
|
||||
def check_enum(expr: QAPIExpression) -> None:
|
||||
"""
|
||||
Normalize and validate this expression as an ``enum`` definition.
|
||||
|
||||
:param expr: The expression to validate.
|
||||
:param info: QAPI schema source file information.
|
||||
|
||||
:raise QAPISemError: When ``expr`` is not a valid ``enum``.
|
||||
:return: None, ``expr`` is normalized in-place as needed.
|
||||
@ -460,6 +450,7 @@ def check_enum(expr: _JSONObject, info: QAPISourceInfo) -> None:
|
||||
name = expr['enum']
|
||||
members = expr['data']
|
||||
prefix = expr.get('prefix')
|
||||
info = expr.info
|
||||
|
||||
if not isinstance(members, list):
|
||||
raise QAPISemError(info, "'data' must be an array")
|
||||
@ -486,12 +477,11 @@ def check_enum(expr: _JSONObject, info: QAPISourceInfo) -> None:
|
||||
check_features(member.get('features'), info)
|
||||
|
||||
|
||||
def check_struct(expr: _JSONObject, info: QAPISourceInfo) -> None:
|
||||
def check_struct(expr: QAPIExpression) -> None:
|
||||
"""
|
||||
Normalize and validate this expression as a ``struct`` definition.
|
||||
|
||||
:param expr: The expression to validate.
|
||||
:param info: QAPI schema source file information.
|
||||
|
||||
:raise QAPISemError: When ``expr`` is not a valid ``struct``.
|
||||
:return: None, ``expr`` is normalized in-place as needed.
|
||||
@ -499,16 +489,15 @@ def check_struct(expr: _JSONObject, info: QAPISourceInfo) -> None:
|
||||
name = cast(str, expr['struct']) # Checked in check_exprs
|
||||
members = expr['data']
|
||||
|
||||
check_type(members, info, "'data'", allow_dict=name)
|
||||
check_type(expr.get('base'), info, "'base'")
|
||||
check_type(members, expr.info, "'data'", allow_dict=name)
|
||||
check_type(expr.get('base'), expr.info, "'base'")
|
||||
|
||||
|
||||
def check_union(expr: _JSONObject, info: QAPISourceInfo) -> None:
|
||||
def check_union(expr: QAPIExpression) -> None:
|
||||
"""
|
||||
Normalize and validate this expression as a ``union`` definition.
|
||||
|
||||
:param expr: The expression to validate.
|
||||
:param info: QAPI schema source file information.
|
||||
|
||||
:raise QAPISemError: when ``expr`` is not a valid ``union``.
|
||||
:return: None, ``expr`` is normalized in-place as needed.
|
||||
@ -517,6 +506,7 @@ def check_union(expr: _JSONObject, info: QAPISourceInfo) -> None:
|
||||
base = expr['base']
|
||||
discriminator = expr['discriminator']
|
||||
members = expr['data']
|
||||
info = expr.info
|
||||
|
||||
check_type(base, info, "'base'", allow_dict=name)
|
||||
check_name_is_str(discriminator, info, "'discriminator'")
|
||||
@ -531,17 +521,17 @@ def check_union(expr: _JSONObject, info: QAPISourceInfo) -> None:
|
||||
check_type(value['type'], info, source, allow_array=not base)
|
||||
|
||||
|
||||
def check_alternate(expr: _JSONObject, info: QAPISourceInfo) -> None:
|
||||
def check_alternate(expr: QAPIExpression) -> None:
|
||||
"""
|
||||
Normalize and validate this expression as an ``alternate`` definition.
|
||||
|
||||
:param expr: The expression to validate.
|
||||
:param info: QAPI schema source file information.
|
||||
|
||||
:raise QAPISemError: When ``expr`` is not a valid ``alternate``.
|
||||
:return: None, ``expr`` is normalized in-place as needed.
|
||||
"""
|
||||
members = expr['data']
|
||||
info = expr.info
|
||||
|
||||
if not members:
|
||||
raise QAPISemError(info, "'data' must not be empty")
|
||||
@ -557,12 +547,11 @@ def check_alternate(expr: _JSONObject, info: QAPISourceInfo) -> None:
|
||||
check_type(value['type'], info, source, allow_array=True)
|
||||
|
||||
|
||||
def check_command(expr: _JSONObject, info: QAPISourceInfo) -> None:
|
||||
def check_command(expr: QAPIExpression) -> None:
|
||||
"""
|
||||
Normalize and validate this expression as a ``command`` definition.
|
||||
|
||||
:param expr: The expression to validate.
|
||||
:param info: QAPI schema source file information.
|
||||
|
||||
:raise QAPISemError: When ``expr`` is not a valid ``command``.
|
||||
:return: None, ``expr`` is normalized in-place as needed.
|
||||
@ -572,17 +561,16 @@ def check_command(expr: _JSONObject, info: QAPISourceInfo) -> None:
|
||||
boxed = expr.get('boxed', False)
|
||||
|
||||
if boxed and args is None:
|
||||
raise QAPISemError(info, "'boxed': true requires 'data'")
|
||||
check_type(args, info, "'data'", allow_dict=not boxed)
|
||||
check_type(rets, info, "'returns'", allow_array=True)
|
||||
raise QAPISemError(expr.info, "'boxed': true requires 'data'")
|
||||
check_type(args, expr.info, "'data'", allow_dict=not boxed)
|
||||
check_type(rets, expr.info, "'returns'", allow_array=True)
|
||||
|
||||
|
||||
def check_event(expr: _JSONObject, info: QAPISourceInfo) -> None:
|
||||
def check_event(expr: QAPIExpression) -> None:
|
||||
"""
|
||||
Normalize and validate this expression as an ``event`` definition.
|
||||
|
||||
:param expr: The expression to validate.
|
||||
:param info: QAPI schema source file information.
|
||||
|
||||
:raise QAPISemError: When ``expr`` is not a valid ``event``.
|
||||
:return: None, ``expr`` is normalized in-place as needed.
|
||||
@ -591,11 +579,11 @@ def check_event(expr: _JSONObject, info: QAPISourceInfo) -> None:
|
||||
boxed = expr.get('boxed', False)
|
||||
|
||||
if boxed and args is None:
|
||||
raise QAPISemError(info, "'boxed': true requires 'data'")
|
||||
check_type(args, info, "'data'", allow_dict=not boxed)
|
||||
raise QAPISemError(expr.info, "'boxed': true requires 'data'")
|
||||
check_type(args, expr.info, "'data'", allow_dict=not boxed)
|
||||
|
||||
|
||||
def check_exprs(exprs: List[_JSONObject]) -> List[_JSONObject]:
|
||||
def check_exprs(exprs: List[QAPIExpression]) -> List[QAPIExpression]:
|
||||
"""
|
||||
Validate and normalize a list of parsed QAPI schema expressions.
|
||||
|
||||
@ -607,21 +595,9 @@ def check_exprs(exprs: List[_JSONObject]) -> List[_JSONObject]:
|
||||
:raise QAPISemError: When any expression fails validation.
|
||||
:return: The same list of expressions (now modified).
|
||||
"""
|
||||
for expr_elem in exprs:
|
||||
# Expression
|
||||
assert isinstance(expr_elem['expr'], dict)
|
||||
for key in expr_elem['expr'].keys():
|
||||
assert isinstance(key, str)
|
||||
expr: _JSONObject = expr_elem['expr']
|
||||
|
||||
# QAPISourceInfo
|
||||
assert isinstance(expr_elem['info'], QAPISourceInfo)
|
||||
info: QAPISourceInfo = expr_elem['info']
|
||||
|
||||
# Optional[QAPIDoc]
|
||||
tmp = expr_elem.get('doc')
|
||||
assert tmp is None or isinstance(tmp, QAPIDoc)
|
||||
doc: Optional[QAPIDoc] = tmp
|
||||
for expr in exprs:
|
||||
info = expr.info
|
||||
doc = expr.doc
|
||||
|
||||
if 'include' in expr:
|
||||
continue
|
||||
@ -653,24 +629,24 @@ def check_exprs(exprs: List[_JSONObject]) -> List[_JSONObject]:
|
||||
if meta == 'enum':
|
||||
check_keys(expr, info, meta,
|
||||
['enum', 'data'], ['if', 'features', 'prefix'])
|
||||
check_enum(expr, info)
|
||||
check_enum(expr)
|
||||
elif meta == 'union':
|
||||
check_keys(expr, info, meta,
|
||||
['union', 'base', 'discriminator', 'data'],
|
||||
['if', 'features'])
|
||||
normalize_members(expr.get('base'))
|
||||
normalize_members(expr['data'])
|
||||
check_union(expr, info)
|
||||
check_union(expr)
|
||||
elif meta == 'alternate':
|
||||
check_keys(expr, info, meta,
|
||||
['alternate', 'data'], ['if', 'features'])
|
||||
normalize_members(expr['data'])
|
||||
check_alternate(expr, info)
|
||||
check_alternate(expr)
|
||||
elif meta == 'struct':
|
||||
check_keys(expr, info, meta,
|
||||
['struct', 'data'], ['base', 'if', 'features'])
|
||||
normalize_members(expr['data'])
|
||||
check_struct(expr, info)
|
||||
check_struct(expr)
|
||||
elif meta == 'command':
|
||||
check_keys(expr, info, meta,
|
||||
['command'],
|
||||
@ -678,17 +654,17 @@ def check_exprs(exprs: List[_JSONObject]) -> List[_JSONObject]:
|
||||
'gen', 'success-response', 'allow-oob',
|
||||
'allow-preconfig', 'coroutine'])
|
||||
normalize_members(expr.get('data'))
|
||||
check_command(expr, info)
|
||||
check_command(expr)
|
||||
elif meta == 'event':
|
||||
check_keys(expr, info, meta,
|
||||
['event'], ['data', 'boxed', 'if', 'features'])
|
||||
normalize_members(expr.get('data'))
|
||||
check_event(expr, info)
|
||||
check_event(expr)
|
||||
else:
|
||||
assert False, 'unexpected meta type'
|
||||
|
||||
check_if(expr, info, meta)
|
||||
check_features(expr.get('features'), info)
|
||||
check_flags(expr, info)
|
||||
check_flags(expr)
|
||||
|
||||
return exprs
|
||||
|
@ -21,6 +21,7 @@ from typing import (
|
||||
TYPE_CHECKING,
|
||||
Dict,
|
||||
List,
|
||||
Mapping,
|
||||
Optional,
|
||||
Set,
|
||||
Union,
|
||||
@ -37,15 +38,19 @@ if TYPE_CHECKING:
|
||||
from .schema import QAPISchemaFeature, QAPISchemaMember
|
||||
|
||||
|
||||
#: Represents a single Top Level QAPI schema expression.
|
||||
TopLevelExpr = Dict[str, object]
|
||||
|
||||
# Return value alias for get_expr().
|
||||
_ExprValue = Union[List[object], Dict[str, object], str, bool]
|
||||
|
||||
# FIXME: Consolidate and centralize definitions for TopLevelExpr,
|
||||
# _ExprValue, _JSONValue, and _JSONObject; currently scattered across
|
||||
# several modules.
|
||||
|
||||
class QAPIExpression(Dict[str, object]):
|
||||
# pylint: disable=too-few-public-methods
|
||||
def __init__(self,
|
||||
data: Mapping[str, object],
|
||||
info: QAPISourceInfo,
|
||||
doc: Optional['QAPIDoc'] = None):
|
||||
super().__init__(data)
|
||||
self.info = info
|
||||
self.doc: Optional['QAPIDoc'] = doc
|
||||
|
||||
|
||||
class QAPIParseError(QAPISourceError):
|
||||
@ -100,7 +105,7 @@ class QAPISchemaParser:
|
||||
self.line_pos = 0
|
||||
|
||||
# Parser output:
|
||||
self.exprs: List[Dict[str, object]] = []
|
||||
self.exprs: List[QAPIExpression] = []
|
||||
self.docs: List[QAPIDoc] = []
|
||||
|
||||
# Showtime!
|
||||
@ -147,8 +152,7 @@ class QAPISchemaParser:
|
||||
"value of 'include' must be a string")
|
||||
incl_fname = os.path.join(os.path.dirname(self._fname),
|
||||
include)
|
||||
self.exprs.append({'expr': {'include': incl_fname},
|
||||
'info': info})
|
||||
self._add_expr(OrderedDict({'include': incl_fname}), info)
|
||||
exprs_include = self._include(include, info, incl_fname,
|
||||
self._included)
|
||||
if exprs_include:
|
||||
@ -165,17 +169,18 @@ class QAPISchemaParser:
|
||||
for name, value in pragma.items():
|
||||
self._pragma(name, value, info)
|
||||
else:
|
||||
expr_elem = {'expr': expr,
|
||||
'info': info}
|
||||
if cur_doc:
|
||||
if not cur_doc.symbol:
|
||||
raise QAPISemError(
|
||||
cur_doc.info, "definition documentation required")
|
||||
expr_elem['doc'] = cur_doc
|
||||
self.exprs.append(expr_elem)
|
||||
if cur_doc and not cur_doc.symbol:
|
||||
raise QAPISemError(
|
||||
cur_doc.info, "definition documentation required")
|
||||
self._add_expr(expr, info, cur_doc)
|
||||
cur_doc = None
|
||||
self.reject_expr_doc(cur_doc)
|
||||
|
||||
def _add_expr(self, expr: Mapping[str, object],
|
||||
info: QAPISourceInfo,
|
||||
doc: Optional['QAPIDoc'] = None) -> None:
|
||||
self.exprs.append(QAPIExpression(expr, info, doc))
|
||||
|
||||
@staticmethod
|
||||
def reject_expr_doc(doc: Optional['QAPIDoc']) -> None:
|
||||
if doc and doc.symbol:
|
||||
@ -784,7 +789,7 @@ class QAPIDoc:
|
||||
% feature.name)
|
||||
self.features[feature.name].connect(feature)
|
||||
|
||||
def check_expr(self, expr: TopLevelExpr) -> None:
|
||||
def check_expr(self, expr: QAPIExpression) -> None:
|
||||
if self.has_section('Returns') and 'command' not in expr:
|
||||
raise QAPISemError(self.info,
|
||||
"'Returns:' is only valid for commands")
|
||||
|
@ -23,6 +23,7 @@ disable=fixme,
|
||||
too-many-statements,
|
||||
too-many-instance-attributes,
|
||||
consider-using-f-string,
|
||||
useless-option-value,
|
||||
|
||||
[REPORTS]
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
from collections import OrderedDict
|
||||
import os
|
||||
import re
|
||||
from typing import Optional
|
||||
from typing import List, Optional
|
||||
|
||||
from .common import (
|
||||
POINTER_SUFFIX,
|
||||
@ -29,7 +29,7 @@ from .common import (
|
||||
)
|
||||
from .error import QAPIError, QAPISemError, QAPISourceError
|
||||
from .expr import check_exprs
|
||||
from .parser import QAPISchemaParser
|
||||
from .parser import QAPIExpression, QAPISchemaParser
|
||||
|
||||
|
||||
class QAPISchemaIfCond:
|
||||
@ -964,10 +964,11 @@ class QAPISchema:
|
||||
name = self._module_name(fname)
|
||||
return self._module_dict[name]
|
||||
|
||||
def _def_include(self, expr, info, doc):
|
||||
def _def_include(self, expr: QAPIExpression):
|
||||
include = expr['include']
|
||||
assert doc is None
|
||||
self._def_entity(QAPISchemaInclude(self._make_module(include), info))
|
||||
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))
|
||||
@ -1045,14 +1046,15 @@ class QAPISchema:
|
||||
name, info, None, ifcond, None, None, members, None))
|
||||
return name
|
||||
|
||||
def _def_enum_type(self, expr, info, doc):
|
||||
def _def_enum_type(self, expr: QAPIExpression):
|
||||
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(
|
||||
name, info, doc, ifcond, features,
|
||||
name, info, expr.doc, ifcond, features,
|
||||
self._make_enum_members(data, info), prefix))
|
||||
|
||||
def _make_member(self, name, typ, ifcond, features, info):
|
||||
@ -1072,14 +1074,15 @@ class QAPISchema:
|
||||
value.get('features'), info)
|
||||
for (key, value) in data.items()]
|
||||
|
||||
def _def_struct_type(self, expr, info, doc):
|
||||
def _def_struct_type(self, expr: QAPIExpression):
|
||||
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(
|
||||
name, info, doc, ifcond, features, base,
|
||||
name, info, expr.doc, ifcond, features, base,
|
||||
self._make_members(data, info),
|
||||
None))
|
||||
|
||||
@ -1089,11 +1092,13 @@ class QAPISchema:
|
||||
typ = self._make_array_type(typ[0], info)
|
||||
return QAPISchemaVariant(case, info, typ, ifcond)
|
||||
|
||||
def _def_union_type(self, expr, info, doc):
|
||||
def _def_union_type(self, expr: QAPIExpression):
|
||||
name = expr['union']
|
||||
base = expr['base']
|
||||
tag_name = expr['discriminator']
|
||||
data = expr['data']
|
||||
assert isinstance(data, dict)
|
||||
info = expr.info
|
||||
ifcond = QAPISchemaIfCond(expr.get('if'))
|
||||
features = self._make_features(expr.get('features'), info)
|
||||
if isinstance(base, dict):
|
||||
@ -1105,17 +1110,19 @@ class QAPISchema:
|
||||
QAPISchemaIfCond(value.get('if')),
|
||||
info)
|
||||
for (key, value) in data.items()]
|
||||
members = []
|
||||
members: List[QAPISchemaObjectTypeMember] = []
|
||||
self._def_entity(
|
||||
QAPISchemaObjectType(name, info, doc, ifcond, features,
|
||||
QAPISchemaObjectType(name, info, expr.doc, ifcond, features,
|
||||
base, members,
|
||||
QAPISchemaVariants(
|
||||
tag_name, info, None, variants)))
|
||||
|
||||
def _def_alternate_type(self, expr, info, doc):
|
||||
def _def_alternate_type(self, expr: QAPIExpression):
|
||||
name = expr['alternate']
|
||||
data = expr['data']
|
||||
assert isinstance(data, dict)
|
||||
ifcond = QAPISchemaIfCond(expr.get('if'))
|
||||
info = expr.info
|
||||
features = self._make_features(expr.get('features'), info)
|
||||
variants = [
|
||||
self._make_variant(key, value['type'],
|
||||
@ -1124,11 +1131,11 @@ class QAPISchema:
|
||||
for (key, value) in data.items()]
|
||||
tag_member = QAPISchemaObjectTypeMember('type', info, 'QType', False)
|
||||
self._def_entity(
|
||||
QAPISchemaAlternateType(name, info, doc, ifcond, features,
|
||||
QAPISchemaVariants(
|
||||
None, info, tag_member, variants)))
|
||||
QAPISchemaAlternateType(
|
||||
name, info, expr.doc, ifcond, features,
|
||||
QAPISchemaVariants(None, info, tag_member, variants)))
|
||||
|
||||
def _def_command(self, expr, info, doc):
|
||||
def _def_command(self, expr: QAPIExpression):
|
||||
name = expr['command']
|
||||
data = expr.get('data')
|
||||
rets = expr.get('returns')
|
||||
@ -1139,6 +1146,7 @@ class QAPISchema:
|
||||
allow_preconfig = expr.get('allow-preconfig', False)
|
||||
coroutine = expr.get('coroutine', False)
|
||||
ifcond = QAPISchemaIfCond(expr.get('if'))
|
||||
info = expr.info
|
||||
features = self._make_features(expr.get('features'), info)
|
||||
if isinstance(data, OrderedDict):
|
||||
data = self._make_implicit_object_type(
|
||||
@ -1147,44 +1155,42 @@ class QAPISchema:
|
||||
if isinstance(rets, list):
|
||||
assert len(rets) == 1
|
||||
rets = self._make_array_type(rets[0], info)
|
||||
self._def_entity(QAPISchemaCommand(name, info, doc, ifcond, features,
|
||||
data, rets,
|
||||
self._def_entity(QAPISchemaCommand(name, info, expr.doc, ifcond,
|
||||
features, data, rets,
|
||||
gen, success_response,
|
||||
boxed, allow_oob, allow_preconfig,
|
||||
coroutine))
|
||||
|
||||
def _def_event(self, expr, info, doc):
|
||||
def _def_event(self, expr: QAPIExpression):
|
||||
name = expr['event']
|
||||
data = expr.get('data')
|
||||
boxed = expr.get('boxed', False)
|
||||
ifcond = QAPISchemaIfCond(expr.get('if'))
|
||||
info = expr.info
|
||||
features = self._make_features(expr.get('features'), info)
|
||||
if isinstance(data, OrderedDict):
|
||||
data = self._make_implicit_object_type(
|
||||
name, info, ifcond,
|
||||
'arg', self._make_members(data, info))
|
||||
self._def_entity(QAPISchemaEvent(name, info, doc, ifcond, features,
|
||||
data, boxed))
|
||||
self._def_entity(QAPISchemaEvent(name, info, expr.doc, ifcond,
|
||||
features, data, boxed))
|
||||
|
||||
def _def_exprs(self, exprs):
|
||||
for expr_elem in exprs:
|
||||
expr = expr_elem['expr']
|
||||
info = expr_elem['info']
|
||||
doc = expr_elem.get('doc')
|
||||
for expr in exprs:
|
||||
if 'enum' in expr:
|
||||
self._def_enum_type(expr, info, doc)
|
||||
self._def_enum_type(expr)
|
||||
elif 'struct' in expr:
|
||||
self._def_struct_type(expr, info, doc)
|
||||
self._def_struct_type(expr)
|
||||
elif 'union' in expr:
|
||||
self._def_union_type(expr, info, doc)
|
||||
self._def_union_type(expr)
|
||||
elif 'alternate' in expr:
|
||||
self._def_alternate_type(expr, info, doc)
|
||||
self._def_alternate_type(expr)
|
||||
elif 'command' in expr:
|
||||
self._def_command(expr, info, doc)
|
||||
self._def_command(expr)
|
||||
elif 'event' in expr:
|
||||
self._def_event(expr, info, doc)
|
||||
self._def_event(expr)
|
||||
elif 'include' in expr:
|
||||
self._def_include(expr, info, doc)
|
||||
self._def_include(expr)
|
||||
else:
|
||||
assert False
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user