API Reference
- class entanglement.interface.EphemeralUnflooded
Bases:
objectA sync_owner value indicating that an object is not to be flooded and when received shall be considered belonging to the sender. Used for protocol messages like errors, Ihave and the like
- destination = NotImplemented
- classmethod sync_encode_value()
- class entanglement.interface.SyncRegistry
Bases:
objectA registry of Synchronizable classes. A connection may accept synchronization from one or more registries. A Synchronizable typically belongs to one registry. A registry can be thought of as a schema of related objects implementing some related synchronizable interface.
A registry supports one or more operations on its Synchronizables. Most registries support the ‘sync’ operation, which requests the full attributes of an object to be flooded to the destinations.
A SyncRegistry represents one of the common points for an application to override behavior or to be notified of incoming changes. Overiding should_listen, should_listen_constructed and should_send is a good way to implement access control or filtering. Overriding sync_receive or the incoming methods associated with an operation provide hooks for an application to be notified of incoming changes. In general when methods are overridden, allowing the superclass method to run is important.
- associate_with_manager(manager)
Called by a manager when the registry is in the manager’s list of registries. Should not hold a non weak reference to the manager
- get_operation(operation)
- get_syncable(tag, default='raise')
- register_operation(operation, op)
Add the operation operation to the set of operations this class accepts on input. Either pass in a handle_incoming function passing the same arguments as sync_receive. Note that self is not explicitly passed; pass in a bound method or use functools.partial if needed. or a SyncOperation instance
- register_syncable(type_name, cls)
Called to add a Synchronizable to this registry
- should_listen(msg, cls, **info)
Authorization check as well as a check on whether we want to ignore the class for some reason
- should_listen_constructed(obj, msg, **info)
- should_send(obj, destination, **info)
- sync_context(**info)
Create a context in which the sync_receive call can be run. Permits exceptions to be trapped and isolation of objects like SQL sessions. At least for now, no need to call the superclass method when overriding.
- sync_receive(object, operation, **kwargs)
Responsible for registry-specific processing of received objects. Called after should_listen and should_listen_constructed have returned True, and after the class’s sync_receive_constructed has filled in the class state.
Typically the specific processing is dependent on the operation, so a method incoming_operation_name (for example incoming_sync) is called. Overriding either sync_receive or incoming_operation_name for application-specific processing is a reasonable choice.
Typically a registry represents a schema of related objects in some application domain. Depending on the nature of a schema, the application logic may vary. If the schema represents a database schema, then incoming_sync may commit the objects to a database while incoming_delete requests deletion. If the schema represents graphical objects to be displayed in a GUI, incoming_sync may draw/redraw an object. In such a case it would be better to have a draw method on all objects in the registry called by incoming_sync than to have the draw operation be triggered by the class’s sync_receive method. The class’s sync_receive would need to duplicate any registry-global logic before deciding to draw.
- exception entanglement.interface.SyncUnauthorized(*args, network_msg=None, **kwargs)
Bases:
entanglement.interface.SyncError
- class entanglement.interface.Synchronizable
Bases:
objectRepresents a class that can be synchronized
A Synchronizable can be synchronized between two Entanglement
SyncManager`s. Objects are synchronized by calling the :meth:`entanglement.network.SyncManager.synchronizemethod on a SyncManager. Synchronizables have one or more sync_properties. Thesync_propertiesare packaged up into a serialized representation by the to_sync method and reconstituted into an object by thesync_construct,sync_receiveandsync_receive_constructedmethods. Objects may have primary keys set in thesync_primary_keysattribute. Objects with the same sync_primary_keys may be coalesced during transmission; only the latest synchronized version will be sent.- sync_compatible(other)
Return true if the primary keys of self match the primary keys of other; true if these two objects can be combined in synchronization
- classmethod sync_construct(msg, **kwargs)
Return a new object of cls consistent with msg that can be filled in with the rest of the contents of msg. Renamed from the previously non-API _sync_construct.
For many classes, this could simply call the class. It could also be overridden to look up an existing instance of a class in a database. The default implementation calls the constructor with sync properties where the constructor argument to the property is set. If constructor is set to a number, that ordinal index is used. If True, the property name is used as a constructor keyword.
Subclasses such as SqlSynchronizable that associate Synchronizables with some persistence layer typically override this method and look up objects based on the primary key in the incoming message.
- sync_hash()
Hash all the primary keys. Any two instances that are sync_compatible must have the same sync_hash.
- property sync_is_local
- sync_owner
- sync_primary_keys
A tuple of primary keys or the value entanglement.interface.Unique meaning that no instances of this class represent the same object
- sync_priority = 100
- classmethod sync_receive(msg, **kwargs)
A convenience method for constructing an object from a json dictionary. NOTE! Do not override this method: the SyncManager does not call it. Instead override sync_construct and sync_receive_constructed.
- sync_receive_constructed(msg, **kwargs)
Given a constructed object, fill in the remaining fields from a javascript message
- classmethod sync_should_listen(msg, **info)
Return True if the incoming object should be received locally. Raise SynchronizationUnauthorized or some other exception if the incoming message should be ignored.
- sync_should_listen_constructed(msg, **info)
Return True if we should listen to this object else raise an exception. Called after an object is constructed; several checks are easier after construction. Checks that can be made without construct should be made there to avoid the security exposure of constructing objects.
- sync_should_send(destination, **info)
Returns True if this object should be synchronized to the given destination
- sync_type = 'Synchronizable'
- to_sync(attributes=None)
Return a dictionary containing the attributes of self that should be synchronized. Attributes can be passed in; if so, then the list of attributes will be limited to those passed in.
- class entanglement.interface.SynchronizableMeta(name, bases, ns, **kwargs)
Bases:
typeA metaclass for capturing Synchronizable classes. In python3.6, no metaclass will be needed; __init__subclass will be sufficient.
- property sync_registry
A registry of classes that this Syncable belongs to. Registries can be associated with a connection; only classes in registries associated with a connection are permitted to be synchronized over that connection
- exception entanglement.interface.WrongSyncDestination(msg=None, *args, dest=None, got_hash=None, **kwargs)
Bases:
entanglement.interface.SyncError
- class entanglement.interface.no_sync_property(wraps=None)
Bases:
objectWraps a property that should not be synchronized. Used mostly to wrap SQLAlchemy columns in SqlSynchronizable classes that would be synchronized by default. Can also be used to mask a parent’s sync_property for example when the value is always the same for some subclass.
Examples:
- class Model(base):
id = Column(GUID, primary_key = True) # Would be a sync_property local_state = no_sync_property(Column(String,)) # Not synchronized
or: class Polygon(Synchronizable):
sides = sync_property()
- class Triangle(Polygon):
sides = no_sync_property(3)
- class entanglement.interface.sync_property(wraps=None, doc=None, *, encoder=None, decoder=None, constructor=False, type=None)
Bases:
objectRepresents a property that can be synchronized.
Simplest usage:
color = sync_property()
Color will be read and written in the synchronization of the object using its default JSON representation
manager =sync_property() @manager.encoder def manager(manager): return manager.id @manager.decoder def manager(id): return Manager.get_by_id(id)
- decoder(decoderfn)
If the property is specified, then decoderfn( value_from_json) will be called. If it returns non-None, then setattr(obj, prop_name, return_value) will be called.
- encoder(encoderfn)
The return of the encoder function will be used as the value to encode
- class entanglement.network.OutgoingUnixDestination(dest_hash, name, path, *, bw_per_sec=10000000000)
- class entanglement.network.SyncDestination(dest_hash=None, name=None, *, host=None, bw_per_sec=10000000, server_hostname=None)
Bases:
entanglement.network.SyncDestinationBaseA standard SyncDestination representing another system that can be reached by a TLS encrypted TCP connection.
- class entanglement.network.SyncDestinationBase(dest_hash, name, bw_per_sec=10000000000)
Bases:
objectA SyncDestination represents a SyncManager other than ourselves that can receive (and generate) synchronizations. The Synchronizable and subclasses of SyncDestination must cooperate to make sure that receiving and object does not create a loop by trying to Synchronize that object back to the sender. One solution is for should_send on SyncDestination to return False (or raise) if the outgoing object is received from this destination.
- async connected(manager, protocol, bwprotocol)
Interface point; called by manager when an outgoing or incoming connection is made to the destination. Except in the case of an unknown destination connecting to a server, the destination is known and already in the manager’s list of connecting destinations. The destination will not be added to the manager’s list of connections until this coroutine returns true. However, incoming synchronizations will be processed and will result in calls to the destination’s should_listen method. If this raises, the connection will be closed and aborted.
- on_connect(callback)
call callback on connection
- should_listen(msg, cls, **kwargs)
Must return True or raise
- class entanglement.network.SyncManager(cert, port, *, key=None, loop=None, capath=None, cafile=None, registries=[])
Bases:
objectA SyncManager manages connections to other Synchronization endpoints. A SyncManager presents a single identity to the rest of the world represented by a private key and certificate. SyncManager includes the logic necessary to act as a client; SyncServer extends SyncManager with logic necessary to accept connections.
- property connections
Return a list of all active protocol objects
- property destinations
A set of destinations for this manager
- synchronize(obj, *, destinations=None, exclude=[], operation='sync', attributes_to_sync=None, response=False, response_for=None, priority=None)
The primary interface for synchronizing an object.
Destinations must be destinations in self.destinations; exclude is a set of destinations to exclude. If attributes is set only these attributes are included in outgoing messages. If response is True, returns a future that will receive the response from this message. Response may also be a future to associate with the object. Response_for should be passed the response object from the context when responding to a message in a flood
- async unknown_destination(protocol)
Called when protocol.dest_hash is not in the local set of destinations. Can return a new destination which will be added to the set of destinations or None, in which case an error is raised and the protocol disconnected. This method is an extension point; by default it returns None
- class entanglement.network.SyncServer(cert, port, *, cafile=None, capath=None, key=None, **kwargs)
Bases:
entanglement.network.SyncManagerA SyncManager that accepts incoming connections
- listen_ssl(port=None, host=None)
Start listening for ssl connections
- Parameters
port – None will use the outgoing port specified in the constructuor; otherwise specify a port to listen on.
host – None will listen on all addresses, else a hostname or address.
- listen_unix(path)
Listen on the given unix path.
- class entanglement.sql.base.Serial(**kwargs)
Keep track of serial numbers. A sequence would be better, but sqlite can’t do them
- serial
- timestamp
- class entanglement.sql.base.SqlSyncDestination(*args, **kwargs)
- attach_callbacks()
This method is guaranteed to be called whenever a
SqlSyncDestinationis instantiated. It is intended for subclasses to override and to attach any callbacks they wish to attach. Note that overriding__init__()is insufficient because SQLAlchemy mapped classes do not call __init__ when loading from the database.
- bw_per_sec
- clear_all_objects(manager=None, *, registries=None, session=None)
- async connected(manager, *args, **kwargs)
Interface point; called by manager when an outgoing or incoming connection is made to the destination. Except in the case of an unknown destination connecting to a server, the destination is known and already in the manager’s list of connecting destinations. The destination will not be added to the manager’s list of connections until this coroutine returns true. However, incoming synchronizations will be processed and will result in calls to the destination’s should_listen method. If this raises, the connection will be closed and aborted.
- dest_hash
- host
- id
- name
- reconstruct()
- type
- exception entanglement.sql.base.SqlSyncError(*args, network_msg=None, **kwargs)
- class entanglement.sql.base.SqlSyncMeta(name, bases, ns)
- class entanglement.sql.base.SqlSyncRegistry(*args, sessionmaker=None, bind=None, **kwargs)
- after_flood_create(obj, manager, **info)
- after_flood_delete(obj, manager, **info)
- after_flood_forward(obj, manager, **info)
- associate_with_manager(manager)
Called by a manager when the registry is in the manager’s list of registries. Should not hold a non weak reference to the manager
- classmethod create_bookkeeping(bind)
Should be called at least once per engine typically before metadata.create_all is called on any sql_sync_declarative_base using the engine.
- ensure_session(manager)
- incoming_create(obj, context, sender, manager, operation, **info)
- incoming_delete(obj, context, manager, sender, **info)
- incoming_forward(obj, context, sender, manager, operation, **info)
- incoming_sync(object, manager, context, **info)
- inherited_registries = [<entanglement.sql.internal._SqlMetaRegistry object>]
- sync_context(**info)
Return a context used to receive an incoming object. This context follows the context manager protocol. The context will have an attribute ‘session’ that is an SqlSyncSession into which an object can be constructed
- class entanglement.sql.base.SqlSyncSession(*args, manager=None, **kwargs)
SqlSyncSession is an sqlalchemy.orm Session that supports entanglement operations. Even if you are not using Entanglement, SqlSyncSession should be used with SqlSynchronizables because it has the logic to update the sync_serial columm. Most functionality is only enabled when the manager property of the session is set to a SyncManager. In that case, committing objects where sync_is_local returns True will synchronize those objects to all destinations of the associated manager. If a manager is associated, it is an error to flush a non-local object. The correct usage pattern is more like:
session.sync_commit() #flush and send non-local objects session.commit() # commit local objects
- sync_commit(expunge_nonlocal=True, *, update_responses=True)
For any SqlSynchronizable modified in the session, synchronize the object. If the object is sync_is_local, send a ‘sync’ operation to all destinations of the manager. If the object is non-local, send a ‘forward’ object toward the destination of the object owner, requesting that they update the object. Deleted objects cause a ‘delete’ operation. If they are local, the delete is sent to all destinations, otherwise it is a request to the owner. If ‘update_responses’ is True, then non-local objects have a ‘sync_future’ set on them. This future will receive either an error or the updated object when the owner respons to the operation. If ‘expunge_nonlocal’ is True, then nonlocal objects are expunged from the session so that a later flush/commit call will not affect them.
- class entanglement.sql.base.SqlSynchronizable
A SQLAlchemy mapped class that can be synchronized. By default every column becomes a sync_property. You can explicitly set sync_property around a Column if you need to override the encoder or decoder, although see entanglement.sql.encoder for a type map that can be used in most cases. The sync_should_send method on this class and should_send on any containing registries must be able to make a decision about whether to send a deleted object when presented with an object containing only the primary keys and no relationships.
- classmethod sync_construct(msg, context, operation=None, manager=None, registry=None, **info)
Return a new object of cls consistent with msg that can be filled in with the rest of the contents of msg. Renamed from the previously non-API _sync_construct.
For many classes, this could simply call the class. It could also be overridden to look up an existing instance of a class in a database. The default implementation calls the constructor with sync properties where the constructor argument to the property is set. If constructor is set to a number, that ordinal index is used. If True, the property name is used as a constructor keyword.
Subclasses such as SqlSynchronizable that associate Synchronizables with some persistence layer typically override this method and look up objects based on the primary key in the incoming message.
- sync_create(manager, owner)
Send a create operation to a given owner for this object. Returns a future whose result will either be the object synchronized by the owner or an error.
- sync_owner = <RelationshipProperty at 0x7fae8b16c4d0; no key>
- sync_owner_id = Column(None, GUID(), ForeignKey('sync_owners.id'), table=None)
- sync_priority
memoize topological sort of a given metadata’s tables
- sync_serial = Column(None, Integer(), table=None, nullable=False)
- class entanglement.sql.base.SyncDeleted(**kwargs)
- id
- meth = 'sync_priority'
- primary_key
- sync_compatible
- sync_hash
- sync_owner
- sync_owner_id
- sync_primary_keys
- sync_priority
- sync_serial
- sync_should_send
- sync_type
- to_sync
- class entanglement.sql.base.SyncOwner(**kwargs)
- clear_all_objects(manager=None, *, registries=None, session=None)
- dest_hash
- property epoch
- classmethod find_from_msg(session, dest, msg)
- id
- incoming_epoch
- incoming_serial
- outgoing_epoch
- outgoing_serial = 0
- sql_destination
- classmethod sync_construct(msg, context, sender, **info)
Return a new object of cls consistent with msg that can be filled in with the rest of the contents of msg. Renamed from the previously non-API _sync_construct.
For many classes, this could simply call the class. It could also be overridden to look up an existing instance of a class in a database. The default implementation calls the constructor with sync properties where the constructor argument to the property is set. If constructor is set to a number, that ordinal index is used. If True, the property name is used as a constructor keyword.
Subclasses such as SqlSynchronizable that associate Synchronizables with some persistence layer typically override this method and look up objects based on the primary key in the incoming message.
- sync_encode_value()
- property sync_is_local
- property sync_owner
Describes an object property that holds a single item or list of items that correspond to a related database table.
Public constructor is the
_orm.relationship()function.See also
relationship_config_toplevel
- sync_owner_id
- sync_primary_keys = ('id',)
- sync_receive_constructed(msg, **options)
Given a constructed object, fill in the remaining fields from a javascript message
- sync_serial
- type
- entanglement.sql.base.sql_sync_declarative_base(*args, registry=None, registry_class=<class 'entanglement.sql.base.SqlSyncRegistry'>, cls=None, **kwargs)
- entanglement.sql.base.sync_manager_destinations(manager, session=None, cls=<class 'entanglement.sql.base.SqlSyncDestination'>, force_resync=False)
Query for :class SqlSyncDestination objects in the :param session. Add any not currently in the manager; remove any present in the manager but no longer in the database. If force_resync is True, then for any added destination, a resynchronization will be forced in both directions.
- entanglement.sql.base.sync_session_maker(*args, **kwargs)
Like sql.orm.sessionmaker for SqlSyncSessions
- entanglement.types.binary_decoder(val)
- entanglement.types.binary_encoder(val)
- entanglement.types.datetime_decoder(value)
- entanglement.types.datetime_encoder(dt)
- entanglement.types.register_type(typ, encoder, decoder)
- entanglement.types.uuid_decoder(val)
- entanglement.types.uuid_encoder(val)
Internals
- class entanglement.protocol.SyncProtocol(manager, incoming=False, dest=None, **kwargs)
- connection_lost(exc)
Called when the connection is lost or closed.
The argument is an exception object or None (the latter meaning a regular EOF is received or the connection was aborted or closed).
- connection_made(transport, bwprotocol)
Called when a connection is made.
The argument is the transport representing the pipe connection. To receive data, wait for data_received() calls. When the connection is closed, connection_lost() is called.