bagofholding 0.0.3__tar.gz → 0.1.1__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 (35) hide show
  1. {bagofholding-0.0.3 → bagofholding-0.1.1}/PKG-INFO +54 -50
  2. {bagofholding-0.0.3/cached-miniforge/my-env/lib/python3.1/site-packages → bagofholding-0.1.1}/bagofholding/__init__.py +1 -1
  3. {bagofholding-0.0.3 → bagofholding-0.1.1}/bagofholding/_version.py +2 -2
  4. {bagofholding-0.0.3 → bagofholding-0.1.1}/bagofholding/content.py +10 -0
  5. {bagofholding-0.0.3/cached-miniforge/my-env/lib/python3.1/site-packages → bagofholding-0.1.1}/bagofholding/exceptions.py +1 -1
  6. {bagofholding-0.0.3 → bagofholding-0.1.1}/bagofholding/retrieve.py +2 -2
  7. {bagofholding-0.0.3/cached-miniforge/my-env/lib/python3.1/site-packages → bagofholding-0.1.1}/bagofholding/trie.py +6 -3
  8. {bagofholding-0.0.3 → bagofholding-0.1.1/cached-miniforge/my-env/lib/python3.1/site-packages}/bagofholding/__init__.py +1 -1
  9. {bagofholding-0.0.3 → bagofholding-0.1.1}/cached-miniforge/my-env/lib/python3.1/site-packages/bagofholding/_version.py +2 -2
  10. {bagofholding-0.0.3 → bagofholding-0.1.1}/cached-miniforge/my-env/lib/python3.1/site-packages/bagofholding/content.py +10 -0
  11. {bagofholding-0.0.3 → bagofholding-0.1.1/cached-miniforge/my-env/lib/python3.1/site-packages}/bagofholding/exceptions.py +1 -1
  12. {bagofholding-0.0.3 → bagofholding-0.1.1}/cached-miniforge/my-env/lib/python3.1/site-packages/bagofholding/retrieve.py +2 -2
  13. {bagofholding-0.0.3 → bagofholding-0.1.1/cached-miniforge/my-env/lib/python3.1/site-packages}/bagofholding/trie.py +6 -3
  14. {bagofholding-0.0.3 → bagofholding-0.1.1}/docs/README.md +49 -45
  15. {bagofholding-0.0.3 → bagofholding-0.1.1}/pyproject.toml +3 -3
  16. {bagofholding-0.0.3 → bagofholding-0.1.1}/.gitignore +0 -0
  17. {bagofholding-0.0.3 → bagofholding-0.1.1}/LICENSE +0 -0
  18. {bagofholding-0.0.3 → bagofholding-0.1.1}/bagofholding/bag.py +0 -0
  19. {bagofholding-0.0.3 → bagofholding-0.1.1}/bagofholding/h5/__init__.py +0 -0
  20. {bagofholding-0.0.3 → bagofholding-0.1.1}/bagofholding/h5/bag.py +0 -0
  21. {bagofholding-0.0.3 → bagofholding-0.1.1}/bagofholding/h5/content.py +0 -0
  22. {bagofholding-0.0.3 → bagofholding-0.1.1}/bagofholding/h5/context.py +0 -0
  23. {bagofholding-0.0.3 → bagofholding-0.1.1}/bagofholding/h5/dtypes.py +0 -0
  24. {bagofholding-0.0.3 → bagofholding-0.1.1}/bagofholding/h5/triebag.py +0 -0
  25. {bagofholding-0.0.3 → bagofholding-0.1.1}/bagofholding/metadata.py +0 -0
  26. {bagofholding-0.0.3 → bagofholding-0.1.1}/bagofholding/widget.py +0 -0
  27. {bagofholding-0.0.3 → bagofholding-0.1.1}/cached-miniforge/my-env/lib/python3.1/site-packages/bagofholding/bag.py +0 -0
  28. {bagofholding-0.0.3 → bagofholding-0.1.1}/cached-miniforge/my-env/lib/python3.1/site-packages/bagofholding/h5/__init__.py +0 -0
  29. {bagofholding-0.0.3 → bagofholding-0.1.1}/cached-miniforge/my-env/lib/python3.1/site-packages/bagofholding/h5/bag.py +0 -0
  30. {bagofholding-0.0.3 → bagofholding-0.1.1}/cached-miniforge/my-env/lib/python3.1/site-packages/bagofholding/h5/content.py +0 -0
  31. {bagofholding-0.0.3 → bagofholding-0.1.1}/cached-miniforge/my-env/lib/python3.1/site-packages/bagofholding/h5/context.py +0 -0
  32. {bagofholding-0.0.3 → bagofholding-0.1.1}/cached-miniforge/my-env/lib/python3.1/site-packages/bagofholding/h5/dtypes.py +0 -0
  33. {bagofholding-0.0.3 → bagofholding-0.1.1}/cached-miniforge/my-env/lib/python3.1/site-packages/bagofholding/h5/triebag.py +0 -0
  34. {bagofholding-0.0.3 → bagofholding-0.1.1}/cached-miniforge/my-env/lib/python3.1/site-packages/bagofholding/metadata.py +0 -0
  35. {bagofholding-0.0.3 → bagofholding-0.1.1}/cached-miniforge/my-env/lib/python3.1/site-packages/bagofholding/widget.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bagofholding
