Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-immutabledict for 
openSUSE:Factory checked in at 2023-12-08 22:32:08
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-immutabledict (Old)
 and      /work/SRC/openSUSE:Factory/.python-immutabledict.new.25432 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-immutabledict"

Fri Dec  8 22:32:08 2023 rev:4 rq:1131733 version:4.0.0

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/python-immutabledict/python-immutabledict.changes    
    2023-08-10 15:35:03.544597330 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-immutabledict.new.25432/python-immutabledict.changes
     2023-12-08 22:32:39.381330942 +0100
@@ -1,0 +2,10 @@
+Thu Dec  7 22:34:25 UTC 2023 - Dirk Müller <dmuel...@suse.com>
+
+- update to 4.0.0:
+  * Replace `__init__` by `__new__`.
+  * Add explicit items()/keys()/values() methods to speedup these
+    methods.
+  * Add set/delete/update functions.
+  * Add documentation at immutabledict.corenting.fr
+
+-------------------------------------------------------------------

Old:
----
  immutabledict-3.0.0.tar.gz

New:
----
  immutabledict-4.0.0.tar.gz

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

Other differences:
------------------
++++++ python-immutabledict.spec ++++++
--- /var/tmp/diff_new_pack.poZ2ye/_old  2023-12-08 22:32:39.861348604 +0100
+++ /var/tmp/diff_new_pack.poZ2ye/_new  2023-12-08 22:32:39.865348752 +0100
@@ -27,7 +27,7 @@
 %define         short_name immutabledict
 %{?sle15_python_module_pythons}
 Name:           python-%{short_name}%{psuffix}
-Version:        3.0.0
+Version:        4.0.0
 Release:        0
 Summary:        Immutable wrapper around dictionaries (a fork of frozendict)
 License:        MIT

++++++ immutabledict-3.0.0.tar.gz -> immutabledict-4.0.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/immutabledict-3.0.0/PKG-INFO 
new/immutabledict-4.0.0/PKG-INFO
--- old/immutabledict-3.0.0/PKG-INFO    1970-01-01 01:00:00.000000000 +0100
+++ new/immutabledict-4.0.0/PKG-INFO    1970-01-01 01:00:00.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: immutabledict
-Version: 3.0.0
+Version: 4.0.0
 Summary: Immutable wrapper around dictionaries (a fork of frozendict)
 Home-page: https://github.com/corenting/immutabledict
 License: MIT
@@ -15,9 +15,12 @@
 Classifier: Programming Language :: Python :: 3.9
 Classifier: Programming Language :: Python :: 3.10
 Classifier: Programming Language :: Python :: 3.11
+Classifier: Programming Language :: Python :: 3.12
 Classifier: Topic :: Software Development :: Libraries :: Python Modules
 Project-URL: Bug Tracker, https://github.com/corenting/immutabledict/issues
 Project-URL: Changelog, 
https://github.com/corenting/immutabledict/blob/master/CHANGELOG.md
+Project-URL: Documentation, https://immutabledict.corenting.fr
+Project-URL: Donation, https://corenting.fr/donate
 Project-URL: Repository, https://github.com/corenting/immutabledict
 Description-Content-Type: text/markdown
 
