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 2026-09-08 16:53:02
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-libvirt-python (Old)
 and      /work/SRC/openSUSE:Factory/.python-libvirt-python.new.1265 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-libvirt-python"

Tue Sep  8 16:53:02 2026 rev:106 rq:1375859 version:12.7.0

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/python-libvirt-python/python-libvirt-python.changes  
    2026-08-05 17:46:27.565751196 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-libvirt-python.new.1265/python-libvirt-python.changes
    2026-09-08 16:53:33.864573595 +0200
@@ -1,0 +2,6 @@
+Fri Sep  4 21:21:11 UTC 2026 - James Fehlig <[email protected]>
+
+- Update to 12.7.0
+  - Add all new APIs and constants in libvirt 12.7.0
+
+-------------------------------------------------------------------

Old:
----
  libvirt-python-12.6.0.tar.gz

New:
----
  libvirt-python-12.7.0.tar.gz

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

Other differences:
------------------
++++++ python-libvirt-python.spec ++++++
--- /var/tmp/diff_new_pack.OV0IAQ/_old  2026-09-08 16:53:34.874615970 +0200
+++ /var/tmp/diff_new_pack.OV0IAQ/_new  2026-09-08 16:53:34.877616096 +0200
@@ -23,7 +23,7 @@
 %{?sle15_python_module_pythons}
 Name:           python-libvirt-python
 URL:            https://libvirt.org/
-Version:        12.6.0
+Version:        12.7.0
 Release:        0
 Summary:        Library providing a virtualization API
 License:        LGPL-2.1-or-later

++++++ _service ++++++
--- /var/tmp/diff_new_pack.OV0IAQ/_old  2026-09-08 16:53:34.923618025 +0200
+++ /var/tmp/diff_new_pack.OV0IAQ/_new  2026-09-08 16:53:34.930618319 +0200
@@ -1,7 +1,7 @@
 <services>
   <service name="tar_scm" mode="manual">
     <param name="filename">libvirt-python</param>
-    <param name="revision">v12.6.0</param>
+    <param name="revision">v12.7.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-12.6.0.tar.gz -> libvirt-python-12.7.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libvirt-python-12.6.0/.gitignore 
new/libvirt-python-12.7.0/.gitignore
--- old/libvirt-python-12.6.0/.gitignore        2026-07-28 17:41:42.000000000 
+0200
+++ new/libvirt-python-12.7.0/.gitignore        2026-08-25 14:50:01.000000000 
+0200
@@ -13,3 +13,4 @@
 sdist/
 *.egg-info/
 *.egg
+docs/_build/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libvirt-python-12.6.0/.gitlab-ci.yml 
new/libvirt-python-12.7.0/.gitlab-ci.yml
--- old/libvirt-python-12.6.0/.gitlab-ci.yml    2026-07-28 17:41:42.000000000 
+0200
+++ new/libvirt-python-12.7.0/.gitlab-ci.yml    2026-08-25 14:50:01.000000000 
+0200
@@ -3,6 +3,7 @@
   - containers
   - builds
   - sanity_checks
+  - pages
 
 .git_build_vars: &git_build_vars |
   export MAKEFLAGS="-j$(getconf _NPROCESSORS_ONLN)"
@@ -57,6 +58,49 @@
 
 include: '/ci/gitlab.yml'
 
+# Build Sphinx HTML API docs.
+py_api_docs:
+  extends:
+    - .gitlab_native_build_job
+  needs:
+    - job: x86_64-fedora-44-container
+      optional: true
+  script:
+    - export MAKEFLAGS="-j$(getconf _NPROCESSORS_ONLN)"
+    - export CFLAGS="-Werror"
+    - $PYTHON -m build -n -x
+    - $PYTHON -m venv docs-venv --system-site-packages --symlinks
+    - docs-venv/bin/python -m pip install dist/libvirt_python*.whl
+    - docs-venv/bin/python -m pip install -r requirements-docs.txt
+    - docs-venv/bin/sphinx-build -b html docs/ py_api_docs
+  artifacts:
+    expose_as: 'py_api_docs'
+    name: 'py_api_docs'
+    when: on_success
+    expire_in: 30 days
+    paths:
+      - py_api_docs
+  variables:
+    NAME: fedora-44
+    TARGET_BASE_IMAGE: registry.fedoraproject.org/fedora:44
+
+# Publish "py_api_docs" output via GitLab Pages
+pages:
+  stage: pages
+  script:
+    - mv py_api_docs public
+  dependencies:
+    - py_api_docs
+  rules:
+    - if: '$CI_PROJECT_NAMESPACE == $RUN_UPSTREAM_NAMESPACE && 
$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
+      when: on_success
+    - when: never
+  artifacts:
+    expose_as: 'pages'
+    name: 'pages'
+    paths:
+      - public
+
 api_coverage_job:
   extends:
     - .gitlab_native_build_job
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libvirt-python-12.6.0/HACKING 
new/libvirt-python-12.7.0/HACKING
--- old/libvirt-python-12.6.0/HACKING   2026-07-28 17:41:42.000000000 +0200
+++ new/libvirt-python-12.7.0/HACKING   2026-08-25 14:50:01.000000000 +0200
@@ -36,3 +36,23 @@
    the virStoragePool class
  - libvirt-override-virStream.py - high level overrides in
    the virStream class
+
+
+
+    Building API Documentation
+    ==========================
+
+The Python API reference is built with Sphinx using the autodoc
+extension. Since the Python modules are generated at build time
+from XML API descriptions, the package must be compiled before
+Sphinx can import anything.
+
+  $ python -m venv docs-venv --system-site-packages --symlinks
+  $ source docs-venv/bin/activate
+  $ python -m pip install setuptools build
+  $ python -m pip install -r requirements-docs.txt
+  $ python -m build -n -x
+  $ python -m pip install dist/libvirt_python*.whl
+  $ python -m sphinx -b html docs/ py_api_docs
+
+The rendered HTML will be in the py_api_docs/ directory.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libvirt-python-12.6.0/VERSION 
new/libvirt-python-12.7.0/VERSION
--- old/libvirt-python-12.6.0/VERSION   2026-07-28 17:41:42.000000000 +0200
+++ new/libvirt-python-12.7.0/VERSION   2026-08-25 14:50:01.000000000 +0200
@@ -1 +1 @@
-12.6.0
+12.7.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/libvirt-python-12.6.0/ci/buildenv/centos-stream-10.sh 
new/libvirt-python-12.7.0/ci/buildenv/centos-stream-10.sh
--- old/libvirt-python-12.6.0/ci/buildenv/centos-stream-10.sh   2026-07-28 
17:41:42.000000000 +0200
+++ new/libvirt-python-12.7.0/ci/buildenv/centos-stream-10.sh   2026-08-25 
14:50:01.000000000 +0200
@@ -17,6 +17,7 @@
                 glibc-langpack-en \
                 libvirt-devel \
                 pkgconfig \
