Hello community,

here is the log from the commit of package libvirt-python for openSUSE:Factory 
checked in at 2017-05-09 18:09:50
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/libvirt-python (Old)
 and      /work/SRC/openSUSE:Factory/.libvirt-python.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "libvirt-python"

Tue May  9 18:09:50 2017 rev:41 rq:493580 version:3.3.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/libvirt-python/libvirt-python.changes    
2017-04-06 11:02:51.821533179 +0200
+++ /work/SRC/openSUSE:Factory/.libvirt-python.new/libvirt-python.changes       
2017-05-09 18:09:52.215913160 +0200
@@ -1,0 +2,7 @@
+Mon May  8 17:40:15 UTC 2017 - [email protected]
+
+- Update to 3.3.0
+  - Add all new APIs and constants in libvirt 3.3.0
+  - FATE#319684, FATE#321335, FATE#321349
+
+-------------------------------------------------------------------

Old:
----
  libvirt-python-3.2.0.tar.gz
  libvirt-python-3.2.0.tar.gz.asc

New:
----
  libvirt-python-3.3.0.tar.gz
  libvirt-python-3.3.0.tar.gz.asc

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ libvirt-python.spec ++++++
--- /var/tmp/diff_new_pack.fAfKDX/_old  2017-05-09 18:09:52.899816516 +0200
+++ /var/tmp/diff_new_pack.fAfKDX/_new  2017-05-09 18:09:52.903815951 +0200
@@ -18,7 +18,7 @@
 
 Name:           libvirt-python
 Url:            http://libvirt.org/
-Version:        3.2.0
+Version:        3.3.0
 Release:        0
 Summary:        Library providing a simple virtualization API
 License:        LGPL-2.1+

++++++ libvirt-python-3.2.0.tar.gz -> libvirt-python-3.3.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libvirt-python-3.2.0/AUTHORS 
new/libvirt-python-3.3.0/AUTHORS
--- old/libvirt-python-3.2.0/AUTHORS    2017-04-02 17:10:54.000000000 +0200
+++ new/libvirt-python-3.3.0/AUTHORS    2017-05-05 21:48:18.000000000 +0200
@@ -75,6 +75,7 @@
    Tomoki Sekiyama <[email protected]>
    Victor Stinner <[email protected]>
    Viktor Mihajlovski <[email protected]>
+   Wojtek Porczyk <[email protected]>
    Wu Zongyong <[email protected]>
    Zeeshan Ali (Khattak) <[email protected]>
    Zhou Yimin <[email protected]>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libvirt-python-3.2.0/ChangeLog 
new/libvirt-python-3.3.0/ChangeLog
--- old/libvirt-python-3.2.0/ChangeLog  2017-04-02 17:10:54.000000000 +0200
+++ new/libvirt-python-3.3.0/ChangeLog  2017-05-05 21:48:18.000000000 +0200
@@ -1,3 +1,75 @@
+2017-04-04 Daniel P. Berrange  <[email protected]>
+    
+    event-test: add ability to run the asyncio event loop
+    The event test program '--loop' arg is modified to take the name
+    of an event loop impl to run. eg 'event-test.py --loop asyncio'
+    
+    
+    
+2017-04-04 Daniel P. Berrange  <[email protected]>
+    
+    event-test: rename example event loop impl
+    Use the name 'Poll' instead of 'Pure' for the event loop demo,
+    since there's now a second pure python loop impl available.
+    
+    
+    
+2017-04-04 Daniel P. Berrange  <[email protected]>
+    
+    event-test: unregister callbacks & close conn on exit
+    In order to test cleanup code paths we must unregister all callbacks
+    and close the connection on shutdown. Since cleanup happens in the
+    background, we do a short sleep to allow the main loop to run its
+    cleanup too.
+    
+    
+    
+2017-04-04 Daniel P. Berrange  <[email protected]>
+    
+    event-test: add timeout to exit event loop
+    
+    
+2017-04-04 Daniel P. Berrange  <[email protected]>
+    
+    event-test: free opaque data when removing callbacks
+    The pure python event loop impl has to call
+    
+    libvirt.virEventInvokeFreeCallback
+    
+    to free the event opaque data from a clean stack context
+    
+    
+    
+2017-04-04 Wojtek Porczyk  <[email protected]>
+    
+    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.
+    
+    
+    
+2017-04-04 Wojtek Porczyk  <[email protected]>
+    
+    Allow for ff callbacks to be called by custom event implementations
+    The documentation says:
+    > If the opaque user data requires free'ing when the handle is
+    > unregistered, then a 2nd callback can be supplied for this purpose.
+    > This callback needs to be invoked from a clean stack. If 'ff'
+    > callbacks are invoked directly from the virEventRemoveHandleFunc they
+    > will likely deadlock in libvirt.
+    
+    And they did deadlock. In removeTimeout too. Now we supply a custom
+    function to pick it from the opaque blob and fire.
+    
+    
+    
 2017-04-02 Daniel Veillard  <[email protected]>
     
     Release of libvirt-python-3.2.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libvirt-python-3.2.0/PKG-INFO 
new/libvirt-python-3.3.0/PKG-INFO
--- old/libvirt-python-3.2.0/PKG-INFO   2017-04-02 17:10:54.000000000 +0200
+++ new/libvirt-python-3.3.0/PKG-INFO   2017-05-05 21:48:18.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: libvirt-python
-Version: 3.2.0
+Version: 3.3.0
 Summary: The libvirt virtualization API python binding
 Home-page: http://www.libvirt.org
 Author: Libvirt Maintainers
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libvirt-python-3.2.0/examples/event-test.py 
new/libvirt-python-3.3.0/examples/event-test.py
--- old/libvirt-python-3.2.0/examples/event-test.py     2017-04-02 
16:52:04.000000000 +0200
+++ new/libvirt-python-3.3.0/examples/event-test.py     2017-05-05 
21:39:32.000000000 +0200
@@ -15,16 +15,19 @@
 import time
 import threading
 
-# For the sake of demonstration, this example program includes
-# an implementation of a pure python event loop. Most applications
-# would be better off just using the default libvirt event loop
-# APIs, instead of implementing this in python. The exception is
-# where an application wants to integrate with an existing 3rd
-# party event loop impl
+# This example can use three different event loop impls. It defaults
+# to a portable pure-python impl based on poll that is implemented
+# in this file.
 #
-# Change this to 'False' to make the demo use the native
-# libvirt event loop impl
-use_pure_python_event_loop = True
+# When Python >= 3.4, it can optionally use an impl based on the
+# new asyncio module.
+#
+# Finally, it can also use the libvirt native event loop impl
+#
+# This setting thus allows 'poll', 'native' or 'asyncio' as valid
+# choices
+#
+event_impl = "poll"
 
 do_debug = False
 def debug(msg):
@@ -39,10 +42,10 @@
 #
 # It is a pure python implementation based around the poll() API
 #
-class virEventLoopPure:
+class virEventLoopPoll:
     # This class contains the data we need to track for a
     # single file handle
-    class virEventLoopPureHandle:
+    class virEventLoopPollHandle:
         def __init__(self, handle, fd, events, cb, opaque):
             self.handle = handle
             self.fd = fd
@@ -70,7 +73,7 @@
 
     # This class contains the data we need to track for a
     # single periodic timer
-    class virEventLoopPureTimer:
+    class virEventLoopPollTimer:
         def __init__(self, timer, interval, cb, opaque):
             self.timer = timer
             self.interval = interval
@@ -107,6 +110,7 @@
         self.nextTimerID = 1
         self.handles = []
         self.timers = []
+        self.cleanup = []
         self.quit = False
 
         # The event loop can be used from multiple threads at once.
@@ -141,14 +145,14 @@
 
         return next
 
-    # Lookup a virEventLoopPureHandle object based on file descriptor
+    # Lookup a virEventLoopPollHandle object based on file descriptor
     def get_handle_by_fd(self, fd):
         for h in self.handles:
             if h.get_fd() == fd:
                 return h
         return None
 
-    # Lookup a virEventLoopPureHandle object based on its event loop ID
+    # Lookup a virEventLoopPollHandle object based on its event loop ID
     def get_handle_by_id(self, handleID):
         for h in self.handles:
             if h.get_id() == handleID:
@@ -178,6 +182,11 @@
     def run_once(self):
         sleep = -1
         self.runningPoll = True
+
+        for opaque in self.cleanup:
+            libvirt.virEventInvokeFreeCallback(opaque)
+        self.cleanup = []
+
         try:
             next = self.next_timeout()
             debug("Next timeout due at %d" % next)
@@ -247,7 +256,7 @@
         handleID = self.nextHandleID + 1
         self.nextHandleID = self.nextHandleID + 1
 
-        h = self.virEventLoopPureHandle(handleID, fd, events, cb, opaque)
+        h = self.virEventLoopPollHandle(handleID, fd, events, cb, opaque)
         self.handles.append(h)
 
         self.poll.register(fd, self.events_to_poll(events))
@@ -266,7 +275,7 @@
         timerID = self.nextTimerID + 1
         self.nextTimerID = self.nextTimerID + 1
 
-        h = self.virEventLoopPureTimer(timerID, interval, cb, opaque)
+        h = self.virEventLoopPollTimer(timerID, interval, cb, opaque)
         self.timers.append(h)
         self.interrupt()
 
@@ -300,8 +309,9 @@
         handles = []
         for h in self.handles:
             if h.get_id() == handleID:
-                self.poll.unregister(h.get_fd())
                 debug("Remove handle %d fd %d" % (handleID, h.get_fd()))
+                self.poll.unregister(h.get_fd())
+                self.cleanup.append(h.opaque)
             else:
                 handles.append(h)
         self.handles = handles
@@ -313,7 +323,9 @@
         for h in self.timers:
             if h.get_id() != timerID:
                 timers.append(h)
+            else:
                 debug("Remove timer %d" % timerID)
+                self.cleanup.append(h.opaque)
         self.timers = timers
         self.interrupt()
 
@@ -352,7 +364,7 @@
 
 # This single global instance of the event loop wil be used for
 # monitoring libvirt events
-eventLoop = virEventLoopPure()
+eventLoop = virEventLoopPoll()
 
 # This keeps track of what thread is running the event loop,
 # (if it is run in a background thread)
@@ -362,7 +374,7 @@
 # These next set of 6 methods are the glue between the official
 # libvirt events API, and our particular impl of the event loop
 #
-# There is no reason why the 'virEventLoopPure' has to be used.
+# There is no reason why the 'virEventLoopPoll' has to be used.
 # An application could easily may these 6 glue methods hook into
 # another event loop such as GLib's, or something like the python
 # Twisted event framework.
@@ -393,7 +405,7 @@
 
 # This tells libvirt what event loop implementation it
 # should use
-def virEventLoopPureRegister():
+def virEventLoopPollRegister():
     libvirt.virEventRegisterImpl(virEventAddHandleImpl,
                                  virEventUpdateHandleImpl,
                                  virEventRemoveHandleImpl,
@@ -402,19 +414,34 @@
                                  virEventRemoveTimerImpl)
 
 # Directly run the event loop in the current thread
-def virEventLoopPureRun():
+def virEventLoopPollRun():
     global eventLoop
     eventLoop.run_loop()
 
+def virEventLoopAIORun(loop):
+    import asyncio
+    asyncio.set_event_loop(loop)
+    loop.run_forever()
+
 def virEventLoopNativeRun():
     while True:
         libvirt.virEventRunDefaultImpl()
 
 # Spawn a background thread to run the event loop
-def virEventLoopPureStart():
+def virEventLoopPollStart():
     global eventLoopThread
-    virEventLoopPureRegister()
-    eventLoopThread = threading.Thread(target=virEventLoopPureRun, 
name="libvirtEventLoop")
+    virEventLoopPollRegister()
+    eventLoopThread = threading.Thread(target=virEventLoopPollRun, 
name="libvirtEventLoop")
+    eventLoopThread.setDaemon(True)
+    eventLoopThread.start()
+
+def virEventLoopAIOStart():
+    global eventLoopThread
+    import libvirtaio
+    import asyncio
+    loop = asyncio.new_event_loop()
+    libvirtaio.virEventRegisterAsyncIOImpl(loop=loop)
+    eventLoopThread = threading.Thread(target=virEventLoopAIORun, 
args=(loop,), name="libvirtEventLoop")
     eventLoopThread.setDaemon(True)
     eventLoopThread.start()
 
@@ -641,16 +668,18 @@
     print("   uri will default to qemu:///system")
     print("   --help, -h   Print(this help message")
     print("   --debug, -d  Print(debug output")
-    print("   --loop, -l   Toggle event-loop-implementation")
+    print("   --loop=TYPE, -l   Choose event-loop-implementation (native, 
poll, asyncio)")
+    print("   --timeout=SECS  Quit after SECS seconds running")
 
 def main():
     try:
