Interface Definitions

Immutable Interfaces.

interface shoobx.immutable.interfaces.IImmutable

Immutable Object

In an immutable object no data can be modified. To modify state, a copy of the object must be created into which the changes are applied.

When trying to modify an attribute of a locked immutable, an AttributeError is raised with the message saying that the attribute cannot be set. The only exceptions are internal attributes which are determined using the __im_is_internal_attr__(name) -> bool method.

Immutables are created using the __im_create__() context manager in the following way:

with Immutable.__im_create__() as factory:
    im = factory(attr=value)

Immutables are updated using the __im_update__() context manager in the following way:

with im.__im_update__() as im2:
    im2.attr = value2

In the example above, im is not modified and all changes are applied to im2.

The algorithm works as follows:

  1. The __im_update__() method is used to create a context manager.

  2. Upon entering the context manager, a clone of the original immutable is created and returned as context.

  3. The clone is in the transient state, allowing all data to be modified. Note that modifications can be made at any depth in the object.

  4. Upon exiting the context manager, the clone is put in the locked state.

Internally, updating deeply nested objects is managed by assigning a mode to the immutable. The master mode describes an immutable that can be updated while a slave (sub-object) is updated as part of its master. The following rules apply:

  1. All immutable sub-objects must be slave immutables.

  2. A master immutable cannot be assigned or added to another immutable, whether that’s a master or slave.

  3. Only master immutables can call __im_update__().

  4. Any immutable object can only have sub-objects that are also immutable or can be made immutable upon assignment.[1]

..[1] During initialization all class attributes are checked to be

immutable or are converted to immutables. On assignment, any mutable object is converted into an immutable object. If convertsion to an immutable object fails, a ValueError error is raised.

Conversion of mutable to immutable objects:

  1. All immutable objects are ignored. These object include all Python core immutables and any object providing this IImmutable interface.

  2. A conversion from lists, dicts and sets is provided.

  3. A mutable object can implement the __im_get__() method to provide an immutable version of itself. Note: __im_get__() must NOT return the same object instance!

__im_mode__

Immutable Mode

Implementation

zope.schema.Choice

Read Only

False

Required

True

Default Value

‘master’

__im_state__

Immutable State

Implementation

zope.schema.Choice

Read Only

False

Required

True

Default Value

‘transient’

__im_conform__(object)

Get an immutable version of the object.

This method converts the given object into its immutable self.

The return value will either be a core immutable object or an object implementing the IImmutable interface. If the latter is returned, it must be in IM_MODE_SLAVE mode and in the IM_STATE_TRANSIENT state.

When having an IImmutable object, we must ensure that the result is in the transient state. Thus, if the immutable is already in the transient state, just return it, otherwise create a transient clone of it.

This method is intended for internal use only and should only be called for sub-objects while adding them to the immutable. The resulting immutable must also be in the IM_STATE_TRANSIENT state.

Raises a ValueError exception if the object cannot be converted.

__im_clone__()

Return a clone of itself.

Important: This method produces a deep clone of itself in transient mode.

__im_set_state__(state)

Set state on the object and all sub objects

Sub-objects are objects in attributes, dict values, list items, etc.

__im_finalize__()

Finalize the object.

The immutable and all its sub-objects are being locked to disallow any further write access.

__im_create__(cls, mode=None, finalize=True, *create_args, **create_kw)

Returns a context manager allowing the cls class to be instantiated

Within the context you can set any attribute on the object, call any method to setup the initial state. Exiting the context shall finalize the object.

  • mode: gets set on the object as it’s __im_mode__

  • finalize: the object gets finalized at the very end

  • create_args, create_kw: get passed to cls.__im_after_create__ right after cls.__init__ is called, thus allowing to set e.g. creator before the object is finalized

__im_after_create__(*args, **kw)

Hook called right after __im_create__ factory called __init__

The just created object is still in transient state.

__im_before_update__(clone)

Hook called before __im_update__()

It is called after a clone in transient state has been created and self is retired.

__im_after_update__(clone)

Hook called at the end of __im_update__().

This method is called while exiting the context manager but before finalizing the clone. Thus, the clone object is still in transient state.

__im_update__()

Returns a context manager allowing the context to be modified.

If the immutable is initially in the locked state, then a clone in the transient state is created and provided as context.

If the immutable is already in the transient state, then the object itself is returned.

__setattr__(name, value)

Set the new attribute value for the given name.

If the value is not an immutable, an AttributeError will be raised.

interface shoobx.immutable.interfaces.IImmutableObject

Extends: shoobx.immutable.interfaces.IImmutable

Immutable Type.

Specific interface to mark general immutable classes.