+                pyproject-rpm-macros \
                 python3 \
                 python3-build \
                 python3-devel \
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libvirt-python-12.6.0/ci/buildenv/centos-stream-9.sh 
new/libvirt-python-12.7.0/ci/buildenv/centos-stream-9.sh
--- old/libvirt-python-12.6.0/ci/buildenv/centos-stream-9.sh    2026-07-28 
17:41:42.000000000 +0200
+++ new/libvirt-python-12.7.0/ci/buildenv/centos-stream-9.sh    2026-08-25 
14:50:01.000000000 +0200
@@ -32,6 +32,7 @@
                 ninja-build \
                 perl-base \
                 pkgconfig \
+                pyproject-rpm-macros \
                 python3 \
                 python3-build \
                 python3-devel \
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libvirt-python-12.6.0/ci/buildenv/fedora-43.sh 
new/libvirt-python-12.7.0/ci/buildenv/fedora-43.sh
--- old/libvirt-python-12.6.0/ci/buildenv/fedora-43.sh  2026-07-28 
17:41:42.000000000 +0200
+++ new/libvirt-python-12.7.0/ci/buildenv/fedora-43.sh  2026-08-25 
14:50:01.000000000 +0200
@@ -14,6 +14,7 @@
                 glibc-langpack-en \
                 libvirt-devel \
                 pkgconfig \
+                pyproject-rpm-macros \
                 python3 \
                 python3-build \
                 python3-devel \
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libvirt-python-12.6.0/ci/buildenv/fedora-44.sh 
new/libvirt-python-12.7.0/ci/buildenv/fedora-44.sh
--- old/libvirt-python-12.6.0/ci/buildenv/fedora-44.sh  2026-07-28 
17:41:42.000000000 +0200
+++ new/libvirt-python-12.7.0/ci/buildenv/fedora-44.sh  2026-08-25 
14:50:01.000000000 +0200
@@ -14,6 +14,7 @@
                 glibc-langpack-en \
                 libvirt-devel \
                 pkgconfig \
+                pyproject-rpm-macros \
                 python3 \
                 python3-build \
                 python3-devel \
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libvirt-python-12.6.0/ci/buildenv/fedora-rawhide.sh 
new/libvirt-python-12.7.0/ci/buildenv/fedora-rawhide.sh
--- old/libvirt-python-12.6.0/ci/buildenv/fedora-rawhide.sh     2026-07-28 
17:41:42.000000000 +0200
+++ new/libvirt-python-12.7.0/ci/buildenv/fedora-rawhide.sh     2026-08-25 
14:50:01.000000000 +0200
@@ -15,6 +15,7 @@
                 glibc-langpack-en \
                 libvirt-devel \
                 pkgconfig \
+                pyproject-rpm-macros \
                 python3 \
                 python3-build \
                 python3-devel \
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/libvirt-python-12.6.0/ci/containers/centos-stream-10.Dockerfile 
new/libvirt-python-12.7.0/ci/containers/centos-stream-10.Dockerfile
--- old/libvirt-python-12.6.0/ci/containers/centos-stream-10.Dockerfile 
2026-07-28 17:41:42.000000000 +0200
+++ new/libvirt-python-12.7.0/ci/containers/centos-stream-10.Dockerfile 
2026-08-25 14:50:01.000000000 +0200
@@ -18,6 +18,7 @@
                 glibc-langpack-en \
                 libvirt-devel \
                 pkgconfig \
+                pyproject-rpm-macros \
                 python3 \
                 python3-build \
                 python3-devel \
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/libvirt-python-12.6.0/ci/containers/centos-stream-9.Dockerfile 
new/libvirt-python-12.7.0/ci/containers/centos-stream-9.Dockerfile
--- old/libvirt-python-12.6.0/ci/containers/centos-stream-9.Dockerfile  
2026-07-28 17:41:42.000000000 +0200
+++ new/libvirt-python-12.7.0/ci/containers/centos-stream-9.Dockerfile  
2026-08-25 14:50:01.000000000 +0200
@@ -33,6 +33,7 @@
                 ninja-build \
                 perl-base \
                 pkgconfig \
+                pyproject-rpm-macros \
                 python3 \
                 python3-build \
                 python3-devel \
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/libvirt-python-12.6.0/ci/containers/fedora-43.Dockerfile 
new/libvirt-python-12.7.0/ci/containers/fedora-43.Dockerfile
--- old/libvirt-python-12.6.0/ci/containers/fedora-43.Dockerfile        
2026-07-28 17:41:42.000000000 +0200
+++ new/libvirt-python-12.7.0/ci/containers/fedora-43.Dockerfile        
2026-08-25 14:50:01.000000000 +0200
@@ -25,6 +25,7 @@
                        glibc-langpack-en \
                        libvirt-devel \
                        pkgconfig \
+                       pyproject-rpm-macros \
                        python3 \
                        python3-build \
                        python3-devel \
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/libvirt-python-12.6.0/ci/containers/fedora-44.Dockerfile 
new/libvirt-python-12.7.0/ci/containers/fedora-44.Dockerfile
--- old/libvirt-python-12.6.0/ci/containers/fedora-44.Dockerfile        
2026-07-28 17:41:42.000000000 +0200
+++ new/libvirt-python-12.7.0/ci/containers/fedora-44.Dockerfile        
2026-08-25 14:50:01.000000000 +0200
@@ -25,6 +25,7 @@
                        glibc-langpack-en \
                        libvirt-devel \
                        pkgconfig \
