New Upstream Snapshot - python-etcd

Ready changes

Summary

Merged new upstream version: 0.4.5+git20170622.1.b227f49 (was: 0.4.5).

Resulting package

Built on 2022-09-19T16:29 (took 2m32s)

The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:

apt install -t fresh-snapshots python3-etcd

Lintian Result

Diff

diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index 3f90b7f..0000000
--- a/.gitignore
+++ /dev/null
@@ -1,15 +0,0 @@
-*.pyc
-
-.installed.cfg
-bin
-develop-eggs
-eggs
-.eggs
-.idea
-*.egg-info
-
-tmp
-build
-dist
-docs
-.coverage
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 2c3ba50..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,23 +0,0 @@
-language: python
-python:
-  - "2.7"
-  - "3.5"
-
-before_install:
-  - ./build_etcd.sh v2.2.0
-  - pip install --upgrade setuptools
-
-# command to install dependencies
-install:
-  - pip install coveralls
-  - pip install coverage
-  - python bootstrap.py
-  - bin/buildout
-
-# command to run tests
-script:
-  PATH=$PATH:./etcd/bin coverage run --source=src/etcd --omit="src/etcd/tests/*" bin/test
-
-after_success: coveralls
-# Add env var to detect it during build
-env: TRAVIS=True
diff --git a/AUTHORS b/AUTHORS
index b12bda9..716c883 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -23,6 +23,7 @@ Jim Rollenhagen
 John Kristensen
 Joshua Conner
 Lars Bahner
+Matthew Barnes
 Matthias Urlichs
 Michal Witkowski
 Mike Place
diff --git a/MANIFEST.in b/MANIFEST.in
index 1e7e568..e34a526 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,2 +1,4 @@
+include AUTHORS
+include LICENSE.txt
 include README.rst
 include NEWS.txt
