Skip to content

Commit

Permalink
give to caesar...
Browse files Browse the repository at this point in the history
  • Loading branch information
Marco-Sulla committed Apr 14, 2024
1 parent 3208ed8 commit a63cad5
Showing 1 changed file with 248 additions and 0 deletions.
248 changes: 248 additions & 0 deletions src/frozendict/_frozendict_py.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,248 @@
from copy import deepcopy


def immutable(self, *args, **kwargs):
r"""
Function for not implemented method since the object is immutable
"""

raise AttributeError(
f"'{self.__class__.__name__}' object is read-only"
)


_empty_frozendict = None


class frozendict(dict):
r"""
A simple immutable dictionary.
The API is the same as `dict`, without methods that can change the
immutability. In addition, it supports __hash__().
"""

__slots__ = (
"_hash",
)

@classmethod
def fromkeys(cls, *args, **kwargs):
r"""
Identical to dict.fromkeys().
"""

return cls(dict.fromkeys(*args, **kwargs))

def __new__(e4b37cdf_d78a_4632_bade_6f0579d8efac, *args, **kwargs):
cls = e4b37cdf_d78a_4632_bade_6f0579d8efac

has_kwargs = bool(kwargs)
continue_creation = True

# check if there's only an argument and it's of the same class
if len(args) == 1 and not has_kwargs:
it = args[0]

# no isinstance, to avoid subclassing problems
if it.__class__ == frozendict and cls == frozendict:
self = it
continue_creation = False

if continue_creation:
self = dict.__new__(cls, *args, **kwargs)

dict.__init__(self, *args, **kwargs)

# empty singleton - start

if self.__class__ == frozendict and not len(self):
global _empty_frozendict

if _empty_frozendict is None:
_empty_frozendict = self
else:
self = _empty_frozendict
continue_creation = False

# empty singleton - end

if continue_creation:
object.__setattr__(self, "_hash", -1)

return self

def __init__(self, *args, **kwargs):
pass

def __hash__(self, *args, **kwargs):
r"""
Calculates the hash if all values are hashable, otherwise
raises a TypeError.
"""

if self._hash != -1:
_hash = self._hash
else:
fs = frozenset(self.items())
_hash = hash(fs)

object.__setattr__(self, "_hash", _hash)

return _hash

def __repr__(self, *args, **kwargs):
r"""
Identical to dict.__repr__().
"""

body = super().__repr__(*args, **kwargs)
klass = self.__class__

if klass == frozendict:
name = f"frozendict.{klass.__name__}"
else:
name = klass.__name__

return f"{name}({body})"

def copy(self):
r"""
Return the object itself, as it's an immutable.
"""

klass = self.__class__

if klass == frozendict:
return self

return klass(self)

def __copy__(self, *args, **kwargs):
r"""
See copy().
"""

return self.copy()

def __deepcopy__(self, memo, *args, **kwargs):
r"""
As for tuples, if hashable, see copy(); otherwise, it returns a
deepcopy.
"""

klass = self.__class__
return_copy = klass == frozendict

if return_copy:
try:
hash(self)
except TypeError:
return_copy = False

if return_copy:
return self.copy()

tmp = deepcopy(dict(self))

return klass(tmp)

def __reduce__(self, *args, **kwargs):
r"""
Support for `pickle`.
"""

return (self.__class__, (dict(self),))

def set(self, key, val):
new_self = deepcopy(dict(self))
new_self[key] = val

return self.__class__(new_self)

def setdefault(self, key, default=None):
if key in self:
return self

new_self = deepcopy(dict(self))

new_self[key] = default

return self.__class__(new_self)

def delete(self, key):
new_self = deepcopy(dict(self))
del new_self[key]

if new_self:
return self.__class__(new_self)

return self.__class__()

def _get_by_index(self, collection, index):
try:
return collection[index]
except IndexError:
maxindex = len(collection) - 1
name = self.__class__.__name__
raise IndexError(
f"{name} index {index} out of range {maxindex}"
) from None

def key(self, index=0):
collection = tuple(self.keys())

return self._get_by_index(collection, index)

def value(self, index=0):
collection = tuple(self.values())

return self._get_by_index(collection, index)

def item(self, index=0):
collection = tuple(self.items())

return self._get_by_index(collection, index)

def __setitem__(self, key, val, *args, **kwargs):
raise TypeError(
f"'{self.__class__.__name__}' object doesn't support item "
"assignment"
)

def __delitem__(self, key, *args, **kwargs):
raise TypeError(
f"'{self.__class__.__name__}' object doesn't support item "
"deletion"
)


def frozendict_or(self, other, *args, **kwargs):
res = {}
res.update(self)
res.update(other)

return self.__class__(res)


frozendict.__or__ = frozendict_or
frozendict.__ior__ = frozendict_or

try:
frozendict.__reversed__
except AttributeError:
def frozendict_reversed(self, *args, **kwargs):
return reversed(tuple(self))


frozendict.__reversed__ = frozendict_reversed

frozendict.clear = immutable
frozendict.pop = immutable
frozendict.popitem = immutable
frozendict.update = immutable
frozendict.__delattr__ = immutable
frozendict.__setattr__ = immutable
frozendict.__module__ = 'frozendict'

__all__ = (frozendict.__name__,)

0 comments on commit a63cad5

Please sign in to comment.