+                       pyproject-rpm-macros \
                        python3 \
                        python3-build \
                        python3-devel \
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/libvirt-python-12.6.0/ci/containers/fedora-rawhide.Dockerfile 
new/libvirt-python-12.7.0/ci/containers/fedora-rawhide.Dockerfile
--- old/libvirt-python-12.6.0/ci/containers/fedora-rawhide.Dockerfile   
2026-07-28 17:41:42.000000000 +0200
+++ new/libvirt-python-12.7.0/ci/containers/fedora-rawhide.Dockerfile   
2026-08-25 14:50:01.000000000 +0200
@@ -26,6 +26,7 @@
                        glibc-langpack-en \
                        libvirt-devel \
                        pkgconfig \
+                       pyproject-rpm-macros \
                        python3 \
                        python3-build \
                        python3-devel \
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/libvirt-python-12.6.0/ci/lcitool/projects/libvirt-python.yml 
new/libvirt-python-12.7.0/ci/lcitool/projects/libvirt-python.yml
--- old/libvirt-python-12.6.0/ci/lcitool/projects/libvirt-python.yml    
2026-07-28 17:41:42.000000000 +0200
+++ new/libvirt-python-12.7.0/ci/lcitool/projects/libvirt-python.yml    
2026-08-25 14:50:01.000000000 +0200
@@ -3,6 +3,7 @@
   - ccache
   - gcc
   - pkg-config
+  - pyproject-rpm-macros
   - python3
   - python3-build
   - python3-devel
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libvirt-python-12.6.0/docs/Makefile 
new/libvirt-python-12.7.0/docs/Makefile
--- old/libvirt-python-12.6.0/docs/Makefile     1970-01-01 01:00:00.000000000 
+0100
+++ new/libvirt-python-12.7.0/docs/Makefile     2026-08-25 14:50:01.000000000 
+0200
@@ -0,0 +1,12 @@
+SPHINXOPTS    ?=
+SPHINXBUILD   ?= sphinx-build
+SOURCEDIR     = .
+BUILDDIR      = _build
+
+help:
+       @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
+
+.PHONY: help Makefile
+
+%: Makefile
+       @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libvirt-python-12.6.0/docs/conf.py 
new/libvirt-python-12.7.0/docs/conf.py
--- old/libvirt-python-12.6.0/docs/conf.py      1970-01-01 01:00:00.000000000 
+0100
+++ new/libvirt-python-12.7.0/docs/conf.py      2026-08-25 14:50:01.000000000 
+0200
@@ -0,0 +1,68 @@
+import os
+import sys
+
+sys.path.insert(0, os.path.abspath('../build'))
+sys.path.insert(0, os.path.abspath('..'))
+
+project = 'libvirt-python'
+author = 'Libvirt Maintainers'
+
+with open(os.path.abspath('../VERSION')) as f:
+    version = f.read().strip()
+release = version
+
+# Libvirt major version tracks the year as major + 2014 (e.g. 12 → 2026)
+copyright = '%d, Libvirt Maintainers' % (int(version.split('.')[0]) + 2014)
+
+extensions = [
+    'sphinx.ext.autodoc',
+    'sphinx.ext.viewcode',
+]
+
+autodoc_member_order = 'groupwise'
+autodoc_default_options = {
+    'members': True,
+    'undoc-members': True,
+    'show-inheritance': True,
+}
+
+html_theme = 'alabaster'
+html_theme_options = {
+    'description': 'Python bindings for the libvirt API',
+    'github_button': False,
+}
+
+
+def _needs_literal_docstring(lines):
+    """Here comes a little bit of magic.
+    This function returns True if docstring content is unsafe as 
reStructuredText,
+    it will tell Sphinx to use the docstring as is, without any formatting.
+
+    Docs from C API descriptions are not always valid reStructuredText,
+    these are valid for Python help() but are not docutils.
+    """
+    in_field = False
+    for line in lines:
+        if line.startswith(':'):
+            in_field = True
+            continue
+        if in_field:
+            stripped = line.lstrip()
+            if stripped.startswith(('-', '*')) and line[:1].isspace():
+                return True
+            if line and not line[0].isspace() and not line.startswith(':'):
+                in_field = False
+        if line.startswith((' ', '\t')):
+            return True
+    return False
+
+
+def process_docstring(app, what, name, obj, options, lines):
+    if not lines or not _needs_literal_docstring(lines):
+        return
+    body = list(lines)
+    lines[:] = ['::', ''] + [('    ' + line if line else '') for line in body]
+
+
+def setup(app):
+    app.connect('autodoc-process-docstring', process_docstring)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libvirt-python-12.6.0/docs/index.rst 
new/libvirt-python-12.7.0/docs/index.rst
--- old/libvirt-python-12.6.0/docs/index.rst    1970-01-01 01:00:00.000000000 
+0100
+++ new/libvirt-python-12.7.0/docs/index.rst    2026-08-25 14:50:01.000000000 
+0200
@@ -0,0 +1,20 @@
+libvirt-python API Documentation
+=================================
+
+Python bindings for the `libvirt <https://libvirt.org/>`_ virtualization API.
+
+.. toctree::
+   :maxdepth: 2
+   :caption: API Reference
+
+   libvirt
+   libvirt_qemu
+   libvirt_lxc
+   libvirtaio
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libvirt-python-12.6.0/docs/libvirt.rst 
new/libvirt-python-12.7.0/docs/libvirt.rst
--- old/libvirt-python-12.6.0/docs/libvirt.rst  1970-01-01 01:00:00.000000000 
+0100
+++ new/libvirt-python-12.7.0/docs/libvirt.rst  2026-08-25 14:50:01.000000000 
+0200
@@ -0,0 +1,7 @@
+libvirt --- Main API
+====================
+
+.. automodule:: libvirt
+   :members:
+   :undoc-members:
+   :show-inheritance:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libvirt-python-12.6.0/docs/libvirt_lxc.rst 
new/libvirt-python-12.7.0/docs/libvirt_lxc.rst
--- old/libvirt-python-12.6.0/docs/libvirt_lxc.rst      1970-01-01 
01:00:00.000000000 +0100
+++ new/libvirt-python-12.7.0/docs/libvirt_lxc.rst      2026-08-25 
14:50:01.000000000 +0200
@@ -0,0 +1,7 @@
+libvirt_lxc --- LXC Extensions
+===============================
+
+.. automodule:: libvirt_lxc
+   :members:
+   :undoc-members:
+   :show-inheritance:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libvirt-python-12.6.0/docs/libvirt_qemu.rst 
new/libvirt-python-12.7.0/docs/libvirt_qemu.rst
--- old/libvirt-python-12.6.0/docs/libvirt_qemu.rst     1970-01-01 
01:00:00.000000000 +0100
+++ new/libvirt-python-12.7.0/docs/libvirt_qemu.rst     2026-08-25 
14:50:01.000000000 +0200
@@ -0,0 +1,7 @@
+libvirt_qemu --- QEMU Extensions
+=================================
+
+.. automodule:: libvirt_qemu
+   :members:
+   :undoc-members:
+   :show-inheritance:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libvirt-python-12.6.0/docs/libvirtaio.rst 
new/libvirt-python-12.7.0/docs/libvirtaio.rst
--- old/libvirt-python-12.6.0/docs/libvirtaio.rst       1970-01-01 
01:00:00.000000000 +0100
+++ new/libvirt-python-12.7.0/docs/libvirtaio.rst       2026-08-25 
14:50:01.000000000 +0200
@@ -0,0 +1,7 @@
+libvirtaio --- Asyncio Integration
+====================================
+
+.. automodule:: libvirtaio
+   :members:
+   :undoc-members:
+   :show-inheritance:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libvirt-python-12.6.0/libvirt-override.c 
new/libvirt-python-12.7.0/libvirt-override.c
--- old/libvirt-python-12.6.0/libvirt-override.c        2026-07-28 
17:41:42.000000000 +0200
+++ new/libvirt-python-12.7.0/libvirt-override.c        2026-08-25 
14:50:01.000000000 +0200
@@ -1696,6 +1696,9 @@
     { VIR_DOMAIN_IOTHREAD_THREAD_POOL_MIN, VIR_TYPED_PARAM_INT },
     { VIR_DOMAIN_IOTHREAD_THREAD_POOL_MAX, VIR_TYPED_PARAM_INT },
 # endif /*  LIBVIR_CHECK_VERSION(8, 5, 0) */
