Package: zc.zk
The zc.zk package provides support for registering and discovering
services with ZooKeeper. It also provides support for defining
services with a tree-based model and syncing the model with ZooKeeper.The use cases are:Register a server providing a service.Get the addresses of servers providing a service.Get and set service configuration data.Model system architecture as a tree.Important note for zc.zk 1.x usersVersion 2 is mostly. but not entirely backward compatible.Although the goal of version 1 was primarily service registration
and discovery, it also provided a high-level ZooKeeper API.Kazoois a much better high-level
interface for ZooKeeper because:It isn’t based on the buggy ZooKeeper C interface and Python
extension.It doesn’t assume that ephemeral nodes should be reestablished
when a session expires and is recreated.zc.zk 2 uses Kazoo.This package makes no effort to support Windows.  (Patches to support
Windows might be accepted if they don’t add much complexity.)ContentsInstallationInstantiating a ZooKeeper helperRegister a server providing a serviceGet the addresses of service providersGet service configuration dataUpdating node propertiesGetting property data without tracking changesTree-definition format, import, and exportRecursive deletionSymbolic linksProperty linksNode deletionRegistering a server with a blank hostnameServer-registration eventsZooKeeper Session Managementzookeeper_export scriptzookeeper_import scriptPropery-update scriptIterating over a treeGraph analysisReferencezc.zk.ZooKeeperzc.zk.Childrenzc.zk.PropertiesOther module attributesTesting supportChange History2.1.0 (2014-10-20)2.0.1 (2014-08-28)2.0.0 (2014-06-02)2.0.0a7 (2014-02-12)2.0.0a6 (2014-02-10)2.0.0a5 (2014-01-30)2.0.0a4 (2014-01-13)2.0.0a3 (2014-01-08)2.0.0a2 (2014-01-06)2.0.0a1 (2014-01-06)InstallationYou can install this as you would any other distribution.
It requires the kazoo Python ZooKeeper interface.Instantiating a ZooKeeper helperTo use the helper API, create a ZooKeeper instance:>>> import zc.zk
>>> zk = zc.zk.ZooKeeper('zookeeper.example.com:2181')The ZooKeeper constructor takes a ZooKeeper connection string, which is
a comma-separated list of addresses of the formHOST:PORT.  It
defaults to the value of theZC_ZK_CONNECTION_STRINGenvironment
variable, if set, or'127.0.0.1:2181'if not, which is convenient
during development.You can also pass a kazoo client object, instead of a connection string.Register a server providing a serviceTo register a server, use theregistermethod, which takes
a service path and the address a server is listing on:>>> zk.register('/fooservice/providers', ('192.168.0.42', 8080))registercreates a read-only ephemeral ZooKeeper node as a
child of the given service path.  The name of the new node is (a
string representation of) the given address. This allows clients to
get the list of addresses by just getting the list of the names of
children of the service path.Ephemeral nodes have the useful property that they’re automatically
removed when a ZooKeeper session is closed or when the process
containing it dies.  De-registration is automatic.When registering a server, you can optionally provide server (node)
data as additional keyword arguments to register.  By default,
the process id is set as thepidproperty.  This is useful to
tracking down the server process.  In addition, an event is generated,
providing subscribers to add properties as a server is being
registered. (SeeServer-registration events.)Get the addresses of service providersGetting the addresses providing a service is accomplished by getting the
children of a service node:>>> addresses = zk.children('/fooservice/providers')
>>> sorted(addresses)
['192.168.0.42:8080']Thechildrenmethod returns an iterable of names of child nodes of
the node specified by the given path.  The iterable is automatically
updated when new providers are registered:>>> zk.register('/fooservice/providers', ('192.168.0.42', 8081))
>>> sorted(addresses)
['192.168.0.42:8080', '192.168.0.42:8081']You can also get the number of children withlen:>>> len(addresses)
2You can call the iterable with a callback function that is called
whenever the list of children changes:>>> @zk.children('/fooservice/providers')
... def addresses_updated(addresses):
...     print 'addresses changed'
...     print sorted(addresses)
addresses changed
['192.168.0.42:8080', '192.168.0.42:8081']The callback is called immediately with the children.  When we add
another child, it’ll be called again:>>> zk.register('/fooservice/providers', ('192.168.0.42', 8082))
addresses changed
['192.168.0.42:8080', '192.168.0.42:8081', '192.168.0.42:8082']Get service configuration dataYou get service configuration data by getting properties associated with a
ZooKeeper node.  The interface for getting properties is similar to the
interface for getting children:>>> data = zk.properties('/fooservice')
>>> data['database']
u'/databases/foomain'
>>> data['threads']
1Thepropertiesmethod returns a mapping object that provides access to
node data.  (ZooKeeper only stores string data for nodes.zc.zkprovides a higher-level data interface by storing JSON strings.)The properties objects can be called with callback functions and used
as function decorators to get update notification:>>> @zk.properties('/fooservice')
... def data_updated(data):
...     print 'data updated'
...     for item in sorted(data.items()):
...         print '%s: %r' % item
data updated
database: u'/databases/foomain'
favorite_color: u'red'
threads: 1The callback is called immediately. It’ll also be called when data are
updated.Updating node propertiesYou can update properties by calling theupdatemethod:>>> thread_info = {'threads': 2}
>>> data.update(thread_info, secret='123')
data updated
database: u'/databases/foomain'
favorite_color: u'red'
secret: u'123'
threads: 2You can also set individual properties:>>> data['threads'] = 1
data updated
database: u'/databases/foomain'
favorite_color: u'red'
secret: u'123'
threads: 1If you call thesetmethod, keys not listed are removed:>>> data.set(threads= 3, secret='1234')
data updated
secret: u'1234'
threads: 3Bothupdateandsetcan take data from a positional data argument, or
from keyword parameters.  Keyword parameters take precedent over the
positional data argument.Getting property data without tracking changesSometimes, you want to get service data, but don’t want to watch for
changes. If you passwatch=Falsetoproperties, Then properties
won’t track changes.  In this case, you can’t set callback functions,
but you can still update data.Tree-definition format, import, and exportYou can describe a ZooKeeper tree using a textual tree
representation. You can then populate the tree by importing the
representation.  Heres an example:/lb : ipvs
  /pools
    /cms
      # The address is fixed because it's
      # exposed externally
      address = '1.2.3.4:80'
      providers -> /cms/providers
    /retail
      address = '1.2.3.5:80'
      providers -> /cms/providers

