jetpytools 1.4.0__py3-none-any.whl → 1.6.0__py3-none-any.whl

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.

Potentially problematic release.


This version of jetpytools might be problematic. Click here for more details.

@@ -1,31 +1,32 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import sys
3
4
  from fractions import Fraction
4
5
  from typing import Any, Callable, Iterable, Iterator, Sequence, overload
5
6
 
7
+ from ..exceptions import CustomOverflowError
6
8
  from ..types import SoftRange, SoftRangeN, SoftRangesN, StrictRange, SupportsString, T, is_soft_range_n
7
9
 
8
10
  __all__ = [
9
- 'normalize_seq',
10
- 'to_arr',
11
- 'flatten',
12
- 'normalize_list_to_ranges',
13
- 'normalize_ranges_to_list',
14
- 'normalize_range',
15
- 'normalize_ranges',
16
- 'invert_ranges',
17
- 'norm_func_name', 'norm_display_name'
11
+ "flatten",
12
+ "invert_ranges",
13
+ "norm_display_name",
14
+ "norm_func_name",
15
+ "normalize_list_to_ranges",
16
+ "normalize_range",
17
+ "normalize_ranges",
18
+ "normalize_ranges_to_list",
19
+ "normalize_seq",
20
+ "to_arr",
18
21
  ]
19
22
 
20
23
 
21
24
  @overload
22
- def normalize_seq(val: T | Sequence[T], length: int) -> list[T]:
23
- ...
25
+ def normalize_seq(val: T | Sequence[T], length: int) -> list[T]: ...
24
26
 
25
27
 
26
28
  @overload
27
- def normalize_seq(val: Any, length: int) -> list[Any]:
28
- ...
29
+ def normalize_seq(val: Any, length: int) -> list[Any]: ...
29
30
 
30
31
 
31
32
  def normalize_seq(val: T | Sequence[T], length: int) -> list[T]:
@@ -48,13 +49,11 @@ def normalize_seq(val: T | Sequence[T], length: int) -> list[T]:
48
49
 
49
50
 
50
51
  @overload
51
- def to_arr(val: T | Iterable[T]) -> list[T]:
52
- ...
52
+ def to_arr(val: T | Iterable[T]) -> list[T]: ...
53
53
 
54
54
 
55
55
  @overload
56
- def to_arr(val: Any) -> list[Any]:
57
- ...
56
+ def to_arr(val: Any) -> list[Any]: ...
58
57
 
59
58
 
60
59
  def to_arr(val: Any, *, sub: Any = []) -> list[Any]:
@@ -64,19 +63,18 @@ def to_arr(val: Any, *, sub: Any = []) -> list[Any]:
64
63
  """
65
64
  if sub:
66
65
  import warnings
66
+
67
67
  warnings.warn("sub is deprecated.", DeprecationWarning)
68
68
 
69
69
  return list(val) if (isinstance(val, Iterable) and not isinstance(val, (str, bytes))) else [val]
70
70
 
71
71
 
72
72
  @overload
73
- def flatten(items: Iterable[Iterable[T]]) -> Iterator[T]:
74
- ...
73
+ def flatten(items: Iterable[Iterable[T]]) -> Iterator[T]: ...
75
74
 
76
75
 
77
76
  @overload
78
- def flatten(items: Iterable[Any]) -> Iterator[Any]:
79
- ...
77
+ def flatten(items: Iterable[Any]) -> Iterator[Any]: ...
80
78
 
81
79
 
82
80
  def flatten(items: Any) -> Iterator[Any]:
@@ -93,11 +91,13 @@ def flatten(items: Any) -> Iterator[Any]:
93
91
  yield val
94
92
 
95
93
 
96
- def normalize_range(ranges: SoftRange, /) -> Iterable[int]:
94
+ def normalize_range(ranges: SoftRange, /, exclusive: bool = False) -> Sequence[int]:
97
95
  """
98
96
  Normalize ranges represented by a tuple to an iterable of frame numbers.
99
97
 
100
98
  :param ranges: Ranges to normalize.
99
+ :param exclusive: Whether to use exclusive (Python-style) ranges.
100
+ Defaults to False.
101
101
 
102
102
  :return: List of positive frame ranges.
103
103
  """
@@ -109,22 +109,21 @@ def normalize_range(ranges: SoftRange, /) -> Iterable[int]:
109
109
  start, stop = ranges
110
110
  step = -1 if stop < start else 1
111
111
 
112
- return range(start, stop + step, step)
112
+ return range(start, stop + (not exclusive * step), step)
113
113
 
114
114
  return ranges
115
115
 
116
116
 
117
- def normalize_list_to_ranges(flist: Iterable[int], min_length: int = 0) -> list[StrictRange]:
117
+ def normalize_list_to_ranges(flist: Iterable[int], min_length: int = 0, exclusive: bool = False) -> list[StrictRange]:
118
118
  flist2 = list[list[int]]()
119
119
  flist3 = list[int]()
120
120
 
121
121
  prev_n = -1
122
122
 
123
123
  for n in sorted(set(flist)):
124
- if prev_n + 1 != n:
125
- if flist3:
126
- flist2.append(flist3)
127
- flist3 = []
124
+ if prev_n + 1 != n and flist3:
125
+ flist2.append(flist3)
126
+ flist3.clear()
128
127
  flist3.append(n)
129
128
  prev_n = n
130
129
 
@@ -133,22 +132,21 @@ def normalize_list_to_ranges(flist: Iterable[int], min_length: int = 0) -> list[
133
132
 
134
133
  flist4 = [i for i in flist2 if len(i) > min_length]
135
134
 
136
- return list(zip(
137
- [i[0] for i in flist4],
138
- [i[-1] for j, i in enumerate(flist4)]
139
- ))
135
+ return list(zip([i[0] for i in flist4], [i[-1] + exclusive for i in flist4]))
140
136
 
141
137
 
142
- def normalize_ranges_to_list(ranges: Iterable[SoftRange]) -> list[int]:
138
+ def normalize_ranges_to_list(ranges: Iterable[SoftRange], exclusive: bool = False) -> list[int]:
143
139
  out = list[int]()
144
140
 
145
141
  for srange in ranges:
146
- out.extend(normalize_range(srange))
142
+ out.extend(normalize_range(srange, exclusive))
147
143
 
148
144
  return out
149
145
 
150
146
 
151
- def normalize_ranges(ranges: SoftRangeN | SoftRangesN, end: int) -> list[StrictRange]:
147
+ def normalize_ranges(
148
+ ranges: SoftRangeN | SoftRangesN, length: int, exclusive: bool = False, *, strict: bool = True
149
+ ) -> list[StrictRange]:
152
150
  """
153
151
  Normalize ranges to a list of positive ranges.
154
152
 
