1
0
mirror of https://gitlab.com/libvirt/libvirt-python.git synced 2024-10-26 07:55:06 +03:00
Commit Graph

20 Commits

Author SHA1 Message Date
Daniel P. Berrangé
c2fae558c3 libvirtaio: add better docs on best practice usage pattern
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
2022-06-08 16:43:52 +01:00
Daniel P. Berrangé
376a977659 libvirtio: lazy create the Event object in drain()
The drain method uses an asyncio.Event object to be notified when other
coroutines have removed all registered callbacks. The Event object needs
to be associated with the coroutine that the event loop is running with
and currently this is achieved by passing in the 'loop' parameter.

Unfortunately Python 3.10 has removed the 'loop' parameter and now the
object is associated implicitly with the current thread's event loop.
At the time the virEventAsyncIOImpl constructor is called, however,
there is no guarantee that an event loop has been set for the thread.
The explicitly passed in 'loop' parameter would handle this scenario.

For portability with Python >= 3.10 we need to delay creation of the
Event object until we have a guarantee that there is a loop associated
with the current thread. This is achieved by lazily creating the Event
object inside the 'drain' method, which is expected to be invoked from
coroutine context and thus ensure a loop is associated.

Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
2022-06-08 16:43:52 +01:00
Chris Gunn
30f8123072 libvirtaio: convert to using 'async' / 'await' syntax
The 'async' keyword is new in Python 3.5, as a way to declare that a
method is a coroutine. This replaces the '@asyncio.coroutine' decorator
that is deprecated since 3.8 and scheduled to be removed in 3.11

The 'await' keyword has to be used instead of 'yield' from any
coroutines declared with 'async'.

Signed-off-by: Chris Gunn <chrisgun@microsoft.com>
[DB: Split off from a larger patch mixing multiple changes]
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
2022-06-08 16:43:52 +01:00
Chris Gunn
ca3731a126 libvirtaio: drop back compat for python < 3.4.4
setup.py ensures we have python >= 3.5, so there is no need to do
back compat with the 'asyncio.ensure_future' method, which was new
in 3.4.4

Signed-off-by: Chris Gunn <chrisgun@microsoft.com>
[DB: Split off from a larger patch mixing multiple changes]
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
2022-06-08 16:43:52 +01:00
Philipp Hahn
8c800b0adf Revert "libvirtaio: Drop object(*args, **kwargs)"
This reverts commit f4be03b330.

While object.__init__() does not expect any additional arguments, this
construct is required for Pythons multiple inheritance implementation.
The original author Wojtek Porczyk <woju@invisiblethingslab.com>
explained is this way:

> I'm sorry I didn't notice this earlier, but the commit f4be03b3 dated
> 2020-04-20 [0] is wrong. The super().__init__(*args, **kwargs) in
> Callback.__init__ was there on purpose, because of how Python's inheritance in
> new-style classes works.
>
> Let me explain this a bit, because it is not obvious.
>
> Suppose you had diamond inheritance like this:
>
>     class A(object): pass
>     class B(A): pass
>     class C(A): pass
>     class D(B,C): pass
>
> And those classes needed a common function with varying arguments:
>
>     class A(object):
>         def spam(self, a): print(f'A: {a}')
>     class B(A):
>         def spam(self, b): print(f'B: {b}')
>     class C(A):
>         def spam(self, c): print(f'C: {c}')
>     class D(B,C):
>         def spam(self, d): print(f'D: {d}')
>
> The way to call all parent's functions exactly once (as per MRO) and accept
> all arguments and also forbid unknown arguments is to accept **kwargs
> everywhere and pass them to super().spam():
>
>     class A:
>         def spam(self, a):
>             print(f'A: {a}')
>     class B(A):
>         def spam(self, b, **kwargs):
>             print(f'B: {b}')
>             super().spam(**kwargs)
>     class C(A):
>         def spam(self, c, **kwargs):
>             print(f'C: {c}')
>             super().spam(**kwargs)
>     class D(B, C):
>         def spam(self, d, **kwargs):
>             print(f'D: {d}')
>             super().spam(**kwargs)
>
> Let's run this:
>
>     >>> B().spam(a=1, b=2)
>     B: 2
>     A: 1
>     >>> D().spam(a=1, b=2, c=3, d=4)
>     D: 4
>     B: 2
>     C: 3
>     A: 1
>
> You may notice that super() in B.spam refers to two different classes, either
> A or C, depending on inheritance order in yet undefined classes (as of B's
> definition).
>
> That's why the conclusion that super() in Callback.__init__ refers to object
> is wrong. In this example, spam=__init__, A=object, B=Callback and C and D are
> not yet written, but theoretically possible classes that could be written by
> someone else. Why would they be needed, I don't know, but if someone writes
> them, s/he would be out of options to invent new arguments to C.__init__.
>
> Note that super().__init__(*args, **kwargs) when super() refers to object
> isn't harmful, and just ensures that args and kwargs are empty (i.e. no
> unknown arguments were passed). In fact, this is exactly why object.__init__()
> takes no arguments since Python 2.6 [1][2], as you correctly point out in the
> commit message.
>
> I don't think this breaks anything (I very much doubt anyone would need to
> write code that would trigger this), nevertheless, as the commit is both
> pointless and wrong, and as the original author of libvirtaio I'd like to ask
> for this commit to be reverted. If this breaks some static analysis tool,
> could you just suppress it for this particular line?
>
>
> [0] f4be03b330
> [1] https://bugs.python.org/issue1683368
> [2] https://docs.python.org/3/whatsnew/2.6.html#porting-to-python-2-6
>     (fourth point)
>