diff --git a/PKG-INFO b/PKG-INFO
new file mode 100644
index 0000000..2962fd2
--- /dev/null
+++ b/PKG-INFO
@@ -0,0 +1,419 @@
+Metadata-Version: 2.1
+Name: python-etcd
+Version: 0.4.5
+Summary: A python client for etcd
+Home-page: http://github.com/jplana/python-etcd
+Author: Jose Plana
+Author-email: jplana@gmail.com
+License: MIT
+Keywords: etcd raft distributed log api client
+Platform: UNKNOWN
+Classifier: Topic :: System :: Distributed Computing
+Classifier: Topic :: Software Development :: Libraries
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 3
+Classifier: Topic :: Database :: Front-Ends
+License-File: LICENSE.txt
+License-File: AUTHORS
+
+python-etcd documentation
+=========================
+
+A python client for Etcd https://github.com/coreos/etcd
+
+Official documentation: http://python-etcd.readthedocs.org/
+
+.. image:: https://travis-ci.org/jplana/python-etcd.png?branch=master
+   :target: https://travis-ci.org/jplana/python-etcd
+
+.. image:: https://coveralls.io/repos/jplana/python-etcd/badge.svg?branch=master&service=github
+   :target: https://coveralls.io/github/jplana/python-etcd?branch=master
+
+Installation
+------------
+
+Pre-requirements
+~~~~~~~~~~~~~~~~
+
+This version of python-etcd will only work correctly with the etcd server version 2.0.x or later. If you are running an older version of etcd, please use python-etcd 0.3.3 or earlier.
+
+This client is known to work with python 2.7 and with python 3.3 or above. It is not tested or expected to work in more outdated versions of python.
+
+From source
+~~~~~~~~~~~
+
+.. code:: bash
+
+    $ python setup.py install
+    
+From Pypi
+~~~~~~~~~
+
+.. code:: bash
+
+   $ python3.5 -m pip install python-etcd
+
+Usage
+-----
+
+The basic methods of the client have changed compared to previous versions, to reflect the new API structure; however a compatibility layer has been maintained so that you don't necessarily need to rewrite all your existing code.
+
+Create a client object
+~~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: python
+
+    import etcd
+
+    client = etcd.Client() # this will create a client against etcd server running on localhost on port 4001
+    client = etcd.Client(port=4002)
+    client = etcd.Client(host='127.0.0.1', port=4003)
+    client = etcd.Client(host=(('127.0.0.1', 4001), ('127.0.0.1', 4002), ('127.0.0.1', 4003)))
+    client = etcd.Client(host='127.0.0.1', port=4003, allow_redirect=False) # wont let you run sensitive commands on non-leader machines, default is true
+    # If you have defined a SRV record for _etcd._tcp.example.com pointing to the clients
+    client = etcd.Client(srv_domain='example.com', protocol="https")
+    # create a client against https://api.example.com:443/etcd
+    client = etcd.Client(host='api.example.com', protocol='https', port=443, version_prefix='/etcd')
+
+Write a key
+~~~~~~~~~~~
+
+.. code:: python
+
+    client.write('/nodes/n1', 1)
+    # with ttl
+    client.write('/nodes/n2', 2, ttl=4)  # sets the ttl to 4 seconds
+    client.set('/nodes/n2', 1) # Equivalent, for compatibility reasons.
+
+Read a key
+~~~~~~~~~~
+
+.. code:: python
+
+    client.read('/nodes/n2').value
+    client.read('/nodes', recursive = True) #get all the values of a directory, recursively.
+    client.get('/nodes/n2').value
+
+    # raises etcd.EtcdKeyNotFound when key not found
+    try:
+        client.read('/invalid/path')
+    except etcd.EtcdKeyNotFound:
+        # do something
+        print "error"
+
+
+Delete a key
+~~~~~~~~~~~~
+
+.. code:: python
+
+    client.delete('/nodes/n1')
+
+Atomic Compare and Swap
+~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: python
+
+    client.write('/nodes/n2', 2, prevValue = 4) # will set /nodes/n2 's value to 2 only if its previous value was 4 and
+    client.write('/nodes/n2', 2, prevExist = False) # will set /nodes/n2 's value to 2 only if the key did not exist before
+    client.write('/nodes/n2', 2, prevIndex = 30) # will set /nodes/n2 's value to 2 only if the key was last modified at index 30
+    client.test_and_set('/nodes/n2', 2, 4) #equivalent to client.write('/nodes/n2', 2, prevValue = 4)
+
+You can also atomically update a result:
+
+.. code:: python
+
+    result = client.read('/foo')
+    print(result.value) # bar
+    result.value += u'bar'
+    updated = client.update(result) # if any other client wrote '/foo' in the meantime this will fail
+    print(updated.value) # barbar
+
+Watch a key
+~~~~~~~~~~~
+
+.. code:: python
+
+    client.read('/nodes/n1', wait = True) # will wait till the key is changed, and return once its changed
+    client.read('/nodes/n1', wait = True, timeout=30) # will wait till the key is changed, and return once its changed, or exit with an exception after 30 seconds.
+    client.read('/nodes/n1', wait = True, waitIndex = 10) # get all changes on this key starting from index 10
+    client.watch('/nodes/n1') #equivalent to client.read('/nodes/n1', wait = True)
+    client.watch('/nodes/n1', index = 10)
+
+Refreshing key TTL
+~~~~~~~~~~~~~~~~~~
+
+(Since etcd 2.3.0) Keys in etcd can be refreshed without notifying current watchers.
+
+This can be achieved by setting the refresh to true when updating a TTL.
+
+You cannot update the value of a key when refreshing it.
+
+.. code:: python
+
+    client.write('/nodes/n1', 'value', ttl=30)  # sets the ttl to 30 seconds
+    client.refresh('/nodes/n1', ttl=600)  # refresh ttl to 600 seconds, without notifying current watchers
+
+Locking module
+~~~~~~~~~~~~~~
+
+.. code:: python
+
+    # Initialize the lock object:
+    # NOTE: this does not acquire a lock yet
+    client = etcd.Client()
+    # Or you can custom lock prefix, default is '/_locks/' if you are using HEAD
+    client = etcd.Client(lock_prefix='/my_etcd_root/_locks')
+    lock = etcd.Lock(client, 'my_lock_name')
+
+    # Use the lock object:
+    lock.acquire(blocking=True, # will block until the lock is acquired
+          lock_ttl=None) # lock will live until we release it
+    lock.is_acquired  # True
+    lock.acquire(lock_ttl=60) # renew a lock
+    lock.release() # release an existing lock
+    lock.is_acquired  # False
+
+    # The lock object may also be used as a context manager:
+    client = etcd.Client()
+    with etcd.Lock(client, 'customer1') as my_lock:
+        do_stuff()
+        my_lock.is_acquired  # True
+        my_lock.acquire(lock_ttl=60)
+    my_lock.is_acquired  # False
+
+
+Get machines in the cluster
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: python
+
+    client.machines
+
+Get leader of the cluster
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: python
+
+    client.leader
+
+Generate a sequential key in a directory
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: python
+
+    x = client.write("/dir/name", "value", append=True)
+    print("generated key: " + x.key)
+    print("stored value: " + x.value)
+
+List contents of a directory
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: python
+
+    #stick a couple values in the directory
+    client.write("/dir/name", "value1", append=True)
+    client.write("/dir/name", "value2", append=True)
+
+    directory = client.get("/dir/name")
+
+    # loop through directory children
+    for result in directory.children:
+      print(result.key + ": " + result.value)
+
+    # or just get the first child value
+    print(directory.children.next().value)
+
+Development setup
+-----------------
+
+To create a buildout,
+
+.. code:: bash
+
+    $ python bootstrap.py
+    $ bin/buildout
+
+to test you should have etcd available in your system path:
+
+.. code:: bash
+
+    $ bin/test
+
+to generate documentation,
+
+.. code:: bash
+
+    $ cd docs
+    $ make
+
+Release HOWTO
+-------------
+
+To make a release
+
+    1) Update release date/version in NEWS.txt and setup.py
+    2) Run 'python setup.py sdist'
+    3) Test the generated source distribution in dist/
+    4) Upload to PyPI: 'python setup.py sdist register upload'
+
+
+News
+====
+0.4.5
+-----
+*Release date: 3-Mar-2017*
+
+* Remove dnspython2/3 requirement
+* Change property name setter in lock
+* Fixed acl tests
+* Added version/cluster_version properties to client
+* Fixes in lock when used as context manager
+* Fixed improper usage of urllib3 exceptions
+* Minor fixes for error classes
+* In lock return modifiedIndex to watch changes
+* In lock fix context manager exception handling
+* Improvments to the documentation
+* Remove _base_uri only after refresh from cluster
+* Avoid double update of _machines_cache
+
+
+0.4.4
+-----
+*Release date: 10-Jan-2017*
+
+* Fix some tests
+* Use sys,version_info tuple, instead of named tuple
+* Improve & fix documentation
+* Fix python3 specific problem when blocking on contented lock
+* Add refresh key method
+* Add custom lock prefix support
+
+
+0.4.3
+-----
+*Release date: 14-Dec-2015*
+
+* Fix check for parameters in case of connection error
+* Python 3.5 compatibility and general python3 cleanups
+* Added authentication and module for managing ACLs
+* Added srv record-based DNS discovery
+* Fixed (again) logging of cluster id changes
+* Fixed leader lookup
+* Properly retry request on exception
+* Client: clean up open connections when deleting
+
+0.4.2
+-----
+*Release date: 8-Oct-2015*
+
+* Fixed lock documentation
+* Fixed lock sequences due to etcd 2.2 change
+* Better exception management during response processing
+* Fixed logging of cluster ID changes
+* Fixed subtree results
+* Do not check cluster ID if etcd responses don't contain the ID
+* Added a cause to EtcdConnectionFailed
+
+
+0.4.1
+-----
+*Release date: 1-Aug-2015*
+
+* Added client-side leader election
+* Added stats endpoints
+* Added logging
+* Better exception handling
+* Check for cluster ID on each request
+* Added etcd.Client.members and fixed etcd.Client.leader
+* Removed locking and election etcd support
+* Allow the use of etcd proxies with reconnections
+* Implement pop: Remove key from etc and return the corresponding value.
+* Eternal watcher can be now recursive
+* Fix etcd.Client machines
+* Do not send parameters with `None` value to etcd
+* Support ttl=0 in write.
+* Moved pyOpenSSL into test requirements.
+* Always set certificate information so redirects from http to https work.
+
+
+0.3.3
+-----
+*Release date: 12-Apr-2015*
+
+* Forward leaves_only value in get_subtree() recursive calls
+* Fix README prevExists->prevExist
+* Added configurable version_prefix
+* Added support for recursive watch
+* Better error handling support (more detailed exceptions)
+* Fixed some unreliable tests
+
+
+0.3.2
+-----
+
+*Release date: 4-Aug-2014*
+
+* Fixed generated documentation version.
+
+
+0.3.1
+-----
+
+*Release date: 4-Aug-2014*
+
+* Added consisten read option
+* Fixed timeout parameter in read()
+* Added atomic delete parameter support
+* Fixed delete behaviour
+* Added update method that allows atomic updated on results
+* Fixed checks on write()
+* Added leaves generator to EtcdResult and get_subtree for recursive fetch
+* Added etcd_index to EtcdResult
+* Changed ethernal -> eternal
+* Updated urllib3 & pyOpenSSL libraries
+* Several performance fixes
+* Better parsing of etcd_index and raft_index
+* Removed duplicated tests
+* Added several integration and unit tests
+* Use etcd v0.3.0 in travis
+* Execute test using `python setup.py test` and nose
+
+
+0.3.0
+-----
+
+*Release date: 18-Jan-2014*
+
+* API v2 support
+* Python 3.3 compatibility
+
+
+0.2.1
+-----
+
+*Release data: 30-Nov-2013*
+
+* SSL support
+* Added support for subdirectories in results.
+* Improve test
+* Added support for reconnections, allowing death node tolerance.
+
+
+0.2.0
+-----
+
+*Release date: 30-Sep-2013*
+
+* Allow fetching of multiple keys (sub-nodes)
+
+
+0.1
+---
+
+*Release date: 18-Sep-2013*
+
+* Initial release
+
+
diff --git a/README.rst b/README.rst
index 9520aad..0df9c60 100644
--- a/README.rst
+++ b/README.rst
@@ -27,6 +27,13 @@ From source
 .. code:: bash
 
     $ python setup.py install
+    
+From Pypi
+~~~~~~~~~
+
+.. code:: bash
+
+   $ python3.5 -m pip install python-etcd
 
 Usage
 -----
