bw-processing 1.1__tar.gz → 1.2__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.
Files changed (54) hide show
  1. {bw_processing-1.1/src/bw_processing.egg-info → bw_processing-1.2}/PKG-INFO +21 -1
  2. {bw_processing-1.1 → bw_processing-1.2}/README.md +20 -0
  3. {bw_processing-1.1 → bw_processing-1.2}/src/bw_processing/__init__.py +1 -1
  4. {bw_processing-1.1 → bw_processing-1.2}/src/bw_processing/io_helpers.py +13 -2
  5. {bw_processing-1.1 → bw_processing-1.2}/src/bw_processing/matrix_entry.py +16 -0
  6. {bw_processing-1.1 → bw_processing-1.2/src/bw_processing.egg-info}/PKG-INFO +21 -1
  7. {bw_processing-1.1 → bw_processing-1.2}/tests/test_datapackage.py +40 -1
  8. {bw_processing-1.1 → bw_processing-1.2}/tests/test_matrix_entry.py +21 -1
  9. {bw_processing-1.1 → bw_processing-1.2}/LICENSE +0 -0
  10. {bw_processing-1.1 → bw_processing-1.2}/MANIFEST.in +0 -0
  11. {bw_processing-1.1 → bw_processing-1.2}/pyproject.toml +0 -0
  12. {bw_processing-1.1 → bw_processing-1.2}/setup.cfg +0 -0
  13. {bw_processing-1.1 → bw_processing-1.2}/src/bw_processing/array_creation.py +0 -0
  14. {bw_processing-1.1 → bw_processing-1.2}/src/bw_processing/constants.py +0 -0
  15. {bw_processing-1.1 → bw_processing-1.2}/src/bw_processing/datapackage.py +0 -0
  16. {bw_processing-1.1 → bw_processing-1.2}/src/bw_processing/errors.py +0 -0
  17. {bw_processing-1.1 → bw_processing-1.2}/src/bw_processing/examples/__init__.py +0 -0
  18. {bw_processing-1.1 → bw_processing-1.2}/src/bw_processing/examples/datapackage_1/another name.indices.parquet +0 -0
  19. {bw_processing-1.1 → bw_processing-1.2}/src/bw_processing/examples/datapackage_1/sa-data-vector-from-dict.data.parquet +0 -0
  20. {bw_processing-1.1 → bw_processing-1.2}/src/bw_processing/examples/datapackage_1/sa-data-vector-from-dict.distributions.parquet +0 -0
  21. {bw_processing-1.1 → bw_processing-1.2}/src/bw_processing/examples/datapackage_1/sa-data-vector-from-dict.flip.parquet +0 -0
  22. {bw_processing-1.1 → bw_processing-1.2}/src/bw_processing/examples/datapackage_1/sa-data-vector-from-dict.indices.parquet +0 -0
  23. {bw_processing-1.1 → bw_processing-1.2}/src/bw_processing/examples/datapackage_1/some name.data.parquet +0 -0
  24. {bw_processing-1.1 → bw_processing-1.2}/src/bw_processing/examples/datapackage_1/some name.flip.parquet +0 -0
  25. {bw_processing-1.1 → bw_processing-1.2}/src/bw_processing/examples/datapackage_1/some name.indices.parquet +0 -0
  26. {bw_processing-1.1 → bw_processing-1.2}/src/bw_processing/examples/datapackage_2.zip +0 -0
  27. {bw_processing-1.1 → bw_processing-1.2}/src/bw_processing/examples/interfaces.py +0 -0
  28. {bw_processing-1.1 → bw_processing-1.2}/src/bw_processing/examples/parquet_files.py +0 -0
  29. {bw_processing-1.1 → bw_processing-1.2}/src/bw_processing/examples/simple.zip +0 -0
  30. {bw_processing-1.1 → bw_processing-1.2}/src/bw_processing/filesystem.py +0 -0
  31. {bw_processing-1.1 → bw_processing-1.2}/src/bw_processing/indexing.py +0 -0
  32. {bw_processing-1.1 → bw_processing-1.2}/src/bw_processing/io_parquet_helpers.py +0 -0
  33. {bw_processing-1.1 → bw_processing-1.2}/src/bw_processing/io_pyarrow_helpers.py +0 -0
  34. {bw_processing-1.1 → bw_processing-1.2}/src/bw_processing/merging.py +0 -0
  35. {bw_processing-1.1 → bw_processing-1.2}/src/bw_processing/proxies.py +0 -0
  36. {bw_processing-1.1 → bw_processing-1.2}/src/bw_processing/unique_fields.py +0 -0
  37. {bw_processing-1.1 → bw_processing-1.2}/src/bw_processing/utils.py +0 -0
  38. {bw_processing-1.1 → bw_processing-1.2}/src/bw_processing.egg-info/SOURCES.txt +0 -0
  39. {bw_processing-1.1 → bw_processing-1.2}/src/bw_processing.egg-info/dependency_links.txt +0 -0
  40. {bw_processing-1.1 → bw_processing-1.2}/src/bw_processing.egg-info/requires.txt +0 -0
  41. {bw_processing-1.1 → bw_processing-1.2}/src/bw_processing.egg-info/top_level.txt +0 -0
  42. {bw_processing-1.1 → bw_processing-1.2}/tests/test_array_creation.py +0 -0
  43. {bw_processing-1.1 → bw_processing-1.2}/tests/test_filesystem.py +0 -0
  44. {bw_processing-1.1 → bw_processing-1.2}/tests/test_filtered_datapackage.py +0 -0
  45. {bw_processing-1.1 → bw_processing-1.2}/tests/test_indexing.py +0 -0
  46. {bw_processing-1.1 → bw_processing-1.2}/tests/test_integration.py +0 -0
  47. {bw_processing-1.1 → bw_processing-1.2}/tests/test_interfaces.py +0 -0
  48. {bw_processing-1.1 → bw_processing-1.2}/tests/test_io_parquet_helpers.py +0 -0
  49. {bw_processing-1.1 → bw_processing-1.2}/tests/test_io_pyarrow_helpers.py +0 -0
  50. {bw_processing-1.1 → bw_processing-1.2}/tests/test_loading.py +0 -0
  51. {bw_processing-1.1 → bw_processing-1.2}/tests/test_merging.py +0 -0
  52. {bw_processing-1.1 → bw_processing-1.2}/tests/test_proxies.py +0 -0
  53. {bw_processing-1.1 → bw_processing-1.2}/tests/test_unique_fields.py +0 -0
  54. {bw_processing-1.1 → bw_processing-1.2}/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bw_processing
