Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-cfgv for openSUSE:Factory 
checked in at 2026-02-17 16:47:21
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-cfgv (Old)
 and      /work/SRC/openSUSE:Factory/.python-cfgv.new.1977 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-cfgv"

Tue Feb 17 16:47:21 2026 rev:8 rq:1333397 version:3.5.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-cfgv/python-cfgv.changes  2023-09-20 
13:31:53.132440418 +0200
+++ /work/SRC/openSUSE:Factory/.python-cfgv.new.1977/python-cfgv.changes        
2026-02-17 16:48:10.993528884 +0100
@@ -1,0 +2,6 @@
+Mon Feb 16 16:49:53 UTC 2026 - Dirk Müller <[email protected]>
+
+- update to 3.5.0:
+  * CI updates and minor bugfixes
+
+-------------------------------------------------------------------

Old:
----
  cfgv-3.4.0.tar.gz

New:
----
  cfgv-3.5.0.tar.gz

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

Other differences:
------------------
++++++ python-cfgv.spec ++++++
--- /var/tmp/diff_new_pack.BQ1u9E/_old  2026-02-17 16:48:12.625597083 +0100
+++ /var/tmp/diff_new_pack.BQ1u9E/_new  2026-02-17 16:48:12.629597250 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package python-cfgv
 #
-# Copyright (c) 2023 SUSE LLC
+# Copyright (c) 2026 SUSE LLC and contributors
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -18,7 +18,7 @@
 
 %{?sle15_python_module_pythons}
 Name:           python-cfgv
-Version:        3.4.0
+Version:        3.5.0
 Release:        0
 Summary:        Configuration validator producing human readable error messages
 License:        MIT

++++++ cfgv-3.4.0.tar.gz -> cfgv-3.5.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cfgv-3.4.0/.github/workflows/main.yml 
new/cfgv-3.5.0/.github/workflows/main.yml
--- old/cfgv-3.4.0/.github/workflows/main.yml   2023-08-12 22:38:08.000000000 
+0200
+++ new/cfgv-3.5.0/.github/workflows/main.yml   2025-11-19 21:55:30.000000000 
+0100
@@ -8,6 +8,6 @@
 
 jobs:
   main:
-    uses: asottile/workflows/.github/workflows/[email protected]
+    uses: asottile/workflows/.github/workflows/[email protected]
     with:
-      env: '["py38", "py39", "py310", "py311"]'
+      env: '["py310", "py311", "py312", "py313"]'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cfgv-3.4.0/.pre-commit-config.yaml 
new/cfgv-3.5.0/.pre-commit-config.yaml
--- old/cfgv-3.4.0/.pre-commit-config.yaml      2023-08-12 22:38:08.000000000 
+0200
+++ new/cfgv-3.5.0/.pre-commit-config.yaml      2025-11-19 21:55:30.000000000 
+0100
@@ -1,6 +1,6 @@
 repos:
 -   repo: https://github.com/pre-commit/pre-commit-hooks
-    rev: v4.4.0
+    rev: v6.0.0
     hooks:
     -   id: trailing-whitespace
     -   id: end-of-file-fixer
@@ -10,28 +10,28 @@
     -   id: name-tests-test
     -   id: requirements-txt-fixer
 -   repo: https://github.com/asottile/setup-cfg-fmt
-    rev: v2.4.0
+    rev: v3.1.0
     hooks:
     -   id: setup-cfg-fmt
 -   repo: https://github.com/asottile/reorder-python-imports
-    rev: v3.10.0
+    rev: v3.16.0
     hooks:
     -   id: reorder-python-imports
