diff -pruN 0.2.5-1/debian/changelog 1.0.1-2/debian/changelog
--- 0.2.5-1/debian/changelog	2021-01-13 08:49:04.000000000 +0000
+++ 1.0.1-2/debian/changelog	2022-03-24 10:38:50.000000000 +0000
@@ -1,3 +1,16 @@
+python-etcd3gw (1.0.1-2) unstable; urgency=medium
+
+  * Uploading to unstable.
+
+ -- Thomas Goirand <zigo@debian.org>  Thu, 24 Mar 2022 11:38:50 +0100
+
+python-etcd3gw (1.0.1-1) experimental; urgency=medium
+
+  * New upstream release.
+  * Add python3-openstackdocstheme build-depends.
+
+ -- Thomas Goirand <zigo@debian.org>  Thu, 17 Feb 2022 13:44:27 +0100
+
 python-etcd3gw (0.2.5-1) unstable; urgency=medium
 
   [ Ondřej Nový ]
diff -pruN 0.2.5-1/debian/control 1.0.1-2/debian/control
--- 0.2.5-1/debian/control	2021-01-13 08:49:04.000000000 +0000
+++ 1.0.1-2/debian/control	2022-03-24 10:38:50.000000000 +0000
@@ -18,6 +18,7 @@ Build-Depends-Indep:
  python3-hacking,
  python3-mock,
  python3-nose,
+ python3-openstackdocstheme,
  python3-oslosphinx,
  python3-oslotest,
  python3-pytest,
diff -pruN 0.2.5-1/doc/requirements.txt 1.0.1-2/doc/requirements.txt
--- 0.2.5-1/doc/requirements.txt	1970-01-01 00:00:00.000000000 +0000
+++ 1.0.1-2/doc/requirements.txt	2021-11-11 17:22:15.000000000 +0000
@@ -0,0 +1,3 @@
+sphinx>=1.5.1 # BSD
+openstackdocstheme>=2.2.1 # Apache-2.0
+reno>=1.8.0 # Apache-2.0
diff -pruN 0.2.5-1/doc/source/conf.py 1.0.1-2/doc/source/conf.py
--- 0.2.5-1/doc/source/conf.py	2019-09-18 02:33:08.000000000 +0000
+++ 1.0.1-2/doc/source/conf.py	2021-11-11 17:22:15.000000000 +0000
@@ -30,10 +30,13 @@
 # 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',
+extensions = [
+    'openstackdocstheme',
+    'sphinx.ext.autodoc',
     'sphinx.ext.intersphinx',
     'sphinx.ext.todo',
-    'sphinx.ext.viewcode']
+    'sphinx.ext.viewcode',
+]
 
 # Add any paths that contain templates here, relative to this directory.
 templates_path = ['_templates']
@@ -48,18 +51,18 @@ source_suffix = '.rst'
 master_doc = 'index'
 
 # General information about the project.
-project = u'etcd3-gateway'
-copyright = u'2017, Davanum Srinivas'
-author = u'Davanum Srinivas'
+project = 'etcd3-gateway'
+copyright = '2017, Davanum Srinivas'
+author = 'Davanum Srinivas'
 
 # 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 = u''
+version = ''
 # The full version, including alpha/beta/rc tags.
-release = u''
+release = ''
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
@@ -74,7 +77,7 @@ language = None
 exclude_patterns = []
 
 # The name of the Pygments (syntax highlighting) style to use.
-pygments_style = 'sphinx'
+pygments_style = 'native'
 
 # If true, `todo` and `todoList` produce output, else they produce nothing.
 todo_include_todos = True
@@ -85,7 +88,7 @@ todo_include_todos = True
 # The theme to use for HTML and HTML Help pages.  See the documentation for
 # a list of builtin themes.
 #
-html_theme = 'alabaster'
+html_theme = 'openstackdocs'
 
 # 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