+# if LIBVIR_CHECK_VERSION(12, 7, 0)
+    { VIR_DOMAIN_IOTHREAD_POLL_WEIGHT, VIR_TYPED_PARAM_UINT },
+# endif /*  LIBVIR_CHECK_VERSION(12, 7, 0) */
 };
 
 static PyObject *
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libvirt-python-12.6.0/libvirt-python.spec.in 
new/libvirt-python-12.7.0/libvirt-python.spec.in
--- old/libvirt-python-12.6.0/libvirt-python.spec.in    2026-07-28 
17:41:42.000000000 +0200
+++ new/libvirt-python-12.7.0/libvirt-python.spec.in    2026-08-25 
14:50:01.000000000 +0200
@@ -3,8 +3,8 @@
 # This spec file assumes you are building on a Fedora or RHEL version
 # that's still supported by the vendor. It may work on other distros
 # or versions, but no effort will be made to ensure that going forward
-%define min_rhel 8
-%define min_fedora 33
+%define min_rhel 9
+%define min_fedora 43
 
 %if (0%{?fedora} && 0%{?fedora} >= %{min_fedora}) || (0%{?rhel} && 0%{?rhel} 
>= %{min_rhel})
     %define supported_platform 1
@@ -25,7 +25,6 @@
 BuildRequires: python3-devel
 BuildRequires: python3-pytest
 BuildRequires: python3-lxml
-BuildRequires: python3-setuptools
 BuildRequires: gcc
 
 # Don't want provides for python shared objects
@@ -59,31 +58,26 @@
 # for the -python3 package
 find examples -type f -exec chmod 0644 \{\} \;
 
+%generate_buildrequires
+%pyproject_buildrequires
+
 %build
 %if ! %{supported_platform}
 echo "This RPM requires either Fedora >= %{min_fedora} or RHEL >= %{min_rhel}"
 exit 1
 %endif
 
-%py3_build
+%pyproject_wheel
 
 %install
-%py3_install
+%pyproject_install
+%pyproject_save_files libvirt libvirt_lxc libvirt_qemu libvirtaio 'libvirtmod*'
 
 %check
+%pyproject_check_import
 %pytest
 
-%files -n python3-libvirt
+%files -n python3-libvirt -f %{pyproject_files}
 %doc ChangeLog AUTHORS README COPYING examples/
-%{python3_sitearch}/libvirt.py*
-%{python3_sitearch}/libvirtaio.py*
-%{python3_sitearch}/libvirt_qemu.py*
-%{python3_sitearch}/libvirt_lxc.py*
-%{python3_sitearch}/__pycache__/libvirt.cpython-*.py*
-%{python3_sitearch}/__pycache__/libvirt_qemu.cpython-*.py*
-%{python3_sitearch}/__pycache__/libvirt_lxc.cpython-*.py*
-%{python3_sitearch}/__pycache__/libvirtaio.cpython-*.py*
-%{python3_sitearch}/libvirtmod*
-%{python3_sitearch}/*egg-info
 
 %changelog
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libvirt-python-12.6.0/requirements-docs.txt 
new/libvirt-python-12.7.0/requirements-docs.txt
--- old/libvirt-python-12.6.0/requirements-docs.txt     1970-01-01 
01:00:00.000000000 +0100
+++ new/libvirt-python-12.7.0/requirements-docs.txt     2026-08-25 
14:50:01.000000000 +0200
@@ -0,0 +1 @@
+sphinx
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libvirt-python-12.6.0/setup.cfg 
new/libvirt-python-12.7.0/setup.cfg
--- old/libvirt-python-12.6.0/setup.cfg 2026-07-28 17:41:42.000000000 +0200
+++ new/libvirt-python-12.7.0/setup.cfg 2026-08-25 14:50:01.000000000 +0200
@@ -15,6 +15,6 @@
       Programming Language :: Python :: 3 :: Only
 
 [options]
-python_requires = >=3.6
+python_requires = >=3.9
 package_dir =
     =build
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libvirt-python-12.6.0/tests/test_conn.py 
new/libvirt-python-12.7.0/tests/test_conn.py
--- old/libvirt-python-12.6.0/tests/test_conn.py        2026-07-28 
17:41:42.000000000 +0200
+++ new/libvirt-python-12.7.0/tests/test_conn.py        2026-08-25 
14:50:01.000000000 +0200
@@ -18,6 +18,182 @@
         self.assertEqual(type(doms[0]), libvirt.virDomain)
         self.assertEqual(doms[0].name(), "test")
 
+
+class TestLibvirtConnMetadata(unittest.TestCase):
+    """Connection metadata and lifecycle tests"""
+
+    def setUp(self):
+        self.conn = libvirt.open("test:///default")
+
+    def tearDown(self):
+        self.conn = None
+
+    def testConnGetURI(self):
+        uri = self.conn.getURI()
+
+        self.assertIsInstance(uri, str)
+        self.assertEqual(uri, "test:///default")
+
+    def testConnGetHostname(self):
+        hostname = self.conn.getHostname()
+
+        self.assertIsInstance(hostname, str)
+        self.assertGreater(len(hostname), 0)
+
+    def testConnGetLibVersion(self):
+        version = self.conn.getLibVersion()
+
+        self.assertIsInstance(version, int)
+        self.assertGreater(version, 0)
+
+    def testConnGetVersion(self):
+        """test driver reports hypervisor version 2"""
+        version = self.conn.getVersion()
+
+        self.assertIsInstance(version, int)
+        self.assertEqual(version, 2)
+
+    def testConnGetType(self):
+        """test driver reports type TEST"""
+        hv_type = self.conn.getType()
+
+        self.assertIsInstance(hv_type, str)
+        self.assertEqual(hv_type, "TEST")
+
+    def testConnIsAlive(self):
+        self.assertTrue(self.conn.isAlive())
+
+    def testConnIsEncrypted(self):
+        result = self.conn.isEncrypted()
+
+        self.assertIsInstance(result, (bool, int))
+        self.assertFalse(result)
+
+    def testConnIsSecure(self):
+        result = self.conn.isSecure()
+
+        self.assertIsInstance(result, (bool, int))
+        self.assertTrue(result)
+
+    def testConnClose(self):
+        self.assertTrue(self.conn.isAlive())
+
+        ret = self.conn.close()
+        self.assertEqual(ret, 0)
+
+        with self.assertRaises(libvirt.libvirtError):
+            self.conn.isAlive()
+
+    def testConnContextManager(self):
+        with libvirt.open("test:///default") as conn:
+            self.assertEqual(conn.getURI(), "test:///default")
+            self.assertTrue(conn.isAlive())
+
+        with self.assertRaises(libvirt.libvirtError):
+            conn.isAlive()
+
+
+class TestLibvirtConnOpenNegative(unittest.TestCase):
+    """Connection open failure for an invalid URI"""
+
+    def testOpenFails(self):
+        with self.assertRaises(libvirt.libvirtError) as ctx:
+            libvirt.open("not-a-valid-libvirt-uri")
+
+        self.assertIsNotNone(ctx.exception.get_error_message())
+
+
+class TestLibvirtConnReadOnly(unittest.TestCase):
+    """Read-only libvirt.openReadOnly() connection tests"""
+
+    DEFINE_XML = """
+        <domain type='test'>
+          <name>test-define-temp</name>
+          <uuid>12345678-1234-1234-1234-123456789abc</uuid>
+          <memory unit='KiB'>524288</memory>
+          <vcpu>1</vcpu>
+          <os>
+            <type>hvm</type>
+          </os>
+        </domain>
+        """
+
+    def setUp(self):
+        self.conn = libvirt.openReadOnly("test:///default")
+
+    def tearDown(self):
+        self.conn = None
+
+    def testOpenReadOnlySucceeds(self):
+        self.assertIsNotNone(self.conn)
+        self.assertTrue(self.conn.isAlive())
+
+    def testReadOnlyGetURI(self):
+        self.assertEqual(self.conn.getURI(), "test:///default")
+
+    def testReadOnlyGetType(self):
+        self.assertEqual(self.conn.getType(), "TEST")
+
+    def testReadOnlyListDomains(self):
+        domains = self.conn.listAllDomains()
+
+        self.assertIsInstance(domains, list)
+        self.assertGreater(len(domains), 0)
+        self.assertIsInstance(domains[0], libvirt.virDomain)
+
+    def testReadOnlyLookupAndInfo(self):
+        dom = self.conn.lookupByName("test")
+
+        self.assertEqual(dom.name(), "test")
+
+        info = dom.info()
+        self.assertIsInstance(info, (tuple, list))
+        self.assertEqual(len(info), 5)
+
+        state, _ = dom.state()
+        self.assertIsInstance(state, int)
+
+    def testReadOnlyXMLDesc(self):
+        dom = self.conn.lookupByName("test")
+        xml = dom.XMLDesc(0)
+
+        self.assertIsInstance(xml, str)
+        self.assertIn("<domain", xml)
+
+    def testReadOnlyDefineXMLDenied(self):
+        with self.assertRaises(libvirt.libvirtError) as ctx:
+            self.conn.defineXML(self.DEFINE_XML)
+
+        self.assertEqual(ctx.exception.get_error_code(),
+                         libvirt.VIR_ERR_OPERATION_DENIED)
+
+    def testReadOnlyDestroyDenied(self):
+        dom = self.conn.lookupByName("test")
+
+        with self.assertRaises(libvirt.libvirtError) as ctx:
+            dom.destroy()
+
+        self.assertEqual(ctx.exception.get_error_code(),
+                         libvirt.VIR_ERR_OPERATION_DENIED)
+
+    def testReadOnlyXMLDescSecureDenied(self):
+        dom = self.conn.lookupByName("test")
+
+        with self.assertRaises(libvirt.libvirtError) as ctx:
+            dom.XMLDesc(libvirt.VIR_DOMAIN_XML_SECURE)
+
+        self.assertEqual(ctx.exception.get_error_code(),
+                         libvirt.VIR_ERR_OPERATION_DENIED)
+
+    def testReadOnlyContextManager(self):
+        with libvirt.openReadOnly("test:///default") as conn:
+            self.assertEqual(conn.getURI(), "test:///default")
+            self.assertTrue(conn.isAlive())
+
+        with self.assertRaises(libvirt.libvirtError):
+            conn.isAlive()
+
+
 class TestLibvirtConnAuth(unittest.TestCase):
     connXML = """
 <node>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libvirt-python-12.6.0/tests/test_domain_migration.py 
new/libvirt-python-12.7.0/tests/test_domain_migration.py
--- old/libvirt-python-12.6.0/tests/test_domain_migration.py    1970-01-01 
01:00:00.000000000 +0100
+++ new/libvirt-python-12.7.0/tests/test_domain_migration.py    2026-08-25 
14:50:01.000000000 +0200
@@ -0,0 +1,391 @@
+import libvirt
+import unittest
+
+from unittest.mock import patch, MagicMock
+
+
+class TestLibvirtDomainMigrationMocked(unittest.TestCase):
+    def setUp(self):
+        self.conn = libvirt.open("test:///default")
+        self.dom = self.conn.lookupByName("test")
+
+    def tearDown(self):
+        self.dom = None
+        self.conn = None
+
+    @patch("libvirtmod.virDomainMigrate3")
+    def testMigrate3LiveMigrationSuccess(self, mock_migrate3):
+        dst_conn = libvirt.open("test:///default")
+        dst_dom = dst_conn.lookupByName("test")
+
+        # A small hack to make virDomainFree work with mocked objects,
+        # the same applies to all tests in this set that return a domain 
pointer.
+        # Transfer ownership of the raw C pointer to the mock return value by
+        # setting _o to None so dst_dom.__del__ won't also call virDomainFree 
on it.
+        mock_migrate3.return_value = dst_dom._o
+        dst_dom._o = None
+
+        params = {
+            libvirt.VIR_MIGRATE_PARAM_URI: "qemu+ssh://desthost/system",
+            libvirt.VIR_MIGRATE_PARAM_BANDWIDTH: 1024,
+        }
+        flags = libvirt.VIR_MIGRATE_LIVE | libvirt.VIR_MIGRATE_PERSIST_DEST
+
+        result = self.dom.migrate3(dst_conn, params, flags)
+
+        self.assertIsInstance(result, libvirt.virDomain)
+
+        mock_migrate3.assert_called_once()
+        call_args = mock_migrate3.call_args
+        self.assertEqual(call_args[0][0], self.dom._o)
+        self.assertEqual(call_args[0][1], dst_conn._o)
+        self.assertEqual(call_args[0][3], flags)
+
+        dst_conn.close()
+
+    @patch("libvirtmod.virDomainMigrateToURI3")
+    def testMigrateToURI3PeerToPeerSuccess(self, mock_migrateToURI3):
+        mock_migrateToURI3.return_value = 0
+
+        dest_uri = "qemu+ssh://desthost/system"
+        params = {
+            libvirt.VIR_MIGRATE_PARAM_BANDWIDTH: 2048,
+            libvirt.VIR_MIGRATE_PARAM_DEST_NAME: "migrated-vm",
+        }
+        flags = libvirt.VIR_MIGRATE_LIVE | libvirt.VIR_MIGRATE_PEER2PEER
+
+        result = self.dom.migrateToURI3(dest_uri, params, flags)
+
+        self.assertEqual(result, 0)
+
+        mock_migrateToURI3.assert_called_once()
+        call_args = mock_migrateToURI3.call_args
+        self.assertEqual(call_args[0][0], self.dom._o)
+        self.assertEqual(call_args[0][1], dest_uri)
+        self.assertEqual(call_args[0][3], flags)
+
+    @patch("libvirtmod.virDomainMigrate3")
+    def testMigrate3OfflineMigration(self, mock_migrate3):
+        dst_conn = libvirt.open("test:///default")
+        dst_dom = dst_conn.lookupByName("test")
+
+        # domain must be inactive
+        if self.dom.isActive():
+            self.dom.destroy()
+
+        mock_migrate3.return_value = dst_dom._o
+        dst_dom._o = None
+
+        params = {}
+        flags = libvirt.VIR_MIGRATE_OFFLINE | libvirt.VIR_MIGRATE_PERSIST_DEST
+
+        result = self.dom.migrate3(dst_conn, params, flags)
+
+        self.assertIsInstance(result, libvirt.virDomain)
+        call_args = mock_migrate3.call_args
+        self.assertTrue(call_args[0][3] & libvirt.VIR_MIGRATE_OFFLINE)
+
+        dst_conn.close()
+
+    @patch("libvirtmod.virDomainMigrate3")
+    def testMigrate3WithCompressionParameters(self, mock_migrate3):
+        dst_conn = libvirt.open("test:///default")
+        dst_dom = dst_conn.lookupByName("test")
+
+        mock_migrate3.return_value = dst_dom._o
+        dst_dom._o = None
+
+        params = {
+            libvirt.VIR_MIGRATE_PARAM_BANDWIDTH: 1024,
+            libvirt.VIR_MIGRATE_PARAM_COMPRESSION: "mt",
+            libvirt.VIR_MIGRATE_PARAM_COMPRESSION_MT_LEVEL: 9,
+            libvirt.VIR_MIGRATE_PARAM_COMPRESSION_MT_THREADS: 4,
+            libvirt.VIR_MIGRATE_PARAM_COMPRESSION_MT_DTHREADS: 2,
+        }
+        flags = libvirt.VIR_MIGRATE_LIVE | libvirt.VIR_MIGRATE_COMPRESSED
+
+        result = self.dom.migrate3(dst_conn, params, flags)
+
+        self.assertIsInstance(result, libvirt.virDomain)
+        mock_migrate3.assert_called_once()
+        call_args = mock_migrate3.call_args
+        self.assertTrue(call_args[0][3] & libvirt.VIR_MIGRATE_COMPRESSED)
+
+        dst_conn.close()
+
+    @patch("libvirtmod.virDomainMigrateToURI3")
+    def testMigrateToURI3WithAutoConverge(self, mock_migrateToURI3):
+        mock_migrateToURI3.return_value = 0
+
+        params = {
+            libvirt.VIR_MIGRATE_PARAM_AUTO_CONVERGE_INITIAL: 20,
+            libvirt.VIR_MIGRATE_PARAM_AUTO_CONVERGE_INCREMENT: 10,
+        }
+        flags = (
+            libvirt.VIR_MIGRATE_LIVE
+            | libvirt.VIR_MIGRATE_PEER2PEER
+            | libvirt.VIR_MIGRATE_AUTO_CONVERGE
+        )
+
+        result = self.dom.migrateToURI3("qemu+ssh://dest/system", params, 
flags)
+
+        self.assertEqual(result, 0)
+        mock_migrateToURI3.assert_called_once()
+        call_args = mock_migrateToURI3.call_args
+        self.assertTrue(call_args[0][3] & libvirt.VIR_MIGRATE_AUTO_CONVERGE)
+
+    @patch("libvirtmod.virDomainMigrate3")
+    def testMigrate3WithTLSParameters(self, mock_migrate3):
+        dst_conn = libvirt.open("test:///default")
+        dst_dom = dst_conn.lookupByName("test")
+
+        mock_migrate3.return_value = dst_dom._o
+        dst_dom._o = None
+
+        params = {
+            libvirt.VIR_MIGRATE_PARAM_URI: "qemu+ssh://desthost/system",
+            libvirt.VIR_MIGRATE_PARAM_TLS_DESTINATION: "desthost.example.com",
+        }
+        flags = libvirt.VIR_MIGRATE_LIVE | libvirt.VIR_MIGRATE_TLS
+
+        result = self.dom.migrate3(dst_conn, params, flags)
+
+        self.assertIsInstance(result, libvirt.virDomain)
+        call_args = mock_migrate3.call_args
+        self.assertTrue(call_args[0][3] & libvirt.VIR_MIGRATE_TLS)
+
+        dst_conn.close()
+
+    @patch("libvirtmod.virDomainMigrateToURI3")
+    def testMigrateToURI3WithParallelConnections(self, mock_migrateToURI3):
+        mock_migrateToURI3.return_value = 0
+
+        params = {
+            libvirt.VIR_MIGRATE_PARAM_PARALLEL_CONNECTIONS: 4,
+            libvirt.VIR_MIGRATE_PARAM_BANDWIDTH: 4096,
+        }
+        flags = (
+            libvirt.VIR_MIGRATE_LIVE
+            | libvirt.VIR_MIGRATE_PEER2PEER
+            | libvirt.VIR_MIGRATE_PARALLEL
+        )
+
+        result = self.dom.migrateToURI3("qemu+ssh://dest/system", params, 
flags)
+
+        self.assertEqual(result, 0)
+
+        call_args = mock_migrateToURI3.call_args
+        self.assertTrue(call_args[0][3] & libvirt.VIR_MIGRATE_PARALLEL)
+
+    @patch("libvirtmod.virDomainMigrate3")
+    def testMigrate3EmptyParameterDict(self, mock_migrate3):
+        dst_conn = libvirt.open("test:///default")
+        dst_dom = dst_conn.lookupByName("test")
+
+        mock_migrate3.return_value = dst_dom._o
+        dst_dom._o = None
+
+        # Empty params dict
+        params = {}
+        flags = libvirt.VIR_MIGRATE_LIVE
+
+        result = self.dom.migrate3(dst_conn, params, flags)
+
+        self.assertIsInstance(result, libvirt.virDomain)
+        mock_migrate3.assert_called_once()
+
+        dst_conn.close()
+
+    @patch("libvirtmod.virDomainMigrate3")
+    def testMigrate3MultipleFlags(self, mock_migrate3):
+        dst_conn = libvirt.open("test:///default")
+        dst_dom = dst_conn.lookupByName("test")
+
+        mock_migrate3.return_value = dst_dom._o
+        dst_dom._o = None
+
+        params = {
+            libvirt.VIR_MIGRATE_PARAM_BANDWIDTH: 1024,
+        }
+
+        flags = (
+            libvirt.VIR_MIGRATE_LIVE
+            | libvirt.VIR_MIGRATE_PERSIST_DEST
+            | libvirt.VIR_MIGRATE_UNDEFINE_SOURCE
+            | libvirt.VIR_MIGRATE_COMPRESSED
+            | libvirt.VIR_MIGRATE_AUTO_CONVERGE
+        )
+
+        result = self.dom.migrate3(dst_conn, params, flags)
+
+        self.assertIsInstance(result, libvirt.virDomain)
+
+        call_args = mock_migrate3.call_args
+        passed_flags = call_args[0][3]
+        self.assertTrue(passed_flags & libvirt.VIR_MIGRATE_LIVE)
+        self.assertTrue(passed_flags & libvirt.VIR_MIGRATE_PERSIST_DEST)
+        self.assertTrue(passed_flags & libvirt.VIR_MIGRATE_UNDEFINE_SOURCE)
+        self.assertTrue(passed_flags & libvirt.VIR_MIGRATE_COMPRESSED)
+        self.assertTrue(passed_flags & libvirt.VIR_MIGRATE_AUTO_CONVERGE)
+
+        dst_conn.close()
+
+    @patch("libvirtmod.virDomainMigrate3")
+    def testMigrate3Failure(self, mock_migrate3):
+        dst_conn = libvirt.open("test:///default")
+
+        mock_migrate3.return_value = None
+
+        params = {}
+        flags = libvirt.VIR_MIGRATE_LIVE
+
+        # raise exception when C layer returns None
+        with self.assertRaises(libvirt.libvirtError) as ctx:
+            self.dom.migrate3(dst_conn, params, flags)
+
+        self.assertIn("virDomainMigrate3() failed", str(ctx.exception))
+
+        dst_conn.close()
+
+    @patch("libvirtmod.virDomainMigrateToURI3")
+    def testMigrateToURI3Failure(self, mock_migrateToURI3):
+        mock_migrateToURI3.return_value = -1
+
+        params = {}
+        flags = libvirt.VIR_MIGRATE_LIVE | libvirt.VIR_MIGRATE_PEER2PEER
+
+        # raise exception on failure
+        with self.assertRaises(libvirt.libvirtError):
+            self.dom.migrateToURI3("qemu+ssh://dest/system", params, flags)
+
+
+class TestLibvirtDomainMigrateLegacyMocked(unittest.TestCase):
+    """Tests for the legacy virDomainMigrate and virDomainMigrate2 APIs.
+
+    Both virDomainMigrate and virDomainMigrate2 call independent C functionas
+    (libvirtmod.virDomainMigrate and libvirtmod.virDomainMigrate2) and have
+    their own wrapping logic, so they are tested separately from migrate3.
+    """
+
+    def setUp(self):
+        self.conn = libvirt.open("test:///default")
+        self.dom = self.conn.lookupByName("test")
+
+    def tearDown(self):
+        self.dom = None
+        self.conn = None
+
+    @patch("libvirtmod.virDomainMigrate")
+    def testMigrateSuccess(self, mock_migrate):
+        dst_conn = libvirt.open("test:///default")
+        dst_dom = dst_conn.lookupByName("test")
+
+        mock_migrate.return_value = dst_dom._o
+        dst_dom._o = None
+
+        flags = libvirt.VIR_MIGRATE_LIVE | libvirt.VIR_MIGRATE_PERSIST_DEST
+        result = self.dom.migrate(dst_conn, flags, dname="migrated-vm",
+                                  uri="qemu+ssh://desthost/system", 
bandwidth=1024)
+
+        self.assertIsInstance(result, libvirt.virDomain)
+        mock_migrate.assert_called_once()
+        call_args = mock_migrate.call_args
+        self.assertEqual(call_args[0][0], self.dom._o)
+        self.assertEqual(call_args[0][1], dst_conn._o)
+        self.assertEqual(call_args[0][2], flags)
+
+        dst_conn.close()
+
+    @patch("libvirtmod.virDomainMigrate")
+    def testMigrateWithFlags(self, mock_migrate):
+        dst_conn = libvirt.open("test:///default")
+        dst_dom = dst_conn.lookupByName("test")
+
+        mock_migrate.return_value = dst_dom._o
+        dst_dom._o = None
+
+        flags = (
+            libvirt.VIR_MIGRATE_LIVE
+            | libvirt.VIR_MIGRATE_PERSIST_DEST
+            | libvirt.VIR_MIGRATE_UNDEFINE_SOURCE
+        )
+        result = self.dom.migrate(dst_conn, flags)
+
+        self.assertIsInstance(result, libvirt.virDomain)
+        call_args = mock_migrate.call_args
+        passed_flags = call_args[0][2]
+        self.assertTrue(passed_flags & libvirt.VIR_MIGRATE_LIVE)
+        self.assertTrue(passed_flags & libvirt.VIR_MIGRATE_PERSIST_DEST)
+        self.assertTrue(passed_flags & libvirt.VIR_MIGRATE_UNDEFINE_SOURCE)
+
+        dst_conn.close()
+
+    @patch("libvirtmod.virDomainMigrate")
+    def testMigrateFailure(self, mock_migrate):
+        dst_conn = libvirt.open("test:///default")
+
+        mock_migrate.return_value = None
+
+        with self.assertRaises(libvirt.libvirtError) as ctx:
+            self.dom.migrate(dst_conn, libvirt.VIR_MIGRATE_LIVE)
+
+        self.assertIn("virDomainMigrate() failed", str(ctx.exception))
+
+        dst_conn.close()
+
+    @patch("libvirtmod.virDomainMigrate2")
+    def testMigrate2Success(self, mock_migrate2):
+        dst_conn = libvirt.open("test:///default")
+        dst_dom = dst_conn.lookupByName("test")
+
+        mock_migrate2.return_value = dst_dom._o
+        dst_dom._o = None
+
+        dxml = "<domain type='test'><name>migrated-vm</name></domain>"
+        flags = libvirt.VIR_MIGRATE_LIVE | libvirt.VIR_MIGRATE_PERSIST_DEST
+        result = self.dom.migrate2(dst_conn, dxml=dxml, flags=flags,
+                                   dname="migrated-vm")
+
+        self.assertIsInstance(result, libvirt.virDomain)
+        mock_migrate2.assert_called_once()
+        call_args = mock_migrate2.call_args
+        self.assertEqual(call_args[0][0], self.dom._o)
+        self.assertEqual(call_args[0][1], dst_conn._o)
+        self.assertEqual(call_args[0][2], dxml)
+        self.assertEqual(call_args[0][3], flags)
+
+        dst_conn.close()
+
+    @patch("libvirtmod.virDomainMigrate2")
+    def testMigrate2WithoutXML(self, mock_migrate2):
+        dst_conn = libvirt.open("test:///default")
+        dst_dom = dst_conn.lookupByName("test")
+
+        mock_migrate2.return_value = dst_dom._o
+        dst_dom._o = None
+
+        flags = libvirt.VIR_MIGRATE_LIVE
+        result = self.dom.migrate2(dst_conn, flags=flags)
+
+        self.assertIsInstance(result, libvirt.virDomain)
+        call_args = mock_migrate2.call_args
+        self.assertIsNone(call_args[0][2])
+
+        dst_conn.close()
+
+    @patch("libvirtmod.virDomainMigrate2")
+    def testMigrate2Failure(self, mock_migrate2):
+        dst_conn = libvirt.open("test:///default")
+
+        mock_migrate2.return_value = None
+
+        with self.assertRaises(libvirt.libvirtError) as ctx:
+            self.dom.migrate2(dst_conn, flags=libvirt.VIR_MIGRATE_LIVE)
+
+        self.assertIn("virDomainMigrate2() failed", str(ctx.exception))
+
+        dst_conn.close()
+
+
+if __name__ == "__main__":
+    unittest.main()

Reply via email to