Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-libvirt-python for openSUSE:Factory checked in at 2022-07-07 12:56:37 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-libvirt-python (Old) and /work/SRC/openSUSE:Factory/.python-libvirt-python.new.1523 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-libvirt-python" Thu Jul 7 12:56:37 2022 rev:58 rq:987262 version:8.5.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-libvirt-python/python-libvirt-python.changes 2022-06-03 14:15:45.417245583 +0200 +++ /work/SRC/openSUSE:Factory/.python-libvirt-python.new.1523/python-libvirt-python.changes 2022-07-07 12:56:55.575284147 +0200 @@ -1,0 +2,6 @@ +Tue Jul 5 22:54:11 UTC 2022 - James Fehlig <jfeh...@suse.com> + +- Update to 8.5.0 + - Add all new APIs and constants in libvirt 8.5.0 + +------------------------------------------------------------------- Old: ---- libvirt-python-8.4.0.tar.gz New: ---- libvirt-python-8.5.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-libvirt-python.spec ++++++ --- /var/tmp/diff_new_pack.JEkN8o/_old 2022-07-07 12:56:56.075284891 +0200 +++ /var/tmp/diff_new_pack.JEkN8o/_new 2022-07-07 12:56:56.075284891 +0200 @@ -23,7 +23,7 @@ %define srcname libvirt-python Name: python-libvirt-python URL: https://libvirt.org/ -Version: 8.4.0 +Version: 8.5.0 Release: 0 Summary: Library providing a virtualization API License: LGPL-2.1-or-later ++++++ _service ++++++ --- /var/tmp/diff_new_pack.JEkN8o/_old 2022-07-07 12:56:56.103284933 +0200 +++ /var/tmp/diff_new_pack.JEkN8o/_new 2022-07-07 12:56:56.107284939 +0200 @@ -1,7 +1,7 @@ <services> <service name="tar_scm" mode="disabled"> <param name="filename">libvirt-python</param> - <param name="revision">v8.4.0</param> + <param name="revision">v8.5.0</param> <param name="scm">git</param> <param name="submodules">disable</param> <param name="url">https://gitlab.com/libvirt/libvirt-python.git</param> ++++++ libvirt-python-8.4.0.tar.gz -> libvirt-python-8.5.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libvirt-python-8.4.0/examples/event-test.py new/libvirt-python-8.5.0/examples/event-test.py --- old/libvirt-python-8.4.0/examples/event-test.py 2022-05-13 13:28:11.000000000 +0200 +++ new/libvirt-python-8.5.0/examples/event-test.py 2022-06-25 06:38:30.000000000 +0200 @@ -438,8 +438,9 @@ def virEventLoopPollStart() -> None: global eventLoopThread virEventLoopPollRegister() - eventLoopThread = threading.Thread(target=virEventLoopPollRun, name="libvirtEventLoop") - eventLoopThread.setDaemon(True) + eventLoopThread = threading.Thread(target=virEventLoopPollRun, + name="libvirtEventLoop", + daemon=True) eventLoopThread.start() @@ -449,16 +450,19 @@ import asyncio loop = asyncio.new_event_loop() libvirtaio.virEventRegisterAsyncIOImpl(loop=loop) - eventLoopThread = threading.Thread(target=virEventLoopAIORun, args=(loop,), name="libvirtEventLoop") - eventLoopThread.setDaemon(True) + eventLoopThread = threading.Thread(target=virEventLoopAIORun, + args=(loop,), + name="libvirtEventLoop", + daemon=True) eventLoopThread.start() def virEventLoopNativeStart() -> None: global eventLoopThread libvirt.virEventRegisterDefaultImpl() - eventLoopThread = threading.Thread(target=virEventLoopNativeRun, name="libvirtEventLoop") - eventLoopThread.setDaemon(True) + eventLoopThread = threading.Thread(target=virEventLoopNativeRun, + name="libvirtEventLoop", + daemon=True) eventLoopThread.start() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libvirt-python-8.4.0/libvirtaio.py new/libvirt-python-8.5.0/libvirtaio.py --- old/libvirt-python-8.4.0/libvirtaio.py 2022-05-13 13:28:11.000000000 +0200 +++ new/libvirt-python-8.5.0/libvirtaio.py 2022-06-25 06:38:30.000000000 +0200 @@ -21,8 +21,27 @@ Register the implementation of default loop: - >>> import libvirtaio - >>> libvirtaio.virEventRegisterAsyncIOImpl() + import asyncio + import libvirtaio + + async def myapp(): + libvirtaio.virEventRegisterAsyncIOImpl() + + conn = libvirt.open("test:///default") + +For compatibility with Python < 3.7: + + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + + loop.run_until_complete(myapp()) + + asyncio.set_event_loop(None) + loop.close() + +If Python >= 3.7 can be required then + + asyncio.run(myapp()) .. seealso:: https://libvirt.org/html/libvirt-libvirt-event.html @@ -46,14 +65,6 @@ 'virEventRegisterAsyncIOImpl', ] -# Python < 3.4.4 doesn't have 'ensure_future', so we have to fall -# back to 'async'; however, since 'async' is a reserved keyword -# in Python >= 3.7, we can't perform a straightforward import and -# we have to resort to getattr() instead -ensure_future = getattr(asyncio, "ensure_future", None) -if not ensure_future: - ensure_future = getattr(asyncio, "async") - class Callback(object): '''Base class for holding callback @@ -219,8 +230,7 @@ return '<{} iden={} timeout={}>'.format( self.__class__.__name__, self.iden, self.timeout) - @asyncio.coroutine - def _timer(self) -> Generator[Any, None, None]: + async def _timer(self) -> Generator[Any, None, None]: '''An actual timer running on the event loop. This is a coroutine. @@ -230,10 +240,10 @@ if self.timeout > 0: timeout = self.timeout * 1e-3 self.impl.log.debug('sleeping %r', timeout) - yield from asyncio.sleep(timeout) + await asyncio.sleep(timeout) else: # scheduling timeout for next loop iteration - yield + await asyncio.sleep(0) except asyncio.CancelledError: self.impl.log.debug('timer %d cancelled', self.iden) @@ -248,8 +258,8 @@ 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) + self._task = asyncio.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) @@ -280,10 +290,11 @@ self.descriptors = DescriptorDict(self) self.log = logging.getLogger(self.__class__.__name__) - # NOTE invariant: _finished.is_set() iff _pending == 0 self._pending = 0 - self._finished = asyncio.Event(loop=loop) - self._finished.set() + # Transient asyncio.Event instance dynamically created + # and destroyed by drain() + # NOTE invariant: _finished.is_set() iff _pending == 0 + self._finished = None def __repr__(self) -> str: return '<{} callbacks={} descriptors={}>'.format( @@ -292,13 +303,14 @@ def _pending_inc(self) -> None: '''Increase the count of pending affairs. Do not use directly.''' self._pending += 1 - self._finished.clear() + if self._finished is not None: + self._finished.clear() def _pending_dec(self) -> None: '''Decrease the count of pending affairs. Do not use directly.''' assert self._pending > 0 self._pending -= 1 - if self._pending == 0: + if self._pending == 0 and self._finished is not None: self._finished.set() def register(self) -> "virEventAsyncIOImpl": @@ -312,10 +324,9 @@ def schedule_ff_callback(self, iden: int, opaque: _T) -> None: '''Schedule a ff callback from one of the handles or timers''' - ensure_future(self._ff_callback(iden, opaque), loop=self.loop) + asyncio.ensure_future(self._ff_callback(iden, opaque), loop=self.loop) - @asyncio.coroutine - def _ff_callback(self, iden: int, opaque: _T) -> None: + async def _ff_callback(self, iden: int, opaque: _T) -> None: '''Directly free the opaque object This is a coroutine. @@ -324,15 +335,18 @@ libvirt.virEventInvokeFreeCallback(opaque) self._pending_dec() - @asyncio.coroutine - def drain(self) -> Generator[Any, None, None]: + async def drain(self) -> None: '''Wait for the implementation to become idle. This is a coroutine. ''' self.log.debug('drain()') if self._pending: - yield from self._finished.wait() + assert self._finished is None + self._finished = asyncio.Event() + await self._finished.wait() + self._finished = None + assert self._pending == 0 self.log.debug('drain ended') def is_idle(self) -> bool: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libvirt-python-8.4.0/setup.py new/libvirt-python-8.5.0/setup.py --- old/libvirt-python-8.4.0/setup.py 2022-05-13 13:28:11.000000000 +0200 +++ new/libvirt-python-8.5.0/setup.py 2022-06-25 06:38:30.000000000 +0200 @@ -312,8 +312,17 @@ pytest = self.find_pytest_path() subprocess.check_call([pytest]) - class my_clean(Command): + user_options = [ + ('all', None, 'unused, compatibility with distutils') + ] + + def initialize_options(self): + self.all = False + + def finalize_options(self): + pass + def run(self): if os.path.exists("build"): shutil.rmtree("build", ignore_errors=True) @@ -326,7 +335,7 @@ _c_modules, _py_modules = get_module_lists() setup(name = 'libvirt-python', - version = '8.4.0', + version = '8.5.0', url = 'http://www.libvirt.org', maintainer = 'Libvirt Maintainers', maintainer_email = 'libvir-l...@redhat.com', @@ -359,5 +368,7 @@ "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", ] ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libvirt-python-8.4.0/tests/eventmock.py new/libvirt-python-8.5.0/tests/eventmock.py --- old/libvirt-python-8.4.0/tests/eventmock.py 1970-01-01 01:00:00.000000000 +0100 +++ new/libvirt-python-8.5.0/tests/eventmock.py 2022-06-25 06:38:30.000000000 +0200 @@ -0,0 +1,82 @@ + +import libvirt +import libvirtmod + +_add_handle_impl = None +_update_handle_impl = None +_remove_handle_impl = None + +_add_timeout_impl = None +_update_timeout_impl = None +_remove_timeout_impl = None + +_registered = False + +def _add_handle(fd: int, event: int, cb: libvirt._EventCB, opaque: libvirt._T) -> int: + global _add_handle_impl + assert _add_handle_impl != None + return _add_handle_impl(fd, event, cb, opaque) + +def _update_handle(watch: int, event: int) -> None: + global _update_handle_impl + assert _update_handle_impl != None + _update_handle_impl(watch, event) + +def _remove_handle(watch: int) -> int: + global _remove_handle_impl + assert _remove_handle_impl != None + return _remove_handle_impl(watch) + +def _add_timeout(timeout: int, cb: libvirt._TimerCB, opaque: libvirt._T) -> int: + global _add_timeout_impl + assert _add_timeout_impl != None + return _add_timeout_impl(timeout, cb, opaque) + +def _update_timeout(timer: int, timeout: int) -> None: + global _update_timeout_impl + assert _update_timeout_impl != None + _update_timeout_impl(timer, timeout) + +def _remove_timeout(timer: int) -> int: + global _remove_timeout_impl + assert _remove_timeout_impl != None + return _remove_timeout_impl(timer) + +# libvirt.virEventRegisterImpl() is a one time call per process +# This method is intended to be used with mock patching, so that +# tests can get the appearance of being able to call +# virEventRegisterImpl many times. +# +# Note, this relies on the tests closing all connection objects +# and not leaving any handles/timers pending when they stop +# running their event loop impl. + +def virEventRegisterImplMock(add_handle_impl, + update_handle_impl, + remove_handle_impl, + add_timeout_impl, + update_timeout_impl, + remove_timeout_impl): + global _add_handle_impl + global _update_handle_impl + global _remove_handle_impl + global _add_timeout_impl + global _update_timeout_impl + global _remove_timeout_impl + + _add_handle_impl = add_handle_impl + _update_handle_impl = update_handle_impl + _remove_handle_impl = remove_handle_impl + _add_timeout_impl = add_timeout_impl + _update_timeout_impl = update_timeout_impl + _remove_timeout_impl = remove_timeout_impl + + global _registered + if not _registered: + libvirtmod.virEventRegisterImpl(_add_handle, + _update_handle, + _remove_timeout, + _add_timeout, + _update_timeout, + _remove_timeout) + _registered = True diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libvirt-python-8.4.0/tests/test_aio.py new/libvirt-python-8.5.0/tests/test_aio.py --- old/libvirt-python-8.4.0/tests/test_aio.py 1970-01-01 01:00:00.000000000 +0100 +++ new/libvirt-python-8.5.0/tests/test_aio.py 2022-06-25 06:38:30.000000000 +0200 @@ -0,0 +1,156 @@ +import asyncio +import libvirt +import libvirtaio +import sys +import unittest +from unittest import mock + +import eventmock + + +class TestLibvirtAio(unittest.TestCase): + async def _run(self, register): + def lifecycleCallback(conn, dom, event, detail, domainChangedEvent): + if (event == libvirt.VIR_DOMAIN_EVENT_STOPPED or + event == libvirt.VIR_DOMAIN_EVENT_STARTED): + domainChangedEvent.set() + + if register: + libvirtEvents = libvirtaio.virEventRegisterAsyncIOImpl() + else: + libvirtEvents = libvirtaio.getCurrentImpl() + + conn = libvirt.open("test:///default") + dom = conn.lookupByName("test") + + eventRegistered = False + domainStopped = False + try: + # Ensure the VM is running. + self.assertEqual([libvirt.VIR_DOMAIN_RUNNING, libvirt.VIR_DOMAIN_RUNNING_UNKNOWN], dom.state()) + self.assertTrue(libvirtEvents.is_idle()) + + # Register VM start/stopped event handler. + domainChangedEvent = asyncio.Event() + conn.domainEventRegisterAny(dom, libvirt.VIR_DOMAIN_EVENT_ID_LIFECYCLE, lifecycleCallback, domainChangedEvent) + eventRegistered = True + + self.assertFalse(libvirtEvents.is_idle()) + + # Stop the VM. + dom.destroy() + domainStopped = True + + # Ensure domain stopped event is received. + await asyncio.wait_for(domainChangedEvent.wait(), 2) + self.assertEqual([libvirt.VIR_DOMAIN_SHUTOFF, libvirt.VIR_DOMAIN_SHUTOFF_DESTROYED], dom.state()) + + # Start the VM. + domainChangedEvent.clear() + domainStopped = False + dom.create() + + # Ensure domain started event is received. + await asyncio.wait_for(domainChangedEvent.wait(), 2) + self.assertEqual([libvirt.VIR_DOMAIN_RUNNING, libvirt.VIR_DOMAIN_RUNNING_BOOTED], dom.state()) + self.assertFalse(libvirtEvents.is_idle()) + + # Deregister the VM start/stopped event handler. + eventRegistered = False + conn.domainEventDeregisterAny(libvirt.VIR_DOMAIN_EVENT_ID_LIFECYCLE) + + # Wait for event queue to clear. + await libvirtEvents.drain() + + # Make sure event queue is cleared. + self.assertTrue(libvirtEvents.is_idle()) + + finally: + if eventRegistered: + conn.domainEventDeregisterAny(libvirt.VIR_DOMAIN_EVENT_ID_LIFECYCLE) + + if domainStopped: + dom.create() + + @mock.patch('libvirt.virEventRegisterImpl', + side_effect=eventmock.virEventRegisterImplMock) + def testEventsWithManualLoopSetup(self, mock_event_register): + # Register libvirt events after starting the asyncio loop. + # + # Manually create and set the event loop against this + # thread. + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + + loop.run_until_complete(self._run(register=True)) + + loop.close() + asyncio.set_event_loop(None) + mock_event_register.assert_called_once() + + @mock.patch('libvirt.virEventRegisterImpl', + side_effect=eventmock.virEventRegisterImplMock) + @unittest.skipIf(sys.version_info < (3,7), "test requires Python 3.7+") + def testEventsWithAsyncioRun(self, mock_event_register): + # Register libvirt events after starting the asyncio loop. + # + # Use asyncio helper to create and set the event loop + # against this thread. + asyncio.run(self._run(register=True)) + mock_event_register.assert_called_once() + + @mock.patch('libvirt.virEventRegisterImpl', + side_effect=eventmock.virEventRegisterImplMock) + def testEventsPreInitExplicit(self, mock_event_register): + # Register libvirt events before starting the asyncio loop. + # + # Tell virEventRegisterAsyncIOImpl() explicitly what loop + # to use before we set a loop for this thread. + loop = asyncio.new_event_loop() + libvirtaio.virEventRegisterAsyncIOImpl(loop) + asyncio.set_event_loop(loop) + + loop.run_until_complete(self._run(register=False)) + + loop.close() + asyncio.set_event_loop(None) + mock_event_register.assert_called_once() + + @mock.patch('libvirt.virEventRegisterImpl', + side_effect=eventmock.virEventRegisterImplMock) + @unittest.skipIf(sys.version_info >= (3,10), "test incompatible with 3.10") + def testEventsPreInitImplicit(self, mock_event_register): + # Register libvirt events before starting the asyncio loop. + # + # Allow virEventRegisterAsyncIOImpl() to implicitly find the + # loop we set for this thread. + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + libvirtaio.virEventRegisterAsyncIOImpl() + + loop.run_until_complete(self._run(register=False)) + + loop.close() + asyncio.set_event_loop(None) + mock_event_register.assert_called_once() + + @mock.patch('libvirt.virEventRegisterImpl', + side_effect=eventmock.virEventRegisterImplMock) + @unittest.skipIf(sys.version_info >= (3,10), "test incompatible with 3.10") + def testEventsImplicitLoopInit(self, mock_event_register): + # Register libvirt events before starting the asyncio loop. + # + # Let virEventRegisterAsyncIOImpl() auto-create a default + # event loop, which we then register against this thread. + # + # Historically this often worked if called from the main thead, + # but since Python 3.10 this triggers a deprecation warning, + # which will turn into a RuntimeError in a later release. + libvirtaio.virEventRegisterAsyncIOImpl() + loop = asyncio.get_event_loop() + + loop.run_until_complete(self._run(register=False)) + + loop.close() + asyncio.set_event_loop(None) + mock_event_register.assert_called_once()