diff --git a/bootstrap.py b/bootstrap.py
deleted file mode 100644
index 1b28969..0000000
--- a/bootstrap.py
+++ /dev/null
@@ -1,170 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2006 Zope Foundation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Bootstrap a buildout-based project
-
-Simply run this script in a directory containing a buildout.cfg.
-The script accepts buildout command-line options, so you can
-use the -c option to specify an alternate configuration file.
-"""
-
-import os
-import shutil
-import sys
-import tempfile
-
-from optparse import OptionParser
-
-tmpeggs = tempfile.mkdtemp()
-
-usage = '''\
-[DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options]
-
-Bootstraps a buildout-based project.
-
-Simply run this script in a directory containing a buildout.cfg, using the
-Python that you want bin/buildout to use.
-
-Note that by using --find-links to point to local resources, you can keep 
-this script from going over the network.
-'''
-
-parser = OptionParser(usage=usage)
-parser.add_option("-v", "--version", help="use a specific zc.buildout version")
-
-parser.add_option("-t", "--accept-buildout-test-releases",
-                  dest='accept_buildout_test_releases',
-                  action="store_true", default=False,
-                  help=("Normally, if you do not specify a --version, the "
-                        "bootstrap script and buildout gets the newest "
-                        "*final* versions of zc.buildout and its recipes and "
-                        "extensions for you.  If you use this flag, "
-                        "bootstrap and buildout will get the newest releases "
-                        "even if they are alphas or betas."))
-parser.add_option("-c", "--config-file",
-                  help=("Specify the path to the buildout configuration "
-                        "file to be used."))
-parser.add_option("-f", "--find-links",
-                  help=("Specify a URL to search for buildout releases"))
-
-
-options, args = parser.parse_args()
-
-######################################################################
-# load/install setuptools
-
-to_reload = False
-try:
-    import pkg_resources
-    import setuptools
-except ImportError:
-    ez = {}
-
-    try:
-        from urllib.request import urlopen
-    except ImportError:
-        from urllib2 import urlopen
-
-    # XXX use a more permanent ez_setup.py URL when available.
-    exec(urlopen('https://bitbucket.org/pypa/setuptools/raw/0.7.2/ez_setup.py'
-                ).read(), ez)
-    setup_args = dict(to_dir=tmpeggs, download_delay=0)
-    ez['use_setuptools'](**setup_args)
-
-    if to_reload:
-        reload(pkg_resources)
-    import pkg_resources
-    # This does not (always?) update the default working set.  We will
-    # do it.
-    for path in sys.path:
-        if path not in pkg_resources.working_set.entries:
-            pkg_resources.working_set.add_entry(path)
-
-######################################################################
-# Install buildout
-
-ws = pkg_resources.working_set
-
-cmd = [sys.executable, '-c',
-       'from setuptools.command.easy_install import main; main()',
-       '-mZqNxd', tmpeggs]
-
-find_links = os.environ.get(
-    'bootstrap-testing-find-links',
-    options.find_links or
-    ('http://downloads.buildout.org/'
-     if options.accept_buildout_test_releases else None)
-    )
-if find_links:
-    cmd.extend(['-f', find_links])
-
-setuptools_path = ws.find(
-    pkg_resources.Requirement.parse('setuptools')).location
-
-requirement = 'zc.buildout'
-version = options.version
-if version is None and not options.accept_buildout_test_releases:
-    # Figure out the most recent final version of zc.buildout.
-    import setuptools.package_index
-    _final_parts = '*final-', '*final'
-
-    def _final_version(parsed_version):
-        for part in parsed_version:
-            if (part[:1] == '*') and (part not in _final_parts):
-                return False
-        return True
-    index = setuptools.package_index.PackageIndex(
-        search_path=[setuptools_path])
-    if find_links:
-        index.add_find_links((find_links,))
-    req = pkg_resources.Requirement.parse(requirement)
-    if index.obtain(req) is not None:
-        best = []
-        bestv = None
-        for dist in index[req.project_name]:
-            distv = dist.parsed_version
-            if _final_version(distv):
-                if bestv is None or distv > bestv:
-                    best = [dist]
-                    bestv = distv
-                elif distv == bestv:
-                    best.append(dist)
-        if best:
-            best.sort()
-            version = best[-1].version
-if version:
-    requirement = '=='.join((requirement, version))
-cmd.append(requirement)
-
-import subprocess
-if subprocess.call(cmd, env=dict(os.environ, PYTHONPATH=setuptools_path)) != 0:
-    raise Exception(
-        "Failed to execute command:\n%s",
-        repr(cmd)[1:-1])
-
-######################################################################
-# Import and run buildout
-
-ws.add_entry(tmpeggs)
-ws.require(requirement)
-import zc.buildout.buildout
-
-if not [a for a in args if '=' not in a]:
-    args.append('bootstrap')
-
-# if -c was provided, we push it back into args for buildout' main function
-if options.config_file is not None:
-    args[0:0] = ['-c', options.config_file]
-
-zc.buildout.buildout.main(args)
-shutil.rmtree(tmpeggs)
diff --git a/build_etcd.sh b/build_etcd.sh
deleted file mode 100755
index fc31991..0000000
--- a/build_etcd.sh
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/bin/sh
-
-if [  $# -gt 0 ]
-    then
-    ETCD_VERSION="$1";
-    else
-    ETCD_VERSION="master";
-fi
-
-echo "Using ETCD version $ETCD_VERSION"
-
-git clone https://github.com/coreos/etcd.git
-cd etcd
-git checkout $ETCD_VERSION
-./build
-
-
-${TRAVIS:?"This is not a Travis build. All Done"}
-#Temporal solution to travis issue #155
-sudo rm -rf /dev/shm && sudo ln -s /run/shm /dev/shm
-echo "All Done"
diff --git a/buildout.cfg b/buildout.cfg
deleted file mode 100644
index 4de9036..0000000
--- a/buildout.cfg
+++ /dev/null
@@ -1,41 +0,0 @@
-[buildout]
-parts = python
-      sphinxbuilder
-      test
-      coverage
-develop = .
-eggs = 
-     urllib3==1.7.1
-     pyOpenSSL==0.13.1
-     ${deps:extraeggs}
-
-[python]
-recipe = zc.recipe.egg
-interpreter = python
-eggs = ${buildout:eggs}
-
-[test]
-recipe = pbp.recipe.noserunner
-eggs = ${python:eggs}
-     mock
-
-[coverage]
-recipe = pbp.recipe.noserunner
-eggs = ${test:eggs}
-     coverage
-defaults = --with-coverage
-     --cover-package=etcd
-
-[sphinxbuilder]
-recipe = collective.recipe.sphinxbuilder
-source = ${buildout:directory}/docs-source
-build = ${buildout:directory}/docs
-
-
-[deps:python2]
-extraeggs =
-        dnspython==1.12.0
-
-[deps:python3]
-extraeggs =
-        dnspython3==1.12.0
diff --git a/debian/changelog b/debian/changelog
index cc5812e..07977f3 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+python-etcd (0.4.5+git20170622.1.b227f49-1) UNRELEASED; urgency=low
+
+  * New upstream snapshot.
+
+ -- Debian Janitor <janitor@jelmer.uk>  Mon, 19 Sep 2022 16:27:53 -0000
+
 python-etcd (0.4.5-4) unstable; urgency=medium
 
   * Team upload.
diff --git a/docs-source/api.rst b/docs-source/api.rst
deleted file mode 100644
index 1059eef..0000000
--- a/docs-source/api.rst
+++ /dev/null
@@ -1,12 +0,0 @@
-API Documentation
-=========================
-.. automodule:: etcd
-   :members:
-.. autoclass:: Client
-   :special-members:
-   :members:
-   :exclude-members: __weakref__
-.. autoclass:: Lock
-   :special-members:
-   :members:
-   :exclude-members: __weakref__
diff --git a/docs-source/conf.py b/docs-source/conf.py
deleted file mode 100644
index 5148c23..0000000
--- a/docs-source/conf.py
+++ /dev/null
@@ -1,253 +0,0 @@
-# -*- coding: utf-8 -*-
-
-import sys, os
-
-class Mock(object):
-    def __init__(self, *args, **kwargs):
-        pass
-
-    def __call__(self, *args, **kwargs):
-        return Mock()
-
-    @classmethod
-    def __getattr__(cls, name):
-        if name in ('__file__', '__path__'):
-            return '/dev/null'
-        elif name[0] == name[0].upper():
-            mockType = type(name, (), {})
-            mockType.__module__ = __name__
-            return mockType
-        else:
-            return Mock()
-
-MOCK_MODULES = ['urllib3']
-for mod_name in MOCK_MODULES:
-    sys.modules[mod_name] = Mock()
-
-# If extensions (or modules to document with autodoc) are in another directory,
-# add these directories to sys.path here. If the directory is relative to the
-# documentation root, use os.path.abspath to make it absolute, like shown here.
-sys.path.insert(0, os.path.abspath('../src'))
-
-# -- General configuration -----------------------------------------------------
-
-# If your documentation needs a minimal Sphinx version, state it here.
-#needs_sphinx = '1.0'
-
-# Add any Sphinx extension module names here, as strings. They can be extensions
-# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
-extensions = ['sphinx.ext.autodoc']
-
-# Add any paths that contain templates here, relative to this directory.
-templates_path = ['_templates']
-
-# The suffix of source filenames.
-source_suffix = '.rst'
-
-# The encoding of source files.
-#source_encoding = 'utf-8-sig'
-
-# The master toctree document.
-master_doc = 'index'
-
-# General information about the project.
-project = u'python-etcd'
-copyright = u'2013-2015 Jose Plana, Giuseppe Lavagetto'
-
-# The version info for the project you're documenting, acts as replacement for
-# |version| and |release|, also used in various other places throughout the
-# built documents.
-#
-# The short X.Y version.
-version = '0.4'
-# The full version, including alpha/beta/rc tags.
-release = '0.4.3'
-
-# The language for content autogenerated by Sphinx. Refer to documentation
-# for a list of supported languages.
-#language = None
-
-# There are two options for replacing |today|: either, you set today to some
-# non-false value, then it is used:
-#today = ''
-# Else, today_fmt is used as the format for a strftime call.
-#today_fmt = '%B %d, %Y'
-
-# List of patterns, relative to source directory, that match files and
-# directories to ignore when looking for source files.
-exclude_patterns = ['_build']
-
-# The reST default role (used for this markup: `text`) to use for all documents.
-#default_role = None
-
-# If true, '()' will be appended to :func: etc. cross-reference text.
-#add_function_parentheses = True
-
-# If true, the current module name will be prepended to all description
-# unit titles (such as .. function::).
-#add_module_names = True
-
-# If true, sectionauthor and moduleauthor directives will be shown in the
-# output. They are ignored by default.
-#show_authors = False
-
-# The name of the Pygments (syntax highlighting) style to use.
-pygments_style = 'sphinx'
-
-# A list of ignored prefixes for module index sorting.
-#modindex_common_prefix = []
-
-
-# -- Options for HTML output ---------------------------------------------------
-
-# The theme to use for HTML and HTML Help pages.  See the documentation for
-# a list of builtin themes.
-html_theme = 'sphinxdoc'
-
-# Theme options are theme-specific and customize the look and feel of a theme
-# further.  For a list of options available for each theme, see the
-# documentation.
-#html_theme_options = {}
-
-# Add any paths that contain custom themes here, relative to this directory.
-#html_theme_path = []
-
-# The name for this set of Sphinx documents.  If None, it defaults to
-# "<project> v<release> documentation".
-#html_title = None
-
-# A shorter title for the navigation bar.  Default is the same as html_title.
-#html_short_title = None
-
-# The name of an image file (relative to this directory) to place at the top
-# of the sidebar.
-#html_logo = None
-
-# The name of an image file (within the static path) to use as favicon of the
-# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
-# pixels large.
-#html_favicon = None
-
-# Add any paths that contain custom static files (such as style sheets) here,
-# relative to this directory. They are copied after the builtin static files,
-# so a file named "default.css" will overwrite the builtin "default.css".
-html_static_path = ['_static']
-
-# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
-# using the given strftime format.
-#html_last_updated_fmt = '%b %d, %Y'
-
-# If true, SmartyPants will be used to convert quotes and dashes to
-# typographically correct entities.
-#html_use_smartypants = True
-
-# Custom sidebar templates, maps document names to template names.
-#html_sidebars = {}
-
-# Additional templates that should be rendered to pages, maps page names to
-# template names.
-#html_additional_pages = {}
-
-# If false, no module index is generated.
-#html_domain_indices = True
-
-# If false, no index is generated.
-#html_use_index = True
-
-# If true, the index is split into individual pages for each letter.
-#html_split_index = False
-
-# If true, links to the reST sources are added to the pages.
-#html_show_sourcelink = True
-
-# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
-#html_show_sphinx = True
-
-# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
-#html_show_copyright = True
-
-# If true, an OpenSearch description file will be output, and all pages will
-# contain a <link> tag referring to it.  The value of this option must be the
-# base URL from which the finished HTML is served.
-#html_use_opensearch = ''
-
-# This is the file name suffix for HTML files (e.g. ".xhtml").
-#html_file_suffix = None
-
-# Output file base name for HTML help builder.
-htmlhelp_basename = 'python-etcddoc'
-
-
-# -- Options for LaTeX output --------------------------------------------------
-
-latex_elements = {
-# The paper size ('letterpaper' or 'a4paper').
-#'papersize': 'letterpaper',
-
-# The font size ('10pt', '11pt' or '12pt').
-#'pointsize': '10pt',
-
-# Additional stuff for the LaTeX preamble.
-#'preamble': '',
-}
-
-# Grouping the document tree into LaTeX files. List of tuples
-# (source start file, target name, title, author, documentclass [howto/manual]).
-latex_documents = [
-  ('index', 'python-etcd.tex', u'python-etcd Documentation',
-   u'Jose Plana', 'manual'),
-]
-
-# The name of an image file (relative to this directory) to place at the top of
-# the title page.
-#latex_logo = None
-
-# For "manual" documents, if this is true, then toplevel headings are parts,
-# not chapters.
-#latex_use_parts = False
-
-# If true, show page references after internal links.
-#latex_show_pagerefs = False
-
-# If true, show URL addresses after external links.
-#latex_show_urls = False
-
-# Documents to append as an appendix to all manuals.
-#latex_appendices = []
-
-# If false, no module index is generated.
-#latex_domain_indices = True
-
-
-# -- Options for manual page output --------------------------------------------
-
-# One entry per manual page. List of tuples
-# (source start file, name, description, authors, manual section).
-man_pages = [
-    ('index', 'python-etcd', u'python-etcd Documentation',
-     [u'Jose Plana'], 1)
-]
-
-# If true, show URL addresses after external links.
-#man_show_urls = False
-
-
-# -- Options for Texinfo output ------------------------------------------------
-
-# Grouping the document tree into Texinfo files. List of tuples
-# (source start file, target name, title, author,
-#  dir menu entry, description, category)
-texinfo_documents = [
-  ('index', 'python-etcd', u'python-etcd Documentation',
-   u'Jose Plana', 'python-etcd', 'One line description of project.',
-   'Miscellaneous'),
-]
-
-# Documents to append as an appendix to all manuals.
-#texinfo_appendices = []
-
-# If false, no module index is generated.
-#texinfo_domain_indices = True
-
-# How to display URL addresses: 'footnote', 'no', or 'inline'.
-#texinfo_show_urls = 'footnote'
diff --git a/docs-source/index.rst b/docs-source/index.rst
deleted file mode 100644
index e35d685..0000000
--- a/docs-source/index.rst
+++ /dev/null
@@ -1,199 +0,0 @@
-Python-etcd documentation
-=========================
-
-A python client for Etcd https://github.com/coreos/etcd
-
-
-
-
-Installation
-------------
-
-Pre-requirements
-................
-
-Install etcd
-
-
-From source
-...........
-
-.. code-block:: bash
-
-    $ python setup.py install
-
-
-Usage
------
-
-Create a client object
-......................
-
-.. code-block:: python
-
-   import etcd
-
-   client = etcd.Client() # this will create a client against etcd server running on localhost on port 4001
-   client = etcd.Client(port=4002)
-   client = etcd.Client(host='127.0.0.1', port=4003)
-   client = etcd.Client(host='127.0.0.1', port=4003, allow_redirect=False) # wont let you run sensitive commands on non-leader machines, default is true
-   client = etcd.Client(
-                host='127.0.0.1',
-                port=4003,
-                allow_reconnect=True,
-                protocol='https',)
-
-Set a key
-.........
-
-.. code-block:: python
-
-    client.write('/nodes/n1', 1)
-    # with ttl
-    client.write('/nodes/n2', 2, ttl=4)  # sets the ttl to 4 seconds
-    # create only
-    client.write('/nodes/n3', 'test', prevExist=False)
-    # Compare and swap values atomically
-    client.write('/nodes/n3', 'test2', prevValue='test1') #this fails to write
-    client.write('/nodes/n3', 'test2', prevIndex=10) #this fails to write
-    # mkdir
-    client.write('/nodes/queue', None, dir=True)
-    # Append a value to a queue dir
-    client.write('/nodes/queue', 'test', append=True) #will write i.e. /nodes/queue/11
-    client.write('/nodes/queue', 'test2', append=True) #will write i.e. /nodes/queue/12
-
-You can also atomically update a result:
-
-.. code:: python
-
-    result = client.read('/foo')
-    print(result.value) # bar
-    result.value += u'bar'
-    updated = client.update(result) # if any other client wrote '/foo' in the meantime this will fail
-    print(updated.value) # barbar
-
-
-
-Get a key
-.........
-
-.. code-block:: python
-
-    client.read('/nodes/n2').value
-    #recursively read a directory
-    r = client.read('/nodes', recursive=True, sorted=True)
-    for child in r.children:
-        print("%s: %s" % (child.key,child.value))
-
-    client.read('/nodes/n2', wait=True) #Waits for a change in value in the key before returning.
-    client.read('/nodes/n2', wait=True, waitIndex=10)
-
-    # raises etcd.EtcdKeyNotFound when key not found
-    try:
-        client.read('/invalid/path')
-    except etcd.EtcdKeyNotFound:
-        # do something
-        print "error"
-
-
-Delete a key
-............
-
-.. code-block:: python
-
-    client.delete('/nodes/n1')
-    client.delete('/nodes', dir=True) #spits an error if dir is not empty
-    client.delete('/nodes', recursive=True) #this works recursively
-
-Locking module
-~~~~~~~~~~~~~~
-
-.. code:: python
-
-    # Initialize the lock object:
-    # NOTE: this does not acquire a lock yet
-    client = etcd.Client()
-    lock = etcd.Lock(client, 'my_lock_name')
-
-    # Use the lock object:
-    lock.acquire(blocking=True, # will block until the lock is acquired
-          lock_ttl=None)  # lock will live until we release it
-    lock.is_acquired  # True
-    lock.acquire(lock_ttl=60)  # renew a lock
-    lock.release()  # release an existing lock
-    lock.is_acquired  # False
-
-    # The lock object may also be used as a context manager:
-    client = etcd.Client()
-    with etcd.Lock(client, 'customer1') as my_lock:
-        do_stuff()
-        my_lock.is_acquired  # True
-        my_lock.acquire(lock_ttl=60)
-    my_lock.is_acquired  # False
-
-
-Get machines in the cluster
-...........................
-
-.. code-block:: python
-
-    client.machines
-
-
-Get leader of the cluster
-.........................
-
-.. code-block:: python
-
-    client.leader
-
-
-
-
-Development setup
------------------
-
-To create a buildout,
-
-.. code-block:: bash
-
-  $ python bootstrap.py
-  $ bin/buildout
-
-
-to test you should have etcd available in your system path:
-
-.. code-block:: bash
-
-  $ bin/test
-
-to generate documentation,
-
-.. code-block:: bash
-
-  $ cd docs
-  $ make
-
-
-
-Release HOWTO
--------------
-
-To make a release,
-
-  1) Update release date/version in NEWS.txt and setup.py
-  2) Run 'python setup.py sdist'
-  3) Test the generated source distribution in dist/
-  4) Upload to PyPI: 'python setup.py sdist register upload'
-  5) Increase version in setup.py (for next release)
-
-
-List of contributors at https://github.com/jplana/python-etcd/graphs/contributors
-
-Code documentation
-------------------
-
-.. toctree::
-   :maxdepth: 2
-
-   api.rst
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 0000000..8bfd5a1
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,4 @@
+[egg_info]
+tag_build = 
+tag_date = 0
+
diff --git a/src/etcd/auth.py b/src/etcd/auth.py
index 796772d..c5c7346 100644
--- a/src/etcd/auth.py
+++ b/src/etcd/auth.py
@@ -14,13 +14,28 @@ class EtcdAuthBase(object):
         self.name = name
         self.uri = "{}/auth/{}s/{}".format(self.client.version_prefix,
                                            self.entity, self.name)
+        # This will be lazily evaluated if not manually set
+        self._legacy_api = None
+
+    @property
+    def legacy_api(self):
+        if self._legacy_api is None:
+            # The auth API has changed between 2.2 and 2.3, true story!
+            major, minor, _ = map(int, self.client.version.split('.'))
+            self._legacy_api = (major < 3 and minor < 3)
+        return self._legacy_api
+
 
     @property
     def names(self):
         key = "{}s".format(self.entity)
         uri = "{}/auth/{}".format(self.client.version_prefix, key)
         response = self.client.api_execute(uri, self.client._MGET)
-        return json.loads(response.data.decode('utf-8'))[key]
+        if self.legacy_api:
+            return json.loads(response.data.decode('utf-8'))[key]
+        else:
+            return [obj[self.entity]
+                    for obj in json.loads(response.data.decode('utf-8'))[key]]
 
     def read(self):
         try:
@@ -102,7 +117,16 @@ class EtcdUser(EtcdAuthBase):
 
     def _from_net(self, data):
         d = json.loads(data.decode('utf-8'))
-        self.roles = d.get('roles', [])
+        roles = d.get('roles', [])
+        try:
+            self.roles = roles
+        except TypeError:
+            # with the change of API, PUT responses are different
+            # from GET reponses, which makes everything so funny.
+            # Specifically, PUT responses are the same as before...
+            if self.legacy_api:
+                raise
+            self.roles = [obj['role'] for obj in roles]
         self.name = d.get('user')
 
     def _to_net(self, prevobj=None):
diff --git a/src/etcd/client.py b/src/etcd/client.py
index 74ad8fc..7c4d985 100644
--- a/src/etcd/client.py
+++ b/src/etcd/client.py
@@ -214,12 +214,8 @@ class Client(object):
         Sets the version information provided by the server.
         """
         # Set the version