All immutable objcets will support two constructor arguments implicitly:

  1. im_finalize = True: When true, the object will be created in the locked state. That is particularly useful when all data is set inside the constructor.

  2. im_mode = None: If a mode is provided, the created immutable will be set to this mode.

interface shoobx.immutable.interfaces.IRevisionedImmutableManager

Revisioned immutable contianer.

This interface is agnostic on how the underlying object is identified from the revision. A sensible implementation is to have a deignated attribute for the name of the object.

The API was also designed to support efficient revision management when working large numbers of revisions. This adds some complexities for simple implementations.

getCurrentRevision(obj)

Get the currently active revision of the object.

If no revision or active revision is found for the object, None is returned.

getNumberOfRevisions(obj)

Return the total number of revisions.

getRevisionHistory(obj, creator=None, comment=None, startBefore=None, startAfter=None, batchStart=0, batchSize=None, reversed=False)

Returns an iterable of object revisions in chronological order.

The following arguments filter the search results:

  • creator: The creator of the revision must match the argument.

  • comment: The comment must contain the argument as a substring.

  • startBefore: The revision must start before the given date/time.

  • startAfter: The revision must start after the given date/time.

The following arguments affect the ordering:

  • reversed: When true, the history will be return in reverse

    chronological order, specifically the latest revision is listed first.

The following arguments apply batching:

  • batchStart: The index at which to start the batch.

  • batchSize: The size the of the batch. It is thus the max length of

    the iterable.

addRevision(new, old=None)

Add a new revision.

This method should be implemented to allow a simple append operation to the revision history.

It must assign the __im_start_on__ attribute of the new revision to the current date/time. Also, the __im_manager__ attribute will be set to this IRevisionedImmutableManager instance. It is assumed and may be asserted that the new revision is already locked.

If the old revision is None, then a new revision history will be created and the new revision is the origin revision.

If the old revision is specified, the old revision’s __im_end_on__ date/time is set to the new revision’s __im_start_on__ date/time and the state is set to the IM_STATE_RETIRED state.

rollbackToRevision(revision, activate=True)

Rollback to the given revision making it the newest one.

Properly roll back to a previous revision.

  1. The revision must exist in the revision history. Otherwise a KeyError is raised.

  2. Find all revisions with a start timestamp greater than the revision’s start timestamp.

    If no revisions are found, the revision is already the latest one.

    Remove all found revisions.

  3. If the activate flag is set, then set the revision’s end timestamp should be set to None.

interface shoobx.immutable.interfaces.IRevisionedImmutable

Extends: shoobx.immutable.interfaces.IImmutable

Revisioned Immutable Object

This object represents one revision on an immutable object in the revision history of the immutable.

While not strictly necessary, the revisioned immutable works best in combination with a manager. If __im_manager__ is set, callbacks will be made to the manager to notify it of any new revisions using the addRevision() method.

__im_state__

Immutable State

Implementation

zope.schema.Choice

Read Only

False

Required

True

Default Value

‘transient’

__im_version__

Version

The version of the immutable revision. It is used to establish chronological order.

Implementation

zope.schema.Int

Read Only

False

Required

True

Default Value

0

Allowed Type

int

__im_start_on__

Active Start Timestamp

Timestamp describing the moment at which the revision became active.

Implementation

zope.schema.Datetime

Read Only

False

Required

True

Default Value

None

Allowed Type

datetime.datetime

__im_end_on__

Active End Timestamp

Timestamp describing the moment at which the revision retired. If the value is None, the revision is still active.

Implementation

zope.schema.Datetime

Read Only

False

Required

False

Default Value

None

Allowed Type

datetime.datetime

__im_creator__

Revision Creator

A string representing the creator of the revision. It is up to the application to provide further meaning to this field.

Implementation

zope.schema.TextLine

Read Only

False

Required

False

Default Value

None

Allowed Type

str

__im_comment__

Revision Comment

A himan readable comment of the revision.

Implementation

zope.schema.Datetime

Read Only

False

Required

False

Default Value

None

Allowed Type

datetime.datetime

__im_manager__

Revisioned Immutable Manager

If set, callbacks will be made to notify the manager of changes.

Implementation

zope.schema.Object

Read Only

False

Required

False

Default Value

None

Must Provide

shoobx.immutable.interfaces.IRevisionedImmutableManager

__im_update__(creator=None, comment=None)

Returns a context manager providing a clone that can be edited.

If the immutable is already in the transient state, then the object itself is returned. All arguments to the method are ignored.

If a clone is created, then the __im_creator__ and __im_comment__ attributes will be set.

If __im_manager__ is set, __im_manager__.addRevision(clone, old=self) must be called.

__im_after_create__(creator=None, comment=None)

Hook called right after __im_create__ factory called __init__

The just created object is still in transient state.