plexus-python-common 1.1.87__py3-none-any.whl → 1.1.89__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.
- plexus/common/utils/funcutils.py +23 -17
- plexus/common/utils/logger.py +11 -10
- plexus/common/utils/retry.py +74 -16
- plexus/common/utils/strutils.py +1 -1
- plexus/common/utils/testutils.py +4 -1
- {plexus_python_common-1.1.87.dist-info → plexus_python_common-1.1.89.dist-info}/METADATA +1 -1
- {plexus_python_common-1.1.87.dist-info → plexus_python_common-1.1.89.dist-info}/RECORD +9 -9
- {plexus_python_common-1.1.87.dist-info → plexus_python_common-1.1.89.dist-info}/WHEEL +1 -1
- {plexus_python_common-1.1.87.dist-info → plexus_python_common-1.1.89.dist-info}/top_level.txt +0 -0
plexus/common/utils/funcutils.py
CHANGED
|
@@ -21,7 +21,8 @@ __all__ = [
|
|
|
21
21
|
|
|
22
22
|
def const[T](value: T) -> Callable[..., T]:
|
|
23
23
|
"""
|
|
24
|
-
Returns a function that always returns the specified ``value``, regardless of the input
|
|
24
|
+
Returns a function that always returns the specified ``value``, regardless of the input
|
|
25
|
+
arguments.
|
|
25
26
|
|
|
26
27
|
:param value: The constant value to return.
|
|
27
28
|
:return: A function that takes any arguments and returns ``value``.
|
|
@@ -65,15 +66,17 @@ def second[V]() -> Callable[[tuple[Any, V]], V]:
|
|
|
65
66
|
|
|
66
67
|
def packed[R](func: Callable[..., R]) -> Callable[[tuple[Any, ...]], R]:
|
|
67
68
|
"""
|
|
68
|
-
Wraps a function to accept its arguments as a single tuple, unpacking them when called. This is
|
|
69
|
-
scenarios where arguments are naturally grouped in tuples, such as when working with
|
|
70
|
-
lists of tuples, or when interfacing with APIs that provide
|
|
69
|
+
Wraps a function to accept its arguments as a single tuple, unpacking them when called. This is
|
|
70
|
+
useful for scenarios where arguments are naturally grouped in tuples, such as when working with
|
|
71
|
+
data structures like maps or lists of tuples, or when interfacing with APIs that provide
|
|
72
|
+
arguments in tuple form.
|
|
71
73
|
|
|
72
74
|
>>> data = [(1, 2), (3, 4), (5, 6)]
|
|
73
75
|
>>> sums = map(packed(lambda x, y: x + y), data)
|
|
74
76
|
|
|
75
77
|
:param func: The function to wrap.
|
|
76
|
-
:return: A function that takes a tuple of arguments and calls the original function with them
|
|
78
|
+
:return: A function that takes a tuple of arguments and calls the original function with them
|
|
79
|
+
unpacked.
|
|
77
80
|
"""
|
|
78
81
|
|
|
79
82
|
@functools.wraps(func)
|
|
@@ -85,7 +88,8 @@ def packed[R](func: Callable[..., R]) -> Callable[[tuple[Any, ...]], R]:
|
|
|
85
88
|
|
|
86
89
|
def identity[T](instance: T) -> T:
|
|
87
90
|
"""
|
|
88
|
-
Returns the input ``instance`` unchanged. This is a utility function often used as a default or
|
|
91
|
+
Returns the input ``instance`` unchanged. This is a utility function often used as a default or
|
|
92
|
+
placeholder.
|
|
89
93
|
|
|
90
94
|
:param instance: The value to return.
|
|
91
95
|
:return: The same value as provided in ``instance``.
|
|
@@ -130,9 +134,10 @@ def composable[T, R](func: Callable[[T], R]) -> Composable[T, R]:
|
|
|
130
134
|
return func
|
|
131
135
|
|
|
132
136
|
|
|
133
|
-
def singleton[R](tar: Callable[..., R] = None):
|
|
137
|
+
def singleton[R](tar: Callable[..., R] | None = None):
|
|
134
138
|
"""
|
|
135
|
-
Decorator to ensure a function or class is only instantiated once. Subsequent calls return the
|
|
139
|
+
Decorator to ensure a function or class is only instantiated once. Subsequent calls return the
|
|
140
|
+
same instance.
|
|
136
141
|
|
|
137
142
|
:param tar: The target callable to decorate.
|
|
138
143
|
:return: The singleton instance of the callable.
|
|
@@ -155,9 +160,10 @@ def singleton[R](tar: Callable[..., R] = None):
|
|
|
155
160
|
return decorator if tar is None else decorator(tar)
|
|
156
161
|
|
|
157
162
|
|
|
158
|
-
def memorized[R](tar: Callable[..., R] = None, *, ordered: bool = False, typed: bool = False):
|
|
163
|
+
def memorized[R](tar: Callable[..., R] | None = None, *, ordered: bool = False, typed: bool = False):
|
|
159
164
|
"""
|
|
160
|
-
Decorator to cache the results of a function based on its arguments. Supports options for
|
|
165
|
+
Decorator to cache the results of a function based on its arguments. Supports options for
|
|
166
|
+
argument order and type.
|
|
161
167
|
|
|
162
168
|
:param tar: The target callable to decorate.
|
|
163
169
|
:param ordered: If ``True``, keyword argument order is significant in the cache key.
|
|
@@ -198,7 +204,7 @@ def memorized[R](tar: Callable[..., R] = None, *, ordered: bool = False, typed:
|
|
|
198
204
|
return decorator if tar is None else decorator(tar)
|
|
199
205
|
|
|
200
206
|
|
|
201
|
-
def lazy[R](tar: Callable[..., R] = None):
|
|
207
|
+
def lazy[R](tar: Callable[..., R] | None = None):
|
|
202
208
|
"""
|
|
203
209
|
Decorator to defer the execution of a function until its result is explicitly requested.
|
|
204
210
|
|
|
@@ -219,10 +225,10 @@ def lazy[R](tar: Callable[..., R] = None):
|
|
|
219
225
|
return decorator if tar is None else decorator(tar)
|
|
220
226
|
|
|
221
227
|
|
|
222
|
-
def unique_returns[R](tar: Callable[..., R] = None, *, max_trials: int | None = None):
|
|
228
|
+
def unique_returns[R](tar: Callable[..., R] | None = None, *, max_trials: int | None = None):
|
|
223
229
|
"""
|
|
224
|
-
Decorator to ensure a function produces unique return values. If no unique value is found
|
|
225
|
-
raises an error.
|
|
230
|
+
Decorator to ensure a function produces unique return values. If no unique value is found
|
|
231
|
+
within ``max_trials``, raises an error.
|
|
226
232
|
|
|
227
233
|
:param tar: The target callable to decorate.
|
|
228
234
|
:param max_trials: The maximum number of attempts to find a unique return value. If ``None``,
|
|
@@ -255,9 +261,9 @@ def unique_returns[R](tar: Callable[..., R] = None, *, max_trials: int | None =
|
|
|
255
261
|
|
|
256
262
|
class ChainableResult[T, R]:
|
|
257
263
|
"""
|
|
258
|
-
A proxy object that holds a result of type R and delegates attribute access to a chained
|
|
259
|
-
This is useful for chaining operations that produce intermediate results
|
|
260
|
-
original object.
|
|
264
|
+
A proxy object that holds a result of type ``R`` and delegates attribute access to a chained
|
|
265
|
+
object of type ``T``. This is useful for chaining operations that produce intermediate results
|
|
266
|
+
while still allowing access to the original object.
|
|
261
267
|
"""
|
|
262
268
|
|
|
263
269
|
def __init__(self, target: T, result: R):
|
plexus/common/utils/logger.py
CHANGED
|
@@ -105,13 +105,14 @@ def __get_logger_caller_module_name() -> str:
|
|
|
105
105
|
|
|
106
106
|
:return: The name of the caller's module, or an empty string if not found.
|
|
107
107
|
"""
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
108
|
+
frame = inspect.currentframe()
|
|
109
|
+
try:
|
|
110
|
+
# This helper -> public logging function -> caller.
|
|
111
|
+
caller_frame = frame.f_back.f_back if frame is not None and frame.f_back is not None else None
|
|
112
|
+
if caller_frame is None:
|
|
113
|
+
return "" # cause degeneration to root logger
|
|
114
|
+
module = inspect.getmodule(caller_frame)
|
|
115
|
+
return "" if module is None else module.__name__
|
|
116
|
+
finally:
|
|
117
|
+
# Frame references can otherwise participate in reference cycles.
|
|
118
|
+
del frame
|
plexus/common/utils/retry.py
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import abc
|
|
2
|
+
import functools
|
|
2
3
|
import time
|
|
3
4
|
from collections.abc import Callable
|
|
4
5
|
from typing import Any
|
|
5
6
|
|
|
6
|
-
from plexus.common.utils.dtutils import dt_utc_now
|
|
7
7
|
from plexus.common.utils.randutils import randomizer
|
|
8
8
|
|
|
9
9
|
__all__ = [
|
|
@@ -24,7 +24,7 @@ class Attempt(object):
|
|
|
24
24
|
next_wait: int,
|
|
25
25
|
start_ts: float,
|
|
26
26
|
check_ts: float,
|
|
27
|
-
last_exception: Exception,
|
|
27
|
+
last_exception: Exception | None = None,
|
|
28
28
|
):
|
|
29
29
|
"""
|
|
30
30
|
Represents an attempt in retrying.
|
|
@@ -87,10 +87,11 @@ class RetryWrapper(object):
|
|
|
87
87
|
def __init__(
|
|
88
88
|
self,
|
|
89
89
|
target: Callable[..., Any] | Retry,
|
|
90
|
-
wait: int = None,
|
|
91
|
-
wait_func: Callable[[int], int] = None,
|
|
92
|
-
retrials: int = None,
|
|
93
|
-
timeout: int = None,
|
|
90
|
+
wait: int | None = None,
|
|
91
|
+
wait_func: Callable[[int], int] | None = None,
|
|
92
|
+
retrials: int | None = None,
|
|
93
|
+
timeout: int | None = None,
|
|
94
|
+
exceptions: type[Exception] | tuple[type[Exception], ...] = Exception,
|
|
94
95
|
):
|
|
95
96
|
"""
|
|
96
97
|
Retry executor that wraps a callable or ``Retry`` instance, providing flexible retry strategies including fixed,
|
|
@@ -101,12 +102,27 @@ class RetryWrapper(object):
|
|
|
101
102
|
:param wait_func: Function to determine wait time based on attempt number.
|
|
102
103
|
:param retrials: Maximum number of retrials (``None`` for unlimited).
|
|
103
104
|
:param timeout: Maximum total time (in seconds) allowed for all attempts (``None`` for unlimited).
|
|
105
|
+
:param exceptions: Exceptions to catch during retrials.
|
|
104
106
|
"""
|
|
107
|
+
if wait is not None and wait < 0:
|
|
108
|
+
raise ValueError("'wait' must be greater than or equal to zero")
|
|
109
|
+
if retrials is not None and retrials < 0:
|
|
110
|
+
raise ValueError("'retrials' must be greater than or equal to zero")
|
|
111
|
+
if timeout is not None and timeout < 0:
|
|
112
|
+
raise ValueError("'timeout' must be greater than or equal to zero")
|
|
113
|
+
if isinstance(exceptions, type):
|
|
114
|
+
exceptions = (exceptions,)
|
|
115
|
+
if not exceptions or not all(isinstance(exc, type) and issubclass(exc, Exception) for exc in exceptions):
|
|
116
|
+
raise TypeError("'exceptions' must contain 'Exception' subclasses")
|
|
117
|
+
|
|
105
118
|
self.target = target
|
|
106
119
|
self.wait = wait
|
|
107
120
|
self.wait_func = wait_func
|
|
108
121
|
self.retrials = retrials
|
|
109
122
|
self.timeout = timeout
|
|
123
|
+
self.exceptions = exceptions
|
|
124
|
+
if not isinstance(target, Retry) and hasattr(target, "__name__"):
|
|
125
|
+
functools.update_wrapper(self, target)
|
|
110
126
|
|
|
111
127
|
def __call__(self, *args, **kwargs):
|
|
112
128
|
"""
|
|
@@ -118,7 +134,7 @@ class RetryWrapper(object):
|
|
|
118
134
|
"""
|
|
119
135
|
return self.run(*args, **kwargs)
|
|
120
136
|
|
|
121
|
-
def next_wait(self, attempt_number: int):
|
|
137
|
+
def next_wait(self, attempt_number: int) -> int:
|
|
122
138
|
"""
|
|
123
139
|
Determines the wait time before the next retry attempt based on the configured strategy.
|
|
124
140
|
|
|
@@ -126,7 +142,7 @@ class RetryWrapper(object):
|
|
|
126
142
|
:return: The wait time in seconds, or ``None`` if not applicable.
|
|
127
143
|
"""
|
|
128
144
|
if attempt_number <= 0:
|
|
129
|
-
return
|
|
145
|
+
return 0
|
|
130
146
|
if self.wait is not None:
|
|
131
147
|
return self.wait
|
|
132
148
|
if self.wait_func is not None:
|
|
@@ -140,7 +156,7 @@ class RetryWrapper(object):
|
|
|
140
156
|
:param start_ts: The start timestamp of the first attempt.
|
|
141
157
|
:return: Tuple (``True`` if within timeout, current timestamp).
|
|
142
158
|
"""
|
|
143
|
-
current_ts =
|
|
159
|
+
current_ts = time.monotonic()
|
|
144
160
|
if self.timeout is None:
|
|
145
161
|
return True, current_ts
|
|
146
162
|
return current_ts < start_ts + self.timeout, current_ts
|
|
@@ -156,7 +172,7 @@ class RetryWrapper(object):
|
|
|
156
172
|
:raises RuntimeError: If all attempts fail or timeout is reached.
|
|
157
173
|
"""
|
|
158
174
|
attempt_number = 0
|
|
159
|
-
start_ts =
|
|
175
|
+
start_ts = time.monotonic()
|
|
160
176
|
last_exception = None
|
|
161
177
|
|
|
162
178
|
while self.retrials is None or attempt_number <= self.retrials:
|
|
@@ -182,33 +198,55 @@ class RetryWrapper(object):
|
|
|
182
198
|
return result
|
|
183
199
|
else:
|
|
184
200
|
return self.target(*args, **kwargs)
|
|
185
|
-
except
|
|
201
|
+
except self.exceptions as e:
|
|
186
202
|
last_exception = e
|
|
187
203
|
if isinstance(self.target, Retry):
|
|
188
204
|
self.target.on_failure(attempt, e)
|
|
189
|
-
|
|
205
|
+
has_retrial = self.retrials is None or attempt_number <= self.retrials
|
|
206
|
+
if not has_retrial:
|
|
207
|
+
break
|
|
208
|
+
|
|
209
|
+
wait = self.next_wait(attempt_number)
|
|
210
|
+
if self.timeout is not None:
|
|
211
|
+
remaining = start_ts + self.timeout - time.monotonic()
|
|
212
|
+
if remaining <= 0:
|
|
213
|
+
break
|
|
214
|
+
wait = min(wait, remaining)
|
|
215
|
+
time.sleep(wait)
|
|
190
216
|
|
|
191
217
|
raise RuntimeError(
|
|
192
218
|
f"failed to execute target '{self.target}' after {attempt_number} attempts") from last_exception
|
|
193
219
|
|
|
194
220
|
|
|
195
|
-
def retry(
|
|
221
|
+
def retry(
|
|
222
|
+
wait: int | None = None,
|
|
223
|
+
retrials: int | None = None,
|
|
224
|
+
timeout: int | None = None,
|
|
225
|
+
exceptions: type[Exception] | tuple[type[Exception], ...] = Exception,
|
|
226
|
+
):
|
|
196
227
|
"""
|
|
197
228
|
Decorator to apply fixed wait retry logic to a function or callable.
|
|
198
229
|
|
|
199
230
|
:param wait: Fixed wait time (in seconds) between retrials.
|
|
200
231
|
:param retrials: Maximum number of retrials (``None`` for unlimited).
|
|
201
232
|
:param timeout: Maximum total time (in seconds) allowed for all attempts (``None`` for unlimited).
|
|
233
|
+
:param exceptions: Exceptions to apply to retrials.
|
|
202
234
|
:return: A decorated function with retry logic.
|
|
203
235
|
"""
|
|
204
236
|
|
|
205
237
|
def wrapper(target):
|
|
206
|
-
return RetryWrapper(target, wait=wait, retrials=retrials, timeout=timeout)
|
|
238
|
+
return RetryWrapper(target, wait=wait, retrials=retrials, timeout=timeout, exceptions=exceptions)
|
|
207
239
|
|
|
208
240
|
return wrapper
|
|
209
241
|
|
|
210
242
|
|
|
211
|
-
def retry_exponent(
|
|
243
|
+
def retry_exponent(
|
|
244
|
+
wait_init: int,
|
|
245
|
+
wait_max: int,
|
|
246
|
+
retrials: int | None = None,
|
|
247
|
+
timeout: int | None = None,
|
|
248
|
+
exceptions: type[Exception] | tuple[type[Exception], ...] = Exception,
|
|
249
|
+
):
|
|
212
250
|
"""
|
|
213
251
|
Decorator to apply exponential backoff retry logic to a function or callable.
|
|
214
252
|
|
|
@@ -216,21 +254,34 @@ def retry_exponent(wait_init: int, wait_max: int, retrials: int = None, timeout:
|
|
|
216
254
|
:param wait_max: Maximum wait time for exponential backoff.
|
|
217
255
|
:param retrials: Maximum number of retrials (``None`` for unlimited).
|
|
218
256
|
:param timeout: Maximum total time (in seconds) allowed for all attempts (``None`` for unlimited).
|
|
257
|
+
:param exceptions: Exceptions to apply to retrials.
|
|
219
258
|
:return: A decorated function with retry logic.
|
|
220
259
|
"""
|
|
221
260
|
|
|
261
|
+
if wait_init < 0 or wait_max < 0:
|
|
262
|
+
raise ValueError("'wait_init' and 'wait_max' must be greater than or equal to zero")
|
|
263
|
+
if wait_init > wait_max:
|
|
264
|
+
raise ValueError("'wait_init' must be less than or equal to 'wait_max'")
|
|
265
|
+
|
|
222
266
|
def wrapper(target):
|
|
223
267
|
return RetryWrapper(
|
|
224
268
|
target,
|
|
225
269
|
wait_func=lambda x: min(wait_init * (2 ** (x - 1)), wait_max),
|
|
226
270
|
retrials=retrials,
|
|
227
271
|
timeout=timeout,
|
|
272
|
+
exceptions=exceptions,
|
|
228
273
|
)
|
|
229
274
|
|
|
230
275
|
return wrapper
|
|
231
276
|
|
|
232
277
|
|
|
233
|
-
def retry_random(
|
|
278
|
+
def retry_random(
|
|
279
|
+
wait_min: int,
|
|
280
|
+
wait_max: int,
|
|
281
|
+
retrials: int | None = None,
|
|
282
|
+
timeout: int | None = None,
|
|
283
|
+
exceptions: type[Exception] | tuple[type[Exception], ...] = Exception,
|
|
284
|
+
):
|
|
234
285
|
"""
|
|
235
286
|
Decorator to apply random wait retry logic to a function or callable.
|
|
236
287
|
|
|
@@ -238,15 +289,22 @@ def retry_random(wait_min: int, wait_max: int, retrials: int = None, timeout: in
|
|
|
238
289
|
:param wait_max: Maximum wait time for random backoff.
|
|
239
290
|
:param retrials: Maximum number of retrials (``None`` for unlimited).
|
|
240
291
|
:param timeout: Maximum total time (in seconds) allowed for all attempts (``None`` for unlimited).
|
|
292
|
+
:param exceptions: Exceptions to apply to retrials.
|
|
241
293
|
:return: A decorated function with retry logic.
|
|
242
294
|
"""
|
|
243
295
|
|
|
296
|
+
if wait_min < 0 or wait_max < 0:
|
|
297
|
+
raise ValueError("'wait_min' and 'wait_max' must be greater than or equal to zero")
|
|
298
|
+
if wait_min > wait_max:
|
|
299
|
+
raise ValueError("'wait_min' must be less than or equal to 'wait_max'")
|
|
300
|
+
|
|
244
301
|
def wrapper(target):
|
|
245
302
|
return RetryWrapper(
|
|
246
303
|
target,
|
|
247
304
|
wait_func=lambda x: randomizer().next_int(wait_min, wait_max),
|
|
248
305
|
retrials=retrials,
|
|
249
306
|
timeout=timeout,
|
|
307
|
+
exceptions=exceptions,
|
|
250
308
|
)
|
|
251
309
|
|
|
252
310
|
return wrapper
|
plexus/common/utils/strutils.py
CHANGED
|
@@ -66,7 +66,7 @@ def parse_bool(v: Any) -> bool:
|
|
|
66
66
|
elif isinstance(v, bool):
|
|
67
67
|
return v
|
|
68
68
|
else:
|
|
69
|
-
raise ValueError(f"type '{type(v)}' is not convertible to bool")
|
|
69
|
+
raise ValueError(f"type '{type(v)}' is not convertible to 'bool'")
|
|
70
70
|
|
|
71
71
|
|
|
72
72
|
def parse_bool_or(v: Any, default: bool | None = False) -> bool | None:
|
plexus/common/utils/testutils.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import abc
|
|
2
|
+
import datetime
|
|
2
3
|
from decimal import Decimal
|
|
3
4
|
from typing import Any, Protocol
|
|
4
5
|
|
|
@@ -69,7 +70,9 @@ def nested_approx(expected, rel: float = None, abs: float = None, nan_ok: bool =
|
|
|
69
70
|
return ApproxNestedSequenceLike(expected, rel, abs, nan_ok)
|
|
70
71
|
if isinstance(expected, Decimal):
|
|
71
72
|
return ApproxDecimal(expected, to_decimal(rel), to_decimal(abs), nan_ok)
|
|
72
|
-
|
|
73
|
+
if isinstance(expected, (datetime.datetime, datetime.date, datetime.time, datetime.timedelta)):
|
|
74
|
+
return pytest.approx(expected, abs=datetime.timedelta(0))
|
|
75
|
+
return pytest.approx(expected, rel=rel, abs=abs, nan_ok=nan_ok)
|
|
73
76
|
|
|
74
77
|
|
|
75
78
|
class MockedCallable(Protocol):
|
|
@@ -5,19 +5,19 @@ plexus/common/utils/config.py,sha256=Hc35GzKWyKU4jyjsay5JtGhAtQ9GReNWKJEOskJVe3s
|
|
|
5
5
|
plexus/common/utils/csvutils.py,sha256=quGN_F-WxtznhCLqst2coXaK-DVgxzwe2FA0qiiskf8,8344
|
|
6
6
|
plexus/common/utils/dbutils.py,sha256=0GhnW1P1fJsqB4NjS4V6R-oV8d4R-ZZzi-IpiZCRjAs,16575
|
|
7
7
|
plexus/common/utils/dtutils.py,sha256=A_upNJJJ3q6e3QZ2m5jXkDLwpAtUU9lEBY2MotAV5aY,12229
|
|
8
|
-
plexus/common/utils/funcutils.py,sha256=
|
|
8
|
+
plexus/common/utils/funcutils.py,sha256=fdWmQ3GG0RjBwe2kgx4BIrsBUIs89saa60VN5lvZb4I,9862
|
|
9
9
|
plexus/common/utils/iterutils.py,sha256=JL8j8plIoc2hF8D-BY6dOHEBoeoFZ1nLrhw4dFth_lA,30988
|
|
10
10
|
plexus/common/utils/jsonutils.py,sha256=BDtqkvmWHiVFo4d5nGkmFtC00JQkGLC7ybchrpID5pU,18529
|
|
11
|
-
plexus/common/utils/logger.py,sha256=
|
|
11
|
+
plexus/common/utils/logger.py,sha256=ce8B8CrxeoZnPIWNkNSL4JXFsK_3yXnBPDzxntUwG48,4046
|
|
12
12
|
plexus/common/utils/numutils.py,sha256=p6Rz1qyCcUru3v1zDy2PM-nds2NWJdL5A_vLmG-kswk,4294
|
|
13
13
|
plexus/common/utils/pathutils.py,sha256=vUuBZZShkK4oJN_GqWzMYeSGmnUFTcT8NoMgjh1YuUs,10201
|
|
14
14
|
plexus/common/utils/randutils.py,sha256=Mkba-g2ZnasuhdtBWoVDsP_VuwKMJ8p2UCf6-GF4drg,12852
|
|
15
|
-
plexus/common/utils/retry.py,sha256=
|
|
15
|
+
plexus/common/utils/retry.py,sha256=S_IfYrA30ci_sx6_ar0WUkNpKufoWi8xOSiWeYeAemA,11424
|
|
16
16
|
plexus/common/utils/span.py,sha256=RqgUuupN01xCjm4l5uxrr8BFFrUrytRVGihmENUawpk,6839
|
|
17
|
-
plexus/common/utils/strutils.py,sha256=
|
|
18
|
-
plexus/common/utils/testutils.py,sha256=
|
|
17
|
+
plexus/common/utils/strutils.py,sha256=uB46pPgaO_UMulwfW-hO7QOpCyhB9AdupeWSsJR3wGA,5098
|
|
18
|
+
plexus/common/utils/testutils.py,sha256=AIuGok17mRackiSXO0ZiWXEwlna6Bv2J8ZFN48nypDY,5638
|
|
19
19
|
plexus/common/utils/typeutils.py,sha256=RVkYkFRgDrx77OHFH7PavMV0AIB0S8ly40rs4g7JWE4,8220
|
|
20
|
-
plexus_python_common-1.1.
|
|
21
|
-
plexus_python_common-1.1.
|
|
22
|
-
plexus_python_common-1.1.
|
|
23
|
-
plexus_python_common-1.1.
|
|
20
|
+
plexus_python_common-1.1.89.dist-info/METADATA,sha256=ak_tbOiy9nSsTLaWvmqwr6k9kfUxukLOIqbk4rk4nmo,871
|
|
21
|
+
plexus_python_common-1.1.89.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
|
|
22
|
+
plexus_python_common-1.1.89.dist-info/top_level.txt,sha256=ug_g7CVwaMQuas5UzAXbHUrQvKGCn8ezc6ZNvvRlJOE,7
|
|
23
|
+
plexus_python_common-1.1.89.dist-info/RECORD,,
|
{plexus_python_common-1.1.87.dist-info → plexus_python_common-1.1.89.dist-info}/top_level.txt
RENAMED
|
File without changes
|