-        version_info = json.loads(self.http.request(
-            self._MGET,
-            self._base_uri + '/version',
-            headers=self._get_headers(),
-            timeout=self.read_timeout,
-            redirect=self.allow_redirect).data.decode('utf-8'))
+        data = self.api_execute('/version', self._MGET).data
+        version_info = json.loads(data.decode('utf-8'))
         self._version = version_info['etcdserver']
         self._cluster_version = version_info['etcdcluster']
 
@@ -232,7 +228,7 @@ class Client(object):
                 (answer.target.to_text(omit_final_dot=True), answer.port))
         _log.debug("Found %s", hosts)
         if not len(hosts):
-            raise ValueError("The SRV record is present but no host were found")
+            raise ValueError("The SRV record is present but no hosts were found")
         return tuple(hosts)
 
     def __del__(self):
@@ -822,7 +818,7 @@ class Client(object):
 
     def _next_server(self, cause=None):
         """ Selects the next server in the list, refreshes the server list. """
-        _log.debug("Selection next machine in cache. Available machines: %s",
+        _log.debug("Selecting next machine in cache. Available machines: %s",
                    self._machines_cache)
         try:
             mach = self._machines_cache.pop()
@@ -856,7 +852,7 @@ class Client(object):
                     # Check the cluster ID hasn't changed under us.  We use
                     # preload_content=False above so we can read the headers
                     # before we wait for the content of a watch.
-                    self._check_cluster_id(response)
+                    self._check_cluster_id(response, path)
                     # Now force the data to be preloaded in order to trigger any
                     # IO-related errors in this method rather than when we try to
                     # access it later.
@@ -896,7 +892,7 @@ class Client(object):
                     _log.warning(e)
                     raise
                 except:
-                    _log.exception("Unexpected request failure, re-raising.")
+                    _log.debug("Unexpected request failure, re-raising.")
                     raise
 
                 if some_request_failed:
@@ -950,10 +946,11 @@ class Client(object):
                                  headers=headers,
                                  preload_content=False)
 
