pelutils 3.8.4__tar.gz → 3.9.0__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.4 → pelutils-3.9.0}/PKG-INFO +2 -2
- {pelutils-3.8.4 → pelutils-3.9.0}/README.md +1 -1
- {pelutils-3.8.4 → pelutils-3.9.0}/pelutils/__init__.py +1 -1
- {pelutils-3.8.4 → pelutils-3.9.0}/pelutils/__version__.py +1 -1
- pelutils-3.9.0/pelutils/_utils.py +46 -0
- {pelutils-3.8.4 → pelutils-3.9.0}/pelutils/datastorage2/_pretty_json.py +11 -0
- {pelutils-3.8.4 → pelutils-3.9.0}/pelutils/ds/__init__.py +21 -9
- {pelutils-3.8.4 → pelutils-3.9.0}/pelutils/types.py +5 -0
- {pelutils-3.8.4 → pelutils-3.9.0}/pelutils.egg-info/PKG-INFO +2 -2
- {pelutils-3.8.4 → pelutils-3.9.0}/pelutils.egg-info/SOURCES.txt +3 -1
- pelutils-3.9.0/tests/test_types.py +37 -0
- pelutils-3.9.0/tests/test_utils.py +13 -0
- pelutils-3.8.4/tests/test_types.py +0 -22
- {pelutils-3.8.4 → pelutils-3.9.0}/MANIFEST.in +0 -0
- {pelutils-3.8.4 → pelutils-3.9.0}/pelutils/_c/__init__.py +0 -0
- {pelutils-3.8.4 → pelutils-3.9.0}/pelutils/_c/ds.c +0 -0
- {pelutils-3.8.4 → pelutils-3.9.0}/pelutils/_c/hashmap.c/LICENSE +0 -0
- {pelutils-3.8.4 → pelutils-3.9.0}/pelutils/_c/hashmap.c/hashmap.c +0 -0
- {pelutils-3.8.4 → pelutils-3.9.0}/pelutils/_c/hashmap.c/hashmap.h +0 -0
- {pelutils-3.8.4 → pelutils-3.9.0}/pelutils/_entry_points/__init__.py +0 -0
- {pelutils-3.8.4 → pelutils-3.9.0}/pelutils/_entry_points/linecounter.py +0 -0
- {pelutils-3.8.4 → pelutils-3.9.0}/pelutils/datastorage.py +0 -0
- {pelutils-3.8.4 → pelutils-3.9.0}/pelutils/datastorage2/__init__.py +0 -0
- {pelutils-3.8.4 → pelutils-3.9.0}/pelutils/ds/distributions.py +0 -0
- {pelutils-3.8.4 → pelutils-3.9.0}/pelutils/ds/plots.py +0 -0
- {pelutils-3.8.4 → pelutils-3.9.0}/pelutils/ds/stats.py +0 -0
- {pelutils-3.8.4 → pelutils-3.9.0}/pelutils/format.py +0 -0
- {pelutils-3.8.4 → pelutils-3.9.0}/pelutils/jsonl.py +0 -0
- {pelutils-3.8.4 → pelutils-3.9.0}/pelutils/logging/__init__.py +0 -0
- {pelutils-3.8.4 → pelutils-3.9.0}/pelutils/logging/_rotate.py +0 -0
- {pelutils-3.8.4 → pelutils-3.9.0}/pelutils/logging/_utils.py +0 -0
- {pelutils-3.8.4 → pelutils-3.9.0}/pelutils/parser.py +0 -0
- {pelutils-3.8.4 → pelutils-3.9.0}/pelutils/pretty_json.py +0 -0
- {pelutils-3.8.4 → pelutils-3.9.0}/pelutils/py.typed +0 -0
- {pelutils-3.8.4 → pelutils-3.9.0}/pelutils/tests.py +0 -0
- {pelutils-3.8.4 → pelutils-3.9.0}/pelutils/ticktock.py +0 -0
- {pelutils-3.8.4 → pelutils-3.9.0}/pelutils.egg-info/dependency_links.txt +0 -0
- {pelutils-3.8.4 → pelutils-3.9.0}/pelutils.egg-info/entry_points.txt +0 -0
- {pelutils-3.8.4 → pelutils-3.9.0}/pelutils.egg-info/requires.txt +0 -0
- {pelutils-3.8.4 → pelutils-3.9.0}/pelutils.egg-info/top_level.txt +0 -0
- {pelutils-3.8.4 → pelutils-3.9.0}/setup.cfg +0 -0
- {pelutils-3.8.4 → pelutils-3.9.0}/setup.py +0 -0
- {pelutils-3.8.4 → pelutils-3.9.0}/tests/test_datastorage.py +0 -0
- {pelutils-3.8.4 → pelutils-3.9.0}/tests/test_format.py +0 -0
- {pelutils-3.8.4 → pelutils-3.9.0}/tests/test_init.py +0 -0
- {pelutils-3.8.4 → pelutils-3.9.0}/tests/test_jsonl.py +0 -0
- {pelutils-3.8.4 → pelutils-3.9.0}/tests/test_parser.py +0 -0
- {pelutils-3.8.4 → pelutils-3.9.0}/tests/test_pretty_json.py +0 -0
- {pelutils-3.8.4 → pelutils-3.9.0}/tests/test_tests.py +0 -0
- {pelutils-3.8.4 → pelutils-3.9.0}/tests/test_ticktock.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: pelutils
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.9.0
|
|
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/
|
|
@@ -275,7 +275,7 @@ log2.configure("path/to/save/log2.log")
|
|
|
275
275
|
|
|
276
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.
|
|
277
277
|
```py
|
|
278
|
-
from pelutils.types import AnyArray, FloatArray, IntArray
|
|
278
|
+
from pelutils.types import AnyArray, BoolArray, BytesArray, ComplexArray, FloatArray, IntArray, ObjectArray, StringArray
|
|
279
279
|
|
|
280
280
|
|
|
281
281
|
def function_which_takes_np_types(
|
|
@@ -250,7 +250,7 @@ log2.configure("path/to/save/log2.log")
|
|
|
250
250
|
|
|
251
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.
|
|
252
252
|
```py
|
|
253
|
-
from pelutils.types import AnyArray, FloatArray, IntArray
|
|
253
|
+
from pelutils.types import AnyArray, BoolArray, BytesArray, ComplexArray, FloatArray, IntArray, ObjectArray, StringArray
|
|
254
254
|
|
|
255
255
|
|
|
256
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
|
|
@@ -315,6 +314,7 @@ from .ticktock import * # noqa: F403
|
|
|
315
314
|
TT: TickTock # noqa: F405
|
|
316
315
|
from .datastorage import * # noqa: F403
|
|
317
316
|
from .datastorage2 import * # noqa: F403
|
|
317
|
+
from .ds import unique
|
|
318
318
|
from .format import * # noqa: F403
|
|
319
319
|
from .jsonl import * # noqa: F403
|
|
320
320
|
from .pretty_json import * # noqa: F403
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
# Do not put anything else in this file
|
|
2
|
-
__version__ = "3.
|
|
2
|
+
__version__ = "3.9.0"
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def isinstance_by_name(obj: Any, module: str, qualname: str) -> bool: # pyright: ignore[reportExplicitAny]
|
|
6
|
+
"""Check whether ``obj`` is an instance of a class without importing its module.
|
|
7
|
+
|
|
8
|
+
This is useful for libraries with optional dependencies: if the dependency
|
|
9
|
+
has not been imported anywhere in the current process, ``obj`` cannot
|
|
10
|
+
possibly be an instance of one of its classes, so we can skip the check
|
|
11
|
+
without forcing an import.
|
|
12
|
+
|
|
13
|
+
Parameters
|
|
14
|
+
----------
|
|
15
|
+
obj
|
|
16
|
+
The object whose type is being checked.
|
|
17
|
+
module
|
|
18
|
+
The fully qualified name of the module that defines the target class
|
|
19
|
+
(e.g. ``"pandas"`` or ``"numpy"``).
|
|
20
|
+
qualname
|
|
21
|
+
The attribute name of the class within ``module`` (e.g. ``"Series"``
|
|
22
|
+
or ``"ndarray"``). Dotted paths are not supported.
|
|
23
|
+
|
|
24
|
+
Returns
|
|
25
|
+
-------
|
|
26
|
+
bool
|
|
27
|
+
``True`` if ``module`` is already loaded in :data:`sys.modules` and
|
|
28
|
+
``obj`` is an instance of ``module.qualname``; ``False`` otherwise
|
|
29
|
+
(including when the module is not loaded or does not expose the
|
|
30
|
+
named attribute).
|
|
31
|
+
|
|
32
|
+
Examples
|
|
33
|
+
--------
|
|
34
|
+
>>> import pandas as pd
|
|
35
|
+
>>> _isinstance_by_name(pd.Series([1, 2, 3]), "pandas", "Series")
|
|
36
|
+
True
|
|
37
|
+
>>> _isinstance_by_name([1, 2, 3], "pandas", "Series")
|
|
38
|
+
False
|
|
39
|
+
"""
|
|
40
|
+
mod = sys.modules.get(module)
|
|
41
|
+
if mod is None:
|
|
42
|
+
return False
|
|
43
|
+
cls = getattr(mod, qualname, None)
|
|
44
|
+
if not isinstance(cls, type):
|
|
45
|
+
return False
|
|
46
|
+
return isinstance(obj, cls)
|
|
@@ -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,7 +5,8 @@ from typing import TypeVar, Union, cast
|
|
|
5
5
|
|
|
6
6
|
import numpy as np
|
|
7
7
|
|
|
8
|
-
from pelutils.
|
|
8
|
+
from pelutils._utils import isinstance_by_name
|
|
9
|
+
from pelutils.types import AnyArray, BoolArray, BytesArray, FloatArray, IntArray, StringArray
|
|
9
10
|
|
|
10
11
|
try:
|
|
11
12
|
import torch
|
|
@@ -18,27 +19,38 @@ import _pelutils_c as _c
|
|
|
18
19
|
|
|
19
20
|
import pelutils._c as _c_utils
|
|
20
21
|
|
|
21
|
-
ArrayOrTensor =
|
|
22
|
+
ArrayOrTensor = Union["BoolArray | BytesArray | FloatArray | IntArray | StringArray | torch.Tensor"]
|
|
22
23
|
|
|
23
24
|
|
|
24
|
-
def unique(
|
|
25
|
-
array:
|
|
25
|
+
def unique( # noqa: PLR0912
|
|
26
|
+
array: ...,
|
|
26
27
|
*,
|
|
27
28
|
return_index: bool = False,
|
|
28
29
|
return_inverse: bool = False,
|
|
29
30
|
return_counts: bool = False,
|
|
30
31
|
axis: int = 0,
|
|
31
32
|
) -> ArrayOrTensor | tuple[ArrayOrTensor, ...]:
|
|
32
|
-
"""
|
|
33
|
-
if not array.size:
|
|
34
|
-
raise ValueError("Array must be non-empty")
|
|
33
|
+
"""Return unique elements in a given numpy array (or torch tensor or pandas series).
|
|
35
34
|
|
|
35
|
+
This function works very similar to np.unique, but it runs in linear time, making it significantly faster
|
|
36
|
+
for large arrays. The returned unique elements are unsorted, however.
|
|
37
|
+
"""
|
|
36
38
|
is_tensor = False
|
|
37
39
|
if _has_torch and isinstance(array, torch.Tensor): # pyright: ignore[reportPossiblyUnboundVariable]
|
|
38
40
|
is_tensor = True
|
|
39
41
|
np_array = array.numpy()
|
|
40
|
-
|
|
42
|
+
elif isinstance_by_name(array, "pandas", "Series"):
|
|
43
|
+
np_array = array.values
|
|
44
|
+
elif isinstance(array, np.ndarray):
|
|
45
|
+
if np.issubdtype(array.dtype, np.object_):
|
|
46
|
+
raise TypeError(f"Unsupported array dtype {array.dtype}")
|
|
41
47
|
np_array = array
|
|
48
|
+
else:
|
|
49
|
+
raise TypeError(f"Unsupported array type {type(array)}, must be numpy array, torch tensor, or pandas dataframe.")
|
|
50
|
+
|
|
51
|
+
if np_array.ndim == 0:
|
|
52
|
+
raise ValueError("unique does not work for shape-less arrays")
|
|
53
|
+
|
|
42
54
|
np_array = cast(AnyArray, np_array)
|
|
43
55
|
del array # Prevent reuse - underlying tensor already referenced by np_array, which should be used from here
|
|
44
56
|
|
|
@@ -82,7 +94,7 @@ def unique(
|
|
|
82
94
|
if _has_torch and is_tensor:
|
|
83
95
|
ret = [torch.from_numpy(x) for x in ret] # pyright: ignore[reportPossiblyUnboundVariable]
|
|
84
96
|
|
|
85
|
-
return tuple(ret) if len(ret) > 1 else ret[0]
|
|
97
|
+
return tuple(ret) if len(ret) > 1 else ret[0]
|
|
86
98
|
|
|
87
99
|
|
|
88
100
|
def tensor_bytes(x: AnyArray | torch.Tensor) -> int:
|
|
@@ -5,5 +5,10 @@ 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
|
+
BytesArray = npt.NDArray[np.bytes_]
|
|
10
|
+
ComplexArray = npt.NDArray[np.complexfloating[Any]] # pyright: ignore[reportExplicitAny, reportInvalidTypeArguments]
|
|
8
11
|
FloatArray = npt.NDArray[np.floating[Any]] # pyright: ignore[reportExplicitAny]
|
|
9
12
|
IntArray = npt.NDArray[np.integer[Any]] # pyright: ignore[reportExplicitAny]
|
|
13
|
+
ObjectArray = npt.NDArray[np.object_]
|
|
14
|
+
StringArray = npt.NDArray[np.str_]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: pelutils
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.9.0
|
|
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/
|
|
@@ -275,7 +275,7 @@ log2.configure("path/to/save/log2.log")
|
|
|
275
275
|
|
|
276
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.
|
|
277
277
|
```py
|
|
278
|
-
from pelutils.types import AnyArray, FloatArray, IntArray
|
|
278
|
+
from pelutils.types import AnyArray, BoolArray, BytesArray, ComplexArray, FloatArray, IntArray, ObjectArray, StringArray
|
|
279
279
|
|
|
280
280
|
|
|
281
281
|
def function_which_takes_np_types(
|
|
@@ -3,6 +3,7 @@ README.md
|
|
|
3
3
|
setup.py
|
|
4
4
|
pelutils/__init__.py
|
|
5
5
|
pelutils/__version__.py
|
|
6
|
+
pelutils/_utils.py
|
|
6
7
|
pelutils/datastorage.py
|
|
7
8
|
pelutils/format.py
|
|
8
9
|
pelutils/jsonl.py
|
|
@@ -42,4 +43,5 @@ tests/test_parser.py
|
|
|
42
43
|
tests/test_pretty_json.py
|
|
43
44
|
tests/test_tests.py
|
|
44
45
|
tests/test_ticktock.py
|
|
45
|
-
tests/test_types.py
|
|
46
|
+
tests/test_types.py
|
|
47
|
+
tests/test_utils.py
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from pelutils import AnyArray, BoolArray, ComplexArray, FloatArray, IntArray, StringArray
|
|
4
|
+
from pelutils.types import BytesArray, ObjectArray
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def function_which_takes_np_types( # noqa: PLR0913
|
|
8
|
+
any_array: AnyArray,
|
|
9
|
+
bool_array: BoolArray,
|
|
10
|
+
bytes_array: BytesArray,
|
|
11
|
+
complex_array: ComplexArray,
|
|
12
|
+
float_array: FloatArray,
|
|
13
|
+
int_array: IntArray,
|
|
14
|
+
object_array: ObjectArray,
|
|
15
|
+
string_array: StringArray,
|
|
16
|
+
) -> ComplexArray:
|
|
17
|
+
assert np.issubdtype(object_array.dtype, np.object_)
|
|
18
|
+
assert not np.issubdtype(bytes_array.dtype, np.object_)
|
|
19
|
+
assert not np.issubdtype(string_array.dtype, np.object_)
|
|
20
|
+
assert not np.issubdtype(float_array.dtype, np.object_)
|
|
21
|
+
return any_array + bool_array + complex_array + float_array + int_array + len(bytes_array) + len(string_array)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def test_types():
|
|
25
|
+
"""There isn't much to test.
|
|
26
|
+
|
|
27
|
+
Just make sure that using the types doesn't break anything silly like function declarations.
|
|
28
|
+
"""
|
|
29
|
+
any_array = np.arange(5, dtype=np.float16)
|
|
30
|
+
bool_array = np.arange(5).astype(bool)
|
|
31
|
+
bytes_array = np.array([x.to_bytes(x, "little") for x in list(range(5))])
|
|
32
|
+
complex_array = 1j * np.arange(5)
|
|
33
|
+
float_array = np.arange(5, dtype=np.float32)
|
|
34
|
+
int_array = np.arange(5)
|
|
35
|
+
string_array = np.array([str(x) for x in list(range(5))])
|
|
36
|
+
object_array = np.array([str, "", 1, 2, object, object()])
|
|
37
|
+
function_which_takes_np_types(any_array, bool_array, bytes_array, complex_array, float_array, int_array, object_array, string_array)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
from numpy import array, ndarray
|
|
3
|
+
|
|
4
|
+
from pelutils._utils import isinstance_by_name
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def test_isinstance_by_name():
|
|
8
|
+
assert not isinstance_by_name(array([1, 2, 3]), "np", "ndarray")
|
|
9
|
+
assert isinstance_by_name(array([1, 2, 3]), "numpy", "ndarray")
|
|
10
|
+
assert isinstance_by_name(pd.DataFrame({"a": [1]}), "pandas", "DataFrame")
|
|
11
|
+
assert isinstance_by_name(pd.Series([1]), "pandas", "Series")
|
|
12
|
+
assert not isinstance_by_name(pd.Series([1]), "pd", "Series")
|
|
13
|
+
assert not isinstance_by_name(ndarray, "np", "ndarray")
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import numpy as np
|
|
2
|
-
|
|
3
|
-
from pelutils.types import AnyArray, FloatArray, IntArray
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
def function_which_takes_np_types(
|
|
7
|
-
any_array: AnyArray,
|
|
8
|
-
float_array: FloatArray,
|
|
9
|
-
int_array: IntArray,
|
|
10
|
-
) -> FloatArray:
|
|
11
|
-
return any_array + float_array + int_array
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
def test_types():
|
|
15
|
-
"""There isn't much to test.
|
|
16
|
-
|
|
17
|
-
Just make sure that using the types doesn't break anything silly like function declarations.
|
|
18
|
-
"""
|
|
19
|
-
any_array = np.arange(5, dtype=np.float16)
|
|
20
|
-
float_array = np.arange(5, dtype=np.float32)
|
|
21
|
-
int_array = np.arange(5)
|
|
22
|
-
function_which_takes_np_types(any_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
|