sdata 0.19.0__tar.gz → 0.22.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of sdata might be problematic. Click here for more details.
- sdata-0.22.0/PKG-INFO +128 -0
- {sdata-0.19.0 → sdata-0.22.0}/sdata/__init__.py +6 -2
- sdata-0.22.0/sdata/contrib/attrdict/__init__.py +10 -0
- sdata-0.22.0/sdata/contrib/attrdict/default.py +133 -0
- sdata-0.22.0/sdata/contrib/attrdict/dictionary.py +60 -0
- sdata-0.22.0/sdata/contrib/attrdict/mapping.py +100 -0
- sdata-0.22.0/sdata/contrib/attrdict/merge.py +47 -0
- sdata-0.22.0/sdata/contrib/attrdict/mixins.py +213 -0
- sdata-0.22.0/sdata/contrib/semver.py +1259 -0
- sdata-0.22.0/sdata/contrib/sqlitedict.py +598 -0
- {sdata-0.19.0 → sdata-0.22.0}/sdata/data.py +48 -5
- {sdata-0.19.0 → sdata-0.22.0}/sdata/doe.py +29 -15
- sdata-0.22.0/sdata/iolib/db.py +86 -0
- {sdata-0.19.0/sdata/io → sdata-0.22.0/sdata/iolib}/hdf.py +1 -1
- sdata-0.22.0/sdata/iolib/isomme.py +410 -0
- {sdata-0.19.0/sdata/io → sdata-0.22.0/sdata/iolib}/pud.py +1 -1
- sdata-0.22.0/sdata/iolib/simple_signature.py +446 -0
- {sdata-0.19.0 → sdata-0.22.0}/sdata/metadata.py +2 -2
- sdata-0.22.0/sdata/suuid.py +178 -0
- {sdata-0.19.0 → sdata-0.22.0}/sdata/timestamp.py +5 -2
- sdata-0.22.0/sdata.egg-info/PKG-INFO +128 -0
- {sdata-0.19.0 → sdata-0.22.0}/sdata.egg-info/SOURCES.txt +22 -9
- {sdata-0.19.0/tests/io → sdata-0.22.0/tests/iolib}/pud/test_pud.py +2 -2
- {sdata-0.19.0/tests/io → sdata-0.22.0/tests/iolib}/test_hdf.py +1 -1
- {sdata-0.19.0 → sdata-0.22.0}/tests/test_blob.py +3 -0
- {sdata-0.19.0 → sdata-0.22.0}/tests/test_data.py +11 -0
- sdata-0.22.0/tests/test_sqlite.py +15 -0
- {sdata-0.19.0 → sdata-0.22.0}/tests/test_vault.py +2 -2
- sdata-0.19.0/PKG-INFO +0 -125
- sdata-0.19.0/sdata.egg-info/PKG-INFO +0 -125
- {sdata-0.19.0 → sdata-0.22.0}/LICENSE-MIT +0 -0
- {sdata-0.19.0 → sdata-0.22.0}/MANIFEST.in +0 -0
- {sdata-0.19.0 → sdata-0.22.0}/README.md +0 -0
- {sdata-0.19.0 → sdata-0.22.0}/sdata/blob.py +0 -0
- {sdata-0.19.0 → sdata-0.22.0}/sdata/contrib/__init__.py +0 -0
- {sdata-0.19.0 → sdata-0.22.0}/sdata/contrib/ranger/__init__.py +0 -0
- {sdata-0.19.0 → sdata-0.22.0}/sdata/contrib/ranger/collections/__init__.py +0 -0
- {sdata-0.19.0 → sdata-0.22.0}/sdata/contrib/ranger/collections/rangebucketmap.py +0 -0
- {sdata-0.19.0 → sdata-0.22.0}/sdata/contrib/ranger/collections/rangemap.py +0 -0
- {sdata-0.19.0 → sdata-0.22.0}/sdata/contrib/ranger/collections/rangeset.py +0 -0
- {sdata-0.19.0 → sdata-0.22.0}/sdata/contrib/ranger/range/__init__.py +0 -0
- {sdata-0.19.0 → sdata-0.22.0}/sdata/contrib/ranger/range/cut.py +0 -0
- {sdata-0.19.0 → sdata-0.22.0}/sdata/contrib/ranger/range/range.py +0 -0
- {sdata-0.19.0 → sdata-0.22.0}/sdata/contrib/simple_graph_db/LICENSE +0 -0
- {sdata-0.19.0 → sdata-0.22.0}/sdata/contrib/simple_graph_db/__init__.py +0 -0
- {sdata-0.19.0 → sdata-0.22.0}/sdata/contrib/simple_graph_db/database.py +0 -0
- {sdata-0.19.0 → sdata-0.22.0}/sdata/contrib/simple_graph_db/schema.sql +0 -0
- {sdata-0.19.0 → sdata-0.22.0}/sdata/contrib/sobol_seq.py +0 -0
- {sdata-0.19.0 → sdata-0.22.0}/sdata/contrib/sortedcontainers/LICENSE +0 -0
- {sdata-0.19.0 → sdata-0.22.0}/sdata/contrib/sortedcontainers/__init__.py +0 -0
- {sdata-0.19.0 → sdata-0.22.0}/sdata/contrib/sortedcontainers/sorteddict.py +0 -0
- {sdata-0.19.0 → sdata-0.22.0}/sdata/contrib/sortedcontainers/sortedlist.py +0 -0
- {sdata-0.19.0 → sdata-0.22.0}/sdata/contrib/sortedcontainers/sortedset.py +0 -0
- {sdata-0.19.0 → sdata-0.22.0}/sdata/contrib/timeflake/__init__.py +0 -0
- {sdata-0.19.0 → sdata-0.22.0}/sdata/contrib/timeflake/flake.py +0 -0
- {sdata-0.19.0 → sdata-0.22.0}/sdata/contrib/timeflake/utils.py +0 -0
- {sdata-0.19.0 → sdata-0.22.0}/sdata/experiments/__init__.py +0 -0
- {sdata-0.19.0 → sdata-0.22.0}/sdata/experiments/ks2.py +0 -0
- {sdata-0.19.0 → sdata-0.22.0}/sdata/experiments/lapshear.py +0 -0
- {sdata-0.19.0 → sdata-0.22.0}/sdata/experiments/material.py +0 -0
- {sdata-0.19.0/sdata/io → sdata-0.22.0/sdata/iolib}/__init__.py +0 -0
- {sdata-0.19.0/sdata/io → sdata-0.22.0/sdata/iolib}/pgp.py +0 -0
- {sdata-0.19.0/sdata/io → sdata-0.22.0/sdata/iolib}/vault.py +0 -0
- {sdata-0.19.0 → sdata-0.22.0}/sdata/tools.py +0 -0
- {sdata-0.19.0 → sdata-0.22.0}/sdata/workbook.py +0 -0
- {sdata-0.19.0 → sdata-0.22.0}/sdata.egg-info/dependency_links.txt +0 -0
- {sdata-0.19.0 → sdata-0.22.0}/sdata.egg-info/requires.txt +0 -0
- {sdata-0.19.0 → sdata-0.22.0}/sdata.egg-info/top_level.txt +0 -0
- {sdata-0.19.0 → sdata-0.22.0}/setup.cfg +0 -0
- {sdata-0.19.0 → sdata-0.22.0}/setup.py +0 -0
- {sdata-0.19.0 → sdata-0.22.0}/tests/__init__.py +0 -0
- {sdata-0.19.0/tests/io → sdata-0.22.0/tests/iolib}/__init__.py +0 -0
- {sdata-0.19.0/tests/io → sdata-0.22.0/tests/iolib}/pud/__init__.py +0 -0
- {sdata-0.19.0 → sdata-0.22.0}/tests/test_attribute.py +0 -0
- {sdata-0.19.0 → sdata-0.22.0}/tests/test_io.py +0 -0
- {sdata-0.19.0 → sdata-0.22.0}/tests/test_ks2.py +0 -0
- {sdata-0.19.0 → sdata-0.22.0}/tests/test_metadata.py +0 -0
- {sdata-0.19.0 → sdata-0.22.0}/tests/test_table.py +0 -0
- {sdata-0.19.0 → sdata-0.22.0}/tests/test_testprogram.py +0 -0
- {sdata-0.19.0 → sdata-0.22.0}/tests/test_timeflake.py +0 -0
- {sdata-0.19.0 → sdata-0.22.0}/tests/test_timestamp.py +0 -0
- {sdata-0.19.0 → sdata-0.22.0}/tests/test_tools.py +0 -0
- {sdata-0.19.0 → sdata-0.22.0}/tests/test_workbook.py +0 -0
sdata-0.22.0/PKG-INFO
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: sdata
|
|
3
|
+
Version: 0.22.0
|
|
4
|
+
Summary: a structured data format
|
|
5
|
+
Home-page: https://github.com/lepy/sdata
|
|
6
|
+
Author: Lepy
|
|
7
|
+
Author-email: lepy@mailbox.org
|
|
8
|
+
Maintainer: Lepy
|
|
9
|
+
Maintainer-email: lepy@mailbox.org
|
|
10
|
+
License: MIT/Apache-2.0
|
|
11
|
+
Keywords: open data
|
|
12
|
+
Platform: UNKNOWN
|
|
13
|
+
Classifier: Development Status :: 3 - Alpha
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Natural Language :: English
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Programming Language :: Python :: 2.7
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.5
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.6
|
|
21
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
22
|
+
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE-MIT
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
[](https://badge.fury.io/py/sdata)
|
|
28
|
+
[](https://pypi.python.org/pypi/sdata/)
|
|
29
|
+
[](http://sdata.readthedocs.io/en/latest/)
|
|
30
|
+
[](https://travis-ci.org/lepy/sdata)
|
|
31
|
+
[](https://www.codacy.com/app/lepy/sdata?utm_source=github.com&utm_medium=referral&utm_content=lepy/sdata&utm_campaign=Badge_Grade)
|
|
32
|
+
[](https://coveralls.io/github/lepy/sdata?branch=master)
|
|
33
|
+
[](https://doi.org/10.5281/zenodo.4311323)
|
|
34
|
+
|
|
35
|
+
https://lepy.github.io/sdata/
|
|
36
|
+
|
|
37
|
+
# Structured data format (sdata)
|
|
38
|
+
|
|
39
|
+
## Design goals
|
|
40
|
+
|
|
41
|
+
* open data format for open science projects
|
|
42
|
+
* self describing data
|
|
43
|
+
* flexible data structure layout
|
|
44
|
+
* hierarchical data structure (nesting groups, dictionaries)
|
|
45
|
+
* (posix path syntax support?)
|
|
46
|
+
* extendable data structure
|
|
47
|
+
* data format versions
|
|
48
|
+
* platform independent
|
|
49
|
+
* simple object model
|
|
50
|
+
* support of standard metadata formats (key/value, ...)
|
|
51
|
+
* support of standard dataset formats (hdf5, netcdf, csv, ...)
|
|
52
|
+
* support of standard dataset types (datacubes, tables, series, ...)
|
|
53
|
+
* support of physical units (conversion of units)
|
|
54
|
+
* transparent, optional data compression (zlib, blosc, ...)
|
|
55
|
+
* support of (de-)serialization of every dataset type (group, data, metadata)
|
|
56
|
+
* easy defineable (project) standards, e.g. for a uniaxial tension test (UT)
|
|
57
|
+
* (optional data encryption (gpg, ...))
|
|
58
|
+
* change management support?
|
|
59
|
+
* Enable use of data structures from existing tensor libraries transparently
|
|
60
|
+
* (single writer/ multiple reader (swmr) support)
|
|
61
|
+
* (nested data support)
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
df = pandas.DataFrame({"a":[1,2,3]})
|
|
65
|
+
import sdata
|
|
66
|
+
data = sdata.Data(name="my_data", table=df, comment="A remarkable comment")
|
|
67
|
+
data.metadata.add("my_key", 123, unit="m^3", description="a volume")
|
|
68
|
+
data.metadata.add("force", 1.234, unit="kN", description="x force")
|
|
69
|
+
data.to_xlsx(filepath="my_data.xlsx")
|
|
70
|
+
print(data.metadata.df)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
name value dtype unit description
|
|
75
|
+
key
|
|
76
|
+
name name my_data str -
|
|
77
|
+
uuid uuid 08222ca66e5047808bdc3b35d8f17224 str -
|
|
78
|
+
my_key my_key 123 int m^3 a volume
|
|
79
|
+
force force 1.234 float kN x force
|
|
80
|
+
```
|
|
81
|
+
## Howto
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
* [Das sdata-Format - slides](https://lepy.github.io/sdata/ipynb/Das_sdata_Format.slides.html#)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
## Demo App
|
|
88
|
+
|
|
89
|
+
* [test the demo app with editor](https://share.streamlit.io/lepy/sdata_streamlit/main/sdata_editor.py)
|
|
90
|
+
|
|
91
|
+
Try to paste some Excel-Data in the forms ...
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
## Metadata
|
|
95
|
+
|
|
96
|
+
### Attributes
|
|
97
|
+
|
|
98
|
+
* name
|
|
99
|
+
* value
|
|
100
|
+
* dtype
|
|
101
|
+
* unit
|
|
102
|
+
* description
|
|
103
|
+
* label
|
|
104
|
+
* required
|
|
105
|
+
|
|
106
|
+
### dtypes for attributes
|
|
107
|
+
|
|
108
|
+
* int
|
|
109
|
+
* float
|
|
110
|
+
* str
|
|
111
|
+
* bool
|
|
112
|
+
* timestamp (datetime.isoformat with timezone)
|
|
113
|
+
|
|
114
|
+
## paper
|
|
115
|
+
|
|
116
|
+
* [Das sdata-Format](https://zenodo.org/record/4311323#.X89yo9-YXys)
|
|
117
|
+
* Ingolf Lepenies. (2020). Das sdata-Format (Version 0.8.4). http://doi.org/10.5281/zenodo.4311323
|
|
118
|
+
* [slides](https://lepy.github.io/sdata/ipynb/Das_sdata_Format.slides.html#),
|
|
119
|
+
[html](https://lepy.github.io/sdata/paper/2020/Das_sdata-Format.html),
|
|
120
|
+
[pdf](https://lepy.github.io/sdata/paper/2020/Das_sdata-Format.pdf)
|
|
121
|
+
[temperaturmessung-001.json](https://lepy.github.io/sdata/paper/2020/temperaturmessung-001.json)
|
|
122
|
+
[temperaturmessung-001.xlsx](https://lepy.github.io/sdata/paper/2020/temperaturmessung-001.xlsx)
|
|
123
|
+
|
|
124
|
+
* [sdata](https://doi.org/10.5281/zenodo.4311396)
|
|
125
|
+
* Ingolf Lepenies. (2020, December 8). sdata - a structured data format (Version 0.8.4). Zenodo. http://doi.org/10.5281/zenodo.4311397
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# -*-coding: utf-8-*-
|
|
2
2
|
from __future__ import division
|
|
3
3
|
|
|
4
|
-
__version__ = '0.
|
|
4
|
+
__version__ = '0.22.0'
|
|
5
5
|
__revision__ = None
|
|
6
6
|
__version_info__ = tuple([int(num) for num in __version__.split('.')])
|
|
7
7
|
|
|
@@ -21,6 +21,7 @@ import pandas
|
|
|
21
21
|
from sdata.metadata import Metadata, Attribute
|
|
22
22
|
from sdata.data import Data
|
|
23
23
|
from sdata.blob import Blob
|
|
24
|
+
from sdata.suuid import SUUID
|
|
24
25
|
|
|
25
26
|
# import sdata.timestamp as timestamp
|
|
26
27
|
from sdata.timestamp import today_str, now_utc_str, now_local_str
|
|
@@ -36,6 +37,7 @@ except:
|
|
|
36
37
|
def uuid_from_str(name):
|
|
37
38
|
return uuid.uuid3(uuid.NAMESPACE_DNS, name)
|
|
38
39
|
|
|
40
|
+
|
|
39
41
|
def osname(name, lower=True):
|
|
40
42
|
mapper = [("ä", "ae"), ("ö", "oe"), ("ü", "ue"), ("Ä", "Ae"), ("Ö", "Oe"), ("Ü", "Ue"),
|
|
41
43
|
("ß", "sz"), (" ", "_"), ("/", "_"), ("\\", "_")]
|
|
@@ -45,11 +47,13 @@ def osname(name, lower=True):
|
|
|
45
47
|
name = name.lower()
|
|
46
48
|
return name.encode('ascii', 'replace').decode("ascii")
|
|
47
49
|
|
|
50
|
+
|
|
48
51
|
SDATACLS = {"Data": Data,
|
|
49
52
|
"Blob": Blob,
|
|
53
|
+
"SUUID": SUUID,
|
|
50
54
|
}
|
|
51
55
|
|
|
52
|
-
__all__ = ["Data", "Blob"]
|
|
56
|
+
__all__ = ["Data", "Blob", "SUUID"]
|
|
53
57
|
|
|
54
58
|
|
|
55
59
|
def print_classes():
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"""
|
|
2
|
+
A subclass of MutableAttr that has defaultdict support.
|
|
3
|
+
"""
|
|
4
|
+
try:
|
|
5
|
+
from collections.abc import Mapping
|
|
6
|
+
except ImportError:
|
|
7
|
+
from collections import Mapping
|
|
8
|
+
|
|
9
|
+
import six
|
|
10
|
+
|
|
11
|
+
from .mixins import MutableAttr
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
__all__ = ['AttrDefault']
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class AttrDefault(MutableAttr):
|
|
18
|
+
"""
|
|
19
|
+
An implementation of MutableAttr with defaultdict support
|
|
20
|
+
"""
|
|
21
|
+
def __init__(self, default_factory=None, items=None, sequence_type=tuple,
|
|
22
|
+
pass_key=False):
|
|
23
|
+
if items is None:
|
|
24
|
+
items = {}
|
|
25
|
+
elif not isinstance(items, Mapping):
|
|
26
|
+
items = dict(items)
|
|
27
|
+
|
|
28
|
+
self._setattr('_default_factory', default_factory)
|
|
29
|
+
self._setattr('_mapping', items)
|
|
30
|
+
self._setattr('_sequence_type', sequence_type)
|
|
31
|
+
self._setattr('_pass_key', pass_key)
|
|
32
|
+
self._setattr('_allow_invalid_attributes', False)
|
|
33
|
+
|
|
34
|
+
def _configuration(self):
|
|
35
|
+
"""
|
|
36
|
+
The configuration for a AttrDefault instance
|
|
37
|
+
"""
|
|
38
|
+
return self._sequence_type, self._default_factory, self._pass_key
|
|
39
|
+
|
|
40
|
+
def __getitem__(self, key):
|
|
41
|
+
"""
|
|
42
|
+
Access a value associated with a key.
|
|
43
|
+
|
|
44
|
+
Note: values returned will not be wrapped, even if recursive
|
|
45
|
+
is True.
|
|
46
|
+
"""
|
|
47
|
+
if key in self._mapping:
|
|
48
|
+
return self._mapping[key]
|
|
49
|
+
elif self._default_factory is not None:
|
|
50
|
+
return self.__missing__(key)
|
|
51
|
+
|
|
52
|
+
raise KeyError(key)
|
|
53
|
+
|
|
54
|
+
def __setitem__(self, key, value):
|
|
55
|
+
"""
|
|
56
|
+
Add a key-value pair to the instance.
|
|
57
|
+
"""
|
|
58
|
+
self._mapping[key] = value
|
|
59
|
+
|
|
60
|
+
def __delitem__(self, key):
|
|
61
|
+
"""
|
|
62
|
+
Delete a key-value pair
|
|
63
|
+
"""
|
|
64
|
+
del self._mapping[key]
|
|
65
|
+
|
|
66
|
+
def __len__(self):
|
|
67
|
+
"""
|
|
68
|
+
Check the length of the mapping.
|
|
69
|
+
"""
|
|
70
|
+
return len(self._mapping)
|
|
71
|
+
|
|
72
|
+
def __iter__(self):
|
|
73
|
+
"""
|
|
74
|
+
Iterated through the keys.
|
|
75
|
+
"""
|
|
76
|
+
return iter(self._mapping)
|
|
77
|
+
|
|
78
|
+
def __missing__(self, key):
|
|
79
|
+
"""
|
|
80
|
+
Add a missing element.
|
|
81
|
+
"""
|
|
82
|
+
if self._pass_key:
|
|
83
|
+
self[key] = value = self._default_factory(key)
|
|
84
|
+
else:
|
|
85
|
+
self[key] = value = self._default_factory()
|
|
86
|
+
|
|
87
|
+
return value
|
|
88
|
+
|
|
89
|
+
def __repr__(self):
|
|
90
|
+
"""
|
|
91
|
+
Return a string representation of the object.
|
|
92
|
+
"""
|
|
93
|
+
return six.u(
|
|
94
|
+
"AttrDefault({default_factory}, {pass_key}, {mapping})"
|
|
95
|
+
).format(
|
|
96
|
+
default_factory=repr(self._default_factory),
|
|
97
|
+
pass_key=repr(self._pass_key),
|
|
98
|
+
mapping=repr(self._mapping),
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
def __getstate__(self):
|
|
102
|
+
"""
|
|
103
|
+
Serialize the object.
|
|
104
|
+
"""
|
|
105
|
+
return (
|
|
106
|
+
self._default_factory,
|
|
107
|
+
self._mapping,
|
|
108
|
+
self._sequence_type,
|
|
109
|
+
self._pass_key,
|
|
110
|
+
self._allow_invalid_attributes,
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
def __setstate__(self, state):
|
|
114
|
+
"""
|
|
115
|
+
Deserialize the object.
|
|
116
|
+
"""
|
|
117
|
+
(default_factory, mapping, sequence_type, pass_key,
|
|
118
|
+
allow_invalid_attributes) = state
|
|
119
|
+
|
|
120
|
+
self._setattr('_default_factory', default_factory)
|
|
121
|
+
self._setattr('_mapping', mapping)
|
|
122
|
+
self._setattr('_sequence_type', sequence_type)
|
|
123
|
+
self._setattr('_pass_key', pass_key)
|
|
124
|
+
self._setattr('_allow_invalid_attributes', allow_invalid_attributes)
|
|
125
|
+
|
|
126
|
+
@classmethod
|
|
127
|
+
def _constructor(cls, mapping, configuration):
|
|
128
|
+
"""
|
|
129
|
+
A standardized constructor.
|
|
130
|
+
"""
|
|
131
|
+
sequence_type, default_factory, pass_key = configuration
|
|
132
|
+
return cls(default_factory, mapping, sequence_type=sequence_type,
|
|
133
|
+
pass_key=pass_key)
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""
|
|
2
|
+
A dict that implements MutableAttr.
|
|
3
|
+
"""
|
|
4
|
+
from .mixins import MutableAttr
|
|
5
|
+
|
|
6
|
+
import six
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
__all__ = ['AttrDict']
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class AttrDict(dict, MutableAttr):
|
|
13
|
+
"""
|
|
14
|
+
A dict that implements MutableAttr.
|
|
15
|
+
"""
|
|
16
|
+
def __init__(self, *args, **kwargs):
|
|
17
|
+
super(AttrDict, self).__init__(*args, **kwargs)
|
|
18
|
+
|
|
19
|
+
self._setattr('_sequence_type', tuple)
|
|
20
|
+
self._setattr('_allow_invalid_attributes', False)
|
|
21
|
+
|
|
22
|
+
def _configuration(self):
|
|
23
|
+
"""
|
|
24
|
+
The configuration for an attrmap instance.
|
|
25
|
+
"""
|
|
26
|
+
return self._sequence_type
|
|
27
|
+
|
|
28
|
+
def __getstate__(self):
|
|
29
|
+
"""
|
|
30
|
+
Serialize the object.
|
|
31
|
+
"""
|
|
32
|
+
return (
|
|
33
|
+
self.copy(),
|
|
34
|
+
self._sequence_type,
|
|
35
|
+
self._allow_invalid_attributes
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
def __setstate__(self, state):
|
|
39
|
+
"""
|
|
40
|
+
Deserialize the object.
|
|
41
|
+
"""
|
|
42
|
+
mapping, sequence_type, allow_invalid_attributes = state
|
|
43
|
+
self.update(mapping)
|
|
44
|
+
self._setattr('_sequence_type', sequence_type)
|
|
45
|
+
self._setattr('_allow_invalid_attributes', allow_invalid_attributes)
|
|
46
|
+
|
|
47
|
+
def __repr__(self):
|
|
48
|
+
return six.u('AttrDict({contents})').format(
|
|
49
|
+
contents=super(AttrDict, self).__repr__()
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
@classmethod
|
|
53
|
+
def _constructor(cls, mapping, configuration):
|
|
54
|
+
"""
|
|
55
|
+
A standardized constructor.
|
|
56
|
+
"""
|
|
57
|
+
attr = cls(mapping)
|
|
58
|
+
attr._setattr('_sequence_type', configuration)
|
|
59
|
+
|
|
60
|
+
return attr
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"""
|
|
2
|
+
An implementation of MutableAttr.
|
|
3
|
+
"""
|
|
4
|
+
try:
|
|
5
|
+
from collections.abc import Mapping
|
|
6
|
+
except ImportError:
|
|
7
|
+
from collections import Mapping
|
|
8
|
+
|
|
9
|
+
import six
|
|
10
|
+
|
|
11
|
+
from .mixins import MutableAttr
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
__all__ = ['AttrMap']
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class AttrMap(MutableAttr):
|
|
18
|
+
"""
|
|
19
|
+
An implementation of MutableAttr.
|
|
20
|
+
"""
|
|
21
|
+
def __init__(self, items=None, sequence_type=tuple):
|
|
22
|
+
if items is None:
|
|
23
|
+
items = {}
|
|
24
|
+
elif not isinstance(items, Mapping):
|
|
25
|
+
items = dict(items)
|
|
26
|
+
|
|
27
|
+
self._setattr('_sequence_type', sequence_type)
|
|
28
|
+
self._setattr('_mapping', items)
|
|
29
|
+
self._setattr('_allow_invalid_attributes', False)
|
|
30
|
+
|
|
31
|
+
def _configuration(self):
|
|
32
|
+
"""
|
|
33
|
+
The configuration for an attrmap instance.
|
|
34
|
+
"""
|
|
35
|
+
return self._sequence_type
|
|
36
|
+
|
|
37
|
+
def __getitem__(self, key):
|
|
38
|
+
"""
|
|
39
|
+
Access a value associated with a key.
|
|
40
|
+
"""
|
|
41
|
+
return self._mapping[key]
|
|
42
|
+
|
|
43
|
+
def __setitem__(self, key, value):
|
|
44
|
+
"""
|
|
45
|
+
Add a key-value pair to the instance.
|
|
46
|
+
"""
|
|
47
|
+
self._mapping[key] = value
|
|
48
|
+
|
|
49
|
+
def __delitem__(self, key):
|
|
50
|
+
"""
|
|
51
|
+
Delete a key-value pair
|
|
52
|
+
"""
|
|
53
|
+
del self._mapping[key]
|
|
54
|
+
|
|
55
|
+
def __len__(self):
|
|
56
|
+
"""
|
|
57
|
+
Check the length of the mapping.
|
|
58
|
+
"""
|
|
59
|
+
return len(self._mapping)
|
|
60
|
+
|
|
61
|
+
def __iter__(self):
|
|
62
|
+
"""
|
|
63
|
+
Iterated through the keys.
|
|
64
|
+
"""
|
|
65
|
+
return iter(self._mapping)
|
|
66
|
+
|
|
67
|
+
def __repr__(self):
|
|
68
|
+
"""
|
|
69
|
+
Return a string representation of the object.
|
|
70
|
+
"""
|
|
71
|
+
# sequence type seems like more trouble than it is worth.
|
|
72
|
+
# If people want full serialization, they can pickle, and in
|
|
73
|
+
# 99% of cases, sequence_type won't change anyway
|
|
74
|
+
return six.u("AttrMap({mapping})").format(mapping=repr(self._mapping))
|
|
75
|
+
|
|
76
|
+
def __getstate__(self):
|
|
77
|
+
"""
|
|
78
|
+
Serialize the object.
|
|
79
|
+
"""
|
|
80
|
+
return (
|
|
81
|
+
self._mapping,
|
|
82
|
+
self._sequence_type,
|
|
83
|
+
self._allow_invalid_attributes
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
def __setstate__(self, state):
|
|
87
|
+
"""
|
|
88
|
+
Deserialize the object.
|
|
89
|
+
"""
|
|
90
|
+
mapping, sequence_type, allow_invalid_attributes = state
|
|
91
|
+
self._setattr('_mapping', mapping)
|
|
92
|
+
self._setattr('_sequence_type', sequence_type)
|
|
93
|
+
self._setattr('_allow_invalid_attributes', allow_invalid_attributes)
|
|
94
|
+
|
|
95
|
+
@classmethod
|
|
96
|
+
def _constructor(cls, mapping, configuration):
|
|
97
|
+
"""
|
|
98
|
+
A standardized constructor.
|
|
99
|
+
"""
|
|
100
|
+
return cls(mapping, sequence_type=configuration)
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""
|
|
2
|
+
A right-favoring Mapping merge.
|
|
3
|
+
"""
|
|
4
|
+
try:
|
|
5
|
+
from collections.abc import Mapping
|
|
6
|
+
except ImportError:
|
|
7
|
+
from collections import Mapping
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
__all__ = ['merge']
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def merge(left, right):
|
|
14
|
+
"""
|
|
15
|
+
Merge two mappings objects together, combining overlapping Mappings,
|
|
16
|
+
and favoring right-values
|
|
17
|
+
|
|
18
|
+
left: The left Mapping object.
|
|
19
|
+
right: The right (favored) Mapping object.
|
|
20
|
+
|
|
21
|
+
NOTE: This is not commutative (merge(a,b) != merge(b,a)).
|
|
22
|
+
"""
|
|
23
|
+
merged = {}
|
|
24
|
+
|
|
25
|
+
left_keys = frozenset(left)
|
|
26
|
+
right_keys = frozenset(right)
|
|
27
|
+
|
|
28
|
+
# Items only in the left Mapping
|
|
29
|
+
for key in left_keys - right_keys:
|
|
30
|
+
merged[key] = left[key]
|
|
31
|
+
|
|
32
|
+
# Items only in the right Mapping
|
|
33
|
+
for key in right_keys - left_keys:
|
|
34
|
+
merged[key] = right[key]
|
|
35
|
+
|
|
36
|
+
# in both
|
|
37
|
+
for key in left_keys & right_keys:
|
|
38
|
+
left_value = left[key]
|
|
39
|
+
right_value = right[key]
|
|
40
|
+
|
|
41
|
+
if (isinstance(left_value, Mapping) and
|
|
42
|
+
isinstance(right_value, Mapping)): # recursive merge
|
|
43
|
+
merged[key] = merge(left_value, right_value)
|
|
44
|
+
else: # overwrite with right value
|
|
45
|
+
merged[key] = right_value
|
|
46
|
+
|
|
47
|
+
return merged
|