/cms : z4m cms
  threads = 3
  /providers
  /databases
    /main
      /providers

/retail : z4m retail
  threads = 1
  /providers
  /databases
    main -> /cms/databases/main
    /ugc
      /providersThis example defines a tree with 3 top nodes,lbandcms, andretail.  Theretailnode has two sub-nodes,providersanddatabasesand a propertythreads.The/retail/databasesnode has symbolic link,mainand augcsub-node.  The symbolic link is implemented as a property named
`` We’ll say more about symbolic links in a later section.Thelb,cmsandretailnodes havetypes.  A type is
indicated by following a node name with a colon and a string value.
The string value is used to populate atypeproperty.  Types are
useful to document the kinds of services provided at a node and can be
used by deployment tools to deploy service providers.You can import a tree definition with theimport_treemethod:>>> zk.import_tree(tree_text)This imports the tree at the top of the ZooKeeper tree.We can also export a ZooKeeper tree:>>> print zk.export_tree(),
/cms : z4m cms
  threads = 3
  /databases
    /main
      /providers
  /providers
/fooservice
  secret = u'1234'
  threads = 3
  /providers
/lb : ipvs
  /pools
    /cms
      address = u'1.2.3.4:80'
      providers -> /cms/providers
    /retail
      address = u'1.2.3.5:80'
      providers -> /cms/providers
/retail : z4m retail
  threads = 1
  /databases
    main -> /cms/databases/main
    /ugc
      /providers
  /providersNote that when we export a tree:The special reserved top-level zookeeper node is omitted.Ephemeral nodes are omitted.Each node’s information is sorted by type (properties, then links,then sub-nodes) and then by name,You can export just a portion of a tree:>>> print zk.export_tree('/fooservice'),
/fooservice
  secret = u'1234'
  threads = 3
  /providersYou can optionally see ephemeral nodes:>>> print zk.export_tree('/fooservice', ephemeral=True),