@@ -129,8 +132,8 @@ latex_elements = {
 # (source start file, target name, title,
 #  author, documentclass [howto, manual, or own class]).
 latex_documents = [
-    (master_doc, 'etcd3-gateway.tex', u'etcd3-gateway Documentation',
-     u'Davanum Srinivas', 'manual'),
+    (master_doc, 'etcd3-gateway.tex', 'etcd3-gateway Documentation',
+     'Davanum Srinivas', 'manual'),
 ]
 
 
@@ -139,7 +142,7 @@ latex_documents = [
 # One entry per manual page. List of tuples
 # (source start file, name, description, authors, manual section).
 man_pages = [
-    (master_doc, 'etcd3-gateway', u'etcd3-gateway Documentation',
+    (master_doc, 'etcd3-gateway', 'etcd3-gateway Documentation',
      [author], 1)
 ]
 
@@ -150,7 +153,7 @@ man_pages = [
 # (source start file, target name, title, author,
 #  dir menu entry, description, category)
 texinfo_documents = [
-    (master_doc, 'etcd3-gateway', u'etcd3-gateway Documentation',
+    (master_doc, 'etcd3-gateway', 'etcd3-gateway Documentation',
      author, 'etcd3-gateway', 'One line description of project.',
      'Miscellaneous'),
 ]
@@ -160,3 +163,6 @@ texinfo_documents = [
 
 # Example configuration for intersphinx: refer to the Python standard library.
 intersphinx_mapping = {'https://docs.python.org/': None}
+
+# openstackdocstheme options
+openstackdocs_repo_name = 'openstack/etcd3gw'
diff -pruN 0.2.5-1/doc/source/usage.rst 1.0.1-2/doc/source/usage.rst
--- 0.2.5-1/doc/source/usage.rst	2019-09-18 02:33:08.000000000 +0000
+++ 1.0.1-2/doc/source/usage.rst	2021-11-11 17:22:15.000000000 +0000
@@ -2,6 +2,39 @@
 Usage
 ========
 
-To use etcd3-gateway in a project::
+You can find examples in ``etcd3gw/examples`` and look at ``etcd3gw/client.py``.
 
-    import etcd3gw
+Basic usage example::
+
+    from etcd3gw.client import Etcd3Client
+ 
+    client = Etcd3Client(host='localhost', port=2379)
+
+    # Put key
+    client.put(key='foo', value='bar')
+
+    # Get key
+    client.get(key='foo')
+
+    # Get all keys
+    client.get_all()
+
+
+    # Create lease and use it
+    lease = client.lease(ttl=100)
+
+    client.put(key='foo', value='bar', lease=lease)
+
+    # Get lease keys
+    lease.keys()
+
+    # Refresh lease
+    lease.refresh()
+
+
+    # Use watch
+    watcher, watch_cancel = client.watch(key='KEY')
+
+    for event in watcher: # blocks until event comes, cancel via watch_cancel()
+        print(event)
+        # modify event: {'kv': {'mod_revision': '8', 'version': '3', 'value': 'NEW_VAL', 'create_revision': '2', 'key': 'KEY', 'lease': '7587847878767953426'}}
diff -pruN 0.2.5-1/etcd3gw/client.py 1.0.1-2/etcd3gw/client.py
--- 0.2.5-1/etcd3gw/client.py	2019-09-18 02:33:08.000000000 +0000
+++ 1.0.1-2/etcd3gw/client.py	2021-11-11 17:22:15.000000000 +0000
@@ -41,8 +41,9 @@ _EXCEPTIONS_BY_CODE = {
 
 class Etcd3Client(object):
     def __init__(self, host='localhost', port=2379, protocol="http",
-                 ca_cert=None, cert_key=None, cert_cert=None, timeout=None):
-        """Construct an client to talk to etcd3's grpc-gateway's /v3alpha HTTP API
+                 ca_cert=None, cert_key=None, cert_cert=None, timeout=None,
+                 api_path='/v3alpha/'):
+        """Construct an client to talk to etcd3's grpc-gateway's /v3 HTTP API
 
         :param host:
         :param port:
@@ -59,9 +60,10 @@ class Etcd3Client(object):
             self.session.verify = ca_cert
         if cert_cert is not None and cert_key is not None:
             self.session.cert = (cert_cert, cert_key)
+        self.api_path = api_path
 
     def get_url(self, path):
-        """Construct a full url to the v3alpha API given a specific path
+        """Construct a full url to the v3 API given a specific path
 
         :param path:
         :return: url
@@ -69,7 +71,7 @@ class Etcd3Client(object):
         host = ('[' + self.host + ']' if (self.host.find(':') != -1)
                 else self.host)
         base_url = self.protocol + '://' + host + ':' + str(self.port)
-        return base_url + '/v3alpha/' + path.lstrip("/")
+        return base_url + self.api_path + path.lstrip("/")
 
     def post(self, *args, **kwargs):
         """helper method for HTTP POST
@@ -81,7 +83,10 @@ class Etcd3Client(object):
         try:
             resp = self.session.post(*args, **kwargs)
             if resp.status_code in _EXCEPTIONS_BY_CODE:
-                raise _EXCEPTIONS_BY_CODE[resp.status_code](resp.reason)
+                raise _EXCEPTIONS_BY_CODE[resp.status_code](
+                    resp.text,
+                    resp.reason
+                )
             if resp.status_code != requests.codes['ok']:
                 raise exceptions.Etcd3Exception(resp.text, resp.reason)
         except requests.exceptions.Timeout as ex:
@@ -128,7 +133,7 @@ class Etcd3Client(object):
             id = str(uuid.uuid4())
         return Lock(id, ttl=ttl, client=self)
 
-    def create(self, key, value):
+    def create(self, key, value, lease=None):
         """Atomically create the given key only if the key doesn't exist.
 
         This verifies that the create_revision of a key equales to 0, then
@@ -138,6 +143,7 @@ class Etcd3Client(object):
         :param key: key in etcd to create
         :param value: value of the key
         :type value: bytes or string
+        :param lease: lease to connect with, optional
         :returns: status of transaction, ``True`` if the create was
                   successful, ``False`` otherwise
         :rtype: bool
@@ -159,6 +165,8 @@ class Etcd3Client(object):
             }],
             'failure': []
         }
+        if lease:
+            txn['success'][0]['request_put']['lease'] = lease.id
         result = self.transaction(txn)
         if 'succeeded' in result:
             return result['succeeded']
diff -pruN 0.2.5-1/etcd3gw/examples/etcd.py 1.0.1-2/etcd3gw/examples/etcd.py
--- 0.2.5-1/etcd3gw/examples/etcd.py	2019-09-18 02:33:08.000000000 +0000
+++ 1.0.1-2/etcd3gw/examples/etcd.py	2021-11-11 17:22:15.000000000 +0000
@@ -10,7 +10,12 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
-import time
+try:
+    # Python 3.8 : time.clock was deprecated and removed.
+    from time import perf_counter as clock
+except ImportError:
+    from time import clock
+
 
 from etcd3gw.client import Etcd3Client
 from etcd3gw.lock import Lock
@@ -54,7 +59,7 @@ def main():
     print("Key delete foo-unknown : %r" % result)
 
     print('>>>> Lock')
-    lock = Lock('xyz-%s' % time.clock(), ttl=10000, client=client)
+    lock = Lock('xyz-%s' % clock(), ttl=10000, client=client)
     result = lock.acquire()
     print("acquire : %r" % result)
     result = lock.refresh()
diff -pruN 0.2.5-1/etcd3gw/tests/test_client.py 1.0.1-2/etcd3gw/tests/test_client.py
--- 0.2.5-1/etcd3gw/tests/test_client.py	2019-09-18 02:33:08.000000000 +0000
+++ 1.0.1-2/etcd3gw/tests/test_client.py	2021-11-11 17:22:15.000000000 +0000
@@ -10,10 +10,11 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
-import mock
+from unittest import mock
 
 from etcd3gw.client import Etcd3Client
 from etcd3gw.exceptions import Etcd3Exception
+from etcd3gw.exceptions import InternalServerError
 from etcd3gw.tests import base
 
 
@@ -54,3 +55,22 @@ class TestEtcd3Gateway(base.TestCase):
 "error": "etcdserver: mvcc: required revision has been compacted",
 "code": 11
 }''')
+
+    def test_client_exceptions_by_code(self):
+        client = Etcd3Client(host="127.0.0.1")
+        with mock.patch.object(client, "session") as mock_session:
+            mock_response = mock.Mock()
+            mock_response.status_code = 500
+            mock_response.reason = "Internal Server Error"
+            mock_response.text = '''{
+"error": "etcdserver: unable to reach quorum"
+}'''
+            mock_session.post.return_value = mock_response
+            try:
+                client.status()
+                self.assertFalse(True)
+            except InternalServerError as e:
+                self.assertEqual(str(e), "Internal Server Error")
+                self.assertEqual(e.detail_text, '''{
+"error": "etcdserver: unable to reach quorum"
+}''')
diff -pruN 0.2.5-1/etcd3gw/tests/test_etcd3gw.py 1.0.1-2/etcd3gw/tests/test_etcd3gw.py
--- 0.2.5-1/etcd3gw/tests/test_etcd3gw.py	2019-09-18 02:33:08.000000000 +0000
+++ 1.0.1-2/etcd3gw/tests/test_etcd3gw.py	2021-11-11 17:22:15.000000000 +0000
@@ -17,18 +17,28 @@ test_etcd3-gateway
 Tests for `etcd3gw` module.
 """
 
+import base64
+import json
+import requests
 import six
 import threading
 import time
 import uuid
 
 from testtools.testcase import unittest
+from unittest import mock
 import urllib3
 
 from etcd3gw.client import Etcd3Client
 from etcd3gw import exceptions
 from etcd3gw.tests import base
 
+try:
+    # Python 3.8 : time.clock was deprecated and removed.
+    from time import perf_counter as clock
+except ImportError:
+    from time import clock
+
 
 def _is_etcd3_running():
     try:
@@ -344,7 +354,7 @@ class TestEtcd3Gateway(base.TestCase):
     @unittest.skipUnless(
         _is_etcd3_running(), "etcd3 is not available")
     def test_client_locks(self):
-        lock = self.client.lock(id='xyz-%s' % time.clock(), ttl=60)
+        lock = self.client.lock(id='xyz-%s' % clock(), ttl=60)
         self.assertIsNotNone(lock)
 
         self.assertTrue(lock.acquire())
@@ -382,3 +392,46 @@ class TestEtcd3Gateway(base.TestCase):
         # Verify that key is still 'bar'
         self.assertEqual([six.b('bar')], self.client.get(key))
         self.assertFalse(status)
+
+    @unittest.skipUnless(
+        _is_etcd3_running(), "etcd3 is not available")
+    def test_create_with_lease_success(self):
+        key = '/foo/unique' + str(uuid.uuid4())
+        # Verify that key is empty
+        self.assertEqual([], self.client.get(key))
+        lease = self.client.lease()
+
+        status = self.client.create(key, 'bar', lease=lease)
+        # Verify that key is 'bar'
+        self.assertEqual([six.b('bar')], self.client.get(key))
+        self.assertTrue(status)
+        keys = lease.keys()
+        self.assertEqual(1, len(keys))
+        self.assertIn(six.b(key), keys)
+
+    def my_iter_content(self, *args, **kwargs):
+        payload = json.dumps({
+            'result': {
+                'events': [{
+                    'kv': {'key': base64.b64encode(b'value').decode('utf-8')},
+                }]
+            }
+        })
+
+        if not kwargs.get('decode_unicode', False):
+            payload = payload.encode()
+        return [payload]
+
+    @mock.patch.object(requests.Response, 'iter_content', new=my_iter_content)
+    @mock.patch.object(requests.sessions.Session, 'post')
+    def test_watch_unicode(self, mock_post):
+        mocked_response = requests.Response()
+        mocked_response.connection = mock.Mock()
+        mock_post.return_value = mocked_response
+
+        try:
+            res = self.client.watch_once('/some/key', timeout=1)
+        except exceptions.WatchTimedOut:
+            self.fail("watch timed out when server responded with unicode")
+
+        self.assertEqual(res, {'kv': {'key': b'value'}})
diff -pruN 0.2.5-1/etcd3gw/utils.py 1.0.1-2/etcd3gw/utils.py
--- 0.2.5-1/etcd3gw/utils.py	2019-09-18 02:33:08.000000000 +0000
+++ 1.0.1-2/etcd3gw/utils.py	2021-11-11 17:22:15.000000000 +0000
@@ -74,6 +74,7 @@ def _try_import(import_str, default=None
     except ImportError:
         return default
 
+
 # These may or may not exist; so carefully import them if we can...
 _eventlet = _try_import('eventlet')
 _patcher = _try_import('eventlet.patcher')
diff -pruN 0.2.5-1/etcd3gw/watch.py 1.0.1-2/etcd3gw/watch.py
--- 0.2.5-1/etcd3gw/watch.py	2019-09-18 02:33:08.000000000 +0000
+++ 1.0.1-2/etcd3gw/watch.py	2021-11-11 17:22:15.000000000 +0000
@@ -19,7 +19,7 @@ from etcd3gw.utils import _get_threadpoo
 
 
 def _watch(resp, callback):
-    for line in resp.iter_content(chunk_size=None, decode_unicode=True):
+    for line in resp.iter_content(chunk_size=None, decode_unicode=False):
         decoded_line = line.decode('utf-8')
         payload = json.loads(decoded_line)
         if 'created' in payload['result']:
diff -pruN 0.2.5-1/.gitreview 1.0.1-2/.gitreview
--- 0.2.5-1/.gitreview	2019-09-18 02:33:08.000000000 +0000
+++ 1.0.1-2/.gitreview	2021-11-11 17:22:15.000000000 +0000
@@ -1,4 +1,4 @@
 [gerrit]
-host=review.openstack.org
+host=review.opendev.org
 port=29418
-project=dims/etcd3-gateway.git
+project=openstack/etcd3gw.git
diff -pruN 0.2.5-1/README.md 1.0.1-2/README.md
--- 0.2.5-1/README.md	2019-09-18 02:33:08.000000000 +0000
+++ 1.0.1-2/README.md	2021-11-11 17:22:15.000000000 +0000
@@ -6,4 +6,4 @@
 [![pypi status](https://img.shields.io/pypi/status/etcd3gw.svg)](https://pypi.python.org/pypi/etcd3gw)
 [![pypi supported versions](https://img.shields.io/pypi/pyversions/etcd3gw.svg)](https://pypi.python.org/pypi/etcd3gw)
 
-A python client for etcd3 grpc-gateway v3alpha API
\ No newline at end of file
+A python client for etcd3 grpc-gateway v3 API
diff -pruN 0.2.5-1/releasenotes/source/conf.py 1.0.1-2/releasenotes/source/conf.py
--- 0.2.5-1/releasenotes/source/conf.py	2019-09-18 02:33:08.000000000 +0000
+++ 1.0.1-2/releasenotes/source/conf.py	2021-11-11 17:22:15.000000000 +0000
@@ -38,7 +38,7 @@
 # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
 # ones.
 extensions = [
-    'oslosphinx',
+    'openstackdocstheme',
     'reno.sphinxext',
 ]
 
@@ -55,8 +55,8 @@ source_suffix = '.rst'
 master_doc = 'index'
 
 # General information about the project.
-project = u'etcd3gw Release Notes'
-copyright = u'2016, OpenStack Foundation'
+project = 'etcd3gw Release Notes'
+copyright = '2016, OpenStack Foundation'
 
 # The version info for the project you're documenting, acts as replacement for
 # |version| and |release|, also used in various other places throughout the
@@ -98,7 +98,7 @@ exclude_patterns = []
 # show_authors = False
 
 # The name of the Pygments (syntax highlighting) style to use.
-pygments_style = 'sphinx'
+pygments_style = 'native'
 
 # A list of ignored prefixes for module index sorting.
 # modindex_common_prefix = []
@@ -111,7 +111,7 @@ pygments_style = 'sphinx'
 
 # The theme to use for HTML and HTML Help pages.  See the documentation for
 # a list of builtin themes.
-html_theme = 'default'
+html_theme = 'openstackdocs'
 
 # 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
@@ -209,8 +209,8 @@ latex_elements = {
 # (source start file, target name, title,
 #  author, documentclass [howto, manual, or own class]).
 latex_documents = [
-    ('index', 'GlanceReleaseNotes.tex', u'Glance Release Notes Documentation',
-     u'Glance Developers', 'manual'),
+    ('index', 'GlanceReleaseNotes.tex', 'Glance Release Notes Documentation',
+     'Glance Developers', 'manual'),
 ]
 
 # The name of an image file (relative to this directory) to place at the top of
@@ -239,8 +239,8 @@ latex_documents = [
 # One entry per manual page. List of tuples
 # (source start file, name, description, authors, manual section).
 man_pages = [
-    ('index', 'glancereleasenotes', u'Glance Release Notes Documentation',
-     [u'Glance Developers'], 1)
+    ('index', 'glancereleasenotes', 'Glance Release Notes Documentation',
+     ['Glance Developers'], 1)
 ]
 
 # If true, show URL addresses after external links.
@@ -253,8 +253,8 @@ man_pages = [
 # (source start file, target name, title, author,
 #  dir menu entry, description, category)
 texinfo_documents = [
-    ('index', 'GlanceReleaseNotes', u'Glance Release Notes Documentation',
-     u'Glance Developers', 'GlanceReleaseNotes',
+    ('index', 'GlanceReleaseNotes', 'Glance Release Notes Documentation',
+     'Glance Developers', 'GlanceReleaseNotes',
      'One line description of project.',
      'Miscellaneous'),
 ]
@@ -273,3 +273,6 @@ texinfo_documents = [
 
 # -- Options for Internationalization output ------------------------------
 locale_dirs = ['locale/']
+
+# openstackdocstheme options
+openstackdocs_repo_name = 'openstack/etcd3gw'
diff -pruN 0.2.5-1/requirements.txt 1.0.1-2/requirements.txt
--- 0.2.5-1/requirements.txt	2019-09-18 02:33:08.000000000 +0000
+++ 1.0.1-2/requirements.txt	2021-11-11 17:22:15.000000000 +0000
@@ -3,7 +3,6 @@
 # process, which may cause wedges in the gate later.
 
 pbr>=2.0 # Apache-2.0
-urllib3>=1.15.1  # MIT
-requests>=2.10.0,!=2.12.2,!=2.13.0  # Apache-2.0
+requests>=2.20.0  # Apache-2.0
 six>=1.9.0  # MIT
-futurist>=0.11.0,!=0.15.0  # Apache-2.0
\ No newline at end of file
+futurist>=0.16.0  # Apache-2.0
diff -pruN 0.2.5-1/setup.cfg 1.0.1-2/setup.cfg
--- 0.2.5-1/setup.cfg	2019-09-18 02:33:08.000000000 +0000
+++ 1.0.1-2/setup.cfg	2021-11-11 17:22:15.000000000 +0000
@@ -1,13 +1,13 @@
 [metadata]
 name = etcd3gw
 summary = A python client for etcd3 grpc-gateway v3 API
-description-file =
+description_file =
     README.md
-author = Davanum Srinivas
-author-email = davanum@gmail.com
-home-page = https://github.com/dims/etcd3-gateway
+author = OpenStack
+author_email = openstack-discuss@lists.openstack.org
+home_page = https://docs.openstack.org/etcd3gw/latest/
+python_requires = >=3.6
 classifier =
-    Development Status :: 3 - Alpha
     Environment :: Console
     Environment :: OpenStack
     Intended Audience :: Developers
@@ -15,44 +15,13 @@ classifier =
     License :: OSI Approved :: Apache Software License
     Operating System :: OS Independent
     Programming Language :: Python
-    Programming Language :: Python :: 2
-    Programming Language :: Python :: 2.7
     Programming Language :: Python :: 3
-    Programming Language :: Python :: 3.5
+    Programming Language :: Python :: 3.6
+    Programming Language :: Python :: 3.7
+    Programming Language :: Python :: 3.8
+    Programming Language :: Python :: 3 :: Only
+    Topic :: System :: Distributed Computing
 
 [files]
 packages =
     etcd3gw
-
-[pbr]
-warnerrors = True
-autodoc_index_modules = true
-autodoc_exclude_modules =
-    etcd3gw.tests.*
-    etcd3gw.examples.*
-
-[wheel]
-universal = 1
-
-[build_sphinx]
-all-files = 1
-warning-is-error = 1
-source-dir = doc/source
-build-dir = doc/build
-
-[upload_sphinx]
-upload-dir = doc/build/html
-
-[compile_catalog]
-directory = etcd3gw/locale
-domain = etcd3gw
-
-[update_catalog]
-domain = etcd3gw
-output_dir = etcd3gw/locale
-input_file = etcd3gw/locale/etcd3gw.pot
-
-[extract_messages]
-keywords = _ gettext ngettext l_ lazy_gettext
-mapping_file = babel.cfg
-output_file = etcd3gw/locale/etcd3gw.pot
diff -pruN 0.2.5-1/test-requirements.txt 1.0.1-2/test-requirements.txt
--- 0.2.5-1/test-requirements.txt	2019-09-18 02:33:08.000000000 +0000
+++ 1.0.1-2/test-requirements.txt	2021-11-11 17:22:15.000000000 +0000
@@ -2,20 +2,15 @@
 # of appearance. Changing the order has an impact on the overall integration
 # process, which may cause wedges in the gate later.
 
-hacking>=0.12.0,!=0.13.0,<0.14  # Apache-2.0
+hacking>=3.0,<3.1.0 # Apache-2.0
 
 coverage>=4.0 # Apache-2.0
 python-subunit>=0.0.18 # Apache-2.0/BSD
-sphinx>=1.5.1 # BSD
-oslosphinx>=4.7.0 # Apache-2.0
 oslotest>=1.10.0 # Apache-2.0
 testrepository>=0.0.18  # Apache-2.0/BSD
 testscenarios>=0.4  # Apache-2.0/BSD
 testtools>=1.4.0 # MIT
 pifpaf>=0.10.0 # Apache-2.0
-codecov>=1.4.0
-nose>=1.3.7
-pytest
-
-# releasenotes
-reno>=1.8.0 # Apache-2.0
+nose>=1.3.7  # GNU LGPL
+pytest>=3.0.0  # MIT
+urllib3>=1.15.1  # MIT
diff -pruN 0.2.5-1/tox.ini 1.0.1-2/tox.ini
--- 0.2.5-1/tox.ini	2019-09-18 02:33:08.000000000 +0000
+++ 1.0.1-2/tox.ini	2021-11-11 17:22:15.000000000 +0000
@@ -1,17 +1,13 @@
 [tox]
-minversion = 2.0
-envlist = py36,py35,py27,pypy,pep8
+minversion = 3.1.0
+envlist = py36,py38,pypy,pep8
 skipsdist = True
 
 [testenv]
-passenv = TOXENV CI TRAVIS TRAVIS_*
 usedevelop = True
-setenv =
-   VIRTUAL_ENV={envdir}
-   PYTHONWARNINGS=default::DeprecationWarning
-deps =
-   -r{toxinidir}/requirements.txt
-   -r{toxinidir}/test-requirements.txt
+deps = -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}
+       -r{toxinidir}/requirements.txt
+       -r{toxinidir}/test-requirements.txt
 commands = py.test -vv {posargs}
 
 [testenv:pep8]
@@ -20,28 +16,26 @@ commands = flake8 {posargs}
 [testenv:venv]
 commands = {posargs}
 
-[testenv:py27-cover]
+[testenv:cover]
 commands =
     coverage erase
     python setup.py test --coverage --testr-args='{posargs}'
 
-[testenv:py27-codecov]
+[testenv:codecov]
+deps = {[testenv]deps}
+       codecov>=1.4.0
 commands =
     {toxinidir}/setup-etcd-env.sh pifpaf -g TOOZ_TEST run etcd -- nosetests --with-coverage --cover-package=etcd3gw --cover-tests
     codecov
 
 [testenv:docs]
-commands = python setup.py build_sphinx
+deps = -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}
+       -r{toxinidir}/doc/requirements.txt
+commands = sphinx-build -W -b html doc/source doc/build/html
 
 [testenv:pypy-etcd]
 commands = {toxinidir}/setup-etcd-env.sh pifpaf -g TOOZ_TEST run etcd -- py.test -vv '{posargs}'
 
-[testenv:py27-etcd]
-commands = {toxinidir}/setup-etcd-env.sh pifpaf -g TOOZ_TEST run etcd -- py.test -vv '{posargs}'
-
-[testenv:py35-etcd]
-commands = {toxinidir}/setup-etcd-env.sh pifpaf -g TOOZ_TEST run etcd -- py.test -vv '{posargs}'
-
 [testenv:py36-etcd]
 commands = {toxinidir}/setup-etcd-env.sh pifpaf -g TOOZ_TEST run etcd -- py.test -vv '{posargs}'
 
@@ -49,6 +43,7 @@ commands = {toxinidir}/setup-etcd-env.sh
 commands = {toxinidir}/setup-etcd-env.sh pifpaf -g TOOZ_TEST run etcd -- python {toxinidir}/etcd3gw/examples/etcd.py
 
 [testenv:releasenotes]
+deps = {[testenv:docs]deps}
 commands =
   sphinx-build -a -E -W -d releasenotes/build/doctrees -b html releasenotes/source releasenotes/build/html
 
diff -pruN 0.2.5-1/.travis.yml 1.0.1-2/.travis.yml
--- 0.2.5-1/.travis.yml	2019-09-18 02:33:08.000000000 +0000
+++ 1.0.1-2/.travis.yml	1970-01-01 00:00:00.000000000 +0000
@@ -1,48 +0,0 @@
-dist: trusty
-sudo: required
-services:
-  - docker
-language: python
-matrix:
-  include:
-    - python: 2.7
-      env: TOXENV=pep8
-    - python: 2.7
-      env: TOXENV=py27
-    - python: pypy
-      env: TOXENV=pypy
-    - python: 3.5
-      env: TOXENV=py35
-    - python: 3.6
-      env: TOXENV=py36
-    - python: 2.7
-      env: TOXENV=py27-codecov
-    - python: 2.7
-      env: TOXENV=py27-etcd
-    - python: pypy
-      env: TOXENV=pypy-etcd
-    - python: 3.5
-      env: TOXENV=py35-etcd
-    - python: 3.6
-      env: TOXENV=py36-etcd
-  allow_failures:
-    - python: pypy
-      env: TOXENV=pypy-etcd
-    - python: 3.5
-      env: TOXENV=py35-etcd
-    - python: 3.6
-      env: TOXENV=py36-etcd
-
-before_install:
-  - python --version
-  - uname -a
-  - lsb_release -a
-install:
-  - python -m pip install pip -U
-  - python -m pip install tox coverage coveralls
-  - python -m virtualenv --version
-  - python -m easy_install --version
-  - python -m pip --version
-  - python -m tox --version
-script:
-  - tox
diff -pruN 0.2.5-1/.zuul.yaml 1.0.1-2/.zuul.yaml
--- 0.2.5-1/.zuul.yaml	1970-01-01 00:00:00.000000000 +0000
+++ 1.0.1-2/.zuul.yaml	2021-11-11 17:22:15.000000000 +0000
@@ -0,0 +1,12 @@
+- project:
+    templates:
+      - check-requirements
+      # FIXME: see https://review.opendev.org/747460
+      # - lib-forward-testing-python3
+      - openstack-cover-jobs
+      # FIXME: add lower-constraints or drop this
+      # - openstack-lower-constraints-jobs
+      - openstack-python3-wallaby-jobs
+      - periodic-stable-jobs
+      - publish-openstack-docs-pti
+      - release-notes-jobs-python3
