pymodaq_utils 5.3.7__tar.gz → 5.3.9__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.
- {pymodaq_utils-5.3.7 → pymodaq_utils-5.3.9}/PKG-INFO +1 -1
- {pymodaq_utils-5.3.7 → pymodaq_utils-5.3.9}/src/pymodaq_utils/abstract.py +6 -2
- {pymodaq_utils-5.3.7 → pymodaq_utils-5.3.9}/src/pymodaq_utils/config.py +4 -3
- {pymodaq_utils-5.3.7 → pymodaq_utils-5.3.9}/src/pymodaq_utils/enums.py +12 -9
- {pymodaq_utils-5.3.7 → pymodaq_utils-5.3.9}/src/pymodaq_utils/math_utils.py +1 -1
- pymodaq_utils-5.3.9/src/pymodaq_utils/serialize/__init__.py +0 -0
- {pymodaq_utils-5.3.7 → pymodaq_utils-5.3.9}/src/pymodaq_utils/utils.py +97 -13
- {pymodaq_utils-5.3.7 → pymodaq_utils-5.3.9}/.gitignore +0 -0
- {pymodaq_utils-5.3.7 → pymodaq_utils-5.3.9}/LICENSE +0 -0
- {pymodaq_utils-5.3.7 → pymodaq_utils-5.3.9}/README.rst +0 -0
- {pymodaq_utils-5.3.7 → pymodaq_utils-5.3.9}/pyproject.toml +0 -0
- {pymodaq_utils-5.3.7 → pymodaq_utils-5.3.9}/src/pymodaq_utils/__init__.py +0 -0
- {pymodaq_utils-5.3.7 → pymodaq_utils-5.3.9}/src/pymodaq_utils/array_manipulation.py +0 -0
- {pymodaq_utils-5.3.7 → pymodaq_utils-5.3.9}/src/pymodaq_utils/categorizing.py +0 -0
- {pymodaq_utils-5.3.7 → pymodaq_utils-5.3.9}/src/pymodaq_utils/environment.py +0 -0
- {pymodaq_utils-5.3.7 → pymodaq_utils-5.3.9}/src/pymodaq_utils/factory.py +0 -0
- {pymodaq_utils-5.3.7 → pymodaq_utils-5.3.9}/src/pymodaq_utils/help.py +0 -0
- {pymodaq_utils-5.3.7 → pymodaq_utils-5.3.9}/src/pymodaq_utils/icon.ico +0 -0
- {pymodaq_utils-5.3.7 → pymodaq_utils-5.3.9}/src/pymodaq_utils/logger.py +0 -0
- {pymodaq_utils-5.3.7 → pymodaq_utils-5.3.9}/src/pymodaq_utils/mysocket.py +0 -0
- {pymodaq_utils-5.3.7 → pymodaq_utils-5.3.9}/src/pymodaq_utils/packages.py +0 -0
- {pymodaq_utils-5.3.7 → pymodaq_utils-5.3.9}/src/pymodaq_utils/plugin_checks.py +0 -0
- {pymodaq_utils-5.3.7 → pymodaq_utils-5.3.9}/src/pymodaq_utils/plugin_rules.py +0 -0
- {pymodaq_utils-5.3.7 → pymodaq_utils-5.3.9}/src/pymodaq_utils/plugin_scaffold.py +0 -0
- {pymodaq_utils-5.3.7 → pymodaq_utils-5.3.9}/src/pymodaq_utils/plugin_testing.py +0 -0
- {pymodaq_utils-5.3.7 → pymodaq_utils-5.3.9}/src/pymodaq_utils/plugin_tools/__init__.py +0 -0
- {pymodaq_utils-5.3.7 → pymodaq_utils-5.3.9}/src/pymodaq_utils/plugin_tools/checks.py +0 -0
- {pymodaq_utils-5.3.7 → pymodaq_utils-5.3.9}/src/pymodaq_utils/plugin_tools/contract.py +0 -0
- {pymodaq_utils-5.3.7 → pymodaq_utils-5.3.9}/src/pymodaq_utils/plugin_tools/extension_checks.py +0 -0
- {pymodaq_utils-5.3.7 → pymodaq_utils-5.3.9}/src/pymodaq_utils/plugin_tools/platforms.py +0 -0
- {pymodaq_utils-5.3.7 → pymodaq_utils-5.3.9}/src/pymodaq_utils/plugin_tools/rules.py +0 -0
- {pymodaq_utils-5.3.7 → pymodaq_utils-5.3.9}/src/pymodaq_utils/plugin_tools/scaffold.py +0 -0
- /pymodaq_utils-5.3.7/src/pymodaq_utils/resources/__init__.py → /pymodaq_utils-5.3.9/src/pymodaq_utils/py.typed +0 -0
- {pymodaq_utils-5.3.7/src/pymodaq_utils/serialize → pymodaq_utils-5.3.9/src/pymodaq_utils/resources}/__init__.py +0 -0
- {pymodaq_utils-5.3.7 → pymodaq_utils-5.3.9}/src/pymodaq_utils/resources/config_template.toml +0 -0
- {pymodaq_utils-5.3.7 → pymodaq_utils-5.3.9}/src/pymodaq_utils/resources/hatch_build_plugins.py +0 -0
- {pymodaq_utils-5.3.7 → pymodaq_utils-5.3.9}/src/pymodaq_utils/serialize/factory.py +0 -0
- {pymodaq_utils-5.3.7 → pymodaq_utils-5.3.9}/src/pymodaq_utils/serialize/mysocket.py +0 -0
- {pymodaq_utils-5.3.7 → pymodaq_utils-5.3.9}/src/pymodaq_utils/serialize/serializer.py +0 -0
- {pymodaq_utils-5.3.7 → pymodaq_utils-5.3.9}/src/pymodaq_utils/serialize/serializer_legacy.py +0 -0
- {pymodaq_utils-5.3.7 → pymodaq_utils-5.3.9}/src/pymodaq_utils/serialize/utils.py +0 -0
- {pymodaq_utils-5.3.7 → pymodaq_utils-5.3.9}/src/pymodaq_utils/singleton.py +0 -0
- {pymodaq_utils-5.3.7 → pymodaq_utils-5.3.9}/src/pymodaq_utils/splash.png +0 -0
- {pymodaq_utils-5.3.7 → pymodaq_utils-5.3.9}/src/pymodaq_utils/units.py +0 -0
- {pymodaq_utils-5.3.7 → pymodaq_utils-5.3.9}/src/pymodaq_utils/warnings.py +0 -0
|
@@ -10,7 +10,7 @@ See https://stackoverflow.com/a/50381071/8090831
|
|
|
10
10
|
|
|
11
11
|
from abc import ABCMeta as NativeABCMeta
|
|
12
12
|
from abc import abstractmethod
|
|
13
|
-
from typing import cast, Any, Callable, TypeVar
|
|
13
|
+
from typing import cast, Any, Callable, Optional, TypeVar
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
R = TypeVar('R')
|
|
@@ -20,7 +20,11 @@ class DummyAttribute:
|
|
|
20
20
|
pass
|
|
21
21
|
|
|
22
22
|
|
|
23
|
-
def abstract_attribute(obj: Callable[[Any], R] = None) -> R:
|
|
23
|
+
def abstract_attribute(obj: Optional[Callable[[Any], R]] = None) -> R:
|
|
24
|
+
"""Declare an attribute that subclasses have to define, checked when instantiating (see ABCMeta)
|
|
25
|
+
|
|
26
|
+
Use it as a decorator on a property or call it without argument: ``name = abstract_attribute()``.
|
|
27
|
+
"""
|
|
24
28
|
_obj = cast(Any, obj)
|
|
25
29
|
if obj is None:
|
|
26
30
|
_obj = DummyAttribute()
|
|
@@ -10,7 +10,7 @@ from os import environ
|
|
|
10
10
|
import sys
|
|
11
11
|
import datetime
|
|
12
12
|
from pathlib import Path
|
|
13
|
-
from typing import Union, Dict, TypeVar, Any, List, TYPE_CHECKING, Callable, Type
|
|
13
|
+
from typing import Optional, Union, Dict, TypeVar, Any, List, TYPE_CHECKING, Callable, Type
|
|
14
14
|
from typing import Iterable as IterableType
|
|
15
15
|
|
|
16
16
|
from pymodaq_utils import warnings
|
|
@@ -209,8 +209,8 @@ def check_config(config_base: dict, config_local: dict):
|
|
|
209
209
|
return status
|
|
210
210
|
|
|
211
211
|
|
|
212
|
-
def copy_template_config(config_file_name: str = 'config', source_path: Union[Path, str] = None,
|
|
213
|
-
dest_path: Union[Path, str] = None):
|
|
212
|
+
def copy_template_config(config_file_name: str = 'config', source_path: Optional[Union[Path, str]] = None,
|
|
213
|
+
dest_path: Optional[Union[Path, str]] = None):
|
|
214
214
|
"""Get a toml file path and copy it
|
|
215
215
|
|
|
216
216
|
the destination is made of a given folder path (or the system-wide local path by default) and the config_file_name
|
|
@@ -233,6 +233,7 @@ def copy_template_config(config_file_name: str = 'config', source_path: Union[Pa
|
|
|
233
233
|
"""
|
|
234
234
|
if dest_path is None:
|
|
235
235
|
dest_path = get_set_config_dir('config')
|
|
236
|
+
dest_path = Path(dest_path)
|
|
236
237
|
|
|
237
238
|
file_name = Path(config_file_name).stem # remove eventual extensions
|
|
238
239
|
file_name += '.toml'
|
|
@@ -1,16 +1,15 @@
|
|
|
1
|
-
import
|
|
2
|
-
from packaging.version import Version
|
|
1
|
+
import sys
|
|
3
2
|
|
|
4
|
-
if
|
|
5
|
-
from strenum import StrEnum
|
|
3
|
+
if sys.version_info < (3, 11):
|
|
4
|
+
from strenum import StrEnum as _StrEnum
|
|
6
5
|
else:
|
|
7
|
-
from enum import StrEnum
|
|
6
|
+
from enum import StrEnum as _StrEnum
|
|
8
7
|
|
|
9
8
|
from enum import Enum, auto # noqa # pylint: disable=unused-import
|
|
10
|
-
from typing import List, Union
|
|
9
|
+
from typing import List, Type, TypeVar, Union
|
|
11
10
|
|
|
12
11
|
|
|
13
|
-
class StrEnum(
|
|
12
|
+
class StrEnum(_StrEnum): #to be imported in other modules
|
|
14
13
|
@classmethod
|
|
15
14
|
def names(cls) -> List[str]:
|
|
16
15
|
"""Returns all the names of the enum"""
|
|
@@ -60,7 +59,10 @@ class BaseEnum(Enum):
|
|
|
60
59
|
return super().__eq__(other)
|
|
61
60
|
|
|
62
61
|
|
|
63
|
-
|
|
62
|
+
EnumT = TypeVar('EnumT', bound=BaseEnum)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def enum_checker(enum: Type[EnumT], item: Union[EnumT, str]) -> EnumT:
|
|
64
66
|
"""Check if the item parameter is a valid enum or at least one valid string name of the enum
|
|
65
67
|
|
|
66
68
|
If a string, transforms it to a valid enum (case not important)
|
|
@@ -73,7 +75,8 @@ def enum_checker(enum: BaseEnum, item: Union[BaseEnum, str]):
|
|
|
73
75
|
|
|
74
76
|
Returns
|
|
75
77
|
-------
|
|
76
|
-
BaseEnum
|
|
78
|
+
BaseEnum
|
|
79
|
+
The member of the ``enum`` class corresponding to item
|
|
77
80
|
"""
|
|
78
81
|
|
|
79
82
|
if not isinstance(item, enum):
|
|
@@ -174,7 +174,7 @@ def linspace_step_N(start, step, Npts):
|
|
|
174
174
|
return linspace_step(start, stop, step)
|
|
175
175
|
|
|
176
176
|
|
|
177
|
-
def find_index(x, threshold: Union[Number, List[Number]]) -> List[tuple]:
|
|
177
|
+
def find_index(x, threshold: Union[float, Number, List[Union[float, Number]]]) -> List[tuple]:
|
|
178
178
|
"""find_index finds the index ix such that x(ix) is the closest from threshold
|
|
179
179
|
|
|
180
180
|
Parameters
|
|
File without changes
|
|
@@ -9,7 +9,7 @@ import time
|
|
|
9
9
|
from packaging import version as version_mod
|
|
10
10
|
from pathlib import Path
|
|
11
11
|
import traceback
|
|
12
|
-
from typing import Any, cast, List, Optional, Tuple
|
|
12
|
+
from typing import Any, cast, List, Optional, Sequence, Tuple, Union
|
|
13
13
|
|
|
14
14
|
import numpy as np
|
|
15
15
|
|
|
@@ -35,7 +35,8 @@ ser_factory = SerializableFactory()
|
|
|
35
35
|
config = Config()
|
|
36
36
|
|
|
37
37
|
|
|
38
|
-
def is_64bits():
|
|
38
|
+
def is_64bits() -> bool:
|
|
39
|
+
"""Return True if the running Python interpreter is a 64 bits one"""
|
|
39
40
|
return sys.maxsize > 2**32
|
|
40
41
|
|
|
41
42
|
|
|
@@ -59,25 +60,41 @@ def get_version(package_name='pymodaq'):
|
|
|
59
60
|
|
|
60
61
|
|
|
61
62
|
class JsonConverter:
|
|
63
|
+
"""Convert simple python objects to and from a json string
|
|
64
|
+
|
|
65
|
+
The json string holds the module, type and ``repr`` of the object. Only the types listed in
|
|
66
|
+
:meth:`trusted_types` are rebuilt when converting back.
|
|
67
|
+
"""
|
|
62
68
|
def __init__(self):
|
|
63
69
|
super().__init__()
|
|
64
70
|
|
|
65
71
|
@classmethod
|
|
66
|
-
def trusted_types(cls):
|
|
72
|
+
def trusted_types(cls) -> list[str]:
|
|
73
|
+
"""Names of the types :meth:`json2object` is allowed to rebuild"""
|
|
67
74
|
return ['float', 'int', 'str', 'datetime', 'date', 'time', 'tuple', 'list', 'bool', 'bytes',
|
|
68
75
|
'float64']
|
|
69
76
|
|
|
70
77
|
@classmethod
|
|
71
|
-
def istrusted(cls, type_name):
|
|
78
|
+
def istrusted(cls, type_name: str) -> bool:
|
|
79
|
+
"""Return True if ``type_name`` is one of the :meth:`trusted_types`"""
|
|
72
80
|
return type_name in cls.trusted_types()
|
|
73
81
|
|
|
74
82
|
@classmethod
|
|
75
|
-
def object2json(cls, obj):
|
|
83
|
+
def object2json(cls, obj: Any) -> str:
|
|
84
|
+
"""Return a json string with the module, type name and repr of ``obj``"""
|
|
76
85
|
dic = dict(module=type(obj).__module__, type=type(obj).__name__, data=repr(obj))
|
|
77
86
|
return json.dumps(dic)
|
|
78
87
|
|
|
79
88
|
@classmethod
|
|
80
|
-
def json2object(cls, jsonstring):
|
|
89
|
+
def json2object(cls, jsonstring: Any) -> Any:
|
|
90
|
+
"""Rebuild an object from the json string created by :meth:`object2json`
|
|
91
|
+
|
|
92
|
+
Returns
|
|
93
|
+
-------
|
|
94
|
+
Any
|
|
95
|
+
The object if its type is trusted, otherwise the decoded dict. If ``jsonstring`` cannot be
|
|
96
|
+
decoded, it is returned unchanged.
|
|
97
|
+
"""
|
|
81
98
|
try:
|
|
82
99
|
dic = json.loads(jsonstring)
|
|
83
100
|
if isinstance(dic, dict):
|
|
@@ -105,7 +122,8 @@ def capitalize(string, Nfirst=1):
|
|
|
105
122
|
return string[:Nfirst].upper() + string[Nfirst:]
|
|
106
123
|
|
|
107
124
|
|
|
108
|
-
def uncapitalize(string, Nfirst=1):
|
|
125
|
+
def uncapitalize(string: str, Nfirst: int = 1) -> str:
|
|
126
|
+
"""Return the same string but with its first ``Nfirst`` letters in lower case"""
|
|
109
127
|
return string[:Nfirst].lower() + string[Nfirst:]
|
|
110
128
|
|
|
111
129
|
|
|
@@ -167,6 +185,7 @@ class ThreadCommand(SerializableBase):
|
|
|
167
185
|
|
|
168
186
|
@staticmethod
|
|
169
187
|
def serialize(obj: "ThreadCommand") -> bytes: # type: ignore[override]
|
|
188
|
+
"""Serialize the command, attribute, args and kwargs of a ThreadCommand into bytes"""
|
|
170
189
|
serialize_factory = SerializableFactory()
|
|
171
190
|
byte_string = b""
|
|
172
191
|
byte_string += serialize_factory.get_apply_serializer(obj.command)
|
|
@@ -177,6 +196,13 @@ class ThreadCommand(SerializableBase):
|
|
|
177
196
|
|
|
178
197
|
@staticmethod
|
|
179
198
|
def deserialize(bytes_str: bytes) -> Tuple["ThreadCommand", bytes]:
|
|
199
|
+
"""Rebuild a ThreadCommand from bytes created by :meth:`serialize`
|
|
200
|
+
|
|
201
|
+
Returns
|
|
202
|
+
-------
|
|
203
|
+
tuple
|
|
204
|
+
The ThreadCommand and the remaining bytes that were not consumed.
|
|
205
|
+
"""
|
|
180
206
|
serialize_factory = SerializableFactory()
|
|
181
207
|
command, remaining = cast(
|
|
182
208
|
Tuple[str, bytes],
|
|
@@ -219,6 +245,10 @@ def ensure_ndarray(data):
|
|
|
219
245
|
|
|
220
246
|
|
|
221
247
|
def recursive_find_files_extension(ini_path, ext, paths=[]):
|
|
248
|
+
"""Collect the paths of all files with the extension ``ext`` (without dot) below ``ini_path``
|
|
249
|
+
|
|
250
|
+
Note that ``paths`` is shared between calls when not given (mutable default): pass a new list.
|
|
251
|
+
"""
|
|
222
252
|
with os.scandir(ini_path) as it:
|
|
223
253
|
for entry in it:
|
|
224
254
|
if os.path.splitext(entry.name)[1][1:] == ext and entry.is_file():
|
|
@@ -230,6 +260,11 @@ def recursive_find_files_extension(ini_path, ext, paths=[]):
|
|
|
230
260
|
|
|
231
261
|
def recursive_find_files(ini_path, exp='make_enum', paths=[],
|
|
232
262
|
filters=['build']):
|
|
263
|
+
"""Collect the paths of all files below ``ini_path`` whose name (without extension) contains ``exp``
|
|
264
|
+
|
|
265
|
+
Paths containing one of the ``filters`` strings are skipped. As in
|
|
266
|
+
:func:`recursive_find_files_extension`, pass a new list as ``paths``.
|
|
267
|
+
"""
|
|
233
268
|
for child in Path(ini_path).iterdir():
|
|
234
269
|
if child.is_dir():
|
|
235
270
|
recursive_find_files(child, exp, paths, filters)
|
|
@@ -243,7 +278,13 @@ def recursive_find_files(ini_path, exp='make_enum', paths=[],
|
|
|
243
278
|
def recursive_find_expr_in_files(ini_path, exp='make_enum', paths=[],
|
|
244
279
|
filters=['.git', '.idea', '__pycache__', 'build', 'egg', 'documentation', '.tox'],
|
|
245
280
|
replace=False, replace_str=''):
|
|
281
|
+
"""Search the text ``exp`` in the files below ``ini_path``
|
|
246
282
|
|
|
283
|
+
Each match is appended to ``paths`` as ``[file path, line index, line]``. Paths containing one of the
|
|
284
|
+
``filters`` strings are skipped and unreadable files are ignored. If ``replace`` is True the matches
|
|
285
|
+
are replaced in the files by ``replace_str``. As in :func:`recursive_find_files_extension`, pass a new
|
|
286
|
+
list as ``paths``.
|
|
287
|
+
"""
|
|
247
288
|
for child in Path(ini_path).iterdir():
|
|
248
289
|
if not any(filt in str(child) for filt in filters):
|
|
249
290
|
if child.is_dir():
|
|
@@ -271,6 +312,10 @@ def recursive_find_expr_in_files(ini_path, exp='make_enum', paths=[],
|
|
|
271
312
|
|
|
272
313
|
|
|
273
314
|
def count_lines(ini_path, count=0, filters=['lextab', 'yacctab','pycache', 'pyc']):
|
|
315
|
+
"""Count the lines of the python files below ``ini_path``, starting from ``count``
|
|
316
|
+
|
|
317
|
+
The names of the files skipped because of ``filters`` are printed.
|
|
318
|
+
"""
|
|
274
319
|
# if Path(ini_path).is_file():
|
|
275
320
|
# with Path(ini_path).open('r') as f:
|
|
276
321
|
# count += len(f.readlines())
|
|
@@ -320,6 +365,16 @@ def rint(x):
|
|
|
320
365
|
|
|
321
366
|
|
|
322
367
|
def elt_as_first_element(elt_list, match_word='Mock'):
|
|
368
|
+
"""Return a list of str with the first one containing ``match_word`` moved to the front
|
|
369
|
+
|
|
370
|
+
The first element is kept in front if none matches. Note that the matching element is removed from
|
|
371
|
+
``elt_list`` itself, which is modified.
|
|
372
|
+
|
|
373
|
+
Raises
|
|
374
|
+
------
|
|
375
|
+
TypeError
|
|
376
|
+
If ``elt_list`` is not an iterable of str.
|
|
377
|
+
"""
|
|
323
378
|
if not hasattr(elt_list, '__iter__'):
|
|
324
379
|
raise TypeError('elt_list must be an iterable')
|
|
325
380
|
if elt_list:
|
|
@@ -340,6 +395,13 @@ def elt_as_first_element(elt_list, match_word='Mock'):
|
|
|
340
395
|
|
|
341
396
|
|
|
342
397
|
def elt_as_first_element_dicts(elt_list, match_word='Mock', key='name'):
|
|
398
|
+
"""Same as :func:`elt_as_first_element` for a list of dicts, matching ``match_word`` in ``elt[key]``
|
|
399
|
+
|
|
400
|
+
Raises
|
|
401
|
+
------
|
|
402
|
+
TypeError
|
|
403
|
+
If ``elt_list`` is not an iterable of dict.
|
|
404
|
+
"""
|
|
343
405
|
if not hasattr(elt_list, '__iter__'):
|
|
344
406
|
raise TypeError('elt_list must be an iterable')
|
|
345
407
|
if elt_list:
|
|
@@ -386,7 +448,7 @@ def find_object_if_matched_attr_name_val(obj, attr_name, attr_value):
|
|
|
386
448
|
return False
|
|
387
449
|
|
|
388
450
|
|
|
389
|
-
def find_objects_in_list_from_attr_name_val(objects:
|
|
451
|
+
def find_objects_in_list_from_attr_name_val(objects: Sequence[Any], attr_name: str,
|
|
390
452
|
attr_value: object, return_first=True):
|
|
391
453
|
""" lookup within a list of objects. Look for the objects within the list which has the correct attribute name,
|
|
392
454
|
value pair
|
|
@@ -504,13 +566,14 @@ def get_entrypoints(group='pymodaq.plugins') -> List[metadata.EntryPoint]:
|
|
|
504
566
|
group: str
|
|
505
567
|
the name of the group
|
|
506
568
|
"""
|
|
569
|
+
discovered_entrypoints: Any
|
|
507
570
|
try:
|
|
508
571
|
discovered_entrypoints = metadata.entry_points(group=group)
|
|
509
572
|
except TypeError:
|
|
510
573
|
try:
|
|
511
574
|
discovered_entrypoints = metadata.entry_points().select(group=group)
|
|
512
575
|
except AttributeError:
|
|
513
|
-
discovered_entrypoints = metadata.entry_points().get(group, [])
|
|
576
|
+
discovered_entrypoints = metadata.entry_points().get(group, []) # type: ignore[attr-defined] # Python < 3.10
|
|
514
577
|
if isinstance(discovered_entrypoints, tuple): # API for python > 3.8
|
|
515
578
|
discovered_entrypoints = list(discovered_entrypoints)
|
|
516
579
|
if not isinstance(discovered_entrypoints, list):
|
|
@@ -518,7 +581,8 @@ def get_entrypoints(group='pymodaq.plugins') -> List[metadata.EntryPoint]:
|
|
|
518
581
|
return discovered_entrypoints
|
|
519
582
|
|
|
520
583
|
|
|
521
|
-
def check_vals_in_iterable(iterable1, iterable2):
|
|
584
|
+
def check_vals_in_iterable(iterable1, iterable2) -> None:
|
|
585
|
+
"""Assert that two iterables (list, tuple, ndarray...) have the same length and equal values"""
|
|
522
586
|
assert len(iterable1) == len(iterable2)
|
|
523
587
|
iterable1 = list(iterable1) # so the assertion below is valid for any kind of iterable, list, tuple, ndarray...
|
|
524
588
|
iterable2 = list(iterable2)
|
|
@@ -582,7 +646,15 @@ def zeros_aligned(n, align, dtype=np.uint32):
|
|
|
582
646
|
# ########################
|
|
583
647
|
# #File management
|
|
584
648
|
|
|
585
|
-
def get_new_file_name(base_path: Path, base_name: str = 'tttr_data'):
|
|
649
|
+
def get_new_file_name(base_path: Union[Path, str], base_name: str = 'tttr_data') -> Tuple[str, Path]:
|
|
650
|
+
"""Get the name of a new file in the folder ``<base_path>/<year>/<date>`` (created if needed)
|
|
651
|
+
|
|
652
|
+
Returns
|
|
653
|
+
-------
|
|
654
|
+
tuple
|
|
655
|
+
The file name without extension, ``<base_name>_NNN`` with NNN the index following the last existing
|
|
656
|
+
file starting with ``base_name`` in the folder, and the path of the folder.
|
|
657
|
+
"""
|
|
586
658
|
if isinstance(base_path, str):
|
|
587
659
|
base_path = Path(base_path)
|
|
588
660
|
|
|
@@ -614,16 +686,28 @@ def get_module_path(module_name: str) -> Path:
|
|
|
614
686
|
""" Get Path of a given module represented by its name
|
|
615
687
|
|
|
616
688
|
You get the name usually with the dunder __module__ on an object or class
|
|
689
|
+
|
|
690
|
+
Raises
|
|
691
|
+
------
|
|
692
|
+
TypeError
|
|
693
|
+
If the module has no file (namespace package or built-in module)
|
|
617
694
|
"""
|
|
618
695
|
module = sys.modules[module_name]
|
|
696
|
+
if module.__file__ is None:
|
|
697
|
+
raise TypeError(f'The module {module_name} has no file (namespace package or built-in module)')
|
|
619
698
|
return Path(module.__file__)
|
|
620
699
|
|
|
621
700
|
def format_dir_path(path: Path) -> str:
|
|
622
|
-
|
|
623
|
-
|
|
701
|
+
"""Return ``path`` as a str, with the separator of the OS appended if it is an existing folder"""
|
|
702
|
+
dir_trailing_symbol = '\\' if sys.platform == 'win32' else '/'
|
|
703
|
+
return f'{path}{dir_trailing_symbol if path.is_dir() else ""}'
|
|
624
704
|
|
|
625
705
|
|
|
626
706
|
def read_binary_and_deserialize(fname: Path) -> list[SerializableBase]:
|
|
707
|
+
"""Deserialize all the objects stored one after the other in a binary file
|
|
708
|
+
|
|
709
|
+
Returns an empty list if the file does not exist.
|
|
710
|
+
"""
|
|
627
711
|
if not fname.exists():
|
|
628
712
|
return []
|
|
629
713
|
with open(fname, 'rb') as file:
|
|
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
|
{pymodaq_utils-5.3.7 → pymodaq_utils-5.3.9}/src/pymodaq_utils/plugin_tools/extension_checks.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pymodaq_utils-5.3.7 → pymodaq_utils-5.3.9}/src/pymodaq_utils/resources/config_template.toml
RENAMED
|
File without changes
|
{pymodaq_utils-5.3.7 → pymodaq_utils-5.3.9}/src/pymodaq_utils/resources/hatch_build_plugins.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pymodaq_utils-5.3.7 → pymodaq_utils-5.3.9}/src/pymodaq_utils/serialize/serializer_legacy.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|