summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--python-dict-deep.spec657
-rw-r--r--sources1
3 files changed, 659 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index e69de29..66a4ce1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -0,0 +1 @@
+/dict-deep-4.1.2.tar.gz
diff --git a/python-dict-deep.spec b/python-dict-deep.spec
new file mode 100644
index 0000000..36e01a7
--- /dev/null
+++ b/python-dict-deep.spec
@@ -0,0 +1,657 @@
+%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 <Python_Bot@openeuler.org> - 4.1.2-1
+- Package Spec generated
diff --git a/sources b/sources
new file mode 100644
index 0000000..b3aea86
--- /dev/null
+++ b/sources
@@ -0,0 +1 @@
+4fc37f859712b414091b8aac30cd3be6 dict-deep-4.1.2.tar.gz