Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-hardware for openSUSE:Factory
checked in at 2026-10-26 10:01:00
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-hardware (Old)
and /work/SRC/openSUSE:Factory/.python-hardware.new.2252680 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-hardware"
Mon Oct 26 10:01:00 2026 rev:4 rq:1392465 version:0.33.0
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-hardware/python-hardware.changes
2026-04-28 11:59:54.474325357 +0200
+++
/work/SRC/openSUSE:Factory/.python-hardware.new.2252680/python-hardware.changes
2026-10-26 10:02:23.467724877 +0100
@@ -1,0 +2,19 @@
+Sun Oct 25 15:40:55 UTC 2026 - Dirk Müller <[email protected]>
+
+- update to 0.33.0:
+ * Fix PEP8 line length violations
+ * Modernize configuration file parsing
+ * Refactor get_cpus() function into single-responsibility
+ functions
+ * Update link of ipmitool project
+ * Simplify sphinx version requirement
+ * Remove options for babel
+ * Remove options for sphinx setuptools hook
+ * Bump lint packages
+ * Bump github actions
+ * Update supported python versions
+ * Add pyproject.toml to support pip version 23.1
+ * Run tests on ubuntu 24.04
+ * Remove Python 3.8 support
+
+-------------------------------------------------------------------
Old:
----
hardware-0.32.0.tar.gz
New:
----
hardware-0.33.0.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-hardware.spec ++++++
--- /var/tmp/diff_new_pack.Mtmsc7/_old 2026-10-26 10:02:24.434765431 +0100
+++ /var/tmp/diff_new_pack.Mtmsc7/_new 2026-10-26 10:02:24.439765641 +0100
@@ -24,7 +24,7 @@
%{?sle15_python_module_pythons}
Name: python-hardware
-Version: 0.32.0
+Version: 0.33.0
Release: 0
Summary: Hardware detection and classification utilities
License: Apache-2.0
++++++ hardware-0.32.0.tar.gz -> hardware-0.33.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hardware-0.32.0/.github/workflows/docs-testing.yml
new/hardware-0.33.0/.github/workflows/docs-testing.yml
--- old/hardware-0.32.0/.github/workflows/docs-testing.yml 2024-01-31
14:59:08.000000000 +0100
+++ new/hardware-0.33.0/.github/workflows/docs-testing.yml 2026-09-24
14:44:48.000000000 +0200
@@ -5,15 +5,15 @@
jobs:
build:
- runs-on: ubuntu-22.04
+ runs-on: ubuntu-24.04
strategy:
matrix:
- python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']
+ python-version: ['3.10', '3.11', '3.12', '3.13', '3.14']
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v7
- name: Set up Python ${{ matrix.python-version }}
- uses: actions/setup-python@v2
+ uses: actions/setup-python@v7
with:
python-version: ${{ matrix.python-version }}
- name: Install Tox
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hardware-0.32.0/.github/workflows/pep8-testing.yml
new/hardware-0.33.0/.github/workflows/pep8-testing.yml
--- old/hardware-0.32.0/.github/workflows/pep8-testing.yml 2024-01-31
14:59:08.000000000 +0100
+++ new/hardware-0.33.0/.github/workflows/pep8-testing.yml 2026-09-24
14:44:48.000000000 +0200
@@ -5,15 +5,15 @@
jobs:
build:
- runs-on: ubuntu-22.04
+ runs-on: ubuntu-24.04
strategy:
matrix:
- python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']
+ python-version: ['3.10', '3.11', '3.12', '3.13', '3.14']
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v7
- name: Set up Python ${{ matrix.python-version }}
- uses: actions/setup-python@v2
+ uses: actions/setup-python@v7
with:
python-version: ${{ matrix.python-version }}
- name: Install Tox
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hardware-0.32.0/.github/workflows/unit-testing.yml
new/hardware-0.33.0/.github/workflows/unit-testing.yml
--- old/hardware-0.32.0/.github/workflows/unit-testing.yml 2024-01-31
14:59:08.000000000 +0100
+++ new/hardware-0.33.0/.github/workflows/unit-testing.yml 2026-09-24
14:44:48.000000000 +0200
@@ -5,15 +5,15 @@
jobs:
build:
- runs-on: ubuntu-22.04
+ runs-on: ubuntu-24.04
strategy:
matrix:
- python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']
+ python-version: ['3.10', '3.11', '3.12', '3.13', '3.14']
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v7
- name: Set up Python ${{ matrix.python-version }}
- uses: actions/setup-python@v2
+ uses: actions/setup-python@v7
with:
python-version: ${{ matrix.python-version }}
- name: Install Tox
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hardware-0.32.0/AUTHORS new/hardware-0.33.0/AUTHORS
--- old/hardware-0.32.0/AUTHORS 2024-11-19 14:57:03.000000000 +0100
+++ new/hardware-0.33.0/AUTHORS 2026-09-24 15:03:41.000000000 +0200
@@ -1,5 +1,6 @@
Alfredo Moralejo <[email protected]>
Bob Fournier <[email protected]>
+Cursor <[email protected]>
Cédric Jeanneret <[email protected]>
Cédric LECOMTE <[email protected]>
Dmitry Tantsur <[email protected]>
@@ -30,6 +31,7 @@
Steven A. Broderick Elias <[email protected]>
Sylvain Baubeau <[email protected]>
Sylvain Baubeau <[email protected]>
+Takashi Kajinami <[email protected]>
Tony Breeds <[email protected]>
Uros Orozel <[email protected]>
Victor Stinner <[email protected]>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hardware-0.32.0/ChangeLog
new/hardware-0.33.0/ChangeLog
--- old/hardware-0.32.0/ChangeLog 2024-11-19 14:57:03.000000000 +0100
+++ new/hardware-0.33.0/ChangeLog 2026-09-24 15:03:41.000000000 +0200
@@ -1,6 +1,23 @@
CHANGES
=======
+0.33.0
+------
+
+* Fix PEP8 line length violations
+* Modernize configuration file parsing
+* Refactor get\_cpus() function into single-responsibility functions
+* Update link of ipmitool project
+* Simplify sphinx version requirement
+* Remove options for babel
+* Remove options for sphinx setuptools hook
+* Bump lint packages
+* Bump github actions
+* Update supported python versions
+* Add pyproject.toml to support pip version 23.1
+* Run tests on ubuntu 24.04
+* Remove Python 3.8 support
+
0.32.0
------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hardware-0.32.0/PKG-INFO new/hardware-0.33.0/PKG-INFO
--- old/hardware-0.32.0/PKG-INFO 2024-11-19 14:57:03.820579000 +0100
+++ new/hardware-0.33.0/PKG-INFO 2026-09-24 15:03:42.301639000 +0200
@@ -1,6 +1,6 @@
-Metadata-Version: 2.1
+Metadata-Version: 2.4
Name: hardware
-Version: 0.32.0
+Version: 0.33.0
Summary: Hardware detection and classification utilities
Home-page: https://github.com/redhat-cip/hardware
Author: eNovance
@@ -13,16 +13,25 @@
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
-Classifier: Programming Language :: Python :: 3.8
-Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
-Requires-Python: >=3.8
+Classifier: Programming Language :: Python :: 3.13
+Classifier: Programming Language :: Python :: 3.14
+Requires-Python: >=3.10
License-File: LICENSE
License-File: AUTHORS
Requires-Dist: pbr>=3.1.1
Requires-Dist: pexpect
+Dynamic: author
+Dynamic: author-email
+Dynamic: classifier
+Dynamic: description
+Dynamic: home-page
+Dynamic: license-file
+Dynamic: requires-dist
+Dynamic: requires-python
+Dynamic: summary
===============================
hardware
@@ -94,7 +103,7 @@
System
======
-* ipmitool from https://sourceforge.net/projects/ipmitool/
+* ipmitool from https://codeberg.org/IPMITool/ipmitool
* pciutils
* lshw from http://www.ezix.org/project/wiki/HardwareLiSter
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hardware-0.32.0/README.rst
new/hardware-0.33.0/README.rst
--- old/hardware-0.32.0/README.rst 2022-12-14 12:38:12.000000000 +0100
+++ new/hardware-0.33.0/README.rst 2026-09-24 14:44:48.000000000 +0200
@@ -68,7 +68,7 @@
System
======
-* ipmitool from https://sourceforge.net/projects/ipmitool/
+* ipmitool from https://codeberg.org/IPMITool/ipmitool
* pciutils
* lshw from http://www.ezix.org/project/wiki/HardwareLiSter
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hardware-0.32.0/babel.cfg
new/hardware-0.33.0/babel.cfg
--- old/hardware-0.32.0/babel.cfg 2022-12-14 12:38:12.000000000 +0100
+++ new/hardware-0.33.0/babel.cfg 1970-01-01 01:00:00.000000000 +0100
@@ -1,2 +0,0 @@
-[python: **.py]
-
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hardware-0.32.0/doc/requirements.txt
new/hardware-0.33.0/doc/requirements.txt
--- old/hardware-0.32.0/doc/requirements.txt 2022-12-14 12:38:12.000000000
+0100
+++ new/hardware-0.33.0/doc/requirements.txt 2026-09-24 14:44:48.000000000
+0200
@@ -1 +1 @@
-sphinx!=1.6.6,!=1.6.7,!=2.1.0,>=1.6.2;python_version>='3.4' # BSD
\ No newline at end of file
+sphinx>=2.0.0 # BSD
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hardware-0.32.0/hardware/cmdb.py
new/hardware-0.33.0/hardware/cmdb.py
--- old/hardware-0.32.0/hardware/cmdb.py 2022-12-14 12:38:12.000000000
+0100
+++ new/hardware-0.33.0/hardware/cmdb.py 2026-09-24 14:45:16.000000000
+0200
@@ -12,6 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+import ast
import errno
import logging
import os
@@ -36,12 +37,17 @@
'Load the cmdb.'
filename = cmdb_filename(cfg_dir, name)
try:
- return eval(open(filename).read(-1))
+ with open(filename, 'r') as cmdb_file:
+ content = cmdb_file.read()
+ return ast.literal_eval(content)
except IOError as xcpt:
if xcpt.errno != errno.ENOENT:
LOG.error("exception while processing CMDB (%s) %s" % (filename,
str(xcpt)))
return None
+ except (ValueError, SyntaxError) as e:
+ LOG.error('Invalid CMDB file format %s: %s', filename, e)
+ return None
def save_cmdb(cfg_dir, name, cmdb):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hardware-0.32.0/hardware/detect_utils.py
new/hardware-0.33.0/hardware/detect_utils.py
--- old/hardware-0.32.0/hardware/detect_utils.py 2022-12-14
12:38:12.000000000 +0100
+++ new/hardware-0.33.0/hardware/detect_utils.py 2026-09-24
14:44:48.000000000 +0200
@@ -270,36 +270,43 @@
break
-def get_cpus(hw_lst):
- def _maybe_int(v):
- try:
- base = 10
- if 'x' in v:
- base = 16
- v = int(v, base)
- except Exception:
- pass
- return v
+def _maybe_int(v):
+ """Convert value to int with hex support, return original if fails."""
+ try:
+ base = 10
+ if 'x' in v:
+ base = 16
+ v = int(v, base)
+ except Exception:
+ pass
+ return v
+
+
+def _get_governor(lcpu):
+ """Return the scaling governor of a logical core.
- def _get_governor(lcpu):
- """Return the scaling governor of a logical core.
+ :param lcpu: the logical core number
+ :returns: the scaling governor if it exists, otherwise None
+ """
+ with contextlib.suppress(IOError):
+ file_name = ("/sys/devices/system/cpu/cpufreq/"
+ "policy{}/scaling_governor".format(lcpu))
+ return from_file(file_name)
+
+ # fallback to the old interface available in kernels < 4.3;
+ with contextlib.suppress(IOError):
+ file_name = ("/sys/devices/system/cpu/cpu{}/cpufreq/"
+ "scaling_governor".format(lcpu))
+ return from_file(file_name)
+ return None
- :param lcpu: the logical core number
- :returns: the scaling governor if it exists, otherwise None
- """
- with contextlib.suppress(IOError):
- file_name = ("/sys/devices/system/cpu/cpufreq/"
- "policy{}/scaling_governor".format(lcpu))
- return from_file(file_name)
-
- # fallback to the old interface available in kernels < 4.3;
- with contextlib.suppress(IOError):
- file_name = ("/sys/devices/system/cpu/cpu{}/cpufreq/"
- "scaling_governor".format(lcpu))
- return from_file(file_name)
- return None
- # Extracting lspcu information
+def _parse_lscpu_output():
+ """Parse lscpu command output into dictionaries.
+
+ :returns: tuple of (lscpu_dict, lscpux_dict) containing parsed output
+ """
+ # Parse basic lscpu information
lscpu = {}
output = output_lines('LANG=en_US.UTF-8 lscpu')
@@ -308,8 +315,7 @@
item, value = line.split(':', 1)
lscpu[item.strip(':')] = value.strip()
- # Extracting lspcu -x information
- # Use hexadecimal masks for CPU sets
+ # Parse extended lscpu -x information with hexadecimal masks
lscpux = {}
output = output_lines('LANG=en_US.UTF-8 lscpu -x')
@@ -318,14 +324,27 @@
item, value = line.split(':', 1)
lscpux[item.strip(':')] = value.strip()
+ return lscpu, lscpux
+
+
+def _detect_physical_cpus(hw_lst, lscpu):
+ """Detect and append physical CPU information.
+
+ :param hw_lst: hardware list to append CPU info to
+ :param lscpu: parsed lscpu output dictionary
+ """
hw_lst.append(("cpu", "physical", "number", int(lscpu["Socket(s)"])))
+ # SMT (Simultaneous Multi-Threading) control
with contextlib.suppress(IOError):
value = from_file("/sys/devices/system/cpu/smt/control")
hw_lst.append(("cpu", "physical", "smt", value))
+ # Process each physical processor socket
for processor in range(int(lscpu["Socket(s)"])):
ptag = "physical_{}".format(processor)
+
+ # CPU boost setting
try:
value = from_file("/sys/devices/system/cpu/cpufreq/boost")
except IOError:
@@ -334,37 +353,51 @@
value = 'enabled' if value == '1' else 'disabled'
hw_lst.append(('cpu', ptag, 'boost', value))
- for (t_key, d_key, conv) in [('vendor', 'Vendor ID', None),
- ('product', 'Model name', None),
- ('cores', 'Core(s) per socket', int),
- ('threads', None, None),
- ('family', 'CPU family', int),
- ('model', 'Model', _maybe_int),
- ('stepping', 'Stepping', _maybe_int),
- ('architecture', 'Architecture', None),
- ('l1d cache', 'L1d cache', None),
- ('l1i cache', 'L1i cache', None),
- ('l2 cache', 'L2 cache', None),
- ('l3 cache', 'L3 cache', None),
- ('min_Mhz', 'CPU min MHz', float),
- ('max_Mhz', 'CPU max MHz', float),
- ('current_Mhz', 'CPU MHz', float),
- ('flags', 'Flags', None),
- ('threads_per_core', 'Thread(s) per core',
- int)]:
+ # CPU properties mapping: (hw_key, lscpu_key, converter_func)
+ cpu_properties = [
+ ('vendor', 'Vendor ID', None),
+ ('product', 'Model name', None),
+ ('cores', 'Core(s) per socket', int),
+ ('threads', None, None), # Special case: calculated below
+ ('family', 'CPU family', int),
+ ('model', 'Model', _maybe_int),
+ ('stepping', 'Stepping', _maybe_int),
+ ('architecture', 'Architecture', None),
+ ('l1d cache', 'L1d cache', None),
+ ('l1i cache', 'L1i cache', None),
+ ('l2 cache', 'L2 cache', None),
+ ('l3 cache', 'L3 cache', None),
+ ('min_Mhz', 'CPU min MHz', float),
+ ('max_Mhz', 'CPU max MHz', float),
+ ('current_Mhz', 'CPU MHz', float),
+ ('flags', 'Flags', None),
+ ('threads_per_core', 'Thread(s) per core', int)
+ ]
+
+ for (t_key, d_key, conv) in cpu_properties:
value = None
- if d_key in lscpu:
+ if d_key and d_key in lscpu:
value = lscpu[d_key]
if conv:
value = conv(value)
elif t_key == 'threads':
+ # Calculate total threads per socket
value = (int(lscpu.get('Thread(s) per core', 1))
* int(lscpu.get('Core(s) per socket', 1)))
+
if value is not None:
hw_lst.append(('cpu', ptag, t_key, value))
+
+def _detect_logical_cpus(hw_lst, lscpu):
+ """Detect and append logical CPU information including governors.
+
+ :param hw_lst: hardware list to append CPU info to
+ :param lscpu: parsed lscpu output dictionary
+ """
hw_lst.append(('cpu', 'logical', 'number', int(lscpu['CPU(s)'])))
- # Governors could be different on logical cpus
+
+ # Check governor for each logical CPU (can be different per CPU)
for cpu in range(int(lscpu['CPU(s)'])):
ltag = "logical_{}".format(cpu)
@@ -372,49 +405,68 @@
if governor is not None:
hw_lst.append(('cpu', ltag, "governor", governor))
- # Extracting numa nodes
+
+def _detect_numa_nodes(hw_lst, lscpu, lscpux):
+ """Detect and append NUMA node information.
+
+ :param hw_lst: hardware list to append NUMA info to
+ :param lscpu: parsed lscpu output dictionary
+ :param lscpux: parsed lscpu -x output dictionary
+ """
+ # Overall NUMA node count
try:
hw_lst.append(('numa', 'nodes', 'count', int(lscpu['NUMA node(s)'])))
except KeyError:
pass
- # Allow for sparse numa nodes.
+ # Process individual NUMA nodes (handle sparse node numbering)
numa_nodes = []
for key in lscpux:
match = re.match(r"NUMA node(\d+) CPU\(s\)", key)
if match:
numa_nodes.append((key, int(match.groups()[0])))
- # NOTE(tonyb): Explicitly sort the list as prior to python 3.7? keys() did
- # not have a predictable ordering and there maybe consumers of hw_lst rely
- # on that.
+
+ # Sort nodes by ID for consistent ordering (ensures reproducible output)
numa_nodes.sort(key=lambda t: t[1])
+
for (key, node_id) in numa_nodes:
ntag = 'node_{}'.format(node_id)
cpus = lscpu[key]
- # lscpu -x provides the cpu mask
- cpu_mask = lscpux[key]
+ cpu_mask = lscpux[key] # Hexadecimal CPU mask from lscpu -x
total_cpus = 0
- min_cpu = None
- max_cpu = None
- # It's possible to have a NUMA node without any CPUs
+ # Parse CPU range/list (e.g., "0-5,48-53" or "0,1,2")
if cpus:
for item in cpus.split(','):
- # lscpu report numa nodes like 0-5,48-53
if "-" in item:
- max_cpu = int(item.split("-")[1])
- min_cpu = int(item.split("-")[0])
- total_cpus = total_cpus + max_cpu - min_cpu + 1
+ # Handle ranges like "0-5"
+ start, end = item.split("-")
+ total_cpus += int(end) - int(start) + 1
else:
- # or like 0,1
- # As we don't have dashes, there is only one core to count
- total_cpus = total_cpus + 1
+ # Handle individual CPUs like "0"
+ total_cpus += 1
- # total_cpus = 12 for "0-5,48-53"
hw_lst.append(('numa', ntag, 'cpu_count', total_cpus))
hw_lst.append(('numa', ntag, 'cpu_mask', cpu_mask))
+def get_cpus(hw_lst):
+ """Detect and append CPU and NUMA information to hardware list.
+
+ This function orchestrates CPU detection by calling focused sub-functions
+ for different aspects of CPU hardware detection.
+
+ :param hw_lst: list to append hardware tuples to
+ """
+ # Parse lscpu output once and reuse for all detection functions
+ lscpu, lscpux = _parse_lscpu_output()
+
+ # Detect different aspects of CPU hardware
+ _detect_physical_cpus(hw_lst, lscpu)
+ _detect_logical_cpus(hw_lst, lscpu)
+ _detect_numa_nodes(hw_lst, lscpu, lscpux)
+
+
def modprobe(module):
"""Load a kernel module using modprobe."""
status, _ = cmd('modprobe %s' % module)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hardware-0.32.0/hardware/state.py
new/hardware-0.33.0/hardware/state.py
--- old/hardware-0.32.0/hardware/state.py 2022-12-14 12:38:12.000000000
+0100
+++ new/hardware-0.33.0/hardware/state.py 2026-09-24 14:53:49.000000000
+0200
@@ -23,6 +23,7 @@
profile and matches only 3 times then try hw2 any number of times.
'''
+import ast
import errno
import logging
import os
@@ -57,7 +58,20 @@
self._validate_lockname()
self.lock()
LOG.info('Reading state from %s' % self._state_filename)
- self._data = eval(open(self._state_filename).read(-1))
+ try:
+ with open(self._state_filename, 'r') as state_file:
+ content = state_file.read()
+ self._data = ast.literal_eval(content)
+ except (OSError, IOError) as e:
+ LOG.error('Failed to read state file %s: %s',
+ self._state_filename, e)
+ raise StateError('Cannot read state file %s: %s' %
+ (self._state_filename, e))
+ except (ValueError, SyntaxError) as e:
+ LOG.error('Invalid state file format %s: %s',
+ self._state_filename, e)
+ raise StateError('Invalid state file format %s: %s' %
+ (self._state_filename, e))
def failed_profile(self, prof):
'''If we get a failure report, let's reincrement the counter
@@ -95,7 +109,16 @@
if self._cfg_dir:
fname = os.path.join(self._cfg_dir, name + '.specs')
if os.path.exists(fname):
- return eval(open(fname, 'r').read(-1))
+ try:
+ with open(fname, 'r') as specs_file:
+ content = specs_file.read()
+ return ast.literal_eval(content)
+ except (OSError, IOError) as e:
+ LOG.error('Failed to read specs file %s: %s', fname, e)
+ return _INVALID_SPECS
+ except (ValueError, SyntaxError) as e:
+ LOG.error('Invalid specs file format %s: %s', fname, e)
+ return _INVALID_SPECS
LOG.info('Specs file %s not found' % fname)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hardware-0.32.0/hardware/tests/test_cmdb.py
new/hardware-0.33.0/hardware/tests/test_cmdb.py
--- old/hardware-0.32.0/hardware/tests/test_cmdb.py 2022-12-14
12:38:12.000000000 +0100
+++ new/hardware-0.33.0/hardware/tests/test_cmdb.py 2026-09-24
14:53:49.000000000 +0200
@@ -12,6 +12,9 @@
# License for the specific language governing permissions and limitations
# under the License.
+import os
+import shutil
+import tempfile
import unittest
from hardware import cmdb
@@ -57,6 +60,61 @@
self.assertRaises(cmdb.CmdbError, cmdb.update_cmdb,
data, var, var, True)
+ def test_load_cmdb_valid_file(self):
+ """Test loading a valid CMDB file with safe parsing."""
+ tmpdir = tempfile.mkdtemp()
+ try:
+ # Create a valid CMDB file
+ valid_data = [{'hostname': 'test1', 'mac': 'aa:bb:cc'},
+ {'hostname': 'test2', 'used': 1}]
+ cmdb_file = os.path.join(tmpdir, 'test.cmdb')
+ with open(cmdb_file, 'w') as f:
+ import pprint
+ pprint.pprint(valid_data, stream=f)
+
+ result = cmdb.load_cmdb(tmpdir, 'test')
+ self.assertEqual(result, valid_data)
+ finally:
+ shutil.rmtree(tmpdir)
+
+ def test_load_cmdb_invalid_file_syntax(self):
+ """Test that invalid Python syntax in CMDB file returns None."""
+ tmpdir = tempfile.mkdtemp()
+ try:
+ cmdb_file = os.path.join(tmpdir, 'test.cmdb')
+ # Create an invalid CMDB file with syntax errors
+ with open(cmdb_file, 'w') as f:
+ f.write('[{"hostname": "test1", "mac":}]') # Missing value
+
+ result = cmdb.load_cmdb(tmpdir, 'test')
+ self.assertIsNone(result)
+ finally:
+ shutil.rmtree(tmpdir)
+
+ def test_load_cmdb_malicious_file(self):
+ """Test that malicious code in CMDB file cannot be executed."""
+ tmpdir = tempfile.mkdtemp()
+ try:
+ cmdb_file = os.path.join(tmpdir, 'test.cmdb')
+ # Create a CMDB file with malicious code
+ malicious_code = '__import__("os").system("echo CMDB_BREACH")'
+ with open(cmdb_file, 'w') as f:
+ # Write malicious data that would be executed with eval()
+ exploit_entry = (f'{{"hostname": "test1", '
+ f'"exploit": {malicious_code}}}')
+ f.write(f'[{exploit_entry}]')
+
+ result = cmdb.load_cmdb(tmpdir, 'test')
+ # Should return None instead of executing malicious code
+ self.assertIsNone(result)
+ finally:
+ shutil.rmtree(tmpdir)
+
+ def test_load_cmdb_nonexistent_file(self):
+ """Test loading nonexistent CMDB file returns None."""
+ result = cmdb.load_cmdb('/nonexistent/directory', 'test')
+ self.assertIsNone(result)
+
if __name__ == "__main__":
unittest.main()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hardware-0.32.0/hardware.egg-info/PKG-INFO
new/hardware-0.33.0/hardware.egg-info/PKG-INFO
--- old/hardware-0.32.0/hardware.egg-info/PKG-INFO 2024-11-19
14:57:03.000000000 +0100
+++ new/hardware-0.33.0/hardware.egg-info/PKG-INFO 2026-09-24
15:03:41.000000000 +0200
@@ -1,6 +1,6 @@
-Metadata-Version: 2.1
+Metadata-Version: 2.4
Name: hardware
-Version: 0.32.0
+Version: 0.33.0
Summary: Hardware detection and classification utilities
Home-page: https://github.com/redhat-cip/hardware
Author: eNovance
@@ -13,16 +13,25 @@
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
-Classifier: Programming Language :: Python :: 3.8
-Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
-Requires-Python: >=3.8
+Classifier: Programming Language :: Python :: 3.13
+Classifier: Programming Language :: Python :: 3.14
+Requires-Python: >=3.10
License-File: LICENSE
License-File: AUTHORS
Requires-Dist: pbr>=3.1.1
Requires-Dist: pexpect
+Dynamic: author
+Dynamic: author-email
+Dynamic: classifier
+Dynamic: description
+Dynamic: home-page
+Dynamic: license-file
+Dynamic: requires-dist
+Dynamic: requires-python
+Dynamic: summary
===============================
hardware
@@ -94,7 +103,7 @@
System
======
-* ipmitool from https://sourceforge.net/projects/ipmitool/
+* ipmitool from https://codeberg.org/IPMITool/ipmitool
* pciutils
* lshw from http://www.ezix.org/project/wiki/HardwareLiSter
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hardware-0.32.0/hardware.egg-info/SOURCES.txt
new/hardware-0.33.0/hardware.egg-info/SOURCES.txt
--- old/hardware-0.32.0/hardware.egg-info/SOURCES.txt 2024-11-19
14:57:03.000000000 +0100
+++ new/hardware-0.33.0/hardware.egg-info/SOURCES.txt 2026-09-24
15:03:42.000000000 +0200
@@ -8,7 +8,7 @@
LICENSE
MANIFEST.in
README.rst
-babel.cfg
+pyproject.toml
requirements.txt
setup.cfg
setup.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hardware-0.32.0/hardware.egg-info/pbr.json
new/hardware-0.33.0/hardware.egg-info/pbr.json
--- old/hardware-0.32.0/hardware.egg-info/pbr.json 2024-11-19
14:57:03.000000000 +0100
+++ new/hardware-0.33.0/hardware.egg-info/pbr.json 2026-09-24
15:03:41.000000000 +0200
@@ -1 +1 @@
-{"git_version": "93c555b8", "is_release": false}
\ No newline at end of file
+{"git_version": "2270d2d0", "is_release": false}
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hardware-0.32.0/pyproject.toml
new/hardware-0.33.0/pyproject.toml
--- old/hardware-0.32.0/pyproject.toml 1970-01-01 01:00:00.000000000 +0100
+++ new/hardware-0.33.0/pyproject.toml 2026-09-24 14:44:48.000000000 +0200
@@ -0,0 +1,4 @@
+[build-system]
+requires = ["pbr>=6.0.0", "setuptools>=64.0.0"]
+build-backend = "pbr.build"
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hardware-0.32.0/setup.cfg
new/hardware-0.33.0/setup.cfg
--- old/hardware-0.32.0/setup.cfg 2024-11-19 14:57:03.821579200 +0100
+++ new/hardware-0.33.0/setup.cfg 2026-09-24 15:03:42.303144700 +0200
@@ -6,7 +6,7 @@
author = eNovance
author_email = [email protected]
home_page = https://github.com/redhat-cip/hardware
-python_requires = >=3.8
+python_requires = >=3.10
classifier =
Topic :: System :: Hardware
Intended Audience :: Information Technology
@@ -16,38 +16,16 @@
Programming Language :: Python
Programming Language :: Python :: 3
Programming Language :: Python :: 3 :: Only
- Programming Language :: Python :: 3.8
- Programming Language :: Python :: 3.9
Programming Language :: Python :: 3.10
Programming Language :: Python :: 3.11
Programming Language :: Python :: 3.12
+ Programming Language :: Python :: 3.13
+ Programming Language :: Python :: 3.14
[files]
packages =
hardware
-[build_sphinx]
-source-dir = doc/source
-build-dir = doc/build
-all_files = 1
-
-[upload_sphinx]
-upload-dir = doc/build/html
-
-[compile_catalog]
-directory = hardware/locale
-domain = hardware
-
-[update_catalog]
-domain = hardware
-output_dir = hardware/locale
-input_file = hardware/locale/hardware.pot
-
-[extract_messages]
-keywords = _ gettext ngettext l_ lazy_gettext
-mapping_file = babel.cfg
-output_file = hardware/locale/hardware.pot
-
[entry_points]
console_scripts =
hardware-detect = hardware.detect:main
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hardware-0.32.0/tox.ini new/hardware-0.33.0/tox.ini
--- old/hardware-0.32.0/tox.ini 2024-06-20 10:23:00.000000000 +0200
+++ new/hardware-0.33.0/tox.ini 2026-09-24 14:44:48.000000000 +0200
@@ -1,6 +1,6 @@
[tox]
minversion = 4.4.0
-envlist = py38,py39,py310,py311,py312,pep8,cover,docs
+envlist = py310,py311,py312,py313,py314,pep8,cover,docs
skipsdist = True
ignore_basepython_conflict=true
@@ -22,8 +22,8 @@
[testenv:pep8]
deps=
- hacking~=6.1.0 # Apache-2.0
- flake8-import-order~=0.18.0 # LGPLv3
+ hacking~=8.1.0 # Apache-2.0
+ flake8-import-order~=0.19.0 # LGPLv3
pycodestyle>=2.0.0 # MIT
commands = flake8 {posargs}
@@ -36,7 +36,7 @@
[testenv:cover]
deps=
{[testenv]deps}
- coverage!=4.4,>=4.0 # Apache-2.0
+ coverage>=4.4 # Apache-2.0
setenv =
VIRTUAL_ENV={envdir}
PYTHON=coverage run --source hardware --omit='*tests*' --parallel-mode