/fooservice
  secret = u'1234'
  threads = 3
  /providers
    /192.168.0.42:8080
      pid = 9999
    /192.168.0.42:8081
      pid = 9999
    /192.168.0.42:8082
      pid = 9999We can import a tree over an existing tree and changes will be
applied.  Let’s update our textual description:/lb : ipvs
  /pools
    /cms
      # The address is fixed because it's
      # exposed externally
      address = '1.2.3.4:80'
      providers -> /cms/providers

/cms : z4m cms
  threads = 4
  /providers
  /databases
    /main
      /providersand re-import:>>> zk.import_tree(tree_text)
extra path not trimmed: /lb/pools/retailWe got a warning about nodes left over from the old tree.  We can see
this if we look at the tree:>>> print zk.export_tree(),
/cms : z4m cms
  threads = 4
  /databases
    /main
      /providers
  /providers
/fooservice
  secret = u'1234'
  threads = 3
  /providers
/lb : ipvs
  /pools
    /cms
      address = u'1.2.3.4:80'
      providers -> /cms/providers
    /retail
      address = u'1.2.3.5:80'
      providers -> /cms/providers
/retail : z4m retail
  threads = 1
  /databases
    main -> /cms/databases/main
    /ugc
      /providers
  /providersIf we want to trim these, we can add atrimoption.  This is a
little scary, so we’ll use the dry-run option to see what it’s going
to do:>>> zk.import_tree(tree_text, trim=True, dry_run=True)
would delete /lb/pools/retail.If we know we’re not trimming things and want to avoid a warning, we
can use trim=False:>>> zk.import_tree(tree_text, trim=False)We can see that this didn’t trim by using dry-run again:>>> zk.import_tree(tree_text, trim=True, dry_run=True)
would delete /lb/pools/retail.We do want to trim, so we use trim=True:>>> zk.import_tree(tree_text, trim=True)
>>> print zk.export_tree(),
/cms : z4m cms
  threads = 4
  /databases
    /main
      /providers
  /providers
/fooservice
  secret = u'1234'
  threads = 3
  /providers
/lb : ipvs
  /pools
    /cms
      address = u'1.2.3.4:80'
      providers -> /cms/providers
/retail : z4m retail
  threads = 1
  /databases
    main -> /cms/databases/main
    /ugc
      /providers
  /providersNote that nodes containing (directly or recursively) ephemeral nodes
will never be trimmed.  Also node that top-level nodes are never
automatically trimmed.  So we weren’t warned about the unreferenced
top-level nodes in the import.Recursive deletionZooKeeper only allows deletion of nodes without children.
Thedelete_recursivemethod automates removing a node and all of
it’s children.If we want to remove theretailtop-level node, we can use
delete_recursive:>>> zk.delete_recursive('/retail')
>>> print zk.export_tree(),
/cms : z4m cms
  threads = 4
  /databases
    /main
      /providers
  /providers
/fooservice
  secret = u'1234'
  threads = 3
  /providers
/lb : ipvs
  /pools
    /cms
      address = u'1.2.3.4:80'
      providers -> /cms/providersBt default,delete_recursivewon’t delete ephemeral nodes, or
