pelutils 3.8.3__tar.gz → 3.8.5__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 (47) hide show
  1. {pelutils-3.8.3 → pelutils-3.8.5}/PKG-INFO +12 -11
  2. {pelutils-3.8.3 → pelutils-3.8.5}/README.md +11 -10
  3. {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/__init__.py +0 -1
  4. {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/__version__.py +1 -1
  5. {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/datastorage2/__init__.py +16 -5
  6. {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/datastorage2/_pretty_json.py +11 -0
  7. {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/types.py +2 -0
  8. {pelutils-3.8.3 → pelutils-3.8.5}/pelutils.egg-info/PKG-INFO +12 -11
  9. {pelutils-3.8.3 → pelutils-3.8.5}/tests/test_types.py +8 -4
  10. {pelutils-3.8.3 → pelutils-3.8.5}/MANIFEST.in +0 -0
  11. {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/_c/__init__.py +0 -0
  12. {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/_c/ds.c +0 -0
  13. {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/_c/hashmap.c/LICENSE +0 -0
  14. {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/_c/hashmap.c/hashmap.c +0 -0
  15. {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/_c/hashmap.c/hashmap.h +0 -0
  16. {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/_entry_points/__init__.py +0 -0
  17. {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/_entry_points/linecounter.py +0 -0
  18. {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/datastorage.py +0 -0
  19. {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/ds/__init__.py +0 -0
  20. {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/ds/distributions.py +0 -0
  21. {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/ds/plots.py +0 -0
  22. {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/ds/stats.py +0 -0
  23. {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/format.py +0 -0
  24. {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/jsonl.py +0 -0
  25. {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/logging/__init__.py +0 -0
  26. {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/logging/_rotate.py +0 -0
  27. {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/logging/_utils.py +0 -0
  28. {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/parser.py +0 -0
  29. {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/pretty_json.py +0 -0
  30. {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/py.typed +0 -0
  31. {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/tests.py +0 -0
  32. {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/ticktock.py +0 -0
  33. {pelutils-3.8.3 → pelutils-3.8.5}/pelutils.egg-info/SOURCES.txt +0 -0
  34. {pelutils-3.8.3 → pelutils-3.8.5}/pelutils.egg-info/dependency_links.txt +0 -0
  35. {pelutils-3.8.3 → pelutils-3.8.5}/pelutils.egg-info/entry_points.txt +0 -0
  36. {pelutils-3.8.3 → pelutils-3.8.5}/pelutils.egg-info/requires.txt +0 -0
  37. {pelutils-3.8.3 → pelutils-3.8.5}/pelutils.egg-info/top_level.txt +0 -0
  38. {pelutils-3.8.3 → pelutils-3.8.5}/setup.cfg +0 -0
  39. {pelutils-3.8.3 → pelutils-3.8.5}/setup.py +0 -0
  40. {pelutils-3.8.3 → pelutils-3.8.5}/tests/test_datastorage.py +0 -0
  41. {pelutils-3.8.3 → pelutils-3.8.5}/tests/test_format.py +0 -0
  42. {pelutils-3.8.3 → pelutils-3.8.5}/tests/test_init.py +0 -0
  43. {pelutils-3.8.3 → pelutils-3.8.5}/tests/test_jsonl.py +0 -0
  44. {pelutils-3.8.3 → pelutils-3.8.5}/tests/test_parser.py +0 -0
  45. {pelutils-3.8.3 → pelutils-3.8.5}/tests/test_pretty_json.py +0 -0
  46. {pelutils-3.8.3 → pelutils-3.8.5}/tests/test_tests.py +0 -0
  47. {pelutils-3.8.3 → pelutils-3.8.5}/tests/test_ticktock.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pelutils
3
- Version: 3.8.3
3
+ Version: 3.8.5
4
4
  Summary: The Swiss army knife of Python projects.
5
5
  Home-page: https://github.com/peleiden/pelutils
6
6
  Download-URL: https://pypi.org/project/pelutils/
@@ -90,15 +90,17 @@ while True:
90
90
 
91
91
  ## Data Serialisation
92
92
 
93
- The `DataStorage2` class is an extension of `pydantic.BaseModel` that incluces save and load functionality.
94
- It supports any data type, storing all data to a pretty JSON file. A class should simply inherit from
95
- `DataStorage2`. The stored JSON will be a dictionary-like structure with the whole nested structure.
96
- Any nested `BaseModel` is automatically converted to a dictionary. If a data type is reached which is not
97
- JSON serialisable (e.g. normal classes, pandas DataFramas, numpy arrays), they are encoded with `pickle`
98
- and `base64`. Inside the JSON file, a record is kept of the original type.
93
+ The `DataStorage2` class is an extension of `pydantic.BaseModel` which adds convenient `safe` and `load` methods for trivial saving to and loading from JSON files.
94
+ It can serialise *any* attribute on the model to JSON by pickling types which `pydantic` cannot natively serialise.
95
+ To get use it, simply inherit from `DataStorage2`, like you would inherit from `BaseModel`.
99
96
 
100
- Very long lists utilise the full allowed line length before splitting, preventing the common JSON issue of
101
- having either very long lines (no indents) or excessively many lines with a single element on each.
97
+ The produced JSON files take advantage of `pelutils.pretty_json(...)` to ensure good and human-readable formatting, almost no matter the data types.
98
+ Very long lists utilise the full allowed line length before splitting.
99
+ This prevents the common JSON issue of having either very long lines (no indents) or excessively many lines with a single, small element on each.
100
+
101
+ It is possible to get only the serialised JSON objects as dicts instead of saving them directly to a file with the `DataStorage2.model_safe_dump()` method.
102
+ This is practical if you want to nest the objects into another dict or list.
103
+ `DataStorage2.model_safe_load(...)` does the inverse operation by creating a class instance from a JSON-serialised dict.
102
104
 
103
105
  Because the class inherits from `pydantic.BaseModel`, type checking is built directly into it.
104
106
 
@@ -154,7 +156,6 @@ This will produce `directory/to/save/in/BasedClass.json` with the following cont
154
156
  "baseder": {"based_string": "Hello there"}
155
157
  }
156
158
  ```
157
- The class is built on top of the also provided `pretty_json` which does the exact same as the built-in `json.dumps` but with prettier formatting of the JSON string.
158
159
 
159
160
  ## Config and Command-line Argument Parsing
160
161
 
@@ -274,7 +275,7 @@ log2.configure("path/to/save/log2.log")
274
275
 
275
276
  A few different numpy types are defined for the convenience of not having to remember what data types your arrays are - and also to satisfy your nasty type checkers.
276
277
  ```py
277
- from pelutils.types import AnyArray, FloatArray, IntArray
278
+ from pelutils.types import AnyArray, BoolArray, ComplexArray, FloatArray, IntArray
278
279
 
279
280
 
280
281
  def function_which_takes_np_types(
@@ -65,15 +65,17 @@ while True:
65
65
 
66
66
  ## Data Serialisation
67
67
 
68
- The `DataStorage2` class is an extension of `pydantic.BaseModel` that incluces save and load functionality.
69
- It supports any data type, storing all data to a pretty JSON file. A class should simply inherit from
70
- `DataStorage2`. The stored JSON will be a dictionary-like structure with the whole nested structure.
71
- Any nested `BaseModel` is automatically converted to a dictionary. If a data type is reached which is not
72
- JSON serialisable (e.g. normal classes, pandas DataFramas, numpy arrays), they are encoded with `pickle`
73
- and `base64`. Inside the JSON file, a record is kept of the original type.
68
+ The `DataStorage2` class is an extension of `pydantic.BaseModel` which adds convenient `safe` and `load` methods for trivial saving to and loading from JSON files.
69
+ It can serialise *any* attribute on the model to JSON by pickling types which `pydantic` cannot natively serialise.
70
+ To get use it, simply inherit from `DataStorage2`, like you would inherit from `BaseModel`.
74
71
 
75
- Very long lists utilise the full allowed line length before splitting, preventing the common JSON issue of
76
- having either very long lines (no indents) or excessively many lines with a single element on each.
72
+ The produced JSON files take advantage of `pelutils.pretty_json(...)` to ensure good and human-readable formatting, almost no matter the data types.
73
+ Very long lists utilise the full allowed line length before splitting.
74
+ This prevents the common JSON issue of having either very long lines (no indents) or excessively many lines with a single, small element on each.
75
+
76
+ It is possible to get only the serialised JSON objects as dicts instead of saving them directly to a file with the `DataStorage2.model_safe_dump()` method.
77
+ This is practical if you want to nest the objects into another dict or list.
78
+ `DataStorage2.model_safe_load(...)` does the inverse operation by creating a class instance from a JSON-serialised dict.
77
79
 
78
80
  Because the class inherits from `pydantic.BaseModel`, type checking is built directly into it.
79
81
 
@@ -129,7 +131,6 @@ This will produce `directory/to/save/in/BasedClass.json` with the following cont
129
131
  "baseder": {"based_string": "Hello there"}
130
132
  }
131
133
  ```
132
- The class is built on top of the also provided `pretty_json` which does the exact same as the built-in `json.dumps` but with prettier formatting of the JSON string.
133
134
 
134
135
  ## Config and Command-line Argument Parsing
135
136
 
@@ -249,7 +250,7 @@ log2.configure("path/to/save/log2.log")
249
250
 
250
251
  A few different numpy types are defined for the convenience of not having to remember what data types your arrays are - and also to satisfy your nasty type checkers.
251
252
  ```py
252
- from pelutils.types import AnyArray, FloatArray, IntArray
253
+ from pelutils.types import AnyArray, BoolArray, ComplexArray, FloatArray, IntArray
253
254
 
254
255
 
255
256
  def function_which_takes_np_types(
@@ -24,7 +24,6 @@ import numpy as np
24
24
  import psutil
25
25
 
26
26
  try:
27
- # torch is only to be installed if pelutils[ds] has been installed
28
27
  import torch
29
28
 
30
29
  _has_torch = True
@@ -1,2 +1,2 @@
1
1
  # Do not put anything else in this file
2
- __version__ = "3.8.3"
2
+ __version__ = "3.8.5"
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import json
4
4
  from pathlib import Path
5
- from typing import TypeVar
5
+ from typing import Any, TypeVar
6
6
 
7
7
  from pydantic import BaseModel, ConfigDict
8
8
 
@@ -24,6 +24,19 @@ class DataStorage2(BaseModel):
24
24
 
25
25
  model_config = ConfigDict(arbitrary_types_allowed=True)
26
26
 
27
+ def model_safe_dump(self) -> dict[str, Any]: # pyright: ignore[reportExplicitAny]
28
+ """Dump the model as a dictionary where pickled objects have been converted to b64 strings.
29
+
30
+ This is very similar to `self.model_dump(mode="json")` but it handles non-JSON-serialisable types.
31
+ """
32
+ return self.model_dump(mode="json", fallback=_pickle_encode)
33
+
34
+ @classmethod
35
+ def model_safe_load(cls: type[_T], safe_json: dict[str, Any]) -> _T: # pyright: ignore[reportExplicitAny]
36
+ """Build an instance from a safe JSON. This method is the inverse of `model_safe_dump`."""
37
+ self_dict = _make_json_unsafe(safe_json)
38
+ return cls.model_validate(self_dict)
39
+
27
40
  @classmethod
28
41
  def _resolve_save_file(cls, directory: str | Path, filename: str | None = None) -> Path:
29
42
  if filename is None:
@@ -39,10 +52,9 @@ class DataStorage2(BaseModel):
39
52
  """
40
53
  savepath = self._resolve_save_file(directory, filename)
41
54
  savepath.parent.mkdir(parents=True, exist_ok=True)
42
- self_dict = self.model_dump(mode="json", fallback=_pickle_encode)
43
55
  savepath.write_text(
44
56
  _pretty_json(
45
- self_dict,
57
+ self.model_safe_dump(),
46
58
  max_line_length=max_line_length,
47
59
  indent=indent,
48
60
  # Safe should not be needed here, as the fallback function in model_dump should ensure no issues
@@ -59,5 +71,4 @@ class DataStorage2(BaseModel):
59
71
  savepath = cls._resolve_save_file(directory, filename)
60
72
  with savepath.open(encoding=encoding) as f:
61
73
  self_dict = json.load(f)
62
- self_dict = _make_json_unsafe(self_dict)
63
- return cls.model_validate(self_dict)
74
+ return cls.model_safe_load(self_dict)
@@ -9,6 +9,13 @@ import json
9
9
  import pickle
10
10
  from typing import Any
11
11
 
12
+ try:
13
+ import torch
14
+
15
+ _has_torch = True
16
+ except ModuleNotFoundError:
17
+ _has_torch = False
18
+
12
19
  # Sentinel prefix so consumers can detect pickled blobs.
13
20
  _PICKLE_PREFIX = "__pickled_b64__"
14
21
 
@@ -45,6 +52,10 @@ def _get_qualified_type_name(obj: object) -> str:
45
52
 
46
53
  def _pickle_encode(value: object) -> str:
47
54
  """Pickle *value*, base64-encode the bytes, and return a prefixed string."""
55
+ if _has_torch and isinstance(value, torch.Tensor): # pyright: ignore[reportPossiblyUnboundVariable]
56
+ # If a view of torch Tensor is given, the whole tensor is pickled, not just the view
57
+ # Therefore, it is cloned first to ensure that only the view itself is pickled
58
+ value = value.clone()
48
59
  raw = pickle.dumps(value, protocol=pickle.HIGHEST_PROTOCOL)
49
60
  encoded = base64.b64encode(raw).decode("ascii")
50
61
  return f"{_PICKLE_PREFIX}:{_get_qualified_type_name(value)}:{encoded}"
@@ -5,5 +5,7 @@ import numpy.typing as npt
5
5
 
6
6
  # Common numpy types
7
7
  AnyArray = npt.NDArray[Any] # pyright: ignore[reportExplicitAny]
8
+ BoolArray = npt.NDArray[np.bool_]
9
+ ComplexArray = npt.NDArray[np.complexfloating[Any]] # pyright: ignore[reportExplicitAny, reportInvalidTypeArguments]
8
10
  FloatArray = npt.NDArray[np.floating[Any]] # pyright: ignore[reportExplicitAny]
9
11
  IntArray = npt.NDArray[np.integer[Any]] # pyright: ignore[reportExplicitAny]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pelutils
3
- Version: 3.8.3
3
+ Version: 3.8.5
4
4
  Summary: The Swiss army knife of Python projects.
5
5
  Home-page: https://github.com/peleiden/pelutils
6
6
  Download-URL: https://pypi.org/project/pelutils/
@@ -90,15 +90,17 @@ while True:
90
90
 
91
91
  ## Data Serialisation
92
92
 
93
- The `DataStorage2` class is an extension of `pydantic.BaseModel` that incluces save and load functionality.
94
- It supports any data type, storing all data to a pretty JSON file. A class should simply inherit from
95
- `DataStorage2`. The stored JSON will be a dictionary-like structure with the whole nested structure.
96
- Any nested `BaseModel` is automatically converted to a dictionary. If a data type is reached which is not
97
- JSON serialisable (e.g. normal classes, pandas DataFramas, numpy arrays), they are encoded with `pickle`
98
- and `base64`. Inside the JSON file, a record is kept of the original type.
93
+ The `DataStorage2` class is an extension of `pydantic.BaseModel` which adds convenient `safe` and `load` methods for trivial saving to and loading from JSON files.
94
+ It can serialise *any* attribute on the model to JSON by pickling types which `pydantic` cannot natively serialise.
95
+ To get use it, simply inherit from `DataStorage2`, like you would inherit from `BaseModel`.
99
96
 
100
- Very long lists utilise the full allowed line length before splitting, preventing the common JSON issue of
101
- having either very long lines (no indents) or excessively many lines with a single element on each.
97
+ The produced JSON files take advantage of `pelutils.pretty_json(...)` to ensure good and human-readable formatting, almost no matter the data types.
98
+ Very long lists utilise the full allowed line length before splitting.
99
+ This prevents the common JSON issue of having either very long lines (no indents) or excessively many lines with a single, small element on each.
100
+
101
+ It is possible to get only the serialised JSON objects as dicts instead of saving them directly to a file with the `DataStorage2.model_safe_dump()` method.
102
+ This is practical if you want to nest the objects into another dict or list.
103
+ `DataStorage2.model_safe_load(...)` does the inverse operation by creating a class instance from a JSON-serialised dict.
102
104
 
103
105
  Because the class inherits from `pydantic.BaseModel`, type checking is built directly into it.
104
106
 
@@ -154,7 +156,6 @@ This will produce `directory/to/save/in/BasedClass.json` with the following cont
154
156
  "baseder": {"based_string": "Hello there"}
155
157
  }
156
158
  ```
157
- The class is built on top of the also provided `pretty_json` which does the exact same as the built-in `json.dumps` but with prettier formatting of the JSON string.
158
159
 
159
160
  ## Config and Command-line Argument Parsing
160
161
 
@@ -274,7 +275,7 @@ log2.configure("path/to/save/log2.log")
274
275
 
275
276
  A few different numpy types are defined for the convenience of not having to remember what data types your arrays are - and also to satisfy your nasty type checkers.
276
277
  ```py
277
- from pelutils.types import AnyArray, FloatArray, IntArray
278
+ from pelutils.types import AnyArray, BoolArray, ComplexArray, FloatArray, IntArray
278
279
 
279
280
 
280
281
  def function_which_takes_np_types(
@@ -1,14 +1,16 @@
1
1
  import numpy as np
2
2
 
3
- from pelutils.types import AnyArray, FloatArray, IntArray
3
+ from pelutils import AnyArray, BoolArray, ComplexArray, FloatArray, IntArray
4
4
 
5
5
 
6
6
  def function_which_takes_np_types(
7
7
  any_array: AnyArray,
8
+ bool_array: BoolArray,
9
+ complex_array: ComplexArray,
8
10
  float_array: FloatArray,
9
11
  int_array: IntArray,
10
- ) -> FloatArray:
11
- return any_array + float_array + int_array
12
+ ) -> ComplexArray:
13
+ return any_array + bool_array + complex_array + float_array + int_array
12
14
 
13
15
 
14
16
  def test_types():
@@ -17,6 +19,8 @@ def test_types():
17
19
  Just make sure that using the types doesn't break anything silly like function declarations.
18
20
  """
19
21
  any_array = np.arange(5, dtype=np.float16)
22
+ bool_array = np.arange(5).astype(bool)
23
+ complex_array = 1j * np.arange(5)
20
24
  float_array = np.arange(5, dtype=np.float32)
21
25
  int_array = np.arange(5)
22
- function_which_takes_np_types(any_array, float_array, int_array)
26
+ function_which_takes_np_types(any_array, bool_array, complex_array, float_array, int_array)
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes