public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
* [rpms/python-dmidecode] main: Patched for libxml2-2.15.4
@ 2026-09-17 19:03 Antonio Trande
  0 siblings, 0 replies; only message in thread
From: Antonio Trande @ 2026-09-17 19:03 UTC (permalink / raw)
  To: git-commits

A new commit has been pushed.

Repo   : rpms/python-dmidecode
Branch : main
Commit : b807f4cd332538f0668b1ac00df13dcbb74b68ef
Author : Antonio Trande <sagitter@fedoraproject.org>
Date   : 2026-09-17T21:02:56+02:00
Stats  : +752/-4 in 2 file(s)
URL    : https://src.fedoraproject.org/rpms/python-dmidecode/c/b807f4cd332538f0668b1ac00df13dcbb74b68ef?branch=main

Log:
Patched for libxml2-2.15.4

---
diff --git a/python-dmidecode-libxml2.patch b/python-dmidecode-libxml2.patch
new file mode 100644
index 0000000..f82c8c0
--- /dev/null
+++ b/python-dmidecode-libxml2.patch
@@ -0,0 +1,737 @@
+From 4ad2e4ca0f6ca6c40fb994a72f8972d24b890554 Mon Sep 17 00:00:00 2001
+From: Yuzuru10 <yuzuru_10@proton.me>
+Date: Sat, 5 Jul 2025 20:21:14 +0300
+Subject: [PATCH] Fix XML handling and update libxml2 bindings in python-dmidecode
+
+diff --git a/dmidecode.py b/dmidecode.py
+index ac81365..19379f4 100644
+--- a/dmidecode.py
++++ b/dmidecode.py
+@@ -25,24 +25,25 @@
+ #   are deemed to be part of the source code.
+ #
+ 
+-import libxml2
++try:
++    from lxml import etree
++except ImportError:
++    raise ImportError("lxml is required. Install with: pip install lxml")
++
+ from dmidecodemod import *
++from lxml import etree
++from dmidecodemod import xmlapi
+ 
+-DMIXML_NODE='n'
+-DMIXML_DOC='d'
++DMIXML_NODE = 'n'
++DMIXML_DOC = 'd'
+ 
+ class dmidecodeXML:
+     "Native Python API for retrieving dmidecode information as XML"
+-
++    
+     def __init__(self):
+-        self.restype = DMIXML_NODE;
++        self.restype = DMIXML_NODE
+ 
+     def SetResultType(self, type):
+-        """
+-        Sets the result type of queries.  The value can be DMIXML_NODE or DMIXML_DOC,
+-        which will return an libxml2::xmlNode or libxml2::xmlDoc object, respectively
+-        """
+-
+         if type == DMIXML_NODE:
+             self.restype = DMIXML_NODE
+         elif type == DMIXML_DOC:
+@@ -52,38 +53,308 @@ def SetResultType(self, type):
+         return True
+ 
+     def QuerySection(self, sectname):
+-        """
+-        Queries the DMI data structure for a given section name.  A section
+-        can often contain several DMI type elements
+-        """
+-        if self.restype == DMIXML_NODE:
+-            ret = libxml2.xmlNode( _obj = xmlapi(query_type='s',
+-                                                           result_type=self.restype,
+-                                                           section=sectname) )
+-        elif self.restype == DMIXML_DOC:
+-            ret = libxml2.xmlDoc( _obj = xmlapi(query_type='s',
+-                                                          result_type=self.restype,
+-                                                          section=sectname) )
+-        else:
+-            raise TypeError("Invalid result type value")
++        try:
++            query_args = {
++                'query_type': 's',
++                'result_type': 'n' if self.restype == DMIXML_NODE else 'd',
++                'section': sectname
++            }
++
++            xml_string = xmlapi(**query_args)
+ 
+-        return ret
++            if not xml_string or not isinstance(xml_string, str):
++                raise RuntimeError("C module did not return a valid XML string")
+ 
++            if self.restype == DMIXML_NODE:
++                return etree.fromstring(xml_string)
++            elif self.restype == DMIXML_DOC:
++                return etree.ElementTree(etree.fromstring(xml_string))
++            else:
++                raise TypeError("Invalid result type value")
++
++        except Exception as e:
++            raise RuntimeError(f"Failed to query section '{sectname}': {str(e)}")
+ 
+     def QueryTypeId(self, tpid):
+-        """
+-        Queries the DMI data structure for a specific DMI type.
+-        """
+-        if self.restype == DMIXML_NODE:
+-            ret = libxml2.xmlNode( _obj = xmlapi(query_type='t',
+-                                                           result_type=self.restype,
+-                                                           typeid=tpid))
+-        elif self.restype == DMIXML_DOC:
+-            ret = libxml2.xmlDoc( _obj = xmlapi(query_type='t',
+-                                                          result_type=self.restype,
+-                                                          typeid=tpid))
+-        else:
+-            raise TypeError("Invalid result type value")
++        try:
++            tpid = int(tpid)
++            query_args = {
++                'query_type': 't',
++                'result_type': 'n' if self.restype == DMIXML_NODE else 'd',
++                'typeid': tpid
++            }
++
++            xml_string = xmlapi(**query_args)
++
++            if not xml_string or not isinstance(xml_string, str):
++                raise RuntimeError("C module did not return a valid XML string")
++
++            if self.restype == DMIXML_NODE:
++                return etree.fromstring(xml_string)
++            elif self.restype == DMIXML_DOC:
++                return etree.ElementTree(etree.fromstring(xml_string))
++            else:
++                raise TypeError("Invalid result type value")
++
++        except Exception as e:
++            raise RuntimeError(f"Failed to query type ID '{tpid}': {str(e)}")
++
++# Convenience functions for backward compatibility
++def query_section(sectname, result_type=DMIXML_NODE):
++    """
++    Convenience function to query a section and return lxml object
++    """
++    dmi = dmidecodeXML()
++    dmi.SetResultType(result_type)
++    return dmi.QuerySection(sectname)
++
++def query_type_id(tpid, result_type=DMIXML_NODE):
++    """
++    Convenience function to query a type ID and return lxml object
++    """
++    dmi = dmidecodeXML()
++    dmi.SetResultType(result_type)
++    return dmi.QueryTypeId(tpid)
++
++# Backward compatibility class for older API
++class DMIDecode:
++    def __init__(self):
++        self.dmi = dmidecodeXML()
++
++    def get(self, section=None, type_id=None):
++        try:
++            if section is not None:
++                section = str(section)
++                xml_data = self.dmi.QuerySection(section)
++            elif type_id is not None:
++                if isinstance(type_id, dict):
++                    try:
++                        type_id = int(list(type_id.keys())[0], 16)
++                    except Exception as e:
++                        raise ValueError(f"Invalid type_id dict format: {type_id}") from e
++                else:
++                    type_id = int(type_id)
++                xml_data = self.dmi.QueryTypeId(type_id)
++            else:
++                raise ValueError("Either section or type_id must be specified")
++
++            if xml_data is None:
++                return {}
++
++            return self._xml_to_dict(xml_data)
++
++        except Exception as e:
++            import traceback
++            traceback.print_exc()
++            return {}
++
++    def _xml_to_dict(self, xml_element):
++        result = {}
++        if xml_element.attrib:
++            result.update(xml_element.attrib)
++        if xml_element.text and xml_element.text.strip():
++            if len(xml_element) == 0:
++                return xml_element.text.strip()
++            else:
++                result['_text'] = xml_element.text.strip()
++        for child in xml_element:
++            child_data = self._xml_to_dict(child)
++            if child.tag in result:
++                if not isinstance(result[child.tag], list):
++                    result[child.tag] = [result[child.tag]]
++                result[child.tag].append(child_data)
++            else:
++                result[child.tag] = child_data
++        return result
++
++    def system(self):
++        """Get system information"""
++        return self.get(section="system")
++    
++    def bios(self):
++        """Get BIOS information"""
++        return self.get(type_id=0)
++    
++    def baseboard(self):
++        """Get baseboard information"""
++        return self.get(type_id=2)
++    
++    def chassis(self):
++        """Get chassis information"""
++        return self.get(type_id=3)
++    
++    def processor(self):
++        """Get processor information"""
++        return self.get(type_id=4)
++    
++    def memory(self):
++        """Get memory information"""
++        return self.get(section="memory")
++    
++    def model(self):
++        """Get system model information"""
++        try:
++            system_info = self.get(section="system")
++            if system_info and isinstance(system_info, dict):
++                # Try to find model/product name in the system info
++                # Look for common keys that might contain model info
++                for key in ['product', 'model', 'product_name', 'system_product_name']:
++                    if key in system_info:
++                        return system_info[key]
++                
++                # If it's nested, try to find it in nested structures
++                for value in system_info.values():
++                    if isinstance(value, dict):
++                        for subkey in ['product', 'model', 'product_name']:
++                            if subkey in value:
++                                return value[subkey]
++            
++            return "Unknown"
++        except Exception as e:
++            print(f"Error getting model info: {e}")
++            return "Unknown"
++    
++    def manufacturer(self):
++        """Get system manufacturer"""
++        try:
++            system_info = self.get(section="system")
++            if system_info and isinstance(system_info, dict):
++                for key in ['manufacturer', 'vendor', 'system_manufacturer']:
++                    if key in system_info:
++                        return system_info[key]
++                
++                # Check nested structures
++                for value in system_info.values():
++                    if isinstance(value, dict):
++                        for subkey in ['manufacturer', 'vendor']:
++                            if subkey in value:
++                                return value[subkey]
++            
++            return "Unknown"
++        except Exception as e:
++            print(f"Error getting manufacturer info: {e}")
++            return "Unknown"
++    
++    def version(self):
++        """Get system version"""
++        try:
++            system_info = self.get(section="system")
++            if system_info and isinstance(system_info, dict):
++                for key in ['version', 'system_version']:
++                    if key in system_info:
++                        return system_info[key]
++                
++                # Check nested structures
++                for value in system_info.values():
++                    if isinstance(value, dict):
++                        if 'version' in value:
++                            return value['version']
++            
++            return "Unknown"
++        except Exception as e:
++            print(f"Error getting version info: {e}")
++            return "Unknown"
++    
++    def serial(self):
++        """Get system serial number"""
++        try:
++            system_info = self.get(section="system")
++            if system_info and isinstance(system_info, dict):
++                for key in ['serial', 'serial_number', 'system_serial']:
++                    if key in system_info:
++                        return system_info[key]
++                
++                # Check nested structures
++                for value in system_info.values():
++                    if isinstance(value, dict):
++                        for subkey in ['serial', 'serial_number']:
++                            if subkey in value:
++                                return value[subkey]
++            
++            return "Unknown"
++        except Exception as e:
++            print(f"Error getting serial info: {e}")
++            return "Unknown"
++    
++    def cpu_type(self):
++        """Get CPU type/model information"""
++        try:
++            # Try processor section first
++            proc_info = self.get(type_id=4)  # Type 4 is processor
++            if proc_info and isinstance(proc_info, dict):
++                # Look for CPU model/type info
++                for key in ['version', 'model', 'name', 'processor_version', 'processor_name']:
++                    if key in proc_info:
++                        return proc_info[key]
++                
++                # Check nested structures
++                for value in proc_info.values():
++                    if isinstance(value, dict):
++                        for subkey in ['version', 'model', 'name']:
++                            if subkey in value:
++                                return value[subkey]
++            
++            # If that fails, try a different approach
++            return "Unknown"
++        except Exception as e:
++            print(f"Error getting CPU type: {e}")
++            return "Unknown"
++    
++    def cpu(self):
++        """Alias for cpu_type() for compatibility"""
++        return self.cpu_type()
+ 
+-        return ret
++# Example usage functions
++def get_system_info():
++    """
++    Get system information as a convenient dictionary
++    """
++    try:
++        root = query_section("system")
++        if root is None:
++            return None
++        
++        system_info = {}
++        
++        # Extract common system information
++        for elem in root.iter():
++            if elem.tag == "manufacturer":
++                system_info["manufacturer"] = elem.text
++            elif elem.tag == "product":
++                system_info["product"] = elem.text
++            elif elem.tag == "version":
++                system_info["version"] = elem.text
++            elif elem.tag == "serial":
++                system_info["serial"] = elem.text
++            elif elem.tag == "uuid":
++                system_info["uuid"] = elem.text
++            elif elem.tag == "family":
++                system_info["family"] = elem.text
++        
++        return system_info
++    except Exception as e:
++        print(f"Error getting system info: {e}")
++        return None
+ 
++def get_memory_info():
++    """
++    Get memory information as a list of memory modules
++    """
++    try:
++        root = query_section("memory")
++        if root is None:
++            return None
++        
++        memory_modules = []
++        
++        # This is a simplified example - you'd need to adjust based on actual XML structure
++        for device in root.findall(".//memory_device"):
++            module = {}
++            for child in device:
++                module[child.tag] = child.text
++            memory_modules.append(module)
++        
++        return memory_modules
++    except Exception as e:
++        print(f"Error getting memory info: {e}")
++        return None
+
+diff --git a/src/dmidecodemodule.c b/src/dmidecodemodule.c
+index efa730b..2b3f67f 100644
+--- a/src/dmidecodemodule.c
++++ b/src/dmidecodemodule.c
+@@ -42,8 +42,6 @@
+ #include <Python.h>
+ 
+ #include <libxml/tree.h>
+-#include "libxml_wrap.h"
+-
+ #include "dmidecodemodule.h"
+ #include "dmixml.h"
+ #include "dmierror.h"
+@@ -431,6 +429,7 @@ xmlNode *__dmidecode_xml_getsection(options *opt, const char *section) {
+ 
+         dmixml_n = xmlNewNode(NULL, (xmlChar *) "dmidecode");
+         assert( dmixml_n != NULL );
++
+         // Append DMI version info
+         if( opt->dmiversion_n != NULL ) {
+                 xmlAddChild(dmixml_n, xmlCopyNode(opt->dmiversion_n, 1));
+@@ -439,7 +438,6 @@ xmlNode *__dmidecode_xml_getsection(options *opt, const char *section) {
+         // Fetch the Mapping XML file
+         if( (group_n = load_mappingxml(opt)) == NULL) {
+                 xmlFreeNode(dmixml_n);
+-                // Exception already set by calling function
+                 return NULL;
+         }
+ 
+@@ -468,36 +466,35 @@ xmlNode *__dmidecode_xml_getsection(options *opt, const char *section) {
+                         continue;
+                 }
+ 
+-                // The children of <Mapping> tags must only be <TypeMap> and
+-                // they must have an 'id' attribute
+                 if( (typeid == NULL) || (xmlStrcmp(group_n->name, (xmlChar *) "TypeMap") != 0) ) {
+                         PyReturnError(PyExc_RuntimeError, "Invalid TypeMap node in mapping XML");
+                 }
+ 
+-                // Parse the typeid string to a an integer
+                 opt->type = parse_opt_type(opt->logdata, typeid);
+                 if(opt->type == -1) {
+                         char *err = log_retrieve(opt->logdata, LOG_ERR);
+                         log_clear_partial(opt->logdata, LOG_ERR, 0);
+-                        _pyReturnError(PyExc_RuntimeError, "Invalid type id '%s' -- %s", typeid, err);
++                        PyErr_Format(PyExc_RuntimeError, "Invalid type id '%s' -- %s", typeid, err);
+                         free(err);
+                         return NULL;
+                 }
+ 
+-                // Parse the DMI data and put the result into dmixml_n node chain.
+                 if( dmidecode_get_xml(opt, dmixml_n) != 0 ) {
+-                        PyReturnError(PyExc_RuntimeError, "Error decoding DMI data");
++                        return NULL;
+                 }
+         }
++
+ #if 0  // DEBUG - will dump generated XML to stdout
+         xmlDoc *doc = xmlNewDoc((xmlChar *) "1.0");
+         xmlDocSetRootElement(doc, xmlCopyNode(dmixml_n, 1));
+         xmlSaveFormatFileEnc("-", doc, "UTF-8", 1);
+         xmlFreeDoc(doc);
+ #endif
++
+         return dmixml_n;
+ }
+ 
++
+ static PyObject *dmidecode_get_group(options *opt, const char *section)
+ {
+ 	int efi;
+@@ -692,73 +689,127 @@ static PyObject *dmidecode_get_type(PyObject * self, PyObject * args)
+ 
+ static PyObject *dmidecode_xmlapi(PyObject *self, PyObject *args, PyObject *keywds)
+ {
+-        static char *keywordlist[] = {"query_type", "result_type", "section", "typeid", NULL};
+-        PyObject *pydata = NULL;
+-        xmlDoc *dmixml_doc = NULL;
+-        xmlNode *dmixml_n = NULL;
+-        char *sect_query = NULL, *qtype = NULL, *rtype = NULL;
+-        int type_query = -1;
++    static char *keywordlist[] = {"query_type", "result_type", "section", "typeid", NULL};
++    PyObject *pydata = NULL;
++    xmlDoc *dmixml_doc = NULL;
++    xmlNode *dmixml_n = NULL;
++    char *sect_query = NULL, *qtype = NULL, *rtype = NULL;
++    int type_query = -1;
++    xmlBuffer *buffer = NULL;
++    xmlChar *xml_string = NULL;
++    int xml_size = 0;
++
++    if (!PyArg_ParseTupleAndKeywords(args, keywds, "ss|si", keywordlist,
++                                     &qtype, &rtype, &sect_query, &type_query))
++        return NULL;
++
++    if (!qtype || !rtype) {
++        PyErr_SetString(PyExc_TypeError, "query_type and result_type cannot be NULL");
++        return NULL;
++    }
++
++    switch (*qtype) {
++        case 's':
++            if (!sect_query) {
++                PyErr_SetString(PyExc_TypeError, "section keyword cannot be NULL");
++                return NULL;
++            }
++            dmixml_n = __dmidecode_xml_getsection(global_options, sect_query);
++            if (!dmixml_n) {
++                PyErr_Format(PyExc_RuntimeError, "DMI section '%s' returned NULL - possibly unsupported or bad permissions", sect_query);
++                return NULL;
++            }
++            break;
++        case 't':
++            if (type_query < 0) {
++                PyErr_SetString(PyExc_TypeError, "typeid keyword must be set and positive integer");
++                return NULL;
++            }
++            if (type_query > 255) {
++                PyErr_SetString(PyExc_ValueError, "typeid must be between 0 and 255");
++                return NULL;
++            }
++            dmixml_n = __dmidecode_xml_gettypeid(global_options, type_query);
++            if (!dmixml_n) {
++                PyErr_Format(PyExc_RuntimeError, "DMI type '%d' returned NULL - possibly unsupported or bad permissions", type_query);
++                return NULL;
++            }
++            break;
++        default:
++            PyErr_Format(PyExc_TypeError, "Invalid query type '%c' - must be 's' or 't'", *qtype);
++            return NULL;
++    }
++
++    if (!dmixml_n) // ekstra kontrol, zaten hata set edildi
++        return NULL;
+ 
+-        // Parse the keywords - we only support keywords, as this is an internal API
+-        if( !PyArg_ParseTupleAndKeywords(args, keywds, "ss|si", keywordlist,
+-                                         &qtype, &rtype, &sect_query, &type_query) ) {
++    switch (*rtype) {
++        case 'n': // XML node string
++            buffer = xmlBufferCreate();
++            if (!buffer) {
++                xmlFreeNode(dmixml_n);
++                PyErr_SetString(PyExc_MemoryError, "Could not create XML buffer");
+                 return NULL;
+-        }
++            }
+ 
+-        // Check for sensible arguments and retrieve the xmlNode with DMI data
+-        switch( *qtype ) {
+-        case 's': // Section / GroupName
+-                if( sect_query == NULL ) {
+-                        PyReturnError(PyExc_TypeError, "section keyword cannot be NULL")
+-                }
+-                dmixml_n = __dmidecode_xml_getsection(global_options, sect_query);
+-                break;
+-
+-        case 't': // TypeID / direct TypeMap
+-                if( type_query < 0 ) {
+-                        PyReturnError(PyExc_TypeError,
+-                                      "typeid keyword must be set and must be a positive integer");
+-                } else if( type_query > 255 ) {
+-                        PyReturnError(PyExc_ValueError,
+-                                      "typeid keyword must be an integer between 0 and 255");
+-                }
+-                dmixml_n = __dmidecode_xml_gettypeid(global_options, type_query);
+-                break;
++            if (xmlNodeDump(buffer, dmixml_n->doc, dmixml_n, 0, 1) < 0) {
++                xmlBufferFree(buffer);
++                xmlFreeNode(dmixml_n);
++                PyErr_SetString(PyExc_RuntimeError, "Could not dump XML node to buffer");
++                return NULL;
++            }
+ 
+-        default:
+-                PyReturnError(PyExc_TypeError, "Internal error - invalid query type '%c'", *qtype);
+-        }
++            pydata = PyUnicode_FromString((const char *)xmlBufferContent(buffer));
++            xmlBufferFree(buffer);
++            xmlFreeNode(dmixml_n);
++            break;
+ 
+-        // Check if we got any data
+-        if( dmixml_n == NULL ) {
+-                // Exception already set
++        case 'd': // Full XML document string
++            dmixml_doc = xmlNewDoc((xmlChar *)"1.0");
++            if (!dmixml_doc) {
++                xmlFreeNode(dmixml_n);
++                PyErr_SetString(PyExc_MemoryError, "Could not create new XML document");
+                 return NULL;
+-        }
++            }
+ 
+-        // Check for sensible return type and wrap the correct type into a Python Object
+-        switch( *rtype ) {
+-        case 'n':
+-                pydata = libxml_xmlNodePtrWrap((xmlNode *) dmixml_n);
+-                break;
++            xmlNode *root_node = xmlCopyNode(dmixml_n, 1);
++            if (!root_node) {
++                xmlFreeDoc(dmixml_doc);
++                xmlFreeNode(dmixml_n);
++                PyErr_SetString(PyExc_MemoryError, "Could not copy XML node");
++                return NULL;
++            }
+ 
+-        case 'd':
+-                dmixml_doc = xmlNewDoc((xmlChar *) "1.0");
+-                if( dmixml_doc == NULL ) {
+-                        PyReturnError(PyExc_MemoryError, "Could not create new XML document");
+-                }
+-                xmlDocSetRootElement(dmixml_doc, dmixml_n);
+-                pydata = libxml_xmlDocPtrWrap((xmlDoc *) dmixml_doc);
+-                break;
++            xmlDocSetRootElement(dmixml_doc, root_node);
++
++            xmlDocDumpMemory(dmixml_doc, &xml_string, &xml_size);
++            if (!xml_string) {
++                xmlFreeDoc(dmixml_doc);
++                xmlFreeNode(dmixml_n);
++                PyErr_SetString(PyExc_RuntimeError, "Could not dump XML document to memory");
++                return NULL;
++            }
++
++            pydata = PyUnicode_FromString((const char *)xml_string);
++
++            xmlFree(xml_string);
++            xmlFreeDoc(dmixml_doc);
++            xmlFreeNode(dmixml_n);
++            break;
+ 
+         default:
+-                PyReturnError(PyExc_TypeError, "Internal error - invalid result type '%c'", *rtype);
+-        }
++            xmlFreeNode(dmixml_n);
++            PyErr_Format(PyExc_TypeError, "Invalid result type '%c' - must be 'n' or 'd'", *rtype);
++            return NULL;
++    }
+ 
+-        // Return XML data
+-        Py_INCREF(pydata);
+-        return pydata;
+-}
++    if (!pydata) {
++        PyErr_SetString(PyExc_RuntimeError, "Could not create Python string from XML data");
++        return NULL;
++    }
+ 
++    return pydata;
++}
+ 
+ 
+ static PyObject *dmidecode_dump(PyObject * self, PyObject * null)
+@@ -913,8 +964,12 @@ static PyMethodDef DMIDataMethods[] = {
+         {(char *)"pythonmap", dmidecode_set_pythonxmlmap, METH_O,
+          (char *) "Use another python dict map definition. The default file is " PYTHON_XML_MAP},
+ 
+-        {(char *)"xmlapi", dmidecode_xmlapi, METH_VARARGS | METH_KEYWORDS,
+-         (char *) "Internal API for retrieving data as raw XML data"},
++        { 
++                 .ml_name = "xmlapi", 
++                 .ml_meth = (PyCFunction)(void(*)(void))dmidecode_xmlapi,
++                .ml_flags = METH_VARARGS | METH_KEYWORDS, 
++                 .ml_doc = "Get DMI data as XML"
++        },
+ 
+ 
+         {(char *)"get_warnings", dmidecode_get_warnings, METH_NOARGS,
+@@ -926,48 +981,49 @@ static PyMethodDef DMIDataMethods[] = {
+         {NULL, NULL, 0, NULL}
+ };
+ 
+-void destruct_options(void *ptr)
++void destruct_options(PyObject *capsule)
+ {
+-#ifdef IS_PY3K
+-        ptr = PyCapsule_GetPointer(ptr, NULL);
+-#endif
++    void *ptr = PyCapsule_GetPointer(capsule, NULL);
++    if (ptr) {
+         options *opt = (options *) ptr;
+ 
+         if( opt->mappingxml != NULL ) {
+-                xmlFreeDoc(opt->mappingxml);
+-                opt->mappingxml = NULL;
++            xmlFreeDoc(opt->mappingxml);
++            opt->mappingxml = NULL;
+         }
+ 
+         if( opt->python_xml_map != NULL ) {
+-                free(opt->python_xml_map);
+-                opt->python_xml_map = NULL;
++            free(opt->python_xml_map);
++            opt->python_xml_map = NULL;
+         }
+ 
+         if( opt->dmiversion_n != NULL ) {
+-                xmlFreeNode(opt->dmiversion_n);
+-                opt->dmiversion_n = NULL;
++            xmlFreeNode(opt->dmiversion_n);
++            opt->dmiversion_n = NULL;
+         }
+ 
+         if( opt->dumpfile != NULL ) {
+-                free(opt->dumpfile);
+-                opt->dumpfile = NULL;
++            free(opt->dumpfile);
++            opt->dumpfile = NULL;
+         }
+ 
+         if( opt->logdata != NULL ) {
+-                char *warn = NULL;
++            char *warn = NULL;
+ 
+-                log_clear_partial(opt->logdata, LOG_WARNING, 0);
+-                warn = log_retrieve(opt->logdata, LOG_WARNING);
+-                if( warn ) {
+-                        fprintf(stderr, "\n** COLLECTED WARNINGS **\n%s** END OF WARNINGS **\n\n", warn);
+-                        free(warn);
+-                }
+-                log_close(opt->logdata);
++            log_clear_partial(opt->logdata, LOG_WARNING, 0);
++            warn = log_retrieve(opt->logdata, LOG_WARNING);
++            if( warn ) {
++                fprintf(stderr, "\n** COLLECTED WARNINGS **\n%s** END OF WARNINGS **\n\n", warn);
++                free(warn);
++            }
++            log_close(opt->logdata);
+         }
+ 
+         free(ptr);
++    }
+ }
+ 
++
+ #ifdef IS_PY3K
+ static struct PyModuleDef dmidecodemod_def = {
+     PyModuleDef_HEAD_INIT,
+diff --git a/src/setup_common.py b/src/setup_common.py
+index aec1f9b..90d88c3 100644
+--- a/setup_common.py
++++ b/setup_common.py
+@@ -69,7 +69,7 @@ def libxml2_lib(libdir, libs):
+             libs.append(l.replace("-l", "", 1))
+ 
+     # this library is not reported and we need it anyway
+-    libs.append('xml2mod')
++    #libs.append('xml2mod')
+ 
+ 
+ 
+

diff --git a/python-dmidecode.spec b/python-dmidecode.spec
index f210ac1..128409a 100644
--- a/python-dmidecode.spec
+++ b/python-dmidecode.spec
@@ -13,18 +13,23 @@
 Name: python-dmidecode
 Summary: Python module to access DMI data
 Version: 3.12.3
-Release: 19%{date}%{shortcommit}%{?dist}
+Release: 20%{date}%{shortcommit}%{?dist}
 License: GPL-2.0-only
 URL: https://github.com/nima/python-dmidecode
 Source0: %{url}/archive/%{version}/%{name}-%{version}.tar.gz
 
 Patch0: python-dmidecode-rhbz2154949.patch
 
+# This patch derives by a fork, 
+# https://github.com/Yuzuru10/python-dmidecode/commit/4ad2e4ca0f6ca6c40fb994a72f8972d24b890554
+Patch1: python-dmidecode-libxml2.patch
+
 BuildRequires: make
 BuildRequires: gcc
 BuildRequires: libxml2-devel
 BuildRequires: python3-devel
 BuildRequires: libxml2-python3
+BuildRequires: python3-lxml
 
 %global _description\
 python-dmidecode is a python extension module that uses the\
@@ -38,6 +43,7 @@ as python data structures or as XML data using libxml2.\
 %package -n python3-dmidecode
 Summary: Python 3 module to access DMI data
 Requires: libxml2-python3
+Requires: python3-lxml
 
 %description -n python3-dmidecode %_description
 
@@ -49,6 +55,10 @@ Requires: libxml2-python3
 # we need the setup.py file in PWD to make the setuptools build backend see it
 mv src/setup*.py .
 
+%if 0%{?fedora} > 45
+%patch 1 -p1 -b .libxml2
+%endif
+
 %generate_buildrequires
 %pyproject_buildrequires
 
@@ -65,20 +75,21 @@ export CXX=g++
 %pyproject_install
 %pyproject_save_files -L dmidecode dmidecodemod
 
-
 %check
 %pyproject_check_import
 export PYTHONPATH=%{buildroot}%{python3_sitearch}
-export PYTHON_BIN=%{__python3}
+%{py3_test_envvars}
 make -C unit-tests
 
-
 %files -n python3-dmidecode -f %{pyproject_files}
 %license doc/LICENSE
 %doc README doc/AUTHORS doc/AUTHORS.upstream
 %{_datadir}/%{name}/
 
 %changelog
+* Thu Sep 17 2026 Antonio Trande <sagitter@fedoraproject.org> - 3.12.3-20
+- Patched for libxml2-2.15.4
+
 * Wed Jul 22 2026 Python Maint <python-maint@redhat.com> - 3.12.3-19
 - Rebuilt for Python 3.15.0b4 ABI change
 

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2026-09-17 19:03 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-17 19:03 [rpms/python-dmidecode] main: Patched for libxml2-2.15.4 Antonio Trande

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox