summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/cyextension/immutabledict.pyx
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy/cyextension/immutabledict.pyx')
-rw-r--r--lib/sqlalchemy/cyextension/immutabledict.pyx100
1 files changed, 100 insertions, 0 deletions
diff --git a/lib/sqlalchemy/cyextension/immutabledict.pyx b/lib/sqlalchemy/cyextension/immutabledict.pyx
new file mode 100644
index 000000000..89bcf3ed6
--- /dev/null
+++ b/lib/sqlalchemy/cyextension/immutabledict.pyx
@@ -0,0 +1,100 @@
+from cpython.dict cimport PyDict_New, PyDict_Update, PyDict_Size
+
+
+def _immutable_fn(obj):
+ raise TypeError("%s object is immutable" % obj.__class__.__name__)
+
+
+class ImmutableContainer:
+ def _immutable(self, *a,**kw):
+ _immutable_fn(self)
+
+ __delitem__ = __setitem__ = __setattr__ = _immutable
+
+
+cdef class immutabledict(dict):
+ def __repr__(self):
+ return f"immutabledict({dict.__repr__(self)})"
+
+ def union(self, *args, **kw):
+ cdef dict to_merge = None
+ cdef immutabledict result
+ cdef Py_ssize_t args_len = len(args)
+ if args_len > 1:
+ raise TypeError(
+ f'union expected at most 1 argument, got {args_len}'
+ )
+ if args_len == 1:
+ attribute = args[0]
+ if isinstance(attribute, dict):
+ to_merge = <dict> attribute
+ if to_merge is None:
+ to_merge = dict(*args, **kw)
+
+ if PyDict_Size(to_merge) == 0:
+ return self
+
+ # new + update is faster than immutabledict(self)
+ result = immutabledict()
+ PyDict_Update(result, self)
+ PyDict_Update(result, to_merge)
+ return result
+
+ def merge_with(self, *other):
+ cdef immutabledict result = None
+ cdef object d
+ cdef bint update = False
+ if not other:
+ return self
+ for d in other:
+ if d:
+ if update == False:
+ update = True
+ # new + update is faster than immutabledict(self)
+ result = immutabledict()
+ PyDict_Update(result, self)
+ PyDict_Update(
+ result, <dict>(d if isinstance(d, dict) else dict(d))
+ )
+
+ return self if update == False else result
+
+ def copy(self):
+ return self
+
+ def __reduce__(self):
+ return immutabledict, (dict(self), )
+
+ def __delitem__(self, k):
+ _immutable_fn(self)
+
+ def __setitem__(self, k, v):
+ _immutable_fn(self)
+
+ def __setattr__(self, k, v):
+ _immutable_fn(self)
+
+ def clear(self, *args, **kw):
+ _immutable_fn(self)
+
+ def pop(self, *args, **kw):
+ _immutable_fn(self)
+
+ def popitem(self, *args, **kw):
+ _immutable_fn(self)
+
+ def setdefault(self, *args, **kw):
+ _immutable_fn(self)
+
+ def update(self, *args, **kw):
+ _immutable_fn(self)
+
+ # PEP 584
+ def __ior__(self, other):
+ _immutable_fn(self)
+
+ def __or__(self, other):
+ return immutabledict(super().__or__(other))
+
+ def __ror__(self, other):
+ return immutabledict(super().__ror__(other))