pysyncml 0.1 documentation

Module: pysyncml.change.tracker

«  Module: pysyncml.change.merger   ::   Contents   ::   Module: pysyncml.cli  »

Module: pysyncml.change.tracker

The pysyncml.change.tracker is a helper package that provides routines to generate and parse change-specs that are compliant with pysyncml’s change tracking system.

class pysyncml.change.tracker.AttributeChangeTracker(changeSpec=None, *args, **kw)[source]

A ChangeTracker implementation that manages changes made to attributes that are completely independent of each other.

Initializes this AttributeChangeTracker with the provided changeSpec, which is expected to be in the same format as what would have been returned by a call to str() on this object. The change-spec will look similar to:

add:tel-home|mod:firstname@m68b329d...,lastname@mh4d9...|del:tel-pager@mba45...

If changeSpec is not specified, this AttributeChangeTracker will start assuming no prior changes were made to any fields.

isChange(fieldname, changeType, newValue=None, isMd5=False)[source]

Implements as specified in ChangeTracker.isChange() where the changeObject is simply the fieldname that needs to be updated with the newValue. Currently, this is always equal to fieldname.

class pysyncml.change.tracker.ChangeTracker(changeSpec=None, *args, **kw)[source]

A ChangeTracker is an abstract interface to help with generating, parsing, and managing pysyncml change-specs. See Matching, Merging, and Conflict Resolution for details on change-spec handling.

append(fieldname, changeType, initialValue=None, isMd5=False)[source]

Add a change to this ChangeTracker.

Parameters:
  • fieldname – The item attribute that was changed in some way. The type of fieldname is dependent on which subclass of ChangeTracker is being used.
  • changeType – The type of change that was applied to fieldname, which can be one of pysyncml.ITEM_ADDED, pysyncml.ITEM_MODIFIED, or pysyncml.ITEM_DELETED.
  • initialValue – For non-ADDED change types, specifies the initial value of the field, before the change was applied. Note that if the initialValue is very large, an MD5 checksum can be provided instead, in which case isMd5 should be set to True.
  • isMd5 – Specifies whether initialValue is an MD5 checksum or not. For large values of initialValue the ChangeTrackers will automatically convert it to a checksum, but this allows the caller to potentially do some additional optimizations.
getChangeSpec()[source]

Returns a string-representation of the changes recorded by this ChangeTracker that were reported since construction (or calls to pushChangeSpec()) by calls to append() or update().

This is similar to, but distinct from, getFullChangeSpec().

getFullChangeSpec()[source]

Returns a string-representation of all changes recorded by this ChangeTracker, including those provided in the constructor and any calls to pushChangeSpec(). Note that this is usually NOT what you are looking for when reporting changes to the pysyncml framework – for that, see getChangeSpec().

isChange(fieldname, changeType, newValue=None, isMd5=False)[source]

Checks to see if the specified field should be changed to the newValue, first checking to see if the change conflicts with the change-spec stored by this ChangeTracker. IMPORTANT: the changeType is relative to the current local value, as recorded by the changes stored by this tracker from the initial value.

See update() for a layer above.

This method will terminate in one of the following three ways:

  • returns None:

    The newValue is actually outdated, but does not conflict. The field should be left as-is.

  • returns changeObject:

    If any form of change should be applied as a result of this change request, then changeObject will be non-None and will define how. The exact nature of the object is ChangeTracker subclass dependent.

  • raises pysyncml.ConflictError:

    The newValue conflicts with a change made by another source and should be handled by following conflict resolution policy.

For example, if two clients and a server are tracking changes made to the following fields:

initial values (on server, client 1 and client 2):
  field "a" => "A"    (will not change)
  field "b" => "B"    (will be modified by client 1)
  field "c" => "C"    (will be deleted by client 1)
  field "d" => "D"    (will be modified by client 2)
  field "e" => "E"    (will be a conflict)
  field "f" => "F"    (will be modified identically)

client 1 changes:
  does not alter field "a"
  modifies field "b" to "Bmod"
  deletes field "c"
  does not alter field "d"
  deletes field "e"
  modifies field "f" to "Fmod"