-        opts, args = getopt.getopt(sys.argv[1:], "hdl", ["help", "debug", 
"loop"])
+        opts, args = getopt.getopt(sys.argv[1:], "hdl:", ["help", "debug", 
"loop=", "timeout="])
     except getopt.GetoptError as err:
         # print help information and exit:
         print(str(err)) # will print something like "option -a not recognized"
         usage()
         sys.exit(2)
+    timeout = None
     for o, a in opts:
         if o in ("-h", "--help"):
             usage()
@@ -659,19 +688,23 @@
             global do_debug
             do_debug = True
         if o in ("-l", "--loop"):
-            global use_pure_python_event_loop
-            use_pure_python_event_loop ^= True
+            global event_impl
+            event_impl = a
+        if o in ("--timeout"):
+            timeout = int(a)
 
     if len(args) >= 1:
         uri = args[0]
     else:
         uri = "qemu:///system"
 
-    print("Using uri:" + uri)
+    print("Using uri '%s' and event loop '%s'" % (uri, event_impl))
 
     # Run a background thread with the event loop
-    if use_pure_python_event_loop:
-        virEventLoopPureStart()
+    if event_impl == "poll":
+        virEventLoopPollStart()
+    elif event_impl == "asyncio":
+        virEventLoopAIOStart()
     else:
         virEventLoopNativeStart()
 
@@ -689,42 +722,47 @@
 
     #Add 2 lifecycle callbacks to prove this works with more than just one
     vc.domainEventRegister(myDomainEventCallback1,None)