nodes that contain them:>>> zk.delete_recursive('/fooservice')
Not deleting /fooservice/providers/192.168.0.42:8080 because it's ephemeral.
Not deleting /fooservice/providers/192.168.0.42:8081 because it's ephemeral.
Not deleting /fooservice/providers/192.168.0.42:8082 because it's ephemeral.
/fooservice/providers not deleted due to ephemeral descendent.
/fooservice not deleted due to ephemeral descendent.You can use theforceoption to force ephemeral nodes to be
deleted.Symbolic linksZooKeeper doesn’t have a concept of symbolic links, butzc.zkprovides a convention for dealing with symbolic links.  When trying to
resolve a path, if a node lacks a child, but has a property with a
name ending in'->', the child will be found by following the
path in the property value.Theresolvemethod is used to resolve a path to a real path:>>> zk.resolve('/lb/pools/cms/providers')
u'/cms/providers'In this example, the link was at the endpoint of the virtual path, but
it could be anywhere:>>> zk.register('/cms/providers', '1.2.3.4:5')
>>> zk.resolve('/lb/pools/cms/providers/1.2.3.4:5')
u'/cms/providers/1.2.3.4:5'Note a limitation of symbolic links is that they can be hidden by
children.  For example, if we added a real node, at/lb/pools/cms/provioders, it would shadow the link.children,properties, andregisterwill
automatically useresolveto resolve paths.When thechildrenandpropertiesare used for a node, the
paths they use will be adjusted dynamically when paths are removed.
To illustrate this, let’s get children of/cms/databases/main:>>> main_children = zk.children('/cms/databases/main')
>>> main_children.path
'/cms/databases/main'
>>> main_children.real_path
'/cms/databases/main'ChildrenandPropertiesobjects have apathattribute that
has the value passed to thechildrenorpropertiesmethods. They have areal_pathattribute that contains the path
after resolving symbolic links.  Let’s suppose we want to move the
database node to ‘/databases/cms’.  First we’ll export it:>>> export = zk.export_tree('/cms/databases/main', name='cms')
>>> print export,
/cms
  /providersNote that we used the exportnameoption to specify a new name for
the exported tree.Now, we’ll create a databases node:>>> zk.create('/databases')
u'/databases'And import the export:>>> zk.import_tree(export, '/databases')
>>> print zk.export_tree('/databases'),
/databases
  /cms
    /providersNext, we’ll create a symbolic link at the old location. We can use thelnconvenience method:>>> zk.ln('/databases/cms', '/cms/databases/main')
>>> zk.get_properties('/cms/databases')
{u'main ->': u'/databases/cms'}Now, we can remove/cms/databases/mainandmain_childrenwill
be updated:>>> zk.delete_recursive('/cms/databases/main')
>>> main_children.path
'/cms/databases/main'
>>> main_children.real_path
u'/databases/cms'If we update/databases/cms,main_childrenwill see the
updates:>>> sorted(main_children)
['providers']
>>> _ = zk.delete('/databases/cms/providers')
>>> sorted(main_children)
[]Symbolic links can be relative. If a link doesn’t start with a slash,
it’s interpreted relative to the node the link occurs in.  The special
names.and..have their usual meanings.So, in:/a
  /b
    l -> c
    l2 -> ../c
    /c
  /cThe link at/a/b/lresolves to/a/b/cand/a/b/l2resolves
to/a/c.Property linksIn addition to symbolic links between nodes, you can have links
between properties.  In our earlier example, both the/cmsand/fooservicenodes hadthreadsproperties:/cms : z4m cms
  threads = 4
  /databases
    /main
      /providers
  /providers
/fooservice
  secret = u'1234'
  threads = 3
  /providers
/lb : ipvs
  /pools
    /cms
      address = u'1.2.3.4:80'
      providers -> /cms/providersIf we wanted/cmsto have the samethreadssettings, we could
use a property link:/cms : z4m cms
  threads => /fooservice threads
  /databases
    /main
      /providers
  /providers
/fooservice
  secret = u'1234'
  threads = 3
  /providers
/lb : ipvs
  /pools
    /cms
      address = u'1.2.3.4:80'
      providers -> /cms/providersProperty links are indicated with=>. The value is a node path and
