diff --git a/.gitignore b/.gitignore index fda7fdd..d06015f 100644 --- a/.gitignore +++ b/.gitignore @@ -47,3 +47,4 @@ coverage.xml # Sphinx documentation docs/_build/ +.idea \ No newline at end of file diff --git a/nested_query_string/nested_query_string.py b/nested_query_string/nested_query_string.py index 5b50a2f..b1bb724 100644 --- a/nested_query_string/nested_query_string.py +++ b/nested_query_string/nested_query_string.py @@ -8,51 +8,70 @@ is_py3 = (_ver[0] == 3) if is_py2: - from urllib import quote + from urllib import quote elif is_py3: - from urllib.parse import quote + from urllib.parse import quote + class UnsupportedParameterClassException(Exception): - def __init__(self, value, obj): - self.value = value - self.obj = obj - def __str__(self): - return repr(self.value) + " <" + repr(self.obj.__class__.__name__) +":" + repr(self.obj) +">" + def __init__(self, value, obj): + self.value = value + self.obj = obj + + def __str__(self): + return repr(self.value) + " <" + repr(self.obj.__class__.__name__) + ":" + repr(self.obj) + ">" + class NestedQueryString: - @classmethod - def encode(cls, value, key = None): - class_name = value.__class__ - if class_name == dict: - result = [] - for k, v in value.items(): - result.append(cls.encode(v, cls.__append_key(key, k))) - result = '&'.join(result) - return result - elif class_name == list: - result = [] - for v in value: - result.append(cls.encode(v, key+'[]')) - result = '&'.join(result) - return result - elif class_name == str: - return key + "=" + cls.__escape(value) - elif class_name == int: - return key + "=" + str(value) - elif class_name == None: - return '' - else: - raise UnsupportedParameterClassException('Unknown value class', value) - - @classmethod - def __escape(cls, value): - return quote(value) - - @classmethod - def __append_key(cls, root_key, key): - if root_key is None: - return key - else: - return root_key + "["+key+"]" + @classmethod + def encode(cls, value, key=None): + class_name = value.__class__ + + if class_name == dict: + result = [] + for k, v in value.items(): + result.append(cls.encode(v, cls.__append_key(key, k))) + result = '&'.join(result) + return result + + if class_name == list: + result = [] + for v in value: + result.append(cls.encode(v, key + '[]')) + result = '&'.join(result) + return result + + if class_name == str: + return key + "=" + cls.__escape(value) + + if class_name == int: + return key + "=" + str(value) + + if class_name == float: + return key + "=" + str(value) + + if class_name == bool: + if value is True: + return key + "=" + 'true' + return key + "=" + 'false' + + if value is None: + return key + "=" + '' + + if class_name is None: + return '' + + raise UnsupportedParameterClassException('Unknown value class', value) + + @classmethod + def __escape(cls, value): + return quote(value) + + @classmethod + def __append_key(cls, root_key, key): + if root_key is None: + return key + else: + return root_key + "[" + key + "]" diff --git a/setup.py b/setup.py index ade84a6..84c315d 100644 --- a/setup.py +++ b/setup.py @@ -20,6 +20,7 @@ if not __version__: raise RuntimeError('Cannot find version information') + def data_for(filename): with open(filename) as fd: content = fd.read() @@ -27,22 +28,22 @@ def data_for(filename): setup( - name="nested_query_string", - version=__version__, - description='Generate nested query strings similar to rack and node qs', - license='MIT', - author='Cine.io Engineering', - author_email='engineering@cine.io', - url='https://github.com/cine-io/nested-query-string', - packages=packages, - package_data={'': ['LICENSE']}, - include_package_data=True, - install_requires=requires, - classifiers=[ - "License :: OSI Approved :: MIT License", - "Programming Language :: Python", - "Development Status :: 3 - Alpha", - "Intended Audience :: Developers", - "Topic :: Internet", - ], + name="nested_query_string", + version=__version__, + description='Generate nested query strings similar to rack and node qs', + license='MIT', + author='Cine.io Engineering', + author_email='engineering@cine.io', + url='https://github.com/cine-io/nested-query-string', + packages=packages, + package_data={'': ['LICENSE']}, + include_package_data=True, + install_requires=requires, + classifiers=[ + "License :: OSI Approved :: MIT License", + "Programming Language :: Python", + "Development Status :: 3 - Alpha", + "Intended Audience :: Developers", + "Topic :: Internet", + ], ) diff --git a/test/nested_query_string_test.py b/test/nested_query_string_test.py index 6cc9367..773b6f5 100644 --- a/test/nested_query_string_test.py +++ b/test/nested_query_string_test.py @@ -1,48 +1,74 @@ import sys, os, time -testdir = os.path.dirname(__file__) -srcdir = '../nested_query_string' -sys.path.insert(0, os.path.abspath(os.path.join(testdir, srcdir))) + +test_dir = os.path.dirname(__file__) +src_dir = '../nested_query_string' +sys.path.insert(0, os.path.abspath(os.path.join(test_dir, src_dir))) import unittest from nested_query_string import NestedQueryString, UnsupportedParameterClassException + class NestedQueryStringTestCase(unittest.TestCase): - def assertEqualQueryStrings(self, expected, actual): - expectedValues = expected.split("&") - actualValues = actual.split("&") - self.assertEqual(sorted(expected), sorted(actual)) + def assertEqualQueryStrings(self, expected, actual): + self.assertEqual(sorted(expected), sorted(actual)) + class EncodeTest(NestedQueryStringTestCase): - def runTest(self): - qs = NestedQueryString.encode({'abc': 'def'}) - self.assertEqualQueryStrings(qs, 'abc=def') + def runTest(self): + qs = NestedQueryString.encode({'abc': 'def'}) + self.assertEqualQueryStrings(qs, 'abc=def') + class EncodeNumericTest(NestedQueryStringTestCase): - def runTest(self): - qs = NestedQueryString.encode({'abc': 1}) - self.assertEqualQueryStrings(qs, 'abc=1') + def runTest(self): + qs = NestedQueryString.encode({'abc': 1}) + self.assertEqualQueryStrings(qs, 'abc=1') + + +class EncodeFloatTest(NestedQueryStringTestCase): + def runTest(self): + qs = NestedQueryString.encode({'abc': 12345.12345}) + self.assertEqualQueryStrings(qs, 'abc=12345.12345') + class EncodeNumericAndStringTest(NestedQueryStringTestCase): - def runTest(self): - qs = NestedQueryString.encode({'abc': 'def', 'ghi': 1}) - self.assertEqualQueryStrings(qs, "abc=def&ghi=1") + def runTest(self): + qs = NestedQueryString.encode({'abc': 'def', 'ghi': 1}) + self.assertEqualQueryStrings(qs, "abc=def&ghi=1") + class EncodeDictTest(NestedQueryStringTestCase): - def runTest(self): - qs = NestedQueryString.encode({'abc': {'def': 'ghi', 'jkl': 'mno'}, 'pqr': 'stu'}) - self.assertEqualQueryStrings(qs, "abc[def]=ghi&abc[jkl]=mno&pqr=stu") + def runTest(self): + qs = NestedQueryString.encode({'abc': {'def': 'ghi', 'jkl': 'mno'}, 'pqr': 'stu'}) + self.assertEqualQueryStrings(qs, "abc[def]=ghi&abc[jkl]=mno&pqr=stu") + class EncodeListTest(NestedQueryStringTestCase): - def runTest(self): - qs = NestedQueryString.encode({'abc': ['def', 'ghi']}) - self.assertEqualQueryStrings(qs, 'abc[]=def&abc[]=ghi') + def runTest(self): + qs = NestedQueryString.encode({'abc': ['def', 'ghi']}) + self.assertEqualQueryStrings(qs, 'abc[]=def&abc[]=ghi') + + +class EncodeBooleanTest(NestedQueryStringTestCase): + def runTest(self): + encode_params = { + 'name': True, + 'deep': { + 'deep_name': False + } + } + expected = 'name=true&deep[deep_name]=false' + qs = NestedQueryString.encode(encode_params) + self.assertEqual(expected, qs) + class EncodeMixedTest(NestedQueryStringTestCase): - def runTest(self): - qs = NestedQueryString.encode({'abc': ['def', {'ghi': 'jkl'}]}) - self.assertEqualQueryStrings(qs, 'abc[]=def&abc[][ghi]=jkl') + def runTest(self): + qs = NestedQueryString.encode({'abc': ['def', {'ghi': 'jkl'}]}) + self.assertEqualQueryStrings(qs, 'abc[]=def&abc[][ghi]=jkl') + class EncodeExceptionTest(NestedQueryStringTestCase): - def runTest(self): - with self.assertRaises(UnsupportedParameterClassException): - NestedQueryString.encode({'abc': EncodeExceptionTest}) + def runTest(self): + with self.assertRaises(UnsupportedParameterClassException): + NestedQueryString.encode({'abc': EncodeExceptionTest})