-    vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_LIFECYCLE, 
myDomainEventCallback2, None)
-    vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_REBOOT, 
myDomainEventRebootCallback, None)
-    vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_RTC_CHANGE, 
myDomainEventRTCChangeCallback, None)
-    vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_WATCHDOG, 
myDomainEventWatchdogCallback, None)
-    vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_IO_ERROR, 
myDomainEventIOErrorCallback, None)
-    vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_GRAPHICS, 
myDomainEventGraphicsCallback, None)
-    vc.domainEventRegisterAny(None, 
libvirt.VIR_DOMAIN_EVENT_ID_IO_ERROR_REASON, 
myDomainEventIOErrorReasonCallback, None)
-    vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_CONTROL_ERROR, 
myDomainEventControlErrorCallback, None)
-    vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_BLOCK_JOB, 
myDomainEventBlockJobCallback, None)
-    vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_DISK_CHANGE, 
myDomainEventDiskChangeCallback, None)
-    vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_TRAY_CHANGE, 
myDomainEventTrayChangeCallback, None)
-    vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_PMWAKEUP, 
myDomainEventPMWakeupCallback, None)
-    vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_PMSUSPEND, 
myDomainEventPMSuspendCallback, None)
-    vc.domainEventRegisterAny(None, 
libvirt.VIR_DOMAIN_EVENT_ID_BALLOON_CHANGE, myDomainEventBalloonChangeCallback, 
None)
-    vc.domainEventRegisterAny(None, 
libvirt.VIR_DOMAIN_EVENT_ID_PMSUSPEND_DISK, myDomainEventPMSuspendDiskCallback, 
None)
-    vc.domainEventRegisterAny(None, 
libvirt.VIR_DOMAIN_EVENT_ID_DEVICE_REMOVED, myDomainEventDeviceRemovedCallback, 
None)
-    vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_BLOCK_JOB_2, 
myDomainEventBlockJob2Callback, None)
-    vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_TUNABLE, 
myDomainEventTunableCallback, None)
-    vc.domainEventRegisterAny(None, 
libvirt.VIR_DOMAIN_EVENT_ID_AGENT_LIFECYCLE, 
myDomainEventAgentLifecycleCallback, None)
-    vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_DEVICE_ADDED, 
myDomainEventDeviceAddedCallback, None)
-    vc.domainEventRegisterAny(None, 
libvirt.VIR_DOMAIN_EVENT_ID_MIGRATION_ITERATION, 
myDomainEventMigrationIteration, None)
-    vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_JOB_COMPLETED, 
myDomainEventJobCompletedCallback, None)
-    vc.domainEventRegisterAny(None, 
libvirt.VIR_DOMAIN_EVENT_ID_DEVICE_REMOVAL_FAILED, 
myDomainEventDeviceRemovalFailedCallback, None)
-    vc.domainEventRegisterAny(None, 
libvirt.VIR_DOMAIN_EVENT_ID_METADATA_CHANGE, 
myDomainEventMetadataChangeCallback, None)
-    vc.domainEventRegisterAny(None, 
libvirt.VIR_DOMAIN_EVENT_ID_BLOCK_THRESHOLD, 
myDomainEventBlockThresholdCallback, None)
-
-    vc.networkEventRegisterAny(None, libvirt.VIR_NETWORK_EVENT_ID_LIFECYCLE, 
myNetworkEventLifecycleCallback, None)
-
-    vc.storagePoolEventRegisterAny(None, 
libvirt.VIR_STORAGE_POOL_EVENT_ID_LIFECYCLE, 
myStoragePoolEventLifecycleCallback, None)
-    vc.storagePoolEventRegisterAny(None, 
libvirt.VIR_STORAGE_POOL_EVENT_ID_REFRESH, myStoragePoolEventRefreshCallback, 
None)
-
-    vc.nodeDeviceEventRegisterAny(None, 
libvirt.VIR_NODE_DEVICE_EVENT_ID_LIFECYCLE, myNodeDeviceEventLifecycleCallback, 
None)
-    vc.nodeDeviceEventRegisterAny(None, 
libvirt.VIR_NODE_DEVICE_EVENT_ID_UPDATE, myNodeDeviceEventUpdateCallback, None)
-
-    vc.secretEventRegisterAny(None, libvirt.VIR_SECRET_EVENT_ID_LIFECYCLE, 
mySecretEventLifecycleCallback, None)
-    vc.secretEventRegisterAny(None, libvirt.VIR_SECRET_EVENT_ID_VALUE_CHANGED, 
mySecretEventValueChanged, None)
+    domcallbacks = []
+    domcallbacks.append(vc.domainEventRegisterAny(None, 
libvirt.VIR_DOMAIN_EVENT_ID_LIFECYCLE, myDomainEventCallback2, None))
+    domcallbacks.append(vc.domainEventRegisterAny(None, 
libvirt.VIR_DOMAIN_EVENT_ID_REBOOT, myDomainEventRebootCallback, None))
+    domcallbacks.append(vc.domainEventRegisterAny(None, 
libvirt.VIR_DOMAIN_EVENT_ID_RTC_CHANGE, myDomainEventRTCChangeCallback, None))
+    domcallbacks.append(vc.domainEventRegisterAny(None, 
libvirt.VIR_DOMAIN_EVENT_ID_WATCHDOG, myDomainEventWatchdogCallback, None))
+    domcallbacks.append(vc.domainEventRegisterAny(None, 
libvirt.VIR_DOMAIN_EVENT_ID_IO_ERROR, myDomainEventIOErrorCallback, None))
+    domcallbacks.append(vc.domainEventRegisterAny(None, 
libvirt.VIR_DOMAIN_EVENT_ID_GRAPHICS, myDomainEventGraphicsCallback, None))
+    domcallbacks.append(vc.domainEventRegisterAny(None, 
libvirt.VIR_DOMAIN_EVENT_ID_IO_ERROR_REASON, 
myDomainEventIOErrorReasonCallback, None))
+    domcallbacks.append(vc.domainEventRegisterAny(None, 
libvirt.VIR_DOMAIN_EVENT_ID_CONTROL_ERROR, myDomainEventControlErrorCallback, 
None))
+    domcallbacks.append(vc.domainEventRegisterAny(None, 
libvirt.VIR_DOMAIN_EVENT_ID_BLOCK_JOB, myDomainEventBlockJobCallback, None))
+    domcallbacks.append(vc.domainEventRegisterAny(None, 
libvirt.VIR_DOMAIN_EVENT_ID_DISK_CHANGE, myDomainEventDiskChangeCallback, None))
+    domcallbacks.append(vc.domainEventRegisterAny(None, 
libvirt.VIR_DOMAIN_EVENT_ID_TRAY_CHANGE, myDomainEventTrayChangeCallback, None))
+    domcallbacks.append(vc.domainEventRegisterAny(None, 
libvirt.VIR_DOMAIN_EVENT_ID_PMWAKEUP, myDomainEventPMWakeupCallback, None))
+    domcallbacks.append(vc.domainEventRegisterAny(None, 
libvirt.VIR_DOMAIN_EVENT_ID_PMSUSPEND, myDomainEventPMSuspendCallback, None))
+    domcallbacks.append(vc.domainEventRegisterAny(None, 
libvirt.VIR_DOMAIN_EVENT_ID_BALLOON_CHANGE, myDomainEventBalloonChangeCallback, 
None))
+    domcallbacks.append(vc.domainEventRegisterAny(None, 
libvirt.VIR_DOMAIN_EVENT_ID_PMSUSPEND_DISK, myDomainEventPMSuspendDiskCallback, 
None))
+    domcallbacks.append(vc.domainEventRegisterAny(None, 
libvirt.VIR_DOMAIN_EVENT_ID_DEVICE_REMOVED, myDomainEventDeviceRemovedCallback, 
None))
+    domcallbacks.append(vc.domainEventRegisterAny(None, 
libvirt.VIR_DOMAIN_EVENT_ID_BLOCK_JOB_2, myDomainEventBlockJob2Callback, None))
+    domcallbacks.append(vc.domainEventRegisterAny(None, 
libvirt.VIR_DOMAIN_EVENT_ID_TUNABLE, myDomainEventTunableCallback, None))
+    domcallbacks.append(vc.domainEventRegisterAny(None, 
libvirt.VIR_DOMAIN_EVENT_ID_AGENT_LIFECYCLE, 
myDomainEventAgentLifecycleCallback, None))
+    domcallbacks.append(vc.domainEventRegisterAny(None, 
libvirt.VIR_DOMAIN_EVENT_ID_DEVICE_ADDED, myDomainEventDeviceAddedCallback, 
None))
+    domcallbacks.append(vc.domainEventRegisterAny(None, 
libvirt.VIR_DOMAIN_EVENT_ID_MIGRATION_ITERATION, 
myDomainEventMigrationIteration, None))
+    domcallbacks.append(vc.domainEventRegisterAny(None, 
libvirt.VIR_DOMAIN_EVENT_ID_JOB_COMPLETED, myDomainEventJobCompletedCallback, 
None))
+    domcallbacks.append(vc.domainEventRegisterAny(None, 
libvirt.VIR_DOMAIN_EVENT_ID_DEVICE_REMOVAL_FAILED, 
myDomainEventDeviceRemovalFailedCallback, None))
+    domcallbacks.append(vc.domainEventRegisterAny(None, 
libvirt.VIR_DOMAIN_EVENT_ID_METADATA_CHANGE, 
myDomainEventMetadataChangeCallback, None))
+    domcallbacks.append(vc.domainEventRegisterAny(None, 
libvirt.VIR_DOMAIN_EVENT_ID_BLOCK_THRESHOLD, 
myDomainEventBlockThresholdCallback, None))
+
+    netcallbacks = []
+    netcallbacks.append(vc.networkEventRegisterAny(None, 
libvirt.VIR_NETWORK_EVENT_ID_LIFECYCLE, myNetworkEventLifecycleCallback, None))
+
+    poolcallbacks = []
+    poolcallbacks.append(vc.storagePoolEventRegisterAny(None, 
libvirt.VIR_STORAGE_POOL_EVENT_ID_LIFECYCLE, 
myStoragePoolEventLifecycleCallback, None))
+    poolcallbacks.append(vc.storagePoolEventRegisterAny(None, 
libvirt.VIR_STORAGE_POOL_EVENT_ID_REFRESH, myStoragePoolEventRefreshCallback, 
None))
+
+    devcallbacks = []
+    devcallbacks.append(vc.nodeDeviceEventRegisterAny(None, 
libvirt.VIR_NODE_DEVICE_EVENT_ID_LIFECYCLE, myNodeDeviceEventLifecycleCallback, 
None))
+    devcallbacks.append(vc.nodeDeviceEventRegisterAny(None, 
libvirt.VIR_NODE_DEVICE_EVENT_ID_UPDATE, myNodeDeviceEventUpdateCallback, None))
+
+    seccallbacks = []
+    seccallbacks.append(vc.secretEventRegisterAny(None, 
libvirt.VIR_SECRET_EVENT_ID_LIFECYCLE, mySecretEventLifecycleCallback, None))
+    seccallbacks.append(vc.secretEventRegisterAny(None, 
libvirt.VIR_SECRET_EVENT_ID_VALUE_CHANGED, mySecretEventValueChanged, None))
 
     vc.setKeepAlive(5, 3)
 
@@ -732,9 +770,29 @@
     # of demo we'll just go to sleep. The other option is to
     # run the event loop in your main thread if your app is
     # totally event based.
-    while run:
+    count = 0
+    while run and (timeout is None or count < timeout):
+        count = count + 1
         time.sleep(1)
 
