pythonwrench 0.4.0__tar.gz → 0.4.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.
- {pythonwrench-0.4.0/src/pythonwrench.egg-info → pythonwrench-0.4.2}/PKG-INFO +3 -3
- pythonwrench-0.4.2/docs/requirements.txt +3 -0
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/pyproject.toml +4 -1
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/src/pythonwrench/__init__.py +6 -2
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/src/pythonwrench/_core.py +63 -5
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/src/pythonwrench/abc.py +4 -3
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/src/pythonwrench/argparse.py +9 -9
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/src/pythonwrench/cast.py +3 -4
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/src/pythonwrench/checksum.py +6 -5
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/src/pythonwrench/collections/collections.py +31 -36
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/src/pythonwrench/csv.py +9 -9
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/src/pythonwrench/disk_cache.py +77 -47
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/src/pythonwrench/functools.py +25 -10
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/src/pythonwrench/importlib.py +9 -5
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/src/pythonwrench/inspect.py +28 -25
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/src/pythonwrench/json.py +3 -3
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/src/pythonwrench/jsonl.py +3 -3
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/src/pythonwrench/pickle.py +3 -3
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/src/pythonwrench/random.py +12 -1
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/src/pythonwrench/re.py +3 -4
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/src/pythonwrench/semver.py +2 -0
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/src/pythonwrench/typing/__init__.py +2 -0
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/src/pythonwrench/typing/checks.py +13 -11
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/src/pythonwrench/typing/classes.py +30 -18
- {pythonwrench-0.4.0 → pythonwrench-0.4.2/src/pythonwrench.egg-info}/PKG-INFO +3 -3
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/src/pythonwrench.egg-info/SOURCES.txt +2 -1
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/src/pythonwrench.egg-info/requires.txt +2 -0
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/tests/test_checksum.py +6 -0
- pythonwrench-0.4.2/tests/test_functools.py +32 -0
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/tests/test_inspect.py +17 -0
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/tests/test_typing.py +7 -0
- pythonwrench-0.4.0/src/pythonwrench/io.py +0 -59
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/LICENSE +0 -0
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/README.md +0 -0
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/setup.cfg +0 -0
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/setup.py +0 -0
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/src/pythonwrench/__main__.py +0 -0
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/src/pythonwrench/collections/__init__.py +0 -0
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/src/pythonwrench/collections/prop.py +0 -0
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/src/pythonwrench/collections/reducers.py +0 -0
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/src/pythonwrench/dataclasses.py +0 -0
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/src/pythonwrench/datetime.py +0 -0
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/src/pythonwrench/difflib.py +0 -0
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/src/pythonwrench/entries.py +0 -0
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/src/pythonwrench/enum.py +0 -0
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/src/pythonwrench/hashlib.py +0 -0
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/src/pythonwrench/logging.py +0 -0
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/src/pythonwrench/math.py +0 -0
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/src/pythonwrench/os.py +0 -0
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/src/pythonwrench/warnings.py +0 -0
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/src/pythonwrench.egg-info/dependency_links.txt +0 -0
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/src/pythonwrench.egg-info/entry_points.txt +0 -0
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/src/pythonwrench.egg-info/top_level.txt +0 -0
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/tests/test_abc.py +0 -0
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/tests/test_argparse.py +0 -0
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/tests/test_cast.py +0 -0
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/tests/test_collections.py +0 -0
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/tests/test_csv.py +0 -0
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/tests/test_dataclasses.py +0 -0
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/tests/test_difflib.py +0 -0
- /pythonwrench-0.4.0/tests/test_functools.py → /pythonwrench-0.4.2/tests/test_disk_cache.py +0 -0
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/tests/test_entries.py +0 -0
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/tests/test_enum.py +0 -0
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/tests/test_hashlib.py +0 -0
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/tests/test_importlib.py +0 -0
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/tests/test_json.py +0 -0
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/tests/test_jsonl.py +0 -0
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/tests/test_logging.py +0 -0
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/tests/test_math.py +0 -0
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/tests/test_os.py +0 -0
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/tests/test_random.py +0 -0
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/tests/test_readme.py +0 -0
- {pythonwrench-0.4.0 → pythonwrench-0.4.2}/tests/test_semver.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
2
|
Name: pythonwrench
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.2
|
|
4
4
|
Summary: Set of tools for Python that could be in the standard library.
|
|
5
5
|
Author-email: "Étienne Labbé (Labbeti)" <labbeti.pub@gmail.com>
|
|
6
6
|
Maintainer-email: "Étienne Labbé (Labbeti)" <labbeti.pub@gmail.com>
|
|
@@ -47,7 +47,7 @@ Requires-Python: >=3.8
|
|
|
47
47
|
Description-Content-Type: text/markdown
|
|
48
48
|
License-File: LICENSE
|
|
49
49
|
Requires-Dist: typing-extensions>=4.10.0
|
|
50
|
-
|
|
50
|
+
Provides-Extra: dev
|
|
51
51
|
|
|
52
52
|
# pythonwrench
|
|
53
53
|
|
|
@@ -45,6 +45,9 @@ pyw-info = "pythonwrench.entries:print_install_info"
|
|
|
45
45
|
pyw-tree = "pythonwrench.entries:main_tree"
|
|
46
46
|
pyw-safe-rmdir = "pythonwrench.entries:main_safe_rmdir"
|
|
47
47
|
|
|
48
|
+
[project.optional-dependencies]
|
|
49
|
+
dev = []
|
|
50
|
+
|
|
48
51
|
[build-system]
|
|
49
52
|
requires = ["setuptools >= 61.0"]
|
|
50
53
|
build-backend = "setuptools.build_meta"
|
|
@@ -87,6 +90,6 @@ dev = [
|
|
|
87
90
|
"ruff>=0.12.0",
|
|
88
91
|
"setuptools",
|
|
89
92
|
"sphinx",
|
|
90
|
-
"sphinx-
|
|
93
|
+
"sphinx-immaterial>=0.11.14",
|
|
91
94
|
"twine",
|
|
92
95
|
]
|
|
@@ -9,25 +9,28 @@ __author_email__ = "labbeti.pub@gmail.com"
|
|
|
9
9
|
__license__ = "MIT"
|
|
10
10
|
__maintainer__ = "Étienne Labbé (Labbeti)"
|
|
11
11
|
__status__ = "Development"
|
|
12
|
-
__version__ = "0.4.
|
|
12
|
+
__version__ = "0.4.2"
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
# Re-import for language servers
|
|
16
16
|
from . import abc as abc
|
|
17
17
|
from . import argparse as argparse
|
|
18
|
+
from . import cast as cast
|
|
19
|
+
from . import checksum as checksum
|
|
18
20
|
from . import collections as collections
|
|
19
21
|
from . import csv as csv
|
|
20
22
|
from . import dataclasses as dataclasses
|
|
21
23
|
from . import datetime as datetime
|
|
22
24
|
from . import difflib as difflib
|
|
25
|
+
from . import disk_cache as disk_cache
|
|
23
26
|
from . import entries as entries
|
|
24
27
|
from . import enum as enum
|
|
25
28
|
from . import functools as functools
|
|
26
29
|
from . import hashlib as hashlib
|
|
27
30
|
from . import importlib as importlib
|
|
28
31
|
from . import inspect as inspect
|
|
29
|
-
from . import io as io
|
|
30
32
|
from . import json as json
|
|
33
|
+
from . import jsonl as jsonl
|
|
31
34
|
from . import logging as logging
|
|
32
35
|
from . import math as math
|
|
33
36
|
from . import os as os
|
|
@@ -166,6 +169,7 @@ from .typing import (
|
|
|
166
169
|
SupportsAnd,
|
|
167
170
|
SupportsBool,
|
|
168
171
|
SupportsDiv,
|
|
172
|
+
SupportsGetitem,
|
|
169
173
|
SupportsGetitemIterLen,
|
|
170
174
|
SupportsGetitemLen,
|
|
171
175
|
SupportsIterLen,
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env python
|
|
2
2
|
# -*- coding: utf-8 -*-
|
|
3
3
|
|
|
4
|
+
import os
|
|
4
5
|
from functools import wraps
|
|
6
|
+
from io import TextIOWrapper
|
|
7
|
+
from pathlib import Path
|
|
5
8
|
from typing import (
|
|
6
9
|
Any,
|
|
7
10
|
Callable,
|
|
@@ -9,22 +12,27 @@ from typing import (
|
|
|
9
12
|
Generic,
|
|
10
13
|
Literal,
|
|
11
14
|
Optional,
|
|
15
|
+
Protocol,
|
|
12
16
|
Tuple,
|
|
13
|
-
TypeVar,
|
|
14
17
|
Union,
|
|
15
18
|
get_args,
|
|
19
|
+
overload,
|
|
16
20
|
)
|
|
17
21
|
|
|
18
|
-
from typing_extensions import ParamSpec
|
|
22
|
+
from typing_extensions import ParamSpec, TypeVar
|
|
19
23
|
|
|
20
24
|
P = ParamSpec("P")
|
|
21
|
-
T = TypeVar("T")
|
|
22
|
-
U = TypeVar("U")
|
|
25
|
+
T = TypeVar("T", covariant=True)
|
|
26
|
+
U = TypeVar("U", covariant=True)
|
|
23
27
|
T_Output = TypeVar("T_Output")
|
|
28
|
+
T_Any = TypeVar("T_Any", contravariant=True, default=Any)
|
|
24
29
|
|
|
25
30
|
UnkMode = Literal["identity", "error"]
|
|
26
31
|
ClassOrTuple = Union[type, Tuple[type, ...]]
|
|
27
|
-
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class Predicate(Protocol[T_Any]):
|
|
35
|
+
def __call__(self, x: T_Any) -> bool: ...
|
|
28
36
|
|
|
29
37
|
|
|
30
38
|
def return_none(*args, **kwargs) -> None:
|
|
@@ -161,3 +169,53 @@ class _FunctionRegistry(Generic[T_Output]):
|
|
|
161
169
|
else:
|
|
162
170
|
msg = f"Invalid argument {unk_mode=}. (expected one of {get_args(UnkMode)})"
|
|
163
171
|
raise ValueError(msg)
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
@overload
|
|
175
|
+
def _setup_output_fpath(
|
|
176
|
+
fpath: Union[str, Path, os.PathLike],
|
|
177
|
+
overwrite: bool,
|
|
178
|
+
make_parents: bool,
|
|
179
|
+
absolute: bool = True,
|
|
180
|
+
) -> Path: ...
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
@overload
|
|
184
|
+
def _setup_output_fpath(
|
|
185
|
+
fpath: TextIOWrapper,
|
|
186
|
+
overwrite: bool,
|
|
187
|
+
make_parents: bool,
|
|
188
|
+
absolute: bool = True,
|
|
189
|
+
) -> TextIOWrapper: ...
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
@overload
|
|
193
|
+
def _setup_output_fpath(
|
|
194
|
+
fpath: None,
|
|
195
|
+
overwrite: bool,
|
|
196
|
+
make_parents: bool,
|
|
197
|
+
absolute: bool = True,
|
|
198
|
+
) -> None: ...
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def _setup_output_fpath(
|
|
202
|
+
fpath: Union[str, Path, os.PathLike, TextIOWrapper, None],
|
|
203
|
+
overwrite: bool,
|
|
204
|
+
make_parents: bool,
|
|
205
|
+
absolute: bool = True,
|
|
206
|
+
) -> Union[Path, None, TextIOWrapper]:
|
|
207
|
+
"""Resolve path, expand path and create intermediate parents."""
|
|
208
|
+
if not isinstance(fpath, (str, Path, os.PathLike)):
|
|
209
|
+
return fpath
|
|
210
|
+
|
|
211
|
+
fpath = Path(fpath)
|
|
212
|
+
if absolute:
|
|
213
|
+
fpath = fpath.resolve().expanduser()
|
|
214
|
+
|
|
215
|
+
if not overwrite and fpath.exists():
|
|
216
|
+
msg = f"File {fpath} already exists."
|
|
217
|
+
raise FileExistsError(msg)
|
|
218
|
+
elif make_parents:
|
|
219
|
+
fpath.parent.mkdir(parents=True, exist_ok=True)
|
|
220
|
+
|
|
221
|
+
return fpath
|
|
@@ -7,14 +7,15 @@ from typing import Any, ClassVar, Dict, Type
|
|
|
7
7
|
class Singleton(type):
|
|
8
8
|
"""Singleton metaclass.
|
|
9
9
|
|
|
10
|
-
To use it, just inherit from metaclass
|
|
11
|
-
|
|
10
|
+
To use it, just inherit from metaclass.
|
|
11
|
+
|
|
12
|
+
Example
|
|
13
|
+
-------
|
|
12
14
|
>>> class MyClass(metaclass=Singleton):
|
|
13
15
|
>>> pass
|
|
14
16
|
>>> a1 = MyClass()
|
|
15
17
|
>>> a2 = MyClass()
|
|
16
18
|
>>> # a1 and a2 are exactly the same instance, i.e. id(a1) == id(a2)
|
|
17
|
-
```
|
|
18
19
|
"""
|
|
19
20
|
|
|
20
21
|
_instances: ClassVar[Dict[Type, Any]] = {}
|
|
@@ -35,7 +35,7 @@ def parse_to(
|
|
|
35
35
|
) -> Callable[[str], T]:
|
|
36
36
|
"""Returns a callable that convert string value to target type safely.
|
|
37
37
|
|
|
38
|
-
Intended for argparse
|
|
38
|
+
Intended for argparse arguments.
|
|
39
39
|
"""
|
|
40
40
|
return partial(
|
|
41
41
|
str_to_type,
|
|
@@ -56,7 +56,7 @@ def str_to_type(
|
|
|
56
56
|
false_values: Union[str, Iterable[str]] = DEFAULT_FALSE_VALUES,
|
|
57
57
|
none_values: Union[str, Iterable[str]] = DEFAULT_NONE_VALUES,
|
|
58
58
|
) -> T:
|
|
59
|
-
"""Convert string values to target type safely. Intended for argparse
|
|
59
|
+
"""Convert string values to target type safely. Intended for argparse arguments.
|
|
60
60
|
|
|
61
61
|
- True values: 'True', 'T', 'yes', 'y', '1'.
|
|
62
62
|
- False values: 'False', 'F', 'no', 'n', '0'.
|
|
@@ -84,7 +84,7 @@ def str_to_bool(
|
|
|
84
84
|
true_values: Union[str, Iterable[str]] = DEFAULT_TRUE_VALUES,
|
|
85
85
|
false_values: Union[str, Iterable[str]] = DEFAULT_FALSE_VALUES,
|
|
86
86
|
) -> bool:
|
|
87
|
-
"""Convert string values to bool safely. Intended for argparse
|
|
87
|
+
"""Convert string values to bool safely. Intended for argparse arguments.
|
|
88
88
|
|
|
89
89
|
- True values: 'True', 'T', 'yes', 'y', '1'.
|
|
90
90
|
- False values: 'False', 'F', 'no', 'n', '0'.
|
|
@@ -105,7 +105,7 @@ def str_to_none(
|
|
|
105
105
|
case_sensitive: bool = False,
|
|
106
106
|
none_values: Union[str, Iterable[str]] = DEFAULT_NONE_VALUES,
|
|
107
107
|
) -> None:
|
|
108
|
-
"""Convert string values to None safely. Intended for argparse
|
|
108
|
+
"""Convert string values to None safely. Intended for argparse arguments.
|
|
109
109
|
|
|
110
110
|
- None values: 'None', 'null'
|
|
111
111
|
- Other raises ValueError.
|
|
@@ -123,7 +123,7 @@ def str_to_optional_bool(
|
|
|
123
123
|
false_values: Union[str, Iterable[str]] = DEFAULT_FALSE_VALUES,
|
|
124
124
|
none_values: Union[str, Iterable[str]] = DEFAULT_NONE_VALUES,
|
|
125
125
|
) -> Optional[bool]:
|
|
126
|
-
"""Convert string values to optional bool safely. Intended for argparse
|
|
126
|
+
"""Convert string values to optional bool safely. Intended for argparse arguments.
|
|
127
127
|
|
|
128
128
|
- True values: 'True', 'T', 'yes', 'y', '1'.
|
|
129
129
|
- False values: 'False', 'F', 'no', 'n', '0'.
|
|
@@ -141,7 +141,7 @@ def str_to_optional_float(
|
|
|
141
141
|
case_sensitive: bool = False,
|
|
142
142
|
none_values: Union[str, Iterable[str]] = DEFAULT_NONE_VALUES,
|
|
143
143
|
) -> Optional[float]:
|
|
144
|
-
"""Convert string values to optional float safely. Intended for argparse
|
|
144
|
+
"""Convert string values to optional float safely. Intended for argparse arguments."""
|
|
145
145
|
return str_to_type(
|
|
146
146
|
x, Optional[float], case_sensitive=case_sensitive, none_values=none_values
|
|
147
147
|
)
|
|
@@ -153,7 +153,7 @@ def str_to_optional_int(
|
|
|
153
153
|
case_sensitive: bool = False,
|
|
154
154
|
none_values: Union[str, Iterable[str]] = DEFAULT_NONE_VALUES,
|
|
155
155
|
) -> Optional[int]:
|
|
156
|
-
"""Convert string values to optional int safely. Intended for argparse
|
|
156
|
+
"""Convert string values to optional int safely. Intended for argparse arguments."""
|
|
157
157
|
return str_to_type(
|
|
158
158
|
x, Optional[int], case_sensitive=case_sensitive, none_values=none_values
|
|
159
159
|
)
|
|
@@ -165,7 +165,7 @@ def str_to_optional_str(
|
|
|
165
165
|
case_sensitive: bool = False,
|
|
166
166
|
none_values: Union[str, Iterable[str]] = DEFAULT_NONE_VALUES,
|
|
167
167
|
) -> Optional[str]:
|
|
168
|
-
"""Convert string values to optional str safely. Intended for argparse
|
|
168
|
+
"""Convert string values to optional str safely. Intended for argparse arguments."""
|
|
169
169
|
return str_to_type(
|
|
170
170
|
x, Optional[str], case_sensitive=case_sensitive, none_values=none_values
|
|
171
171
|
)
|
|
@@ -284,7 +284,7 @@ def _str_to_none_impl(
|
|
|
284
284
|
case_sensitive: bool = False,
|
|
285
285
|
none_values: Union[str, Iterable[str]] = DEFAULT_NONE_VALUES,
|
|
286
286
|
) -> Union[None, Exception]:
|
|
287
|
-
"""Convert string values to None safely. Intended for argparse
|
|
287
|
+
"""Convert string values to None safely. Intended for argparse arguments.
|
|
288
288
|
|
|
289
289
|
- None values: 'None', 'null'
|
|
290
290
|
- Other raises ValueError.
|
|
@@ -63,16 +63,15 @@ def register_as_builtin_fn(
|
|
|
63
63
|
priority: int = 0,
|
|
64
64
|
) -> Callable:
|
|
65
65
|
"""Decorator to add an as_builtin function.
|
|
66
|
-
```
|
|
67
|
-
>>> import numpy as np
|
|
68
66
|
|
|
67
|
+
Example
|
|
68
|
+
-------
|
|
69
|
+
>>> import numpy as np
|
|
69
70
|
>>> @register_as_builtin_fn(np.ndarray)
|
|
70
71
|
>>> def my_checksum_for_numpy(x: np.ndarray):
|
|
71
72
|
>>> return x.tolist()
|
|
72
|
-
|
|
73
73
|
>>> pw.as_builtin([np.array([1, 2]), [3, 4]])
|
|
74
74
|
... [[1, 2], [3, 4]]
|
|
75
|
-
```
|
|
76
75
|
"""
|
|
77
76
|
return _AS_BUILTIN_REGISTRY.register_decorator(
|
|
78
77
|
class_or_tuple,
|
|
@@ -60,15 +60,14 @@ def register_checksum_fn(
|
|
|
60
60
|
priority: int = 0,
|
|
61
61
|
) -> Callable:
|
|
62
62
|
"""Decorator to add a checksum function.
|
|
63
|
-
```
|
|
64
|
-
>>> import numpy as np
|
|
65
63
|
|
|
64
|
+
Example
|
|
65
|
+
-------
|
|
66
|
+
>>> import numpy as np
|
|
66
67
|
>>> @register_checksum_fn(np.ndarray)
|
|
67
68
|
>>> def my_checksum_for_numpy(x: np.ndarray):
|
|
68
69
|
>>> return int(x.sum())
|
|
69
|
-
|
|
70
70
|
>>> pw.checksum_any(np.array([1, 2])) # calls my_checksum_for_numpy internally, even if array in nested inside a list, dict, etc.
|
|
71
|
-
```
|
|
72
71
|
"""
|
|
73
72
|
return _CHECKSUM_REGISTRY.register_decorator(
|
|
74
73
|
class_or_tuple,
|
|
@@ -196,7 +195,9 @@ def checksum_set(x: Union[set, frozenset], **kwargs) -> int:
|
|
|
196
195
|
kwargs["accumulator"] = kwargs.get("accumulator", 0) + _cached_checksum_str(
|
|
197
196
|
get_fullname(x)
|
|
198
197
|
)
|
|
199
|
-
|
|
198
|
+
# Simply use sum here, order does not matter
|
|
199
|
+
csum = sum(checksum_any(xi, **kwargs) for xi in x)
|
|
200
|
+
return csum
|
|
200
201
|
|
|
201
202
|
|
|
202
203
|
@register_checksum_fn(range)
|
|
@@ -74,17 +74,17 @@ def contained(
|
|
|
74
74
|
@overload
|
|
75
75
|
def dict_list_to_list_dict(
|
|
76
76
|
dic: Mapping[T, Iterable[U]],
|
|
77
|
-
key_mode: Literal["
|
|
78
|
-
default_val:
|
|
79
|
-
) -> List[Dict[T, U]]: ...
|
|
77
|
+
key_mode: Literal["union"] = "union",
|
|
78
|
+
default_val: W = None,
|
|
79
|
+
) -> List[Dict[T, Union[U, W]]]: ...
|
|
80
80
|
|
|
81
81
|
|
|
82
82
|
@overload
|
|
83
83
|
def dict_list_to_list_dict(
|
|
84
84
|
dic: Mapping[T, Iterable[U]],
|
|
85
|
-
key_mode: Literal["
|
|
86
|
-
default_val:
|
|
87
|
-
) -> List[Dict[T,
|
|
85
|
+
key_mode: Literal["same", "intersect"],
|
|
86
|
+
default_val: Any = None,
|
|
87
|
+
) -> List[Dict[T, U]]: ...
|
|
88
88
|
|
|
89
89
|
|
|
90
90
|
def dict_list_to_list_dict(
|
|
@@ -95,20 +95,16 @@ def dict_list_to_list_dict(
|
|
|
95
95
|
"""Convert dict of lists with same sizes to list of dicts.
|
|
96
96
|
|
|
97
97
|
Example 1
|
|
98
|
-
|
|
99
|
-
```
|
|
98
|
+
---------
|
|
100
99
|
>>> dic = {"a": [1, 2], "b": [3, 4]}
|
|
101
100
|
>>> dict_list_to_list_dict(dic)
|
|
102
101
|
... [{"a": 1, "b": 3}, {"a": 2, "b": 4}]
|
|
103
|
-
```
|
|
104
102
|
|
|
105
103
|
Example 2
|
|
106
|
-
|
|
107
|
-
```
|
|
104
|
+
---------
|
|
108
105
|
>>> dic = {"a": [1, 2, 3], "b": [4], "c": [5, 6]}
|
|
109
106
|
>>> dict_list_to_list_dict(dic, key_mode="union", default=-1)
|
|
110
107
|
... [{"a": 1, "b": 4, "c": 5}, {"a": 2, "b": -1, "c": 6}, {"a": 3, "b": -1, "c": -1}]
|
|
111
|
-
```
|
|
112
108
|
"""
|
|
113
109
|
if len(dic) == 0:
|
|
114
110
|
return []
|
|
@@ -151,11 +147,9 @@ def dump_dict(
|
|
|
151
147
|
|
|
152
148
|
Example 1:
|
|
153
149
|
----------
|
|
154
|
-
```
|
|
155
150
|
>>> d = {"a": 1, "b": 2}
|
|
156
151
|
>>> dump_dict(d)
|
|
157
152
|
... 'a=1, b=2'
|
|
158
|
-
```
|
|
159
153
|
"""
|
|
160
154
|
if dic is None:
|
|
161
155
|
dic = {}
|
|
@@ -360,7 +354,6 @@ def flat_dict_of_dict(
|
|
|
360
354
|
|
|
361
355
|
Example 1
|
|
362
356
|
---------
|
|
363
|
-
```
|
|
364
357
|
>>> dic = {
|
|
365
358
|
... "a": 1,
|
|
366
359
|
... "b": {
|
|
@@ -370,15 +363,12 @@ def flat_dict_of_dict(
|
|
|
370
363
|
... }
|
|
371
364
|
>>> flat_dict_of_dict(dic)
|
|
372
365
|
... {"a": 1, "b.a": 2, "b.b": 10}
|
|
373
|
-
```
|
|
374
366
|
|
|
375
367
|
Example 2
|
|
376
368
|
---------
|
|
377
|
-
```
|
|
378
369
|
>>> dic = {"a": ["hello", "world"], "b": 3}
|
|
379
370
|
>>> flat_dict_of_dict(dic, flat_iterables=True)
|
|
380
371
|
... {"a.0": "hello", "a.1": "world", "b": 3}
|
|
381
|
-
```
|
|
382
372
|
|
|
383
373
|
Args:
|
|
384
374
|
nested_dic: Nested mapping containing sub-mappings or iterables.
|
|
@@ -508,10 +498,11 @@ def list_dict_to_dict_list(
|
|
|
508
498
|
|
|
509
499
|
Args:
|
|
510
500
|
lst: The list of dict to merge.
|
|
511
|
-
key_mode: Can be "same" or "intersect".
|
|
512
|
-
If "same", all the dictionaries must contains the same keys otherwise a ValueError will be raised.
|
|
513
|
-
If "intersect", only the intersection of all keys will be used in output.
|
|
514
|
-
If "union", the output dict will contains the union of all keys, and the missing value will use the argument default_val.
|
|
501
|
+
key_mode: Can be "same" or "intersect". \
|
|
502
|
+
- If "same", all the dictionaries must contains the same keys otherwise a ValueError will be raised. \
|
|
503
|
+
- If "intersect", only the intersection of all keys will be used in output. \
|
|
504
|
+
- If "union", the output dict will contains the union of all keys, and the missing value will use the argument default_val. \
|
|
505
|
+
- If an iterable of elements, use them as keys for output dict.
|
|
515
506
|
default_val: Default value of an element when key_mode is "union". defaults to None.
|
|
516
507
|
default_val_fn: Function to return the default value according to a specific key. defaults to None.
|
|
517
508
|
list_fn: Optional function to build the values. defaults to identity.
|
|
@@ -622,7 +613,6 @@ def unflat_dict_of_dict(dic: Mapping[str, Any], *, sep: str = ".") -> Dict[str,
|
|
|
622
613
|
|
|
623
614
|
Example 1
|
|
624
615
|
----------
|
|
625
|
-
```
|
|
626
616
|
>>> dic = {
|
|
627
617
|
"a.a": 1,
|
|
628
618
|
"b.a": 2,
|
|
@@ -631,7 +621,6 @@ def unflat_dict_of_dict(dic: Mapping[str, Any], *, sep: str = ".") -> Dict[str,
|
|
|
631
621
|
}
|
|
632
622
|
>>> unflat_dict_of_dict(dic)
|
|
633
623
|
... {"a": {"a": 1}, "b": {"a": 2, "b": 3}, "c": 4}
|
|
634
|
-
```
|
|
635
624
|
"""
|
|
636
625
|
output = {}
|
|
637
626
|
for k, v in dic.items():
|
|
@@ -671,6 +660,7 @@ def unflat_list_of_list(
|
|
|
671
660
|
|
|
672
661
|
|
|
673
662
|
def union_dicts(dicts: Iterable[Dict[K, V]]) -> Dict[K, V]:
|
|
663
|
+
"""Performs union of dictionaries."""
|
|
674
664
|
if Version.python() >= Version("3.9.0"):
|
|
675
665
|
return reduce_or(*dicts)
|
|
676
666
|
|
|
@@ -721,19 +711,24 @@ def unzip(
|
|
|
721
711
|
) -> Tuple[List[T], List[U], List[V], List[W], List[X]]: ...
|
|
722
712
|
|
|
723
713
|
|
|
714
|
+
@overload
|
|
715
|
+
def unzip(
|
|
716
|
+
lst: Iterable[Tuple[T, ...]],
|
|
717
|
+
) -> Tuple[List[T], ...]: ...
|
|
718
|
+
|
|
719
|
+
|
|
724
720
|
def unzip(lst):
|
|
725
721
|
"""Invert function of builtin zip().
|
|
726
722
|
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
... [1, 2, 3, 4], [5, 6, 7, 8]
|
|
723
|
+
Example
|
|
724
|
+
-------
|
|
725
|
+
>>> lst1 = [1, 2, 3, 4]
|
|
726
|
+
>>> lst2 = [5, 6, 7, 8]
|
|
727
|
+
>>> zipped_list = list(zip(lst1, lst2))
|
|
728
|
+
>>> zipped_list
|
|
729
|
+
... [(1, 5), (2, 6), (3, 7), (4, 8)]
|
|
730
|
+
>>> unzip(zipped_list)
|
|
731
|
+
... [1, 2, 3, 4], [5, 6, 7, 8]
|
|
737
732
|
"""
|
|
738
733
|
return tuple(map(list, zip(*lst)))
|
|
739
734
|
|
|
@@ -741,8 +736,8 @@ def unzip(lst):
|
|
|
741
736
|
def duplicate_list(lst: List[T], sizes: List[int]) -> List[T]:
|
|
742
737
|
"""Duplicate elements elements of a list with the corresponding sizes.
|
|
743
738
|
|
|
744
|
-
Example
|
|
745
|
-
|
|
739
|
+
Example
|
|
740
|
+
-------
|
|
746
741
|
>>> lst = ["a", "b", "c", "d", "e"]
|
|
747
742
|
>>> sizes = [1, 0, 2, 1, 3]
|
|
748
743
|
>>> duplicate_list(lst, sizes)
|
|
@@ -21,10 +21,10 @@ from typing import (
|
|
|
21
21
|
overload,
|
|
22
22
|
)
|
|
23
23
|
|
|
24
|
+
from pythonwrench._core import _setup_output_fpath
|
|
24
25
|
from pythonwrench.cast import as_builtin
|
|
25
26
|
from pythonwrench.collections import dict_list_to_list_dict, list_dict_to_dict_list
|
|
26
27
|
from pythonwrench.functools import function_alias
|
|
27
|
-
from pythonwrench.io import _setup_output_fpath
|
|
28
28
|
from pythonwrench.typing import isinstance_generic
|
|
29
29
|
|
|
30
30
|
T = TypeVar("T")
|
|
@@ -48,7 +48,7 @@ def dump_csv(
|
|
|
48
48
|
replace_newline_by: Optional[str] = "\\n",
|
|
49
49
|
**csv_writer_kwds,
|
|
50
50
|
) -> str:
|
|
51
|
-
"""Dump content to CSV format into string and/or file.
|
|
51
|
+
r"""Dump content to CSV format into string and/or file.
|
|
52
52
|
|
|
53
53
|
Args:
|
|
54
54
|
data: Data to serialize. Can be a list of dicts, dicts of lists or list of lists.
|
|
@@ -59,7 +59,7 @@ def dump_csv(
|
|
|
59
59
|
header: Indicates if CSV must have header. If "auto", an header is added when a dict of list or list of dicts is passed. defaults to "auto".
|
|
60
60
|
align_content: If True, center content at the middle of each row for better visualization. defaults to False.
|
|
61
61
|
replace_newline_by: Replace newline character to avoid newline in CSV content. defaults to "\\n".
|
|
62
|
-
|
|
62
|
+
\*\*csv_writer_kwds: Others optional arguments passed to CSV writer object.
|
|
63
63
|
|
|
64
64
|
Returns:
|
|
65
65
|
Dumped content as string.
|
|
@@ -98,7 +98,7 @@ def dumps_csv(
|
|
|
98
98
|
replace_newline_by: Optional[str] = "\\n",
|
|
99
99
|
**csv_writer_kwds,
|
|
100
100
|
) -> str:
|
|
101
|
-
"""Dump content to CSV format into string.
|
|
101
|
+
r"""Dump content to CSV format into string.
|
|
102
102
|
|
|
103
103
|
Args:
|
|
104
104
|
data: Data to serialize. Can be a list of dicts, dicts of lists or list of lists.
|
|
@@ -108,7 +108,7 @@ def dumps_csv(
|
|
|
108
108
|
header: Indicates if CSV must have header. If "auto", an header is added when a dict of list or list of dicts is passed. defaults to "auto".
|
|
109
109
|
align_content: If True, center content at the middle of each row for better visualization. defaults to False.
|
|
110
110
|
replace_newline_by: Replace newline character to avoid newline in CSV content. defaults to "\\n".
|
|
111
|
-
|
|
111
|
+
\*\*csv_writer_kwds: Others optional arguments passed to CSV writer object.
|
|
112
112
|
|
|
113
113
|
Returns:
|
|
114
114
|
Dumped content as string.
|
|
@@ -140,7 +140,7 @@ def save_csv(
|
|
|
140
140
|
replace_newline_by: Optional[str] = "\\n",
|
|
141
141
|
**csv_writer_kwds,
|
|
142
142
|
) -> None:
|
|
143
|
-
"""Save content to CSV format into a file or buffer.
|
|
143
|
+
r"""Save content to CSV format into a file or buffer.
|
|
144
144
|
|
|
145
145
|
Args:
|
|
146
146
|
data: Data to serialize. Can be a list of dicts, dicts of lists or list of lists.
|
|
@@ -150,7 +150,7 @@ def save_csv(
|
|
|
150
150
|
header: Indicates if CSV must have header. If "auto", an header is added when a dict of list or list of dicts is passed. defaults to "auto".
|
|
151
151
|
align_content: If True, center content at the middle of each row for better visualization. defaults to False.
|
|
152
152
|
replace_newline_by: Replace newline character to avoid newline in CSV content. defaults to "\\n".
|
|
153
|
-
|
|
153
|
+
\*\*csv_writer_kwds: Others optional arguments passed to CSV writer object.
|
|
154
154
|
"""
|
|
155
155
|
if isinstance(file, (str, Path, PathLike)):
|
|
156
156
|
file = _setup_output_fpath(file, overwrite=overwrite, make_parents=make_parents)
|
|
@@ -320,14 +320,14 @@ def load_csv(
|
|
|
320
320
|
delimiter: Optional[str] = ",",
|
|
321
321
|
**csv_reader_kwds,
|
|
322
322
|
) -> Union[List[Dict[str, Any]], Dict[str, List[Any]]]:
|
|
323
|
-
"""Load content from csv filepath.
|
|
323
|
+
r"""Load content from csv filepath.
|
|
324
324
|
|
|
325
325
|
Args:
|
|
326
326
|
orient: Orientation of the output value. Can be "list" or "dict". defaults to "list".
|
|
327
327
|
header: Specify if CSV has header column. defaults to True.
|
|
328
328
|
comment_start: If this string is not None and a line starts with this string, the line will be ignored. defaults to None.
|
|
329
329
|
delimiter: Value delimiter. defaults to ",".
|
|
330
|
-
|
|
330
|
+
\*\*csv_reader_kwds: Other optional csv arguments.
|
|
331
331
|
|
|
332
332
|
Returns:
|
|
333
333
|
The loaded values as dict of lists, list of dicts or list of lists.
|