diff mbox series

[v10,10/14] iotests: add hmp helper with logging

Message ID 20200331000014.11581-11-jsnow@redhat.com
State New
Headers show
Series iotests: use python logging | expand

Commit Message

John Snow March 31, 2020, midnight UTC
Minor cleanup for HMP functions; helps with line length and consolidates
HMP helpers through one implementation function.

Although we are adding a universal toggle to turn QMP logging on or off,
many existing callers to hmp functions don't expect that output to be
logged, which causes quite a few changes in the test output.

For now, offer a use_log parameter.


Typing notes:

QMPResponse is just an alias for Dict[str, Any]. It holds no special
meanings and it is not a formal subtype of Dict[str, Any]. It is best
thought of as a lexical synonym.

We may well wish to add stricter subtypes in the future for certain
shapes of data that are not formalized as Python objects, at which point
we can simply retire the alias and allow mypy to more strictly check
usages of the name.

Signed-off-by: John Snow <jsnow@redhat.com>
---
 tests/qemu-iotests/iotests.py | 35 ++++++++++++++++++++++-------------
 1 file changed, 22 insertions(+), 13 deletions(-)

Comments

Max Reitz March 31, 2020, 10:21 a.m. UTC | #1
On 31.03.20 02:00, John Snow wrote:
> Minor cleanup for HMP functions; helps with line length and consolidates
> HMP helpers through one implementation function.
> 
> Although we are adding a universal toggle to turn QMP logging on or off,
> many existing callers to hmp functions don't expect that output to be
> logged, which causes quite a few changes in the test output.
> 
> For now, offer a use_log parameter.
> 
> 
> Typing notes:
> 
> QMPResponse is just an alias for Dict[str, Any]. It holds no special
> meanings and it is not a formal subtype of Dict[str, Any]. It is best
> thought of as a lexical synonym.
> 
> We may well wish to add stricter subtypes in the future for certain
> shapes of data that are not formalized as Python objects, at which point
> we can simply retire the alias and allow mypy to more strictly check
> usages of the name.
> 
> Signed-off-by: John Snow <jsnow@redhat.com>
> ---
>  tests/qemu-iotests/iotests.py | 35 ++++++++++++++++++++++-------------
>  1 file changed, 22 insertions(+), 13 deletions(-)

Reviewed-by: Max Reitz <mreitz@redhat.com>

> diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
> index b08bcb87e1..dfc753c319 100644
> --- a/tests/qemu-iotests/iotests.py
> +++ b/tests/qemu-iotests/iotests.py
> @@ -37,6 +37,10 @@
>  
>  assert sys.version_info >= (3, 6)
>  
> +# Type Aliases
> +QMPResponse = Dict[str, Any]
> +
> +
>  faulthandler.enable()
>  
>  # This will not work if arguments contain spaces but is necessary if we
> @@ -540,25 +544,30 @@ def add_incoming(self, addr):
>          self._args.append(addr)
>          return self
>  
> -    def pause_drive(self, drive, event=None):
> -        '''Pause drive r/w operations'''
> +    def hmp(self, command_line: str, use_log: bool = False) -> QMPResponse:
> +        cmd = 'human-monitor-command'
> +        kwargs = {'command-line': command_line}
> +        if use_log:
> +            return self.qmp_log(cmd, **kwargs)
> +        else:
> +            return self.qmp(cmd, **kwargs)

Hm.  I suppose I should take this chance to understand something about
mypy.  QEMUMachine.qmp() isn’t typed, so mypy can’t check that this
really returns QMPResponse.  Is there some flag to make it?  Like
--actually-check-types?

(--strict seems, well, overly strict?  Like not allowing generics, I
don’t see why.  Or I suppose for the time being we want to allow untyped
definitions, as long as they don’t break type assertions such as it kind
of does here...?)

Max
Kevin Wolf March 31, 2020, 2 p.m. UTC | #2
Am 31.03.2020 um 12:21 hat Max Reitz geschrieben:
> On 31.03.20 02:00, John Snow wrote:
> > Minor cleanup for HMP functions; helps with line length and consolidates
> > HMP helpers through one implementation function.
> > 
> > Although we are adding a universal toggle to turn QMP logging on or off,
> > many existing callers to hmp functions don't expect that output to be
> > logged, which causes quite a few changes in the test output.
> > 
> > For now, offer a use_log parameter.
> > 
> > 
> > Typing notes:
> > 
> > QMPResponse is just an alias for Dict[str, Any]. It holds no special
> > meanings and it is not a formal subtype of Dict[str, Any]. It is best
> > thought of as a lexical synonym.
> > 
> > We may well wish to add stricter subtypes in the future for certain
> > shapes of data that are not formalized as Python objects, at which point
> > we can simply retire the alias and allow mypy to more strictly check
> > usages of the name.
> > 
> > Signed-off-by: John Snow <jsnow@redhat.com>
> > ---
> >  tests/qemu-iotests/iotests.py | 35 ++++++++++++++++++++++-------------
> >  1 file changed, 22 insertions(+), 13 deletions(-)
> 
> Reviewed-by: Max Reitz <mreitz@redhat.com>
> 
> > diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
> > index b08bcb87e1..dfc753c319 100644
> > --- a/tests/qemu-iotests/iotests.py
> > +++ b/tests/qemu-iotests/iotests.py
> > @@ -37,6 +37,10 @@
> >  
> >  assert sys.version_info >= (3, 6)
> >  
> > +# Type Aliases
> > +QMPResponse = Dict[str, Any]
> > +
> > +
> >  faulthandler.enable()
> >  
> >  # This will not work if arguments contain spaces but is necessary if we
> > @@ -540,25 +544,30 @@ def add_incoming(self, addr):
> >          self._args.append(addr)
> >          return self
> >  
> > -    def pause_drive(self, drive, event=None):
> > -        '''Pause drive r/w operations'''
> > +    def hmp(self, command_line: str, use_log: bool = False) -> QMPResponse:
> > +        cmd = 'human-monitor-command'
> > +        kwargs = {'command-line': command_line}
> > +        if use_log:
> > +            return self.qmp_log(cmd, **kwargs)
> > +        else:
> > +            return self.qmp(cmd, **kwargs)
> 
> Hm.  I suppose I should take this chance to understand something about
> mypy.  QEMUMachine.qmp() isn’t typed, so mypy can’t check that this
> really returns QMPResponse.  Is there some flag to make it?  Like
> --actually-check-types?

