| c256263f | 19-May-2021 |
John Snow <jsnow@redhat.com> |
qapi/parser: Fix token membership tests when token can be None
When the token can be None (EOF), we can't use 'x in "abc"' style membership tests to group types of tokens together, because 'None in
qapi/parser: Fix token membership tests when token can be None
When the token can be None (EOF), we can't use 'x in "abc"' style membership tests to group types of tokens together, because 'None in "abc"' is a TypeError.
Easy enough to fix. (Use a tuple: It's neither a static typing error nor a runtime error to check for None in Tuple[str, ...])
Add tests to prevent a regression. (Note: they cannot be added prior to this fix, as the unhandled stack trace will not match test output in the CI system.)
Signed-off-by: John Snow <jsnow@redhat.com> Message-Id: <20210519183951.3946870-11-jsnow@redhat.com> Reviewed-by: Markus Armbruster <armbru@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
show more ...
|
| e0e8a0ac | 19-May-2021 |
John Snow <jsnow@redhat.com> |
qapi: add must_match helper
Mypy cannot generally understand that these regex functions cannot possibly fail. Add a "must_match" helper that makes this clear for mypy.
Signed-off-by: John Snow <jsn
qapi: add must_match helper
Mypy cannot generally understand that these regex functions cannot possibly fail. Add a "must_match" helper that makes this clear for mypy.
Signed-off-by: John Snow <jsnow@redhat.com> Message-Id: <20210519183951.3946870-10-jsnow@redhat.com> Reviewed-by: Markus Armbruster <armbru@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
show more ...
|
| 43b1be65 | 19-May-2021 |
John Snow <jsnow@redhat.com> |
qapi/parser: Use @staticmethod where appropriate
No self, no thank you!
(Quiets pylint warnings.)
Signed-off-by: John Snow <jsnow@redhat.com> Message-Id: <20210519183951.3946870-9-jsnow@redhat.com
qapi/parser: Use @staticmethod where appropriate
No self, no thank you!
(Quiets pylint warnings.)
Signed-off-by: John Snow <jsnow@redhat.com> Message-Id: <20210519183951.3946870-9-jsnow@redhat.com> Reviewed-by: Markus Armbruster <armbru@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
show more ...
|
| 234dce2c | 19-May-2021 |
John Snow <jsnow@redhat.com> |
qapi/parser: assert object keys are strings
The single quote token implies the value is a string. Assert this to be the case, to allow us to write an accurate return type for get_members.
Signed-of
qapi/parser: assert object keys are strings
The single quote token implies the value is a string. Assert this to be the case, to allow us to write an accurate return type for get_members.
Signed-off-by: John Snow <jsnow@redhat.com> Message-Id: <20210519183951.3946870-8-jsnow@redhat.com> Reviewed-by: Markus Armbruster <armbru@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
show more ...
|
| 9cd0205d | 19-May-2021 |
John Snow <jsnow@redhat.com> |
qapi/parser: enforce all top-level expressions must be dict in _parse()
Instead of using get_expr nested=False, allow get_expr to always return any expression. In exchange, add a new error message t
qapi/parser: enforce all top-level expressions must be dict in _parse()
Instead of using get_expr nested=False, allow get_expr to always return any expression. In exchange, add a new error message to the top-level parser that explains the semantic error: Top-level expressions must always be JSON objects.
This helps mypy understand the rest of this function which assumes that get_expr did indeed return a dict.
The exception type changes from QAPIParseError to QAPISemError as a result, and the error message in two tests now changes.
Signed-off-by: John Snow <jsnow@redhat.com>
Message-Id: <20210519183951.3946870-7-jsnow@redhat.com> Reviewed-by: Markus Armbruster <armbru@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
show more ...
|
| 7c610ce6 | 19-May-2021 |
John Snow <jsnow@redhat.com> |
qapi/parser: Assert lexer value is a string
The type checker can't narrow the type of the token value to string, because it's only loosely correlated with the return token.
We know that a token of
qapi/parser: Assert lexer value is a string
The type checker can't narrow the type of the token value to string, because it's only loosely correlated with the return token.
We know that a token of '#' should always have a "str" value. Add an assertion.
Signed-off-by: John Snow <jsnow@redhat.com> Message-Id: <20210519183951.3946870-6-jsnow@redhat.com> Reviewed-by: Markus Armbruster <armbru@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
show more ...
|
| 16ff40ac | 19-May-2021 |
John Snow <jsnow@redhat.com> |
qapi/parser: factor parsing routine into method
For the sake of keeping __init__ smaller (and treating it more like a gallery of what state variables we can expect to see), put the actual parsing ac
qapi/parser: factor parsing routine into method
For the sake of keeping __init__ smaller (and treating it more like a gallery of what state variables we can expect to see), put the actual parsing action into a parse method. It remains invoked from the init method to reduce churn.
To accomplish this, @previously_included becomes the private data member ._included, and the filename is stashed as ._fname.
Add any missing declarations to the init method, and group them by function so they can be understood quickly at a glance.
Signed-off-by: John Snow <jsnow@redhat.com> Message-Id: <20210519183951.3946870-5-jsnow@redhat.com> Reviewed-by: Markus Armbruster <armbru@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
show more ...
|
| b2b31fdf | 19-May-2021 |
John Snow <jsnow@redhat.com> |
qapi/source: Remove line number from QAPISourceInfo initializer
With the QAPISourceInfo(None, None, None) construct gone, there's no longer any reason to have to specify that a file starts on the fi
qapi/source: Remove line number from QAPISourceInfo initializer
With the QAPISourceInfo(None, None, None) construct gone, there's no longer any reason to have to specify that a file starts on the first line. Remove it from the initializer and default it to 1.
Remove the last vestiges where we check for 'line' being unset, that can't happen, now.
Signed-off-by: John Snow <jsnow@redhat.com> Message-Id: <20210519183951.3946870-4-jsnow@redhat.com> Reviewed-by: Markus Armbruster <armbru@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
show more ...
|
| 3404e574 | 19-May-2021 |
John Snow <jsnow@redhat.com> |
qapi/parser: Don't try to handle file errors
Fixes: f5d4361cda Fixes: 52a474180a Fixes: 46f49468c6
Remove the try/except block that handles file-opening errors in QAPISchemaParser.__init__() and ad
qapi/parser: Don't try to handle file errors
Fixes: f5d4361cda Fixes: 52a474180a Fixes: 46f49468c6
Remove the try/except block that handles file-opening errors in QAPISchemaParser.__init__() and add one each to QAPISchemaParser._include() and QAPISchema.__init__() respectively.
This simultaneously fixes the typing of info.fname (f5d4361cda), A static typing violation in test-qapi (46f49468c6), and a regression of an error message (52a474180a).
The short-ish version of what motivates this patch is:
- It's hard to write a good error message in the init method, because we need to determine the context of our caller to do so. It's easier to just let the caller write the message. - We don't want to allow QAPISourceInfo(None, None, None) to exist. The typing introduced by commit f5d4361cda types the 'fname' field as (non-optional) str, which was premature until the removal of this construct. - Errors made using such an object are currently incorrect (since 52a474180a) - It's not technically a semantic error if we cannot open the schema. - There are various typing constraints that make mixing these two cases undesirable for a single special case. - test-qapi's code handling an fname of 'None' is now dead, drop it. Additionally, Not all QAPIError objects have an 'info' field (since 46f49468), so deleting this stanza corrects a typing oversight in test-qapi introduced by that commit.
Other considerations:
- open() is moved to a 'with' block to ensure file pointers are cleaned up deterministically. - Python 3.3 deprecated IOError and made it a synonym for OSError. Avoid the misleading perception these exception handlers are narrower than they really are.
The long version:
The error message here is incorrect (since commit 52a474180a):
> python3 qapi-gen.py 'fake.json' qapi-gen.py: qapi-gen.py: can't read schema file 'fake.json': No such file or directory
In pursuing it, we find that QAPISourceInfo has a special accommodation for when there's no filename. Meanwhile, the intent when QAPISourceInfo was typed (f5d4361cda) was non-optional 'str'. This usage was overlooked.
To remove this, I'd want to avoid having a "fake" QAPISourceInfo object. I also don't want to explicitly begin accommodating QAPISourceInfo itself being None, because we actually want to eventually prove that this can never happen -- We don't want to confuse "The file isn't open yet" with "This error stems from a definition that wasn't defined in any file".
(An earlier series tried to create a dummy info object, but it was tough to prove in review that it worked correctly without creating new regressions. This patch avoids that distraction. We would like to first prove that we never raise QAPISemError for any built-in object before we add "special" info objects. We aren't ready to do that yet.)
So, which way out of the labyrinth?
Here's one way: Don't try to handle errors at a level with "mixed" semantic contexts; i.e. don't mix inclusion errors (should report a source line where the include was triggered) and command line errors (where we specified a file we couldn't read).
Remove the error handling from the initializer of the parser. Pythonic! Now it's the caller's job to figure out what to do about it. Handle the error in QAPISchemaParser._include() instead, where we can write a targeted error message where we are guaranteed to have an 'info' context to report with.
The root level error can similarly move to QAPISchema.__init__(), where we know we'll never have an info context to report with, so we use a more abstract error type.
Now the error looks sensible again:
> python3 qapi-gen.py 'fake.json' qapi-gen.py: can't read schema file 'fake.json': No such file or directory
With these error cases separated, QAPISourceInfo can be solidified as never having placeholder arguments that violate our desired types. Clean up test-qapi along similar lines.
Signed-off-by: John Snow <jsnow@redhat.com> Message-Id: <20210519183951.3946870-2-jsnow@redhat.com> Reviewed-by: Markus Armbruster <armbru@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
show more ...
|
| b54626e0 | 21-Apr-2021 |
John Snow <jsnow@redhat.com> |
qapi/error.py: enable mypy checks
Signed-off-by: John Snow <jsnow@redhat.com>
Message-Id: <20210421192233.3542904-9-jsnow@redhat.com> Reviewed-by: Markus Armbruster <armbru@redhat.com> Signed-off-b
qapi/error.py: enable mypy checks
Signed-off-by: John Snow <jsnow@redhat.com>
Message-Id: <20210421192233.3542904-9-jsnow@redhat.com> Reviewed-by: Markus Armbruster <armbru@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
show more ...
|
| 30d0a016 | 21-Apr-2021 |
John Snow <jsnow@redhat.com> |
qapi/error: Add type hints
No functional change.
Note: QAPISourceError's info parameter is Optional[] because schema.py treats the info property of its various classes as Optional to accommodate bu
qapi/error: Add type hints
No functional change.
Note: QAPISourceError's info parameter is Optional[] because schema.py treats the info property of its various classes as Optional to accommodate built-in types, which have no source. See prior commit 'qapi/error: assert QAPISourceInfo is not None'.
Signed-off-by: John Snow <jsnow@redhat.com>
Message-Id: <20210421192233.3542904-8-jsnow@redhat.com> Reviewed-by: Markus Armbruster <armbru@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
show more ...
|
| 92870cf3 | 21-Apr-2021 |
John Snow <jsnow@redhat.com> |
qapi/error.py: enable pylint checks
Signed-off-by: John Snow <jsnow@redhat.com> Message-Id: <20210421192233.3542904-7-jsnow@redhat.com> Reviewed-by: Markus Armbruster <armbru@redhat.com> Signed-off-
qapi/error.py: enable pylint checks
Signed-off-by: John Snow <jsnow@redhat.com> Message-Id: <20210421192233.3542904-7-jsnow@redhat.com> Reviewed-by: Markus Armbruster <armbru@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
show more ...
|
| ac6a7d88 | 21-Apr-2021 |
John Snow <jsnow@redhat.com> |
qapi/error.py: move QAPIParseError to parser.py
Keeping it in error.py will create some cyclic import problems when we add types to the QAPISchemaParser. Callers don't need to know the details of QA
qapi/error.py: move QAPIParseError to parser.py
Keeping it in error.py will create some cyclic import problems when we add types to the QAPISchemaParser. Callers don't need to know the details of QAPIParseError unless they are parsing or dealing directly with the parser, so this won't create any harsh new requirements for callers in the general case.
Update error.py with a little docstring that gives a nod to where the error may now be found.
Signed-off-by: John Snow <jsnow@redhat.com> Message-Id: <20210421192233.3542904-6-jsnow@redhat.com> Reviewed-by: Markus Armbruster <armbru@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
show more ...
|
| ac897611 | 21-Apr-2021 |
John Snow <jsnow@redhat.com> |
qapi/error: assert QAPISourceInfo is not None
Built-in stuff is not parsed from a source file, and therefore have no QAPISourceInfo. If such None info was used for reporting an error, built-in stuff
qapi/error: assert QAPISourceInfo is not None
Built-in stuff is not parsed from a source file, and therefore have no QAPISourceInfo. If such None info was used for reporting an error, built-in stuff would be broken. Programming error. Instead of reporting a confusing error with bogus source location then, we better crash.
We currently crash only if self.col was set. Assert that self.info is not None in order to crash reliably.
We can not yet change the type of the initializer to prove this cannot happen at static analysis time before the remainder of the code is fully typed.
Signed-off-by: John Snow <jsnow@redhat.com> Message-Id: <20210421192233.3542904-5-jsnow@redhat.com> Reviewed-by: Markus Armbruster <armbru@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
show more ...
|
| 86cc2ff6 | 21-Apr-2021 |
John Snow <jsnow@redhat.com> |
qapi/error: Make QAPISourceError 'col' parameter optional
It's already treated as optional, with one direct caller and some subclass callers passing 'None'. Make it officially optional, which requir
qapi/error: Make QAPISourceError 'col' parameter optional
It's already treated as optional, with one direct caller and some subclass callers passing 'None'. Make it officially optional, which requires moving the position of the argument to come after all required parameters.
QAPISemError becomes functionally identical to QAPISourceError. Keep the name to preserve its semantic meaning and avoid code churn, but remove the now-useless __init__ wrapper.
Signed-off-by: John Snow <jsnow@redhat.com> Message-Id: <20210421192233.3542904-4-jsnow@redhat.com> Reviewed-by: Markus Armbruster <armbru@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
show more ...
|
| b54e07cc | 21-Apr-2021 |
John Snow <jsnow@redhat.com> |
qapi/error: Use Python3-style super()
Missed in commit 2cae67bcb5 "qapi: Use super() now we have Python 3".
Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Markus Armbruster <armbru@redhat
qapi/error: Use Python3-style super()
Missed in commit 2cae67bcb5 "qapi: Use super() now we have Python 3".
Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Markus Armbruster <armbru@redhat.com> Message-Id: <20210421192233.3542904-3-jsnow@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
show more ...
|
| 46f49468 | 21-Apr-2021 |
John Snow <jsnow@redhat.com> |
qapi/error: Repurpose QAPIError as an abstract base exception class
Rename QAPIError to QAPISourceError, and then create a new QAPIError class that serves as the basis for all of our other custom ex
qapi/error: Repurpose QAPIError as an abstract base exception class
Rename QAPIError to QAPISourceError, and then create a new QAPIError class that serves as the basis for all of our other custom exceptions, without specifying any class properties.
This leaves QAPIError as a package-wide error class that's suitable for any current or future errors.
(Right now, we don't have any errors that DON'T also want to specify a Source location, but this MAY change. In these cases, a common abstract ancestor would be desired.)
Add docstrings to explain the intended function of each error class.
Signed-off-by: John Snow <jsnow@redhat.com> Message-Id: <20210421192233.3542904-2-jsnow@redhat.com> Reviewed-by: Markus Armbruster <armbru@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
show more ...
|
| e81718c6 | 21-Apr-2021 |
John Snow <jsnow@redhat.com> |
qapi/expr: Update authorship and copyright information
Signed-off-by: John Snow <jsnow@redhat.com> Message-Id: <20210421182032.3521476-18-jsnow@redhat.com> Reviewed-by: Markus Armbruster <armbru@red
qapi/expr: Update authorship and copyright information
Signed-off-by: John Snow <jsnow@redhat.com> Message-Id: <20210421182032.3521476-18-jsnow@redhat.com> Reviewed-by: Markus Armbruster <armbru@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
show more ...
|
| eab99939 | 21-Apr-2021 |
John Snow <jsnow@redhat.com> |
qapi/expr.py: Use tuples instead of lists for static data
It is -- maybe -- possibly -- three nanoseconds faster.
Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Eduardo Habkost <ehabkost@
qapi/expr.py: Use tuples instead of lists for static data
It is -- maybe -- possibly -- three nanoseconds faster.
Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Eduardo Habkost <ehabkost@redhat.com> Reviewed-by: Cleber Rosa <crosa@redhat.com> Message-Id: <20210421182032.3521476-17-jsnow@redhat.com> Reviewed-by: Markus Armbruster <armbru@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
show more ...
|
| a4865363 | 21-Apr-2021 |
John Snow <jsnow@redhat.com> |
qapi/expr.py: Add docstrings
Now with more :words:!
Signed-off-by: John Snow <jsnow@redhat.com> Message-Id: <20210421182032.3521476-16-jsnow@redhat.com> Reviewed-by: Markus Armbruster <armbru@redha
qapi/expr.py: Add docstrings
Now with more :words:!
Signed-off-by: John Snow <jsnow@redhat.com> Message-Id: <20210421182032.3521476-16-jsnow@redhat.com> Reviewed-by: Markus Armbruster <armbru@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
show more ...
|
| 79e4fd14 | 21-Apr-2021 |
John Snow <jsnow@redhat.com> |
qapi/expr: Only explicitly prohibit 'Kind' nor 'List' for type names
Per list review: qapi-code-gen.txt reserves suffixes Kind and List only for type names, but the code rejects them for events and
qapi/expr: Only explicitly prohibit 'Kind' nor 'List' for type names
Per list review: qapi-code-gen.txt reserves suffixes Kind and List only for type names, but the code rejects them for events and commands, too.
It turns out we reject them earlier anyway: In check_name_upper() for event names, and in check_name_lower() for command names.
Still, adjust the code for clarity over what precisely we are guarding against.
Signed-off-by: John Snow <jsnow@redhat.com> Message-Id: <20210421182032.3521476-15-jsnow@redhat.com> Reviewed-by: Markus Armbruster <armbru@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
show more ...
|
| 328e8ca7 | 21-Apr-2021 |
John Snow <jsnow@redhat.com> |
qapi/expr.py: enable pylint checks
Signed-off-by: John Snow <jsnow@redhat.com> Tested-by: Eduardo Habkost <ehabkost@redhat.com> Reviewed-by: Eduardo Habkost <ehabkost@redhat.com> Reviewed-by: Cleber
qapi/expr.py: enable pylint checks
Signed-off-by: John Snow <jsnow@redhat.com> Tested-by: Eduardo Habkost <ehabkost@redhat.com> Reviewed-by: Eduardo Habkost <ehabkost@redhat.com> Reviewed-by: Cleber Rosa <crosa@redhat.com> Tested-by: Cleber Rosa <crosa@redhat.com> Message-Id: <20210421182032.3521476-14-jsnow@redhat.com> Reviewed-by: Markus Armbruster <armbru@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
show more ...
|
| e42648dc | 21-Apr-2021 |
John Snow <jsnow@redhat.com> |
qapi/expr.py: Remove single-letter variable
Signed-off-by: John Snow <jsnow@redhat.com> Message-Id: <20210421182032.3521476-13-jsnow@redhat.com> Reviewed-by: Markus Armbruster <armbru@redhat.com> Si
qapi/expr.py: Remove single-letter variable
Signed-off-by: John Snow <jsnow@redhat.com> Message-Id: <20210421182032.3521476-13-jsnow@redhat.com> Reviewed-by: Markus Armbruster <armbru@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
show more ...
|
| 210fd631 | 21-Apr-2021 |
John Snow <jsnow@redhat.com> |
qapi/expr.py: Consolidate check_if_str calls in check_if
This is a small rewrite to address some minor style nits.
Don't compare against the empty list to check for the empty condition, and move th
qapi/expr.py: Consolidate check_if_str calls in check_if
This is a small rewrite to address some minor style nits.
Don't compare against the empty list to check for the empty condition, and move the normalization forward to unify the check on the now-normalized structure.
With the check unified, the local nested function isn't needed anymore and can be brought down into the normal flow of the function. With the nesting level changed, shuffle the error strings around a bit to get them to fit in 79 columns.
Note: although ifcond is typed as Sequence[str] elsewhere, we *know* that the parser will produce real, bona-fide lists. It's okay to check isinstance(ifcond, list) here.
Signed-off-by: John Snow <jsnow@redhat.com> Message-Id: <20210421182032.3521476-12-jsnow@redhat.com> Reviewed-by: Markus Armbruster <armbru@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
show more ...
|
| b9ad358a | 21-Apr-2021 |
John Snow <jsnow@redhat.com> |
qapi/expr.py: add type hint annotations
Annotations do not change runtime behavior. This commit *only* adds annotations.
Signed-off-by: John Snow <jsnow@redhat.com> Message-Id: <20210421182032.3521
qapi/expr.py: add type hint annotations
Annotations do not change runtime behavior. This commit *only* adds annotations.
Signed-off-by: John Snow <jsnow@redhat.com> Message-Id: <20210421182032.3521476-11-jsnow@redhat.com> Reviewed-by: Markus Armbruster <armbru@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
show more ...
|