-    def _check_cluster_id(self, response):
+    def _check_cluster_id(self, response, path):
         cluster_id = response.getheader("x-etcd-cluster-id")
         if not cluster_id:
-            _log.warning("etcd response did not contain a cluster ID")
+            if self.version_prefix in path:
+                _log.warning("etcd response did not contain a cluster ID")
             return
         id_changed = (self.expected_cluster_id and
                       cluster_id != self.expected_cluster_id)
diff --git a/src/etcd/tests/test_auth.py b/src/etcd/tests/test_auth.py
index 14475f9..5c8c0b0 100644
--- a/src/etcd/tests/test_auth.py
+++ b/src/etcd/tests/test_auth.py
@@ -93,6 +93,10 @@ class EtcdUserTest(TestEtcdAuthBase):
         self.assertEquals(u.roles, set(['guest', 'root']))
         # set roles as a list, it works!
         u.roles = ['guest', 'test_group']
+        # We need this or the new API will return an internal error
+        r = auth.EtcdRole(self.client, 'test_group')
+        r.acls = {'*': 'R', '/test/*': 'RW'}
+        r.write()
         try:
             u.write()
         except:
diff --git a/src/etcd/tests/unit/test_client.py b/src/etcd/tests/unit/test_client.py
index b0b53b2..2981de7 100644
--- a/src/etcd/tests/unit/test_client.py
+++ b/src/etcd/tests/unit/test_client.py
@@ -3,13 +3,15 @@ import etcd
 import dns.name
 import dns.rdtypes.IN.SRV
 import dns.resolver
