snakeoil.klass.immutable module

class snakeoil.klass.immutable.Simple[source]

Bases: object

Make instance immutable, but allow __init__ to mutate.

Like :class:Strict, these protections can be sidestepped by object.__setatttr__ directly. Additionally for any code decoratored with :meth:allow_mutation, mutation is allowed in that invocation.

Once in a mutation block, anything that block calls is still allowed to mutate this instance unless it enters another mutation block (another instance), and that block tries to mutate the original instance. TL;dr: you’ll know if you hit that edgecase.

>>> from snakeoil.klass.immutable import Simple
>>> class foo(Simple):
...   def __init__(self):
...     self.x = 1 # works
...     self._subinit() # works, we're in a mutation context
...   def _subinit(self):
...     # this only works if invoke in a mutation context.
...     # IE, __init__ for example.
...     self.x = 2
>>>
>>> try: foo().x =1 # doesn't
... except AttributeError: pass
>>>
>>> try: foo()._subinit() # same thing, this is disallowed
... except AttributError: pass

This is async and thread safe. It is not safe within generator context due to a python limitation.

class snakeoil.klass.immutable.Strict[source]

Bases: object

Make instances effectively immutable.

This is the ‘strict’ implementation; __setattr__ and __delattr__ will never allow mutation. Any mutation- during __init__ for example, must be done via object.__setattr__(self, ‘attr’, value).

It’s strongly advised you look at :class:Simple since that relaxes the rules for things like __init__.