From 418b15caf406eae24e8cae818ad1f1938d1e1925 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Tue, 8 Mar 2016 13:52:51 +0100 Subject: [PATCH] =?UTF-8?q?Added=20dict=20=E2=86=92=20JSON=20and=20unicode?= =?UTF-8?q?=20=E2=86=92=20UTF8=20conversion=20for=20URL=20parameters.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pillarsdk/utils.py | 32 +++++++++++++++++++++++++------- tests/test_utils.py | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 7 deletions(-) create mode 100644 tests/test_utils.py diff --git a/pillarsdk/utils.py b/pillarsdk/utils.py index 8e59c52..d7d36a9 100644 --- a/pillarsdk/utils.py +++ b/pillarsdk/utils.py @@ -1,4 +1,6 @@ +import json import re +import six from datetime import datetime try: @@ -13,8 +15,8 @@ def join_url(url, *paths): Usage:: - >>> utils.join_url("pillar:5000", "shots") - pillar:5000/shots + >>> join_url("pillar:5000", "shots") + 'pillar:5000/shots' """ for path in paths: url = re.sub(r'/?$', re.sub(r'^/?', '/', path), url) @@ -26,10 +28,25 @@ def join_url_params(url, params): Usage:: - >>> utils.join_url_params("pillar:5000/shots", {"page-id": 2, "NodeType": "Shot Group"}) - pillar:5000/shots?page-id=2&NodeType=Shot+Group + >>> join_url_params("pillar:5000/shots", {"page-id": 2, "NodeType": "Shot Group"}) + 'pillar:5000/shots?page-id=2&NodeType=Shot+Group' """ - return url + "?" + urlencode(params) + + if params is None: + return url + + def convert_to_string(param): + if isinstance(param, dict): + return json.dumps(param) + if isinstance(param, six.text_type): + return param.encode('utf-8') + return param + + jsonified_params = { + key: convert_to_string(param) + for key, param in params.items() + } + return url + "?" + urlencode(jsonified_params) def merge_dict(data, *override): @@ -38,8 +55,9 @@ def merge_dict(data, *override): Usage:: - >>> utils.merge_dict({"foo": "bar"}, {1: 2}, {"foo1": "bar2"}) - {1: 2, 'foo': 'bar', 'foo1': 'bar2'} + >>> md = merge_dict({"foo": "bar"}, {1: 2}, {"foo1": "bar2"}) + >>> md == {1: 2, 'foo': 'bar', 'foo1': 'bar2'} + True """ result = {} for current_dict in (data,) + override: diff --git a/tests/test_utils.py b/tests/test_utils.py new file mode 100644 index 0000000..5c496c2 --- /dev/null +++ b/tests/test_utils.py @@ -0,0 +1,43 @@ +# -*- encoding: utf-8 -*- + +import unittest + +try: + from urllib.parse import quote_plus +except ImportError: + # Python 2 + from urllib import quote_plus + +from pillarsdk import utils + + +class PillarUtilsTests(unittest.TestCase): + + def test_join_url_params(self): + """Test that strings and dicts work as parameters.""" + + # Test empty and None parameters + self.assertEqual('?', utils.join_url_params('', {})) + self.assertEqual('url', utils.join_url_params('url', None)) + + # Test simple string values + self.assertEqual('url?param=simple_param', utils.join_url_params('url', {'param': 'simple_param'})) + self.assertEqual('url?param=space+param', utils.join_url_params('url', {'param': 'space param'})) + + # Test dictionary + self.assertEqual('url?dict=' + quote_plus('{"key": "value"}'), + utils.join_url_params('url', {'dict': {'key': 'value'}})) + + # Test nested dictionary + self.assertEqual('url?dict=' + quote_plus('{"key": {"subkey": "subvalue"}}'), + utils.join_url_params('url', {'dict': {'key': {'subkey': 'subvalue'}}})) + + def test_join_url_params_encoding(self): + """Test that unicode objects in the query parameters are properly UTF-8 encoded.""" + + # Test simple unicode string + self.assertEqual('url?param=St%C3%BCvel', utils.join_url_params('url', {'param': u'Stüvel'})) + + # Test unicode value in string + self.assertEqual('url?dict=' + quote_plus(r'{"food": "\u0e1c\u0e31\u0e14\u0e44\u0e17\u0e22"}'), + utils.join_url_params('url', {'dict': {'food': 'ผัดไทย'}}))