Signed-off-by: Philipp Hahn <hahn@univention.de>
2020-08-28 18:42:48 +02:00
Philipp Hahn
026a47928a libvirtaio: Add manual PEP 484 type annotations
Signed-off-by: Philipp Hahn <hahn@univention.de>
2020-08-07 18:05:53 +02:00
Philipp Hahn
6b97281730 libvirtaio: assert callback type
self.callbacks contains a mix of FDCallback and TimeoutCallback, while
the update code does not explicitly check for.

Signed-off-by: Philipp Hahn <hahn@univention.de>
2020-08-06 08:50:37 +02:00
Philipp Hahn
12d631d11a libvirtaio: Fix return type
libvirtaio.py:364: error: "virEventInvokeFreeCallback" does not return a value

Signed-off-by: Philipp Hahn <hahn@univention.de>
2020-08-06 08:50:37 +02:00
Philipp Hahn
f4be03b330 libvirtaio: Drop object(*args, **kwargs)
object.__init__() does not expect those parameters.

Signed-off-by: Philipp Hahn <hahn@univention.de>
2020-08-06 08:50:37 +02:00
Philipp Hahn
429973c836 libvirtaio: Cleanup imports
Move imports to top

Signed-off-by: Philipp Hahn <hahn@univention.de>
2020-08-06 08:50:37 +02:00
Philipp Hahn
0ca8dc6340 Normalize white space
indent by 4 spaces
one spaces around assignments

Signed-off-by: Philipp Hahn <hahn@univention.de>
2020-08-06 08:50:37 +02:00
Philipp Hahn
cfcf988a98 libvirtaio: Fix return types of callback
libvirt defines the signature for the callback functions, e.g. the
functions for remove() must return -1 on error and 0 on success. Raising
an exception violates that contract.

_remove_timeout() did not explicitly handle a double-remove and
implicitly passed on the exception.

update() expects no return value, so remove the pointless return to pass
on None.

Signed-off-by: Philipp Hahn <hahn@univention.de>
2020-07-27 13:24:36 +02:00
Cole Robinson
e27528204c libvirtaio: Fix compat with python 3.7
In python 3.7, async is now a keyword, so this throws a syntax error:

  File "/usr/lib64/python3.7/site-packages/libvirtaio.py", line 49
    from asyncio import async as ensure_future
                            ^
  SyntaxError: invalid syntax

Switch to getattr trickery to accomplish the same goal

Reviewed-by: Pavel Hrdina <phrdina@redhat.com>
Reviewed-by: Andrea Bolognani <abologna@redhat.com>
Signed-off-by: Cole Robinson <crobinso@redhat.com>
2018-06-27 10:07:39 -04:00
Wojtek Porczyk
f70939fc3e libvirtaio: add .drain() coroutine
The intended use is to ensure that the implementation is empty, which is
one way to ensure that all connections were properly closed and file
descriptors reclaimed.

Signed-off-by: Wojtek Porczyk <woju@invisiblethingslab.com>
2017-09-26 11:01:33 +01:00
Wojtek Porczyk
7f1994ff46 libvirtaio: keep track of the current implementation
Since 7534c19 it is not possible to register event implementation twice.
Instead, allow for retrieving the current one, should it be needed
afterwards.

Signed-off-by: Wojtek Porczyk <woju@invisiblethingslab.com>
2017-09-26 11:01:33 +01:00
Wojtek Porczyk
fc482fc868 libvirtaio: fix closing of the objects
- Descriptor.close() was a dead code, never used.
- TimeoutCallback.close(), as a cleanup function, should have called
    super() as last statement, not first

Signed-off-by: Wojtek Porczyk <woju@invisiblethingslab.com>
2017-09-26 11:01:33 +01:00
Wojtek Porczyk
cc82a94528 libvirtaio: do not double-add callbacks
This was a harmless bug, without any impact, but it is wrong to manage
the collection of callbacks from it's members.

Signed-off-by: Wojtek Porczyk <woju@invisiblethingslab.com>
2017-09-26 11:01:33 +01:00
Wojtek Porczyk
a5cc6da2c8 libvirtaio: cache the list of callbacks when calling
When the callback causes something that results in changes wrt
registered handles, python aborts iteration.

Relevant error message:

    Exception in callback None()
    handle: <Handle cancelled>
    Traceback (most recent call last):
      File "/usr/lib64/python3.5/asyncio/events.py", line 126, in _run
        self._callback(*self._args)
      File "/usr/lib64/python3.5/site-packages/libvirtaio.py", line 99, in _handle
        for callback in self.callbacks.values():
    RuntimeError: dictionary changed size during iteration

QubesOS/qubes-issues#2805
Signed-off-by: Wojtek Porczyk <woju@invisiblethingslab.com>
2017-09-26 11:01:33 +01:00
Wojtek Porczyk
f7e5a9a085 libvirtaio: add more debug logging
This logging is helpful for tracing problems with unclosed connections
and leaking file descriptors.

Signed-off-by: Wojtek Porczyk <woju@invisiblethingslab.com>
2017-09-26 11:01:33 +01:00
Wojtek Porczyk
e985010674 Add asyncio event loop implementation
This is usable only on python >= 3.4 (or 3.3 with out-of-tree asyncio),
however it should be harmless for anyone with older python versions.

In simplest case, to have the callbacks queued on the default loop:

    >>> import libvirtaio
    >>> libvirtaio.virEventRegisterAsyncIOImpl()

The function is not present on non-compatible platforms.

Signed-off-by: Wojtek Porczyk <woju@invisiblethingslab.com>
2017-04-04 15:28:50 +01:00