Syncrepl Client Callbacks

When a Syncrepl instance wants to tell you about something, it uses a callback.

The complete list of callbacks, their parameters, and what they mean is defined in BaseCallback. Syncrepl doesn’t care if your object uses instance methods, class methods, or static methods, so long as your callback is able to accept the parameters provided.

In addition to BaseCallback, LoggingCallback is provided as a way to log the callbacks being received.

Both BaseCallback and LoggingCallback are described below.

BaseCallback

class syncrepl_client.callbacks.BaseCallback[source]

BaseCallback is a class containing all of the callbacks which syncrepl_client.Syncrepl may call. It is implemented as a new-style class, with class methods (although Syncrepl doesn’t care).

This class exists for two reasons:

  • It documents each callback, the parameters the callback receives, and what the callback means.
  • It gives you a useful base class to sink unwanted callbacks. If you only care about certain callbacks, you can implement them in your class, and let all the other callbacks percolate up to this class, where they are received and ignored.

Another reason for using classes is because they can be stacked. For example, if you want to handle callbacks, but you also want them to be logged, you can have your callback class use LoggingCallback as a base class, and then set the LoggingCallback‘s dest attribute to the log sink (which could be stdout, or another file handle).

Note

If your class needs any kind of setup or initalization before it can receive callbacks, it is suggested that you implement your callbacks as instance methods, and then use normal class instantiation to do your preparation, before handing off the instance to Syncrepl‘s constructor.

classmethod bind_complete(ldap, cursor)[source]

Called to mark a successful bind to the LDAP server.

Parameters:
  • ldap (ldap.LDAPObject) – The LDAP object.
  • cursor (sqlite3.Cursor) – A mid-transaction database cursor.
Returns:

None - any returned value is ignored.

This callback is used to indicate a successful bind, and to give you one opportunity to interact with the LDAP server, before the connection is taken over by the syncrepl search.

For example, if you want to record the bind DN (which you might not know, if you are doing things like a SASL bind), or you want to retrieve the schema stored on the server, this is the time to do it!

This is the very first callback to be called. Once the callback completes, the syncrepl search will begin, and other callbacks will start coming in.

Note

Once the callback has completed, there is no guarantee that ldap will still be a valid reference.

Warning

If you start any asynchronous operations (which includes searches), those operations must be completed before this callback returns.

Warning

Please do not unbind ldap from the LDAP server!

Warning

Once the callback completes, this LDAP connection will be used for the syncrepl search. No other operations will be allowed! If you want to communicate with the LDAP server after this callback completes, you will need to set up a separate LDAP connection.

cursor provides access to the underlying database, as described in DBInterface. If you are storing your own data in syncrepl_client’s database, you can use this cursor to make appropriate changes to your own tables. That will ensure your database changes are saved at the same time as ours!

Warning

Do not commit the in-progress transaction! The commit will take place automatically, once your callback returns.

classmethod refresh_done(items, cursor)[source]

Called to mark the end of the refresh phase.

Parameters:
  • items (dict) – The items currently in the directory.
  • cursor (sqlite3.Cursor) – A mid-transaction database cursor.
Returns:

None – any returned value is ignored.

When receiving this callback, you know that the refresh phase has completed, and your view of the directory is now consistent with the LDAP server (at least, the part of the directory which matches your search and your access).

items is a dictionary (or, an object which behaves like a dictionary) where the keys are DNs and the values are dicts of attributes & their values. Every item in items is present in the directory at the time this callback started.

Note

items is read-only. Any attempt to add, change, or delete and item will cause an AttributeError to be raised.

Warning

The content items is guaranteed to be consistent only inside this callback. Once this callback returns, any attempts to access items again will result in undefined behavior.

cursor provides access to the underlying database, as described in DBInterface. If you are storing your own data in syncrepl_client’s database, you can use this cursor to make appropriate changes to your own tables. That will ensure your database changes are saved at the same time as ours!

Warning

Do not commit the in-progress transaction! The commit will take place automatically, once your callback returns.

If you need to do any sort of synchronization with anyone else, this is the best time to do it. Once you return from this callback, the persist phase will begin. The first database commit will also take place.

Note