There is --check-untyped-defs, but I'm not sure if that actually changes
the return type of untyped functions from Any to an inferred type. I
kind of doubt it.

> (--strict seems, well, overly strict?  Like not allowing generics, I
> don’t see why.  Or I suppose for the time being we want to allow untyped
> definitions, as long as they don’t break type assertions such as it kind
> of does here...?)

At least, --strict does actually complain about this one because Any
isn't good enough any more (it includes --warn-return-any):

iotests.py:560: warning: Returning Any from function declared to return "Dict[str, Any]"
iotests.py:560: error: Call to untyped function "qmp_log" in typed context
iotests.py:562: warning: Returning Any from function declared to return "Dict[str, Any]"

Not sure why you think it doesn't allow generics? I never had problems
with that, even in my Python museum. :-)

Kevin
John Snow March 31, 2020, 5:23 p.m. UTC | #3
On 3/31/20 6:21 AM, Max Reitz wrote:
> On 31.03.20 02:00, John Snow wrote:
>> Minor cleanup for HMP functions; helps with line length and consolidates
>> HMP helpers through one implementation function.
>>
>> Although we are adding a universal toggle to turn QMP logging on or off,
>> many existing callers to hmp functions don't expect that output to be
>> logged, which causes quite a few changes in the test output.
>>
>> For now, offer a use_log parameter.
>>
>>
>> Typing notes:
>>
>> QMPResponse is just an alias for Dict[str, Any]. It holds no special
>> meanings and it is not a formal subtype of Dict[str, Any]. It is best
>> thought of as a lexical synonym.
>>
>> We may well wish to add stricter subtypes in the future for certain
>> shapes of data that are not formalized as Python objects, at which point
>> we can simply retire the alias and allow mypy to more strictly check
>> usages of the name.
>>
>> Signed-off-by: John Snow <jsnow@redhat.com>
>> ---
>>  tests/qemu-iotests/iotests.py | 35 ++++++++++++++++++++++-------------
>>  1 file changed, 22 insertions(+), 13 deletions(-)
> 
> Reviewed-by: Max Reitz <mreitz@redhat.com>
> 
>> diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
>> index b08bcb87e1..dfc753c319 100644
>> --- a/tests/qemu-iotests/iotests.py
>> +++ b/tests/qemu-iotests/iotests.py
>> @@ -37,6 +37,10 @@
>>  
>>  assert sys.version_info >= (3, 6)
>>  
>> +# Type Aliases
>> +QMPResponse = Dict[str, Any]
>> +
>> +
>>  faulthandler.enable()
>>  
>>  # This will not work if arguments contain spaces but is necessary if we
>> @@ -540,25 +544,30 @@ def add_incoming(self, addr):
>>          self._args.append(addr)
>>          return self
>>  
>> -    def pause_drive(self, drive, event=None):
>> -        '''Pause drive r/w operations'''
>> +    def hmp(self, command_line: str, use_log: bool = False) -> QMPResponse:
>> +        cmd = 'human-monitor-command'
>> +        kwargs = {'command-line': command_line}
>> +        if use_log:
>> +            return self.qmp_log(cmd, **kwargs)
>> +        else:
>> +            return self.qmp(cmd, **kwargs)
> 
> Hm.  I suppose I should take this chance to understand something about
> mypy.  QEMUMachine.qmp() isn’t typed, so mypy can’t check that this
> really returns QMPResponse.  Is there some flag to make it?  Like
> --actually-check-types?
> 

One of --strict's implied options, I'm not sure which. Otherwise, mypy
is geared towards a 'gradual typing' discipline.

In truth, I'm a little thankful for that because it helps avoid yak
shaving marathons.

It does mean that sometimes the annotations don't "do anything" yet,
apart from offering hints and documentation in e.g. pycharm. Which does
mean that sometimes they can be completely wrong...

The more we add, the more we'll catch problems.

