Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-deepmerge for 
openSUSE:Factory checked in at 2026-08-01 18:34:10
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-deepmerge (Old)
 and      /work/SRC/openSUSE:Factory/.python-deepmerge.new.16738 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-deepmerge"

Sat Aug  1 18:34:10 2026 rev:5 rq:1368878 version:2.1.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-deepmerge/python-deepmerge.changes        
2024-09-30 15:38:50.825138000 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-deepmerge.new.16738/python-deepmerge.changes 
    2026-08-01 18:37:20.940393528 +0200
@@ -1,0 +2,8 @@
+Fri Jul 31 16:48:14 UTC 2026 - Dirk Müller <[email protected]>
+
+- update to 2.1.0:
+  * minor: add __all__ to strategy __init__
+  * fix: compare by equality, not just hash, in ExtendedSet
+  * docs: functools.reduce usage
+
+-------------------------------------------------------------------

Old:
----
  deepmerge-2.0.tar.gz

New:
----
  deepmerge-2.1.0.tar.gz

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

Other differences:
------------------
++++++ python-deepmerge.spec ++++++
--- /var/tmp/diff_new_pack.awzadR/_old  2026-08-01 18:37:21.740421055 +0200
+++ /var/tmp/diff_new_pack.awzadR/_new  2026-08-01 18:37:21.744421192 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package python-deepmerge
 #
-# Copyright (c) 2024 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-deepmerge
-Version:        2.0
+Version:        2.1.0
 Release:        0
 License:        MIT
 Summary:        A toolset to deeply merge python dictionaries

++++++ deepmerge-2.0.tar.gz -> deepmerge-2.1.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/deepmerge-2.0/Makefile new/deepmerge-2.1.0/Makefile
--- old/deepmerge-2.0/Makefile  2024-08-30 07:31:21.000000000 +0200
+++ new/deepmerge-2.1.0/Makefile        2026-06-22 07:45:38.000000000 +0200
@@ -9,6 +9,9 @@
        rm -rf ./dist/
        .venv/bin/python -m build
 
+format: .venv/deps
+       .venv/bin/black deepmerge
+
 # only works with python 3+
 lint: .venv/deps
        .venv/bin/validate-pyproject pyproject.toml
@@ -18,4 +21,15 @@
 test: .venv/deps
        .venv/bin/pytest deepmerge
 
+docs: .venv/deps
+       $(MAKE) -C docs html
+
+docs-serve: docs
+       .venv/bin/python -m http.server --directory docs/_build/html
+
 ready-pr: test lint
+
+clean:
+       rm -rf .venv
+       rm -rf build
+       
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/deepmerge-2.0/PKG-INFO new/deepmerge-2.1.0/PKG-INFO
--- old/deepmerge-2.0/PKG-INFO  2024-08-30 07:31:39.765339400 +0200
+++ new/deepmerge-2.1.0/PKG-INFO        2026-06-22 07:45:57.335164500 +0200
@@ -1,6 +1,6 @@
-Metadata-Version: 2.1
+Metadata-Version: 2.4
 Name: deepmerge
-Version: 2.0
+Version: 2.1.0
 Summary: A toolset for deeply merging Python dictionaries.
 Author-email: Yusuke Tsutsumi <[email protected]>
 License: MIT Licence
@@ -28,6 +28,9 @@
 Requires-Dist: pytest; extra == "dev"
 Requires-Dist: build; extra == "dev"
 Requires-Dist: twine; extra == "dev"
+Requires-Dist: sphinx; extra == "dev"
+Requires-Dist: sphinx-rtd-theme; extra == "dev"
+Dynamic: license-file
 
 =========
 deepmerge
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/deepmerge-2.0/deepmerge/_version.py 
new/deepmerge-2.1.0/deepmerge/_version.py
--- old/deepmerge-2.0/deepmerge/_version.py     2024-08-30 07:31:39.000000000 
+0200
+++ new/deepmerge-2.1.0/deepmerge/_version.py   2026-06-22 07:45:57.000000000 
+0200
@@ -1,16 +1,24 @@
-# file generated by setuptools_scm
+# file generated by vcs-versioning
 # don't change, don't track in version control
-TYPE_CHECKING = False
-if TYPE_CHECKING:
-    from typing import Tuple, Union
-    VERSION_TUPLE = Tuple[Union[int, str], ...]
-else:
-    VERSION_TUPLE = object
+from __future__ import annotations
+
+__all__ = [
+    "__version__",
+    "__version_tuple__",
+    "version",
+    "version_tuple",
+    "__commit_id__",
+    "commit_id",
+]
 
 version: str
 __version__: str
-__version_tuple__: VERSION_TUPLE
-version_tuple: VERSION_TUPLE
+__version_tuple__: tuple[int | str, ...]
+version_tuple: tuple[int | str, ...]
+commit_id: str | None
+__commit_id__: str | None
+
+__version__ = version = '2.1.0'
+__version_tuple__ = version_tuple = (2, 1, 0)
 
-__version__ = version = '2.0'
-__version_tuple__ = version_tuple = (2, 0)
+__commit_id__ = commit_id = 'gf4822dec8'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/deepmerge-2.0/deepmerge/extended_set.py 
new/deepmerge-2.1.0/deepmerge/extended_set.py
--- old/deepmerge-2.0/deepmerge/extended_set.py 2024-08-30 07:31:21.000000000 
+0200
+++ new/deepmerge-2.1.0/deepmerge/extended_set.py       2026-06-22 
07:45:38.000000000 +0200
@@ -1,4 +1,4 @@
-from typing import Sequence, Any
+from typing import Sequence, Any, Dict, List
 
 
 class ExtendedSet(set):
@@ -13,10 +13,18 @@
     """
 
     def __init__(self, elements: Sequence) -> None:
-        self._values_by_hash = {self._hash_element(e): e for e in elements}
+        # Elements are grouped into buckets keyed by their (possibly lossy)
+        # hash. Membership and insertion compare a candidate against the
+        # members of the matching bucket using equality, so two distinct
+        # elements that merely collide on the hash are not treated as equal.
+        self._buckets: Dict[int, List[Any]] = {}
+        for element in elements:
+            self._insert(element)
 
     def _insert(self, element: Any) -> None:
-        self._values_by_hash[self._hash_element(element)] = element
+        bucket = self._buckets.setdefault(self._hash_element(element), [])
+        if not any(element == existing for existing in bucket):
+            bucket.append(element)
         return
 
     def _hash_element(self, element: Any) -> int:
@@ -29,4 +37,7 @@
             return hash(str(element))
 
     def __contains__(self, obj: Any) -> bool:
-        return self._hash_element(obj) in self._values_by_hash
+        bucket = self._buckets.get(self._hash_element(obj))
+        if bucket is None:
+            return False
+        return any(obj == existing for existing in bucket)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/deepmerge-2.0/deepmerge/strategy/__init__.py 
new/deepmerge-2.1.0/deepmerge/strategy/__init__.py
--- old/deepmerge-2.0/deepmerge/strategy/__init__.py    2024-08-30 
07:31:21.000000000 +0200
+++ new/deepmerge-2.1.0/deepmerge/strategy/__init__.py  2026-06-22 
07:45:38.000000000 +0200
@@ -4,3 +4,14 @@
 from .list import ListStrategies
 from .set import SetStrategies
 from .type_conflict import TypeConflictStrategies
+
+__all__ = [
+    "StrategyList",
+    "StrategyCallable",
+    "StrategyListInitable",
+    "DictStrategies",
+    "FallbackStrategies",
+    "ListStrategies",
+    "SetStrategies",
+    "TypeConflictStrategies",
+]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/deepmerge-2.0/deepmerge/strategy/fallback.py 
new/deepmerge-2.1.0/deepmerge/strategy/fallback.py
--- old/deepmerge-2.0/deepmerge/strategy/fallback.py    2024-08-30 
07:31:21.000000000 +0200
+++ new/deepmerge-2.1.0/deepmerge/strategy/fallback.py  2026-06-22 
07:45:38.000000000 +0200
@@ -5,7 +5,6 @@
 import deepmerge.merger
 from .core import StrategyList
 
-
 T = TypeVar("T")
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/deepmerge-2.0/deepmerge/tests/strategy/test_list.py 
new/deepmerge-2.1.0/deepmerge/tests/strategy/test_list.py
--- old/deepmerge-2.0/deepmerge/tests/strategy/test_list.py     2024-08-30 
07:31:21.000000000 +0200
+++ new/deepmerge-2.1.0/deepmerge/tests/strategy/test_list.py   2026-06-22 
07:45:38.000000000 +0200
@@ -43,3 +43,23 @@
     result = custom_merger.merge(base, nxt)
 
     assert result == [{"bar": "bob", "foo": "baz"}, {"x": "y"}]
+
+
+def test_strategy_append_unique_keeps_hash_colliding_dicts(custom_merger):
+    """append_unique must keep distinct dicts even when their lossy
+    "key:value" hash collides (e.g. ``{"a": "1", "b": "2"}`` and
+    ``{"a": "1,b:2"}`` both hash to ``"a:1,b:2"``), and must not treat an
+    ``int`` value as equal to its ``str`` form.
+    """
+    assert custom_merger.merge([{"a": "1", "b": "2"}], [{"a": "1,b:2"}]) == [
+        {"a": "1", "b": "2"},
+        {"a": "1,b:2"},
+    ]
+    assert custom_merger.merge([{"k": 1}], [{"k": "1"}]) == [{"k": 1}, {"k": 
"1"}]
+
+
+def test_strategy_append_unique_hashable_hash_collision(custom_merger):
+    """A hashable element must not be considered present just because a
+    different element shares its hash (e.g. ``hash(-1) == hash(-2)``).
+    """
+    assert custom_merger.merge([-1], [-2]) == [-1, -2]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/deepmerge-2.0/deepmerge/tests/test_full.py 
new/deepmerge-2.1.0/deepmerge/tests/test_full.py
--- old/deepmerge-2.0/deepmerge/tests/test_full.py      2024-08-30 
07:31:21.000000000 +0200
+++ new/deepmerge-2.1.0/deepmerge/tests/test_full.py    2026-06-22 
07:45:38.000000000 +0200
@@ -58,3 +58,40 @@
     result = always_merger.merge(base, next)
 
     assert dict(result) == {"foo": "value", "bar": "value2", "baz": ["a", "b"]}
+
+
[email protected](
+    "initializer,expectation",
+    [
+        (None, {"foo": "value", "bar": "value3", "baz": ["a", "b", "c"]}),
+        ({}, {"foo": "value", "bar": "value3", "baz": ["a", "b", "c"]}),
+        (
+            {"init": "value"},
+            {"foo": "value", "bar": "value3", "baz": ["a", "b", "c"], "init": 
"value"},
+        ),
+    ],
+    ids=["no initilaizer", "empty initializer", "set initializer"],
+)
+def test_reduce(initializer, expectation):
+    # Given
+    from functools import reduce
+
+    base = {"foo": "value", "baz": ["a"]}
+    next = {"bar": "value2", "baz": ["b"]}
+    more = {"bar": "value3", "baz": ["c"]}
+
+    list_to_merge = [base, next, more]
+
+    # When
+    if initializer is None:
+        result = reduce(always_merger.merge, list_to_merge)
+    else:
+        result = reduce(always_merger.merge, list_to_merge, initializer)
+
+    # Then
+    assert result == expectation
+
+    if initializer is None:
+        assert result is base
+    else:
+        assert result is not base
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/deepmerge-2.0/deepmerge.egg-info/PKG-INFO 
new/deepmerge-2.1.0/deepmerge.egg-info/PKG-INFO
--- old/deepmerge-2.0/deepmerge.egg-info/PKG-INFO       2024-08-30 
07:31:39.000000000 +0200
+++ new/deepmerge-2.1.0/deepmerge.egg-info/PKG-INFO     2026-06-22 
07:45:57.000000000 +0200
@@ -1,6 +1,6 @@
-Metadata-Version: 2.1
+Metadata-Version: 2.4
 Name: deepmerge
-Version: 2.0
+Version: 2.1.0
 Summary: A toolset for deeply merging Python dictionaries.
 Author-email: Yusuke Tsutsumi <[email protected]>
 License: MIT Licence
@@ -28,6 +28,9 @@
 Requires-Dist: pytest; extra == "dev"
 Requires-Dist: build; extra == "dev"
 Requires-Dist: twine; extra == "dev"
+Requires-Dist: sphinx; extra == "dev"
+Requires-Dist: sphinx-rtd-theme; extra == "dev"
+Dynamic: license-file
 
 =========
 deepmerge
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/deepmerge-2.0/deepmerge.egg-info/requires.txt 
new/deepmerge-2.1.0/deepmerge.egg-info/requires.txt
--- old/deepmerge-2.0/deepmerge.egg-info/requires.txt   2024-08-30 
07:31:39.000000000 +0200
+++ new/deepmerge-2.1.0/deepmerge.egg-info/requires.txt 2026-06-22 
07:45:57.000000000 +0200
@@ -10,3 +10,5 @@
 pytest
 build
 twine
+sphinx
+sphinx-rtd-theme
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/deepmerge-2.0/docs/api.rst 
new/deepmerge-2.1.0/docs/api.rst
--- old/deepmerge-2.0/docs/api.rst      2024-08-30 07:31:21.000000000 +0200
+++ new/deepmerge-2.1.0/docs/api.rst    2026-06-22 07:45:38.000000000 +0200
@@ -2,9 +2,35 @@
 API Reference
 =============
 
+Merger
+======
+
 .. autoclass:: deepmerge.merger.Merger
     :members:
 
+Strategies
+==========
+
+.. automodule:: deepmerge.strategy.core
+    :members:
+
+.. automodule:: deepmerge.strategy.dict
+    :members:
+
+.. automodule:: deepmerge.strategy.list
+    :members:
+
+.. automodule:: deepmerge.strategy.set
+    :members:
+
+.. automodule:: deepmerge.strategy.fallback
+    :members:
+
+.. automodule:: deepmerge.strategy.type_conflict
+    :members:
+
+Exceptions
+==========
 
 .. automodule:: deepmerge.exception
     :members:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/deepmerge-2.0/docs/conf.py 
new/deepmerge-2.1.0/docs/conf.py
--- old/deepmerge-2.0/docs/conf.py      2024-08-30 07:31:21.000000000 +0200
+++ new/deepmerge-2.1.0/docs/conf.py    2026-06-22 07:45:38.000000000 +0200
@@ -70,7 +70,7 @@
 #
 # This is also used if you do content translation via gettext catalogs.
 # Usually you set "language" from the command line for these cases.
-language = None
+language = "en"
 
 # There are two options for replacing |today|: either, you set today to some
 # non-false value, then it is used:
@@ -129,7 +129,7 @@
     import sphinx_rtd_theme
 
     html_theme = "sphinx_rtd_theme"
-    html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
+    # html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] # DEPRECATED
 
 # html_theme = 'alabaster'
 
@@ -165,7 +165,7 @@
 # Add any paths that contain custom static files (such as style sheets) here,
 # relative to this directory. They are copied after the builtin static files,
 # so a file named "default.css" will overwrite the builtin "default.css".
-html_static_path = ["_static"]
+# html_static_path = ["_static"]
 
 # Add any extra paths that contain custom files (such as robots.txt or
 # .htaccess) here, relative to this directory. These files are copied
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/deepmerge-2.0/docs/guide.rst 
new/deepmerge-2.1.0/docs/guide.rst
--- old/deepmerge-2.0/docs/guide.rst    2024-08-30 07:31:21.000000000 +0200
+++ new/deepmerge-2.1.0/docs/guide.rst  2026-06-22 07:45:38.000000000 +0200
@@ -30,6 +30,8 @@
         "baz": ["a", "b"]
     }
 
+.. _merges_are_destructive:
+
 Merges are Destructive
 ======================
 
@@ -45,6 +47,72 @@
 
     assert id(result) != id(base)
 
+`functools.reduce` Usage
+========================
+
+If you have an iterable collection of data structures to merge, you can use 
`functools.reduce` to merge them all together. 
+Beware that there is some nuanced behaviour when using the initialiser with 
`functools.reduce` 
+which relates to the :ref:`merges_are_destructive` section above.
+
+
+**Example 1**: Not setting an initialiser
+
+.. code-block:: python
+
+    from deepmerge import always_merger
+    from functools import reduce
+
+    base = {"foo": "value", "baz": ["a"]}
+    next = {"bar": "value2", "baz": ["b"]}
+    more = {"bar": "value3", "baz": ["c"]}
+
+    list_to_merge = [base, next, more]
+
+    result = reduce(always_merger.merge, list_to_merge)
+
+    assert result == {
+        "foo": "value",
+        "bar": "value3",
+        "baz": ["a", "b", "c"]
+    }
+    assert result == base
+
+**Example 2**: Setting an empty initialiser
+
+Where as the following will not impact `base` because we initialise a new 
empty `dict`:
+
+.. code-block:: python
+
+    result = reduce(always_merger.merge, list_to_merge, {})
+
+    assert result == {
+        "foo": "value",
+        "bar": "value3",
+        "baz": ["a", "b", "c"]
+    }
+    assert result != base
+
+Which can lead to some fun and easy configuration loading implementations like:
+
+.. code-block:: python
+    
+    import pathlib
+    import yaml #PyYAML
+    from functools import reduce
+    from deepmerge import always_merger
+
+    # Recursively find yaml files, parse and then merge them through pythonic 
map-reduce idioms
+    my_configuration = reduce(
+        always_merger.merge, 
+        map(
+            lambda f: yaml.safe_load(f.read_text()), 
+            pathlib.Path.cwd().glob("**/*.yml")
+        ), 
+        {}
+    )
+    
+
+
 Authoring your own Mergers
 ==========================
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/deepmerge-2.0/pyproject.toml 
new/deepmerge-2.1.0/pyproject.toml
--- old/deepmerge-2.0/pyproject.toml    2024-08-30 07:31:21.000000000 +0200
+++ new/deepmerge-2.1.0/pyproject.toml  2026-06-22 07:45:38.000000000 +0200
@@ -49,6 +49,9 @@
     ## Build / Release
     "build",
     "twine",
+    ## Documentation
+    "sphinx",
+    "sphinx-rtd-theme"
 ]
 
 [tool.setuptools.packages.find]

Reply via email to