3
- Version: 1.1
3
+ Version: 1.2
4
4
  Summary: Foo
5
5
  Author-email: Chris Mutel <cmutel@gmail.com>
6
6
  Maintainer-email: Chris Mutel <cmutel@gmail.com>
@@ -240,6 +240,26 @@ Datapackages are created using `create_datapackage`, which takes the following a
240
240
  * overwrite: `bool`, default `False`. Overwrite an existing resource with the same `dirpath` and `name`.
241
241
  * compress: `bool`, default `False`. Save to a zipfile, if saving to disk.
242
242
 
243
+ ### Zip file compression
244
+
245
+ When writing a datapackage as a zip file via `generic_zipfile_filesystem`, compression is enabled by default (`zipfile.ZIP_DEFLATED`). Index arrays in particular compress extremely well (often to <10% of their original size) because they contain a limited set of repeated integer values. Float data arrays compress less, but the overall file size reduction is substantial.
246
+
247
+ ```python
248
+ import zipfile
249
+ from bw_processing.io_helpers import generic_zipfile_filesystem
250
+
251
+ # Default: ZIP_DEFLATED (recommended — good compression, fast)
252
+ fs = generic_zipfile_filesystem(dirpath=some_path, filename="my.zip")
253
+
254
+ # Uncompressed — fastest write/read, largest file
255
+ fs = generic_zipfile_filesystem(dirpath=some_path, filename="my.zip", compression=zipfile.ZIP_STORED)
256
+
257
+ # LZMA — best compression ratio, but much slower to write
258
+ fs = generic_zipfile_filesystem(dirpath=some_path, filename="my.zip", compression=zipfile.ZIP_LZMA)
259
+ ```
260
+
261
+ The `compression` and `compresslevel` arguments are passed directly to Python's `zipfile.ZipFile`. See the [Python docs](https://docs.python.org/3/library/zipfile.html#zipfile.ZipFile) for all options.
262
+
243
263
  Calling this function return an instance of `Datapackage`. You still need to add data.