client 2 changes (simultaneous to client 1 changes):
  does not alter field "a"
  does not alter field "b"
  does not alter field "c"
  modifies field "d" to "Dmod"
  modifies field "e" to "Emod"
  modifies field "f" to "Fmod"

client 1 synchronizes with server ==> server values:
  field "b" => "Bmod"
  deletes fields "c" and "e"
  field "f" => "Fmod"
  change-spec for client 2: "mod:b@vB,f@vF|del:c@vC,e@vE"

when client 2 synchronizes, the framework detects a conflict and
requests a merge attempt by the agent. the agent then compares the
current values and those presented by client 2 and determines:
  - field "a" is unchanged
  - field "b" differs: changed to "B"
  - field "c" differs: added as "C"
  - field "d" differs: change to "Dmod"
  - field "e" differs: added as "Dmod"
  - field "f" is unchanged

for the fields that are mismatches (i.e. fields "b", "c", "d",
and "e"), the agent checks with this change tracker ("ct") to
see if it was actually a change, and if so, if it conflicts:

  - ct.isChange('b', 'B')    ==> None
  - ct.isChange('c', 'C')    ==> None
  - ct.isChange('d', 'Dmod') ==> 'd'
  - ct.isChange('e', 'Emod') ==> raises ConflictError

Note that this assumes that the caller will have verified that the remote currentValue is not equal to the local active value - i.e. that there is some difference between the fieldname values, and a resolution needs to be negotiated.

Parameters:newValue – A string representing the value that is being tested for conflicts or outdated-ness.
update(fieldname, localValue, remoteValue)[source]

Returns the appropriate current value, based on the changes recorded by this ChangeTracker, the value stored by the server (localValue), and the value stored by the synchronizing client (remoteValue). If remoteValue conflicts with changes stored locally, then a pysyncml.ConflictError is raised.

If a change needs to be applied because remoteValue has been updated, then the new value will be returned, and this ChangeTracker will be updated such that a call to getChangeSpec() will incorporate the change.

Parameters:
  • fieldname – The name of the fieldname being evaluated.
  • localValue – The value of the field as stored by the server, usually the one that also stored the current change-spec. If localValue is None, then it is assumed that the field was potentially added (this will first be verified against the stored change-spec).
  • remoteValue – The new value being presented that may or may not be a source of conflict. If remoteValue is None, then it is assumed that the field was potentially deleted (this will first be verified against the stored change-spec).
class pysyncml.change.tracker.ListChangeTracker(changeSpec=None, *args, **kw)[source]

A ChangeTracker implementation that manages changes made to an ordered sequence of elements. This tracker is aware that (and adjusts for the fact that) the addition or deletion of an element in the list can impact the indexing of elements that come sequentially after the change. The most common use of the ListChangeTracker is to track changes to text that has been broken down into sequences of lines or words.

Initializes this ListChangeTracker with the provided changeSpec, which is expected to be in the same format as what would have been returned by a call to str() on this object. The change-spec will look similar to:

2:a,1:M68b329d...,1:mh4d9,2:Dba45...,3:a

If changeSpec is not specified, this ListChangeTracker will start assuming no prior changes were made to any content and will expect changes to be reported via pushChange().

append(listIndex, changeType, initialValue=None, isMd5=False)[source]

Adds a change spec to the current list of changes. The listIndex represents the line number (in multi-line mode) or word number (in single-line mode), and must be INCLUSIVE of both additions and deletions.

isChange(listIndex, changeType, newValue=None, isMd5=False, token=None)[source]

Implements as specified in ChangeTracker.isChange() where the changeObject is a two-element tuple. The first element is the index at which the change should be applied, and the second element is an abstract token that should be passed back into this method at every iteration.

IMPORTANT: unlike the AttributeChangeTracker, the ListChangeTracker’s isChange() method is sensitive to order (which is why it uses the changeObject and token mechanisms. Therefore, it is important to call isChange() sequentially with all changes in the order that they occur in the change list.

«  Module: pysyncml.change.merger   ::   Contents   ::   Module: pysyncml.cli  »