qapi: expose all schema features to code

This replaces use of the constants from the QapiSpecialFeatures
enum, with constants from the auto-generate QapiFeatures enum
in qapi-features.h

The 'deprecated' and 'unstable' features still have a little bit of
special handling, being force defined to be the 1st + 2nd features
in the enum, regardless of whether they're used in the schema. This
retains compatibility with common code that references the features
via the QapiSpecialFeatures constants.

Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Message-ID: <20250205123550.2754387-5-berrange@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
[Imports tidied up with isort]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
This commit is contained in:
Daniel P. Berrangé 2025-02-05 12:35:50 +00:00 committed by Markus Armbruster
parent ba27dccc04
commit 2ebb09f34f
13 changed files with 110 additions and 7 deletions

View file

@ -29,6 +29,7 @@ from typing import (
List,
Optional,
Union,
ValuesView,
cast,
)
@ -933,8 +934,11 @@ class QAPISchemaEnumMember(QAPISchemaMember):
class QAPISchemaFeature(QAPISchemaMember):
role = 'feature'
# Features which are standardized across all schemas
SPECIAL_NAMES = ['deprecated', 'unstable']
def is_special(self) -> bool:
return self.name in ('deprecated', 'unstable')
return self.name in QAPISchemaFeature.SPECIAL_NAMES
class QAPISchemaObjectTypeMember(QAPISchemaMember):
@ -1138,6 +1142,16 @@ class QAPISchema:
self._entity_list: List[QAPISchemaEntity] = []
self._entity_dict: Dict[str, QAPISchemaDefinition] = {}
self._module_dict: Dict[str, QAPISchemaModule] = OrderedDict()
# NB, values in the dict will identify the first encountered
# usage of a named feature only
self._feature_dict: Dict[str, QAPISchemaFeature] = OrderedDict()
# All schemas get the names defined in the QapiSpecialFeature enum.
# Rely on dict iteration order matching insertion order so that
# the special names are emitted first when generating code.
for f in QAPISchemaFeature.SPECIAL_NAMES:
self._feature_dict[f] = QAPISchemaFeature(f, None)
self._schema_dir = os.path.dirname(fname)
self._make_module(QAPISchemaModule.BUILTIN_MODULE_NAME)
self._make_module(fname)
@ -1147,6 +1161,9 @@ class QAPISchema:
self._def_exprs(exprs)
self.check()
def features(self) -> ValuesView[QAPISchemaFeature]:
return self._feature_dict.values()
def _def_entity(self, ent: QAPISchemaEntity) -> None:
self._entity_list.append(ent)
@ -1258,6 +1275,12 @@ class QAPISchema:
) -> List[QAPISchemaFeature]:
if features is None:
return []
for f in features:
feat = QAPISchemaFeature(f['name'], info)
if feat.name not in self._feature_dict:
self._feature_dict[feat.name] = feat
return [QAPISchemaFeature(f['name'], info,
QAPISchemaIfCond(f.get('if')))
for f in features]
@ -1485,6 +1508,12 @@ class QAPISchema:
for doc in self.docs:
doc.check()
features = list(self._feature_dict.values())
if len(features) > 64:
raise QAPISemError(
features[64].info,
"Maximum of 64 schema features is permitted")
def visit(self, visitor: QAPISchemaVisitor) -> None:
visitor.visit_begin(self)
for mod in self._module_dict.values():