diff -pruN 1.30.0-3/AUTHORS 1.31.0-0ubuntu1/AUTHORS
--- 1.30.0-3/AUTHORS	2018-10-19 14:13:30.000000000 +0000
+++ 1.31.0-0ubuntu1/AUTHORS	2019-03-07 23:58:00.000000000 +0000
@@ -50,6 +50,7 @@ Joshua Harlow <harlowja@yahoo-inc.com>
 Joshua Harlow <jxharlow@godaddy.com>
 Joshua Hesketh <josh@nitrotech.org>
 Julia Kreger <juliaashleykreger@gmail.com>
+Kim Bao Long <longkb@vn.fujitsu.com>
 Kyle Mestery <mestery@mestery.com>
 Lars Kellogg-Stedman <lars@redhat.com>
 Lee Yarwood <lyarwood@redhat.com>
@@ -64,6 +65,7 @@ Mohammed Naser <mnaser@vexxhost.com>
 Monty Taylor <mordred@inaugust.com>
 Morgan Fainberg <morgan.fainberg@gmail.com>
 Mário Santos <mario.rf.santos@gmail.com>
+Nguyen Hai Truong <truongnh@vn.fujitsu.com>
 Olivier Bourdon <obourdon@opennext.io>
 OpenStack Release Bot <infra-root@openstack.org>
 Paul Belanger <pabelanger@redhat.com>
@@ -108,5 +110,7 @@ deepakmourya <deepak.mourya@nectechnolog
 mariojmdavid <mariojmdavid@gmail.com>
 matthew wagoner <zxkuqyb@gmail.com>
 melissaml <ma.lei@99cloud.net>
+qingszhao <zhao.daqing@99cloud.net>
 rajat29 <rajat.sharma@nectechnologies.in>
 tengqm <tengqim@cn.ibm.com>
+wacuuu <jwalecki1996@gmail.com>
diff -pruN 1.30.0-3/ChangeLog 1.31.0-0ubuntu1/ChangeLog
--- 1.30.0-3/ChangeLog	2018-10-19 14:13:29.000000000 +0000
+++ 1.31.0-0ubuntu1/ChangeLog	2019-03-07 23:57:59.000000000 +0000
@@ -1,6 +1,20 @@
 CHANGES
 =======
 
+1.31.0
+------
+
+* Fix dogpile.cache 0.7.0 interaction
+* Restrict inventory test to devstack-admin
+* Change openstack-dev to openstack-discuss
+* Split parser creation and parser for inventory
+* Fix ansible stable pin in tox test
+* Fix grant\_role() when user not in default domain
+* Use openSUSE 15.0 for testing
+* change default python 3 env in tox to 3.5
+* Add python 3.6 unit test job
+* Update the min version of tox to 2.0
+
 1.30.0
 ------
 
diff -pruN 1.30.0-3/debian/changelog 1.31.0-0ubuntu1/debian/changelog
--- 1.30.0-3/debian/changelog	2019-08-21 19:18:32.000000000 +0000
+++ 1.31.0-0ubuntu1/debian/changelog	2019-07-17 14:49:26.000000000 +0000
@@ -1,16 +1,16 @@
-python-shade (1.30.0-3) unstable; urgency=medium
+python-shade (1.31.0-0ubuntu1) eoan; urgency=medium
 
-  * Team upload.
+  * d/gbp.conf: Update gbp configuration file.
+  * d/control: Update Vcs-* links and maintainers.
+  * d/control, d/rules: Drop Python 2 support.
+  * d/*: wrap-and-sort -bast.
+  * New upstream release for OpenStack Train.
+  * d/control: Align (Build-)Depends with upstream.
+  * d/p/0001-Split-parser-creation-and-parser-for-inventory.patch:
+    Dropped. Fixed upstream.
+  * d/rules, d/control: Use pkgos-dh_auto_test to run tests.
 
-  [ Ondřej Nový ]
-  * Use debhelper-compat instead of debian/compat.
-  * Drop Python 2 support (Closes: #934336).
-  * Fix stestr CLI name.
-
-  [ Andrey Rahmatullin ]
-  * Fix building with current dogpile.
-
- -- Andrey Rahmatullin <wrar@debian.org>  Thu, 22 Aug 2019 00:18:32 +0500
+ -- Corey Bryant <corey.bryant@canonical.com>  Wed, 17 Jul 2019 10:49:26 -0400
 
 python-shade (1.30.0-2) unstable; urgency=medium
 
diff -pruN 1.30.0-3/debian/compat 1.31.0-0ubuntu1/debian/compat
--- 1.30.0-3/debian/compat	1970-01-01 00:00:00.000000000 +0000
+++ 1.31.0-0ubuntu1/debian/compat	2019-07-17 14:49:26.000000000 +0000
@@ -0,0 +1 @@
+10
diff -pruN 1.30.0-3/debian/control 1.31.0-0ubuntu1/debian/control
--- 1.30.0-3/debian/control	2019-08-21 19:18:32.000000000 +0000
+++ 1.31.0-0ubuntu1/debian/control	2019-07-17 14:49:26.000000000 +0000
@@ -1,39 +1,52 @@
 Source: python-shade
 Section: python
 Priority: optional
-Maintainer: Debian Python Modules Team <python-modules-team@lists.alioth.debian.org>
-Uploaders: Clint Byrum <spamaps@debian.org>
-Build-Depends: debhelper-compat (= 9),
-    dh-python,
-    python3-all,
-    python3-setuptools,
-    python3-pbr,
-    python3-sphinx,
-    python3-testtools,
-    python3-stestr (>= 2.3.1-1~),
-    python3-dogpile.cache,
-    python3-os-client-config (>=1.28.0),
-    python3-mock,
-    python3-testscenarios,
-    python3-openstacksdk (>=0.15.0),
-    python3-munch,
-    python3-keystoneauth1,
-    python3-jsonpatch,
-    python3-six,
-    python3-munch,
-    python3-requestsexceptions (>= 1.1.1),
-    python3-decorator,
-    python3-betamax,
-    python3-requests-mock,
-    python3-argparse-manpage,
+Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
+XSBC-Original-Maintainer: Debian Python Modules Team <python-modules-team@lists.alioth.debian.org>
+Uploaders:
+ Clint Byrum <spamaps@debian.org>,
+Build-Depends:
+ debhelper (>= 10~),
+ dh-python,
+ openstack-pkg-tools,
+ python-all,
+ python-pbr (>= 2.0.0),
+ python-setuptools,
+ python3-all,
+ python3-pbr (>= 2.0.0),
+ python3-setuptools,
+ python3-sphinx (>= 1.6.2),
+Build-Depends-Indep:
+ python3-argparse-manpage,
+ python3-betamax,
+ python3-decorator,
+ python3-dogpile.cache,
+ python3-jsonpatch,
+ python3-keystoneauth1,
+ python3-mock (>= 2.0.0),
+ python3-munch,
+ python3-openstacksdk (>= 0.15.0),
+ python3-os-client-config (>= 1.28.0),
+ python3-requests-mock (>= 1.2.0),
+ python3-requestsexceptions (>= 1.1.1),
+ python3-six,
+ python3-stestr (>= 1.0.0),
+ python3-testscenarios (>= 0.4),
+ python3-testtools (>= 2.2.0),
 Standards-Version: 3.9.8
 Homepage: https://pypi.python.org/pypi/shade
-Vcs-Git: https://salsa.debian.org/python-team/modules/python-shade.git
-Vcs-Browser: https://salsa.debian.org/python-team/modules/python-shade
+Vcs-Git: https://git.launchpad.net/~ubuntu-server-dev/ubuntu/+source/python-shade
+Vcs-Browser: https://git.launchpad.net/~ubuntu-server-dev/ubuntu/+source/python-shade
 
 Package: python3-shade
 Architecture: all
-Depends: ${misc:Depends},${python3:Depends}
+Depends:
+ python3-keystoneauth1,
+ python3-keystoneclient,
+ python3-openstacksdk (>= 0.15.0),
+ python3-os-client-config (>= 1.28.0),
+ ${misc:Depends},
+ ${python3:Depends},
 Description: Client library for operating OpenStack clouds
  Shade is a simple Python client library for operating OpenStack
  clouds. The key word here is simple. Clouds can do many things - but
@@ -48,8 +61,12 @@ Description: Client library for operatin
 
 Package: shade-inventory
 Architecture: all
-Depends: ${misc:Depends},${python3:Depends},python3-shade (= ${source:Version})
-Suggests: ansible
+Depends:
+ python3-shade (= ${source:Version}),
+ ${misc:Depends},
+ ${python3:Depends},
+Suggests:
+ ansible,
 Description: Ansible inventory script for OpenStack clouds
  Shade is a simple Python client library for operating OpenStack
  clouds. The key word here is simple. Clouds can do many things - but
diff -pruN 1.30.0-3/debian/gbp.conf 1.31.0-0ubuntu1/debian/gbp.conf
--- 1.30.0-3/debian/gbp.conf	1970-01-01 00:00:00.000000000 +0000
+++ 1.31.0-0ubuntu1/debian/gbp.conf	2019-07-17 14:49:26.000000000 +0000
@@ -0,0 +1,7 @@
+[DEFAULT]
+debian-branch = master
+upstream-tag = %(version)s
+pristine-tar = True
+
+[buildpackage]
+export-dir = ../build-area
diff -pruN 1.30.0-3/debian/patches/0001-Split-parser-creation-and-parser-for-inventory.patch 1.31.0-0ubuntu1/debian/patches/0001-Split-parser-creation-and-parser-for-inventory.patch
--- 1.30.0-3/debian/patches/0001-Split-parser-creation-and-parser-for-inventory.patch	2019-08-21 19:18:32.000000000 +0000
+++ 1.31.0-0ubuntu1/debian/patches/0001-Split-parser-creation-and-parser-for-inventory.patch	1970-01-01 00:00:00.000000000 +0000
@@ -1,44 +0,0 @@
-From: Clint Byrum <clint@fewbar.com>
-Date: Sun, 6 Jan 2019 21:07:09 -0800
-Subject: Split parser creation and parser for inventory
-
-Access to the object separate from parsing allows us to use
-argparse-manpage to generate a man page in the Debian package
-automatically. We also need to set 'prog' explicitly rather
-than let it be picked up via argv[0] so that when we load
-the parser via argparse-manpage it produces the right value.
-
-Change-Id: I654b4408444f804f900951333a6ebc3372d5037e
----
- shade/cmd/inventory.py | 11 ++++++++---
- 1 file changed, 8 insertions(+), 3 deletions(-)
-
-diff --git a/shade/cmd/inventory.py b/shade/cmd/inventory.py
-index 26d6152..ab3a265 100755
---- a/shade/cmd/inventory.py
-+++ b/shade/cmd/inventory.py
-@@ -29,8 +29,9 @@ def output_format_dict(data, use_yaml):
-         return json.dumps(data, sort_keys=True, indent=2)
- 
- 
--def parse_args():
--    parser = argparse.ArgumentParser(description='OpenStack Inventory Module')
-+def get_parser():
-+    parser = argparse.ArgumentParser(description='OpenStack Inventory Module',
-+                                     prog='shade-inventory')
-     parser.add_argument('--refresh', action='store_true',
-                         help='Refresh cached information')
-     group = parser.add_mutually_exclusive_group(required=True)
-@@ -45,7 +46,11 @@ def parse_args():
-                         help='Output data in nicely readable yaml')
-     parser.add_argument('--debug', action='store_true', default=False,
-                         help='Enable debug output')
--    return parser.parse_args()
-+    return parser
-+
-+
-+def parse_args():
-+    return get_parser().parse_args()
- 
- 
- def main():
diff -pruN 1.30.0-3/debian/patches/0002-Fix-dogpile.cache-0.7.0-interaction.patch 1.31.0-0ubuntu1/debian/patches/0002-Fix-dogpile.cache-0.7.0-interaction.patch
--- 1.30.0-3/debian/patches/0002-Fix-dogpile.cache-0.7.0-interaction.patch	2019-08-21 19:18:32.000000000 +0000
+++ 1.31.0-0ubuntu1/debian/patches/0002-Fix-dogpile.cache-0.7.0-interaction.patch	1970-01-01 00:00:00.000000000 +0000
@@ -1,59 +0,0 @@
-From: Morgan Fainberg <morgan.fainberg@gmail.com>
-Date: Fri, 14 Dec 2018 14:46:40 -0800
-Subject: Fix dogpile.cache 0.7.0 interaction
-
-Due to the change in behavior in dogpile.cache > 0.7.0 where bound
-methods can no longer be passed to the cache_on_arguments decorator,
-openstackSDK now explicitly provides a non-method wrapper for all
-elements passed to cache_on_arguments. This is handled via an explicit
-no-op decorator. functools.wraps is used to preserve data from the
-original method.
-
-Needed-By: https://review.openstack.org/#/c/624993
-Change-Id: Ied27fa1e834d145246815afcb67c59d48669ffb2
-Story: 2004605
-Task: 28502
----
- shade/_utils.py | 15 ++++++++++++++-
- 1 file changed, 14 insertions(+), 1 deletion(-)
-
-diff --git a/shade/_utils.py b/shade/_utils.py
-index 3ca54d1..9cf566d 100644
---- a/shade/_utils.py
-+++ b/shade/_utils.py
-@@ -14,6 +14,7 @@
- 
- import contextlib
- import fnmatch
-+import functools
- import inspect
- import jmespath
- import munch
-@@ -414,6 +415,18 @@ def valid_kwargs(*valid_args):
-     return func_wrapper
- 
- 
-+def _func_wrap(f):
-+    # NOTE(morgan): This extra wrapper is intended to eliminate ever
-+    # passing a bound method to dogpile.cache's cache_on_arguments. In
-+    # 0.7.0 and later it is impossible to pass bound methods to the
-+    # decorator. This was introduced when utilizing the decorate module in
-+    # lieu of a direct wrap implementation.
-+    @functools.wraps(f)
-+    def inner(*args, **kwargs):
-+        return f(*args, **kwargs)
-+    return inner
-+
-+
- def cache_on_arguments(*cache_on_args, **cache_on_kwargs):
-     _cache_name = cache_on_kwargs.pop('resource', None)
- 
-@@ -421,7 +434,7 @@ def cache_on_arguments(*cache_on_args, **cache_on_kwargs):
-         def _cache_decorator(obj, *args, **kwargs):
-             the_method = obj._get_cache(_cache_name).cache_on_arguments(
-                 *cache_on_args, **cache_on_kwargs)(
--                    func.__get__(obj, type(obj)))
-+                    _func_wrap(func.__get__(obj, type(obj))))
-             return the_method(*args, **kwargs)
- 
-         def invalidate(obj, *args, **kwargs):
diff -pruN 1.30.0-3/debian/patches/series 1.31.0-0ubuntu1/debian/patches/series
--- 1.30.0-3/debian/patches/series	2019-08-21 19:18:32.000000000 +0000
+++ 1.31.0-0ubuntu1/debian/patches/series	1970-01-01 00:00:00.000000000 +0000
@@ -1,2 +0,0 @@
-0001-Split-parser-creation-and-parser-for-inventory.patch
-0002-Fix-dogpile.cache-0.7.0-interaction.patch
diff -pruN 1.30.0-3/debian/rules 1.31.0-0ubuntu1/debian/rules
--- 1.30.0-3/debian/rules	2019-08-21 19:18:32.000000000 +0000
+++ 1.31.0-0ubuntu1/debian/rules	2019-07-17 14:49:26.000000000 +0000
@@ -2,7 +2,7 @@
 export PYBUILD_NAME=shade
 
 %:
-		dh $@ --with python3 --buildsystem=pybuild
+	dh $@ --with python3 --buildsystem=pybuild
 
 override_dh_install:
 	dh_install -O--buildsystem=pybuild
@@ -16,6 +16,5 @@ debian/shade-inventory.1:
 
 override_dh_auto_test:
 ifeq (,$(filter nocheck, $(DEB_BUILD_OPTIONS)))
-	stestr run
-	stestr slowest
+	pkgos-dh_auto_test --no-py2
 endif
diff -pruN 1.30.0-3/PKG-INFO 1.31.0-0ubuntu1/PKG-INFO
--- 1.30.0-3/PKG-INFO	2018-10-19 14:13:30.000000000 +0000
+++ 1.31.0-0ubuntu1/PKG-INFO	2019-03-07 23:58:00.000000000 +0000
@@ -1,10 +1,10 @@
 Metadata-Version: 1.1
 Name: shade
-Version: 1.30.0
+Version: 1.31.0
 Summary: Simple client library for interacting with OpenStack clouds
 Home-page: http://docs.openstack.org/shade/latest
 Author: OpenStack
-Author-email: openstack-dev@lists.openstack.org
+Author-email: openstack-discuss@lists.openstack.org
 License: UNKNOWN
 Description: Introduction
         ============
@@ -108,4 +108,4 @@ Classifier: Programming Language :: Pyth
 Classifier: Programming Language :: Python :: 2
 Classifier: Programming Language :: Python :: 2.7
 Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.4
+Classifier: Programming Language :: Python :: 3.5
diff -pruN 1.30.0-3/setup.cfg 1.31.0-0ubuntu1/setup.cfg
--- 1.30.0-3/setup.cfg	2018-10-19 14:13:30.000000000 +0000
+++ 1.31.0-0ubuntu1/setup.cfg	2019-03-07 23:58:00.000000000 +0000
@@ -4,7 +4,7 @@ summary = Simple client library for inte
 description-file = 
 	README.rst
 author = OpenStack
-author-email = openstack-dev@lists.openstack.org
+author-email = openstack-discuss@lists.openstack.org
 home-page = http://docs.openstack.org/shade/latest
 classifier = 
 	Environment :: OpenStack
@@ -16,7 +16,7 @@ classifier =
 	Programming Language :: Python :: 2
 	Programming Language :: Python :: 2.7
 	Programming Language :: Python :: 3
-	Programming Language :: Python :: 3.4
+	Programming Language :: Python :: 3.5
 
 [entry_points]
 console_scripts = 
diff -pruN 1.30.0-3/shade/cmd/inventory.py 1.31.0-0ubuntu1/shade/cmd/inventory.py
--- 1.30.0-3/shade/cmd/inventory.py	2018-10-19 14:12:46.000000000 +0000
+++ 1.31.0-0ubuntu1/shade/cmd/inventory.py	2019-03-07 23:56:16.000000000 +0000
@@ -29,8 +29,9 @@ def output_format_dict(data, use_yaml):
         return json.dumps(data, sort_keys=True, indent=2)
 
 
-def parse_args():
-    parser = argparse.ArgumentParser(description='OpenStack Inventory Module')
+def get_parser():
+    parser = argparse.ArgumentParser(description='OpenStack Inventory Module',
+                                     prog='shade-inventory')
     parser.add_argument('--refresh', action='store_true',
                         help='Refresh cached information')
     group = parser.add_mutually_exclusive_group(required=True)
@@ -45,7 +46,11 @@ def parse_args():
                         help='Output data in nicely readable yaml')
     parser.add_argument('--debug', action='store_true', default=False,
                         help='Enable debug output')
-    return parser.parse_args()
+    return parser
+
+
+def parse_args():
+    return get_parser().parse_args()
 
 
 def main():
diff -pruN 1.30.0-3/shade/openstackcloud.py 1.31.0-0ubuntu1/shade/openstackcloud.py
--- 1.30.0-3/shade/openstackcloud.py	2018-10-19 14:12:46.000000000 +0000
+++ 1.31.0-0ubuntu1/shade/openstackcloud.py	2019-03-07 23:56:16.000000000 +0000
@@ -10913,7 +10913,12 @@ class OpenStackCloud(
                 self.get_domain(domain)['id']
 
         if user:
-            data['user'] = self.get_user(user, filters=filters)
+            if domain:
+                data['user'] = self.get_user(user,
+                                             domain_id=filters['domain_id'],
+                                             filters=filters)
+            else:
+                data['user'] = self.get_user(user, filters=filters)
 
         if project:
             # drop domain in favor of project
diff -pruN 1.30.0-3/shade/tests/functional/test_inventory.py 1.31.0-0ubuntu1/shade/tests/functional/test_inventory.py
--- 1.30.0-3/shade/tests/functional/test_inventory.py	2018-10-19 14:12:46.000000000 +0000
+++ 1.31.0-0ubuntu1/shade/tests/functional/test_inventory.py	2019-03-07 23:56:16.000000000 +0000
@@ -30,7 +30,7 @@ class TestInventory(base.BaseFunctionalT
         super(TestInventory, self).setUp()
         # This needs to use an admin account, otherwise a public IP
         # is not allocated from devstack.
-        self.inventory = inventory.OpenStackInventory()
+        self.inventory = inventory.OpenStackInventory(cloud='devstack-admin')
         self.server_name = self.getUniqueString('inventory')
         self.flavor = pick_flavor(
             self.user_cloud.list_flavors(get_extra=False))
diff -pruN 1.30.0-3/shade/tests/unit/test_role_assignment.py 1.31.0-0ubuntu1/shade/tests/unit/test_role_assignment.py
--- 1.30.0-3/shade/tests/unit/test_role_assignment.py	2018-10-19 14:12:46.000000000 +0000
+++ 1.31.0-0ubuntu1/shade/tests/unit/test_role_assignment.py	2019-03-07 23:56:16.000000000 +0000
@@ -662,7 +662,11 @@ class TestRoleAssignment(base.RequestsMo
                  status_code=200,
                  json=self.domain_data.json_response),
             dict(method='GET',
-                 uri=self.get_mock_url(resource='users'),
+                 uri=self.get_mock_url(resource='users',
+                                       qs_elements=['domain_id=%s' %
+                                                    self.domain_data.
+                                                    domain_id]),
+                 complete_qs=True,
                  status_code=200,
                  json={'users': [self.user_data.json_response['user']]}),
             dict(method='GET',
@@ -693,7 +697,11 @@ class TestRoleAssignment(base.RequestsMo
                  status_code=200,
                  json=self.domain_data.json_response),
             dict(method='GET',
-                 uri=self.get_mock_url(resource='users'),
+                 uri=self.get_mock_url(resource='users',
+                                       qs_elements=['domain_id=%s' %
+                                                    self.domain_data.
+                                                    domain_id]),
+                 complete_qs=True,
                  status_code=200,
                  json={'users': [self.user_data.json_response['user']]}),
             dict(method='GET',
@@ -724,7 +732,11 @@ class TestRoleAssignment(base.RequestsMo
                  status_code=200,
                  json=self.domain_data.json_response),
             dict(method='GET',
-                 uri=self.get_mock_url(resource='users'),
+                 uri=self.get_mock_url(resource='users',
+                                       qs_elements=['domain_id=%s' %
+                                                    self.domain_data.
+                                                    domain_id]),
+                 complete_qs=True,
                  status_code=200,
                  json={'users': [self.user_data.json_response['user']]}),
             dict(method='GET',
@@ -755,7 +767,11 @@ class TestRoleAssignment(base.RequestsMo
                  status_code=200,
                  json=self.domain_data.json_response),
             dict(method='GET',
-                 uri=self.get_mock_url(resource='users'),
+                 uri=self.get_mock_url(resource='users',
+                                       qs_elements=['domain_id=%s' %
+                                                    self.domain_data.
+                                                    domain_id]),
+                 complete_qs=True,
                  status_code=200,
                  json={'users': [self.user_data.json_response['user']]}),
             dict(method='GET',
@@ -807,7 +823,11 @@ class TestRoleAssignment(base.RequestsMo
                  status_code=200,
                  json=self.domain_data.json_response),
             dict(method='GET',
-                 uri=self.get_mock_url(resource='users'),
+                 uri=self.get_mock_url(resource='users',
+                                       qs_elements=['domain_id=%s' %
+                                                    self.domain_data.
+                                                    domain_id]),
+                 complete_qs=True,
                  status_code=200,
                  json={'users': [self.user_data.json_response['user']]}),
             dict(method='GET',
@@ -836,7 +856,11 @@ class TestRoleAssignment(base.RequestsMo
                  status_code=200,
                  json=self.domain_data.json_response),
             dict(method='GET',
-                 uri=self.get_mock_url(resource='users'),
+                 uri=self.get_mock_url(resource='users',
+                                       qs_elements=['domain_id=%s' %
+                                                    self.domain_data.
+                                                    domain_id]),
+                 complete_qs=True,
                  status_code=200,
                  json={'users': [self.user_data.json_response['user']]}),
             dict(method='GET',
@@ -865,7 +889,11 @@ class TestRoleAssignment(base.RequestsMo
                  status_code=200,
                  json=self.domain_data.json_response),
             dict(method='GET',
-                 uri=self.get_mock_url(resource='users'),
+                 uri=self.get_mock_url(resource='users',
+                                       qs_elements=['domain_id=%s' %
+                                                    self.domain_data.
+                                                    domain_id]),
+                 complete_qs=True,
                  status_code=200,
                  json={'users': [self.user_data.json_response['user']]}),
             dict(method='GET',
@@ -894,7 +922,11 @@ class TestRoleAssignment(base.RequestsMo
                  status_code=200,
                  json=self.domain_data.json_response),
             dict(method='GET',
-                 uri=self.get_mock_url(resource='users'),
+                 uri=self.get_mock_url(resource='users',
+                                       qs_elements=['domain_id=%s' %
+                                                    self.domain_data.
+                                                    domain_id]),
+                 complete_qs=True,
                  status_code=200,
                  json={'users': [self.user_data.json_response['user']]}),
             dict(method='GET',
@@ -1768,7 +1800,11 @@ class TestRoleAssignment(base.RequestsMo
                  status_code=200,
                  json=self.domain_data.json_response),
             dict(method='GET',
-                 uri=self.get_mock_url(resource='users'),
+                 uri=self.get_mock_url(resource='users',
+                                       qs_elements=['domain_id=%s' %
+                                                    self.domain_data.
+                                                    domain_id]),
+                 complete_qs=True,
                  status_code=200,
                  json={'users': [self.user_data.json_response['user']]}),
             dict(method='GET',
@@ -1791,7 +1827,11 @@ class TestRoleAssignment(base.RequestsMo
                  status_code=200,
                  json=self.domain_data.json_response),
             dict(method='GET',
-                 uri=self.get_mock_url(resource='users'),
+                 uri=self.get_mock_url(resource='users',
+                                       qs_elements=['domain_id=%s' %
+                                                    self.domain_data.
+                                                    domain_id]),
+                 complete_qs=True,
                  status_code=200,
                  json={'users': [self.user_data.json_response['user']]}),
             dict(method='GET',
@@ -1814,7 +1854,11 @@ class TestRoleAssignment(base.RequestsMo
                  status_code=200,
                  json=self.domain_data.json_response),
             dict(method='GET',
-                 uri=self.get_mock_url(resource='users'),
+                 uri=self.get_mock_url(resource='users',
+                                       qs_elements=['domain_id=%s' %
+                                                    self.domain_data.
+                                                    domain_id]),
+                 complete_qs=True,
                  status_code=200,
                  json={'users': [self.user_data.json_response['user']]}),
             dict(method='GET',
@@ -1837,7 +1881,11 @@ class TestRoleAssignment(base.RequestsMo
                  status_code=200,
                  json=self.domain_data.json_response),
             dict(method='GET',
-                 uri=self.get_mock_url(resource='users'),
+                 uri=self.get_mock_url(resource='users',
+                                       qs_elements=['domain_id=%s' %
+                                                    self.domain_data.
+                                                    domain_id]),
+                 complete_qs=True,
                  status_code=200,
                  json={'users': [self.user_data.json_response['user']]}),
             dict(method='GET',
@@ -1881,7 +1929,11 @@ class TestRoleAssignment(base.RequestsMo
                  status_code=200,
                  json=self.domain_data.json_response),
             dict(method='GET',
-                 uri=self.get_mock_url(resource='users'),
+                 uri=self.get_mock_url(resource='users',
+                                       qs_elements=['domain_id=%s' %
+                                                    self.domain_data.
+                                                    domain_id]),
+                 complete_qs=True,
                  status_code=200,
                  json={'users': [self.user_data.json_response['user']]}),
             dict(method='GET',
@@ -1917,7 +1969,11 @@ class TestRoleAssignment(base.RequestsMo
                  status_code=200,
                  json=self.domain_data.json_response),
             dict(method='GET',
-                 uri=self.get_mock_url(resource='users'),
+                 uri=self.get_mock_url(resource='users',
+                                       qs_elements=['domain_id=%s' %
+                                                    self.domain_data.
+                                                    domain_id]),
+                 complete_qs=True,
                  status_code=200,
                  json={'users': [self.user_data.json_response['user']]}),
             dict(method='GET',
@@ -1953,7 +2009,11 @@ class TestRoleAssignment(base.RequestsMo
                  status_code=200,
                  json=self.domain_data.json_response),
             dict(method='GET',
-                 uri=self.get_mock_url(resource='users'),
+                 uri=self.get_mock_url(resource='users',
+                                       qs_elements=['domain_id=%s' %
+                                                    self.domain_data.
+                                                    domain_id]),
+                 complete_qs=True,
                  status_code=200,
                  json={'users': [self.user_data.json_response['user']]}),
             dict(method='GET',
@@ -1989,7 +2049,11 @@ class TestRoleAssignment(base.RequestsMo
                  status_code=200,
                  json=self.domain_data.json_response),
             dict(method='GET',
-                 uri=self.get_mock_url(resource='users'),
+                 uri=self.get_mock_url(resource='users',
+                                       qs_elements=['domain_id=%s' %
+                                                    self.domain_data.
+                                                    domain_id]),
+                 complete_qs=True,
                  status_code=200,
                  json={'users': [self.user_data.json_response['user']]}),
             dict(method='GET',
@@ -2478,7 +2542,11 @@ class TestRoleAssignment(base.RequestsMo
                  status_code=200,
                  json=self.domain_data.json_response),
             dict(method='GET',
-                 uri=self.get_mock_url(resource='users'),
+                 uri=self.get_mock_url(resource='users',
+                                       qs_elements=['domain_id=%s' %
+                                                    self.domain_data.
+                                                    domain_id]),
+                 complete_qs=True,
                  status_code=200,
                  json={'users': [self.user_data.json_response['user']]}),
             dict(method='GET',
@@ -2527,7 +2595,11 @@ class TestRoleAssignment(base.RequestsMo
                  status_code=200,
                  json=self.domain_data.json_response),
             dict(method='GET',
-                 uri=self.get_mock_url(resource='users'),
+                 uri=self.get_mock_url(resource='users',
+                                       qs_elements=['domain_id=%s' %
+                                                    self.domain_data.
+                                                    domain_id]),
+                 complete_qs=True,
                  status_code=200,
                  json={'users': [self.user_data.json_response['user']]}),
             dict(method='GET',
diff -pruN 1.30.0-3/shade/_utils.py 1.31.0-0ubuntu1/shade/_utils.py
--- 1.30.0-3/shade/_utils.py	2018-10-19 14:12:46.000000000 +0000
+++ 1.31.0-0ubuntu1/shade/_utils.py	2019-03-07 23:56:16.000000000 +0000
@@ -14,6 +14,7 @@
 
 import contextlib
 import fnmatch
+import functools
 import inspect
 import jmespath
 import munch
@@ -414,6 +415,18 @@ def valid_kwargs(*valid_args):
     return func_wrapper
 
 
+def _func_wrap(f):
+    # NOTE(morgan): This extra wrapper is intended to eliminate ever
+    # passing a bound method to dogpile.cache's cache_on_arguments. In
+    # 0.7.0 and later it is impossible to pass bound methods to the
+    # decorator. This was introduced when utilizing the decorate module in
+    # lieu of a direct wrap implementation.
+    @functools.wraps(f)
+    def inner(*args, **kwargs):
+        return f(*args, **kwargs)
+    return inner
+
+
 def cache_on_arguments(*cache_on_args, **cache_on_kwargs):
     _cache_name = cache_on_kwargs.pop('resource', None)
 
@@ -421,7 +434,7 @@ def cache_on_arguments(*cache_on_args, *
         def _cache_decorator(obj, *args, **kwargs):
             the_method = obj._get_cache(_cache_name).cache_on_arguments(
                 *cache_on_args, **cache_on_kwargs)(
-                    func.__get__(obj, type(obj)))
+                    _func_wrap(func.__get__(obj, type(obj))))
             return the_method(*args, **kwargs)
 
         def invalidate(obj, *args, **kwargs):
diff -pruN 1.30.0-3/shade.egg-info/pbr.json 1.31.0-0ubuntu1/shade.egg-info/pbr.json
--- 1.30.0-3/shade.egg-info/pbr.json	2018-10-19 14:13:30.000000000 +0000
+++ 1.31.0-0ubuntu1/shade.egg-info/pbr.json	2019-03-07 23:58:00.000000000 +0000
@@ -1 +1 @@
-{"git_version": "6f40858", "is_release": true}
\ No newline at end of file
+{"git_version": "b23000c", "is_release": true}
\ No newline at end of file
diff -pruN 1.30.0-3/shade.egg-info/PKG-INFO 1.31.0-0ubuntu1/shade.egg-info/PKG-INFO
--- 1.30.0-3/shade.egg-info/PKG-INFO	2018-10-19 14:13:30.000000000 +0000
+++ 1.31.0-0ubuntu1/shade.egg-info/PKG-INFO	2019-03-07 23:58:00.000000000 +0000
@@ -1,10 +1,10 @@
 Metadata-Version: 1.1
 Name: shade
-Version: 1.30.0
+Version: 1.31.0
 Summary: Simple client library for interacting with OpenStack clouds
 Home-page: http://docs.openstack.org/shade/latest
 Author: OpenStack
-Author-email: openstack-dev@lists.openstack.org
+Author-email: openstack-discuss@lists.openstack.org
 License: UNKNOWN
 Description: Introduction
         ============
@@ -108,4 +108,4 @@ Classifier: Programming Language :: Pyth
 Classifier: Programming Language :: Python :: 2
 Classifier: Programming Language :: Python :: 2.7
 Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.4
+Classifier: Programming Language :: Python :: 3.5
diff -pruN 1.30.0-3/tox.ini 1.31.0-0ubuntu1/tox.ini
--- 1.30.0-3/tox.ini	2018-10-19 14:12:46.000000000 +0000
+++ 1.31.0-0ubuntu1/tox.ini	2019-03-07 23:56:16.000000000 +0000
@@ -1,6 +1,6 @@
 [tox]
-minversion = 1.6
-envlist = py35,py27,pep8
+minversion = 2.0
+envlist = py36,py35,py27,pep8
 skipsdist = True
 
 [testenv]
@@ -68,7 +68,7 @@ deps =
     -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt}
     -r{toxinidir}/requirements.txt
     -r{toxinidir}/test-requirements.txt
-    ansible<=2.5
+    ansible<2.6
 commands = {toxinidir}/extras/run-ansible-tests.sh -e {envdir} {posargs}
 
 [testenv:docs]
diff -pruN 1.30.0-3/.zuul.yaml 1.31.0-0ubuntu1/.zuul.yaml
--- 1.30.0-3/.zuul.yaml	2018-10-19 14:12:46.000000000 +0000
+++ 1.31.0-0ubuntu1/.zuul.yaml	2019-03-07 23:56:16.000000000 +0000
@@ -229,7 +229,7 @@
       jobs:
         - bifrost-integration-tinyipa:
             voting: false
-        - bifrost-integration-tinyipa-opensuse-423:
+        - bifrost-integration-tinyipa-opensuse-150:
             voting: false
         - shade-ansible-stable-2.5-functional-devstack:
             voting: false