+from etcd.tests.unit import TestClientApiBase
 try:
     import mock
 except ImportError:
     from unittest import mock
 
 
-class TestClient(unittest.TestCase):
+class TestClient(TestClientApiBase):
+
 
     def test_instantiate(self):
         """ client can be instantiated"""
@@ -123,55 +125,37 @@ class TestClient(unittest.TestCase):
 
     def test__set_version_info(self):
         """Verify _set_version_info makes the proper call to the server"""
-        with mock.patch('urllib3.PoolManager') as _pm:
-            _request = _pm().request
-            # Return the expected data type
-            _request.return_value = mock.MagicMock(
-                data=b'{"etcdserver": "2.2.3", "etcdcluster": "2.3.0"}')
-
-            # Create the client and make the call.
-            client = etcd.Client()
-            client._set_version_info()
-
-            # Verify we call the proper endpoint
-            _request.assert_called_once_with(
-                client._MGET,
-                client._base_uri + '/version',
-                headers=mock.ANY,
-                redirect=mock.ANY,
-                timeout=mock.ANY)
-
-            # Verify the properties while we are here
-            self.assertEquals('2.2.3', client.version)
-            self.assertEquals('2.3.0', client.cluster_version)
+        data = {"etcdserver": "2.2.3", "etcdcluster": "2.3.0"}
+        self._mock_api(200, data)
+        self.client.api_execute.return_value.getheader.return_value = None
+        # Create the client and make the call.
+        self.client._set_version_info()
+
+        # Verify we call the proper endpoint
+        self.client.api_execute.assert_called_once_with(
+            '/version',
+            self.client._MGET
+        )
+        # Verify the properties while we are here
+        self.assertEquals('2.2.3', self.client.version)
+        self.assertEquals('2.3.0', self.client.cluster_version)
 
     def test_version_property(self):
         """Ensure the version property is set on first access."""
-        with mock.patch('urllib3.PoolManager') as _pm:
-            _request = _pm().request
-            # Return the expected data type
-            _request.return_value = mock.MagicMock(
-                data=b'{"etcdserver": "2.2.3", "etcdcluster": "2.3.0"}')
-
-            # Create the client.
-            client = etcd.Client()
+        data = {"etcdserver": "2.2.3", "etcdcluster": "2.3.0"}
+        self._mock_api(200, data)
+        self.client.api_execute.return_value.getheader.return_value = None
 
-            # Verify the version property is set
-            self.assertEquals('2.2.3', client.version)
+        # Verify the version property is set
+        self.assertEquals('2.2.3', self.client.version)
 
     def test_cluster_version_property(self):
         """Ensure the cluster version property is set on first access."""
-        with mock.patch('urllib3.PoolManager') as _pm:
-            _request = _pm().request
-            # Return the expected data type
-            _request.return_value = mock.MagicMock(
-                data=b'{"etcdserver": "2.2.3", "etcdcluster": "2.3.0"}')
-
-            # Create the client.
-            client = etcd.Client()
-
-            # Verify the cluster_version property is set
-            self.assertEquals('2.3.0', client.cluster_version)
+        data = {"etcdserver": "2.2.3", "etcdcluster": "2.3.0"}
+        self._mock_api(200, data)
+        self.client.api_execute.return_value.getheader.return_value = None
+        # Verify the cluster_version property is set
+        self.assertEquals('2.3.0', self.client.cluster_version)
 
     def test_get_headers_without_auth(self):
         client = etcd.Client()
