Package: zc.generationalset
Generational SetsGenerational sets (GSets) are designed to facilitate data synchronization
between a server and clients.Goals:Make synchronization simple by sending all updates for a tree of sets
at once.Allow clients to be updated very quickly.Reduce data-transfer volume by sending only changes.Avoid conflict resolution.Assumptions:Disconnected data updates aren’t needed.Clients mirror server data.This implies that the server data, or more specifically, the user’s
view of the server data, aren’t too large to store on the client.GSets track state by generation.  A client presents a generation and
is sent updates made since the presented generation.  GSets can be
grouped into trees with a shared generation.  A client can present a
single generation and be sent updates for all of the sets making up a
database.This implementation of generational sets usesZODBto store data on the server.High-level usage patternDefine a tree of sets representing the data in an application.
This may be user specific.Clients make updates via REST calls to a server.  They don’t make
local changes except in response to server updates.Client requests include their data generation.Most (JSON) responses to server calls have optional updates property
that contains generational updates since the generation provided by
the client.  When the client gets updates, which include the new
generation, it applies the updates to it’s internal data store.For native apps, the server sends push notifications when there are
updates for a user and, in response, the client polls for the
updates.  This allows updates to be extremely timely without
constant polling.Note that this package only provides the data structure
implementation. Wrapping the data structure in a REST interface or
sending notifications is up to applications.APIEvery object in a GSet must have an id.  By default, this is provided
by anidattribute, but you can configure a GSet to use another
attribute or some other mechanism to get an id for an object.When an object is added to a GSet, call theaddmethod on the Gset with the object:>>> from zc.generationalset import GSet
>>> things = GSet()
>>> athing = Thing(42)
>>> things.add(athing)When an object is changed, call thechangedmethod on the Gset
with the object. If object is not present in the Gset, update will
raise a KeyError:>>> things.changed(athing)
>>> things.changed(Thing(43))
Traceback (most recent call last):
...
KeyError: 43

>>> things.generational_updates(0)
{'generation': 3, 'adds': [Thing(42)]}To remove an object, call
theremovemethod with the object:>>> things.remove(athing)To get updates to a set since a given generation, callgenerational_updates, passing a generation:>>> things.generational_updates(0)
{'generation': 4, 'removals': [42]}

>>> things.add(Thing(1))
>>> things.generational_updates(0)
{'generation': 5, 'removals': [42], 'adds': [Thing(1)]}
>>> things.generational_updates(3)
{'generation': 5, 'adds': [Thing(1)]}Note that generations start at 1.The result of callinggenerational_updatesis a dictionary with
keys:generationThe current generation of the setaddsObjects added since the given generation.removalsIds of objects removed since the given generation.contentsAll of the object in the set.contentsare returned when there have been many removals since
the given generation.  A generational set only keeps track of a
limited number (99 by default, but configurable) of removals.  If a
client is too out of date for the set to have relevant removals, it
returns the entire contents, instead of returning adds and removals.GSets support iteration, and querying length and containment. They
don’t currently support set operations, like intersection and
union. You can also retrieve an item from a GSet using its id:>>> len(things)
1
>>> list(things)
[Thing(1)]
>>> Thing(1) in things
True
>>> things[1]
Thing(1)Nested setsTo define nested sets:Define a parent set:>>> parent = GSet(superset=True)Note the use of thesupersetparameter.Define child sets, and add them to the parent:>>> messages = GSet("messages", parent)
>>> parent.add(messages)When defining child sets, specify an id and the parent.We haven’t tested more than one level of nesting.When asking for generational updates on parent sets, the adds and
contents contain the generational updates for subsets, with ids, but
without subset generations:>>> messages.add(Thing(42))
>>> parent.generational_updates(0)
{'generation': 3, 'adds': [{'id': 'messages', 'adds': [Thing(42)]}]}Changes0.4.0 (2017-06-20)Python 3 supportWhen asking for updates from generation 0, only adds are sent. Never
removals, making this common case more efficient.0.3.0 (2014-08-28)Added achangedmethod to make intent clear when simply recording changes.Fixed: exceptions were raised when objects added to generational
sets quacked a little like generational sets.0.2.0 (2014-08-10)Improved subset APIs:No longer need to specify superset flag.Can have set and non-set children.A subset can be created without a parent and the parent will be
set when it’s added to a containing set.0.1.2 (2014-06-09)Fixed: Internal data structures were misshandled when there were morethan the maximum number of removals.(Release 0.1.1 was made in error.)0.1.0 (2014-06-08)Initial release