-        args: [--py38-plus, --add-import, 'from __future__ import annotations']
+        args: [--py310-plus, --add-import, 'from __future__ import 
annotations']
 -   repo: https://github.com/asottile/add-trailing-comma
-    rev: v3.0.1
+    rev: v4.0.0
     hooks:
     -   id: add-trailing-comma
 -   repo: https://github.com/asottile/pyupgrade
-    rev: v3.10.1
+    rev: v3.21.1
     hooks:
     -   id: pyupgrade
-        args: [--py38-plus]
--   repo: https://github.com/pre-commit/mirrors-autopep8
-    rev: v2.0.2
+        args: [--py310-plus]
+-   repo: https://github.com/hhatto/autopep8
+    rev: v2.3.2
     hooks:
     -   id: autopep8
 -   repo: https://github.com/PyCQA/flake8
-    rev: 6.1.0
+    rev: 7.3.0
     hooks:
     -   id: flake8
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cfgv-3.4.0/README.md new/cfgv-3.5.0/README.md
--- old/cfgv-3.4.0/README.md    2023-08-12 22:38:08.000000000 +0200
+++ new/cfgv-3.5.0/README.md    2025-11-19 21:55:30.000000000 +0100
@@ -116,6 +116,15 @@
 
 When validated, this will check that each element adheres to the sub-schema.
 
+### `KeyValueMap(object_name, key_check_fn, value_schema)`
+
+Used to make a schema representing a homogenous mapping where the keys are
+of a specific type and the values match a schema
+
+- `object_name`: will be displayed in error messages
+- `key_check_fn`: a [check function](#check-functions) for the key
+- `value_schema`: a `Map` / `Array` or other sub-schema.
+
 ## Validator objects
 
 Validator objects are used to validate key-value-pairs of a `Map`.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cfgv-3.4.0/cfgv.py new/cfgv-3.5.0/cfgv.py
--- old/cfgv-3.4.0/cfgv.py      2023-08-12 22:38:08.000000000 +0200
+++ new/cfgv-3.5.0/cfgv.py      2025-11-19 21:55:30.000000000 +0100
@@ -258,6 +258,40 @@
         return ret
 
 
+class KeyValueMap(
+        collections.namedtuple(
+            'KeyValueMap',
+            ('object_name', 'check_key_fn', 'value_schema'),
+        ),
+):
+    __slots__ = ()
+
+    def check(self, v):
+        if not isinstance(v, dict):
+            raise ValidationError(
+                f'Expected a {self.object_name} map but got a '
+                f'{type(v).__name__}',
+            )
+        with validate_context(f'At {self.object_name}()'):
+            for k, val in v.items():
+                with validate_context(f'For key: {k}'):
+                    self.check_key_fn(k)
+                with validate_context(f'At key: {k}'):
+                    validate(val, self.value_schema)
+
+    def apply_defaults(self, v):
+        return {
+            k: apply_defaults(val, self.value_schema)
+            for k, val in v.items()
+        }
+
+    def remove_defaults(self, v):
+        return {
+            k: remove_defaults(val, self.value_schema)
+            for k, val in v.items()
+        }
+
+
 class Array(collections.namedtuple('Array', ('of', 'allow_empty'))):
     __slots__ = ()
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cfgv-3.4.0/setup.cfg new/cfgv-3.5.0/setup.cfg
--- old/cfgv-3.4.0/setup.cfg    2023-08-12 22:38:08.000000000 +0200
+++ new/cfgv-3.5.0/setup.cfg    2025-11-19 21:55:30.000000000 +0100
@@ -1,6 +1,6 @@
 [metadata]
 name = cfgv
-version = 3.4.0
+version = 3.5.0
 description = Validate configuration and produce human readable error messages.
 long_description = file: README.md
 long_description_content_type = text/markdown
@@ -10,7 +10,6 @@
 license = MIT
 license_files = LICENSE
 classifiers =
-    License :: OSI Approved :: MIT License
     Programming Language :: Python :: 3
     Programming Language :: Python :: 3 :: Only
     Programming Language :: Python :: Implementation :: CPython
@@ -18,7 +17,7 @@
 
 [options]
 py_modules = cfgv
-python_requires = >=3.8
+python_requires = >=3.10
 
 [bdist_wheel]
 universal = True
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cfgv-3.4.0/tests/cfgv_test.py 
new/cfgv-3.5.0/tests/cfgv_test.py
--- old/cfgv-3.4.0/tests/cfgv_test.py   2023-08-12 22:38:08.000000000 +0200
+++ new/cfgv-3.5.0/tests/cfgv_test.py   2025-11-19 21:55:30.000000000 +0100
@@ -11,13 +11,16 @@
 from cfgv import check_any
 from cfgv import check_array
 from cfgv import check_bool
+from cfgv import check_int
 from cfgv import check_one_of
 from cfgv import check_regex
+from cfgv import check_string
 from cfgv import check_type
 from cfgv import Conditional
 from cfgv import ConditionalOptional
 from cfgv import ConditionalRecurse
 from cfgv import In
+from cfgv import KeyValueMap
 from cfgv import load_from_filename
 from cfgv import Map
 from cfgv import MISSING
@@ -728,3 +731,79 @@
 def test_warn_additional_keys_when_no_extra_keys(warn_additional_keys):
     validate({True: True}, warn_additional_keys.schema)
     assert not warn_additional_keys.record.called
+
+
+key_value_map_schema = KeyValueMap(
+    'Container',
+    check_string,
+    Map(
+        'Object', 'name',
+        Required('name', check_string),
+        Optional('setting', check_bool, False),
+    ),
+)
+key_value_map_ints_schema = KeyValueMap(
+    'Container',
+    check_int,
+    Array(Map('Object', 'nane', Required('name', check_string))),
+)
+
+
+def test_key_value_map_schema_ok():
+    validate(
+        {'hello': {'name': 'hello'}, 'world': {'name': 'world'}},
+        key_value_map_schema,
+    )
+    validate(
+        {1: [{'name': 'hello'}], 2: [{'name': 'world'}]},
+        key_value_map_ints_schema,
+    )
+
+
+def test_key_value_map_apply_defaults():
+    orig = {'hello': {'name': 'hello'}}
+    ret = apply_defaults(orig, key_value_map_schema)
+    assert orig == {'hello': {'name': 'hello'}}
+    assert ret == {'hello': {'name': 'hello', 'setting': False}}
+
+
+def test_key_value_map_remove_defaults():
+    orig = {'hello': {'name': 'hello', 'setting': False}}
+    ret = remove_defaults(orig, key_value_map_schema)
+    assert orig == {'hello': {'name': 'hello', 'setting': False}}
+    assert ret == {'hello': {'name': 'hello'}}
+
+
+def test_key_value_map_not_a_map():
+    with pytest.raises(ValidationError) as excinfo:
+        validate([], key_value_map_schema)
+    expected = (
+        'Expected a Container map but got a list',
+    )
+    _assert_exception_trace(excinfo.value, expected)
+
+
+def test_key_value_map_wrong_key_type():
+    with pytest.raises(ValidationError) as excinfo:
+        val = {1: {'name': 'hello'}}
+        validate(val, key_value_map_schema)
+    expected = (
+        'At Container()',
+        'For key: 1',
+        'Expected string got int',
+    )
+    _assert_exception_trace(excinfo.value, expected)
+
+
+def test_key_value_map_error_in_child_schema():
+    with pytest.raises(ValidationError) as excinfo:
+        val = {'hello': {'name': 1}}
+        validate(val, key_value_map_schema)
+    expected = (
+        'At Container()',
+        'At key: hello',
+        'At Object(name=1)',
+        'At key: name',
+        'Expected string got int',
+    )
+    _assert_exception_trace(excinfo.value, expected)

Reply via email to