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.
- {pelutils-3.8.3 → pelutils-3.8.5}/PKG-INFO +12 -11
- {pelutils-3.8.3 → pelutils-3.8.5}/README.md +11 -10
- {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/__init__.py +0 -1
- {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/__version__.py +1 -1
- {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/datastorage2/__init__.py +16 -5
- {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/datastorage2/_pretty_json.py +11 -0
- {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/types.py +2 -0
- {pelutils-3.8.3 → pelutils-3.8.5}/pelutils.egg-info/PKG-INFO +12 -11
- {pelutils-3.8.3 → pelutils-3.8.5}/tests/test_types.py +8 -4
- {pelutils-3.8.3 → pelutils-3.8.5}/MANIFEST.in +0 -0
- {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/_c/__init__.py +0 -0
- {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/_c/ds.c +0 -0
- {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/_c/hashmap.c/LICENSE +0 -0
- {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/_c/hashmap.c/hashmap.c +0 -0
- {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/_c/hashmap.c/hashmap.h +0 -0
- {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/_entry_points/__init__.py +0 -0
- {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/_entry_points/linecounter.py +0 -0
- {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/datastorage.py +0 -0
- {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/ds/__init__.py +0 -0
- {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/ds/distributions.py +0 -0
- {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/ds/plots.py +0 -0
- {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/ds/stats.py +0 -0
- {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/format.py +0 -0
- {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/jsonl.py +0 -0
- {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/logging/__init__.py +0 -0
- {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/logging/_rotate.py +0 -0
- {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/logging/_utils.py +0 -0
- {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/parser.py +0 -0
- {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/pretty_json.py +0 -0
- {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/py.typed +0 -0
- {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/tests.py +0 -0
- {pelutils-3.8.3 → pelutils-3.8.5}/pelutils/ticktock.py +0 -0
- {pelutils-3.8.3 → pelutils-3.8.5}/pelutils.egg-info/SOURCES.txt +0 -0
- {pelutils-3.8.3 → pelutils-3.8.5}/pelutils.egg-info/dependency_links.txt +0 -0
- {pelutils-3.8.3 → pelutils-3.8.5}/pelutils.egg-info/entry_points.txt +0 -0
- {pelutils-3.8.3 → pelutils-3.8.5}/pelutils.egg-info/requires.txt +0 -0
- {pelutils-3.8.3 → pelutils-3.8.5}/pelutils.egg-info/top_level.txt +0 -0
- {pelutils-3.8.3 → pelutils-3.8.5}/setup.cfg +0 -0
- {pelutils-3.8.3 → pelutils-3.8.5}/setup.py +0 -0
- {pelutils-3.8.3 → pelutils-3.8.5}/tests/test_datastorage.py +0 -0
- {pelutils-3.8.3 → pelutils-3.8.5}/tests/test_format.py +0 -0
- {pelutils-3.8.3 → pelutils-3.8.5}/tests/test_init.py +0 -0
- {pelutils-3.8.3 → pelutils-3.8.5}/tests/test_jsonl.py +0 -0
- {pelutils-3.8.3 → pelutils-3.8.5}/tests/test_parser.py +0 -0
- {pelutils-3.8.3 → pelutils-3.8.5}/tests/test_pretty_json.py +0 -0
- {pelutils-3.8.3 → pelutils-3.8.5}/tests/test_tests.py +0 -0
- {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
|
+
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`
|
|
94
|
-
It
|
|
95
|
-
|
|
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
|
-
|
|
101
|
-
|
|
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`
|
|
69
|
-
It
|
|
70
|
-
|
|
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
|
-
|
|
76
|
-
|
|
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(
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
# Do not put anything else in this file
|
|
2
|
-
__version__ = "3.8.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
+
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`
|
|
94
|
-
It
|
|
95
|
-
|
|
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
|
-
|
|
101
|
-
|
|
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
|
|
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
|
-
) ->
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|