244
264
 
245
265
  ## Contributing
@@ -198,6 +198,26 @@ Datapackages are created using `create_datapackage`, which takes the following a
198
198
  * overwrite: `bool`, default `False`. Overwrite an existing resource with the same `dirpath` and `name`.
199
199
  * compress: `bool`, default `False`. Save to a zipfile, if saving to disk.
200
200
 
201
+ ### Zip file compression
202
+
203
+ When writing a datapackage as a zip file via `generic_zipfile_filesystem`, compression is enabled by default (`zipfile.ZIP_DEFLATED`). Index arrays in particular compress extremely well (often to <10% of their original size) because they contain a limited set of repeated integer values. Float data arrays compress less, but the overall file size reduction is substantial.
204
+
205
+ ```python
206
+ import zipfile
207
+ from bw_processing.io_helpers import generic_zipfile_filesystem
208
+
209
+ # Default: ZIP_DEFLATED (recommended — good compression, fast)
210
+ fs = generic_zipfile_filesystem(dirpath=some_path, filename="my.zip")
211
+
212
+ # Uncompressed — fastest write/read, largest file
213
+ fs = generic_zipfile_filesystem(dirpath=some_path, filename="my.zip", compression=zipfile.ZIP_STORED)
214
+
215
+ # LZMA — best compression ratio, but much slower to write
216
+ fs = generic_zipfile_filesystem(dirpath=some_path, filename="my.zip", compression=zipfile.ZIP_LZMA)
217
+ ```
218
+
219
+ The `compression` and `compresslevel` arguments are passed directly to Python's `zipfile.ZipFile`. See the [Python docs](https://docs.python.org/3/library/zipfile.html#zipfile.ZipFile) for all options.
220
+
201
221
  Calling this function return an instance of `Datapackage`. You still need to add data.
202
222
 
203
223
  ## Contributing
@@ -29,7 +29,7 @@ __all__ = (
29
29
  "UndefinedInterface",
30
30
  )
31
31
 
32
- __version__ = "1.1"
32
+ __version__ = "1.2"
33
33
 
34
34
 
35
35
  from bw_processing.array_creation import create_array, create_structured_array
@@ -1,4 +1,5 @@
1
1
  import json
2
+ import zipfile
2
3
  from mimetypes import guess_type
3
4
  from pathlib import Path
4
5
  from typing import Any, Optional, Union
@@ -35,12 +36,22 @@ def generic_directory_filesystem(*, dirpath: Path) -> DirFileSystem:
35
36
 
36
37
 
37
38
  def generic_zipfile_filesystem(
38
- *, dirpath: Path, filename: str, write: bool = True
39
+ *,
40
+ dirpath: Path,
41
+ filename: str,
42
+ write: bool = True,
43
+ compression: int = zipfile.ZIP_DEFLATED,
44
+ compresslevel: Optional[int] = None,
39
45
  ) -> ZipFileSystem:
40
46
  assert isinstance(dirpath, Path), "`dirpath` must be a `pathlib.Path` instance"
41
47
  if not dirpath.is_dir():
42
48
  raise ValueError("Destination directory `{}` doesn't exist".format(dirpath))
43
- return ZipFileSystem(dirpath / filename, mode="w" if write else "r")
49
+ return ZipFileSystem(
50
+ dirpath / filename,
51
+ mode="w" if write else "r",
52
+ compression=compression,
53
+ compresslevel=compresslevel,
54
+ )
44
55
 
45
56
 