3
- Version: 0.0.3
3
+ Version: 0.1.1
4
4
  Summary: bagofholding - browsable, partially-reloadable serialization for pickleable python objects.
5
5
  Project-URL: Homepage, https://pyiron.org/
6
6
  Project-URL: Documentation, https://bagofholding.readthedocs.io
@@ -36,18 +36,18 @@ License: BSD 3-Clause License
36
36
  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37
37
  License-File: LICENSE
38
38
  Keywords: pyiron
39
- Classifier: Development Status :: 3 - Alpha
39
+ Classifier: Development Status :: 4 - Beta
40
40
  Classifier: Intended Audience :: Science/Research
41
41
  Classifier: License :: OSI Approved :: BSD License
42
42
  Classifier: Operating System :: OS Independent
43
43
  Classifier: Programming Language :: Python :: 3.12
44
44
  Classifier: Programming Language :: Python :: 3.13
45
45
  Classifier: Topic :: Scientific/Engineering
46
- Requires-Python: <3.14,>=3.12
46
+ Requires-Python: <3.14,>=3.11
47
47
  Requires-Dist: bidict==0.23.1
48
48
  Requires-Dist: h5py<3.15.0,>=3.14.0
49
- Requires-Dist: mpi4py<4.1.0,>=4.0.1
50
- Requires-Dist: numpy<2.4.0,>=2.3.0
49
+ Requires-Dist: mpi4py<4.2.0,>=4.1.0
50
+ Requires-Dist: numpy<2.4.0,>=2.3.1
51
51
  Requires-Dist: pygtrie<2.6.0,>=2.5.0
52
52
  Requires-Dist: pyiron-snippets==0.2.0
53
53
  Provides-Extra: widget
@@ -57,12 +57,24 @@ Description-Content-Type: text/markdown
57
57
 
58
58
  # bagofholding
59
59
 