@@ -27,15 +30,13 @@
 
 ![License](https://img.shields.io/pypi/l/immutabledict) 
![Build](https://img.shields.io/github/actions/workflow/status/corenting/immutabledict/ci.yml?branch=master)
 ![Codecov](https://img.shields.io/codecov/c/github/corenting/immutabledict) 
![PyPI - Downloads](https://img.shields.io/pypi/dm/immutabledict)
 
-A fork of the original 
[frozendict](https://github.com/slezica/python-frozendict), an immutable 
wrapper around dictionaries.
-This library is a pure Python, MIT-licensed alternative to the new LGPL-3.0 
licensed [frozendict](https://github.com/Marco-Sulla/python-frozendict).
+An immutable wrapper around dictionaries. immutabledict implements the 
complete mapping interface and can be used as a drop-in replacement for 
dictionaries where immutability is desired.
 
-It implements the complete mapping interface and can be used as a drop-in 
replacement for dictionaries where immutability is desired.
-The immutabledict constructor mimics dict, and all of the expected interfaces 
(iter, len, repr, hash, getitem) are provided. Note that an immutabledict does 
not guarantee the immutability of its values, so the utility of hash method is 
restricted by usage.
+It's a fork of slezica's 
[frozendict](https://github.com/slezica/python-frozendict). This library is a 
pure Python, MIT-licensed alternative to the new LGPL-3.0 licensed 
[frozendict](https://github.com/Marco-Sulla/python-frozendict).
 
 ## Installation
 
-Official release in [on pypy](https://pypi.org/project/immutabledict/) as 
`immutabledict`.
+Official release in [on pypi](https://pypi.org/project/immutabledict/) as 
`immutabledict`.
 
 **Community-maintained** releases are available:
 - On [conda-forge](https://anaconda.org/conda-forge/immutabledict) as 
`immutabledict`
@@ -58,3 +59,7 @@
 - [PEP 584 union operators](https://www.python.org/dev/peps/pep-0584/)
 - Keep the same signature for `copy()` as `dict` (starting with immutabledict 
3.0.0), don't accept extra keyword arguments.
 
+## Donations
+
+If you wish to support the app, donations are possible 
[here](https://corenting.fr/donate).
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/immutabledict-3.0.0/README.md 
new/immutabledict-4.0.0/README.md
--- old/immutabledict-3.0.0/README.md   2023-07-21 20:13:55.780401200 +0200
+++ new/immutabledict-4.0.0/README.md   2023-11-25 13:34:07.496336700 +0100
@@ -4,15 +4,13 @@
 
 ![License](https://img.shields.io/pypi/l/immutabledict) 
![Build](https://img.shields.io/github/actions/workflow/status/corenting/immutabledict/ci.yml?branch=master)
 ![Codecov](https://img.shields.io/codecov/c/github/corenting/immutabledict) 
![PyPI - Downloads](https://img.shields.io/pypi/dm/immutabledict)
 
-A fork of the original 
[frozendict](https://github.com/slezica/python-frozendict), an immutable 
wrapper around dictionaries.
-This library is a pure Python, MIT-licensed alternative to the new LGPL-3.0 
licensed [frozendict](https://github.com/Marco-Sulla/python-frozendict).
+An immutable wrapper around dictionaries. immutabledict implements the 
complete mapping interface and can be used as a drop-in replacement for 
dictionaries where immutability is desired.
 
-It implements the complete mapping interface and can be used as a drop-in 
replacement for dictionaries where immutability is desired.
-The immutabledict constructor mimics dict, and all of the expected interfaces 
(iter, len, repr, hash, getitem) are provided. Note that an immutabledict does 
not guarantee the immutability of its values, so the utility of hash method is 
restricted by usage.
+It's a fork of slezica's 
[frozendict](https://github.com/slezica/python-frozendict). This library is a 
pure Python, MIT-licensed alternative to the new LGPL-3.0 licensed 
[frozendict](https://github.com/Marco-Sulla/python-frozendict).
 
 ## Installation
 
-Official release in [on pypy](https://pypi.org/project/immutabledict/) as 
`immutabledict`.
+Official release in [on pypi](https://pypi.org/project/immutabledict/) as 
`immutabledict`.
 
 **Community-maintained** releases are available:
 - On [conda-forge](https://anaconda.org/conda-forge/immutabledict) as 
`immutabledict`
@@ -34,3 +32,7 @@
 - Typing
 - [PEP 584 union operators](https://www.python.org/dev/peps/pep-0584/)
 - Keep the same signature for `copy()` as `dict` (starting with immutabledict 
3.0.0), don't accept extra keyword arguments.
+
+## Donations
+
+If you wish to support the app, donations are possible 
[here](https://corenting.fr/donate).
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/immutabledict-3.0.0/immutabledict/__init__.py 
new/immutabledict-4.0.0/immutabledict/__init__.py
--- old/immutabledict-3.0.0/immutabledict/__init__.py   2023-07-21 
20:13:55.780401200 +0200
+++ new/immutabledict-4.0.0/immutabledict/__init__.py   2023-11-25 
13:34:07.496336700 +0100
@@ -1,33 +1,49 @@
+"""Implementation of the :class:`immutabledict` and 
:class:`ImmutableOrderedDict` classes."""
 from __future__ import annotations
 
 from collections import OrderedDict
-from typing import Any, Dict, Iterable, Iterator, Mapping, Optional, Type, 
TypeVar
+from typing import (
+    Any,
+    Dict,
+    ItemsView,
+    Iterable,
+    Iterator,
+    KeysView,
+    Mapping,
+    Optional,
+    Type,
+    TypeVar,
+    ValuesView,
+)
 
-__version__ = "3.0.0"
+__version__ = "4.0.0"
 
 _K = TypeVar("_K")
 _V = TypeVar("_V", covariant=True)
 
 
-class immutabledict(Mapping[_K, _V]):
+class immutabledict(Mapping[_K, _V]):  # noqa: N801
     """
-    An immutable wrapper around dictionaries that implements
-    the complete :py:class:`collections.Mapping` interface.
-    It can be used as a drop-in replacement for dictionaries
-    where immutability is desired.
+    An immutable wrapper around dictionaries that implements the complete 
:py:class:`collections.Mapping` interface.
+
+    It can be used as a drop-in replacement for dictionaries where 
immutability is desired.
     """
 
-    dict_cls: Type[Dict[Any, Any]] = dict
+    _dict_cls: Type[Dict[Any, Any]] = dict
+    _dict: Dict[_K, _V]
+    _hash: Optional[int]
 
     @classmethod
-    def fromkeys(
+    def fromkeys(  # noqa: D102
         cls, seq: Iterable[_K], value: Optional[_V] = None
     ) -> immutabledict[_K, _V]:
-        return cls(cls.dict_cls.fromkeys(seq, value))
+        return cls(cls._dict_cls.fromkeys(seq, value))
 
-    def __init__(self, *args: Any, **kwargs: Any) -> None:
-        self._dict = self.dict_cls(*args, **kwargs)
-        self._hash: Optional[int] = None
+    def __new__(cls, *args: Any, **kwargs: Any) -> immutabledict[_K, _V]:  # 
noqa: D102
+        inst = super().__new__(cls)
+        setattr(inst, "_dict", cls._dict_cls(*args, **kwargs))
+        setattr(inst, "_hash", None)
+        return inst
 
     def __getitem__(self, key: _K) -> _V:
         return self._dict[key]
@@ -35,7 +51,7 @@
     def __contains__(self, key: object) -> bool:
         return key in self._dict
 
-    def copy(self) -> immutabledict[_K, _V]:
+    def copy(self) -> immutabledict[_K, _V]:  # noqa: D102
         return self.__class__(self)
 
     def __iter__(self) -> Iterator[_K]:
@@ -45,7 +61,7 @@
         return len(self._dict)
 
     def __repr__(self) -> str:
-        return "{}({!r})".format(self.__class__.__name__, self._dict)
+        return f"{self.__class__.__name__}({self._dict!r})"
 
     def __hash__(self) -> int:
         if self._hash is None:
@@ -73,10 +89,58 @@
     def __ior__(self, other: Any) -> immutabledict[_K, _V]:
         raise TypeError(f"'{self.__class__.__name__}' object is not mutable")
 
+    def items(self) -> ItemsView[_K, _V]:  # noqa: D102
+        return self._dict.items()
+
+    def keys(self) -> KeysView[_K]:  # noqa: D102
+        return self._dict.keys()
+
+    def values(self) -> ValuesView[_V]:  # noqa: D102
+        return self._dict.values()
+
+    def set(self, key: _K, value: Any) -> immutabledict[_K, _V]:
+        """
+        Return a new :class:`immutabledict` where the item at the given key is 
set to to the given value. If there is already an item at the given key it will 
be replaced.
+
+        :param key: the key for which we want to set a value
+        :param value: the value we want to use
+
+        :return: the new :class:`immutabledict` with the key set to the given 
value
+        """
+        new = dict(self._dict)
+        new[key] = value
+        return self.__class__(new)
+
+    def delete(self, key: _K) -> immutabledict[_K, _V]:
+        """
+        Return a new :class:`immutabledict` without the item at the given key.
+
+        :param key: the key of the item you want to remove in the returned 
:class:`immutabledict`
+
+        :raises [KeyError]: a KeyError is raised if there is no item at the 
given key
+
+        :return: the new :class:`immutabledict` without the item at the given 
key
+        """
+        new = dict(self._dict)
+        del new[key]
+        return self.__class__(new)
+
+    def update(self, _dict: Dict[_K, _V]) -> immutabledict[_K, _V]:
+        """
+        Similar to :meth:`dict.update` but returning an immutabledict.
+
+        :return: the updated :class:`immutabledict`
+        """
+        new = dict(self._dict)
+        new.update(_dict)
+        return self.__class__(new)
+
 
 class ImmutableOrderedDict(immutabledict[_K, _V]):
     """
     An immutabledict subclass that maintains key order.
+
+    Same as :class:`immutabledict` but based on 
:class:`collections.OrderedDict`.
     """
 
     dict_cls = OrderedDict
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/immutabledict-3.0.0/pyproject.toml 
new/immutabledict-4.0.0/pyproject.toml
--- old/immutabledict-3.0.0/pyproject.toml      2023-07-21 20:13:55.780401200 
+0200
+++ new/immutabledict-4.0.0/pyproject.toml      2023-11-25 13:34:07.496336700 
+0100
@@ -1,11 +1,12 @@
 [tool.poetry]
 name = "immutabledict"
-version = "3.0.0"
+version = "4.0.0"
 description = "Immutable wrapper around dictionaries (a fork of frozendict)"
 authors = ["Corentin Garcia <corent...@gmail.com>"]
 license = "MIT"
 readme = "README.md"
 repository = "https://github.com/corenting/immutabledict";
+documentation = "https://immutabledict.corenting.fr";
 keywords = ["immutable", "dictionary"]
 classifiers = [
     "Development Status :: 5 - Production/Stable",
@@ -18,6 +19,7 @@
 [tool.poetry.urls]
 "Changelog" = 
"https://github.com/corenting/immutabledict/blob/master/CHANGELOG.md";
 "Bug Tracker" = "https://github.com/corenting/immutabledict/issues";
+"Donation" = "https://corenting.fr/donate";
 
 [tool.poetry.dependencies]
 python = "^3.8"
@@ -26,14 +28,30 @@
 black = "*"
 coverage = "*"
 mypy = "*"
-pdbpp = "*"
 pytest = "*"
 pytest-cov = "*"
 ruff = "*"
+sphinx = { version = "^7.2", python = "^3.9" }
 tox = "*"
 
 [tool.ruff]
 line-length = 88
+target-version = "py38"
+per-file-ignores = {"tests/**" = ["S101", "D"]}
+# Enable pycodestyle (E), Pyflakes (F), flake8-print (T20), ruff rules (RUF),
+# isort (I), pep8-naming (N),  pyupgrade (UP), flake8-async (ASYNC),
+# flake8-bandit (S), perflint (PERF) and pydocstyle (D)
+select = ["E", "F", "T20", "RUF", "I", "N", "UP", "ASYNC", "S", "PERF", "D"]
+ignore = [
+    "E501",  # line too long as black is used
+    "D203",  # one blank line before class
+    "D212",  # multiline summary first line
+    "D105"   # no docstrings for magic methods
+]
+
+[tool.ruff.pyupgrade]
+# Preserve types, even if a file imports `from __future__ import annotations`.
+keep-runtime-typing = true
 
 [tool.mypy]
 ignore_missing_imports = true
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/immutabledict-3.0.0/tests/test_immutabledict.py 
new/immutabledict-4.0.0/tests/test_immutabledict.py
--- old/immutabledict-3.0.0/tests/test_immutabledict.py 2023-07-21 
20:13:55.780401200 +0200
+++ new/immutabledict-4.0.0/tests/test_immutabledict.py 2023-11-25 
13:34:07.496336700 +0100
@@ -1,4 +1,5 @@
 from typing import Any, Dict, Union
+
 import pytest
 
 from immutabledict import ImmutableOrderedDict, immutabledict
@@ -6,8 +7,7 @@
 
 class TestImmutableDict:
     def test_covariance(self) -> None:
-        """
-        Not a real unit test, but test covariance
+        """Not a real unit test, but test covariance
         as mypy runs on the tests.
         """
 
@@ -26,6 +26,10 @@
         my_dict = second_dict
         assert my_dict == second_dict
 
+    def test_new_init_methods(self) -> None:
+        assert "__new__" in immutabledict.__dict__
+        assert "__init__" not in immutabledict.__dict__
+
     def test_cannot_assign_value(self) -> None:
         with pytest.raises(AttributeError):
             immutabledict().setitem("key", "value")  # type: ignore
@@ -94,7 +98,7 @@
         immutable_dict: immutabledict[str, str] = immutabledict(
             {"a": "value", "b": "other_value"}
         )
-        eval_ret = eval(repr(immutable_dict))
+        eval_ret = eval(repr(immutable_dict))  # noqa: S307
         assert immutable_dict == eval_ret
 
     def test_hash(self) -> None:
@@ -185,6 +189,54 @@
         assert first_dict == {"a": "a", "b": "b"}
         assert second_dict == {"a": "A", "c": "c"}
 
+    @pytest.mark.parametrize(
+        "statement",
+        [
+            "for k, v in d.items(): s += 1",
+            "for v in d.values(): s += 1",
+            "for k in d.keys(): s += 1",
+        ],
+    )
+    def test_performance(self, statement: str) -> None:
+        from timeit import timeit
+
+        time_standard = timeit(
+            statement,
+            number=3,
+            setup="s=0; d = {i:i for i in range(1000000)}",
+        )
+
+        time_immutable = timeit(
+            statement,
+            globals=globals(),
+            number=3,
+            setup="s=0; d = immutabledict({i:i for i in range(1000000)})",
+        )
+
+        assert time_immutable < 1.2 * time_standard
+
+    def test_set_delete_update(self) -> None:
+        d: immutabledict[str, int] = immutabledict(a=1, b=2)
+
+        assert d.set("a", 10) == immutabledict(a=10, b=2) == dict(a=10, b=2)
+        assert d.delete("a") == immutabledict(b=2) == dict(b=2)
+
+        with pytest.raises(KeyError):
+            d.delete("c")
+
+        assert d.update({"a": 3}) == immutabledict(a=3, b=2) == dict(a=3, b=2)
+
+        assert (
+            d.update({"c": 17}) == immutabledict(a=1, b=2, c=17) == dict(a=1, 
b=2, c=17)
+        )
+
+        # Make sure d doesn't change
+        assert d == immutabledict(a=1, b=2) == dict(a=1, b=2)
+
+    def test_new_kwargs(self) -> None:
+        immutable_dict: immutabledict[str, int] = immutabledict(a=1, b=2)
+        assert immutable_dict == {"a": 1, "b": 2} == dict(a=1, b=2)
+
 
 class TestImmutableOrderedDict:
     def test_ordered(self) -> None:

Reply via email to