Once this series is dusted I'll try to tackle more conversions for
iotests, qmp, etc. I've got a few WIP patches to tackle conversions for
tests/qemu-iotests/*.py but I am trying to shepherd this one in first
before I go bananas.

> (--strict seems, well, overly strict?  Like not allowing generics, I
> don’t see why.  Or I suppose for the time being we want to allow untyped
> definitions, as long as they don’t break type assertions such as it kind
> of does here...?)
> 

"disallow-any-generics" means disallowing `Any` generics, not
disallowing generics ... in general. (I think? I've been using mypy in
strict mode for a personal project a lot lately and I use generics in a
few places, it seems OK.)

> Max
>
Kevin Wolf March 31, 2020, 5:39 p.m. UTC | #4
Am 31.03.2020 um 19:23 hat John Snow geschrieben:
> 
> 
> On 3/31/20 6:21 AM, Max Reitz wrote:
> > On 31.03.20 02:00, John Snow wrote:
> >> Minor cleanup for HMP functions; helps with line length and consolidates
> >> HMP helpers through one implementation function.
> >>
> >> Although we are adding a universal toggle to turn QMP logging on or off,
> >> many existing callers to hmp functions don't expect that output to be
> >> logged, which causes quite a few changes in the test output.
> >>
> >> For now, offer a use_log parameter.
> >>
> >>
> >> Typing notes:
> >>
> >> QMPResponse is just an alias for Dict[str, Any]. It holds no special
> >> meanings and it is not a formal subtype of Dict[str, Any]. It is best
> >> thought of as a lexical synonym.
> >>
> >> We may well wish to add stricter subtypes in the future for certain
> >> shapes of data that are not formalized as Python objects, at which point
> >> we can simply retire the alias and allow mypy to more strictly check
> >> usages of the name.
> >>
> >> Signed-off-by: John Snow <jsnow@redhat.com>
> >> ---
> >>  tests/qemu-iotests/iotests.py | 35 ++++++++++++++++++++++-------------
> >>  1 file changed, 22 insertions(+), 13 deletions(-)
> > 
> > Reviewed-by: Max Reitz <mreitz@redhat.com>
> > 
> >> diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
> >> index b08bcb87e1..dfc753c319 100644
> >> --- a/tests/qemu-iotests/iotests.py
> >> +++ b/tests/qemu-iotests/iotests.py
> >> @@ -37,6 +37,10 @@
> >>  
> >>  assert sys.version_info >= (3, 6)
> >>  
> >> +# Type Aliases
> >> +QMPResponse = Dict[str, Any]
> >> +
> >> +
> >>  faulthandler.enable()
> >>  
> >>  # This will not work if arguments contain spaces but is necessary if we
> >> @@ -540,25 +544,30 @@ def add_incoming(self, addr):
> >>          self._args.append(addr)
> >>          return self
> >>  
> >> -    def pause_drive(self, drive, event=None):
> >> -        '''Pause drive r/w operations'''
> >> +    def hmp(self, command_line: str, use_log: bool = False) -> QMPResponse:
> >> +        cmd = 'human-monitor-command'
> >> +        kwargs = {'command-line': command_line}
> >> +        if use_log:
> >> +            return self.qmp_log(cmd, **kwargs)
> >> +        else:
> >> +            return self.qmp(cmd, **kwargs)
> > 
> > Hm.  I suppose I should take this chance to understand something about
> > mypy.  QEMUMachine.qmp() isn’t typed, so mypy can’t check that this
> > really returns QMPResponse.  Is there some flag to make it?  Like
> > --actually-check-types?
> > 
> 
> One of --strict's implied options, I'm not sure which. Otherwise, mypy
> is geared towards a 'gradual typing' discipline.
> 
> In truth, I'm a little thankful for that because it helps avoid yak
> shaving marathons.
> 
> It does mean that sometimes the annotations don't "do anything" yet,
> apart from offering hints and documentation in e.g. pycharm. Which does
> mean that sometimes they can be completely wrong...
> 
> The more we add, the more we'll catch problems.
> 
> Once this series is dusted I'll try to tackle more conversions for
> iotests, qmp, etc. I've got a few WIP patches to tackle conversions for
> tests/qemu-iotests/*.py but I am trying to shepherd this one in first
> before I go bananas.
> 
> > (--strict seems, well, overly strict?  Like not allowing generics, I
> > don’t see why.  Or I suppose for the time being we want to allow untyped
> > definitions, as long as they don’t break type assertions such as it kind
> > of does here...?)
> > 
> 
> "disallow-any-generics" means disallowing `Any` generics, not
> disallowing generics ... in general. (I think? I've been using mypy in
> strict mode for a personal project a lot lately and I use generics in a
> few places, it seems OK.)

--disallow-any-generics
      disallow usage of generic types that do not specify explicit type parameters

So it will complain if you say just List, and you need to be explicit if
you really want List[Any]. Which I think is a reasonable thing to
require.

Kevin
Max Reitz April 1, 2020, 12:28 p.m. UTC | #5
On 31.03.20 16:00, Kevin Wolf wrote:
> Am 31.03.2020 um 12:21 hat Max Reitz geschrieben:
>> On 31.03.20 02:00, John Snow wrote:
>>> Minor cleanup for HMP functions; helps with line length and consolidates
>>> HMP helpers through one implementation function.
>>>
>>> Although we are adding a universal toggle to turn QMP logging on or off,
>>> many existing callers to hmp functions don't expect that output to be
>>> logged, which causes quite a few changes in the test output.
>>>
>>> For now, offer a use_log parameter.
>>>
>>>
>>> Typing notes:
>>>
>>> QMPResponse is just an alias for Dict[str, Any]. It holds no special
>>> meanings and it is not a formal subtype of Dict[str, Any]. It is best
>>> thought of as a lexical synonym.
>>>
>>> We may well wish to add stricter subtypes in the future for certain
>>> shapes of data that are not formalized as Python objects, at which point
>>> we can simply retire the alias and allow mypy to more strictly check
>>> usages of the name.
>>>
>>> Signed-off-by: John Snow <jsnow@redhat.com>
>>> ---
>>>  tests/qemu-iotests/iotests.py | 35 ++++++++++++++++++++++-------------
>>>  1 file changed, 22 insertions(+), 13 deletions(-)
>>
>> Reviewed-by: Max Reitz <mreitz@redhat.com>
>>
>>> diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
>>> index b08bcb87e1..dfc753c319 100644
>>> --- a/tests/qemu-iotests/iotests.py
>>> +++ b/tests/qemu-iotests/iotests.py
>>> @@ -37,6 +37,10 @@
>>>  
>>>  assert sys.version_info >= (3, 6)
>>>  
>>> +# Type Aliases
>>> +QMPResponse = Dict[str, Any]
>>> +
>>> +
>>>  faulthandler.enable()
>>>  
>>>  # This will not work if arguments contain spaces but is necessary if we
>>> @@ -540,25 +544,30 @@ def add_incoming(self, addr):
>>>          self._args.append(addr)
>>>          return self
>>>  
>>> -    def pause_drive(self, drive, event=None):
>>> -        '''Pause drive r/w operations'''
>>> +    def hmp(self, command_line: str, use_log: bool = False) -> QMPResponse:
>>> +        cmd = 'human-monitor-command'
>>> +        kwargs = {'command-line': command_line}
>>> +        if use_log:
>>> +            return self.qmp_log(cmd, **kwargs)
>>> +        else:
>>> +            return self.qmp(cmd, **kwargs)
>>
>> Hm.  I suppose I should take this chance to understand something about
>> mypy.  QEMUMachine.qmp() isn’t typed, so mypy can’t check that this
>> really returns QMPResponse.  Is there some flag to make it?  Like
>> --actually-check-types?
> 
> There is --check-untyped-defs, but I'm not sure if that actually changes
> the return type of untyped functions from Any to an inferred type. I
> kind of doubt it.

Well, but Any doesn’t fit into QMPResponse, so there should be an error
reported somewhere.

>> (--strict seems, well, overly strict?  Like not allowing generics, I
>> don’t see why.  Or I suppose for the time being we want to allow untyped
>> definitions, as long as they don’t break type assertions such as it kind
>> of does here...?)
> 
> At least, --strict does actually complain about this one because Any
> isn't good enough any more (it includes --warn-return-any):

Hm, yes, but we’re not at a point where it’s really feasible to enable
--strict...

> iotests.py:560: warning: Returning Any from function declared to return "Dict[str, Any]"
> iotests.py:560: error: Call to untyped function "qmp_log" in typed context
> iotests.py:562: warning: Returning Any from function declared to return "Dict[str, Any]"
> 
> Not sure why you think it doesn't allow generics? I never had problems
> with that, even in my Python museum. :-)

I thought --disallow-any-generics would mean that.  But I suppose mypy
understands a “generic” to be something else than I do, as John
described... *shrug*

Max
Max Reitz April 1, 2020, 12:40 p.m. UTC | #6
On 31.03.20 19:39, Kevin Wolf wrote:
> Am 31.03.2020 um 19:23 hat John Snow geschrieben:
>>
>>
>> On 3/31/20 6:21 AM, Max Reitz wrote:
>>> On 31.03.20 02:00, John Snow wrote:
>>>> Minor cleanup for HMP functions; helps with line length and consolidates
>>>> HMP helpers through one implementation function.
>>>>
>>>> Although we are adding a universal toggle to turn QMP logging on or off,
>>>> many existing callers to hmp functions don't expect that output to be
>>>> logged, which causes quite a few changes in the test output.
>>>>
>>>> For now, offer a use_log parameter.
>>>>
>>>>
>>>> Typing notes:
>>>>
>>>> QMPResponse is just an alias for Dict[str, Any]. It holds no special
>>>> meanings and it is not a formal subtype of Dict[str, Any]. It is best
>>>> thought of as a lexical synonym.
>>>>
>>>> We may well wish to add stricter subtypes in the future for certain
>>>> shapes of data that are not formalized as Python objects, at which point
>>>> we can simply retire the alias and allow mypy to more strictly check
>>>> usages of the name.
>>>>
>>>> Signed-off-by: John Snow <jsnow@redhat.com>
>>>> ---
>>>>  tests/qemu-iotests/iotests.py | 35 ++++++++++++++++++++++-------------
>>>>  1 file changed, 22 insertions(+), 13 deletions(-)
>>>
>>> Reviewed-by: Max Reitz <mreitz@redhat.com>
>>>
>>>> diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
>>>> index b08bcb87e1..dfc753c319 100644
>>>> --- a/tests/qemu-iotests/iotests.py
>>>> +++ b/tests/qemu-iotests/iotests.py
>>>> @@ -37,6 +37,10 @@
>>>>  
>>>>  assert sys.version_info >= (3, 6)
>>>>  
>>>> +# Type Aliases
>>>> +QMPResponse = Dict[str, Any]
>>>> +
>>>> +
>>>>  faulthandler.enable()
>>>>  
>>>>  # This will not work if arguments contain spaces but is necessary if we
>>>> @@ -540,25 +544,30 @@ def add_incoming(self, addr):
>>>>          self._args.append(addr)
>>>>          return self
>>>>  
>>>> -    def pause_drive(self, drive, event=None):
>>>> -        '''Pause drive r/w operations'''
>>>> +    def hmp(self, command_line: str, use_log: bool = False) -> QMPResponse:
>>>> +        cmd = 'human-monitor-command'
>>>> +        kwargs = {'command-line': command_line}
>>>> +        if use_log:
>>>> +            return self.qmp_log(cmd, **kwargs)
>>>> +        else:
>>>> +            return self.qmp(cmd, **kwargs)
>>>
>>> Hm.  I suppose I should take this chance to understand something about
>>> mypy.  QEMUMachine.qmp() isn’t typed, so mypy can’t check that this
>>> really returns QMPResponse.  Is there some flag to make it?  Like
>>> --actually-check-types?
>>>
>>
>> One of --strict's implied options, I'm not sure which. Otherwise, mypy
>> is geared towards a 'gradual typing' discipline.
>>
>> In truth, I'm a little thankful for that because it helps avoid yak
>> shaving marathons.

Sure.  I was just looking into the different options.  I was interested
in whether I could come up with a mode that leaves wholly untyped code
alone, but warns for code that mixes it.  Or something.

>> It does mean that sometimes the annotations don't "do anything" yet,
>> apart from offering hints and documentation in e.g. pycharm. Which does
>> mean that sometimes they can be completely wrong...
>>
>> The more we add, the more we'll catch problems.
>>
>> Once this series is dusted I'll try to tackle more conversions for
>> iotests, qmp, etc. I've got a few WIP patches to tackle conversions for
>> tests/qemu-iotests/*.py but I am trying to shepherd this one in first
>> before I go bananas.

Sure, sure.

>>> (--strict seems, well, overly strict?  Like not allowing generics, I
>>> don’t see why.  Or I suppose for the time being we want to allow untyped
>>> definitions, as long as they don’t break type assertions such as it kind
>>> of does here...?)
>>>
>>
>> "disallow-any-generics" means disallowing `Any` generics, not
>> disallowing generics ... in general. (I think? I've been using mypy in
>> strict mode for a personal project a lot lately and I use generics in a
>> few places, it seems OK.)
> 
> --disallow-any-generics
>       disallow usage of generic types that do not specify explicit type parameters
> 
> So it will complain if you say just List, and you need to be explicit if
> you really want List[Any]. Which I think is a reasonable thing to
> require.

OK.  So it’s “disallow ‘any’ generics”, not “disallow any ‘generic’s”.
Not easy to parse.  (Yes, yes, I should’ve actually read the man page...)

Good to know that mypy and me actually do seem to loosely agree on what
a generic is. :)

Max
Max Reitz April 1, 2020, 12:42 p.m. UTC | #7
On 01.04.20 14:28, Max Reitz wrote:
> On 31.03.20 16:00, Kevin Wolf wrote:
>> Am 31.03.2020 um 12:21 hat Max Reitz geschrieben:
>>> On 31.03.20 02:00, John Snow wrote:
>>>> Minor cleanup for HMP functions; helps with line length and consolidates
>>>> HMP helpers through one implementation function.
>>>>
>>>> Although we are adding a universal toggle to turn QMP logging on or off,
>>>> many existing callers to hmp functions don't expect that output to be
>>>> logged, which causes quite a few changes in the test output.
>>>>
>>>> For now, offer a use_log parameter.
>>>>
>>>>
>>>> Typing notes:
>>>>
>>>> QMPResponse is just an alias for Dict[str, Any]. It holds no special
>>>> meanings and it is not a formal subtype of Dict[str, Any]. It is best
>>>> thought of as a lexical synonym.
>>>>
>>>> We may well wish to add stricter subtypes in the future for certain
>>>> shapes of data that are not formalized as Python objects, at which point
>>>> we can simply retire the alias and allow mypy to more strictly check
>>>> usages of the name.
>>>>
>>>> Signed-off-by: John Snow <jsnow@redhat.com>
>>>> ---
>>>>  tests/qemu-iotests/iotests.py | 35 ++++++++++++++++++++++-------------
>>>>  1 file changed, 22 insertions(+), 13 deletions(-)
>>>
>>> Reviewed-by: Max Reitz <mreitz@redhat.com>
>>>
>>>> diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
>>>> index b08bcb87e1..dfc753c319 100644
>>>> --- a/tests/qemu-iotests/iotests.py
>>>> +++ b/tests/qemu-iotests/iotests.py
>>>> @@ -37,6 +37,10 @@
>>>>  
>>>>  assert sys.version_info >= (3, 6)
>>>>  
>>>> +# Type Aliases
>>>> +QMPResponse = Dict[str, Any]
>>>> +
>>>> +
>>>>  faulthandler.enable()
>>>>  
>>>>  # This will not work if arguments contain spaces but is necessary if we
>>>> @@ -540,25 +544,30 @@ def add_incoming(self, addr):
>>>>          self._args.append(addr)
>>>>          return self
>>>>  
>>>> -    def pause_drive(self, drive, event=None):
>>>> -        '''Pause drive r/w operations'''
>>>> +    def hmp(self, command_line: str, use_log: bool = False) -> QMPResponse:
>>>> +        cmd = 'human-monitor-command'
>>>> +        kwargs = {'command-line': command_line}
>>>> +        if use_log:
>>>> +            return self.qmp_log(cmd, **kwargs)
>>>> +        else:
>>>> +            return self.qmp(cmd, **kwargs)
>>>
>>> Hm.  I suppose I should take this chance to understand something about
>>> mypy.  QEMUMachine.qmp() isn’t typed, so mypy can’t check that this
>>> really returns QMPResponse.  Is there some flag to make it?  Like
>>> --actually-check-types?
>>
>> There is --check-untyped-defs, but I'm not sure if that actually changes
>> the return type of untyped functions from Any to an inferred type. I
>> kind of doubt it.
> 
> Well, but Any doesn’t fit into QMPResponse, so there should be an error
> reported somewhere.
> 
>>> (--strict seems, well, overly strict?  Like not allowing generics, I
>>> don’t see why.  Or I suppose for the time being we want to allow untyped
>>> definitions, as long as they don’t break type assertions such as it kind
>>> of does here...?)
>>
>> At least, --strict does actually complain about this one because Any
>> isn't good enough any more (it includes --warn-return-any):
> 
> Hm, yes, but we’re not at a point where it’s really feasible to enable
> --strict...
> 
>> iotests.py:560: warning: Returning Any from function declared to return "Dict[str, Any]"
>> iotests.py:560: error: Call to untyped function "qmp_log" in typed context
>> iotests.py:562: warning: Returning Any from function declared to return "Dict[str, Any]"
>>
>> Not sure why you think it doesn't allow generics? I never had problems
>> with that, even in my Python museum. :-)
> 
> I thought --disallow-any-generics would mean that.  But I suppose mypy
> understands a “generic” to be something else than I do, as John
> described... *shrug*

Oh.  John didn’t describe that.  I just read the “Any” thing wrong,
again.  (On my first read, I thought he just used the back ticks to
stress the word “any”, not to refer to the type “Any”.)

Max
Kevin Wolf April 1, 2020, 1:51 p.m. UTC | #8
Am 01.04.2020 um 14:28 hat Max Reitz geschrieben:
> On 31.03.20 16:00, Kevin Wolf wrote:
> > Am 31.03.2020 um 12:21 hat Max Reitz geschrieben:
> >> On 31.03.20 02:00, John Snow wrote:
> >>> Minor cleanup for HMP functions; helps with line length and consolidates
> >>> HMP helpers through one implementation function.
> >>>
> >>> Although we are adding a universal toggle to turn QMP logging on or off,
> >>> many existing callers to hmp functions don't expect that output to be
> >>> logged, which causes quite a few changes in the test output.
> >>>
> >>> For now, offer a use_log parameter.
> >>>
> >>>
> >>> Typing notes:
> >>>
> >>> QMPResponse is just an alias for Dict[str, Any]. It holds no special
> >>> meanings and it is not a formal subtype of Dict[str, Any]. It is best
> >>> thought of as a lexical synonym.
> >>>
> >>> We may well wish to add stricter subtypes in the future for certain
> >>> shapes of data that are not formalized as Python objects, at which point
> >>> we can simply retire the alias and allow mypy to more strictly check
> >>> usages of the name.
> >>>
> >>> Signed-off-by: John Snow <jsnow@redhat.com>
> >>> ---
> >>>  tests/qemu-iotests/iotests.py | 35 ++++++++++++++++++++++-------------
> >>>  1 file changed, 22 insertions(+), 13 deletions(-)
> >>
> >> Reviewed-by: Max Reitz <mreitz@redhat.com>
> >>
> >>> diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
> >>> index b08bcb87e1..dfc753c319 100644
> >>> --- a/tests/qemu-iotests/iotests.py
> >>> +++ b/tests/qemu-iotests/iotests.py
> >>> @@ -37,6 +37,10 @@
> >>>  
> >>>  assert sys.version_info >= (3, 6)
> >>>  
> >>> +# Type Aliases
> >>> +QMPResponse = Dict[str, Any]
> >>> +
> >>> +
> >>>  faulthandler.enable()
> >>>  
> >>>  # This will not work if arguments contain spaces but is necessary if we
> >>> @@ -540,25 +544,30 @@ def add_incoming(self, addr):
> >>>          self._args.append(addr)
> >>>          return self
> >>>  
> >>> -    def pause_drive(self, drive, event=None):
> >>> -        '''Pause drive r/w operations'''
> >>> +    def hmp(self, command_line: str, use_log: bool = False) -> QMPResponse:
> >>> +        cmd = 'human-monitor-command'
> >>> +        kwargs = {'command-line': command_line}
> >>> +        if use_log:
> >>> +            return self.qmp_log(cmd, **kwargs)
> >>> +        else:
> >>> +            return self.qmp(cmd, **kwargs)
> >>
> >> Hm.  I suppose I should take this chance to understand something about
> >> mypy.  QEMUMachine.qmp() isn’t typed, so mypy can’t check that this
> >> really returns QMPResponse.  Is there some flag to make it?  Like
> >> --actually-check-types?
> > 
> > There is --check-untyped-defs, but I'm not sure if that actually changes
> > the return type of untyped functions from Any to an inferred type. I
> > kind of doubt it.
> 
> Well, but Any doesn’t fit into QMPResponse, so there should be an error
> reported somewhere.

Any is the void* of Python typing. It's compatible with everything else,
in both directions.

> >> (--strict seems, well, overly strict?  Like not allowing generics, I
> >> don’t see why.  Or I suppose for the time being we want to allow untyped
> >> definitions, as long as they don’t break type assertions such as it kind
> >> of does here...?)
> > 
> > At least, --strict does actually complain about this one because Any
> > isn't good enough any more (it includes --warn-return-any):
> 
> Hm, yes, but we’re not at a point where it’s really feasible to enable
> --strict...

We're not yet, but I think it's a reasonable goal.

Kevin
Max Reitz April 1, 2020, 2:53 p.m. UTC | #9
On 01.04.20 15:51, Kevin Wolf wrote:
> Am 01.04.2020 um 14:28 hat Max Reitz geschrieben:
>> On 31.03.20 16:00, Kevin Wolf wrote:
>>> Am 31.03.2020 um 12:21 hat Max Reitz geschrieben:
>>>> On 31.03.20 02:00, John Snow wrote:
>>>>> Minor cleanup for HMP functions; helps with line length and consolidates
>>>>> HMP helpers through one implementation function.
>>>>>
>>>>> Although we are adding a universal toggle to turn QMP logging on or off,
>>>>> many existing callers to hmp functions don't expect that output to be
>>>>> logged, which causes quite a few changes in the test output.
>>>>>
>>>>> For now, offer a use_log parameter.
>>>>>
>>>>>
>>>>> Typing notes:
>>>>>
>>>>> QMPResponse is just an alias for Dict[str, Any]. It holds no special
>>>>> meanings and it is not a formal subtype of Dict[str, Any]. It is best
>>>>> thought of as a lexical synonym.
>>>>>
>>>>> We may well wish to add stricter subtypes in the future for certain
>>>>> shapes of data that are not formalized as Python objects, at which point
>>>>> we can simply retire the alias and allow mypy to more strictly check
>>>>> usages of the name.
>>>>>
>>>>> Signed-off-by: John Snow <jsnow@redhat.com>
>>>>> ---
>>>>>  tests/qemu-iotests/iotests.py | 35 ++++++++++++++++++++++-------------
>>>>>  1 file changed, 22 insertions(+), 13 deletions(-)
>>>>
>>>> Reviewed-by: Max Reitz <mreitz@redhat.com>
>>>>
>>>>> diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
>>>>> index b08bcb87e1..dfc753c319 100644
>>>>> --- a/tests/qemu-iotests/iotests.py
>>>>> +++ b/tests/qemu-iotests/iotests.py
>>>>> @@ -37,6 +37,10 @@
>>>>>  
>>>>>  assert sys.version_info >= (3, 6)
>>>>>  
>>>>> +# Type Aliases
>>>>> +QMPResponse = Dict[str, Any]
>>>>> +
>>>>> +
>>>>>  faulthandler.enable()
>>>>>  
>>>>>  # This will not work if arguments contain spaces but is necessary if we
>>>>> @@ -540,25 +544,30 @@ def add_incoming(self, addr):
>>>>>          self._args.append(addr)
>>>>>          return self
>>>>>  
>>>>> -    def pause_drive(self, drive, event=None):
>>>>> -        '''Pause drive r/w operations'''
>>>>> +    def hmp(self, command_line: str, use_log: bool = False) -> QMPResponse:
>>>>> +        cmd = 'human-monitor-command'
>>>>> +        kwargs = {'command-line': command_line}
>>>>> +        if use_log:
>>>>> +            return self.qmp_log(cmd, **kwargs)
>>>>> +        else:
>>>>> +            return self.qmp(cmd, **kwargs)
>>>>
>>>> Hm.  I suppose I should take this chance to understand something about
>>>> mypy.  QEMUMachine.qmp() isn’t typed, so mypy can’t check that this
>>>> really returns QMPResponse.  Is there some flag to make it?  Like
>>>> --actually-check-types?
>>>
>>> There is --check-untyped-defs, but I'm not sure if that actually changes
>>> the return type of untyped functions from Any to an inferred type. I
>>> kind of doubt it.
>>
>> Well, but Any doesn’t fit into QMPResponse, so there should be an error
>> reported somewhere.
> 
> Any is the void* of Python typing. It's compatible with everything else,
> in both directions.

void* is handled differently by C and by C++.

Max
John Snow April 2, 2020, 6:27 p.m. UTC | #10
On 4/1/20 8:40 AM, Max Reitz wrote:
> On 31.03.20 19:39, Kevin Wolf wrote:
>> Am 31.03.2020 um 19:23 hat John Snow geschrieben:
>>>
>>>
>>> On 3/31/20 6:21 AM, Max Reitz wrote:
>>>> On 31.03.20 02:00, John Snow wrote:
>>>>> Minor cleanup for HMP functions; helps with line length and consolidates
>>>>> HMP helpers through one implementation function.
>>>>>
>>>>> Although we are adding a universal toggle to turn QMP logging on or off,
>>>>> many existing callers to hmp functions don't expect that output to be
>>>>> logged, which causes quite a few changes in the test output.
>>>>>
>>>>> For now, offer a use_log parameter.
>>>>>
>>>>>
>>>>> Typing notes:
>>>>>
>>>>> QMPResponse is just an alias for Dict[str, Any]. It holds no special
>>>>> meanings and it is not a formal subtype of Dict[str, Any]. It is best
>>>>> thought of as a lexical synonym.
>>>>>
>>>>> We may well wish to add stricter subtypes in the future for certain
>>>>> shapes of data that are not formalized as Python objects, at which point
>>>>> we can simply retire the alias and allow mypy to more strictly check
>>>>> usages of the name.
>>>>>
>>>>> Signed-off-by: John Snow <jsnow@redhat.com>
>>>>> ---
>>>>>  tests/qemu-iotests/iotests.py | 35 ++++++++++++++++++++++-------------
>>>>>  1 file changed, 22 insertions(+), 13 deletions(-)
>>>>
>>>> Reviewed-by: Max Reitz <mreitz@redhat.com>
>>>>
>>>>> diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
>>>>> index b08bcb87e1..dfc753c319 100644
>>>>> --- a/tests/qemu-iotests/iotests.py
>>>>> +++ b/tests/qemu-iotests/iotests.py
>>>>> @@ -37,6 +37,10 @@
>>>>>  
>>>>>  assert sys.version_info >= (3, 6)
>>>>>  
>>>>> +# Type Aliases
>>>>> +QMPResponse = Dict[str, Any]
>>>>> +
>>>>> +
>>>>>  faulthandler.enable()
>>>>>  
>>>>>  # This will not work if arguments contain spaces but is necessary if we
>>>>> @@ -540,25 +544,30 @@ def add_incoming(self, addr):
>>>>>          self._args.append(addr)
>>>>>          return self
>>>>>  
>>>>> -    def pause_drive(self, drive, event=None):
>>>>> -        '''Pause drive r/w operations'''
>>>>> +    def hmp(self, command_line: str, use_log: bool = False) -> QMPResponse:
>>>>> +        cmd = 'human-monitor-command'
>>>>> +        kwargs = {'command-line': command_line}
>>>>> +        if use_log:
>>>>> +            return self.qmp_log(cmd, **kwargs)
>>>>> +        else:
>>>>> +            return self.qmp(cmd, **kwargs)
>>>>
>>>> Hm.  I suppose I should take this chance to understand something about
>>>> mypy.  QEMUMachine.qmp() isn’t typed, so mypy can’t check that this
>>>> really returns QMPResponse.  Is there some flag to make it?  Like
>>>> --actually-check-types?
>>>>
>>>
>>> One of --strict's implied options, I'm not sure which. Otherwise, mypy
>>> is geared towards a 'gradual typing' discipline.
>>>
>>> In truth, I'm a little thankful for that because it helps avoid yak
>>> shaving marathons.
> 
> Sure.  I was just looking into the different options.  I was interested
> in whether I could come up with a mode that leaves wholly untyped code
> alone, but warns for code that mixes it.  Or something.
> 
>>> It does mean that sometimes the annotations don't "do anything" yet,
>>> apart from offering hints and documentation in e.g. pycharm. Which does
>>> mean that sometimes they can be completely wrong...
>>>
>>> The more we add, the more we'll catch problems.
>>>
>>> Once this series is dusted I'll try to tackle more conversions for
>>> iotests, qmp, etc. I've got a few WIP patches to tackle conversions for
>>> tests/qemu-iotests/*.py but I am trying to shepherd this one in first
>>> before I go bananas.
> 
> Sure, sure.
> 
>>>> (--strict seems, well, overly strict?  Like not allowing generics, I
>>>> don’t see why.  Or I suppose for the time being we want to allow untyped
>>>> definitions, as long as they don’t break type assertions such as it kind
>>>> of does here...?)
>>>>
>>>
>>> "disallow-any-generics" means disallowing `Any` generics, not
>>> disallowing generics ... in general. (I think? I've been using mypy in
>>> strict mode for a personal project a lot lately and I use generics in a
>>> few places, it seems OK.)
>>
>> --disallow-any-generics
>>       disallow usage of generic types that do not specify explicit type parameters
>>
>> So it will complain if you say just List, and you need to be explicit if
>> you really want List[Any]. Which I think is a reasonable thing to
>> require.
> 
> OK.  So it’s “disallow ‘any’ generics”, not “disallow any ‘generic’s”.
> Not easy to parse.  (Yes, yes, I should’ve actually read the man page...)
> 
> Good to know that mypy and me actually do seem to loosely agree on what
> a generic is. :)
> 
> Max
> 

Are we squared up for this series? I am actually not sure.

--js
Kevin Wolf April 3, 2020, 7:46 a.m. UTC | #11
Am 02.04.2020 um 20:27 hat John Snow geschrieben:
> On 4/1/20 8:40 AM, Max Reitz wrote:
> > On 31.03.20 19:39, Kevin Wolf wrote:
> >> Am 31.03.2020 um 19:23 hat John Snow geschrieben:
> >>>
> >>>
> >>> On 3/31/20 6:21 AM, Max Reitz wrote:
> >>>> On 31.03.20 02:00, John Snow wrote:
> >>>>> Minor cleanup for HMP functions; helps with line length and consolidates
> >>>>> HMP helpers through one implementation function.
> >>>>>
> >>>>> Although we are adding a universal toggle to turn QMP logging on or off,
> >>>>> many existing callers to hmp functions don't expect that output to be
> >>>>> logged, which causes quite a few changes in the test output.
> >>>>>
> >>>>> For now, offer a use_log parameter.
> >>>>>
> >>>>>
> >>>>> Typing notes:
> >>>>>
> >>>>> QMPResponse is just an alias for Dict[str, Any]. It holds no special
> >>>>> meanings and it is not a formal subtype of Dict[str, Any]. It is best
> >>>>> thought of as a lexical synonym.
> >>>>>
> >>>>> We may well wish to add stricter subtypes in the future for certain
> >>>>> shapes of data that are not formalized as Python objects, at which point
> >>>>> we can simply retire the alias and allow mypy to more strictly check
> >>>>> usages of the name.
> >>>>>
> >>>>> Signed-off-by: John Snow <jsnow@redhat.com>
> >>>>> ---
> >>>>>  tests/qemu-iotests/iotests.py | 35 ++++++++++++++++++++++-------------
> >>>>>  1 file changed, 22 insertions(+), 13 deletions(-)
> >>>>
> >>>> Reviewed-by: Max Reitz <mreitz@redhat.com>
> >>>>
> >>>>> diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
> >>>>> index b08bcb87e1..dfc753c319 100644
> >>>>> --- a/tests/qemu-iotests/iotests.py
> >>>>> +++ b/tests/qemu-iotests/iotests.py
> >>>>> @@ -37,6 +37,10 @@
> >>>>>  
> >>>>>  assert sys.version_info >= (3, 6)
> >>>>>  
> >>>>> +# Type Aliases
> >>>>> +QMPResponse = Dict[str, Any]
> >>>>> +
> >>>>> +
> >>>>>  faulthandler.enable()
> >>>>>  
> >>>>>  # This will not work if arguments contain spaces but is necessary if we
> >>>>> @@ -540,25 +544,30 @@ def add_incoming(self, addr):
> >>>>>          self._args.append(addr)
> >>>>>          return self
> >>>>>  
> >>>>> -    def pause_drive(self, drive, event=None):
> >>>>> -        '''Pause drive r/w operations'''
> >>>>> +    def hmp(self, command_line: str, use_log: bool = False) -> QMPResponse:
> >>>>> +        cmd = 'human-monitor-command'
> >>>>> +        kwargs = {'command-line': command_line}
> >>>>> +        if use_log:
> >>>>> +            return self.qmp_log(cmd, **kwargs)
> >>>>> +        else:
> >>>>> +            return self.qmp(cmd, **kwargs)
> >>>>
> >>>> Hm.  I suppose I should take this chance to understand something about
> >>>> mypy.  QEMUMachine.qmp() isn’t typed, so mypy can’t check that this
> >>>> really returns QMPResponse.  Is there some flag to make it?  Like
> >>>> --actually-check-types?
> >>>>
> >>>
> >>> One of --strict's implied options, I'm not sure which. Otherwise, mypy
> >>> is geared towards a 'gradual typing' discipline.
> >>>
> >>> In truth, I'm a little thankful for that because it helps avoid yak
> >>> shaving marathons.
> > 
> > Sure.  I was just looking into the different options.  I was interested
> > in whether I could come up with a mode that leaves wholly untyped code
> > alone, but warns for code that mixes it.  Or something.
> > 
> >>> It does mean that sometimes the annotations don't "do anything" yet,
> >>> apart from offering hints and documentation in e.g. pycharm. Which does
> >>> mean that sometimes they can be completely wrong...
> >>>
> >>> The more we add, the more we'll catch problems.
> >>>
> >>> Once this series is dusted I'll try to tackle more conversions for
> >>> iotests, qmp, etc. I've got a few WIP patches to tackle conversions for
> >>> tests/qemu-iotests/*.py but I am trying to shepherd this one in first
> >>> before I go bananas.
> > 
> > Sure, sure.
> > 
> >>>> (--strict seems, well, overly strict?  Like not allowing generics, I
> >>>> don’t see why.  Or I suppose for the time being we want to allow untyped
> >>>> definitions, as long as they don’t break type assertions such as it kind
> >>>> of does here...?)
> >>>>
> >>>
> >>> "disallow-any-generics" means disallowing `Any` generics, not
> >>> disallowing generics ... in general. (I think? I've been using mypy in
> >>> strict mode for a personal project a lot lately and I use generics in a
> >>> few places, it seems OK.)
> >>
> >> --disallow-any-generics
> >>       disallow usage of generic types that do not specify explicit type parameters
> >>
> >> So it will complain if you say just List, and you need to be explicit if
> >> you really want List[Any]. Which I think is a reasonable thing to
> >> require.
> > 
> > OK.  So it’s “disallow ‘any’ generics”, not “disallow any ‘generic’s”.
> > Not easy to parse.  (Yes, yes, I should’ve actually read the man page...)
> > 
> > Good to know that mypy and me actually do seem to loosely agree on what
> > a generic is. :)
> > 
> > Max
> > 
> 
> Are we squared up for this series? I am actually not sure.

I had a comment in patch 14 which you may or may not want to address (my
R-b was unconditional). I think everything else was just tangential
discussion.

Kevin
Max Reitz April 3, 2020, 8:57 a.m. UTC | #12
On 02.04.20 20:27, John Snow wrote:

[...]

> Are we squared up for this series? I am actually not sure.

As far as I’m concerned, yes.  I just had this question on how to use mypy.

Max
John Snow April 4, 2020, 2:38 a.m. UTC | #13
On 4/3/20 4:57 AM, Max Reitz wrote:
> On 02.04.20 20:27, John Snow wrote:
> 
> [...]
> 
>> Are we squared up for this series? I am actually not sure.
> 
> As far as I’m concerned, yes.  I just had this question on how to use mypy.

Oh, whoops, Kevin's comment.

I do want to address that one.

Sorry, I am a bit distracted right now. The last few weeks have been
tough. Having a hard time keeping track of things right now.

--js
diff mbox series

Patch

diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
index b08bcb87e1..dfc753c319 100644
--- a/tests/qemu-iotests/iotests.py
+++ b/tests/qemu-iotests/iotests.py
@@ -37,6 +37,10 @@ 
 
 assert sys.version_info >= (3, 6)
 
+# Type Aliases
+QMPResponse = Dict[str, Any]
+
+
 faulthandler.enable()
 
 # This will not work if arguments contain spaces but is necessary if we
@@ -540,25 +544,30 @@  def add_incoming(self, addr):
         self._args.append(addr)
         return self
 
-    def pause_drive(self, drive, event=None):
-        '''Pause drive r/w operations'''
+    def hmp(self, command_line: str, use_log: bool = False) -> QMPResponse:
+        cmd = 'human-monitor-command'
+        kwargs = {'command-line': command_line}
+        if use_log:
+            return self.qmp_log(cmd, **kwargs)
+        else:
+            return self.qmp(cmd, **kwargs)
+
+    def pause_drive(self, drive: str, event: Optional[str] = None) -> None:
+        """Pause drive r/w operations"""
         if not event:
             self.pause_drive(drive, "read_aio")
             self.pause_drive(drive, "write_aio")
             return
-        self.qmp('human-monitor-command',
-                 command_line='qemu-io %s "break %s bp_%s"'
-                 % (drive, event, drive))
+        self.hmp(f'qemu-io {drive} "break {event} bp_{drive}"')
 
-    def resume_drive(self, drive):
-        self.qmp('human-monitor-command',
-                 command_line='qemu-io %s "remove_break bp_%s"'
-                 % (drive, drive))
+    def resume_drive(self, drive: str) -> None:
+        """Resume drive r/w operations"""
+        self.hmp(f'qemu-io {drive} "remove_break bp_{drive}"')
 
-    def hmp_qemu_io(self, drive, cmd):
-        '''Write to a given drive using an HMP command'''
-        return self.qmp('human-monitor-command',
-                        command_line='qemu-io %s "%s"' % (drive, cmd))
+    def hmp_qemu_io(self, drive: str, cmd: str,
+                    use_log: bool = False) -> QMPResponse:
+        """Write to a given drive using an HMP command"""
+        return self.hmp(f'qemu-io {drive} "{cmd}"', use_log=use_log)
 
     def flatten_qmp_object(self, obj, output=None, basestr=''):
         if output is None: