From 25a0d9c977c2f5db914b0a1619759fd77d97b016 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 12 Oct 2015 22:22:21 -0600 Subject: qapi: Use predicate callback to determine visit filtering Previously, qapi-types and qapi-visit filtered out implicit objects during visit_object_type() by using 'info' (works since implicit objects do not [yet] have associated info); meanwhile qapi-introspect filtered out all schema types on the first pass by returning a python type from visit_begin(), which was then used at a distance in QAPISchema.visit() to do the filtering. Rather than keeping these ad hoc approaches, add a new visitor callback visit_needed() which returns False to skip a given entity, and which defaults to True unless overridden. Use the new mechanism to simplify all three filtering visitors. No change to the generated code. Suggested-by: Markus Armbruster Signed-off-by: Eric Blake Message-Id: <1444710158-8723-2-git-send-email-eblake@redhat.com> Signed-off-by: Markus Armbruster --- scripts/qapi.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'scripts/qapi.py') diff --git a/scripts/qapi.py b/scripts/qapi.py index 26cff3f05c..543b378d7e 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -811,6 +811,10 @@ class QAPISchemaVisitor(object): def visit_end(self): pass + def visit_needed(self, entity): + # Default to visiting everything + return True + def visit_builtin_type(self, name, info, json_type): pass @@ -1304,10 +1308,10 @@ class QAPISchema(object): ent.check(self) def visit(self, visitor): - ignore = visitor.visit_begin(self) - for name in sorted(self._entity_dict.keys()): - if not ignore or not isinstance(self._entity_dict[name], ignore): - self._entity_dict[name].visit(visitor) + visitor.visit_begin(self) + for (name, entity) in sorted(self._entity_dict.items()): + if visitor.visit_needed(entity): + entity.visit(visitor) visitor.visit_end() -- cgit v1.2.3 From 7618b91ff80ec42b84b29be24d8ef53ddb377110 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 12 Oct 2015 22:22:22 -0600 Subject: qapi: Prepare for errors during check() The next few patches will start migrating error checking from ad hoc parse methods into the QAPISchema*.check() methods. But for an error message to display, we first have to fix the overall 'try' to catch those errors. We also want to enable a few more assertions, such as making sure every attempt to raise a semantic error is passed a valid location info, or that various preconditions hold. The general approach for moving error checking will then be to relax an assertion into an if that raises an exception if the condition does not hold, and removing the counterpart ad hoc check done during the parse phase. Signed-off-by: Eric Blake Message-Id: <1444710158-8723-3-git-send-email-eblake@redhat.com> Signed-off-by: Markus Armbruster --- scripts/qapi.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'scripts/qapi.py') diff --git a/scripts/qapi.py b/scripts/qapi.py index 543b378d7e..4573599d7c 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -103,6 +103,7 @@ class QAPISchemaError(Exception): class QAPIExprError(Exception): def __init__(self, expr_info, msg): Exception.__init__(self) + assert expr_info self.info = expr_info self.msg = msg @@ -964,6 +965,7 @@ class QAPISchemaObjectType(QAPISchemaType): members = [] seen = {} for m in members: + assert c_name(m.name) not in seen seen[m.name] = m for m in self.local_members: m.check(schema, members, seen) @@ -1116,13 +1118,13 @@ class QAPISchema(object): def __init__(self, fname): try: self.exprs = check_exprs(QAPISchemaParser(open(fname, "r")).exprs) + self._entity_dict = {} + self._def_predefineds() + self._def_exprs() + self.check() except (QAPISchemaError, QAPIExprError), err: print >>sys.stderr, err exit(1) - self._entity_dict = {} - self._def_predefineds() - self._def_exprs() - self.check() def _def_entity(self, ent): assert ent.name not in self._entity_dict -- cgit v1.2.3 From cae95eae6270c1ea28a9ba8eee75c441b1015f68 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 12 Oct 2015 22:22:25 -0600 Subject: qapi: Drop redundant returns-int test qapi-schema-test was already testing that we could have a command returning int, but burned a command name in the whitelist. Merge the redundant positive test returns-int, and pick a name that reduces the whitelist size. Signed-off-by: Eric Blake Message-Id: <1444710158-8723-6-git-send-email-eblake@redhat.com> Signed-off-by: Markus Armbruster --- scripts/qapi.py | 3 --- 1 file changed, 3 deletions(-) (limited to 'scripts/qapi.py') diff --git a/scripts/qapi.py b/scripts/qapi.py index 4573599d7c..68f97a14bb 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -56,9 +56,6 @@ returns_whitelist = [ 'guest-set-vcpus', 'guest-sync', 'guest-sync-delimited', - - # From qapi-schema-test: - 'user_def_cmd3', ] enum_types = [] -- cgit v1.2.3 From 49823c4b4304a3e4aa5d67e089946b12d6a52d64 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 12 Oct 2015 22:22:27 -0600 Subject: qapi: Don't use info as witness of implicit object type A future patch will enable error reporting from the various QAPISchema*.check() methods. But to report an error related to an implicit type, we'll need to associate a location with the type (the same location as the top-level entity that is causing the creation of the implicit type), and once we do that, keying off of whether foo.info exists is no longer a viable way to determine if foo is an implicit type. Instead, add an is_implicit() method to QAPISchemaEntity, and use it. It can be overridden later for ObjectType and EnumType, when implicit instances of those classes gain info. Signed-off-by: Eric Blake Message-Id: <1444710158-8723-8-git-send-email-eblake@redhat.com> Signed-off-by: Markus Armbruster --- scripts/qapi.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'scripts/qapi.py') diff --git a/scripts/qapi.py b/scripts/qapi.py index 68f97a14bb..d7cf0f3714 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -798,6 +798,9 @@ class QAPISchemaEntity(object): def check(self, schema): pass + def is_implicit(self): + return not self.info + def visit(self, visitor): pass @@ -971,11 +974,11 @@ class QAPISchemaObjectType(QAPISchemaType): self.members = members def c_name(self): - assert self.info + assert not self.is_implicit() return QAPISchemaType.c_name(self) def c_type(self, is_param=False): - assert self.info + assert not self.is_implicit() return QAPISchemaType.c_type(self) def json_type(self): @@ -1043,7 +1046,8 @@ class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember): # This function exists to support ugly simple union special cases # TODO get rid of them, and drop the function def simple_union_type(self): - if isinstance(self.type, QAPISchemaObjectType) and not self.type.info: + if (self.type.is_implicit() and + isinstance(self.type, QAPISchemaObjectType)): assert len(self.type.members) == 1 assert not self.type.variants return self.type.members[0].type @@ -1162,11 +1166,13 @@ class QAPISchema(object): self._def_entity(self.the_empty_object_type) def _make_implicit_enum_type(self, name, values): - name = name + 'Kind' + name = name + 'Kind' # Use namespace reserved by add_name() self._def_entity(QAPISchemaEnumType(name, None, values, None)) return name def _make_array_type(self, element_type): + # TODO fooList namespace is not reserved; user can create collisions, + # or abuse our type system with ['fooList'] for 2D array name = element_type + 'List' if not self.lookup_type(name): self._def_entity(QAPISchemaArrayType(name, None, element_type)) -- cgit v1.2.3 From 9f08c8ec73878122ad4b061ed334f0437afaaa32 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 12 Oct 2015 22:22:28 -0600 Subject: qapi: Lazy creation of array types Commit ac88219a had several TODO markers about whether we needed to automatically create the corresponding array type alongside any other type. It turns out that most of the time, we don't! There are a few exceptions: 1) We have a few situations where we use an array type in internal code but do not expose that type through QMP; fix it by declaring a dummy type that forces the generator to see that we want to use the array type. 2) The builtin arrays (such as intList for QAPI ['int']) must always be generated, because of the way our QAPI_TYPES_BUILTIN compile guard works: we have situations (at the very least tests/test-qmp-output-visitor.c) that include both top-level "qapi-types.h" (via "error.h") and a secondary "test-qapi-types.h". If we were to only emit the builtin types when used locally, then the first .h file would not include all types, but the second .h does not declare anything at all because the first .h set QAPI_TYPES_BUILTIN, and we would end up with compilation error due to things like unknown type 'int8List'. Actually, we may need to revisit how we do type guards, and change from a single QAPI_TYPES_BUILTIN over to a different usage pattern that does one #ifdef per qapi type - right now, the only types that are declared multiple times between two qapi .json files for inclusion by a single .c file happen to be the builtin arrays. But now that we have QAPI 'include' statements, it is logical to assume that we will soon reach a point where we want to reuse non-builtin types (yes, I'm thinking about what it will take to add introspection to QGA, where we will want to reuse the SchemaInfo type and friends). One #ifdef per type will help ensure that generating the same qapi type into more than one qapi-types.h won't cause collisions when both are included in the same .c file; but we also have to solve how to avoid creating duplicate qapi-types.c entry points. So that is a problem left for another day. Generated code for qapi-types and qapi-visit is drastically reduced; less than a third of the arrays that were blindly created were actually needed (a quick grep shows we dropped from 219 to 69 *List types), and the .o files lost more than 30% of their bulk. [For best results, diff the generated files with 'git diff --patience --no-index pre post'.] Interestingly, the introspection output is unchanged - this is because we already cull all types that are not indirectly reachable from a command or event, so introspection was already using only a subset of array types. The subset of types introspected is now a much larger percentage of the overall set of array types emitted in qapi-types.h (since the larger set shrunk), but still not 100% (evidence that the array types emitted for our new Dummy structs, and the new struct itself, don't affect QMP). Signed-off-by: Eric Blake Message-Id: <1444710158-8723-9-git-send-email-eblake@redhat.com> [Moved array info tracking to a later patch] Signed-off-by: Markus Armbruster --- scripts/qapi.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'scripts/qapi.py') diff --git a/scripts/qapi.py b/scripts/qapi.py index d7cf0f3714..9e017050c0 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -1143,7 +1143,12 @@ class QAPISchema(object): def _def_builtin_type(self, name, json_type, c_type, c_null): self._def_entity(QAPISchemaBuiltinType(name, json_type, c_type, c_null)) - self._make_array_type(name) # TODO really needed? + # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple + # qapi-types.h from a single .c, all arrays of builtins must be + # declared in the first file whether or not they are used. Nicer + # would be to use lazy instantiation, while figuring out how to + # avoid compilation issues with multiple qapi-types.h. + self._make_array_type(name) def _def_predefineds(self): for t in [('str', 'string', 'char' + pointer_suffix, 'NULL'), @@ -1192,7 +1197,6 @@ class QAPISchema(object): data = expr['data'] prefix = expr.get('prefix') self._def_entity(QAPISchemaEnumType(name, info, data, prefix)) - self._make_array_type(name) # TODO really needed? def _make_member(self, name, typ): optional = False @@ -1215,7 +1219,6 @@ class QAPISchema(object): self._def_entity(QAPISchemaObjectType(name, info, base, self._make_members(data), None)) - self._make_array_type(name) # TODO really needed? def _make_variant(self, case, typ): return QAPISchemaObjectTypeVariant(case, typ) @@ -1251,7 +1254,6 @@ class QAPISchema(object): QAPISchemaObjectTypeVariants(tag_name, tag_enum, variants))) - self._make_array_type(name) # TODO really needed? def _def_alternate_type(self, expr, info): name = expr['alternate'] @@ -1264,7 +1266,6 @@ class QAPISchema(object): QAPISchemaObjectTypeVariants(None, tag_enum, variants))) - self._make_array_type(name) # TODO really needed? def _def_command(self, expr, info): name = expr['command'] -- cgit v1.2.3 From 46292ba75c515baf733df18644052b2ce9492728 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 12 Oct 2015 22:22:29 -0600 Subject: qapi: Create simple union type member earlier For simple unions, we were creating the implicit 'type' tag member during the QAPISchemaObjectTypeVariants constructor. This is different from every other implicit QAPISchemaEntity object, which get created by QAPISchema methods. Hoist the creation to the caller (renaming _make_tag_enum() to _make_implicit_tag()), and pass the entity rather than the string name, so that we have the nice property that no entities are created as a side effect within a different entity. A later patch will then have an easier time of associating location info with each entity creation. No change to generated code. Signed-off-by: Eric Blake Message-Id: <1444710158-8723-10-git-send-email-eblake@redhat.com> Signed-off-by: Markus Armbruster --- scripts/qapi.py | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) (limited to 'scripts/qapi.py') diff --git a/scripts/qapi.py b/scripts/qapi.py index 9e017050c0..471bbfc406 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -1010,18 +1010,18 @@ class QAPISchemaObjectTypeMember(object): class QAPISchemaObjectTypeVariants(object): - def __init__(self, tag_name, tag_enum, variants): - assert tag_name is None or isinstance(tag_name, str) - assert tag_enum is None or isinstance(tag_enum, str) + def __init__(self, tag_name, tag_member, variants): + # Flat unions pass tag_name but not tag_member. + # Simple unions and alternates pass tag_member but not tag_name. + # After check(), tag_member is always set, and tag_name remains + # a reliable witness of being used by a flat union. + assert bool(tag_member) != bool(tag_name) + assert (isinstance(tag_name, str) or + isinstance(tag_member, QAPISchemaObjectTypeMember)) for v in variants: assert isinstance(v, QAPISchemaObjectTypeVariant) self.tag_name = tag_name - if tag_name: - assert not tag_enum - self.tag_member = None - else: - self.tag_member = QAPISchemaObjectTypeMember('type', tag_enum, - False) + self.tag_member = tag_member self.variants = variants def check(self, schema, members, seen): @@ -1231,28 +1231,29 @@ class QAPISchema(object): [self._make_member('data', typ)]) return QAPISchemaObjectTypeVariant(case, typ) - def _make_tag_enum(self, type_name, variants): - return self._make_implicit_enum_type(type_name, - [v.name for v in variants]) + def _make_implicit_tag(self, type_name, variants): + typ = self._make_implicit_enum_type(type_name, + [v.name for v in variants]) + return QAPISchemaObjectTypeMember('type', typ, False) def _def_union_type(self, expr, info): name = expr['union'] data = expr['data'] base = expr.get('base') tag_name = expr.get('discriminator') - tag_enum = None + tag_member = None if tag_name: variants = [self._make_variant(key, value) for (key, value) in data.iteritems()] else: variants = [self._make_simple_variant(key, value) for (key, value) in data.iteritems()] - tag_enum = self._make_tag_enum(name, variants) + tag_member = self._make_implicit_tag(name, variants) self._def_entity( QAPISchemaObjectType(name, info, base, self._make_members(OrderedDict()), QAPISchemaObjectTypeVariants(tag_name, - tag_enum, + tag_member, variants))) def _def_alternate_type(self, expr, info): @@ -1260,11 +1261,11 @@ class QAPISchema(object): data = expr['data'] variants = [self._make_variant(key, value) for (key, value) in data.iteritems()] - tag_enum = self._make_tag_enum(name, variants) + tag_member = self._make_implicit_tag(name, variants) self._def_entity( QAPISchemaAlternateType(name, info, QAPISchemaObjectTypeVariants(None, - tag_enum, + tag_member, variants))) def _def_command(self, expr, info): -- cgit v1.2.3 From 99df5289d8c7ebf373c3570d8fba3f3a73360281 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 12 Oct 2015 22:22:32 -0600 Subject: qapi: Track location that created an implicit type A future patch will move some error checking from the parser to the various QAPISchema*.check() methods, which run only after parsing completes. It will thus be possible to create a python instance representing an implicit QAPI type that parses fine but will fail validation during check(). Since all errors have to have an associated 'info' location, we need a location to be associated with those implicit types. The intuitive info to use is the location of the enclosing entity that caused the creation of the implicit type. Note that we do not anticipate builtin types being used in an error message (as they are not part of the user's QAPI input, the user can't cause a semantic error in their behavior), so we exempt those types from requiring info, by setting a flag to track the completion of _def_predefineds(), and tracking that flag in _def_entity(). No change to the generated code. Signed-off-by: Eric Blake Message-Id: <1444710158-8723-13-git-send-email-eblake@redhat.com> [Missing QAPISchemaArrayType.is_implicit() supplied] Signed-off-by: Markus Armbruster --- scripts/qapi.py | 74 ++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 47 insertions(+), 27 deletions(-) (limited to 'scripts/qapi.py') diff --git a/scripts/qapi.py b/scripts/qapi.py index 471bbfc406..9d53255320 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -790,6 +790,11 @@ class QAPISchemaEntity(object): def __init__(self, name, info): assert isinstance(name, str) self.name = name + # 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 def c_name(self): @@ -903,6 +908,10 @@ class QAPISchemaEnumType(QAPISchemaType): def check(self, schema): assert len(set(self.values)) == len(self.values) + def is_implicit(self): + # See QAPISchema._make_implicit_enum_type() + return self.name[-4:] == 'Kind' + def c_type(self, is_param=False): return c_name(self.name) @@ -929,6 +938,9 @@ class QAPISchemaArrayType(QAPISchemaType): self.element_type = schema.lookup_type(self._element_type_name) assert self.element_type + def is_implicit(self): + return True + def json_type(self): return 'array' @@ -973,6 +985,10 @@ class QAPISchemaObjectType(QAPISchemaType): self.variants.check(schema, members, seen) self.members = members + def is_implicit(self): + # See QAPISchema._make_implicit_object_type() + return self.name[0] == ':' + def c_name(self): assert not self.is_implicit() return QAPISchemaType.c_name(self) @@ -1120,7 +1136,9 @@ class QAPISchema(object): try: self.exprs = check_exprs(QAPISchemaParser(open(fname, "r")).exprs) self._entity_dict = {} + self._predefining = True self._def_predefineds() + self._predefining = False self._def_exprs() self.check() except (QAPISchemaError, QAPIExprError), err: @@ -1128,6 +1146,8 @@ class QAPISchema(object): exit(1) def _def_entity(self, ent): + # Only the predefined types are allowed to not have info + assert ent.info or self._predefining assert ent.name not in self._entity_dict self._entity_dict[ent.name] = ent @@ -1148,7 +1168,7 @@ class QAPISchema(object): # declared in the first file whether or not they are used. Nicer # would be to use lazy instantiation, while figuring out how to # avoid compilation issues with multiple qapi-types.h. - self._make_array_type(name) + self._make_array_type(name, None) def _def_predefineds(self): for t in [('str', 'string', 'char' + pointer_suffix, 'NULL'), @@ -1170,25 +1190,25 @@ class QAPISchema(object): [], None) self._def_entity(self.the_empty_object_type) - def _make_implicit_enum_type(self, name, values): + def _make_implicit_enum_type(self, name, info, values): name = name + 'Kind' # Use namespace reserved by add_name() - self._def_entity(QAPISchemaEnumType(name, None, values, None)) + self._def_entity(QAPISchemaEnumType(name, info, values, None)) return name - def _make_array_type(self, element_type): + def _make_array_type(self, element_type, info): # TODO fooList namespace is not reserved; user can create collisions, # or abuse our type system with ['fooList'] for 2D array name = element_type + 'List' if not self.lookup_type(name): - self._def_entity(QAPISchemaArrayType(name, None, element_type)) + self._def_entity(QAPISchemaArrayType(name, info, element_type)) return name - def _make_implicit_object_type(self, name, role, members): + def _make_implicit_object_type(self, name, info, role, members): if not members: return None name = ':obj-%s-%s' % (name, role) if not self.lookup_entity(name, QAPISchemaObjectType): - self._def_entity(QAPISchemaObjectType(name, None, None, + self._def_entity(QAPISchemaObjectType(name, info, None, members, None)) return name @@ -1198,18 +1218,18 @@ class QAPISchema(object): prefix = expr.get('prefix') self._def_entity(QAPISchemaEnumType(name, info, data, prefix)) - def _make_member(self, name, typ): + def _make_member(self, name, typ, info): optional = False if name.startswith('*'): name = name[1:] optional = True if isinstance(typ, list): assert len(typ) == 1 - typ = self._make_array_type(typ[0]) + typ = self._make_array_type(typ[0], info) return QAPISchemaObjectTypeMember(name, typ, optional) - def _make_members(self, data): - return [self._make_member(key, value) + def _make_members(self, data, info): + return [self._make_member(key, value, info) for (key, value) in data.iteritems()] def _def_struct_type(self, expr, info): @@ -1217,22 +1237,22 @@ class QAPISchema(object): base = expr.get('base') data = expr['data'] self._def_entity(QAPISchemaObjectType(name, info, base, - self._make_members(data), + self._make_members(data, info), None)) def _make_variant(self, case, typ): return QAPISchemaObjectTypeVariant(case, typ) - def _make_simple_variant(self, case, typ): + def _make_simple_variant(self, case, typ, info): if isinstance(typ, list): assert len(typ) == 1 - typ = self._make_array_type(typ[0]) - typ = self._make_implicit_object_type(typ, 'wrapper', - [self._make_member('data', typ)]) + typ = self._make_array_type(typ[0], info) + typ = self._make_implicit_object_type( + typ, info, 'wrapper', [self._make_member('data', typ, info)]) return QAPISchemaObjectTypeVariant(case, typ) - def _make_implicit_tag(self, type_name, variants): - typ = self._make_implicit_enum_type(type_name, + def _make_implicit_tag(self, type_name, info, variants): + typ = self._make_implicit_enum_type(type_name, info, [v.name for v in variants]) return QAPISchemaObjectTypeMember('type', typ, False) @@ -1246,12 +1266,12 @@ class QAPISchema(object): variants = [self._make_variant(key, value) for (key, value) in data.iteritems()] else: - variants = [self._make_simple_variant(key, value) + variants = [self._make_simple_variant(key, value, info) for (key, value) in data.iteritems()] - tag_member = self._make_implicit_tag(name, variants) + tag_member = self._make_implicit_tag(name, info, variants) self._def_entity( QAPISchemaObjectType(name, info, base, - self._make_members(OrderedDict()), + self._make_members(OrderedDict(), info), QAPISchemaObjectTypeVariants(tag_name, tag_member, variants))) @@ -1261,7 +1281,7 @@ class QAPISchema(object): data = expr['data'] variants = [self._make_variant(key, value) for (key, value) in data.iteritems()] - tag_member = self._make_implicit_tag(name, variants) + tag_member = self._make_implicit_tag(name, info, variants) self._def_entity( QAPISchemaAlternateType(name, info, QAPISchemaObjectTypeVariants(None, @@ -1275,11 +1295,11 @@ class QAPISchema(object): gen = expr.get('gen', True) success_response = expr.get('success-response', True) if isinstance(data, OrderedDict): - data = self._make_implicit_object_type(name, 'arg', - self._make_members(data)) + data = self._make_implicit_object_type( + name, info, 'arg', self._make_members(data, info)) if isinstance(rets, list): assert len(rets) == 1 - rets = self._make_array_type(rets[0]) + rets = self._make_array_type(rets[0], info) self._def_entity(QAPISchemaCommand(name, info, data, rets, gen, success_response)) @@ -1287,8 +1307,8 @@ class QAPISchema(object): name = expr['event'] data = expr.get('data') if isinstance(data, OrderedDict): - data = self._make_implicit_object_type(name, 'arg', - self._make_members(data)) + data = self._make_implicit_object_type( + name, info, 'arg', self._make_members(data, info)) self._def_entity(QAPISchemaEvent(name, info, data)) def _def_exprs(self): -- cgit v1.2.3