Message ID | 20210422030720.3685766-10-jsnow@redhat.com |
---|---|
State | New |
Headers | show |
Series | qapi: static typing conversion, pt5a | expand |
John Snow <jsnow@redhat.com> writes: > Mypy cannot generally understand that these regex functions cannot > possibly fail. Add a _nofail helper that clarifies this for mypy. Convention wants a blank line here. > Signed-off-by: John Snow <jsnow@redhat.com> > --- > scripts/qapi/common.py | 8 +++++++- > scripts/qapi/main.py | 6 ++---- > scripts/qapi/parser.py | 13 +++++++------ > 3 files changed, 16 insertions(+), 11 deletions(-) > > diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py > index cbd3fd81d36..d38c1746767 100644 > --- a/scripts/qapi/common.py > +++ b/scripts/qapi/common.py > @@ -12,7 +12,7 @@ > # See the COPYING file in the top-level directory. > > import re > -from typing import Optional, Sequence > +from typing import Match, Optional, Sequence > > > #: Magic string that gets removed along with all space to its right. > @@ -210,3 +210,9 @@ def gen_endif(ifcond: Sequence[str]) -> str: > #endif /* %(cond)s */ > ''', cond=ifc) > return ret > + > + > +def match_nofail(pattern: str, string: str) -> Match[str]: > + match = re.match(pattern, string) > + assert match is not None > + return match Name it must_match()? You choose. I wish we could have more stating typing with less notational overhead, but no free lunch... [...]
On 4/25/21 3:54 AM, Markus Armbruster wrote: > John Snow <jsnow@redhat.com> writes: > >> Mypy cannot generally understand that these regex functions cannot >> possibly fail. Add a _nofail helper that clarifies this for mypy. > > Convention wants a blank line here. > Tooling failure. stg pop -a while stg push; and stg edit --sign; done (Will fix, but not so sure about fixing the tool...) >> Signed-off-by: John Snow <jsnow@redhat.com> >> --- >> scripts/qapi/common.py | 8 +++++++- >> scripts/qapi/main.py | 6 ++---- >> scripts/qapi/parser.py | 13 +++++++------ >> 3 files changed, 16 insertions(+), 11 deletions(-) >> >> diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py >> index cbd3fd81d36..d38c1746767 100644 >> --- a/scripts/qapi/common.py >> +++ b/scripts/qapi/common.py >> @@ -12,7 +12,7 @@ >> # See the COPYING file in the top-level directory. >> >> import re >> -from typing import Optional, Sequence >> +from typing import Match, Optional, Sequence >> >> >> #: Magic string that gets removed along with all space to its right. >> @@ -210,3 +210,9 @@ def gen_endif(ifcond: Sequence[str]) -> str: >> #endif /* %(cond)s */ >> ''', cond=ifc) >> return ret >> + >> + >> +def match_nofail(pattern: str, string: str) -> Match[str]: >> + match = re.match(pattern, string) >> + assert match is not None >> + return match > > Name it must_match()? You choose. > If you think it reads genuinely better, sure. > I wish we could have more stating typing with less notational overhead, > but no free lunch... > > [...] >
diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py index cbd3fd81d36..d38c1746767 100644 --- a/scripts/qapi/common.py +++ b/scripts/qapi/common.py @@ -12,7 +12,7 @@ # See the COPYING file in the top-level directory. import re -from typing import Optional, Sequence +from typing import Match, Optional, Sequence #: Magic string that gets removed along with all space to its right. @@ -210,3 +210,9 @@ def gen_endif(ifcond: Sequence[str]) -> str: #endif /* %(cond)s */ ''', cond=ifc) return ret + + +def match_nofail(pattern: str, string: str) -> Match[str]: + match = re.match(pattern, string) + assert match is not None + return match diff --git a/scripts/qapi/main.py b/scripts/qapi/main.py index 70f8aa86f37..e8d4ba4b389 100644 --- a/scripts/qapi/main.py +++ b/scripts/qapi/main.py @@ -8,11 +8,11 @@ """ import argparse -import re import sys from typing import Optional from .commands import gen_commands +from .common import match_nofail from .error import QAPIError from .events import gen_events from .introspect import gen_introspect @@ -22,9 +22,7 @@ def invalid_prefix_char(prefix: str) -> Optional[str]: - match = re.match(r'([A-Za-z_.-][A-Za-z0-9_.-]*)?', prefix) - # match cannot be None, but mypy cannot infer that. - assert match is not None + match = match_nofail(r'([A-Za-z_.-][A-Za-z0-9_.-]*)?', prefix) if match.end() != len(prefix): return prefix[match.end()] return None diff --git a/scripts/qapi/parser.py b/scripts/qapi/parser.py index f2425c0228a..7f3c009f64b 100644 --- a/scripts/qapi/parser.py +++ b/scripts/qapi/parser.py @@ -18,6 +18,7 @@ import os import re +from .common import match_nofail from .error import QAPISemError, QAPISourceError from .source import QAPISourceInfo @@ -235,8 +236,8 @@ def accept(self, skip_comment=True): elif not self.tok.isspace(): # Show up to next structural, whitespace or quote # character - match = re.match('[^[\\]{}:,\\s\'"]+', - self.src[self.cursor-1:]) + match = match_nofail('[^[\\]{}:,\\s\'"]+', + self.src[self.cursor-1:]) raise QAPIParseError(self, "stray '%s'" % match.group(0)) def get_members(self): @@ -369,7 +370,7 @@ def append(self, line): # Strip leading spaces corresponding to the expected indent level # Blank lines are always OK. if line: - indent = re.match(r'\s*', line).end() + indent = match_nofail(r'\s*', line).end() if indent < self._indent: raise QAPIParseError( self._parser, @@ -505,7 +506,7 @@ def _append_args_line(self, line): # from line and replace it with spaces so that 'f' has the # same index as it did in the original line and can be # handled the same way we will handle following lines. - indent = re.match(r'@\S*:\s*', line).end() + indent = match_nofail(r'@\S*:\s*', line).end() line = line[indent:] if not line: # Line was just the "@arg:" header; following lines @@ -540,7 +541,7 @@ def _append_features_line(self, line): # from line and replace it with spaces so that 'f' has the # same index as it did in the original line and can be # handled the same way we will handle following lines. - indent = re.match(r'@\S*:\s*', line).end() + indent = match_nofail(r'@\S*:\s*', line).end() line = line[indent:] if not line: # Line was just the "@arg:" header; following lines @@ -586,7 +587,7 @@ def _append_various_line(self, line): # from line and replace it with spaces so that 'f' has the # same index as it did in the original line and can be # handled the same way we will handle following lines. - indent = re.match(r'\S*:\s*', line).end() + indent = match_nofail(r'\S*:\s*', line).end() line = line[indent:] if not line: # Line was just the "Section:" header; following lines
Mypy cannot generally understand that these regex functions cannot possibly fail. Add a _nofail helper that clarifies this for mypy. Signed-off-by: John Snow <jsnow@redhat.com> --- scripts/qapi/common.py | 8 +++++++- scripts/qapi/main.py | 6 ++---- scripts/qapi/parser.py | 13 +++++++------ 3 files changed, 16 insertions(+), 11 deletions(-)