diff --git a/README.md b/README.md index 3624063..247d19d 100644 --- a/README.md +++ b/README.md @@ -46,9 +46,9 @@ data = { } ``` -| ![No Face](https://github.com/saintlyzero/NestedFetch/raw/development/asset/no.jpg) | ![normal code](https://github.com/saintlyzero/NestedFetch/raw/master/asset/normal.png) | +| ![No Face](https://github.com/saintlyzero/NestedFetch/raw/development/asset/no.jpg) | ![normal code](https://github.com/saintlyzero/NestedFetch/raw/master/asset/before.png) | |--|--| -| ![Yes Face](https://github.com/saintlyzero/NestedFetch/raw/master/asset/yes.jpg) |![NestedFetch code](https://github.com/saintlyzero/NestedFetch/raw/master/asset/nested_get.png) +| ![Yes Face](https://github.com/saintlyzero/NestedFetch/raw/master/asset/yes.jpg) |![NestedFetch code](https://github.com/saintlyzero/NestedFetch/raw/master/asset/after.png) ## Installation **NestedFetch** works with Python3.
You can directly install it via **pip**
diff --git a/asset/after.png b/asset/after.png new file mode 100644 index 0000000..1f4f92b Binary files /dev/null and b/asset/after.png differ diff --git a/asset/before.png b/asset/before.png new file mode 100644 index 0000000..8adc497 Binary files /dev/null and b/asset/before.png differ diff --git a/nestedfetch/__init__.py b/nestedfetch/__init__.py index ad1c7fd..5bfc4a3 100644 --- a/nestedfetch/__init__.py +++ b/nestedfetch/__init__.py @@ -1 +1 @@ -from .nested_fetch import nested_get, nested_set, flatten_data \ No newline at end of file +from .nested_fetch import nested_get, nested_set, flatten_data diff --git a/nestedfetch/nested_fetch.py b/nestedfetch/nested_fetch.py index 2fbfeeb..01129e9 100644 --- a/nestedfetch/nested_fetch.py +++ b/nestedfetch/nested_fetch.py @@ -1,44 +1,45 @@ import itertools + def flatten_data(data): """ - @Arguments: + @Arguments: - data : list + data : list - @Return: + @Return: - Returns the flattened list + Returns the flattened list """ - if isinstance(data,list): - while(any(isinstance(o, list) for o in data)): - data = list(itertools.chain.from_iterable(data)) - return data + if isinstance(data, list): + while any(isinstance(o, list) for o in data): + data = list(itertools.chain.from_iterable(data)) + return data def nested_get(data, keys, default=None, flatten=False): - ''' - @Arguments: + """ + @Arguments: - data : dict / list + data : dict / list - keys => List of sequential keys leading to the desired value to fetch + keys => List of sequential keys leading to the desired value to fetch - default => Specifies the default value to be returned if any specified key is not present. - If not specified, it will be None + default => Specifies the default value to be returned if any specified key is not present. + If not specified, it will be None - flatten => Specifies whether to flatten the returned value + flatten => Specifies whether to flatten the returned value - @Return: + @Return: - Returns the fetched value if it exists, or returns specified default value - ''' + Returns the fetched value if it exists, or returns specified default value + """ return { - True : lambda: flatten_data(_nested_get(data,keys,default)), - False : lambda: _nested_get(data,keys,default) - }.get(flatten, lambda : None)() + True: lambda: flatten_data(_nested_get(data, keys, default)), + False: lambda: _nested_get(data, keys, default), + }.get(flatten, lambda: None)() def _nested_get(data, keys, default): @@ -48,14 +49,28 @@ def _nested_get(data, keys, default): if isinstance(value, list): if isinstance(key, int): if any(isinstance(o, list) for o in value): - value = list(map((lambda o: default if (key >= len(o)) else o[key]), value)) + value = list( + map( + (lambda o: default if (key >= len(o)) else o[key]), + value, + ) + ) else: value = value[key] else: - value = list(map((lambda o: default if o == default else _nested_get(o, [key], default)), value)) + value = list( + map( + ( + lambda o: default + if o == default + else _nested_get(o, [key], default) + ), + value, + ) + ) else: value = dict.get(value, key, default) - + if value == default: break return value @@ -63,23 +78,23 @@ def _nested_get(data, keys, default): return default -def nested_set(data, keys, value, create_missing=False, _count = 0): +def nested_set(data, keys, value, create_missing=False, _count=0): """ - @Arguments: + @Arguments: - data => dict / list + data => dict / list - keys => List of sequential keys leading to the desired value to set / update + keys => List of sequential keys leading to the desired value to set / update - value => Specifies the value to set / update + value => Specifies the value to set / update - create_missing => Specifies whether to create new key while building up if the specified key does not exists + create_missing => Specifies whether to create new key while building up if the specified key does not exists - @Return: + @Return: - Returns the number of values updated + Returns the number of values updated """ d = data count = _count @@ -88,21 +103,38 @@ def nested_set(data, keys, value, create_missing=False, _count = 0): if key in d: d = d[key] if isinstance(d, list): - if (itr != len(keys)-1) and (isinstance(keys[itr+1], int)): - if (itr == len(keys)-2): + if (itr != len(keys) - 1) and (isinstance(keys[itr + 1], int)): + if itr == len(keys) - 2: d[keys[-1]] = value count += 1 else: - d = d[keys[itr+1]] - count = nested_set(d, keys[itr+2:], value, create_missing, _count= count) + d = d[keys[itr + 1]] + count = nested_set( + d, keys[itr + 2 :], value, create_missing, _count=count + ) else: - count = sum(list(map((lambda o: nested_set(o,keys[itr+1:],value,create_missing,_count = count)),d))) + count = sum( + list( + map( + ( + lambda o: nested_set( + o, + keys[itr + 1 :], + value, + create_missing, + _count=count, + ) + ), + d, + ) + ) + ) return count elif create_missing: d = d.setdefault(key, {}) else: return count - if (keys[-1] in d or create_missing): + if keys[-1] in d or create_missing: d[keys[-1]] = value return count + 1 elif (isinstance(keys[-1], int)) and isinstance(d, list): @@ -112,4 +144,3 @@ def nested_set(data, keys, value, create_missing=False, _count = 0): return count except Exception as e: return count - diff --git a/setup.py b/setup.py index ceca5b2..2f9f153 100644 --- a/setup.py +++ b/setup.py @@ -1,28 +1,39 @@ from setuptools import setup, find_packages setup( - name = 'nestedfetch', - packages = ['nestedfetch'], - version = '0.1.2', - license='MIT', - description = 'Syntactic sugar inspired by XPath to GET, SET, UPDATE and FLATTEN values from nested dictionaries and nested lists', - long_description=open("README.md").read(), - long_description_content_type='text/markdown', - author = 'Shubham Dalvi', - author_email = 'shubham.dalvi97@gmail.com', - url = 'https://github.com/saintlyzero/NestedFetch', - download_url = ('https://github.com/saintlyzero/NestedFetch/archive/v_012.tar.gz'), - keywords = ['dict','nested dictionary','nested list','list','flatten','scalpl','nestedfetch','addict','box','Nested Fetch'], - install_requires=[], - classifiers=[ - 'Development Status :: 3 - Alpha', - 'Intended Audience :: Developers', - 'Topic :: Software Development :: Libraries :: Python Modules', - 'License :: OSI Approved :: MIT License', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', - "Programming Language :: Python :: 3.7" - ] -) \ No newline at end of file + name="nestedfetch", + packages=["nestedfetch"], + version="0.1.2", + license="MIT", + description="Syntactic sugar inspired by XPath to GET, SET, UPDATE and FLATTEN values from nested dictionaries and nested lists", + long_description=open("README.md").read(), + long_description_content_type="text/markdown", + author="Shubham Dalvi", + author_email="shubham.dalvi97@gmail.com", + url="https://github.com/saintlyzero/NestedFetch", + download_url=("https://github.com/saintlyzero/NestedFetch/archive/v_012.tar.gz"), + keywords=[ + "dict", + "nested dictionary", + "nested list", + "list", + "flatten", + "scalpl", + "nestedfetch", + "addict", + "box", + "Nested Fetch", + ], + install_requires=[], + classifiers=[ + "Development Status :: 3 - Alpha", + "Intended Audience :: Developers", + "Topic :: Software Development :: Libraries :: Python Modules", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.4", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + ], +) diff --git a/test_nested_fetch.py b/test_nested_fetch.py index d54a29d..2a388e4 100644 --- a/test_nested_fetch.py +++ b/test_nested_fetch.py @@ -1,186 +1,163 @@ -import unittest +import unittest from nestedfetch import nested_get, nested_set, flatten_data + class TestNestedFetch(unittest.TestCase): - simple_get_data = { - 'name': 'Jesse Pinkman', - 'details': { - 'address':{ - 'city': 'Albuquerque' - } - } - } - + "name": "Jesse Pinkman", + "details": {"address": {"city": "Albuquerque"}}, + } nested_get_data = { - 'name': 'Walter White', - 'details': { - 'address':[{ - 'city': 'Albuquerque' - },{ - 'city': 'El Paso' - }] - } - } - + "name": "Walter White", + "details": {"address": [{"city": "Albuquerque"}, {"city": "El Paso"}]}, + } nested_ll_get_data = { - 'name': 'Walter White', - 'details': { - 'address':[{ - 'city': 'Albuquerque' - },{ - 'city': 'El Paso' - },{ - 'state': 'New Mexico' - }] - } + "name": "Walter White", + "details": { + "address": [ + {"city": "Albuquerque"}, + {"city": "El Paso"}, + {"state": "New Mexico"}, + ] + }, } - + nested_list_get_data = { - 'name': 'Walter White', - 'details': { - 'address':[[{ - 'city': 'Albuquerque' - },{ - 'city': 'El Paso' - }]] - } - } - + "name": "Walter White", + "details": {"address": [[{"city": "Albuquerque"}, {"city": "El Paso"}]]}, + } + flatten_data = { "league": "Champions League", "matches": [ { - "match_id": "match_1", - "goals": [ - { - "time": 13, - "scorrer": "Lionel Messi", - "assist": "Luis Suarez", - "details": [ + "match_id": "match_1", + "goals": [ { - "position": "outside-box" + "time": 13, + "scorrer": "Lionel Messi", + "assist": "Luis Suarez", + "details": [ + {"position": "outside-box"}, + {"position": "right-side"}, + ], }, { - "position": "right-side" - } - ] - }, - { - "time": 78, - "scorrer": "Luis Suarez", - "assist": "Ivan Rakitic", - "details": [ - { - "position": "inside-box" + "time": 78, + "scorrer": "Luis Suarez", + "assist": "Ivan Rakitic", + "details": [ + {"position": "inside-box"}, + {"position": "left-side"}, + ], }, - { - "position": "left-side" - } - ] - } - ] + ], }, { - "match_id": "match_2", - "goals": [ - { - "time": 36, - "scorrer": "C. Ronaldo", - "assist": "Luka Modric", - "details": [ - { - "position": "penalty" - }, + "match_id": "match_2", + "goals": [ { - "position": "d-box" + "time": 36, + "scorrer": "C. Ronaldo", + "assist": "Luka Modric", + "details": [{"position": "penalty"}, {"position": "d-box"}], } - ] - } - ] - } - ] - } + ], + }, + ], + } - flatten_test_data = [ - ['This','is'], - ['flattened', 'data'] - ] + flatten_test_data = [["This", "is"], ["flattened", "data"]] - flatten_nested_data = [[ - ['This','is'], - ['flattened', 'data'] - ]] + flatten_nested_data = [[["This", "is"], ["flattened", "data"]]] def test_simple_get_success(self): - res = nested_get(self.simple_get_data,['details','address','city']) - self.assertEqual(res, 'Albuquerque') - + res = nested_get(self.simple_get_data, ["details", "address", "city"]) + self.assertEqual(res, "Albuquerque") def test_nested_get_all_success(self): - res = nested_get(self.nested_get_data,['details','address','city']) - self.assertEqual(res, ['Albuquerque','El Paso']) - + res = nested_get(self.nested_get_data, ["details", "address", "city"]) + self.assertEqual(res, ["Albuquerque", "El Paso"]) def test_nested_ll_get_all_success(self): - res = nested_get(self.nested_ll_get_data,['details','address','city'], default= None) - self.assertEqual(res, ['Albuquerque','El Paso', None]) - + res = nested_get( + self.nested_ll_get_data, ["details", "address", "city"], default=None + ) + self.assertEqual(res, ["Albuquerque", "El Paso", None]) def test_nested_get_with_index_success(self): - res = nested_get(self.nested_get_data,['details','address','city', 0]) - self.assertEqual(res, 'Albuquerque') - + res = nested_get(self.nested_get_data, ["details", "address", "city", 0]) + self.assertEqual(res, "Albuquerque") def test_nested_list_get_with_index_success(self): - res = nested_get(self.nested_list_get_data,['details','address',0,0]) - self.assertEqual(res, {'city': 'Albuquerque'}) - + res = nested_get(self.nested_list_get_data, ["details", "address", 0, 0]) + self.assertEqual(res, {"city": "Albuquerque"}) def test_nested_get_with_index_error(self): - res = nested_get(self.nested_get_data,['details','address','city', 5], default=None) - self.assertEqual(res, None) - + res = nested_get( + self.nested_get_data, ["details", "address", "city", 5], default=None + ) + self.assertEqual(res, None) def test_nested_get_flatten(self): - res = nested_get(self.flatten_data,['matches','goals','scorrer'], default=None, flatten=True) - self.assertEqual(res, ['Lionel Messi', 'Luis Suarez', 'C. Ronaldo']) - + res = nested_get( + self.flatten_data, + ["matches", "goals", "scorrer"], + default=None, + flatten=True, + ) + self.assertEqual(res, ["Lionel Messi", "Luis Suarez", "C. Ronaldo"]) def test_nested_get_ll_flatten(self): - res = nested_get(self.flatten_data,['matches','goals','details'], default=None, flatten=True) - self.assertEqual(res, [{'position': 'outside-box'}, {'position': 'right-side'}, {'position': 'inside-box'}, {'position': 'left-side'}, {'position': 'penalty'}, {'position': 'd-box'}]) - + res = nested_get( + self.flatten_data, + ["matches", "goals", "details"], + default=None, + flatten=True, + ) + self.assertEqual( + res, + [ + {"position": "outside-box"}, + {"position": "right-side"}, + {"position": "inside-box"}, + {"position": "left-side"}, + {"position": "penalty"}, + {"position": "d-box"}, + ], + ) def test_simple_set_success(self): - res = nested_set(self.simple_get_data,['details','address','city'], "Denver") - self.assertEqual(res, 1) - + res = nested_set(self.simple_get_data, ["details", "address", "city"], "Denver") + self.assertEqual(res, 1) def test_simple_set_build_success(self): - res = nested_set(self.simple_get_data,['details','address','state'], "New Mexico", create_missing=True) - self.assertEqual(res, 1) - self.assertEqual(self.simple_get_data, { - 'name':'Jesse Pinkman', - 'details': { - 'address':{ - 'city':'Albuquerque', - 'state': 'New Mexico' - }}}) + res = nested_set( + self.simple_get_data, + ["details", "address", "state"], + "New Mexico", + create_missing=True, + ) + self.assertEqual(res, 1) + self.assertEqual( + self.simple_get_data, + { + "name": "Jesse Pinkman", + "details": {"address": {"city": "Albuquerque", "state": "New Mexico"}}, + }, + ) def test_simple_flatten(self): - res = flatten_data(self.flatten_test_data) - self.assertEqual(res, ['This','is','flattened','data']) - + res = flatten_data(self.flatten_test_data) + self.assertEqual(res, ["This", "is", "flattened", "data"]) def test_nested_flatten(self): - res = flatten_data(self.flatten_nested_data) - self.assertEqual(res, ['This','is','flattened','data']) - + res = flatten_data(self.flatten_nested_data) + self.assertEqual(res, ["This", "is", "flattened", "data"]) if __name__ == "__main__": - unittest.main() \ No newline at end of file + unittest.main()