60
- `bagofholding` is designed to be an easy stand-in for `pickle` serialization for python object that is transparent, flexible, and suitable for long-term storage.
60
+ <img src="_static/bagofholding_logo.png" alt="Logo" width="190"/>
61
+
62
+ [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/pyiron/bagofholding/HEAD)
63
+ [![License](https://img.shields.io/badge/License-BSD_3--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause)
64
+ [![Coverage](https://codecov.io/gh/pyiron/bagofholding/graph/badge.svg)](https://codecov.io/gh/pyiron/bagofholding)
65
+ [![Documentation](https://readthedocs.org/projects/bagofholding/badge/?version=latest)](https://bagofholding.readthedocs.io/en/latest/?badge=latest)
66
+
67
+ [![Anaconda](https://anaconda.org/conda-forge/bagofholding/badges/version.svg)](https://anaconda.org/conda-forge/bagofholding)
68
+ [![Last Updated](https://anaconda.org/conda-forge/bagofholding/badges/latest_release_date.svg)](https://anaconda.org/conda-forge/bagofholding)
69
+ [![Platform](https://anaconda.org/conda-forge/bagofholding/badges/platforms.svg)](https://anaconda.org/conda-forge/bagofholding)
70
+ [![Downloads](https://anaconda.org/conda-forge/bagofholding/badges/downloads.svg)](https://anaconda.org/conda-forge/bagofholding)
71
+
72
+ `bagofholding` is designed to be an easy stand-in for `pickle` serialization for python objects that is transparent, flexible, and suitable for long-term storage.
61
73
 
62
74
  ## Advantages
63
75
  ### Drop-in replacement
64
76
 
65
- `bagofholding` stores (almost) any `pickle`-able python object, and can be easily used as a drop-in replacement for `pickle` serialization:
77
+ `bagofholding` stores `pickle`-able python objects, and can be easily used as a drop-in replacement for `pickle` serialization:
66
78
 
67
79
  ```python
68
80
  >>> import bagofholding as boh
@@ -76,7 +88,7 @@ Description-Content-Type: text/markdown
76
88
 
77
89
  ### Browseable
78
90
 
79
- The contents of stored objects can be browsed without actually re-instantiating any of the stored data.
91
+ The contents of stored objects can be browsed without re-instantiating any of the stored data.
80
92
  In the example above, we saw that saving is a class-method, while loading is an instance method.
81
93
  We can grab the "bag" instance and use it to peek at what's inside!
82
94
 
@@ -130,53 +142,32 @@ With only `bagofholding` and `numpy` installed, the end user can browse through
130
142
 
131
143
  ### Version control
132
144
 
133
- In the examples above, we saw that version (and of course package) information is part of the stored metadata.
134
- This is useful post-facto for knowing what packages need to be installed to properly load your serialized data.
135
- You can also specify at load-time how strict or relaxed `bagofholding` should be in re-instantiating data if a stored version does not match the currently installed version, thus protecting you from flawed re-instantiations.
145
+ In the examples above, we saw that version (and of course package) information is part of the automatically-scraped and stored metadata.
146
+ This is useful post-facto for knowing what packages need to be installed to properly load your serialized data, and allows us to fail in clean and helpful ways if the loading environment does not match the saving environment.
147
+ You can also specify at load-time how strict or relaxed `bagofholding` should be in re-instantiating data if a stored version does not match the currently installed version, giving flexible protection from flawed re-instantiations.
136
148
 
137
149
  `bagofholding` also provides tools to act on this data a-priori.
138
150
  To increase the likelihood that stored data will be accessible in the future, you can outlaw any (sub)objects coming from particular modules:
139
151
 
140
152
  ```python
141
- import bagofholding.exception
142
- >> > try:
143
- ...
144
- boh.H5Bag.save(something, "will_fail.h5", forbidden_modules=("__main__",))
145
- ... except bagofholding.exception.ModuleForbiddenError as e:
146
- ...
147
- print(e)
148
- Module
149
- '__main__' is forbidden as a
150
- source
151
- of
152
- stored
153
- objects.Change
154
- the
155
- `forbidden_modules` or move
156
- this
157
- object
158
- to
159
- an
160
- allowed
161
- module.
153
+ import bagofholding as boh
154
+ >>> try:
155
+ ... boh.H5Bag.save(something, "will_fail.h5", forbidden_modules=("__main__",))
156
+ ... except boh.ModuleForbiddenError as e:
157
+ ... print(e)
158
+ Module '__main__' is forbidden as a source of stored objects. Change the `forbidden_modules` or move this object to an allowed module.
162
159
 
163
160
  ```
164
161
 
165
- And/or demand that all objects have an identifiable version that:
162
+ And/or demand that all objects have an identifiable version:
166
163
 
167
164
  ```python
168
- import bagofholding.exception
169
- >> > try:
170
- ...
171
- boh.H5Bag.save(something, "will_fail.h5", require_versions=True)
172
- ... except bagofholding.exception.NoVersionError as e:
173
- ...
174
- print(e)
175
- Could
176
- not find
177
- a
178
- version
179
- for __main__.Either disable `require_versions`, use `version_scraping` to find an existing version for this package, or add versioning to the unversioned package.
165
+ import bagofholding as boh
166
+ >>> try:
167
+ ... boh.H5Bag.save(something, "will_fail.h5", require_versions=True)
168
+ ... except boh.NoVersionError as e:
169
+ ... print(e)
170
+ Could not find a version for __main__. Either disable `require_versions`, use `version_scraping` to find an existing version for this package, or add versioning to the unversioned package.
180
171
 
181
172
  ```
182
173
 
@@ -195,8 +186,21 @@ H5Info(qualname='H5Bag', module='bagofholding.h5.bag', version='...', libver_str
195
186
 
196
187
  For a more in-depth look at the above features and to explore other aspects of `bagofholding`, check out [the tutorial notebook](../notebooks/tutorial.ipynb).
197
188
 
198
- Finally, `bagofholding` prioritizes transparency in what is stored and ease-of-use for both savers and loaders/browsers.
199
- As such, the current hdf5-based implementation is likely to be significantly less performant than raw pickling, due to the creation of many small datasets that allow the h5 file to directly replicate the underlying structure of the python objects being saved.
200
- For objects which contain large `numpy` arrays, this disadvantage is significantly alleviated as we benefit from the very efficient treatment of such arrays in hdf5 and `h5py`.
201
- For all other objects, the current `bagofholding.H5Bag` is still an appropriate choice when the robustness of long term storage is more pressing than optimizing storage space.
202
- Other bag types may be available in the future.
189
+
190
+ ## Object requirements
191
+
192
+ Under-the-hood, we follow the same patterns as `pickle` by explicitly invoking many of the same method (`__reduce__`, `__setstate__`, etc).
193
+ _Almost_ and object which can be pickled can be stored using `bagofholding`.
194
+ Our requirements are that the object...
195
+
196
+ - Must be pickleable
197
+ - You can use the `pickle_check` method on bag classes to quickly assess this
198
+ - Must not depend on `pickle` protocol >4
199
+ - Must have a valid boolean response to `hasattr` for each of the following, and they must conform to python and `abc.collections` norms if present:
200
+ - `__setstate__`
201
+ - `__setitem__`
202
+ - `append`
203
+ - `extend`
204
+ - Must have a valid boolean response to `hasattr` for `__metadata__`, and this attribute must be castable to a string if present
205
+
206
+ If your object satisfies these conditions and fails to "bag", please raise a bug report on the issues page!
@@ -19,7 +19,7 @@ from bagofholding.exceptions import NotAGroupError as NotAGroupError
19
19
  from bagofholding.exceptions import NoVersionError as NoVersionError
20
20
  from bagofholding.exceptions import PickleProtocolError as PickleProtocolError
21
21
  from bagofholding.exceptions import (
22
- StringReductionNotImportableError as StringReductionNotImportableError,
22
+ StringNotImportableError as StringNotImportableError,
23
23
  )
24
24
  from bagofholding.h5.bag import H5Bag as H5Bag
25
25
  from bagofholding.h5.triebag import TrieH5Bag as TrieH5Bag
@@ -17,5 +17,5 @@ __version__: str
17
17
  __version_tuple__: VERSION_TUPLE
18
18
  version_tuple: VERSION_TUPLE
19
19
 
20
- __version__ = version = '0.0.3'
21
- __version_tuple__ = version_tuple = (0, 0, 3)
20
+ __version__ = version = '0.1.1'
21
+ __version_tuple__ = version_tuple = (0, 1, 1)
@@ -35,6 +35,7 @@ from bagofholding.exceptions import (
35
35
  ModuleForbiddenError,
36
36
  NoVersionError,
37
37
  PickleProtocolError,
38
+ StringNotImportableError,
38
39
  )
39
40
  from bagofholding.metadata import (
40
41
  Metadata,
@@ -237,6 +238,15 @@ class Global(Item[GlobalType, Any, Packer]):
237
238
  value = "builtins." + obj if "." not in obj else obj
238
239
  else:
239
240
  value = obj.__module__ + "." + obj.__qualname__
241
+
242
+ if "<lambda>" in value:
243
+ raise StringNotImportableError(
244
+ f"Lambda functions are not re-importable, can't pack {obj}"
245
+ )
246
+ elif "<locals>" in value:
247
+ raise StringNotImportableError(
248
+ f"Local functions are not re-importable, can't pack {obj}"
249
+ )
240
250
  packer.pack_string(value, path)
241
251
 
242
252
  @classmethod
@@ -41,4 +41,4 @@ class NoVersionError(BagOfHoldingError, ValueError): ...
41
41
  class PickleProtocolError(BagOfHoldingError, ValueError): ...
42
42
 
43
43
 
44
- class StringReductionNotImportableError(BagOfHoldingError): ...
44
+ class StringNotImportableError(BagOfHoldingError): ...
@@ -7,7 +7,7 @@ from __future__ import annotations
7
7
  from importlib import import_module
8
8
  from typing import Any
9
9
 
10
- from bagofholding.exceptions import StringReductionNotImportableError
10
+ from bagofholding.exceptions import StringNotImportableError
11
11
 
12
12
 
13
13
  def import_from_string(library_path: str) -> Any:
@@ -44,7 +44,7 @@ def get_importable_string_from_string_reduction(
44
44
  try:
45
45
  import_from_string(importable)
46
46
  except (ModuleNotFoundError, AttributeError) as e:
47
- raise StringReductionNotImportableError(
47
+ raise StringNotImportableError(
48
48
  f"Couldn't import {string_reduction} after scoping it as {importable}. "
49
49
  f"Please contact the developers so we can figure out how to handle "
50
50
  f"this edge case."
@@ -1,11 +1,14 @@
1
1
  import random
2
- from typing import cast
2
+ from typing import TypeVar, cast
3
3
 
4
4
  import numpy as np
5
5
  import pygtrie
6
6
 
7
+ ValueType = TypeVar("ValueType") # python <3.12 compatibility
8
+ # def not_allowed_to_have_inline[FunctionGenerics](in_python=3.12):
7
9
 
8
- def decompose_stringtrie[ValueType](
10
+
11
+ def decompose_stringtrie(
9
12
  trie: pygtrie.StringTrie, null_value: ValueType
10
13
  ) -> tuple[list[str], list[int], list[ValueType]]:
11
14
  """
@@ -63,7 +66,7 @@ def decompose_stringtrie[ValueType](
63
66
  return segments, parents, values
64
67
 
65
68
 
66
- def reconstruct_stringtrie[ValueType](
69
+ def reconstruct_stringtrie(
67
70
  segments: list[str],
68
71
  parents: list[int],
69
72
  values: list[ValueType],
@@ -19,7 +19,7 @@ from bagofholding.exceptions import NotAGroupError as NotAGroupError
19
19
  from bagofholding.exceptions import NoVersionError as NoVersionError
20
20
  from bagofholding.exceptions import PickleProtocolError as PickleProtocolError
21
21
  from bagofholding.exceptions import (
22
- StringReductionNotImportableError as StringReductionNotImportableError,
22
+ StringNotImportableError as StringNotImportableError,
23
23
  )
24
24
  from bagofholding.h5.bag import H5Bag as H5Bag
25
25
  from bagofholding.h5.triebag import TrieH5Bag as TrieH5Bag
@@ -17,5 +17,5 @@ __version__: str
17
17
  __version_tuple__: VERSION_TUPLE
18
18
  version_tuple: VERSION_TUPLE
19
19
 
20
- __version__ = version = '0.0.3'
21
- __version_tuple__ = version_tuple = (0, 0, 3)
20
+ __version__ = version = '0.1.1'
21
+ __version_tuple__ = version_tuple = (0, 1, 1)
@@ -35,6 +35,7 @@ from bagofholding.exceptions import (
35
35
  ModuleForbiddenError,
36
36
  NoVersionError,
37
37
  PickleProtocolError,
38
+ StringNotImportableError,
38
39
  )
39
40
  from bagofholding.metadata import (
40
41
  Metadata,
@@ -237,6 +238,15 @@ class Global(Item[GlobalType, Any, Packer]):
237
238
  value = "builtins." + obj if "." not in obj else obj
238
239
  else:
239
240
  value = obj.__module__ + "." + obj.__qualname__
241
+
242
+ if "<lambda>" in value:
243
+ raise StringNotImportableError(
244
+ f"Lambda functions are not re-importable, can't pack {obj}"
245
+ )
246
+ elif "<locals>" in value:
247
+ raise StringNotImportableError(
248
+ f"Local functions are not re-importable, can't pack {obj}"
249
+ )
240
250
  packer.pack_string(value, path)
241
251
 
242
252
  @classmethod
@@ -41,4 +41,4 @@ class NoVersionError(BagOfHoldingError, ValueError): ...
41
41
  class PickleProtocolError(BagOfHoldingError, ValueError): ...
42
42
 
43
43
 
44
- class StringReductionNotImportableError(BagOfHoldingError): ...
44
+ class StringNotImportableError(BagOfHoldingError): ...
@@ -7,7 +7,7 @@ from __future__ import annotations
7
7
  from importlib import import_module
8
8
  from typing import Any
9
9
 
10
- from bagofholding.exceptions import StringReductionNotImportableError
10
+ from bagofholding.exceptions import StringNotImportableError
11
11
 
12
12
 
13
13
  def import_from_string(library_path: str) -> Any:
@@ -44,7 +44,7 @@ def get_importable_string_from_string_reduction(
44
44
  try:
45
45
  import_from_string(importable)
46
46
  except (ModuleNotFoundError, AttributeError) as e:
47
- raise StringReductionNotImportableError(
47
+ raise StringNotImportableError(
48
48
  f"Couldn't import {string_reduction} after scoping it as {importable}. "
49
49
  f"Please contact the developers so we can figure out how to handle "
50
50
  f"this edge case."
@@ -1,11 +1,14 @@
1
1
  import random
2
- from typing import cast
2
+ from typing import TypeVar, cast
3
3
 
4
4
  import numpy as np
5
5
  import pygtrie
6
6
 
7
+ ValueType = TypeVar("ValueType") # python <3.12 compatibility
8
+ # def not_allowed_to_have_inline[FunctionGenerics](in_python=3.12):
7
9
 
8
- def decompose_stringtrie[ValueType](
10
+
11
+ def decompose_stringtrie(
9
12
  trie: pygtrie.StringTrie, null_value: ValueType
10
13
  ) -> tuple[list[str], list[int], list[ValueType]]:
11
14
  """
@@ -63,7 +66,7 @@ def decompose_stringtrie[ValueType](
63
66
  return segments, parents, values
64
67
 
65
68
 
66
- def reconstruct_stringtrie[ValueType](
69
+ def reconstruct_stringtrie(
67
70
  segments: list[str],
68
71
  parents: list[int],
69
72
  values: list[ValueType],
@@ -1,11 +1,23 @@
1
1
  # bagofholding
2
2
 
3
- `bagofholding` is designed to be an easy stand-in for `pickle` serialization for python object that is transparent, flexible, and suitable for long-term storage.
3
+ <img src="_static/bagofholding_logo.png" alt="Logo" width="190"/>
4
+
5
+ [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/pyiron/bagofholding/HEAD)
6
+ [![License](https://img.shields.io/badge/License-BSD_3--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause)
7
+ [![Coverage](https://codecov.io/gh/pyiron/bagofholding/graph/badge.svg)](https://codecov.io/gh/pyiron/bagofholding)
8
+ [![Documentation](https://readthedocs.org/projects/bagofholding/badge/?version=latest)](https://bagofholding.readthedocs.io/en/latest/?badge=latest)
9
+
10
+ [![Anaconda](https://anaconda.org/conda-forge/bagofholding/badges/version.svg)](https://anaconda.org/conda-forge/bagofholding)
11
+ [![Last Updated](https://anaconda.org/conda-forge/bagofholding/badges/latest_release_date.svg)](https://anaconda.org/conda-forge/bagofholding)
12
+ [![Platform](https://anaconda.org/conda-forge/bagofholding/badges/platforms.svg)](https://anaconda.org/conda-forge/bagofholding)
13
+ [![Downloads](https://anaconda.org/conda-forge/bagofholding/badges/downloads.svg)](https://anaconda.org/conda-forge/bagofholding)
14
+
15
+ `bagofholding` is designed to be an easy stand-in for `pickle` serialization for python objects that is transparent, flexible, and suitable for long-term storage.
4
16
 
5
17
  ## Advantages
6
18
  ### Drop-in replacement
7
19
 
8
- `bagofholding` stores (almost) any `pickle`-able python object, and can be easily used as a drop-in replacement for `pickle` serialization:
20
+ `bagofholding` stores `pickle`-able python objects, and can be easily used as a drop-in replacement for `pickle` serialization:
9
21
 
10
22
  ```python
11
23
  >>> import bagofholding as boh
@@ -19,7 +31,7 @@
19
31
 
20
32
  ### Browseable
21
33
 
22
- The contents of stored objects can be browsed without actually re-instantiating any of the stored data.
34
+ The contents of stored objects can be browsed without re-instantiating any of the stored data.
23
35
  In the example above, we saw that saving is a class-method, while loading is an instance method.
24
36
  We can grab the "bag" instance and use it to peek at what's inside!
25
37
 
@@ -73,53 +85,32 @@ With only `bagofholding` and `numpy` installed, the end user can browse through
73
85
 
74
86
  ### Version control
75
87
 
76
- In the examples above, we saw that version (and of course package) information is part of the stored metadata.
77
- This is useful post-facto for knowing what packages need to be installed to properly load your serialized data.
78
- You can also specify at load-time how strict or relaxed `bagofholding` should be in re-instantiating data if a stored version does not match the currently installed version, thus protecting you from flawed re-instantiations.
88
+ In the examples above, we saw that version (and of course package) information is part of the automatically-scraped and stored metadata.
89
+ This is useful post-facto for knowing what packages need to be installed to properly load your serialized data, and allows us to fail in clean and helpful ways if the loading environment does not match the saving environment.
90
+ You can also specify at load-time how strict or relaxed `bagofholding` should be in re-instantiating data if a stored version does not match the currently installed version, giving flexible protection from flawed re-instantiations.
79
91
 
80
92
  `bagofholding` also provides tools to act on this data a-priori.
81
93
  To increase the likelihood that stored data will be accessible in the future, you can outlaw any (sub)objects coming from particular modules:
82
94
 
83
95
  ```python
84
- import bagofholding.exception
85
- >> > try:
86
- ...
87
- boh.H5Bag.save(something, "will_fail.h5", forbidden_modules=("__main__",))
88
- ... except bagofholding.exception.ModuleForbiddenError as e:
89
- ...
90
- print(e)
91
- Module
92
- '__main__' is forbidden as a
93
- source
94
- of
95
- stored
96
- objects.Change
97
- the
98
- `forbidden_modules` or move
99
- this
100
- object
101
- to
102
- an
103
- allowed
104
- module.
96
+ import bagofholding as boh
97
+ >>> try:
98
+ ... boh.H5Bag.save(something, "will_fail.h5", forbidden_modules=("__main__",))
99
+ ... except boh.ModuleForbiddenError as e:
100
+ ... print(e)
101
+ Module '__main__' is forbidden as a source of stored objects. Change the `forbidden_modules` or move this object to an allowed module.
105
102
 
106
103
  ```
107
104
 
108
- And/or demand that all objects have an identifiable version that:
105
+ And/or demand that all objects have an identifiable version:
109
106
 
110
107
  ```python
111
- import bagofholding.exception
112
- >> > try:
113
- ...
114
- boh.H5Bag.save(something, "will_fail.h5", require_versions=True)
115
- ... except bagofholding.exception.NoVersionError as e:
116
- ...
117
- print(e)
118
- Could
119
- not find
120
- a
121
- version
122
- for __main__.Either disable `require_versions`, use `version_scraping` to find an existing version for this package, or add versioning to the unversioned package.
108
+ import bagofholding as boh
109
+ >>> try:
110
+ ... boh.H5Bag.save(something, "will_fail.h5", require_versions=True)
111
+ ... except boh.NoVersionError as e:
112
+ ... print(e)
113
+ Could not find a version for __main__. Either disable `require_versions`, use `version_scraping` to find an existing version for this package, or add versioning to the unversioned package.
123
114
 
124
115
  ```
125
116
 
@@ -138,8 +129,21 @@ H5Info(qualname='H5Bag', module='bagofholding.h5.bag', version='...', libver_str
138
129
 
139
130
  For a more in-depth look at the above features and to explore other aspects of `bagofholding`, check out [the tutorial notebook](../notebooks/tutorial.ipynb).
140
131
 
141
- Finally, `bagofholding` prioritizes transparency in what is stored and ease-of-use for both savers and loaders/browsers.
142
- As such, the current hdf5-based implementation is likely to be significantly less performant than raw pickling, due to the creation of many small datasets that allow the h5 file to directly replicate the underlying structure of the python objects being saved.
143
- For objects which contain large `numpy` arrays, this disadvantage is significantly alleviated as we benefit from the very efficient treatment of such arrays in hdf5 and `h5py`.
144
- For all other objects, the current `bagofholding.H5Bag` is still an appropriate choice when the robustness of long term storage is more pressing than optimizing storage space.
145
- Other bag types may be available in the future.
132
+
133
+ ## Object requirements
134
+
135
+ Under-the-hood, we follow the same patterns as `pickle` by explicitly invoking many of the same method (`__reduce__`, `__setstate__`, etc).
136
+ _Almost_ and object which can be pickled can be stored using `bagofholding`.
137
+ Our requirements are that the object...
138
+
139
+ - Must be pickleable
140
+ - You can use the `pickle_check` method on bag classes to quickly assess this
141
+ - Must not depend on `pickle` protocol >4
142
+ - Must have a valid boolean response to `hasattr` for each of the following, and they must conform to python and `abc.collections` norms if present:
143
+ - `__setstate__`
144
+ - `__setitem__`
145
+ - `append`
146
+ - `extend`
147
+ - Must have a valid boolean response to `hasattr` for `__metadata__`, and this attribute must be castable to a string if present
148
+
149
+ If your object satisfies these conditions and fails to "bag", please raise a bug report on the issues page!
@@ -7,9 +7,9 @@ name = "bagofholding"
7
7
  description = "bagofholding - browsable, partially-reloadable serialization for pickleable python objects."
8
8
  readme = "docs/README.md"
9
9
  keywords = [ "pyiron",]
10
- requires-python = ">=3.12, <3.14"
11
- classifiers = [ "Development Status :: 3 - Alpha", "Topic :: Scientific/Engineering", "License :: OSI Approved :: BSD License", "Intended Audience :: Science/Research", "Operating System :: OS Independent", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13",]
12
- dependencies = [ "bidict==0.23.1", "h5py>=3.14.0,<3.15.0", "mpi4py>=4.0.1,<4.1.0", "numpy>=2.3.0,<2.4.0", "pygtrie>=2.5.0,<2.6.0", "pyiron_snippets==0.2.0",]
10
+ requires-python = ">=3.11, <3.14"
11
+ classifiers = [ "Development Status :: 4 - Beta", "Topic :: Scientific/Engineering", "License :: OSI Approved :: BSD License", "Intended Audience :: Science/Research", "Operating System :: OS Independent", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13",]
12
+ dependencies = [ "bidict==0.23.1", "h5py>=3.14.0,<3.15.0", "mpi4py>=4.1.0,<4.2.0", "numpy>=2.3.1,<2.4.0", "pygtrie>=2.5.0,<2.6.0", "pyiron_snippets==0.2.0",]
13
13
  dynamic = [ "version",]
14
14
  [[project.authors]]
15
15
  name = "Liam Huber"
File without changes
File without changes