optional property name, separated by whitespace.  If the name is
ommitted, then the refering name is used.  For example, the name could
be left off of the property link above.Node deletionIf a node is deleted andChildrenorPropertiesinstances have
been created for it, and the paths they were created with can’t be
resolved using symbolic links, then the instances’ data will be
cleared.  Attempts to update properties will fail.  If callbacks have
been registered, they will be called without arguments, if possible.
It would be bad, in practice, to remove a node that processes are
watching.Registering a server with a blank hostnameIt’s common to use an empty string for a host name when calling bind
to listen on all IPv4 interfaces.  If you pass an address with an
empty host toregisterandnetifacesis installed, then
all of the non-local IPv4 addresses[1](for the given port) will be
registered.If there are no non-local interfaces (not connected to network), then
the local IPV4 interface will be registered.If netifaces isn’t installed and you pass an empty host
name, then the fully-qualified domain name, as returned bysocket.getfqdn()will be used for the host.Server-registration eventsWhenregisteris called, azc.zk.RegisteringServerevent is emmitted with a properties attribute that can be updated by
subscribers prior to creating the ZooKeeper ephemeral node.  This
allows third-party code to record extra server information.Events are emitted by passing them tozc.zk.event.notify. Ifzope.eventis installed, thenzc.zk.event.notifyis an alias
forzope.event.notify, otherwise,zc.zk.event.notifyis an
empty function that can be replaced by applications.ZooKeeper Session ManagementKazoo takes care of reestablishing ZooKeeper sessions. Watches created
with thechildrenandpropertiesmethods are reestablished when
new sessions are established.zc.zkalso recreates ephemeral
nodes created viaregister.zookeeper_export scriptThezc.zkpackage provides a utility script for exporting a
ZooKeeper tree:$ zookeeper_export -e zookeeper.example.com:2181 /fooservice
/fooservice
  secret = u'1234'
  threads = 3
  /providers
    /192.168.0.42:8080
      pid = 9999
    /192.168.0.42:8081
      pid = 9999
    /192.168.0.42:8082
      pid = 9999The export script provides the same features as theexport_treemethod. Use the--helpoption to see how to use it.zookeeper_import scriptThezc.zkpackage provides a utility script for importing a
ZooKeeper tree.  So, for example, given the tree:/provision
  /node1
  /node2In the filemytree.txt, we can import the file like this:$ zookeeper_import zookeeper.example.com:2181 mytree.txt /fooserviceThe import script provides the same features as theimport_treemethod, with the exception that it provides less flexibility for
specifing access control lists. Use the--helpoption to see how
to use it.Propery-update scriptThezc.zkpackage provides a utility script for updating individual
properties:zookeeper_set_property zookeeper.example.com:2181 /fooservice \
    threads=4 debug=True comment='ok'The first argument to the script is the path of the node to be
updated. Any number of additional arguments of the form:NAME=PYTHONEXPRESSIONare provided to supply updates.  If setting
strings, you may have to quote the argument, as in “comment=’a
comment’”.Iterating over a treeThewalkmethod can be used to walk over the nodes in a tree:>>> for path in zk.walk():
...     print path
/
/cms
/cms/databases
/cms/providers
/cms/providers/1.2.3.4:5
/databases
/databases/cms
/fooservice
/fooservice/providers
/fooservice/providers/192.168.0.42:8080
/fooservice/providers/192.168.0.42:8081
/fooservice/providers/192.168.0.42:8082
/fooservice/provision
/fooservice/provision/node1
/fooservice/provision/node2
/lb
/lb/pools
/lb/pools/cms
/zookeeper
/zookeeper/quota

