%global _empty_manifest_terminate_build 0 Name: python-dict-deep Version: 4.1.2 Release: 1 Summary: Very simple deep_set and deep_get functions to access nested dicts (or any object) using 'dotted strings' as key. License: MIT URL: https://github.com/mbello/dict-deep Source0: https://mirrors.nju.edu.cn/pypi/web/packages/af/4b/d14f317d1851869b1b4ac2060f80805a929b34ad9ecd69b3162ca961ad4b/dict-deep-4.1.2.tar.gz BuildArch: noarch %description ## Description Simple functions to set or get values from a nested dict structure or in fact a deep structure of any object, because since version 2 we no longer assume we are dealing with dicts. You may use a custom accessor or pass your own getter, setter, deleter callables so that you can traverse a nested structure of any kind of object. This module DOES NOT implement dotted notation as an alternative access method for dicts. I generally do not like changing python dicts to enable dot notation, hence no available package fitted my needs for a simple deep accessor. NEW IN VERSION 4: Since version 3 we make no assumption that we are dealing with dicts, so you can have your nested structure of any type. However, in version 4 we reintroduce better defaults so that for those that are indeed working with nested dicts the default values shall be enough without having to define an accessor or a getter. Notes: With deep_get, you could use 'lambda o, k: o[k]' or 'lambda o, k: o.get(k)' as either the getter or the accessor. The only 'special' thing about the 'getter' function is that when it is invoked with 'o' being a list, it will instead iterate over the list and call the accessor for each item in the list. In a simplified way, this is how deep_get works: 1. The key is broken down into a list of keys: "customer.address.city" -> ['customer', 'address', 'city'] 2. The list of keys is iterated over, calling the getter for each key and the last value retrieved is returned. ``` for k in keys[:-1]: if o is None: return o o = getter(o, k) o = getter_last_step(o, keys[-1]) return o ``` You see that getter could be as simple as 'lambda o, k: o.get(k)'. However, by default the code uses a smarter getter as defined below, which tries to deal properly with nested lists. ``` def __default_getter(o, k): if isinstance(o, list): return [accessor(i, k) for i in o] else: return accessor(o, k) ``` If you do not want this checks for nested lists, just pass your own getter which could just as well be 'lambda o, k: o.get(k)'. The default setter also knows how to deal with nested lists: ``` def __default_setter(o, k, v): n_set = 0 if isinstance(o, list): for i in o: i[k] = v n_set += 1 return n_set else: o[k] = v return 1 ``` You could just as well replace if with your own 'setter=lambda o, k, v: o[k]=v' if you know that you have no nested lists in your structures and want to avoid the overhead, but in that case you should also change the getter 'getter=lambda o, k: o.get(k)'. However, if you like the list handling skills of the code but just needs to change the way the value is retrieved, in this case you pass an accessor only to deep_get or deep_set which could be, say, 'lambda o, k: o.getValueById(k)' ## Functions *deep_get* accepts: - o: required. Any object, usually a dictionary - k: required. The key or keys, must be a string or anything accepted by the list() constructor - accessor: optional, callable: Takes o, k (object and key) and returns the value. Default accessor is 'lambda o, k: o.get(k) if hasattr(o, "get") else o[k]' - getter: optional, callable. If getter is set, accessor is ignored. Takes an object and a key as arguments and returns a value - getter_last_step: optional, callable. The getter to be used on the last step (with the last key). By default, if the last key is a list of keys, it returns a dict {k[0]: o[k[0]], k[1]: o[k[1]]}. If the last object is a list, it returns a list of dicts [{k[0]: o[0][k[0]]], k[1]: o[0][k[1]]}, {k[0]: o[1][k[0]]], k[1]: o[1][k[1]]}, ...] - sep: optional, string: by default it is a dot '.', you can use anything the string function split will accept - empty_list_as_none: bool = False. If true and the return value would be an empty list, returns None instead. - list_of_len_one_as_value: bool = False. If true and the return value would be a list with a single item, returns the item instead Returns o[k]. If o[k] does not exist, should return None (but depends on the callables used). *deep_set* accepts: - o: see 'deep_get' - k: see 'deep_get' - v: required, the value that will be set - accessor: optional, callable: see 'deep_get'. For the deep_set function, the default accessor is: 'lambda o, k: o.setdefault(k, dict()) if hasattr(o, "setdefault") else o[k]' - getter: optional, callable: see 'deep_get' - setter: optional, callable. A callable that takes 3 parameters: o, k, v - where o = any object, k = key, v = value - sep: optional, string: see 'deep_get' No return value *deep_del* accepts: - o: required: see 'deep_get' - k: required: see 'deep_get' - accessor: optional, callable: see 'deep_get' - getter: optional, callable: see 'deep_get' - deleter: optional, callable: Takes 2 parameters: o, k (object and key). - sep: optional, string: see 'deep_get' Returns an integer with the number of entries that were deleted. ## Example / Usage ``` from dict_deep import deep_get, deep_set, deep_del i = 0 # 1 i += 1 o = {'a': {'b': {}}} deep_set(o, "a.b.c", "Hello World") print("{}: {}".format(i, deep_get(o, "a.b.c"))) # 2 i += 1 o = {} deep_set(o, ['a', 'b', 'c'], "Hello World") print("{}: {}".format(i, deep_get(o, "a.b.c"))) # 3 i += 1 o = {} deep_set(o, "a->b->c", "Hello World", sep="->") print("{}: {}".format(i, deep_get(o, "a->b->c", sep="->"))) # 4 i += 1 o = {} deep_set(o, "a->b->c", "Hello World", getter=lambda o, k: o.setdefault(k, dict()), sep="->") print("{}: {}".format(i, deep_get(o, "a->b->c", sep="->"))) # 5 i += 1 o = {} keys = 'a.b.c' keys = keys.split('.') _ = deep_get(o=o, k=keys[0:-1], accessor=lambda o, k: o.setdefault(k, dict()), sep=".") _[keys[-1]] = "Hello World" print("{}: {}".format(i, deep_get(o, keys))) # 6 i += 1 o = {} deep_set(o, "1.1.1", 'a', accessor=lambda o, k: o.setdefault(k, dict())) deep_set(o, "1.1.2", 'Hello World') deep_set(o, "1.1.3", 'c') deep_del(o, "1.1.2") print("{}: {}".format(i, o)) # 7 i += 1 o = {'students': [{'name': 'Joe', 'age': 10, 'gender': 'male'}, {'name': 'Maria', 'age': 12, 'gender': 'female'}]} keys = ['students', 'name'] print("{}: {}".format(i, deep_get(o, keys))) # 8 i += 1 keys = ['students', ['name', 'age']] print("{}: {}".format(i, deep_get(o, keys))) # 9 i += 1 keys = ['students', 'gender'] deep_set(o, keys, 'Nowadays better not ask') print("{}: {}".format(i, o)) # 10 i += 1 keys = ['students', 'gender'] deep_del(o, keys) print("{}: {}".format(i, o)) # 11 i += 1 keys = ['director', 'name'] print("{}: {}".format(i, deep_get(o, keys))) ``` %package -n python3-dict-deep Summary: Very simple deep_set and deep_get functions to access nested dicts (or any object) using 'dotted strings' as key. Provides: python-dict-deep BuildRequires: python3-devel BuildRequires: python3-setuptools BuildRequires: python3-pip %description -n python3-dict-deep ## Description Simple functions to set or get values from a nested dict structure or in fact a deep structure of any object, because since version 2 we no longer assume we are dealing with dicts. You may use a custom accessor or pass your own getter, setter, deleter callables so that you can traverse a nested structure of any kind of object. This module DOES NOT implement dotted notation as an alternative access method for dicts. I generally do not like changing python dicts to enable dot notation, hence no available package fitted my needs for a simple deep accessor. NEW IN VERSION 4: Since version 3 we make no assumption that we are dealing with dicts, so you can have your nested structure of any type. However, in version 4 we reintroduce better defaults so that for those that are indeed working with nested dicts the default values shall be enough without having to define an accessor or a getter. Notes: With deep_get, you could use 'lambda o, k: o[k]' or 'lambda o, k: o.get(k)' as either the getter or the accessor. The only 'special' thing about the 'getter' function is that when it is invoked with 'o' being a list, it will instead iterate over the list and call the accessor for each item in the list. In a simplified way, this is how deep_get works: 1. The key is broken down into a list of keys: "customer.address.city" -> ['customer', 'address', 'city'] 2. The list of keys is iterated over, calling the getter for each key and the last value retrieved is returned. ``` for k in keys[:-1]: if o is None: return o o = getter(o, k) o = getter_last_step(o, keys[-1]) return o ``` You see that getter could be as simple as 'lambda o, k: o.get(k)'. However, by default the code uses a smarter getter as defined below, which tries to deal properly with nested lists. ``` def __default_getter(o, k): if isinstance(o, list): return [accessor(i, k) for i in o] else: return accessor(o, k) ``` If you do not want this checks for nested lists, just pass your own getter which could just as well be 'lambda o, k: o.get(k)'. The default setter also knows how to deal with nested lists: ``` def __default_setter(o, k, v): n_set = 0 if isinstance(o, list): for i in o: i[k] = v n_set += 1 return n_set else: o[k] = v return 1 ``` You could just as well replace if with your own 'setter=lambda o, k, v: o[k]=v' if you know that you have no nested lists in your structures and want to avoid the overhead, but in that case you should also change the getter 'getter=lambda o, k: o.get(k)'. However, if you like the list handling skills of the code but just needs to change the way the value is retrieved, in this case you pass an accessor only to deep_get or deep_set which could be, say, 'lambda o, k: o.getValueById(k)' ## Functions *deep_get* accepts: - o: required. Any object, usually a dictionary - k: required. The key or keys, must be a string or anything accepted by the list() constructor - accessor: optional, callable: Takes o, k (object and key) and returns the value. Default accessor is 'lambda o, k: o.get(k) if hasattr(o, "get") else o[k]' - getter: optional, callable. If getter is set, accessor is ignored. Takes an object and a key as arguments and returns a value - getter_last_step: optional, callable. The getter to be used on the last step (with the last key). By default, if the last key is a list of keys, it returns a dict {k[0]: o[k[0]], k[1]: o[k[1]]}. If the last object is a list, it returns a list of dicts [{k[0]: o[0][k[0]]], k[1]: o[0][k[1]]}, {k[0]: o[1][k[0]]], k[1]: o[1][k[1]]}, ...] - sep: optional, string: by default it is a dot '.', you can use anything the string function split will accept - empty_list_as_none: bool = False. If true and the return value would be an empty list, returns None instead. - list_of_len_one_as_value: bool = False. If true and the return value would be a list with a single item, returns the item instead Returns o[k]. If o[k] does not exist, should return None (but depends on the callables used). *deep_set* accepts: - o: see 'deep_get' - k: see 'deep_get' - v: required, the value that will be set - accessor: optional, callable: see 'deep_get'. For the deep_set function, the default accessor is: 'lambda o, k: o.setdefault(k, dict()) if hasattr(o, "setdefault") else o[k]' - getter: optional, callable: see 'deep_get' - setter: optional, callable. A callable that takes 3 parameters: o, k, v - where o = any object, k = key, v = value - sep: optional, string: see 'deep_get' No return value *deep_del* accepts: - o: required: see 'deep_get' - k: required: see 'deep_get' - accessor: optional, callable: see 'deep_get' - getter: optional, callable: see 'deep_get' - deleter: optional, callable: Takes 2 parameters: o, k (object and key). - sep: optional, string: see 'deep_get' Returns an integer with the number of entries that were deleted. ## Example / Usage ``` from dict_deep import deep_get, deep_set, deep_del i = 0 # 1 i += 1 o = {'a': {'b': {}}} deep_set(o, "a.b.c", "Hello World") print("{}: {}".format(i, deep_get(o, "a.b.c"))) # 2 i += 1 o = {} deep_set(o, ['a', 'b', 'c'], "Hello World") print("{}: {}".format(i, deep_get(o, "a.b.c"))) # 3 i += 1 o = {} deep_set(o, "a->b->c", "Hello World", sep="->") print("{}: {}".format(i, deep_get(o, "a->b->c", sep="->"))) # 4 i += 1 o = {} deep_set(o, "a->b->c", "Hello World", getter=lambda o, k: o.setdefault(k, dict()), sep="->") print("{}: {}".format(i, deep_get(o, "a->b->c", sep="->"))) # 5 i += 1 o = {} keys = 'a.b.c' keys = keys.split('.') _ = deep_get(o=o, k=keys[0:-1], accessor=lambda o, k: o.setdefault(k, dict()), sep=".") _[keys[-1]] = "Hello World" print("{}: {}".format(i, deep_get(o, keys))) # 6 i += 1 o = {} deep_set(o, "1.1.1", 'a', accessor=lambda o, k: o.setdefault(k, dict())) deep_set(o, "1.1.2", 'Hello World') deep_set(o, "1.1.3", 'c') deep_del(o, "1.1.2") print("{}: {}".format(i, o)) # 7 i += 1 o = {'students': [{'name': 'Joe', 'age': 10, 'gender': 'male'}, {'name': 'Maria', 'age': 12, 'gender': 'female'}]} keys = ['students', 'name'] print("{}: {}".format(i, deep_get(o, keys))) # 8 i += 1 keys = ['students', ['name', 'age']] print("{}: {}".format(i, deep_get(o, keys))) # 9 i += 1 keys = ['students', 'gender'] deep_set(o, keys, 'Nowadays better not ask') print("{}: {}".format(i, o)) # 10 i += 1 keys = ['students', 'gender'] deep_del(o, keys) print("{}: {}".format(i, o)) # 11 i += 1 keys = ['director', 'name'] print("{}: {}".format(i, deep_get(o, keys))) ``` %package help Summary: Development documents and examples for dict-deep Provides: python3-dict-deep-doc %description help ## Description Simple functions to set or get values from a nested dict structure or in fact a deep structure of any object, because since version 2 we no longer assume we are dealing with dicts. You may use a custom accessor or pass your own getter, setter, deleter callables so that you can traverse a nested structure of any kind of object. This module DOES NOT implement dotted notation as an alternative access method for dicts. I generally do not like changing python dicts to enable dot notation, hence no available package fitted my needs for a simple deep accessor. NEW IN VERSION 4: Since version 3 we make no assumption that we are dealing with dicts, so you can have your nested structure of any type. However, in version 4 we reintroduce better defaults so that for those that are indeed working with nested dicts the default values shall be enough without having to define an accessor or a getter. Notes: With deep_get, you could use 'lambda o, k: o[k]' or 'lambda o, k: o.get(k)' as either the getter or the accessor. The only 'special' thing about the 'getter' function is that when it is invoked with 'o' being a list, it will instead iterate over the list and call the accessor for each item in the list. In a simplified way, this is how deep_get works: 1. The key is broken down into a list of keys: "customer.address.city" -> ['customer', 'address', 'city'] 2. The list of keys is iterated over, calling the getter for each key and the last value retrieved is returned. ``` for k in keys[:-1]: if o is None: return o o = getter(o, k) o = getter_last_step(o, keys[-1]) return o ``` You see that getter could be as simple as 'lambda o, k: o.get(k)'. However, by default the code uses a smarter getter as defined below, which tries to deal properly with nested lists. ``` def __default_getter(o, k): if isinstance(o, list): return [accessor(i, k) for i in o] else: return accessor(o, k) ``` If you do not want this checks for nested lists, just pass your own getter which could just as well be 'lambda o, k: o.get(k)'. The default setter also knows how to deal with nested lists: ``` def __default_setter(o, k, v): n_set = 0 if isinstance(o, list): for i in o: i[k] = v n_set += 1 return n_set else: o[k] = v return 1 ``` You could just as well replace if with your own 'setter=lambda o, k, v: o[k]=v' if you know that you have no nested lists in your structures and want to avoid the overhead, but in that case you should also change the getter 'getter=lambda o, k: o.get(k)'. However, if you like the list handling skills of the code but just needs to change the way the value is retrieved, in this case you pass an accessor only to deep_get or deep_set which could be, say, 'lambda o, k: o.getValueById(k)' ## Functions *deep_get* accepts: - o: required. Any object, usually a dictionary - k: required. The key or keys, must be a string or anything accepted by the list() constructor - accessor: optional, callable: Takes o, k (object and key) and returns the value. Default accessor is 'lambda o, k: o.get(k) if hasattr(o, "get") else o[k]' - getter: optional, callable. If getter is set, accessor is ignored. Takes an object and a key as arguments and returns a value - getter_last_step: optional, callable. The getter to be used on the last step (with the last key). By default, if the last key is a list of keys, it returns a dict {k[0]: o[k[0]], k[1]: o[k[1]]}. If the last object is a list, it returns a list of dicts [{k[0]: o[0][k[0]]], k[1]: o[0][k[1]]}, {k[0]: o[1][k[0]]], k[1]: o[1][k[1]]}, ...] - sep: optional, string: by default it is a dot '.', you can use anything the string function split will accept - empty_list_as_none: bool = False. If true and the return value would be an empty list, returns None instead. - list_of_len_one_as_value: bool = False. If true and the return value would be a list with a single item, returns the item instead Returns o[k]. If o[k] does not exist, should return None (but depends on the callables used). *deep_set* accepts: - o: see 'deep_get' - k: see 'deep_get' - v: required, the value that will be set - accessor: optional, callable: see 'deep_get'. For the deep_set function, the default accessor is: 'lambda o, k: o.setdefault(k, dict()) if hasattr(o, "setdefault") else o[k]' - getter: optional, callable: see 'deep_get' - setter: optional, callable. A callable that takes 3 parameters: o, k, v - where o = any object, k = key, v = value - sep: optional, string: see 'deep_get' No return value *deep_del* accepts: - o: required: see 'deep_get' - k: required: see 'deep_get' - accessor: optional, callable: see 'deep_get' - getter: optional, callable: see 'deep_get' - deleter: optional, callable: Takes 2 parameters: o, k (object and key). - sep: optional, string: see 'deep_get' Returns an integer with the number of entries that were deleted. ## Example / Usage ``` from dict_deep import deep_get, deep_set, deep_del i = 0 # 1 i += 1 o = {'a': {'b': {}}} deep_set(o, "a.b.c", "Hello World") print("{}: {}".format(i, deep_get(o, "a.b.c"))) # 2 i += 1 o = {} deep_set(o, ['a', 'b', 'c'], "Hello World") print("{}: {}".format(i, deep_get(o, "a.b.c"))) # 3 i += 1 o = {} deep_set(o, "a->b->c", "Hello World", sep="->") print("{}: {}".format(i, deep_get(o, "a->b->c", sep="->"))) # 4 i += 1 o = {} deep_set(o, "a->b->c", "Hello World", getter=lambda o, k: o.setdefault(k, dict()), sep="->") print("{}: {}".format(i, deep_get(o, "a->b->c", sep="->"))) # 5 i += 1 o = {} keys = 'a.b.c' keys = keys.split('.') _ = deep_get(o=o, k=keys[0:-1], accessor=lambda o, k: o.setdefault(k, dict()), sep=".") _[keys[-1]] = "Hello World" print("{}: {}".format(i, deep_get(o, keys))) # 6 i += 1 o = {} deep_set(o, "1.1.1", 'a', accessor=lambda o, k: o.setdefault(k, dict())) deep_set(o, "1.1.2", 'Hello World') deep_set(o, "1.1.3", 'c') deep_del(o, "1.1.2") print("{}: {}".format(i, o)) # 7 i += 1 o = {'students': [{'name': 'Joe', 'age': 10, 'gender': 'male'}, {'name': 'Maria', 'age': 12, 'gender': 'female'}]} keys = ['students', 'name'] print("{}: {}".format(i, deep_get(o, keys))) # 8 i += 1 keys = ['students', ['name', 'age']] print("{}: {}".format(i, deep_get(o, keys))) # 9 i += 1 keys = ['students', 'gender'] deep_set(o, keys, 'Nowadays better not ask') print("{}: {}".format(i, o)) # 10 i += 1 keys = ['students', 'gender'] deep_del(o, keys) print("{}: {}".format(i, o)) # 11 i += 1 keys = ['director', 'name'] print("{}: {}".format(i, deep_get(o, keys))) ``` %prep %autosetup -n dict-deep-4.1.2 %build %py3_build %install %py3_install install -d -m755 %{buildroot}/%{_pkgdocdir} if [ -d doc ]; then cp -arf doc %{buildroot}/%{_pkgdocdir}; fi if [ -d docs ]; then cp -arf docs %{buildroot}/%{_pkgdocdir}; fi if [ -d example ]; then cp -arf example %{buildroot}/%{_pkgdocdir}; fi if [ -d examples ]; then cp -arf examples %{buildroot}/%{_pkgdocdir}; fi pushd %{buildroot} if [ -d usr/lib ]; then find usr/lib -type f -printf "/%h/%f\n" >> filelist.lst fi if [ -d usr/lib64 ]; then find usr/lib64 -type f -printf "/%h/%f\n" >> filelist.lst fi if [ -d usr/bin ]; then find usr/bin -type f -printf "/%h/%f\n" >> filelist.lst fi if [ -d usr/sbin ]; then find usr/sbin -type f -printf "/%h/%f\n" >> filelist.lst fi touch doclist.lst if [ -d usr/share/man ]; then find usr/share/man -type f -printf "/%h/%f.gz\n" >> doclist.lst fi popd mv %{buildroot}/filelist.lst . mv %{buildroot}/doclist.lst . %files -n python3-dict-deep -f filelist.lst %dir %{python3_sitelib}/* %files help -f doclist.lst %{_docdir}/* %changelog * Fri May 05 2023 Python_Bot - 4.1.2-1 - Package Spec generated