46
57
  def file_reader(
@@ -2,6 +2,12 @@ import dataclasses
2
2
  import math
3
3
  from enum import Enum
4
4
 
5
+ try:
6
+ from stats_arrays import NoUncertainty, UndefinedUncertainty
7
+ _NO_UNCERTAINTY_IDS = (UndefinedUncertainty.id, NoUncertainty.id)
8
+ except ImportError:
9
+ _NO_UNCERTAINTY_IDS = (0, 1)
10
+
5
11
 
6
12
  class MatrixName(str, Enum):
7
13
  """Standard matrix names used in Brightway.
@@ -63,6 +69,16 @@ class MatrixEntry:
63
69
  maximum: float = math.nan
64
70
  negative: bool = False
65
71
 
72
+ def __post_init__(self):
73
+ if self.uncertainty_type in _NO_UNCERTAINTY_IDS:
74
+ if math.isnan(self.loc):
75
+ object.__setattr__(self, "loc", self.amount)
76
+ elif self.loc != self.amount:
77
+ raise ValueError(
78
+ f"uncertainty_type {self.uncertainty_type} requires loc == amount, "
79
+ f"got loc={self.loc} but amount={self.amount}"
80
+ )
81
+
66
82
  def as_dict(self) -> dict:
67
83
  return dataclasses.asdict(self)
68
84
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bw_processing
3
- Version: 1.1
3
+ Version: 1.2
4
4
  Summary: Foo
5
5
  Author-email: Chris Mutel <cmutel@gmail.com>
6
6
  Maintainer-email: Chris Mutel <cmutel@gmail.com>
@@ -240,6 +240,26 @@ Datapackages are created using `create_datapackage`, which takes the following a
240
240
  * overwrite: `bool`, default `False`. Overwrite an existing resource with the same `dirpath` and `name`.
241
241
  * compress: `bool`, default `False`. Save to a zipfile, if saving to disk.
242
242
 
243
+ ### Zip file compression
244
+
245
+ When writing a datapackage as a zip file via `generic_zipfile_filesystem`, compression is enabled by default (`zipfile.ZIP_DEFLATED`). Index arrays in particular compress extremely well (often to <10% of their original size) because they contain a limited set of repeated integer values. Float data arrays compress less, but the overall file size reduction is substantial.
246
+
247
+ ```python
248
+ import zipfile
249
+ from bw_processing.io_helpers import generic_zipfile_filesystem
250
+
251
+ # Default: ZIP_DEFLATED (recommended — good compression, fast)
252
+ fs = generic_zipfile_filesystem(dirpath=some_path, filename="my.zip")
253
+
254
+ # Uncompressed — fastest write/read, largest file
255
+ fs = generic_zipfile_filesystem(dirpath=some_path, filename="my.zip", compression=zipfile.ZIP_STORED)
256
+
257
+ # LZMA — best compression ratio, but much slower to write
258
+ fs = generic_zipfile_filesystem(dirpath=some_path, filename="my.zip", compression=zipfile.ZIP_LZMA)
259
+ ```
260
+
261
+ The `compression` and `compresslevel` arguments are passed directly to Python's `zipfile.ZipFile`. See the [Python docs](https://docs.python.org/3/library/zipfile.html#zipfile.ZipFile) for all options.
262
+
243
263
  Calling this function return an instance of `Datapackage`. You still need to add data.
244
264
 
245
265
  ## Contributing
@@ -1,4 +1,5 @@
1
1
  import shutil
2
+ import zipfile
2
3
  from pathlib import Path
3
4
 
4
5
  import numpy as np
@@ -10,7 +11,7 @@ from morefs.dict import DictFS
10
11
  from bw_processing import create_datapackage, load_datapackage, simple_graph
11
12
  from bw_processing.constants import INDICES_DTYPE, UNCERTAINTY_DTYPE, MAX_SIGNED_64BIT_INT, MAX_SIGNED_32BIT_INT
12
13
  from bw_processing.errors import NonUnique, PotentialInconsistency, ShapeMismatch, WrongDatatype
13
- from bw_processing.io_helpers import generic_directory_filesystem
14
+ from bw_processing.io_helpers import generic_directory_filesystem, generic_zipfile_filesystem
14
15
 
15
16
  dirpath = Path(__file__).parent.resolve() / "fixtures"
16
17
 
@@ -497,3 +498,41 @@ def test_simple_graph():
497
498
  assert d["col"].sum() == 1102
498
499
  d, _ = dp.get_resource("a different life-data.data")
499
500
  assert np.allclose(d, np.array([101.234, 777]))
501
+
502
+
503
+ def _write_zip_datapackage(dirpath, filename="test.zip", **kwargs):
504
+ fs = generic_zipfile_filesystem(dirpath=dirpath, filename=filename, **kwargs)
505
+ dp = create_datapackage(fs=fs, name="test-zip-compression")
506
+ add_data(dp)
507
+ dp.finalize_serialization()
508
+ return dirpath / filename
509
+
510
+
511
+ def test_zipfile_default_compression(tmp_path):
512
+ """Default compression is ZIP_DEFLATED; indices compress well so file is smaller than uncompressed."""
513
+ compressed_path = _write_zip_datapackage(tmp_path, filename="compressed.zip")
514
+ uncompressed_path = _write_zip_datapackage(tmp_path, filename="uncompressed.zip", compression=zipfile.ZIP_STORED)
515
+
516
+ with zipfile.ZipFile(compressed_path) as zf:
517
+ for info in zf.infolist():
518
+ if info.filename.endswith(".indices.npy"):
519
+ assert info.compress_type == zipfile.ZIP_DEFLATED
520
+
521
+ assert compressed_path.stat().st_size < uncompressed_path.stat().st_size
522
+
523
+
524
+ def test_zipfile_stored_compression(tmp_path):
525
+ """ZIP_STORED writes uncompressed entries."""
526
+ zip_path = _write_zip_datapackage(tmp_path, compression=zipfile.ZIP_STORED)
527
+
528
+ with zipfile.ZipFile(zip_path) as zf:
529
+ for info in zf.infolist():
530
+ assert info.compress_type == zipfile.ZIP_STORED
531
+
532
+
533
+ def test_zipfile_compressed_roundtrip(tmp_path):
534
+ """Data written with ZIP_DEFLATED can be read back correctly."""
535
+ zip_path = _write_zip_datapackage(tmp_path)
536
+ dp = load_datapackage(ZipFileSystem(str(zip_path)))
537
+ data, _ = dp.get_resource("sa-data-vector.data")
538
+ assert np.allclose(data, [2, 7, 12])
@@ -42,12 +42,32 @@ class TestMatrixEntry:
42
42
  assert e.flip is False
43
43
  assert e.uncertainty_type == 0
44
44
  assert e.negative is False
45
- assert math.isnan(e.loc)
45
+ assert e.loc == pytest.approx(3.0)
46
46
  assert math.isnan(e.scale)
47
47
  assert math.isnan(e.shape)
48
48
  assert math.isnan(e.minimum)
49
49
  assert math.isnan(e.maximum)
50
50
 
51
+ def test_loc_set_to_amount_for_no_uncertainty(self):
52
+ e = MatrixEntry(row=1, col=2, amount=5.0)
53
+ assert e.loc == pytest.approx(5.0)
54
+
55
+ def test_explicit_loc_matching_amount_accepted(self):
56
+ e = MatrixEntry(row=1, col=2, amount=5.0, uncertainty_type=0, loc=5.0)
57
+ assert e.loc == pytest.approx(5.0)
58
+
59
+ def test_loc_mismatch_raises_for_uncertainty_type_0(self):
60
+ with pytest.raises(ValueError, match="loc == amount"):
61
+ MatrixEntry(row=1, col=2, amount=5.0, uncertainty_type=0, loc=9.9)
62
+
63
+ def test_loc_mismatch_raises_for_uncertainty_type_1(self):
64
+ with pytest.raises(ValueError, match="loc == amount"):
65
+ MatrixEntry(row=1, col=2, amount=5.0, uncertainty_type=1, loc=9.9)
66
+
67
+ def test_loc_not_set_when_uncertainty_type_nonzero(self):
68
+ e = MatrixEntry(row=1, col=2, amount=5.0, uncertainty_type=2)
69
+ assert math.isnan(e.loc)
70
+
51
71
  def test_frozen(self):
52
72
  e = MatrixEntry(row=1, col=2, amount=3.0)
53
73
  with pytest.raises(Exception):
File without changes
File without changes
File without changes
File without changes