>>> for path in zk.walk('/fooservice'):
...     print path
/fooservice
/fooservice/providers
/fooservice/providers/192.168.0.42:8080
/fooservice/providers/192.168.0.42:8081
/fooservice/providers/192.168.0.42:8082
/fooservice/provision
/fooservice/provision/node1
/fooservice/provision/node2You can omit ephemeral nodes:>>> for path in zk.walk('/fooservice', ephemeral=False):
...     print path
/fooservice
/fooservice/providers
/fooservice/providers/192.168.0.42:8080
/fooservice/providers/192.168.0.42:8081
/fooservice/providers/192.168.0.42:8082
/fooservice/provision
/fooservice/provision/node1
/fooservice/provision/node2You can also get a mutable list of children, which you can mutate:>>> i = zk.walk('/fooservice', children=True)
>>> path, children = i.next()
>>> path, children
('/fooservice', [u'providers', u'provision'])>>> del children[0]
>>> for path in i:
...     print path
/fooservice/provision
/fooservice/provision/node1
/fooservice/provision/node2Modifications to nodes are reflected while traversing:>>> for path in zk.walk('/fooservice'):
...     print path
...     if 'provision' in zk.get_children(path):
...         zk.delete_recursive(path+'/provision')
/fooservice
/fooservice/providers
/fooservice/providers/192.168.0.42:8080
/fooservice/providers/192.168.0.42:8081
/fooservice/providers/192.168.0.42:8082Graph analysisThe textual tree representation can be used to model and analyze a
system architecturte.  You can get a parsed representation of a tree
usingzc.zk.parse_treeto parse a text tree representation
generated by hand for import, or using theexport_treemethod.>>> tree = zc.zk.parse_tree(tree_text)
>>> sorted(tree.children)
['cms', 'lb']
>>> tree.children['lb'].properties
{'type': 'ipvs'}The demo module,zc.zk.graphvisshows how you might generate
system diagrams from tree models.Referencezc.zk.ZooKeeperzc.zk.ZooKeeper([connection_string[,session_timeout[,wait]]])Return a new instance given a ZooKeeper connection string.The connection string defaults to the value of theZC_ZK_CONNECTION_STRINGenvironment variable, if set, otherwise
‘127.0.0.1:2181’ will be used.If a session timeout (session_timeout) isn’t specified, the
ZooKeeper server’s default session timeout is used.  If the
connection to ZooKeeper flaps, setting this to a higher value can
avoid having clients think a server has gone away, when it hasn’t.
The downside of setting this to a higher value is that if a server
crashes, it will take longer for ZooKeeper to notice that it’s
gone.Thewaitflag indicates whether the constructor should wait
for a connection to ZooKeeper.  It defaults to False.If a connection can’t be made, azc.zk.FailedConnectexception
is raised.children(path)Return azc.zk.Childrenfor the path.Note that there is a fair bit of machinery inzc.zk.Childrenobjects to support keeping them up to date, callbacks, and cleaning
them up when they are no-longer used.  If you only want to get the
list of children once, useget_children.close()Close the ZooKeeper session.This should be called when cleanly shutting down servers to more
quickly remove ephemeral nodes.delete_recursive(path[, dry_run[, force[,ignore_if_ephemeral]]])Delete a node and all of it’s sub-nodes.Ephemeral nodes or nodes containing them are not deleted by
default. To force deletion of ephemeral nodes, supply theforceoption with a true value.Normally, a message is printed if a node can’t be deleted because
it’s ephemeral or has ephemeral sub-nodes.  If theignore_if_ephemeraloption is true, the a message isn’t printed
if the node’s path was passed todelete_recursivedirectly.
(This is used byimport_treewhen the only nodes that would be
trimmed are ephemeral nodes.)The dry_run option causes a summary of what would be deleted to be
printed without actually deleting anything.export_tree(path[, ephemeral[,name]])Export a tree to a text representation.pathThe path to export.ephemeralBoolean, defaulting to false, indicating whether to include
ephemeral nodes in the export.  Including ephemeral nodes is
mainly useful for visualizing the tree state.nameThe name to use for the top-level node.This is useful when using export and import to copy a tree to
a different location and name in the hierarchy.Normally, when exporting the root node,/, the root isn’t
included, but it is included if a name is given.import_tree(text[,path='/'[,trim[, acl[,dry_run]]]])Create tree nodes by importing a textual tree representation.textA textual representation of the tree.pathThe path at which to create the top-level nodes.trimBoolean, defaulting to false, indicating whether nodes not in
the textual representation should be removed.aclAn access control-list to use for imported nodes.  If not
specified, then full access is allowed to everyone.dry_runBoolean, defaulting to false, indicating whether to do a dry
run of the import, without applying any changes.is_ephemeral(path)ReturnTrueif the node atpathis ephemeral,``False`` otherwise.ln(source, destination)Create a symbolic link at the destination path pointing to the
source path.If the destination path ends with'/', then the source name is
appended to the destination.print_tree(path='/')Print the tree at the given path.This is just a short-hand for:print zk.export_tree(path, ephemeral=True),properties(path, watch=True)Return azc.zk.Propertiesfor the path.Note that there is a fair bit of machinery inzc.zk.Propertiesobjects to support keeping them up to date, callbacks, and cleaning
them up when they are no-longer used.  If you don’t want to track
changes, passwatch=False.register(path, address, acl=zc.zk.READ_ACL_UNSAFE, **data)Register a server at a path with the address.An ephemeral child node ofpathwill be created with name equal
to the string representation (HOST:PORT) of the given address.addressmust be a host and port tuple.aclis a ZooKeeper access control list.Optional node properties can be provided as keyword arguments.resolve(path)Find the real path for the given path.walk(path)Iterate over the nodes of a tree rooted at path.In addition,ZooKeeperinstances provide shortcuts to the following
kazoo client methods:exists,create,delete,get_children,get, andset.zc.zk.Children__iter__()Return an iterator over the child names.__call__(callable)Register a callback to be called whenever a child node is added or
removed.The callback is passed the children instance when a child node is
added or removed.TheChildreninstance is returned.zc.zk.PropertiesProperties objects provide the usual read-only mapping methods,
__getitem__, __len__, etc..set(data=None, **properties)Set the properties for the node, replacing existing data.The data argument, if given, must be a dictionary or something that
can be passed to thedictconstructor.  Items supplied as
keywords take precedence over items supplied in the data argument.update(data=None, **properties)Update the properties for the node.The data argument, if given, must be a dictionary or something that
can be passed to a dictionary’supdatemethod.  Items supplied
as keywords take precedence over items supplied in the data
argument.__call__(callable)Register a callback to be called whenever a node’s properties are changed.The callback is passed the properties instance when properties are
changed.ThePropertiesinstance is returned.Other module attributeszc.zk.ZKA convenient aliad forzc.zk.ZooKeeperfor people who hate to
type.Testing supportThezc.zk.testingmodule providessetUpandtearDownfunctions that can be used to emulate a ZooKeeper server. To find out
more, use the help function:>>> import zc.zk.testing
>>> help(zc.zk.testing)Change History2.1.0 (2014-10-20)Get the default connection string fromZC_ZK_CONNECTION_STRINGif set.2.0.1 (2014-08-28)Fixed: ZooKeeper operations (including closing ZooKeeper
connections) hung after network failures if ZooKeeper sessions were
lost and ephemeral nodes (for registered services) had to be
re-registered.Fixed: Didn’t properly handle None values for node data returned by
Kazoo 2.0.2.0.0 (2014-06-02)Final release (identical to 2.0.0a7). We’ve used this in production
for several months.2.0.0a7 (2014-02-12)Fixed: The release missed a zcml file helpful for registering
monitoring components.2.0.0a6 (2014-02-10)This release has a number of backward-compatibility changes made after
testing some existing client software with the a5 release.Restored thewaitconstructor flag to keep trying if a connection
fails.Restored therecv_timeoutfor test backward compatibility.Restored the test handle-management mechanism for test
backward-compatibility.Fixed a bug in the way test machinery used internal handles.Restored the create_recursive method for backward compatibility.2.0.0a5 (2014-01-30)Log when sessions are lost and ephemeral nodes are restored.Fixed: Kazoo returns node children as Unicode.zc.zk client applications expect children as
returned by the children to have bytes values and
they use the values to connect sockets.Childrenobjects returned by zc.zk.children now encode
child names using UTF-8.Fixed: zc.zk 2 didn’t accept a value of None for session_timeoutconstructor argument, breaking some old clients.2.0.0a4 (2014-01-13)Fixed: When saving properties in ZooKeeper nodes, empty propertieswere encoded as empty strings.  When Kazoo saves empty strings,
it does so in a way that causes the ZooKeeper C client (or at
least the Python C binding) to see semi-random data, sometimes
including data written previously to other nodes.  This can
cause havoc when data for one node leaks into another.Now, we save empty properties as'{}'.2.0.0a3 (2014-01-08)Renamedget_raw_propertiesback toget_properties, for
backward compatibility, now that we’ve decided not to have a
separate package.Addedensure_pathto the testing client.Updated theZooKeeper.closemethod to allow multiple calls.
(Calls after the first have no effect.)2.0.0a2 (2014-01-06)Fixed packaging bug.2.0.0a1 (2014-01-06)Initial version forked from zc.zk 1.2.0[1]It’s a little more complicated.  If there are non-local
interfaces, then only non-local addresses are registered.  In
normal production, there’s really no point in registering local
addresses, as clients on other machines can’t make any sense of
them. Ifonlylocal interfaces are found, then local addresses
are registered, under the assumption that someone is developing on
a disconnected computer.