Once you return from this callback, it may be some time before you see anything happen (either another callback, or syncrepl_client.Syncrepl.poll() returning. That is because the first database commit is taking place, and there may be _many_ changes to commit!

If you are operating in refresh-only mode, then as soon as this callback completes, syncrepl_client.Syncrepl.poll() will return False. It is then safe to call unbind().

classmethod record_add(dn, attrs, cursor)[source]

Called to indicate the addition of a new LDAP record.

Parameters:
  • dn (str) – The DN of the added record.
  • attrs (Dict of lists of bytes) – The record’s attributes.
  • cursor (sqlite3.Cursor) – A mid-transaction database cursor.
Returns:

None - any returned value is ignored.

Warning

attrs is passed by reference. If you modify the dictionary—or its contents—in any way, you will pay for it later!

This callback can happen in all modes, and in all phases, to indicate that an entry has been added to your view of the search results. In refresh-only mode, and the refresh phase of refresh-and-perist mode, the addition may have taken place at any time since your last update. In the persist phase of refresh-and-persist mode, a new entry has just been added—or modified—such that it matches your search.

Attributes which are not present in the record will not present in attrs. Dict keys are attribute names, and dict values are arrays (to support multi-valued attributes).

Note

Just because the dict values are arrays, does not mean that all attributes are multi-valued. The LDAP client does not know which attributes are single- and which are multi-valued, so it assumes that all are multi-valued.

Also, all attribute values will come in as (in Python 2) str objects or (in Python 3) bytes objects.

To learn which attributes are single- or multi-valued, and to learn the type (or, in LDAP terms, the syntax) of an attribute, you need to look at the schema, possibly using ldap.schema.

cursor provides access to the underlying database, as described in DBInterface. If you are storing your own data in syncrepl_client’s database, you can use this cursor to make appropriate changes to your own tables. That will ensure your database changes are saved at the same time as ours!

Warning

Do not commit the in-progress transaction! The commit will take place automatically, once your callback returns.

classmethod record_delete(dn, cursor)[source]

Called to indicate the deletion of an LDAP record.

Parameters:
  • dn (str) – The DN of the deleted record.
  • cursor (sqlite3.Cursor) – A mid-transaction database cursor.
Returns:

None - any returned value is ignored.

This callback can happen in all modes, and in all phases, to indicate that an entry has been either been deleted, or that it no longer matches your search. In refresh-only mode, and the refresh phase of refresh-and-perist mode, the deletion may have taken place at any time since your last update. In the persist phase of refresh-and-persist mode, the entry has just disappeared.

cursor provides access to the underlying database, as described in DBInterface. If you are storing your own data in syncrepl_client’s database, you can use this cursor to make appropriate changes to your own tables. That will ensure your database changes are saved at the same time as ours!

Warning

Do not commit the in-progress transaction! The commit will take place automatically, once your callback returns.

classmethod record_rename(old_dn, new_dn, cursor)[source]

Called to indicate a change in DN.

Parameters:
  • old_dn (str) – The old DN.
  • new_dn (str) – The new DN.
  • cursor (sqlite3.Cursor) – A mid-transaction database cursor.
Returns:

None - any returned value is ignored.

This callback happens when an entry’s DN changes.

This callback can happen in all modes, and in all phases, to indicate that an entry’s DN has been changed. In refresh-only mode, and the refresh phase of refresh-and-perist mode, the change may have taken place at any time since your last update. In the persist phase of refresh-and-persist mode, the entry has just changed.

cursor provides access to the underlying database, as described in DBInterface. If you are storing your own data in syncrepl_client’s database, you can use this cursor to make appropriate changes to your own tables. That will ensure your database changes are saved at the same time as ours!

Warning

Do not commit the in-progress transaction! The commit will take place automatically, once your callback returns.

You should expect a call to record_change() shortly after this callback completes.

classmethod record_change(dn, old_attrs, new_attrs, cursor)[source]

Called to indicate a change in attributes.

Parameters:
  • dn (str) – The DN of the changed record.
  • old_attrs (Dict of lists of bytes) – The old attributes.
  • new_attrs (Dict of lists of bytes) – The new attributes.
  • cursor (sqlite3.Cursor) – A mid-transaction database cursor.
Returns:

None - any returned value is ignored.

This callback happens when an entry has changed.

You are provided with the old attributes, and the new attributes. It is up to you to determine what the changes are (if you care).

Note

If you look back at record_add(), see the note about changing attrs, and how it will come back to bite you? Well, here’s where it comes back to bite you!

Warning

new_attrs is passed by reference. If you modify the dictionary—or its contents—in any way; you will pay for it later!

This callback can happen in all modes, and in all phases, to indicate that an entry has been changed. In refresh-only mode, and the refresh phase of refresh-and-perist mode, the change may have taken place at any time since your last update. In the persist phase of refresh-and-persist mode, the entry has just changed.

Note

Just because the dict values are arrays, does not mean that all attributes are multi-valued. The LDAP client does not know which attributes are single- and which are multi-valued, so it assumes that all are multi-valued.

Also, all attribute values will come in as (in Python 2) str objects or (in Python 3) bytes objects.

To learn which attributes are single- or multi-valued, and to learn the type (or, in LDAP terms, the syntax) of an attribute, you need to look at the schema, possibly using ldap.schema.

cursor provides access to the underlying database, as described in DBInterface. If you are storing your own data in syncrepl_client’s database, you can use this cursor to make appropriate changes to your own tables. That will ensure your database changes are saved at the same time as ours!

Warning

Do not commit the in-progress transaction! The commit will take place automatically, once your callback returns.

classmethod cookie_change(cookie)[source]

Called to log a change in Syncrepl cookie.

Parameters:cookie (str) – The new Syncrepl cookie.

:return None - any returned value is ignored.

This callback happens any time the LDAP server sends us a new Syncrepl cookie.

The Syncrepl cookie is an opaque string, which we send to the LDAP server at the start of a Syncrepl search. If we do not have one, then the LDAP server knows to send us everything. If we do have one, then the LDAP server can use that to know how far behind we are, and to send us just the changes.

This callback can happen in all modes, and in all phases, as it is up to the LDAP server to give us a new Syncrepl cookie, when it is appropriate to do so.

classmethod debug(message)[source]

Called to log debug messages.

Parameters:message (str) – A message of some sort.
Returns:None - any returned value is ignored.

This method doesn’t have much of a use. It’s just a way for Syncrepl to log debug messages. There’s no guarantee that you’ll get anything meaningful, or anything at all.

The safest thing to do is to just pass this method. Or, subclass BaseCallback.

LoggingCallback

class syncrepl_client.callbacks.LoggingCallback[source]

LoggingCallback is a callback class which logs each callback. It is useful for debugging purposes, as the output is not meant to be machine-readable.

Each callback will cause messages to be printed to the file set in dest. For the bind_complete() callback, the bind DN is printed. For callbacks containing DNs, the DNs are printed. For callbacks containing attribute dictionaries, each dictionary’s contents are printed.

For a list of callbacks, and what they mean, see BaseCallback.

dest = <_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'>

The log destination.

This can be anything which can be used in print()‘s file parameter.

Defaults to sys.stdout.