From adcb9b36c9b0a63e3b0cf81994430cfb0d720571 Mon Sep 17 00:00:00 2001 From: John Snow Date: Fri, 9 Oct 2020 12:15:24 -0400 Subject: qapi: modify docstrings to be sphinx-compatible A precise style guide and a package-wide overhaul is forthcoming pending further discussion and consensus. For now, merely avoid obvious errors that cause Sphinx documentation build problems, using a style loosely based on PEP 257 and Sphinx Autodoc. It is chosen for interoperability with our existing Sphinx framework, and because it has loose recognition in the Pycharm IDE. See also: https://www.python.org/dev/peps/pep-0257/ https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#info-field-lists Signed-off-by: John Snow Message-Id: <20201009161558.107041-3-jsnow@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- scripts/qapi/gen.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'scripts/qapi/gen.py') diff --git a/scripts/qapi/gen.py b/scripts/qapi/gen.py index ca66c82b5b..dc7b94aa11 100644 --- a/scripts/qapi/gen.py +++ b/scripts/qapi/gen.py @@ -154,9 +154,11 @@ class QAPIGenH(QAPIGenC): @contextmanager def ifcontext(ifcond, *args): - """A 'with' statement context manager to wrap with start_if()/end_if() + """ + A with-statement context manager that wraps with `start_if()` / `end_if()`. - *args: any number of QAPIGenCCode + :param ifcond: A list of conditionals, passed to `start_if()`. + :param args: any number of `QAPIGenCCode`. Example:: -- cgit 1.4.1 From 7137a96099644734cd6045313823840d4cecd5e8 Mon Sep 17 00:00:00 2001 From: John Snow Date: Fri, 9 Oct 2020 12:15:27 -0400 Subject: qapi: Prefer explicit relative imports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All of the QAPI include statements are changed to be package-aware, as explicit relative imports. A quirk of Python packages is that the name of the package exists only *outside* of the package. This means that to a module inside of the qapi folder, there is inherently no such thing as the "qapi" package. The reason these imports work is because the "qapi" package exists in the context of the caller -- the execution shim, where sys.path includes a directory that has a 'qapi' folder in it. When we write "from qapi import sibling", we are NOT referencing the folder 'qapi', but rather "any package named qapi in sys.path". If you should so happen to have a 'qapi' package in your path, it will use *that* package. When we write "from .sibling import foo", we always reference explicitly our sibling module; guaranteeing consistency in *where* we are importing these modules from. This can be useful when working with virtual environments and packages in development mode. In development mode, a package is installed as a series of symlinks that forwards to your same source files. The problem arises because code quality checkers will follow "import qapi.x" to the "installed" version instead of the sibling file and -- even though they are the same file -- they have different module paths, and this causes cyclic import problems, false positive type mismatch errors, and more. It can also be useful when dealing with hierarchical packages, e.g. if we allow qemu.core.qmp, qemu.qapi.parser, etc. Signed-off-by: John Snow Reviewed-by: Eduardo Habkost Reviewed-by: Cleber Rosa Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20201009161558.107041-6-jsnow@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- scripts/qapi/commands.py | 4 ++-- scripts/qapi/events.py | 8 ++++---- scripts/qapi/expr.py | 4 ++-- scripts/qapi/gen.py | 4 ++-- scripts/qapi/introspect.py | 8 ++++---- scripts/qapi/main.py | 14 +++++++------- scripts/qapi/parser.py | 4 ++-- scripts/qapi/schema.py | 8 ++++---- scripts/qapi/types.py | 6 +++--- scripts/qapi/visit.py | 6 +++--- 10 files changed, 33 insertions(+), 33 deletions(-) (limited to 'scripts/qapi/gen.py') diff --git a/scripts/qapi/commands.py b/scripts/qapi/commands.py index 6e6fc94a14..1f43a0a34e 100644 --- a/scripts/qapi/commands.py +++ b/scripts/qapi/commands.py @@ -13,8 +13,8 @@ This work is licensed under the terms of the GNU GPL, version 2. See the COPYING file in the top-level directory. """ -from qapi.common import * -from qapi.gen import QAPIGenCCode, QAPISchemaModularCVisitor, ifcontext +from .common import * +from .gen import QAPIGenCCode, QAPISchemaModularCVisitor, ifcontext def gen_command_decl(name, arg_type, boxed, ret_type): diff --git a/scripts/qapi/events.py b/scripts/qapi/events.py index b544af5a1c..0467272438 100644 --- a/scripts/qapi/events.py +++ b/scripts/qapi/events.py @@ -12,10 +12,10 @@ This work is licensed under the terms of the GNU GPL, version 2. See the COPYING file in the top-level directory. """ -from qapi.common import * -from qapi.gen import QAPISchemaModularCVisitor, ifcontext -from qapi.schema import QAPISchemaEnumMember -from qapi.types import gen_enum, gen_enum_lookup +from .common import * +from .gen import QAPISchemaModularCVisitor, ifcontext +from .schema import QAPISchemaEnumMember +from .types import gen_enum, gen_enum_lookup def build_event_send_proto(name, arg_type, boxed): diff --git a/scripts/qapi/expr.py b/scripts/qapi/expr.py index a15c1fb474..bb4dc55f56 100644 --- a/scripts/qapi/expr.py +++ b/scripts/qapi/expr.py @@ -16,8 +16,8 @@ import re from collections import OrderedDict -from qapi.common import c_name -from qapi.error import QAPISemError +from .common import c_name +from .error import QAPISemError # Names must be letters, numbers, -, and _. They must start with letter, diff --git a/scripts/qapi/gen.py b/scripts/qapi/gen.py index dc7b94aa11..fc57fdca5b 100644 --- a/scripts/qapi/gen.py +++ b/scripts/qapi/gen.py @@ -17,8 +17,8 @@ import os import re from contextlib import contextmanager -from qapi.common import * -from qapi.schema import QAPISchemaVisitor +from .common import * +from .schema import QAPISchemaVisitor class QAPIGen: diff --git a/scripts/qapi/introspect.py b/scripts/qapi/introspect.py index 5907b09cd5..6c82d9d95f 100644 --- a/scripts/qapi/introspect.py +++ b/scripts/qapi/introspect.py @@ -10,10 +10,10 @@ This work is licensed under the terms of the GNU GPL, version 2. See the COPYING file in the top-level directory. """ -from qapi.common import * -from qapi.gen import QAPISchemaMonolithicCVisitor -from qapi.schema import (QAPISchemaArrayType, QAPISchemaBuiltinType, - QAPISchemaType) +from .common import * +from .gen import QAPISchemaMonolithicCVisitor +from .schema import (QAPISchemaArrayType, QAPISchemaBuiltinType, + QAPISchemaType) def _make_tree(obj, ifcond, features, extra=None): diff --git a/scripts/qapi/main.py b/scripts/qapi/main.py index 92a2a31ca1..42517210b8 100644 --- a/scripts/qapi/main.py +++ b/scripts/qapi/main.py @@ -12,13 +12,13 @@ import re import sys from typing import Optional -from qapi.commands import gen_commands -from qapi.error import QAPIError -from qapi.events import gen_events -from qapi.introspect import gen_introspect -from qapi.schema import QAPISchema -from qapi.types import gen_types -from qapi.visit import gen_visit +from .commands import gen_commands +from .error import QAPIError +from .events import gen_events +from .introspect import gen_introspect +from .schema import QAPISchema +from .types import gen_types +from .visit import gen_visit def invalid_prefix_char(prefix: str) -> Optional[str]: diff --git a/scripts/qapi/parser.py b/scripts/qapi/parser.py index 9d1a3e2eea..7298f5dbd1 100644 --- a/scripts/qapi/parser.py +++ b/scripts/qapi/parser.py @@ -18,8 +18,8 @@ import os import re from collections import OrderedDict -from qapi.error import QAPIParseError, QAPISemError -from qapi.source import QAPISourceInfo +from .error import QAPIParseError, QAPISemError +from .source import QAPISourceInfo class QAPISchemaParser: diff --git a/scripts/qapi/schema.py b/scripts/qapi/schema.py index d1307ec661..676185d1a7 100644 --- a/scripts/qapi/schema.py +++ b/scripts/qapi/schema.py @@ -18,10 +18,10 @@ import os import re from collections import OrderedDict -from qapi.common import c_name, pointer_suffix -from qapi.error import QAPIError, QAPISemError -from qapi.expr import check_exprs -from qapi.parser import QAPISchemaParser +from .common import c_name, pointer_suffix +from .error import QAPIError, QAPISemError +from .expr import check_exprs +from .parser import QAPISchemaParser class QAPISchemaEntity: diff --git a/scripts/qapi/types.py b/scripts/qapi/types.py index 3640f17cd6..ca9a5aacb3 100644 --- a/scripts/qapi/types.py +++ b/scripts/qapi/types.py @@ -13,9 +13,9 @@ This work is licensed under the terms of the GNU GPL, version 2. # See the COPYING file in the top-level directory. """ -from qapi.common import * -from qapi.gen import QAPISchemaModularCVisitor, ifcontext -from qapi.schema import QAPISchemaEnumMember, QAPISchemaObjectType +from .common import * +from .gen import QAPISchemaModularCVisitor, ifcontext +from .schema import QAPISchemaEnumMember, QAPISchemaObjectType # variants must be emitted before their container; track what has already diff --git a/scripts/qapi/visit.py b/scripts/qapi/visit.py index cdabc5fa28..7850f6e848 100644 --- a/scripts/qapi/visit.py +++ b/scripts/qapi/visit.py @@ -13,9 +13,9 @@ This work is licensed under the terms of the GNU GPL, version 2. See the COPYING file in the top-level directory. """ -from qapi.common import * -from qapi.gen import QAPISchemaModularCVisitor, ifcontext -from qapi.schema import QAPISchemaObjectType +from .common import * +from .gen import QAPISchemaModularCVisitor, ifcontext +from .schema import QAPISchemaObjectType def gen_visit_decl(name, scalar=False): -- cgit 1.4.1 From 5af8263d40c698c47befd4c0bed3d6c452b56d82 Mon Sep 17 00:00:00 2001 From: John Snow Date: Fri, 9 Oct 2020 12:15:28 -0400 Subject: qapi: Remove wildcard includes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wildcard includes become hard to manage when refactoring and dealing with circular dependencies with strictly typed mypy. flake8 also flags each one as a warning, as it is not smart enough to know which names exist in the imported file. Remove them and include things explicitly by name instead. Signed-off-by: John Snow Reviewed-by: Eduardo Habkost Reviewed-by: Cleber Rosa Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20201009161558.107041-7-jsnow@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- scripts/qapi/commands.py | 2 +- scripts/qapi/events.py | 7 ++++++- scripts/qapi/gen.py | 12 +++++++++--- scripts/qapi/introspect.py | 7 ++++++- scripts/qapi/types.py | 8 +++++++- scripts/qapi/visit.py | 10 +++++++++- 6 files changed, 38 insertions(+), 8 deletions(-) (limited to 'scripts/qapi/gen.py') diff --git a/scripts/qapi/commands.py b/scripts/qapi/commands.py index 1f43a0a34e..e06c10afcd 100644 --- a/scripts/qapi/commands.py +++ b/scripts/qapi/commands.py @@ -13,7 +13,7 @@ This work is licensed under the terms of the GNU GPL, version 2. See the COPYING file in the top-level directory. """ -from .common import * +from .common import build_params, c_name, mcgen from .gen import QAPIGenCCode, QAPISchemaModularCVisitor, ifcontext diff --git a/scripts/qapi/events.py b/scripts/qapi/events.py index 0467272438..6b3afa14d7 100644 --- a/scripts/qapi/events.py +++ b/scripts/qapi/events.py @@ -12,7 +12,12 @@ This work is licensed under the terms of the GNU GPL, version 2. See the COPYING file in the top-level directory. """ -from .common import * +from .common import ( + build_params, + c_enum_const, + c_name, + mcgen, +) from .gen import QAPISchemaModularCVisitor, ifcontext from .schema import QAPISchemaEnumMember from .types import gen_enum, gen_enum_lookup diff --git a/scripts/qapi/gen.py b/scripts/qapi/gen.py index fc57fdca5b..1fed712b43 100644 --- a/scripts/qapi/gen.py +++ b/scripts/qapi/gen.py @@ -11,13 +11,19 @@ # This work is licensed under the terms of the GNU GPL, version 2. # See the COPYING file in the top-level directory. - +from contextlib import contextmanager import errno import os import re -from contextlib import contextmanager -from .common import * +from .common import ( + c_fname, + gen_endif, + gen_if, + guardend, + guardstart, + mcgen, +) from .schema import QAPISchemaVisitor diff --git a/scripts/qapi/introspect.py b/scripts/qapi/introspect.py index 6c82d9d95f..42016a7e66 100644 --- a/scripts/qapi/introspect.py +++ b/scripts/qapi/introspect.py @@ -10,7 +10,12 @@ This work is licensed under the terms of the GNU GPL, version 2. See the COPYING file in the top-level directory. """ -from .common import * +from .common import ( + c_name, + gen_endif, + gen_if, + mcgen, +) from .gen import QAPISchemaMonolithicCVisitor from .schema import (QAPISchemaArrayType, QAPISchemaBuiltinType, QAPISchemaType) diff --git a/scripts/qapi/types.py b/scripts/qapi/types.py index ca9a5aacb3..53b47f9e58 100644 --- a/scripts/qapi/types.py +++ b/scripts/qapi/types.py @@ -13,7 +13,13 @@ This work is licensed under the terms of the GNU GPL, version 2. # See the COPYING file in the top-level directory. """ -from .common import * +from .common import ( + c_enum_const, + c_name, + gen_endif, + gen_if, + mcgen, +) from .gen import QAPISchemaModularCVisitor, ifcontext from .schema import QAPISchemaEnumMember, QAPISchemaObjectType diff --git a/scripts/qapi/visit.py b/scripts/qapi/visit.py index 7850f6e848..ea277e7704 100644 --- a/scripts/qapi/visit.py +++ b/scripts/qapi/visit.py @@ -13,7 +13,15 @@ This work is licensed under the terms of the GNU GPL, version 2. See the COPYING file in the top-level directory. """ -from .common import * +from .common import ( + c_enum_const, + c_name, + gen_endif, + gen_if, + mcgen, + pop_indent, + push_indent, +) from .gen import QAPISchemaModularCVisitor, ifcontext from .schema import QAPISchemaObjectType -- cgit 1.4.1 From e6a34cd7a440e6ba04251612aa6eb036d3c47d98 Mon Sep 17 00:00:00 2001 From: John Snow Date: Fri, 9 Oct 2020 12:15:39 -0400 Subject: qapi/common.py: move build_params into gen.py Including it in common.py creates a circular import dependency; schema relies on common, but common.build_params requires a type annotation from schema. To type this properly, it needs to be moved outside the cycle. Signed-off-by: John Snow Reviewed-by: Eduardo Habkost Reviewed-by: Cleber Rosa Message-Id: <20201009161558.107041-18-jsnow@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- scripts/qapi/commands.py | 9 +++++++-- scripts/qapi/common.py | 23 ----------------------- scripts/qapi/events.py | 9 ++------- scripts/qapi/gen.py | 29 +++++++++++++++++++++++++++-- 4 files changed, 36 insertions(+), 34 deletions(-) (limited to 'scripts/qapi/gen.py') diff --git a/scripts/qapi/commands.py b/scripts/qapi/commands.py index cde0c1e777..88ba11c40e 100644 --- a/scripts/qapi/commands.py +++ b/scripts/qapi/commands.py @@ -13,8 +13,13 @@ This work is licensed under the terms of the GNU GPL, version 2. See the COPYING file in the top-level directory. """ -from .common import build_params, c_name, mcgen -from .gen import QAPIGenCCode, QAPISchemaModularCVisitor, ifcontext +from .common import c_name, mcgen +from .gen import ( + QAPIGenCCode, + QAPISchemaModularCVisitor, + build_params, + ifcontext, +) def gen_command_decl(name, arg_type, boxed, ret_type): diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py index 669e3829b3..11b86beeab 100644 --- a/scripts/qapi/common.py +++ b/scripts/qapi/common.py @@ -210,26 +210,3 @@ def gen_endif(ifcond: Sequence[str]) -> str: #endif /* %(cond)s */ ''', cond=ifc) return ret - - -def build_params(arg_type, - boxed: bool, - extra: Optional[str] = None) -> str: - ret = '' - sep = '' - if boxed: - assert arg_type - ret += '%s arg' % arg_type.c_param_type() - sep = ', ' - elif arg_type: - assert not arg_type.variants - for memb in arg_type.members: - ret += sep - sep = ', ' - if memb.optional: - ret += 'bool has_%s, ' % c_name(memb.name) - ret += '%s %s' % (memb.type.c_param_type(), - c_name(memb.name)) - if extra: - ret += sep + extra - return ret if ret else 'void' diff --git a/scripts/qapi/events.py b/scripts/qapi/events.py index 6b3afa14d7..f840a62ed9 100644 --- a/scripts/qapi/events.py +++ b/scripts/qapi/events.py @@ -12,13 +12,8 @@ This work is licensed under the terms of the GNU GPL, version 2. See the COPYING file in the top-level directory. """ -from .common import ( - build_params, - c_enum_const, - c_name, - mcgen, -) -from .gen import QAPISchemaModularCVisitor, ifcontext +from .common import c_enum_const, c_name, mcgen +from .gen import QAPISchemaModularCVisitor, build_params, ifcontext from .schema import QAPISchemaEnumMember from .types import gen_enum, gen_enum_lookup diff --git a/scripts/qapi/gen.py b/scripts/qapi/gen.py index 1fed712b43..fff0c0acb6 100644 --- a/scripts/qapi/gen.py +++ b/scripts/qapi/gen.py @@ -2,7 +2,7 @@ # # QAPI code generation # -# Copyright (c) 2018-2019 Red Hat Inc. +# Copyright (c) 2015-2019 Red Hat Inc. # # Authors: # Markus Armbruster @@ -15,16 +15,18 @@ from contextlib import contextmanager import errno import os import re +from typing import Optional from .common import ( c_fname, + c_name, gen_endif, gen_if, guardend, guardstart, mcgen, ) -from .schema import QAPISchemaVisitor +from .schema import QAPISchemaObjectType, QAPISchemaVisitor class QAPIGen: @@ -90,6 +92,29 @@ def _wrap_ifcond(ifcond, before, after): return out +def build_params(arg_type: Optional[QAPISchemaObjectType], + boxed: bool, + extra: Optional[str] = None) -> str: + ret = '' + sep = '' + if boxed: + assert arg_type + ret += '%s arg' % arg_type.c_param_type() + sep = ', ' + elif arg_type: + assert not arg_type.variants + for memb in arg_type.members: + ret += sep + sep = ', ' + if memb.optional: + ret += 'bool has_%s, ' % c_name(memb.name) + ret += '%s %s' % (memb.type.c_param_type(), + c_name(memb.name)) + if extra: + ret += sep + extra + return ret if ret else 'void' + + class QAPIGenCCode(QAPIGen): def __init__(self, fname): -- cgit 1.4.1 From 3ae1c848516d92531a73f2e7f1799c3572f680c5 Mon Sep 17 00:00:00 2001 From: John Snow Date: Fri, 9 Oct 2020 12:15:48 -0400 Subject: qapi/gen: Make _is_user_module() return bool MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit _is_user_module() returns thruth values. The next commit wants it to return bool. Make it so. Signed-off-by: John Snow Reviewed-by: Cleber Rosa Reviewed-by: Eduardo Habkost Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20201009161558.107041-27-jsnow@redhat.com> Reviewed-by: Markus Armbruster [Commit message rewritten] Signed-off-by: Markus Armbruster --- scripts/qapi/gen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'scripts/qapi/gen.py') diff --git a/scripts/qapi/gen.py b/scripts/qapi/gen.py index fff0c0acb6..2c305c4f82 100644 --- a/scripts/qapi/gen.py +++ b/scripts/qapi/gen.py @@ -241,7 +241,7 @@ class QAPISchemaModularCVisitor(QAPISchemaVisitor): @staticmethod def _is_user_module(name): - return name and not name.startswith('./') + return bool(name and not name.startswith('./')) @staticmethod def _is_builtin_module(name): -- cgit 1.4.1 From 17d40c395748dab4cd579d698b89ba6f51ffb692 Mon Sep 17 00:00:00 2001 From: John Snow Date: Fri, 9 Oct 2020 12:15:49 -0400 Subject: qapi/gen.py: add type hint annotations Annotations do not change runtime behavior. This commit *only* adds annotations. Signed-off-by: John Snow Reviewed-by: Eduardo Habkost Reviewed-by: Cleber Rosa Message-Id: <20201009161558.107041-28-jsnow@redhat.com> Message-Id: <20201009161558.107041-29-jsnow@redhat.com> [mypy.ini update squashed in] Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- scripts/qapi/gen.py | 104 +++++++++++++++++++++++++++----------------------- scripts/qapi/mypy.ini | 5 --- 2 files changed, 57 insertions(+), 52 deletions(-) (limited to 'scripts/qapi/gen.py') diff --git a/scripts/qapi/gen.py b/scripts/qapi/gen.py index 2c305c4f82..6b1007a035 100644 --- a/scripts/qapi/gen.py +++ b/scripts/qapi/gen.py @@ -15,7 +15,13 @@ from contextlib import contextmanager import errno import os import re -from typing import Optional +from typing import ( + Dict, + Iterator, + List, + Optional, + Tuple, +) from .common import ( c_fname, @@ -27,31 +33,31 @@ from .common import ( mcgen, ) from .schema import QAPISchemaObjectType, QAPISchemaVisitor +from .source import QAPISourceInfo class QAPIGen: - - def __init__(self, fname): + def __init__(self, fname: Optional[str]): self.fname = fname self._preamble = '' self._body = '' - def preamble_add(self, text): + def preamble_add(self, text: str) -> None: self._preamble += text - def add(self, text): + def add(self, text: str) -> None: self._body += text - def get_content(self): + def get_content(self) -> str: return self._top() + self._preamble + self._body + self._bottom() - def _top(self): + def _top(self) -> str: return '' - def _bottom(self): + def _bottom(self) -> str: return '' - def write(self, output_dir): + def write(self, output_dir: str) -> None: # Include paths starting with ../ are used to reuse modules of the main # schema in specialised schemas. Don't overwrite the files that are # already generated for the main schema. @@ -76,7 +82,7 @@ class QAPIGen: f.close() -def _wrap_ifcond(ifcond, before, after): +def _wrap_ifcond(ifcond: List[str], before: str, after: str) -> str: if before == after: return after # suppress empty #if ... #endif @@ -116,40 +122,38 @@ def build_params(arg_type: Optional[QAPISchemaObjectType], class QAPIGenCCode(QAPIGen): - - def __init__(self, fname): + def __init__(self, fname: Optional[str]): super().__init__(fname) - self._start_if = None + self._start_if: Optional[Tuple[List[str], str, str]] = None - def start_if(self, ifcond): + def start_if(self, ifcond: List[str]) -> None: assert self._start_if is None self._start_if = (ifcond, self._body, self._preamble) - def end_if(self): + def end_if(self) -> None: assert self._start_if self._wrap_ifcond() self._start_if = None - def _wrap_ifcond(self): + def _wrap_ifcond(self) -> None: self._body = _wrap_ifcond(self._start_if[0], self._start_if[1], self._body) self._preamble = _wrap_ifcond(self._start_if[0], self._start_if[2], self._preamble) - def get_content(self): + def get_content(self) -> str: assert self._start_if is None return super().get_content() class QAPIGenC(QAPIGenCCode): - - def __init__(self, fname, blurb, pydoc): + def __init__(self, fname: str, blurb: str, pydoc: str): super().__init__(fname) self._blurb = blurb self._copyright = '\n * '.join(re.findall(r'^Copyright .*', pydoc, re.MULTILINE)) - def _top(self): + def _top(self) -> str: return mcgen(''' /* AUTOMATICALLY GENERATED, DO NOT MODIFY */ @@ -165,7 +169,7 @@ class QAPIGenC(QAPIGenCCode): ''', blurb=self._blurb, copyright=self._copyright) - def _bottom(self): + def _bottom(self) -> str: return mcgen(''' /* Dummy declaration to prevent empty .o file */ @@ -175,16 +179,15 @@ char qapi_dummy_%(name)s; class QAPIGenH(QAPIGenC): - - def _top(self): + def _top(self) -> str: return super()._top() + guardstart(self.fname) - def _bottom(self): + def _bottom(self) -> str: return guardend(self.fname) @contextmanager -def ifcontext(ifcond, *args): +def ifcontext(ifcond: List[str], *args: QAPIGenCCode) -> Iterator[None]: """ A with-statement context manager that wraps with `start_if()` / `end_if()`. @@ -212,8 +215,11 @@ def ifcontext(ifcond, *args): class QAPISchemaMonolithicCVisitor(QAPISchemaVisitor): - - def __init__(self, prefix, what, blurb, pydoc): + def __init__(self, + prefix: str, + what: str, + blurb: str, + pydoc: str): self._prefix = prefix self._what = what self._genc = QAPIGenC(self._prefix + self._what + '.c', @@ -221,38 +227,42 @@ class QAPISchemaMonolithicCVisitor(QAPISchemaVisitor): self._genh = QAPIGenH(self._prefix + self._what + '.h', blurb, pydoc) - def write(self, output_dir): + def write(self, output_dir: str) -> None: self._genc.write(output_dir) self._genh.write(output_dir) class QAPISchemaModularCVisitor(QAPISchemaVisitor): - - def __init__(self, prefix, what, user_blurb, builtin_blurb, pydoc): + def __init__(self, + prefix: str, + what: str, + user_blurb: str, + builtin_blurb: Optional[str], + pydoc: str): self._prefix = prefix self._what = what self._user_blurb = user_blurb self._builtin_blurb = builtin_blurb self._pydoc = pydoc - self._genc = None - self._genh = None - self._module = {} - self._main_module = None + self._genc: Optional[QAPIGenC] = None + self._genh: Optional[QAPIGenH] = None + self._module: Dict[Optional[str], Tuple[QAPIGenC, QAPIGenH]] = {} + self._main_module: Optional[str] = None @staticmethod - def _is_user_module(name): + def _is_user_module(name: Optional[str]) -> bool: return bool(name and not name.startswith('./')) @staticmethod - def _is_builtin_module(name): + def _is_builtin_module(name: Optional[str]) -> bool: return not name - def _module_dirname(self, what, name): + def _module_dirname(self, what: str, name: Optional[str]) -> str: if self._is_user_module(name): return os.path.dirname(name) return '' - def _module_basename(self, what, name): + def _module_basename(self, what: str, name: Optional[str]) -> str: ret = '' if self._is_builtin_module(name) else self._prefix if self._is_user_module(name): basename = os.path.basename(name) @@ -264,27 +274,27 @@ class QAPISchemaModularCVisitor(QAPISchemaVisitor): ret += re.sub(r'-', '-' + name + '-', what) return ret - def _module_filename(self, what, name): + def _module_filename(self, what: str, name: Optional[str]) -> str: return os.path.join(self._module_dirname(what, name), self._module_basename(what, name)) - def _add_module(self, name, blurb): + def _add_module(self, name: Optional[str], blurb: str) -> None: basename = self._module_filename(self._what, name) genc = QAPIGenC(basename + '.c', blurb, self._pydoc) genh = QAPIGenH(basename + '.h', blurb, self._pydoc) self._module[name] = (genc, genh) self._genc, self._genh = self._module[name] - def _add_user_module(self, name, blurb): + def _add_user_module(self, name: str, blurb: str) -> None: assert self._is_user_module(name) if self._main_module is None: self._main_module = name self._add_module(name, blurb) - def _add_system_module(self, name, blurb): + def _add_system_module(self, name: Optional[str], blurb: str) -> None: self._add_module(name and './' + name, blurb) - def write(self, output_dir, opt_builtins=False): + def write(self, output_dir: str, opt_builtins: bool = False) -> None: for name in self._module: if self._is_builtin_module(name) and not opt_builtins: continue @@ -292,13 +302,13 @@ class QAPISchemaModularCVisitor(QAPISchemaVisitor): genc.write(output_dir) genh.write(output_dir) - def _begin_system_module(self, name): + def _begin_system_module(self, name: None) -> None: pass - def _begin_user_module(self, name): + def _begin_user_module(self, name: str) -> None: pass - def visit_module(self, name): + def visit_module(self, name: Optional[str]) -> None: if name is None: if self._builtin_blurb: self._add_system_module(None, self._builtin_blurb) @@ -312,7 +322,7 @@ class QAPISchemaModularCVisitor(QAPISchemaVisitor): self._add_user_module(name, self._user_blurb) self._begin_user_module(name) - def visit_include(self, name, info): + def visit_include(self, name: str, info: QAPISourceInfo) -> None: relname = os.path.relpath(self._module_filename(self._what, name), os.path.dirname(self._genh.fname)) self._genh.preamble_add(mcgen(''' diff --git a/scripts/qapi/mypy.ini b/scripts/qapi/mypy.ini index 1b8555dfa3..c6960ff2db 100644 --- a/scripts/qapi/mypy.ini +++ b/scripts/qapi/mypy.ini @@ -14,11 +14,6 @@ disallow_untyped_defs = False disallow_incomplete_defs = False check_untyped_defs = False -[mypy-qapi.gen] -disallow_untyped_defs = False -disallow_incomplete_defs = False -check_untyped_defs = False - [mypy-qapi.introspect] disallow_untyped_defs = False disallow_incomplete_defs = False -- cgit 1.4.1 From 0cbd5b0516814a07004d6bd22e5c323f8314273f Mon Sep 17 00:00:00 2001 From: John Snow Date: Fri, 9 Oct 2020 12:15:51 -0400 Subject: qapi/gen.py: Remove unused parameter _module_dirname doesn't use the 'what' argument, so remove it. Signed-off-by: John Snow Reviewed-by: Eduardo Habkost Reviewed-by: Cleber Rosa Message-Id: <20201009161558.107041-30-jsnow@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- scripts/qapi/gen.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'scripts/qapi/gen.py') diff --git a/scripts/qapi/gen.py b/scripts/qapi/gen.py index 6b1007a035..8b851c6262 100644 --- a/scripts/qapi/gen.py +++ b/scripts/qapi/gen.py @@ -257,7 +257,7 @@ class QAPISchemaModularCVisitor(QAPISchemaVisitor): def _is_builtin_module(name: Optional[str]) -> bool: return not name - def _module_dirname(self, what: str, name: Optional[str]) -> str: + def _module_dirname(self, name: Optional[str]) -> str: if self._is_user_module(name): return os.path.dirname(name) return '' @@ -275,7 +275,7 @@ class QAPISchemaModularCVisitor(QAPISchemaVisitor): return ret def _module_filename(self, what: str, name: Optional[str]) -> str: - return os.path.join(self._module_dirname(what, name), + return os.path.join(self._module_dirname(name), self._module_basename(what, name)) def _add_module(self, name: Optional[str], blurb: str) -> None: -- cgit 1.4.1 From cc6263c44b3ad70a8cb884518e78e70c17f180d0 Mon Sep 17 00:00:00 2001 From: John Snow Date: Fri, 9 Oct 2020 12:15:52 -0400 Subject: qapi/gen.py: update write() to be more idiomatic Make the file handling here just a tiny bit more idiomatic. (I realize this is heavily subjective.) Use exist_ok=True for os.makedirs and remove the exception, use fdopen() to wrap the file descriptor in a File-like object, and use a context manager for managing the file pointer. Signed-off-by: John Snow Reviewed-by: Eduardo Habkost Reviewed-by: Cleber Rosa Reviewed-by: Markus Armbruster Message-Id: <20201009161558.107041-31-jsnow@redhat.com> Signed-off-by: Markus Armbruster --- scripts/qapi/gen.py | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) (limited to 'scripts/qapi/gen.py') diff --git a/scripts/qapi/gen.py b/scripts/qapi/gen.py index 8b851c6262..670c21e210 100644 --- a/scripts/qapi/gen.py +++ b/scripts/qapi/gen.py @@ -12,7 +12,6 @@ # See the COPYING file in the top-level directory. from contextlib import contextmanager -import errno import os import re from typing import ( @@ -65,21 +64,19 @@ class QAPIGen: return pathname = os.path.join(output_dir, self.fname) odir = os.path.dirname(pathname) + if odir: - try: - os.makedirs(odir) - except os.error as e: - if e.errno != errno.EEXIST: - raise + os.makedirs(odir, exist_ok=True) + + # use os.open for O_CREAT to create and read a non-existant file fd = os.open(pathname, os.O_RDWR | os.O_CREAT, 0o666) - f = open(fd, 'r+', encoding='utf-8') - text = self.get_content() - oldtext = f.read(len(text) + 1) - if text != oldtext: - f.seek(0) - f.truncate(0) - f.write(text) - f.close() + with os.fdopen(fd, 'r+', encoding='utf-8') as fp: + text = self.get_content() + oldtext = fp.read(len(text) + 1) + if text != oldtext: + fp.seek(0) + fp.truncate(0) + fp.write(text) def _wrap_ifcond(ifcond: List[str], before: str, after: str) -> str: -- cgit 1.4.1 From 9abddb5be44245e8529a8c132a16176fc63d0df6 Mon Sep 17 00:00:00 2001 From: John Snow Date: Fri, 9 Oct 2020 12:15:53 -0400 Subject: qapi/gen.py: delint with pylint 'fp' and 'fd' are self-evident in context, add them to the list of OK names. _top and _bottom also need to stay standard methods because some users override the method and need to use `self`. Tell pylint to shush. Signed-off-by: John Snow Reviewed-by: Eduardo Habkost Reviewed-by: Cleber Rosa Message-Id: <20201009161558.107041-32-jsnow@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- scripts/qapi/gen.py | 2 ++ scripts/qapi/pylintrc | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'scripts/qapi/gen.py') diff --git a/scripts/qapi/gen.py b/scripts/qapi/gen.py index 670c21e210..b40f18eee3 100644 --- a/scripts/qapi/gen.py +++ b/scripts/qapi/gen.py @@ -51,9 +51,11 @@ class QAPIGen: return self._top() + self._preamble + self._body + self._bottom() def _top(self) -> str: + # pylint: disable=no-self-use return '' def _bottom(self) -> str: + # pylint: disable=no-self-use return '' def write(self, output_dir: str) -> None: diff --git a/scripts/qapi/pylintrc b/scripts/qapi/pylintrc index d840b15031..8badcb11cd 100644 --- a/scripts/qapi/pylintrc +++ b/scripts/qapi/pylintrc @@ -4,7 +4,6 @@ # The regex matches against base names, not paths. ignore-patterns=error.py, expr.py, - gen.py, parser.py, schema.py, types.py, @@ -45,7 +44,9 @@ good-names=i, k, ex, Run, - _ + _, + fp, # fp = open(...) + fd, # fd = os.open(...) [VARIABLES] -- cgit 1.4.1