From 800877bb1639d38ffaebe312a37b61c66bb10c83 Mon Sep 17 00:00:00 2001 From: Anton Nefedov Date: Mon, 18 Jun 2018 11:40:05 +0300 Subject: qapi: allow empty branches in flat unions It often happens that just a few discriminator values imply extra data in a flat union. Existing checks did not make possible to leave other values uncovered. Such cases had to be worked around by either stating a dummy (empty) type or introducing another (subset) discriminator enumeration. Both options create redundant entities in qapi files for little profit. With this patch it is not necessary anymore to add designated union fields for every possible value of a discriminator enumeration. Signed-off-by: Anton Nefedov Message-Id: <1529311206-76847-2-git-send-email-anton.nefedov@virtuozzo.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- scripts/qapi/common.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'scripts/qapi/common.py') diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py index 2462fc0291..4b53f08627 100644 --- a/scripts/qapi/common.py +++ b/scripts/qapi/common.py @@ -779,13 +779,6 @@ def check_union(expr, info): "enum '%s'" % (key, enum_define['enum'])) - # If discriminator is user-defined, ensure all values are covered - if enum_define: - for value in enum_define['data']: - if value not in members.keys(): - raise QAPISemError(info, "Union '%s' data missing '%s' branch" - % (name, value)) - def check_alternate(expr, info): name = expr['alternate'] @@ -1357,6 +1350,14 @@ class QAPISchemaObjectTypeVariants(object): self.tag_member = seen[c_name(self._tag_name)] assert self._tag_name == self.tag_member.name assert isinstance(self.tag_member.type, QAPISchemaEnumType) + if self._tag_name: # flat union + # branches that are not explicitly covered get an empty type + cases = set([v.name for v in self.variants]) + for val in self.tag_member.type.values: + if val.name not in cases: + v = QAPISchemaObjectTypeVariant(val.name, 'q_empty') + v.set_owner(self.tag_member.owner) + self.variants.append(v) for v in self.variants: v.check(schema) # Union names must match enum values; alternate names are -- cgit v1.2.3-55-g7522 From de685ae5e9a4b523513033bd6cadc8187a227170 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 18 Jun 2018 19:59:57 +0200 Subject: qapi: Open files with encoding='utf-8' Python 2 happily reads UTF-8 files in text mode, but Python 3 requires either UTF-8 locale or an explicit encoding passed to open(). Commit d4e5ec877ca fixed this by setting the en_US.UTF-8 locale. Falls apart when the locale isn't be available. Matthias Maier and Arfrever Frehtes Taifersar Arahesis proposed to use binary mode instead, with manual conversion from bytes to str. Works, but opening with an explicit encoding is simpler, so do that. Since Python 2's open() doesn't support the encoding parameter, we need to suppress it with a version check. Reported-by: Arfrever Frehtes Taifersar Arahesis Reported-by: Matthias Maier Signed-off-by: Markus Armbruster Message-Id: <20180618175958.29073-2-armbru@redhat.com> Reviewed-by: Eduardo Habkost Reviewed-by: Eric Blake --- scripts/qapi/common.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'scripts/qapi/common.py') diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py index 4b53f08627..8b6708dbf1 100644 --- a/scripts/qapi/common.py +++ b/scripts/qapi/common.py @@ -16,6 +16,7 @@ import errno import os import re import string +import sys from collections import OrderedDict builtin_types = { @@ -340,7 +341,10 @@ class QAPISchemaParser(object): return None try: - fobj = open(incl_fname, 'r') + if sys.version_info[0] >= 3: + fobj = open(incl_fname, 'r', encoding='utf-8') + else: + fobj = open(incl_fname, 'r') except IOError as e: raise QAPISemError(info, '%s: %s' % (e.strerror, incl_fname)) return QAPISchemaParser(fobj, previously_included, info) @@ -1493,7 +1497,11 @@ class QAPISchemaEvent(QAPISchemaEntity): class QAPISchema(object): def __init__(self, fname): self._fname = fname - parser = QAPISchemaParser(open(fname, 'r')) + if sys.version_info[0] >= 3: + f = open(fname, 'r', encoding='utf-8') + else: + f = open(fname, 'r') + parser = QAPISchemaParser(f) exprs = check_exprs(parser.exprs) self.docs = parser.docs self._entity_list = [] @@ -2007,7 +2015,10 @@ class QAPIGen(object): if e.errno != errno.EEXIST: raise fd = os.open(pathname, os.O_RDWR | os.O_CREAT, 0o666) - f = os.fdopen(fd, 'r+') + if sys.version_info[0] >= 3: + f = open(fd, 'r+', encoding='utf-8') + else: + f = os.fdopen(fd, 'r+') text = (self._top(fname) + self._preamble + self._body + self._bottom(fname)) oldtext = f.read(len(text) + 1) -- cgit v1.2.3-55-g7522