From dc9e4491779c0347f4eb770de03827b967541bf3 Mon Sep 17 00:00:00 2001 From: Roman Bogorodskiy Date: Thu, 22 Sep 2016 02:06:53 -0400 Subject: [PATCH] Fix non-ascii attributes It's possible to set and get custom attributes through the API, and it's also possible to use any Unicode strings, not only ASCII range. It works perfectly fine when accessing the API directly using e.g. curl. However, keystoneclient stumbles on the non-ascii keys because it tries to set this as an attribute for the resource class and fails because Python 2.7 does not support non-ascii identifiers: https://docs.python.org/2.7/reference/lexical_analysis.html#identifiers So change the logic to skip setting non-ascii attributes; they are still available in the dict representation. Closes-Bug: #1626403 Change-Id: I267188cdb1d303e3d0fb6bd3229b606f4fe9b2d8 --- keystoneclient/base.py | 9 ++++++++- keystoneclient/tests/unit/test_base.py | 10 ++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/keystoneclient/base.py b/keystoneclient/base.py index 3f13a6cc9..af37222eb 100644 --- a/keystoneclient/base.py +++ b/keystoneclient/base.py @@ -479,7 +479,14 @@ class Resource(object): def _add_details(self, info): for (k, v) in six.iteritems(info): try: - setattr(self, k, v) + try: + setattr(self, k, v) + except UnicodeEncodeError: + # This happens when we're running with Python version that + # does not support Unicode identifiers (e.g. Python 2.7). + # In that case we can't help but not set this attrubute; + # it'll be available in a dict representation though + pass self._info[k] = v except AttributeError: # nosec(cjschaef): we already defined the # attribute on the class diff --git a/keystoneclient/tests/unit/test_base.py b/keystoneclient/tests/unit/test_base.py index 9814d3d16..f6ca651af 100644 --- a/keystoneclient/tests/unit/test_base.py +++ b/keystoneclient/tests/unit/test_base.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at @@ -96,6 +97,15 @@ class BaseTest(utils.TestCase): r = HumanReadable(None, {"name": "1 of !"}) self.assertEqual(r.human_id, "1-of") + def test_non_ascii_attr(self): + r_dict = {"name": "foobar", + u"тест": "1234", + u"тест2": u"привет мир"} + + r = base.Resource(None, r_dict) + self.assertEqual(r.name, "foobar") + self.assertEqual(r.to_dict(), r_dict) + class ManagerTest(utils.TestCase): body = {"hello": {"hi": 1}}