diff --git a/src/python_etcd.egg-info/PKG-INFO b/src/python_etcd.egg-info/PKG-INFO
new file mode 100644
index 0000000..2962fd2
--- /dev/null
+++ b/src/python_etcd.egg-info/PKG-INFO
@@ -0,0 +1,419 @@
+Metadata-Version: 2.1
+Name: python-etcd
+Version: 0.4.5
+Summary: A python client for etcd
+Home-page: http://github.com/jplana/python-etcd
+Author: Jose Plana
+Author-email: jplana@gmail.com
+License: MIT
+Keywords: etcd raft distributed log api client
+Platform: UNKNOWN
+Classifier: Topic :: System :: Distributed Computing
+Classifier: Topic :: Software Development :: Libraries
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 3
+Classifier: Topic :: Database :: Front-Ends
+License-File: LICENSE.txt
+License-File: AUTHORS
+
+python-etcd documentation
+=========================
+
+A python client for Etcd https://github.com/coreos/etcd
+
+Official documentation: http://python-etcd.readthedocs.org/
+
+.. image:: https://travis-ci.org/jplana/python-etcd.png?branch=master
+   :target: https://travis-ci.org/jplana/python-etcd
+
+.. image:: https://coveralls.io/repos/jplana/python-etcd/badge.svg?branch=master&service=github
+   :target: https://coveralls.io/github/jplana/python-etcd?branch=master
+
+Installation
+------------
+
+Pre-requirements
+~~~~~~~~~~~~~~~~
+
+This version of python-etcd will only work correctly with the etcd server version 2.0.x or later. If you are running an older version of etcd, please use python-etcd 0.3.3 or earlier.
+
+This client is known to work with python 2.7 and with python 3.3 or above. It is not tested or expected to work in more outdated versions of python.
+
+From source
+~~~~~~~~~~~
+
+.. code:: bash
+
+    $ python setup.py install
+    
+From Pypi
+~~~~~~~~~
+
+.. code:: bash
+
+   $ python3.5 -m pip install python-etcd
+
+Usage
+-----
+
+The basic methods of the client have changed compared to previous versions, to reflect the new API structure; however a compatibility layer has been maintained so that you don't necessarily need to rewrite all your existing code.
+
+Create a client object
+~~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: python
+
+    import etcd
+
+    client = etcd.Client() # this will create a client against etcd server running on localhost on port 4001
+    client = etcd.Client(port=4002)
+    client = etcd.Client(host='127.0.0.1', port=4003)
+    client = etcd.Client(host=(('127.0.0.1', 4001), ('127.0.0.1', 4002), ('127.0.0.1', 4003)))
+    client = etcd.Client(host='127.0.0.1', port=4003, allow_redirect=False) # wont let you run sensitive commands on non-leader machines, default is true
+    # If you have defined a SRV record for _etcd._tcp.example.com pointing to the clients
+    client = etcd.Client(srv_domain='example.com', protocol="https")
+    # create a client against https://api.example.com:443/etcd
+    client = etcd.Client(host='api.example.com', protocol='https', port=443, version_prefix='/etcd')
+
+Write a key
+~~~~~~~~~~~
+
+.. code:: python
+
+    client.write('/nodes/n1', 1)
+    # with ttl
+    client.write('/nodes/n2', 2, ttl=4)  # sets the ttl to 4 seconds
+    client.set('/nodes/n2', 1) # Equivalent, for compatibility reasons.
+
+Read a key
+~~~~~~~~~~
+
+.. code:: python
+
+    client.read('/nodes/n2').value
+    client.read('/nodes', recursive = True) #get all the values of a directory, recursively.
+    client.get('/nodes/n2').value
+
+    # raises etcd.EtcdKeyNotFound when key not found
+    try:
+        client.read('/invalid/path')
+    except etcd.EtcdKeyNotFound:
+        # do something
+        print "error"
+
+
+Delete a key
+~~~~~~~~~~~~
+
+.. code:: python
+
+    client.delete('/nodes/n1')
+
+Atomic Compare and Swap
+~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: python
+
+    client.write('/nodes/n2', 2, prevValue = 4) # will set /nodes/n2 's value to 2 only if its previous value was 4 and
+    client.write('/nodes/n2', 2, prevExist = False) # will set /nodes/n2 's value to 2 only if the key did not exist before
+    client.write('/nodes/n2', 2, prevIndex = 30) # will set /nodes/n2 's value to 2 only if the key was last modified at index 30
+    client.test_and_set('/nodes/n2', 2, 4) #equivalent to client.write('/nodes/n2', 2, prevValue = 4)
+
+You can also atomically update a result:
+
+.. code:: python
+
+    result = client.read('/foo')
+    print(result.value) # bar
+    result.value += u'bar'
+    updated = client.update(result) # if any other client wrote '/foo' in the meantime this will fail
+    print(updated.value) # barbar
+
+Watch a key
+~~~~~~~~~~~
+
+.. code:: python
+
+    client.read('/nodes/n1', wait = True) # will wait till the key is changed, and return once its changed
+    client.read('/nodes/n1', wait = True, timeout=30) # will wait till the key is changed, and return once its changed, or exit with an exception after 30 seconds.
+    client.read('/nodes/n1', wait = True, waitIndex = 10) # get all changes on this key starting from index 10
+    client.watch('/nodes/n1') #equivalent to client.read('/nodes/n1', wait = True)
+    client.watch('/nodes/n1', index = 10)
+
+Refreshing key TTL
+~~~~~~~~~~~~~~~~~~
+
+(Since etcd 2.3.0) Keys in etcd can be refreshed without notifying current watchers.
+
+This can be achieved by setting the refresh to true when updating a TTL.
+
+You cannot update the value of a key when refreshing it.
+
+.. code:: python
+
+    client.write('/nodes/n1', 'value', ttl=30)  # sets the ttl to 30 seconds
+    client.refresh('/nodes/n1', ttl=600)  # refresh ttl to 600 seconds, without notifying current watchers
+
+Locking module
+~~~~~~~~~~~~~~
+
+.. code:: python
+
+    # Initialize the lock object:
+    # NOTE: this does not acquire a lock yet
+    client = etcd.Client()
+    # Or you can custom lock prefix, default is '/_locks/' if you are using HEAD
+    client = etcd.Client(lock_prefix='/my_etcd_root/_locks')
+    lock = etcd.Lock(client, 'my_lock_name')
+
+    # Use the lock object:
+    lock.acquire(blocking=True, # will block until the lock is acquired
+          lock_ttl=None) # lock will live until we release it
+    lock.is_acquired  # True
+    lock.acquire(lock_ttl=60) # renew a lock
+    lock.release() # release an existing lock
+    lock.is_acquired  # False
+
+    # The lock object may also be used as a context manager:
+    client = etcd.Client()
+    with etcd.Lock(client, 'customer1') as my_lock:
+        do_stuff()
+        my_lock.is_acquired  # True
+        my_lock.acquire(lock_ttl=60)
+    my_lock.is_acquired  # False
+
+
+Get machines in the cluster
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: python
+
+    client.machines
+
+Get leader of the cluster
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: python
+
+    client.leader
+
+Generate a sequential key in a directory
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: python
+
+    x = client.write("/dir/name", "value", append=True)
+    print("generated key: " + x.key)
+    print("stored value: " + x.value)
+
+List contents of a directory
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: python
+
+    #stick a couple values in the directory
+    client.write("/dir/name", "value1", append=True)
+    client.write("/dir/name", "value2", append=True)
+
+    directory = client.get("/dir/name")
+
+    # loop through directory children
+    for result in directory.children:
+      print(result.key + ": " + result.value)
+
+    # or just get the first child value
+    print(directory.children.next().value)
+
+Development setup
+-----------------
+
+To create a buildout,
+
+.. code:: bash
+
+    $ python bootstrap.py
+    $ bin/buildout
+
+to test you should have etcd available in your system path:
+
+.. code:: bash
+
+    $ bin/test
+
+to generate documentation,
+
+.. code:: bash
+
+    $ cd docs
+    $ make
+
+Release HOWTO
+-------------
+
+To make a release
+
+    1) Update release date/version in NEWS.txt and setup.py
+    2) Run 'python setup.py sdist'
+    3) Test the generated source distribution in dist/
+    4) Upload to PyPI: 'python setup.py sdist register upload'
+
+
+News
+====
+0.4.5
+-----
+*Release date: 3-Mar-2017*
+
+* Remove dnspython2/3 requirement
+* Change property name setter in lock
+* Fixed acl tests
+* Added version/cluster_version properties to client
+* Fixes in lock when used as context manager
+* Fixed improper usage of urllib3 exceptions
+* Minor fixes for error classes
+* In lock return modifiedIndex to watch changes
+* In lock fix context manager exception handling
+* Improvments to the documentation
+* Remove _base_uri only after refresh from cluster
+* Avoid double update of _machines_cache
+
+
+0.4.4
+-----
+*Release date: 10-Jan-2017*
+
+* Fix some tests
+* Use sys,version_info tuple, instead of named tuple
+* Improve & fix documentation
+* Fix python3 specific problem when blocking on contented lock
+* Add refresh key method
+* Add custom lock prefix support
+
+
+0.4.3
+-----
+*Release date: 14-Dec-2015*
+
+* Fix check for parameters in case of connection error
+* Python 3.5 compatibility and general python3 cleanups
+* Added authentication and module for managing ACLs
+* Added srv record-based DNS discovery
+* Fixed (again) logging of cluster id changes
+* Fixed leader lookup
+* Properly retry request on exception
+* Client: clean up open connections when deleting
+
+0.4.2
+-----
+*Release date: 8-Oct-2015*
+
+* Fixed lock documentation
+* Fixed lock sequences due to etcd 2.2 change
+* Better exception management during response processing
+* Fixed logging of cluster ID changes
+* Fixed subtree results
+* Do not check cluster ID if etcd responses don't contain the ID
+* Added a cause to EtcdConnectionFailed
+
+
+0.4.1
+-----
+*Release date: 1-Aug-2015*
+
+* Added client-side leader election
+* Added stats endpoints
+* Added logging
+* Better exception handling
+* Check for cluster ID on each request
+* Added etcd.Client.members and fixed etcd.Client.leader
+* Removed locking and election etcd support
+* Allow the use of etcd proxies with reconnections
+* Implement pop: Remove key from etc and return the corresponding value.
+* Eternal watcher can be now recursive
+* Fix etcd.Client machines
+* Do not send parameters with `None` value to etcd
+* Support ttl=0 in write.
+* Moved pyOpenSSL into test requirements.
+* Always set certificate information so redirects from http to https work.
+
+
+0.3.3
+-----
+*Release date: 12-Apr-2015*
+
+* Forward leaves_only value in get_subtree() recursive calls
+* Fix README prevExists->prevExist
+* Added configurable version_prefix
+* Added support for recursive watch
+* Better error handling support (more detailed exceptions)
+* Fixed some unreliable tests
+
+
+0.3.2
+-----
+
+*Release date: 4-Aug-2014*
+
+* Fixed generated documentation version.
+
+
+0.3.1
+-----
+
+*Release date: 4-Aug-2014*
+
+* Added consisten read option
+* Fixed timeout parameter in read()
+* Added atomic delete parameter support
+* Fixed delete behaviour
+* Added update method that allows atomic updated on results
+* Fixed checks on write()
+* Added leaves generator to EtcdResult and get_subtree for recursive fetch
+* Added etcd_index to EtcdResult
+* Changed ethernal -> eternal
+* Updated urllib3 & pyOpenSSL libraries
+* Several performance fixes
+* Better parsing of etcd_index and raft_index
+* Removed duplicated tests
+* Added several integration and unit tests
+* Use etcd v0.3.0 in travis
+* Execute test using `python setup.py test` and nose
+
+
+0.3.0
+-----
+
+*Release date: 18-Jan-2014*
+
+* API v2 support
+* Python 3.3 compatibility
+
+
+0.2.1
+-----
+
+*Release data: 30-Nov-2013*
+
+* SSL support
+* Added support for subdirectories in results.
+* Improve test
+* Added support for reconnections, allowing death node tolerance.
+
+
+0.2.0
+-----
+
+*Release date: 30-Sep-2013*
+
+* Allow fetching of multiple keys (sub-nodes)
+
+
+0.1
+---
+
+*Release date: 18-Sep-2013*
+
+* Initial release
+
+
diff --git a/src/python_etcd.egg-info/SOURCES.txt b/src/python_etcd.egg-info/SOURCES.txt
new file mode 100644
index 0000000..443d6ca
--- /dev/null
+++ b/src/python_etcd.egg-info/SOURCES.txt
@@ -0,0 +1,28 @@
+AUTHORS
+LICENSE.txt
+MANIFEST.in
+NEWS.txt
+README.rst
+setup.py
+src/etcd/__init__.py
+src/etcd/auth.py
+src/etcd/client.py
+src/etcd/lock.py
+src/etcd/tests/__init__.py
+src/etcd/tests/test_auth.py
+src/etcd/tests/integration/__init__.py
+src/etcd/tests/integration/helpers.py
+src/etcd/tests/integration/test_simple.py
+src/etcd/tests/integration/test_ssl.py
+src/etcd/tests/unit/__init__.py
+src/etcd/tests/unit/test_client.py
+src/etcd/tests/unit/test_lock.py
+src/etcd/tests/unit/test_old_request.py
+src/etcd/tests/unit/test_request.py
+src/etcd/tests/unit/test_result.py
+src/python_etcd.egg-info/PKG-INFO
+src/python_etcd.egg-info/SOURCES.txt
+src/python_etcd.egg-info/dependency_links.txt
+src/python_etcd.egg-info/not-zip-safe
+src/python_etcd.egg-info/requires.txt
+src/python_etcd.egg-info/top_level.txt
\ No newline at end of file
diff --git a/src/python_etcd.egg-info/dependency_links.txt b/src/python_etcd.egg-info/dependency_links.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/src/python_etcd.egg-info/dependency_links.txt
@@ -0,0 +1 @@
+
diff --git a/src/python_etcd.egg-info/not-zip-safe b/src/python_etcd.egg-info/not-zip-safe
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/src/python_etcd.egg-info/not-zip-safe
@@ -0,0 +1 @@
+
diff --git a/src/python_etcd.egg-info/requires.txt b/src/python_etcd.egg-info/requires.txt
new file mode 100644
index 0000000..bac8bca
--- /dev/null
+++ b/src/python_etcd.egg-info/requires.txt
@@ -0,0 +1,2 @@
+dnspython>=1.13.0
+urllib3>=1.7.1
diff --git a/src/python_etcd.egg-info/top_level.txt b/src/python_etcd.egg-info/top_level.txt
new file mode 100644
index 0000000..7119fa0
--- /dev/null
+++ b/src/python_etcd.egg-info/top_level.txt
@@ -0,0 +1 @@
+etcd

Debdiff

File lists identical (after any substitutions)

No differences were encountered in the control files

More details

Full run details