@@ -160,57 +158,105 @@ def normalize_ranges(ranges: SoftRangeN | SoftRangesN, end: int) -> list[StrictR
160
158
 
161
159
  .. code-block:: python
162
160
 
163
- >>> normalize_ranges((None, None), end=1000)
161
+ >>> normalize_ranges((None, None), length=1000)
164
162
  [(0, 999)]
165
- >>> normalize_ranges((24, -24), end=1000)
163
+ >>> normalize_ranges((24, -24), length=1000)
166
164
  [(24, 975)]
167
- >>> normalize_ranges([(24, 100), (80, 150)], end=1000)
165
+ >>> normalize_ranges([(24, 100), (80, 150)], length=1000)
168
166
  [(24, 150)]
169
167
 
170
168
 
171
- :param franges: Frame range or list of frame ranges.
172
- :param end: End number.
169
+ :param ranges: Frame range or list of frame ranges.
170
+ :param length: Number of frames.
171
+ :param exclusive: Whether to use exclusive (Python-style) ranges.
172
+ Defaults to False.
173
+ :param strict: Whether to enforce strict checking for out-of-range values.
173
174
 
174
175
  :return: List of positive frame ranges.
175
176
  """
177
+ from ..utils import clamp
176
178
 
177
179
  ranges = [ranges] if is_soft_range_n(ranges) else ranges
178
180
 
179
- out = []
181
+ out = list[tuple[int, int]]()
182
+ exceptions = list[Exception]()
180
183
 
181
184
  for r in ranges:
182
185
  if r is None:
183
186
  r = (None, None)
184
187
 
185
188
  if isinstance(r, tuple):
186
- start, endd = r
189
+ start, end = r
187
190
  if start is None:
188
191
  start = 0
189
- if endd is None:
190
- endd = end - 1
192
+ if end is None:
193
+ end = length - (not exclusive)
191
194
  else:
192
195
  start = r
193
- endd = r
196
+ end = r + exclusive
194
197
 
195
198
  if start < 0:
196
- start = end - 1 + start
199
+ start = length + start
200
+
201
+ if end < 0:
202
+ end = length + end - (not exclusive)
203
+
204
+ # Always throws an error if start and end are negative
205
+ # or higher than length
206
+ # or start is higher than end (likely mismatched)
207
+ if any(
208
+ [
209
+ start < 0 and end < 0,
210
+ start >= length and end - (not exclusive) > length,
211
+ start >= end + (not exclusive),
212
+ ]
213
+ ):
214
+ exception = CustomOverflowError(
215
+ f"Range `{r}` with length `{length}` could not be normalized!", normalize_ranges
216
+ )
217
+ exceptions.append(exception)
218
+ continue
219
+
220
+ if strict:
221
+ if start < 0:
222
+ exception = CustomOverflowError(
223
+ f"Start frame `{start}` in range `{r}` with length `{length}` could not be normalized!",
224
+ normalize_ranges,
225
+ )
226
+ exceptions.append(exception)
227
+ continue
228
+ if end - (not exclusive) > length:
229
+ exception = CustomOverflowError(
230
+ f"End frame `{end}` in range `{r}` with length `{length}` could not be normalized!",
231
+ normalize_ranges,
232
+ )
233
+ exceptions.append(exception)
234
+ continue
235
+ else:
236
+ start = clamp(start, 0, length - 1)
237
+ end = clamp(end, int(exclusive), length - (not exclusive))
238
+
239
+ out.append((start, end))
197
240
 
198
- if endd < 0:
199
- endd = end - 1 + endd
241
+ if exceptions:
242
+ if sys.version_info >= (3, 11):
243
+ raise ExceptionGroup("Multiple exceptions occurred!", exceptions) # noqa: F821
200
244
 
201
- out.append((start, endd))
245
+ raise Exception(exceptions)
202
246
 
203
- return normalize_list_to_ranges([
204
- x for start, endd in out for x in range(start, endd + 1)
205
- ])
247
+ return normalize_list_to_ranges(
248
+ [x for start, end in out for x in range(start, end + (not exclusive))], exclusive=exclusive
249
+ )
206
250
 
207
251
 
208
- def invert_ranges(ranges: SoftRangeN | SoftRangesN, enda: int, endb: int | None) -> list[StrictRange]:
209
- norm_ranges = normalize_ranges(ranges, enda if endb is None else endb)
252
+ def invert_ranges(
253
+ ranges: SoftRangeN | SoftRangesN, lengtha: int, lengthb: int | None, exclusive: bool = False
254
+ ) -> list[StrictRange]:
255
+ norm_ranges = normalize_ranges(ranges, lengtha if lengthb is None else lengthb, exclusive)
210
256
 
211
- b_frames = {*normalize_ranges_to_list(norm_ranges)}
257
+ b_frames = {*normalize_ranges_to_list(norm_ranges, exclusive)}
212
258
 
213
- return normalize_list_to_ranges({*range(enda)} - b_frames)
259
+ return normalize_list_to_ranges({*range(lengtha)} - b_frames, exclusive=exclusive)
214
260
 
215
261
 
216
262
  def norm_func_name(func_name: SupportsString | Callable[..., Any]) -> str:
@@ -224,15 +270,14 @@ def norm_func_name(func_name: SupportsString | Callable[..., Any]) -> str:
224
270
 
225
271
  func = func_name
226
272
 
227
- if hasattr(func_name, '__name__'):
273
+ if hasattr(func_name, "__name__"):
228
274
  func_name = func.__name__
229
- elif hasattr(func_name, '__qualname__'):
275
+ elif hasattr(func_name, "__qualname__"):
230
276
  func_name = func.__qualname__
231
277
 
232
- if callable(func):
233
- if hasattr(func, '__self__'):
234
- func = func.__self__ if isinstance(func.__self__, type) else func.__self__.__class__
235
- func_name = f'{func.__name__}.{func_name}'
278
+ if callable(func) and hasattr(func, "__self__"):
279
+ func = func.__self__ if isinstance(func.__self__, type) else func.__self__.__class__
280
+ func_name = f"{func.__name__}.{func_name}"
236
281
 
237
282
  return str(func_name).strip()
238
283
 
@@ -241,12 +286,12 @@ def norm_display_name(obj: object) -> str:
241
286
  """Get a fancy name from any object."""
242
287
 
243
288
  if isinstance(obj, Iterator):
244
- return ', '.join(norm_display_name(v) for v in obj).strip()
289
+ return ", ".join(norm_display_name(v) for v in obj).strip()
245
290
 
246
291
  if isinstance(obj, Fraction):
247
- return f'{obj.numerator}/{obj.denominator}'
292
+ return f"{obj.numerator}/{obj.denominator}"
248
293
 
249
294
  if isinstance(obj, dict):
250
- return '(' + ', '.join(f'{k}={v}' for k, v in obj.items()) + ')'
295
+ return "(" + ", ".join(f"{k}={v}" for k, v in obj.items()) + ")"
251
296
 
252
297
  return norm_func_name(obj)
@@ -2,9 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  from typing import Any
4
4
 
5
- __all__ = [
6
- 'deepmerge'
7
- ]
5
+ __all__ = ["deepmerge"]
8
6
 
9
7
 
10
8
  def deepmerge(source: dict[Any, Any], destination: dict[Any, Any]) -> dict[Any, Any]:
@@ -1,7 +1,7 @@
1
- from .builtins import * # noqa: F401, F403
2
- from .check import * # noqa: F401, F403
3
- from .file import * # noqa: F401, F403
4
- from .funcs import * # noqa: F401, F403
5
- from .generic import * # noqa: F401, F403
6
- from .supports import * # noqa: F401, F403
7
- from .utils import * # noqa: F401, F403
1
+ from .builtins import *
2
+ from .check import *
3
+ from .file import *
4
+ from .funcs import *
5
+ from .generic import *
6
+ from .supports import *
7
+ from .utils import *
@@ -3,58 +3,77 @@ from __future__ import annotations
3
3
  from typing import Any, Callable, ParamSpec, Sequence, SupportsFloat, SupportsIndex, TypeAlias, TypeVar, Union
4
4
 
5
5
  __all__ = [
6
- 'T', 'T0', 'T1', 'T2', 'T_co', 'T0_co', 'T1_co', 'T_contra',
7
-
8
- 'F', 'F0', 'F1', 'F2',
9
-
10
- 'P', 'P0', 'P1', 'P2',
11
- 'R', 'R0', 'R1', 'R2', 'R_co', 'R0_co', 'R1_co', 'R_contra',
12
-
13
- 'Nb',
14
-
15
- 'StrictRange', 'SoftRange', 'SoftRangeN', 'SoftRangesN',
16
-
17
- 'SingleOrArr', 'SingleOrArrOpt',
18
- 'SingleOrSeq', 'SingleOrSeqOpt',
19
-
20
- 'SimpleByteData', 'SimpleByteDataArray',
21
- 'ByteData',
22
-
23
- 'KwargsT'
6
+ "F0",
7
+ "F1",
8
+ "F2",
9
+ "P0",
10
+ "P1",
11
+ "P2",
12
+ "R0",
13
+ "R1",
14
+ "R2",
15
+ "T0",
16
+ "T1",
17
+ "T2",
18
+ "ByteData",
19
+ "F",
20
+ "KwargsT",
21
+ "Nb",
22
+ "P",
23
+ "R",
24
+ "R0_co",
25
+ "R1_co",
26
+ "R_co",
27
+ "R_contra",
28
+ "SimpleByteData",
29
+ "SimpleByteDataArray",
30
+ "SingleOrArr",
31
+ "SingleOrArrOpt",
32
+ "SingleOrSeq",
33
+ "SingleOrSeqOpt",
34
+ "SoftRange",
35
+ "SoftRangeN",
36
+ "SoftRangesN",
37
+ "StrictRange",
38
+ "T",
39
+ "T0_co",
40
+ "T1_co",
41
+ "T_co",
42
+ "T_contra",
24
43
  ]
25
44
 
26
- Nb = TypeVar('Nb', float, int)
45
+ Nb = TypeVar("Nb", float, int)
27
46
 
28
- T = TypeVar('T')
29
- T0 = TypeVar('T0')
30
- T1 = TypeVar('T1')
31
- T2 = TypeVar('T2')
47
+ T = TypeVar("T")
48
+ T0 = TypeVar("T0")
49
+ T1 = TypeVar("T1")
50
+ T2 = TypeVar("T2")
32
51
 
33
- F = TypeVar('F', bound=Callable[..., Any])
34
- F0 = TypeVar('F0', bound=Callable[..., Any])
35
- F1 = TypeVar('F1', bound=Callable[..., Any])
36
- F2 = TypeVar('F2', bound=Callable[..., Any])
52
+ F = TypeVar("F", bound=Callable[..., Any])
53
+ F0 = TypeVar("F0", bound=Callable[..., Any])
54
+ F1 = TypeVar("F1", bound=Callable[..., Any])
55
+ F2 = TypeVar("F2", bound=Callable[..., Any])
37
56
 
38
- P = ParamSpec('P')
39
- P0 = ParamSpec('P0')
40
- P1 = ParamSpec('P1')
41
- P2 = ParamSpec('P2')
57
+ P = ParamSpec("P")
58
+ P0 = ParamSpec("P0")
59
+ P1 = ParamSpec("P1")
60
+ P2 = ParamSpec("P2")
42
61
 
43
- R = TypeVar('R')
44
- R0 = TypeVar('R0')
45
- R1 = TypeVar('R1')
46
- R2 = TypeVar('R2')
62
+ R = TypeVar("R")
63
+ R0 = TypeVar("R0")
64
+ R1 = TypeVar("R1")
65
+ R2 = TypeVar("R2")
47
66
 
48
- T_co = TypeVar('T_co', covariant=True)
49
- T0_co = TypeVar('T0_co', covariant=True)
50
- T1_co = TypeVar('T1_co', covariant=True)
67
+ T_co = TypeVar("T_co", covariant=True)
68
+ T0_co = TypeVar("T0_co", covariant=True)
69
+ T1_co = TypeVar("T1_co", covariant=True)
51
70
 
52
- R_co = TypeVar('R_co', covariant=True)
53
- R0_co = TypeVar('R0_co', covariant=True)
54
- R1_co = TypeVar('R1_co', covariant=True)
71
+ R_co = TypeVar("R_co", covariant=True)
72
+ R0_co = TypeVar("R0_co", covariant=True)
73
+ R1_co = TypeVar("R1_co", covariant=True)
55
74
 
56
- T_contra = TypeVar('T_contra', contravariant=True)
57
- R_contra = TypeVar('R_contra', contravariant=True)
75
+ T_contra = TypeVar("T_contra", contravariant=True)
76
+ R_contra = TypeVar("R_contra", contravariant=True)
58
77
 
59
78
  StrictRange: TypeAlias = tuple[int, int]
60
79
  SoftRange: TypeAlias = int | StrictRange | Sequence[int]
jetpytools/types/check.py CHANGED
@@ -4,9 +4,7 @@ from typing_extensions import TypeIs
4
4
 
5
5
  from .builtins import SoftRange, SoftRangeN, SoftRangesN, StrictRange
6
6
 
7
- __all__ = [
8
- "is_strict_range", "is_soft_range", "is_soft_range_n", "is_soft_ranges_n"
9
- ]
7
+ __all__ = ["is_soft_range", "is_soft_range_n", "is_soft_ranges_n", "is_strict_range"]
10
8
 
11
9
 
12
10
  def is_strict_range(val: Any) -> TypeIs[StrictRange]:
@@ -14,8 +12,10 @@ def is_strict_range(val: Any) -> TypeIs[StrictRange]:
14
12
 
15
13
 
16
14
  def is_soft_range(val: Any) -> TypeIs[SoftRange]:
17
- return isinstance(val, int) or is_strict_range(val) or (
18
- isinstance(val, Sequence) and all(isinstance(x, int) for x in val)
15
+ return (
16
+ isinstance(val, int)
17
+ or is_strict_range(val)
18
+ or (isinstance(val, Sequence) and all(isinstance(x, int) for x in val))
19
19
  )
20
20
 
21
21
 
@@ -28,7 +28,4 @@ def is_soft_range_n(val: Any) -> TypeIs[SoftRangeN]:
28
28
 
29
29
 
30
30
  def is_soft_ranges_n(val: Any) -> TypeIs[SoftRangesN]:
31
- return (
32
- isinstance(val, Sequence)
33
- and all(is_soft_range_n(x) for x in val)
34
- )
31
+ return isinstance(val, Sequence) and all(is_soft_range_n(x) for x in val)