From: Federico Caselli Date: Fri, 21 Oct 2022 19:11:23 +0000 (+0200) Subject: Add pep 584 to python immutabledict fallback X-Git-Tag: rel_2_0_0b3~32^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=25619f27836e80351e078c8badc47b3e0acccf5d;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git Add pep 584 to python immutabledict fallback Fixes: #8695 Change-Id: Ie0412c3a7b2b1ba5bd5112f204318ff763cbb8f4 --- diff --git a/lib/sqlalchemy/cyextension/immutabledict.pyx b/lib/sqlalchemy/cyextension/immutabledict.pyx index 6ab2553112..100287b380 100644 --- a/lib/sqlalchemy/cyextension/immutabledict.pyx +++ b/lib/sqlalchemy/cyextension/immutabledict.pyx @@ -32,6 +32,7 @@ class ImmutableDictBase(dict): __delitem__ = __setitem__ = __setattr__ = _immutable clear = pop = popitem = setdefault = update = _immutable + cdef class immutabledict(dict): def __repr__(self): return f"immutabledict({dict.__repr__(self)})" @@ -118,7 +119,9 @@ cdef class immutabledict(dict): _immutable_fn(self) def __or__(self, other): - return immutabledict(super().__or__(other)) + return immutabledict(dict.__or__(self, other)) def __ror__(self, other): - return immutabledict(super().__ror__(other)) + # NOTE: this is used only in cython 3.x; + # version 0.x will call __or__ with args inversed + return immutabledict(dict.__ror__(self, other)) diff --git a/lib/sqlalchemy/util/_py_collections.py b/lib/sqlalchemy/util/_py_collections.py index 488229abbe..cd46893a44 100644 --- a/lib/sqlalchemy/util/_py_collections.py +++ b/lib/sqlalchemy/util/_py_collections.py @@ -27,6 +27,7 @@ from typing import TypeVar from typing import Union _T = TypeVar("_T", bound=Any) +_S = TypeVar("_S", bound=Any) _KT = TypeVar("_KT", bound=Any) _VT = TypeVar("_VT", bound=Any) @@ -129,8 +130,19 @@ class immutabledict(ImmutableDictBase[_KT, _VT]): def __repr__(self) -> str: return "immutabledict(%s)" % dict.__repr__(self) + # PEP 584 + def __ior__(self, __value: Any) -> NoReturn: # type: ignore + self._readonly() -_S = TypeVar("_S", bound=Any) + def __or__( # type: ignore[override] + self, __value: Mapping[_KT, _VT] + ) -> immutabledict[_KT, _VT]: + return immutabledict(super().__or__(__value)) + + def __ror__( # type: ignore[override] + self, __value: Mapping[_KT, _VT] + ) -> immutabledict[_KT, _VT]: + return immutabledict(super().__ror__(__value)) class OrderedSet(Set[_T]): diff --git a/test/base/test_utils.py b/test/base/test_utils.py index 27945f2368..0ef86545b5 100644 --- a/test/base/test_utils.py +++ b/test/base/test_utils.py @@ -343,6 +343,23 @@ class ImmutableDictTest(fixtures.TestBase): i2 = util.immutabledict({"a": 42, 42: "a"}) eq_(str(i2), "immutabledict({'a': 42, 42: 'a'})") + @testing.requires.python39 + def test_pep584(self): + i = util.immutabledict({"a": 2}) + with expect_raises_message(TypeError, "object is immutable"): + i |= {"b": 42} + eq_(i, {"a": 2}) + + i2 = i | {"x": 3} + eq_(i, {"a": 2}) + eq_(i2, {"a": 2, "x": 3}) + is_true(isinstance(i2, util.immutabledict)) + + i2 = {"x": 3} | i2 + eq_(i, {"a": 2}) + eq_(i2, {"a": 2, "x": 3}) + is_true(isinstance(i2, util.immutabledict)) + class ImmutableTest(fixtures.TestBase): @combinations(util.immutabledict({1: 2, 3: 4}), util.FacadeDict({2: 3}))