bw-processing 0.9__tar.gz → 0.9.6__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.
- bw_processing-0.9.6/MANIFEST.in +3 -0
- {bw-processing-0.9/bw_processing.egg-info → bw_processing-0.9.6}/PKG-INFO +28 -28
- {bw-processing-0.9 → bw_processing-0.9.6}/README.md +7 -7
- {bw-processing-0.9 → bw_processing-0.9.6}/bw_processing/__init__.py +2 -7
- {bw-processing-0.9 → bw_processing-0.9.6}/bw_processing/array_creation.py +2 -1
- {bw-processing-0.9 → bw_processing-0.9.6}/bw_processing/datapackage.py +76 -108
- {bw-processing-0.9 → bw_processing-0.9.6}/bw_processing/errors.py +2 -1
- bw_processing-0.9.6/bw_processing/examples/datapackage_1/another name.indices.parquet +0 -0
- bw_processing-0.9.6/bw_processing/examples/datapackage_1/sa-data-vector-from-dict.data.parquet +0 -0
- bw_processing-0.9.6/bw_processing/examples/datapackage_1/sa-data-vector-from-dict.distributions.parquet +0 -0
- bw_processing-0.9.6/bw_processing/examples/datapackage_1/sa-data-vector-from-dict.flip.parquet +0 -0
- bw_processing-0.9.6/bw_processing/examples/datapackage_1/sa-data-vector-from-dict.indices.parquet +0 -0
- bw_processing-0.9.6/bw_processing/examples/datapackage_1/some name.data.parquet +0 -0
- bw_processing-0.9.6/bw_processing/examples/datapackage_1/some name.flip.parquet +0 -0
- bw_processing-0.9.6/bw_processing/examples/datapackage_1/some name.indices.parquet +0 -0
- bw_processing-0.9.6/bw_processing/examples/datapackage_2.zip +0 -0
- {bw-processing-0.9 → bw_processing-0.9.6}/bw_processing/examples/parquet_files.py +6 -6
- {bw-processing-0.9 → bw_processing-0.9.6}/bw_processing/filesystem.py +3 -4
- {bw-processing-0.9 → bw_processing-0.9.6}/bw_processing/indexing.py +7 -6
- {bw-processing-0.9 → bw_processing-0.9.6}/bw_processing/io_helpers.py +16 -13
- {bw-processing-0.9 → bw_processing-0.9.6}/bw_processing/io_parquet_helpers.py +12 -23
- {bw-processing-0.9 → bw_processing-0.9.6}/bw_processing/io_pyarrow_helpers.py +3 -10
- {bw-processing-0.9 → bw_processing-0.9.6}/bw_processing/merging.py +12 -20
- {bw-processing-0.9 → bw_processing-0.9.6}/bw_processing/proxies.py +2 -1
- {bw-processing-0.9 → bw_processing-0.9.6}/bw_processing/unique_fields.py +3 -2
- {bw-processing-0.9 → bw_processing-0.9.6}/bw_processing/utils.py +13 -4
- {bw-processing-0.9 → bw_processing-0.9.6/bw_processing.egg-info}/PKG-INFO +28 -28
- bw_processing-0.9.6/bw_processing.egg-info/SOURCES.txt +57 -0
- {bw-processing-0.9 → bw_processing-0.9.6}/bw_processing.egg-info/requires.txt +10 -8
- bw_processing-0.9.6/bw_processing.egg-info/top_level.txt +1 -0
- bw_processing-0.9.6/docs/conf.py +109 -0
- bw_processing-0.9.6/pyproject.toml +108 -0
- bw_processing-0.9.6/setup.cfg +4 -0
- {bw-processing-0.9 → bw_processing-0.9.6}/tests/test_utils.py +1 -6
- bw-processing-0.9/MANIFEST.in +0 -3
- bw-processing-0.9/bw_processing.egg-info/SOURCES.txt +0 -39
- bw-processing-0.9/bw_processing.egg-info/not-zip-safe +0 -1
- bw-processing-0.9/bw_processing.egg-info/top_level.txt +0 -5
- bw-processing-0.9/docs/conf.py +0 -48
- bw-processing-0.9/pyproject.toml +0 -3
- bw-processing-0.9/setup.cfg +0 -87
- bw-processing-0.9/tests/fixtures/basic_arrays.py +0 -42
- bw-processing-0.9/tests/helpers/__init__.py +0 -6
- bw-processing-0.9/tests/helpers/basic_array_helpers.py +0 -33
- {bw-processing-0.9 → bw_processing-0.9.6}/LICENSE +0 -0
- {bw-processing-0.9 → bw_processing-0.9.6}/bw_processing/constants.py +0 -0
- {bw-processing-0.9 → bw_processing-0.9.6}/bw_processing/examples/__init__.py +0 -0
- {bw-processing-0.9 → bw_processing-0.9.6}/bw_processing/examples/interfaces.py +0 -0
- {bw-processing-0.9 → bw_processing-0.9.6}/bw_processing/examples/simple.zip +0 -0
- {bw-processing-0.9 → bw_processing-0.9.6}/bw_processing.egg-info/dependency_links.txt +0 -0
- {bw-processing-0.9 → bw_processing-0.9.6}/dev/calculation_package.py +0 -0
- {bw-processing-0.9 → bw_processing-0.9.6}/dev/loading.py +0 -0
- {bw-processing-0.9 → bw_processing-0.9.6}/dev/processed_package.py +0 -0
- {bw-processing-0.9 → bw_processing-0.9.6}/dev/resources.py +0 -0
- {bw-processing-0.9 → bw_processing-0.9.6}/dev/speed_tests.py +0 -0
|
@@ -1,43 +1,43 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
|
-
Name:
|
|
3
|
-
Version: 0.9
|
|
4
|
-
Summary:
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
Author-email: <cmutel@gmail.com>
|
|
8
|
-
Maintainer: Chris Mutel
|
|
9
|
-
Maintainer-email: <cmutel@gmail.com>
|
|
10
|
-
License: BSD-3-Clause
|
|
2
|
+
Name: bw_processing
|
|
3
|
+
Version: 0.9.6
|
|
4
|
+
Summary: Foo
|
|
5
|
+
Author-email: Chris Mutel <cmutel@gmail.com>
|
|
6
|
+
Maintainer-email: Chris Mutel <cmutel@gmail.com>
|
|
11
7
|
Project-URL: source, https://github.com/brightway-lca/bw_processing
|
|
12
8
|
Project-URL: homepage, https://github.com/brightway-lca/bw_processing
|
|
13
9
|
Project-URL: tracker, https://github.com/brightway-lca/bw_processing/issues
|
|
14
|
-
Keywords: "brightway","development"
|
|
15
|
-
Platform: any
|
|
16
10
|
Classifier: Development Status :: 4 - Beta
|
|
17
11
|
Classifier: Programming Language :: Python
|
|
18
12
|
Classifier: Programming Language :: Python :: 3
|
|
19
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
20
13
|
Classifier: Programming Language :: Python :: 3.9
|
|
21
14
|
Classifier: Programming Language :: Python :: 3.10
|
|
22
15
|
Classifier: Programming Language :: Python :: 3.11
|
|
23
|
-
|
|
24
|
-
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Natural Language :: English
|
|
18
|
+
Classifier: Operating System :: OS Independent
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering
|
|
20
|
+
Requires-Python: >=3.9
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
25
22
|
License-File: LICENSE
|
|
26
|
-
Requires-Dist:
|
|
23
|
+
Requires-Dist: fsspec
|
|
24
|
+
Requires-Dist: morefs
|
|
27
25
|
Requires-Dist: numpy
|
|
28
26
|
Requires-Dist: pandas
|
|
29
27
|
Provides-Extra: testing
|
|
30
|
-
Requires-Dist:
|
|
28
|
+
Requires-Dist: bw_processing; extra == "testing"
|
|
29
|
+
Requires-Dist: pyarrow; extra == "testing"
|
|
31
30
|
Requires-Dist: pytest; extra == "testing"
|
|
32
31
|
Requires-Dist: pytest-cov; extra == "testing"
|
|
33
|
-
Requires-Dist:
|
|
32
|
+
Requires-Dist: python-coveralls; extra == "testing"
|
|
34
33
|
Provides-Extra: dev
|
|
34
|
+
Requires-Dist: build; extra == "dev"
|
|
35
35
|
Requires-Dist: pre-commit; extra == "dev"
|
|
36
36
|
Requires-Dist: pylint; extra == "dev"
|
|
37
|
-
|
|
38
|
-
Requires-Dist:
|
|
39
|
-
Requires-Dist:
|
|
40
|
-
Requires-Dist:
|
|
37
|
+
Requires-Dist: pytest; extra == "dev"
|
|
38
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
39
|
+
Requires-Dist: pytest-randomly; extra == "dev"
|
|
40
|
+
Requires-Dist: setuptools; extra == "dev"
|
|
41
41
|
|
|
42
42
|
# bw-processing
|
|
43
43
|
|
|
@@ -46,10 +46,10 @@ Library for storing numeric data for use in matrix-based calculations. Designed
|
|
|
46
46
|
[][pypi status]
|
|
47
47
|
[][pypi status]
|
|
48
48
|
[][pypi status]
|
|
49
|
-
[][license]
|
|
50
50
|
|
|
51
51
|
[][read the docs]
|
|
52
|
-
[][tests]
|
|
53
53
|
[][codecov]
|
|
54
54
|
|
|
55
55
|
[][pre-commit]
|
|
@@ -57,7 +57,7 @@ Library for storing numeric data for use in matrix-based calculations. Designed
|
|
|
57
57
|
|
|
58
58
|
[pypi status]: https://pypi.org/project/bw-processing/
|
|
59
59
|
[read the docs]: https://bw-processing.readthedocs.io/
|
|
60
|
-
[tests]: https://github.com/brightway-lca/
|
|
60
|
+
[tests]: https://github.com/brightway-lca/bw_processing/actions/workflows/python-test.yml
|
|
61
61
|
[codecov]: https://app.codecov.io/gh/brightway-lca/bw-processing
|
|
62
62
|
[pre-commit]: https://github.com/pre-commit/pre-commit
|
|
63
63
|
[black]: https://github.com/psf/black
|
|
@@ -148,10 +148,10 @@ class ExampleArrayInterface:
|
|
|
148
148
|
Serialized datapackages cannot contain executable code, both because of our chosen data formats, and for security reasons. Therefore, when loading a datapackage with an interface, that interface object needs to be reconstituted as Python code - we call this cycle dehydration and rehydration. Dehydration happens automatically when a datapackage is finalized with `finalize_serialization()`, but rehydration needs to be done manually using `rehydrate_interface()`. For example:
|
|
149
149
|
|
|
150
150
|
```python
|
|
151
|
-
from
|
|
151
|
+
from fsspec.implementations.zip import ZipFileSystem
|
|
152
152
|
from bw_processing import load_datapackage
|
|
153
153
|
|
|
154
|
-
my_dp = load_datapackage(
|
|
154
|
+
my_dp = load_datapackage(ZipFileSystem("some-path.zip"))
|
|
155
155
|
my_dp.rehydrate_interface("some-resource-name", ExampleVectorInterface())
|
|
156
156
|
```
|
|
157
157
|
|
|
@@ -160,7 +160,7 @@ You can list the dehydrated interfaces present with `.dehydrated_interfaces()`.
|
|
|
160
160
|
You can store useful information for the interface object initialization under the resource key `config`. This can be used in instantiating an interface if you pass `initialize_with_config`:
|
|
161
161
|
|
|
162
162
|
```python
|
|
163
|
-
from
|
|
163
|
+
from fsspec.implementations.zip import ZipFileSystem
|
|
164
164
|
from bw_processing import load_datapackage
|
|
165
165
|
import requests
|
|
166
166
|
import numpy as np
|
|
@@ -174,7 +174,7 @@ class MyInterface:
|
|
|
174
174
|
return np.array(requests.get(self.url).json())
|
|
175
175
|
|
|
176
176
|
|
|
177
|
-
my_dp = load_datapackage(
|
|
177
|
+
my_dp = load_datapackage(ZipFileSystem("some-path.zip"))
|
|
178
178
|
data_obj, resource_metadata = my_dp.get_resource("some-interface")
|
|
179
179
|
print(resource_metadata['config'])
|
|
180
180
|
>>> {"url": "example.com"}
|
|
@@ -5,10 +5,10 @@ Library for storing numeric data for use in matrix-based calculations. Designed
|
|
|
5
5
|
[][pypi status]
|
|
6
6
|
[][pypi status]
|
|
7
7
|
[][pypi status]
|
|
8
|
-
[][license]
|
|
9
9
|
|
|
10
10
|
[][read the docs]
|
|
11
|
-
[][tests]
|
|
12
12
|
[][codecov]
|
|
13
13
|
|
|
14
14
|
[][pre-commit]
|
|
@@ -16,7 +16,7 @@ Library for storing numeric data for use in matrix-based calculations. Designed
|
|
|
16
16
|
|
|
17
17
|
[pypi status]: https://pypi.org/project/bw-processing/
|
|
18
18
|
[read the docs]: https://bw-processing.readthedocs.io/
|
|
19
|
-
[tests]: https://github.com/brightway-lca/
|
|
19
|
+
[tests]: https://github.com/brightway-lca/bw_processing/actions/workflows/python-test.yml
|
|
20
20
|
[codecov]: https://app.codecov.io/gh/brightway-lca/bw-processing
|
|
21
21
|
[pre-commit]: https://github.com/pre-commit/pre-commit
|
|
22
22
|
[black]: https://github.com/psf/black
|
|
@@ -107,10 +107,10 @@ class ExampleArrayInterface:
|
|
|
107
107
|
Serialized datapackages cannot contain executable code, both because of our chosen data formats, and for security reasons. Therefore, when loading a datapackage with an interface, that interface object needs to be reconstituted as Python code - we call this cycle dehydration and rehydration. Dehydration happens automatically when a datapackage is finalized with `finalize_serialization()`, but rehydration needs to be done manually using `rehydrate_interface()`. For example:
|
|
108
108
|
|
|
109
109
|
```python
|
|
110
|
-
from
|
|
110
|
+
from fsspec.implementations.zip import ZipFileSystem
|
|
111
111
|
from bw_processing import load_datapackage
|
|
112
112
|
|
|
113
|
-
my_dp = load_datapackage(
|
|
113
|
+
my_dp = load_datapackage(ZipFileSystem("some-path.zip"))
|
|
114
114
|
my_dp.rehydrate_interface("some-resource-name", ExampleVectorInterface())
|
|
115
115
|
```
|
|
116
116
|
|
|
@@ -119,7 +119,7 @@ You can list the dehydrated interfaces present with `.dehydrated_interfaces()`.
|
|
|
119
119
|
You can store useful information for the interface object initialization under the resource key `config`. This can be used in instantiating an interface if you pass `initialize_with_config`:
|
|
120
120
|
|
|
121
121
|
```python
|
|
122
|
-
from
|
|
122
|
+
from fsspec.implementations.zip import ZipFileSystem
|
|
123
123
|
from bw_processing import load_datapackage
|
|
124
124
|
import requests
|
|
125
125
|
import numpy as np
|
|
@@ -133,7 +133,7 @@ class MyInterface:
|
|
|
133
133
|
return np.array(requests.get(self.url).json())
|
|
134
134
|
|
|
135
135
|
|
|
136
|
-
my_dp = load_datapackage(
|
|
136
|
+
my_dp = load_datapackage(ZipFileSystem("some-path.zip"))
|
|
137
137
|
data_obj, resource_metadata = my_dp.get_resource("some-interface")
|
|
138
138
|
print(resource_metadata['config'])
|
|
139
139
|
>>> {"url": "example.com"}
|
|
@@ -26,16 +26,11 @@ __all__ = (
|
|
|
26
26
|
"UndefinedInterface",
|
|
27
27
|
)
|
|
28
28
|
|
|
29
|
-
__version__ = "0.9"
|
|
29
|
+
__version__ = "0.9.6"
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
from .array_creation import create_array, create_structured_array
|
|
33
|
-
from .constants import
|
|
34
|
-
DEFAULT_LICENSES,
|
|
35
|
-
INDICES_DTYPE,
|
|
36
|
-
UNCERTAINTY_DTYPE,
|
|
37
|
-
MatrixSerializeFormat,
|
|
38
|
-
)
|
|
33
|
+
from .constants import DEFAULT_LICENSES, INDICES_DTYPE, UNCERTAINTY_DTYPE, MatrixSerializeFormat
|
|
39
34
|
from .datapackage import (
|
|
40
35
|
Datapackage,
|
|
41
36
|
DatapackageBase,
|
|
@@ -68,7 +68,8 @@ def create_structured_array(iterable, dtype, nrows=None, sort=False, sort_fields
|
|
|
68
68
|
|
|
69
69
|
``iterable`` can be data already in memory, or a generator.
|
|
70
70
|
|
|
71
|
-
``nrows`` can be supplied, if known. If ``iterable`` has a length, it will be determined automatically. If ``nrows`` is not known, this function generates chunked arrays until ``iterable`` is exhausted, and concatenates them.
|
|
71
|
+
``nrows`` can be supplied, if known. If ``iterable`` has a length, it will be determined automatically. If ``nrows`` is not known, this function generates chunked arrays until ``iterable`` is exhausted, and concatenates them.
|
|
72
|
+
"""
|
|
72
73
|
if nrows or hasattr(iterable, "__len__"):
|
|
73
74
|
if not nrows:
|
|
74
75
|
nrows = len(iterable)
|
|
@@ -6,9 +6,10 @@ from typing import Any, Dict, List, Optional, Union
|
|
|
6
6
|
|
|
7
7
|
import numpy as np
|
|
8
8
|
import pandas as pd
|
|
9
|
-
from
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
from fsspec import AbstractFileSystem
|
|
10
|
+
|
|
11
|
+
# Use this instead of fsspec MemoryFileSystem because that is a singleton!?
|
|
12
|
+
from morefs.dict import DictFS
|
|
12
13
|
|
|
13
14
|
from .constants import (
|
|
14
15
|
DEFAULT_LICENSES,
|
|
@@ -31,7 +32,7 @@ from .errors import (
|
|
|
31
32
|
from .filesystem import clean_datapackage_name
|
|
32
33
|
from .io_helpers import file_reader, file_writer
|
|
33
34
|
from .proxies import Proxy, UndefinedInterface
|
|
34
|
-
from .utils import check_name, check_suffix, load_bytes, resolve_dict_iterator
|
|
35
|
+
from .utils import check_name, check_suffix, load_bytes, resolve_dict_iterator, utc_now
|
|
35
36
|
|
|
36
37
|
|
|
37
38
|
class DatapackageBase(ABC):
|
|
@@ -109,15 +110,13 @@ class DatapackageBase(ABC):
|
|
|
109
110
|
def del_resource(self, name_or_index: Union[str, int]) -> None:
|
|
110
111
|
"""Remove a resource, and delete its data file, if any."""
|
|
111
112
|
if self._modified:
|
|
112
|
-
raise PotentialInconsistency(
|
|
113
|
-
"Datapackage is modified; save modifications or reload"
|
|
114
|
-
)
|
|
113
|
+
raise PotentialInconsistency("Datapackage is modified; save modifications or reload")
|
|
115
114
|
|
|
116
115
|
index = self._get_index(name_or_index)
|
|
117
116
|
|
|
118
117
|
try:
|
|
119
|
-
self.fs.
|
|
120
|
-
except (KeyError,
|
|
118
|
+
self.fs.rm(self.resources[index]["path"])
|
|
119
|
+
except (KeyError, FileNotFoundError):
|
|
121
120
|
# Interface has no path
|
|
122
121
|
pass
|
|
123
122
|
|
|
@@ -127,28 +126,21 @@ class DatapackageBase(ABC):
|
|
|
127
126
|
def del_resource_group(self, name: str) -> None:
|
|
128
127
|
"""Remove a resource group, and delete its data files, if any.
|
|
129
128
|
|
|
130
|
-
Use ``exclude_resource_group`` if you want to keep the underlying resource in the filesystem.
|
|
129
|
+
Use ``exclude_resource_group`` if you want to keep the underlying resource in the filesystem.
|
|
130
|
+
"""
|
|
131
131
|
if self._modified:
|
|
132
|
-
raise PotentialInconsistency(
|
|
133
|
-
"Datapackage is modified; save modifications or reload"
|
|
134
|
-
)
|
|
132
|
+
raise PotentialInconsistency("Datapackage is modified; save modifications or reload")
|
|
135
133
|
|
|
136
|
-
indices = [
|
|
137
|
-
i
|
|
138
|
-
for i, resource in enumerate(self.resources)
|
|
139
|
-
if resource.get("group") == name
|
|
140
|
-
]
|
|
134
|
+
indices = [i for i, resource in enumerate(self.resources) if resource.get("group") == name]
|
|
141
135
|
|
|
142
136
|
for obj in (obj for i, obj in enumerate(self.resources) if i in indices):
|
|
143
137
|
try:
|
|
144
|
-
self.fs.
|
|
145
|
-
except (KeyError,
|
|
138
|
+
self.fs.rm(obj["path"])
|
|
139
|
+
except (KeyError, FileNotFoundError):
|
|
146
140
|
# Interface has no path
|
|
147
141
|
pass
|
|
148
142
|
|
|
149
|
-
self.resources = [
|
|
150
|
-
obj for i, obj in enumerate(self.resources) if i not in indices
|
|
151
|
-
]
|
|
143
|
+
self.resources = [obj for i, obj in enumerate(self.resources) if i not in indices]
|
|
152
144
|
self.data = [obj for i, obj in enumerate(self.data) if i not in indices]
|
|
153
145
|
|
|
154
146
|
def get_resource(self, name_or_index: Union[str, int]) -> (Any, dict):
|
|
@@ -181,14 +173,13 @@ class DatapackageBase(ABC):
|
|
|
181
173
|
|
|
182
174
|
All included objects are the same as in the original data package, i.e. no copies are made. No checks are made to ensure consistency with modifications to the original datapackage after the creation of this filtered datapackage.
|
|
183
175
|
|
|
184
|
-
This method was introduced to allow for the efficient construction of matrices; each datapackage can have data for multiple matrices, and we can then create filtered datapackages which exclusively have data for the matrix of interest. As such, they should be considered read-only, though this is not enforced.
|
|
176
|
+
This method was introduced to allow for the efficient construction of matrices; each datapackage can have data for multiple matrices, and we can then create filtered datapackages which exclusively have data for the matrix of interest. As such, they should be considered read-only, though this is not enforced.
|
|
177
|
+
"""
|
|
185
178
|
fdp = FilteredDatapackage()
|
|
186
179
|
fdp.fs = self.fs
|
|
187
180
|
fdp.metadata = {k: v for k, v in self.metadata.items() if k != "resources"}
|
|
188
181
|
fdp.metadata["resources"] = []
|
|
189
|
-
to_include = [
|
|
190
|
-
i for i, resource in enumerate(self.resources) if resource.get(key) == value
|
|
191
|
-
]
|
|
182
|
+
to_include = [i for i, resource in enumerate(self.resources) if resource.get(key) == value]
|
|
192
183
|
fdp.data = [o for i, o in enumerate(self.data) if i in to_include]
|
|
193
184
|
fdp.resources = [o for i, o in enumerate(self.resources) if i in to_include]
|
|
194
185
|
if hasattr(self, "indexer"):
|
|
@@ -223,17 +214,13 @@ class DatapackageBase(ABC):
|
|
|
223
214
|
if any(resource.get(key) != value for key, value in filters.items())
|
|
224
215
|
]
|
|
225
216
|
fdp.data = [o for i, o in enumerate(self.data) if i in indices_to_include]
|
|
226
|
-
fdp.resources = [
|
|
227
|
-
o for i, o in enumerate(self.resources) if i in indices_to_include
|
|
228
|
-
]
|
|
217
|
+
fdp.resources = [o for i, o in enumerate(self.resources) if i in indices_to_include]
|
|
229
218
|
return fdp
|
|
230
219
|
|
|
231
220
|
def _dehydrate_interfaces(self) -> None:
|
|
232
221
|
"""Substitute an interface resource with ``UndefinedInterface``, in preparation for finalizing data on disk."""
|
|
233
222
|
interface_indices = [
|
|
234
|
-
index
|
|
235
|
-
for index, obj in enumerate(self.resources)
|
|
236
|
-
if obj["profile"] == "interface"
|
|
223
|
+
index for index, obj in enumerate(self.resources) if obj["profile"] == "interface"
|
|
237
224
|
]
|
|
238
225
|
|
|
239
226
|
for index in interface_indices:
|
|
@@ -299,7 +286,7 @@ class Datapackage(DatapackageBase):
|
|
|
299
286
|
return hash((self.fs, self.metadata))
|
|
300
287
|
|
|
301
288
|
def __eq__(self, other):
|
|
302
|
-
return (self.fs, self.metadata) == (other.fs, other.metadata)
|
|
289
|
+
return (id(self.fs), self.metadata) == (id(other.fs), other.metadata)
|
|
303
290
|
|
|
304
291
|
def _check_length_consistency(self) -> None:
|
|
305
292
|
if len(self.resources) != len(self.data):
|
|
@@ -310,7 +297,7 @@ class Datapackage(DatapackageBase):
|
|
|
310
297
|
)
|
|
311
298
|
|
|
312
299
|
def _load(
|
|
313
|
-
self, fs:
|
|
300
|
+
self, fs: AbstractFileSystem, mmap_mode: Optional[str] = None, proxy: bool = False
|
|
314
301
|
) -> None:
|
|
315
302
|
self.fs = fs
|
|
316
303
|
self.metadata = file_reader(
|
|
@@ -336,7 +323,7 @@ class Datapackage(DatapackageBase):
|
|
|
336
323
|
|
|
337
324
|
def _create(
|
|
338
325
|
self,
|
|
339
|
-
fs: Optional[
|
|
326
|
+
fs: Optional[AbstractFileSystem],
|
|
340
327
|
name: Optional[str],
|
|
341
328
|
id_: Optional[str],
|
|
342
329
|
metadata: Optional[dict],
|
|
@@ -356,7 +343,7 @@ class Datapackage(DatapackageBase):
|
|
|
356
343
|
name = clean_datapackage_name(name or uuid.uuid4().hex)
|
|
357
344
|
check_name(name)
|
|
358
345
|
|
|
359
|
-
self.fs = fs or
|
|
346
|
+
self.fs = fs or DictFS()
|
|
360
347
|
if not isinstance(matrix_serialize_format_type, MatrixSerializeFormat):
|
|
361
348
|
raise TypeError(
|
|
362
349
|
f"Matrix serialize format type ({matrix_serialize_format_type}) not recognized!"
|
|
@@ -369,7 +356,7 @@ class Datapackage(DatapackageBase):
|
|
|
369
356
|
"id": id_ or uuid.uuid4().hex,
|
|
370
357
|
"licenses": (metadata or {}).get("licenses", DEFAULT_LICENSES),
|
|
371
358
|
"resources": [],
|
|
372
|
-
"created":
|
|
359
|
+
"created": utc_now().isoformat("T") + "Z",
|
|
373
360
|
"combinatorial": combinatorial,
|
|
374
361
|
"sequential": sequential,
|
|
375
362
|
"seed": seed,
|
|
@@ -386,7 +373,7 @@ class Datapackage(DatapackageBase):
|
|
|
386
373
|
def finalize_serialization(self) -> None:
|
|
387
374
|
if self._finalized:
|
|
388
375
|
raise Closed("Datapackage already finalized")
|
|
389
|
-
elif isinstance(self.fs,
|
|
376
|
+
elif isinstance(self.fs, DictFS):
|
|
390
377
|
raise ValueError("In-memory file systems can't be serialized")
|
|
391
378
|
|
|
392
379
|
self._dehydrate_interfaces()
|
|
@@ -398,7 +385,8 @@ class Datapackage(DatapackageBase):
|
|
|
398
385
|
resource="datapackage.json",
|
|
399
386
|
mimetype="application/json",
|
|
400
387
|
)
|
|
401
|
-
self.fs
|
|
388
|
+
if hasattr(self.fs, "close"):
|
|
389
|
+
self.fs.close()
|
|
402
390
|
self._finalized = True
|
|
403
391
|
|
|
404
392
|
def _prepare_modifications(self) -> None:
|
|
@@ -469,9 +457,7 @@ class Datapackage(DatapackageBase):
|
|
|
469
457
|
|
|
470
458
|
# Check lengths
|
|
471
459
|
|
|
472
|
-
kwargs.update(
|
|
473
|
-
{"matrix": matrix, "category": "vector", "nrows": len(indices_array)}
|
|
474
|
-
)
|
|
460
|
+
kwargs.update({"matrix": matrix, "category": "vector", "nrows": len(indices_array)})
|
|
475
461
|
name = self._prepare_name(name)
|
|
476
462
|
|
|
477
463
|
indices_array = load_bytes(indices_array)
|
|
@@ -514,9 +500,7 @@ class Datapackage(DatapackageBase):
|
|
|
514
500
|
if distributions_array is not None:
|
|
515
501
|
distributions_array = load_bytes(distributions_array)
|
|
516
502
|
# If no uncertainty, don't need to store it
|
|
517
|
-
if (distributions_array["uncertainty_type"] < 2).sum() < len(
|
|
518
|
-
distributions_array
|
|
519
|
-
):
|
|
503
|
+
if (distributions_array["uncertainty_type"] < 2).sum() < len(distributions_array):
|
|
520
504
|
if distributions_array.shape != indices_array.shape:
|
|
521
505
|
raise ShapeMismatch(
|
|
522
506
|
"`distributions_array` shape ({}) doesn't match `indices_array` ({}).".format(
|
|
@@ -540,9 +524,7 @@ class Datapackage(DatapackageBase):
|
|
|
540
524
|
if flip_array.sum():
|
|
541
525
|
if flip_array.dtype != bool:
|
|
542
526
|
raise WrongDatatype(
|
|
543
|
-
"`flip_array` dtype is {}, but must be `bool`".format(
|
|
544
|
-
flip_array.dtype
|
|
545
|
-
)
|
|
527
|
+
"`flip_array` dtype is {}, but must be `bool`".format(flip_array.dtype)
|
|
546
528
|
)
|
|
547
529
|
elif flip_array.shape != indices_array.shape:
|
|
548
530
|
raise ShapeMismatch(
|
|
@@ -577,9 +559,7 @@ class Datapackage(DatapackageBase):
|
|
|
577
559
|
""" """
|
|
578
560
|
self._prepare_modifications()
|
|
579
561
|
|
|
580
|
-
kwargs.update(
|
|
581
|
-
{"matrix": matrix, "category": "array", "nrows": len(indices_array)}
|
|
582
|
-
)
|
|
562
|
+
kwargs.update({"matrix": matrix, "category": "array", "nrows": len(indices_array)})
|
|
583
563
|
name = self._prepare_name(name)
|
|
584
564
|
|
|
585
565
|
indices_array = load_bytes(indices_array)
|
|
@@ -624,9 +604,7 @@ class Datapackage(DatapackageBase):
|
|
|
624
604
|
if flip_array.sum():
|
|
625
605
|
if flip_array.dtype != bool:
|
|
626
606
|
raise WrongDatatype(
|
|
627
|
-
"`flip_array` dtype is {}, but must be `bool`".format(
|
|
628
|
-
flip_array.dtype
|
|
629
|
-
)
|
|
607
|
+
"`flip_array` dtype is {}, but must be `bool`".format(flip_array.dtype)
|
|
630
608
|
)
|
|
631
609
|
elif flip_array.shape != indices_array.shape:
|
|
632
610
|
raise ShapeMismatch(
|
|
@@ -714,9 +692,7 @@ class Datapackage(DatapackageBase):
|
|
|
714
692
|
meta_type: Optional[str] = None,
|
|
715
693
|
**kwargs,
|
|
716
694
|
) -> None:
|
|
717
|
-
assert
|
|
718
|
-
array.ndim <= 2
|
|
719
|
-
), f"Numpy array should be of dim 2 or less instead of {array.ndim}!"
|
|
695
|
+
assert array.ndim <= 2, f"Numpy array should be of dim 2 or less instead of {array.ndim}!"
|
|
720
696
|
|
|
721
697
|
if matrix_serialize_format_type is None:
|
|
722
698
|
# use instance default serialization format
|
|
@@ -739,13 +715,13 @@ class Datapackage(DatapackageBase):
|
|
|
739
715
|
f"Matrix serialize format type {matrix_serialize_format_type} is not recognized!"
|
|
740
716
|
)
|
|
741
717
|
|
|
742
|
-
if not isinstance(self.fs,
|
|
718
|
+
if not isinstance(self.fs, DictFS):
|
|
743
719
|
file_writer(
|
|
744
720
|
data=array,
|
|
745
721
|
fs=self.fs,
|
|
746
722
|
resource=filename,
|
|
747
723
|
mimetype="application/octet-stream",
|
|
748
|
-
matrix_serialize_format_type=matrix_serialize_format_type,
|
|
724
|
+
matrix_serialize_format_type=matrix_serialize_format_type,
|
|
749
725
|
meta_object=meta_object,
|
|
750
726
|
meta_type=meta_type,
|
|
751
727
|
)
|
|
@@ -791,9 +767,7 @@ class Datapackage(DatapackageBase):
|
|
|
791
767
|
) -> None:
|
|
792
768
|
self._prepare_modifications()
|
|
793
769
|
|
|
794
|
-
kwargs.update(
|
|
795
|
-
{"matrix": matrix, "category": "vector", "nrows": len(indices_array)}
|
|
796
|
-
)
|
|
770
|
+
kwargs.update({"matrix": matrix, "category": "vector", "nrows": len(indices_array)})
|
|
797
771
|
name = self._prepare_name(name)
|
|
798
772
|
|
|
799
773
|
indices_array = load_bytes(indices_array)
|
|
@@ -813,9 +787,7 @@ class Datapackage(DatapackageBase):
|
|
|
813
787
|
if flip_array.sum():
|
|
814
788
|
if flip_array.dtype != bool:
|
|
815
789
|
raise WrongDatatype(
|
|
816
|
-
"`flip_array` dtype is {}, but must be `bool`".format(
|
|
817
|
-
flip_array.dtype
|
|
818
|
-
)
|
|
790
|
+
"`flip_array` dtype is {}, but must be `bool`".format(flip_array.dtype)
|
|
819
791
|
)
|
|
820
792
|
elif flip_array.shape != indices_array.shape:
|
|
821
793
|
raise ShapeMismatch(
|
|
@@ -863,9 +835,7 @@ class Datapackage(DatapackageBase):
|
|
|
863
835
|
if isinstance(flip_array, np.ndarray) and not flip_array.sum():
|
|
864
836
|
flip_array = None
|
|
865
837
|
|
|
866
|
-
kwargs.update(
|
|
867
|
-
{"matrix": matrix, "category": "array", "nrows": len(indices_array)}
|
|
868
|
-
)
|
|
838
|
+
kwargs.update({"matrix": matrix, "category": "array", "nrows": len(indices_array)})
|
|
869
839
|
name = self._prepare_name(name)
|
|
870
840
|
|
|
871
841
|
indices_array = load_bytes(indices_array)
|
|
@@ -885,9 +855,7 @@ class Datapackage(DatapackageBase):
|
|
|
885
855
|
if flip_array.sum():
|
|
886
856
|
if flip_array.dtype != bool:
|
|
887
857
|
raise WrongDatatype(
|
|
888
|
-
"`flip_array` dtype is {}, but must be `bool`".format(
|
|
889
|
-
flip_array.dtype
|
|
890
|
-
)
|
|
858
|
+
"`flip_array` dtype is {}, but must be `bool`".format(flip_array.dtype)
|
|
891
859
|
)
|
|
892
860
|
elif flip_array.shape != indices_array.shape:
|
|
893
861
|
raise ShapeMismatch(
|
|
@@ -975,9 +943,7 @@ class Datapackage(DatapackageBase):
|
|
|
975
943
|
)
|
|
976
944
|
self.resources.append(kwargs)
|
|
977
945
|
|
|
978
|
-
def add_json_metadata(
|
|
979
|
-
self, *, data: Any, valid_for: str, name: str = None, **kwargs
|
|
980
|
-
) -> None:
|
|
946
|
+
def add_json_metadata(self, *, data: Any, valid_for: str, name: str = None, **kwargs) -> None:
|
|
981
947
|
"""Add an iterable metadata object to be stored as a JSON file.
|
|
982
948
|
|
|
983
949
|
The purpose of storing metadata is to enable data exchange; therefore, this method assumes that data is written to disk.
|
|
@@ -1013,9 +979,7 @@ class Datapackage(DatapackageBase):
|
|
|
1013
979
|
|
|
1014
980
|
filename = check_suffix(name, ".json")
|
|
1015
981
|
|
|
1016
|
-
file_writer(
|
|
1017
|
-
data=data, fs=self.fs, resource=filename, mimetype="application/json"
|
|
1018
|
-
)
|
|
982
|
+
file_writer(data=data, fs=self.fs, resource=filename, mimetype="application/json")
|
|
1019
983
|
self.data.append(data)
|
|
1020
984
|
|
|
1021
985
|
kwargs.update(
|
|
@@ -1033,7 +997,7 @@ class Datapackage(DatapackageBase):
|
|
|
1033
997
|
|
|
1034
998
|
|
|
1035
999
|
def create_datapackage(
|
|
1036
|
-
fs: Optional[
|
|
1000
|
+
fs: Optional[AbstractFileSystem] = None,
|
|
1037
1001
|
name: Optional[str] = None,
|
|
1038
1002
|
id_: Optional[str] = None,
|
|
1039
1003
|
metadata: Optional[dict] = None,
|
|
@@ -1046,24 +1010,23 @@ def create_datapackage(
|
|
|
1046
1010
|
) -> Datapackage:
|
|
1047
1011
|
"""Create a new data package.
|
|
1048
1012
|
|
|
1049
|
-
All arguments are optional; if a `
|
|
1013
|
+
All arguments are optional; if a `fsspec <https://filesystem-spec.readthedocs.io/en/latest/>`__ filesystem is not provided, an in-memory `DictFS <https://github.com/iterative/morefs?tab=readme-ov-file#dictfs>`__ will be used.
|
|
1050
1014
|
|
|
1051
1015
|
All metadata elements should follow the `datapackage specification <https://frictionlessdata.io/specs/data-package/>`__.
|
|
1052
1016
|
|
|
1053
1017
|
Licenses are specified as a list in ``metadata``. The default license is the `Open Data Commons Public Domain Dedication and License v1.0 <http://opendatacommons.org/licenses/pddl/>`__.
|
|
1054
1018
|
|
|
1055
1019
|
Args:
|
|
1056
|
-
|
|
1057
|
-
*
|
|
1058
|
-
*
|
|
1059
|
-
*
|
|
1060
|
-
*
|
|
1061
|
-
*
|
|
1062
|
-
*
|
|
1063
|
-
*
|
|
1064
|
-
*
|
|
1065
|
-
*
|
|
1066
|
-
* matrix_serialize_format_type. `MatrixSerializeFormat`, default `MatrixSerializeFormat.NUMPY`. Matrix serialization format type.
|
|
1020
|
+
* fs: A ``Filesystem``, optional. A new ``DictFS`` is used if not provided.
|
|
1021
|
+
* name: ``str``, optional. A new uuid is used if not provided.
|
|
1022
|
+
* `id_`: ``str``, optional. A new uuid is used if not provided.
|
|
1023
|
+
* metadata: ``dict``, optional. Metadata dictionary following datapackage specification; see above.
|
|
1024
|
+
* combinatorial: ``bool``, default ``False`` .: Policy on how to sample columns across multiple data arrays; see readme.
|
|
1025
|
+
* sequential: ``bool``, default ``False`` .: Policy on how to sample columns in data arrays; see readme.
|
|
1026
|
+
* seed: ``int``, optional. Seed to use in random number generator.
|
|
1027
|
+
* sum_intra_duplicates: ``bool``, default ``True``. Should duplicate elements in a single data resource be summed together, or should the last value replace previous values.
|
|
1028
|
+
* sum_inter_duplicates: ``bool``, default ``False``. Should duplicate elements in across data resources be summed together, or should the last value replace previous values. Order of data resources is given by the order they are added to the data package.
|
|
1029
|
+
* matrix_serialize_format_type: ``MatrixSerializeFormat``, default ``MatrixSerializeFormat.NUMPY``. Matrix serialization format type.
|
|
1067
1030
|
|
|
1068
1031
|
Returns:
|
|
1069
1032
|
|
|
@@ -1087,7 +1050,7 @@ def create_datapackage(
|
|
|
1087
1050
|
|
|
1088
1051
|
|
|
1089
1052
|
def load_datapackage(
|
|
1090
|
-
fs_or_obj: Union[DatapackageBase,
|
|
1053
|
+
fs_or_obj: Union[DatapackageBase, AbstractFileSystem],
|
|
1091
1054
|
mmap_mode: Optional[str] = None,
|
|
1092
1055
|
proxy: bool = False,
|
|
1093
1056
|
) -> Datapackage:
|
|
@@ -1099,9 +1062,9 @@ def load_datapackage(
|
|
|
1099
1062
|
|
|
1100
1063
|
Args:
|
|
1101
1064
|
|
|
1102
|
-
* fs_or_obj
|
|
1103
|
-
* mmap_mode
|
|
1104
|
-
* proxy
|
|
1065
|
+
* fs_or_obj: A `Filesystem` or an instance of `DatapackageBase`.
|
|
1066
|
+
* mmap_mode: `str`, optional. Define memory mapping mode to use when loading Numpy arrays.
|
|
1067
|
+
* proxy: bool, default `False`. Load proxies instead of complete Numpy arrays; see above.
|
|
1105
1068
|
|
|
1106
1069
|
Returns:
|
|
1107
1070
|
|
|
@@ -1116,29 +1079,34 @@ def load_datapackage(
|
|
|
1116
1079
|
return obj
|
|
1117
1080
|
|
|
1118
1081
|
|
|
1119
|
-
def simple_graph(data: dict, fs: Optional[
|
|
1082
|
+
def simple_graph(data: dict, fs: Optional[AbstractFileSystem] = None, **metadata) -> Datapackage:
|
|
1120
1083
|
"""Easy creation of simple datapackages with only persistent vectors.
|
|
1121
1084
|
|
|
1122
|
-
|
|
1085
|
+
Args:
|
|
1086
|
+
* data: is a dictionary.
|
|
1087
|
+
The data dictionary has the form::
|
|
1123
1088
|
|
|
1124
|
-
|
|
1089
|
+
{
|
|
1090
|
+
matrix_name: [
|
|
1091
|
+
(row_id, col_id, value, flip)
|
|
1092
|
+
]
|
|
1093
|
+
}
|
|
1125
1094
|
|
|
1126
|
-
matrix_name (str): [
|
|
1127
|
-
(row id (int), col id (int), value (float), flip (bool, default False))
|
|
1128
|
-
]
|
|
1129
1095
|
|
|
1130
|
-
|
|
1096
|
+
Where `row_id` and `col_id are an `int` s, value is a `float` and flip is a `bool` (False by default).
|
|
1131
1097
|
|
|
1132
|
-
|
|
1098
|
+
* fs: is a filesystem.
|
|
1099
|
+
* metadata: are passed as kwargs to ``create_datapackage()``.
|
|
1133
1100
|
|
|
1134
|
-
Returns
|
|
1135
|
-
|
|
1101
|
+
Returns:
|
|
1102
|
+
the datapackage.
|
|
1103
|
+
|
|
1104
|
+
"""
|
|
1105
|
+
dp = create_datapackage(fs=fs or DictFS(), **metadata)
|
|
1136
1106
|
for key, value in data.items():
|
|
1137
1107
|
indices_array = np.array([row[:2] for row in value], dtype=INDICES_DTYPE)
|
|
1138
1108
|
data_array = np.array([row[2] for row in value])
|
|
1139
|
-
flip_array = np.array(
|
|
1140
|
-
[row[3] if len(row) > 3 else False for row in value], dtype=bool
|
|
1141
|
-
)
|
|
1109
|
+
flip_array = np.array([row[3] if len(row) > 3 else False for row in value], dtype=bool)
|
|
1142
1110
|
dp.add_persistent_vector(
|
|
1143
1111
|
matrix=key,
|
|
1144
1112
|
data_array=data_array,
|
|
@@ -29,7 +29,8 @@ class ShapeMismatch(BrightwayProcessingError):
|
|
|
29
29
|
class InvalidName(BrightwayProcessingError):
|
|
30
30
|
"""Name fails datapackage requirements:
|
|
31
31
|
|
|
32
|
-
A short url-usable (and preferably human-readable) name of the package. This MUST be lower-case and contain only alphanumeric characters along with ".", "_" or "-" characters.
|
|
32
|
+
A short url-usable (and preferably human-readable) name of the package. This MUST be lower-case and contain only alphanumeric characters along with ".", "_" or "-" characters.
|
|
33
|
+
"""
|
|
33
34
|
|
|
34
35
|
pass
|
|
35
36
|
|
|
Binary file
|