+    vc.domainEventDeregister(myDomainEventCallback1)
+
+    for id in seccallbacks:
+        vc.secretEventDeregisterAny(id)
+    for id in devcallbacks:
+        vc.nodeDeviceEventDeregisterAny(id)
+    for id in poolcallbacks:
+        vc.storagePoolEventDeregisterAny(id)
+    for id in netcallbacks:
+        vc.networkEventDeregisterAny(id)
+    for id in domcallbacks:
+        vc.domainEventDeregisterAny(id)
+
+    vc.unregisterCloseCallback()
+    vc.close()
+
+    # Allow delayed event loop cleanup to run, just for sake of testing
+    time.sleep(2)
 
 if __name__ == "__main__":
     main()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libvirt-python-3.2.0/libvirt-override.c 
new/libvirt-python-3.3.0/libvirt-override.c
--- old/libvirt-python-3.2.0/libvirt-override.c 2017-04-02 16:52:04.000000000 
+0200
+++ new/libvirt-python-3.3.0/libvirt-override.c 2017-05-05 21:39:32.000000000 
+0200
@@ -5223,6 +5223,9 @@
 
     VIR_PY_TUPLE_SET_GOTO(pyobj_args, 3, cb_args, cleanup);
 
+    /* If changing contents of the opaque object, please also change
+     * virEventInvokeFreeCallback() in libvirt-override.py
+     */
     VIR_PY_TUPLE_SET_GOTO(cb_args, 0, libvirt_virEventHandleCallbackWrap(cb), 
cleanup);
     VIR_PY_TUPLE_SET_GOTO(cb_args, 1, libvirt_virVoidPtrWrap(opaque), cleanup);
     VIR_PY_TUPLE_SET_GOTO(cb_args, 2, libvirt_virFreeCallbackWrap(ff), 
cleanup);
@@ -5279,10 +5282,7 @@
 {
     PyObject *result = NULL;
     PyObject *pyobj_args;
-    PyObject *opaque;
-    PyObject *ff;
     int retval = -1;
-    virFreeCallback cff;
 
     LIBVIRT_ENSURE_THREAD_STATE;
 
@@ -5292,20 +5292,11 @@
     VIR_PY_TUPLE_SET_GOTO(pyobj_args, 0, libvirt_intWrap(watch), cleanup);
 
     result = PyEval_CallObject(removeHandleObj, pyobj_args);
-    if (!result) {
+    if (result) {
+        retval = 0;
+    } else {
         PyErr_Print();
         PyErr_Clear();
-    } else if (!PyTuple_Check(result) || PyTuple_Size(result) != 3) {
-        DEBUG("%s: %s must return opaque obj registered with %s"
-              "to avoid leaking libvirt memory\n",
-              __FUNCTION__, NAME(removeHandle), NAME(addHandle));
-    } else {
-        opaque = PyTuple_GetItem(result, 1);
-        ff = PyTuple_GetItem(result, 2);
-        cff = PyvirFreeCallback_Get(ff);
-        if (cff)
-            (*cff)(PyvirVoidPtr_Get(opaque));
-        retval = 0;
     }
 
  cleanup:
@@ -5350,6 +5341,9 @@
 
     VIR_PY_TUPLE_SET_GOTO(pyobj_args, 2, cb_args, cleanup);
 
+    /* If changing contents of the opaque object, please also change
+     * virEventInvokeFreeCallback() in libvirt-override.py
+     */
     VIR_PY_TUPLE_SET_GOTO(cb_args, 0, libvirt_virEventTimeoutCallbackWrap(cb), 
cleanup);
     VIR_PY_TUPLE_SET_GOTO(cb_args, 1, libvirt_virVoidPtrWrap(opaque), cleanup);
     VIR_PY_TUPLE_SET_GOTO(cb_args, 2, libvirt_virFreeCallbackWrap(ff), 
cleanup);
@@ -5403,10 +5397,7 @@
 {
     PyObject *result = NULL;
     PyObject *pyobj_args;
-    PyObject *opaque;
-    PyObject *ff;
     int retval = -1;
-    virFreeCallback cff;
 
     LIBVIRT_ENSURE_THREAD_STATE;
 
@@ -5416,20 +5407,11 @@
     VIR_PY_TUPLE_SET_GOTO(pyobj_args, 0, libvirt_intWrap(timer), cleanup);
 
     result = PyEval_CallObject(removeTimeoutObj, pyobj_args);
-    if (!result) {
+    if (result) {
+        retval = 0;
+    } else {
         PyErr_Print();
         PyErr_Clear();
-    } else if (!PyTuple_Check(result) || PyTuple_Size(result) != 3) {
-        DEBUG("%s: %s must return opaque obj registered with %s"
-              "to avoid leaking libvirt memory\n",
-              __FUNCTION__, NAME(removeTimeout), NAME(addTimeout));
-    } else {
-        opaque = PyTuple_GetItem(result, 1);
-        ff = PyTuple_GetItem(result, 2);
-        cff = PyvirFreeCallback_Get(ff);
-        if (cff)
-            (*cff)(PyvirVoidPtr_Get(opaque));
-        retval = 0;
     }
 
  cleanup:
@@ -5558,6 +5540,31 @@
     return VIR_PY_INT_SUCCESS;
 }
 
+static PyObject *
+libvirt_virEventInvokeFreeCallback(PyObject *self ATTRIBUTE_UNUSED,
+                                   PyObject *args)
+{
+    PyObject *py_f;
+    PyObject *py_opaque;
+    virFreeCallback cb;
+    void *opaque;
+
+    if (!PyArg_ParseTuple(args, (char *) "OO:virEventInvokeFreeCallback",
+                          &py_f, &py_opaque))
+        return NULL;
+
+    cb     = (virFreeCallback) PyvirEventHandleCallback_Get(py_f);
+    opaque = (void *) PyvirVoidPtr_Get(py_opaque);
+
+    if (cb) {
+        LIBVIRT_BEGIN_ALLOW_THREADS;
+        cb(opaque);
+        LIBVIRT_END_ALLOW_THREADS;
+    }
+
+    return VIR_PY_INT_SUCCESS;
+}
+
 static void
 libvirt_virEventHandleCallback(int watch,
                                int fd,
@@ -9572,6 +9579,7 @@
     {(char *) "virEventAddTimeout", libvirt_virEventAddTimeout, METH_VARARGS, 
NULL},
     {(char *) "virEventInvokeHandleCallback", 
libvirt_virEventInvokeHandleCallback, METH_VARARGS, NULL},
     {(char *) "virEventInvokeTimeoutCallback", 
libvirt_virEventInvokeTimeoutCallback, METH_VARARGS, NULL},
+    {(char *) "virEventInvokeFreeCallback", 
libvirt_virEventInvokeFreeCallback, METH_VARARGS, NULL},
     {(char *) "virNodeListDevices", libvirt_virNodeListDevices, METH_VARARGS, 
NULL},
 #if LIBVIR_CHECK_VERSION(0, 10, 2)
     {(char *) "virConnectListAllNodeDevices", 
libvirt_virConnectListAllNodeDevices, METH_VARARGS, NULL},
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libvirt-python-3.2.0/libvirt-override.py 
new/libvirt-python-3.3.0/libvirt-override.py
--- old/libvirt-python-3.2.0/libvirt-override.py        2016-12-04 
22:14:32.000000000 +0100
+++ new/libvirt-python-3.3.0/libvirt-override.py        2017-05-05 
21:39:32.000000000 +0200
@@ -211,3 +211,26 @@
     ret = libvirtmod.virEventAddTimeout(timeout, cbData)
     if ret == -1: raise libvirtError ('virEventAddTimeout() failed')
     return ret
+
+
+#
+# a caller for the ff callbacks for custom event loop implementations
+#
+
+def virEventInvokeFreeCallback(opaque):
+    """
+    Execute callback which frees the opaque buffer
+
+    @opaque: the opaque object passed to addHandle or addTimeout
+
+    WARNING: This function should not be called from any call by libvirt's
+    core. It will most probably cause deadlock in C-level libvirt code.
+    Instead it should be scheduled and called from implementation's stack.
+
+    See 
https://libvirt.org/html/libvirt-libvirt-event.html#virEventAddHandleFunc
+    for more information.
+
+    This function is not dependent on any event loop implementation.
+    """
+
+    libvirtmod.virEventInvokeFreeCallback(opaque[2], opaque[1])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libvirt-python-3.2.0/libvirt-python.spec 
new/libvirt-python-3.3.0/libvirt-python.spec
--- old/libvirt-python-3.2.0/libvirt-python.spec        2017-04-02 
17:10:54.000000000 +0200
+++ new/libvirt-python-3.3.0/libvirt-python.spec        2017-05-05 
21:48:17.000000000 +0200
@@ -6,7 +6,7 @@
 
 Summary: The libvirt virtualization API python2 binding
 Name: libvirt-python
-Version: 3.2.0
+Version: 3.3.0
 Release: 1%{?dist}%{?extra_release}
 Source0: http://libvirt.org/sources/python/%{name}-%{version}.tar.gz
 Url: http://libvirt.org
@@ -86,11 +86,13 @@
 %defattr(-,root,root)
 %doc ChangeLog AUTHORS NEWS README COPYING COPYING.LESSER examples/
 %{_libdir}/python3*/site-packages/libvirt.py*
+%{_libdir}/python3*/site-packages/libvirtaio.py*
 %{_libdir}/python3*/site-packages/libvirt_qemu.py*
 %{_libdir}/python3*/site-packages/libvirt_lxc.py*
 %{_libdir}/python3*/site-packages/__pycache__/libvirt.cpython-*.py*
 %{_libdir}/python3*/site-packages/__pycache__/libvirt_qemu.cpython-*.py*
 %{_libdir}/python3*/site-packages/__pycache__/libvirt_lxc.cpython-*.py*
+%{_libdir}/python3*/site-packages/__pycache__/libvirtaio.cpython-*.py*
 %{_libdir}/python3*/site-packages/libvirtmod*
 %endif
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libvirt-python-3.2.0/libvirtaio.py 
new/libvirt-python-3.3.0/libvirtaio.py
--- old/libvirt-python-3.2.0/libvirtaio.py      1970-01-01 01:00:00.000000000 
+0100
+++ new/libvirt-python-3.3.0/libvirtaio.py      2017-05-05 21:39:32.000000000 
+0200
@@ -0,0 +1,399 @@
+#
+# libvirtaio -- asyncio adapter for libvirt
+# Copyright (C) 2017  Wojtek Porczyk <[email protected]>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, see
+# <http://www.gnu.org/licenses/>.
+#
+
+'''Libvirt event loop implementation using asyncio
+
+Register the implementation of default loop:
+
+    >>> import libvirtaio
+    >>> libvirtaio.virEventRegisterAsyncIOImpl()
+
+.. seealso::
+    https://libvirt.org/html/libvirt-libvirt-event.html
+'''
+
+__author__ = 'Wojtek Porczyk <[email protected]>'
+__license__ = 'LGPL-2.1+'
+__all__ = ['virEventAsyncIOImpl', 'virEventRegisterAsyncIOImpl']
+
+import asyncio
+import itertools
+import logging
+import warnings
+
+import libvirt
+
+try:
+    from asyncio import ensure_future
+except ImportError:
+    from asyncio import async as ensure_future
+
+
+class Callback(object):
+    '''Base class for holding callback
+
+    :param virEventAsyncIOImpl impl: the implementation in which we run
+    :param cb: the callback itself
+    :param opaque: the opaque tuple passed by libvirt
+    '''
+    # pylint: disable=too-few-public-methods
+
+    _iden_counter = itertools.count()
+
+    def __init__(self, impl, cb, opaque, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        self.iden = next(self._iden_counter)
+        self.impl = impl
+        self.cb = cb
+        self.opaque = opaque
+
+        assert self.iden not in self.impl.callbacks, \
+            'found {} callback: {!r}'.format(
+                self.iden, self.impl.callbacks[self.iden])
+        self.impl.callbacks[self.iden] = self
+
+    def __repr__(self):
+        return '<{} iden={}>'.format(self.__class__.__name__, self.iden)
+
+    def close(self):
+        '''Schedule *ff* callback'''
+        self.impl.log.debug('callback %d close(), scheduling ff', self.iden)
+        self.impl.schedule_ff_callback(self.opaque)
+
+#
+# file descriptors
+#
+
+class Descriptor(object):
+    '''Manager of one file descriptor
+
+    :param virEventAsyncIOImpl impl: the implementation in which we run
+    :param int fd: the file descriptor
+    '''
+    def __init__(self, impl, fd):
+        self.impl = impl
+        self.fd = fd
+        self.callbacks = {}
+
+    def _handle(self, event):
+        '''Dispatch the event to the descriptors
+
+        :param int event: The event (from libvirt's constants) being dispatched
+        '''
+        for callback in self.callbacks.values():
+            if callback.event is not None and callback.event & event:
+                callback.cb(callback.iden, self.fd, event, callback.opaque)
+
+    def update(self):
+        '''Register or unregister callbacks at event loop
+
+        This should be called after change of any ``.event`` in callbacks.
+        '''
+        # It seems like loop.add_{reader,writer} can be run multiple times
+        # and will still register the callback only once. Likewise,
+        # remove_{reader,writer} may be run even if the reader/writer
+        # is not registered (and will just return False).
+
+        # For the edge case of empty callbacks, any() returns False.
+        if any(callback.event & ~(
+                    libvirt.VIR_EVENT_HANDLE_READABLE |
+                    libvirt.VIR_EVENT_HANDLE_WRITABLE)
+                for callback in self.callbacks.values()):
+            warnings.warn(
+                'The only event supported are VIR_EVENT_HANDLE_READABLE '
+                'and VIR_EVENT_HANDLE_WRITABLE',
+                UserWarning)
+
+        if any(callback.event & libvirt.VIR_EVENT_HANDLE_READABLE
+                for callback in self.callbacks.values()):
+            self.impl.loop.add_reader(
+                self.fd, self._handle, libvirt.VIR_EVENT_HANDLE_READABLE)
+        else:
+            self.impl.loop.remove_reader(self.fd)
+
+        if any(callback.event & libvirt.VIR_EVENT_HANDLE_WRITABLE
+                for callback in self.callbacks.values()):
+            self.impl.loop.add_writer(
+                self.fd, self._handle, libvirt.VIR_EVENT_HANDLE_WRITABLE)
+        else:
+            self.impl.loop.remove_writer(self.fd)
+
+    def add_handle(self, callback):
+        '''Add a callback to the descriptor
+
+        :param FDCallback callback: the callback to add
+        :rtype: None
+
+        After adding the callback, it is immediately watched.
+        '''
+        self.callbacks[callback.iden] = callback
+        self.update()
+
+    def remove_handle(self, iden):
+        '''Remove a callback from the descriptor
+
+        :param int iden: the identifier of the callback
+        :returns: the callback
+        :rtype: FDCallback
+
+        After removing the callback, the descriptor may be unwatched, if there
+        are no more handles for it.
+        '''
+        callback = self.callbacks.pop(iden)
+        self.update()
+        return callback
+
+    def close(self):
+        ''''''
+        self.callbacks.clear()
+        self.update()
+
+class DescriptorDict(dict):
+    '''Descriptors collection
+
+    This is used internally by virEventAsyncIOImpl to hold descriptors.
+    '''
+    def __init__(self, impl):
+        super().__init__()
+        self.impl = impl
+
+    def __missing__(self, fd):
+        descriptor = Descriptor(self.impl, fd)
+        self[fd] = descriptor
+        return descriptor
+
+class FDCallback(Callback):
+    '''Callback for file descriptor (watcher)
+
+    :param Descriptor descriptor: the descriptor manager
+    :param int event: bitset of events on which to fire the callback
+    '''
+    # pylint: disable=too-few-public-methods
+
+    def __init__(self, *args, descriptor, event, **kwargs):
+        super().__init__(*args, **kwargs)
+        self.descriptor = descriptor
+        self.event = event
+
+    def __repr__(self):
+        return '<{} iden={} fd={} event={}>'.format(
+            self.__class__.__name__, self.iden, self.descriptor.fd, self.event)
+
+    def update(self, event):
+        '''Update the callback and fix descriptor's watchers'''
+        self.event = event
+        self.descriptor.update()
+
+#
+# timeouts
+#
+
+class TimeoutCallback(Callback):
+    '''Callback for timer'''
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        self.timeout = -1
+        self._task = None
+
+    def __repr__(self):
+        return '<{} iden={} timeout={}>'.format(
+            self.__class__.__name__, self.iden, self.timeout)
+
+    @asyncio.coroutine
+    def _timer(self):
+        '''An actual timer running on the event loop.
+
+        This is a coroutine.
+        '''
+        while True:
+            try:
+                if self.timeout > 0:
+                    timeout = self.timeout * 1e-3
+                    self.impl.log.debug('sleeping %r', timeout)
+                    yield from asyncio.sleep(timeout)
+                else:
+                    # scheduling timeout for next loop iteration
+                    yield
+
+            except asyncio.CancelledError:
+                self.impl.log.debug('timer %d cancelled', self.iden)
+                break
+
+            self.cb(self.iden, self.opaque)
+            self.impl.log.debug('timer %r callback ended', self.iden)
+
+    def update(self, timeout):
+        '''Start or the timer, possibly updating timeout'''
+        self.timeout = timeout
+
+        if self.timeout >= 0 and self._task is None:
+            self.impl.log.debug('timer %r start', self.iden)
+            self._task = ensure_future(self._timer(),
+                loop=self.impl.loop)
+
+        elif self.timeout < 0 and self._task is not None:
+            self.impl.log.debug('timer %r stop', self.iden)
+            self._task.cancel()  # pylint: disable=no-member
+            self._task = None
+
+    def close(self):
+        '''Stop the timer and call ff callback'''
+        super(TimeoutCallback, self).close()
+        self.update(timeout=-1)
+
+#
+# main implementation
+#
+
+class virEventAsyncIOImpl(object):
+    '''Libvirt event adapter to asyncio.
+
+    :param loop: asyncio's event loop
+
+    If *loop* is not specified, the current (or default) event loop is used.
+    '''
+
+    def __init__(self, loop=None):
+        self.loop = loop or asyncio.get_event_loop()
+        self.callbacks = {}
+        self.descriptors = DescriptorDict(self)
+        self.log = logging.getLogger(self.__class__.__name__)
+
+    def register(self):
+        '''Register this instance as event loop implementation'''
+        # pylint: disable=bad-whitespace
+        self.log.debug('register()')
+        libvirt.virEventRegisterImpl(
+            self._add_handle,  self._update_handle,  self._remove_handle,
+            self._add_timeout, self._update_timeout, self._remove_timeout)
+        return self
+
+    def schedule_ff_callback(self, opaque):
+        '''Schedule a ff callback from one of the handles or timers'''
+        self.loop.call_soon(libvirt.virEventInvokeFreeCallback, opaque)
+
+    def is_idle(self):
+        '''Returns False if there are leftovers from a connection
+
+        Those may happen if there are sematical problems while closing
+        a connection. For example, not deregistered events before .close().
+        '''
+        return not self.callbacks
+
+    def _add_handle(self, fd, event, cb, opaque):
+        '''Register a callback for monitoring file handle events
+
+        :param int fd: file descriptor to listen on
+        :param int event: bitset of events on which to fire the callback
+        :param cb: the callback to be called when an event occurrs
+        :param opaque: user data to pass to the callback
+        :rtype: int
+        :returns: handle watch number to be used for updating and 
unregistering for events
+
+        .. seealso::
+            
https://libvirt.org/html/libvirt-libvirt-event.html#virEventAddHandleFuncFunc
+        '''
+        self.log.debug('add_handle(fd=%d, event=%d, cb=%r, opaque=%r)',
+                fd, event, cb, opaque)
+        callback = FDCallback(self, cb, opaque,
+                descriptor=self.descriptors[fd], event=event)
+        self.callbacks[callback.iden] = callback
+        self.descriptors[fd].add_handle(callback)
+        return callback.iden
+
+    def _update_handle(self, watch, event):
+        '''Change event set for a monitored file handle
+
+        :param int watch: file descriptor watch to modify
+        :param int event: new events to listen on
+
+        .. seealso::
+            
https://libvirt.org/html/libvirt-libvirt-event.html#virEventUpdateHandleFunc
+        '''
+        self.log.debug('update_handle(watch=%d, event=%d)', watch, event)
+        return self.callbacks[watch].update(event=event)
+
+    def _remove_handle(self, watch):
+        '''Unregister a callback from a file handle.
+
+        :param int watch: file descriptor watch to stop listening on
+        :returns: None (see source for explanation)
+
+        .. seealso::
+            
https://libvirt.org/html/libvirt-libvirt-event.html#virEventRemoveHandleFunc
+        '''
+        self.log.debug('remove_handle(watch=%d)', watch)
+        callback = self.callbacks.pop(watch)
+        fd = callback.descriptor.fd
+        assert callback is self.descriptors[fd].remove_handle(watch)
+        if len(self.descriptors[fd].callbacks) == 0:
+            del self.descriptors[fd]
+        callback.close()
+
+    def _add_timeout(self, timeout, cb, opaque):
+        '''Register a callback for a timer event
+
+        :param int timeout: the timeout to monitor
+        :param cb: the callback to call when timeout has expired
+        :param opaque: user data to pass to the callback
+        :rtype: int
+        :returns: a timer value
+
+        .. seealso::
+            
https://libvirt.org/html/libvirt-libvirt-event.html#virEventAddTimeoutFunc
+        '''
+        self.log.debug('add_timeout(timeout=%d, cb=%r, opaque=%r)',
+                timeout, cb, opaque)
+        callback = TimeoutCallback(self, cb, opaque)
+        self.callbacks[callback.iden] = callback
+        callback.update(timeout=timeout)
+        return callback.iden
+
+    def _update_timeout(self, timer, timeout):
+        '''Change frequency for a timer
+
+        :param int timer: the timer to modify
+        :param int timeout: the new timeout value in ms
+
+        .. seealso::
+            
https://libvirt.org/html/libvirt-libvirt-event.html#virEventUpdateTimeoutFunc
+        '''
+        self.log.debug('update_timeout(timer=%d, timeout=%d)', timer, timeout)
+        return self.callbacks[timer].update(timeout=timeout)
+
+    def _remove_timeout(self, timer):
+        '''Unregister a callback for a timer
+
+        :param int timer: the timer to remove
+        :returns: None (see source for explanation)
+
+        .. seealso::
+            
https://libvirt.org/html/libvirt-libvirt-event.html#virEventRemoveTimeoutFunc
+        '''
+        self.log.debug('remove_timeout(timer=%d)', timer)
+        callback = self.callbacks.pop(timer)
+        callback.close()
+
+def virEventRegisterAsyncIOImpl(loop=None):
+    '''Arrange for libvirt's callbacks to be dispatched via asyncio event loop
+
+    The implementation object is returned, but in normal usage it can safely be
+    discarded.
+    '''
+    return virEventAsyncIOImpl(loop=loop).register()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libvirt-python-3.2.0/sanitytest.py 
new/libvirt-python-3.3.0/sanitytest.py
--- old/libvirt-python-3.2.0/sanitytest.py      2017-01-17 19:20:56.000000000 
+0100
+++ new/libvirt-python-3.3.0/sanitytest.py      2017-05-05 21:39:32.000000000 
+0200
@@ -349,7 +349,8 @@
         continue
     for func in sorted(gotfunctions[klass]):
         # These are pure python methods with no C APi
-        if func in ["connect", "getConnect", "domain", "getDomain"]:
+        if func in ["connect", "getConnect", "domain", "getDomain",
+                    "virEventInvokeFreeCallback"]:
             continue
 
         key = "%s.%s" % (klass, func)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libvirt-python-3.2.0/setup.py 
new/libvirt-python-3.3.0/setup.py
--- old/libvirt-python-3.2.0/setup.py   2017-04-02 17:08:30.000000000 +0200
+++ new/libvirt-python-3.3.0/setup.py   2017-05-05 21:40:51.000000000 +0200
@@ -14,6 +14,7 @@
 import os
 import os.path
 import re
+import shutil
 import time
 
 MIN_LIBVIRT = "0.9.11"
@@ -50,6 +51,12 @@
     except DistutilsExecError:
         return False
 
+def have_libvirtaio():
+    # This depends on asyncio, which in turn depends on "yield from" syntax.
+    # The asyncio module itself is in standard library since 3.4, but there is
+    # an out-of-tree version compatible with 3.3.
+    return sys.version_info >= (3, 3)
+
 def get_pkgconfig_data(args, mod, required=True):
     """Run pkg-config to and return content associated with it"""
     f = os.popen("%s %s %s" % (get_pkgcfg(), " ".join(args), mod))
@@ -124,6 +131,9 @@
         c_modules.append(modulelxc)
         py_modules.append("libvirt_lxc")
 
+    if have_libvirtaio():
+        py_modules.append("libvirtaio")
+
     return c_modules, py_modules
 
 
@@ -141,6 +151,8 @@
         self.spawn([sys.executable, "generator.py", "libvirt-qemu", apis[1]])
         if have_libvirt_lxc():
             self.spawn([sys.executable, "generator.py", "libvirt-lxc", 
apis[2]])
+        if have_libvirtaio():
+            shutil.copy('libvirtaio.py', 'build')
 
         build.run(self)
 
@@ -322,7 +334,7 @@
 _c_modules, _py_modules = get_module_lists()
 
 setup(name = 'libvirt-python',
-      version = '3.2.0',
+      version = '3.3.0',
       url = 'http://www.libvirt.org',
       maintainer = 'Libvirt Maintainers',
       maintainer_email = '[email protected]',


Reply via email to