python-misc-utils 0.2__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.
Files changed (117) hide show
  1. py_misc_utils/__init__.py +0 -0
  2. py_misc_utils/abs_timeout.py +12 -0
  3. py_misc_utils/alog.py +311 -0
  4. py_misc_utils/app_main.py +179 -0
  5. py_misc_utils/archive_streamer.py +112 -0
  6. py_misc_utils/assert_checks.py +118 -0
  7. py_misc_utils/ast_utils.py +121 -0
  8. py_misc_utils/async_manager.py +189 -0
  9. py_misc_utils/break_control.py +63 -0
  10. py_misc_utils/buffered_iterator.py +35 -0
  11. py_misc_utils/cached_file.py +507 -0
  12. py_misc_utils/call_limiter.py +26 -0
  13. py_misc_utils/call_result_selector.py +13 -0
  14. py_misc_utils/cleanups.py +85 -0
  15. py_misc_utils/cmd.py +97 -0
  16. py_misc_utils/compression.py +116 -0
  17. py_misc_utils/cond_waiter.py +13 -0
  18. py_misc_utils/context_base.py +18 -0
  19. py_misc_utils/context_managers.py +67 -0
  20. py_misc_utils/core_utils.py +577 -0
  21. py_misc_utils/daemon_process.py +252 -0
  22. py_misc_utils/data_cache.py +46 -0
  23. py_misc_utils/date_utils.py +90 -0
  24. py_misc_utils/debug.py +24 -0
  25. py_misc_utils/dyn_modules.py +50 -0
  26. py_misc_utils/dynamod.py +103 -0
  27. py_misc_utils/env_config.py +35 -0
  28. py_misc_utils/executor.py +239 -0
  29. py_misc_utils/file_overwrite.py +29 -0
  30. py_misc_utils/fin_wrap.py +77 -0
  31. py_misc_utils/fp_utils.py +47 -0
  32. py_misc_utils/fs/__init__.py +0 -0
  33. py_misc_utils/fs/file_fs.py +127 -0
  34. py_misc_utils/fs/ftp_fs.py +242 -0
  35. py_misc_utils/fs/gcs_fs.py +196 -0
  36. py_misc_utils/fs/http_fs.py +241 -0
  37. py_misc_utils/fs/s3_fs.py +417 -0
  38. py_misc_utils/fs_base.py +133 -0
  39. py_misc_utils/fs_utils.py +207 -0
  40. py_misc_utils/gcs_fs.py +169 -0
  41. py_misc_utils/gen_indices.py +54 -0
  42. py_misc_utils/gfs.py +371 -0
  43. py_misc_utils/git_repo.py +77 -0
  44. py_misc_utils/global_namespace.py +110 -0
  45. py_misc_utils/http_async_fetcher.py +139 -0
  46. py_misc_utils/http_server.py +196 -0
  47. py_misc_utils/http_utils.py +143 -0
  48. py_misc_utils/img_utils.py +20 -0
  49. py_misc_utils/infix_op.py +20 -0
  50. py_misc_utils/inspect_utils.py +205 -0
  51. py_misc_utils/iostream.py +21 -0
  52. py_misc_utils/iter_file.py +117 -0
  53. py_misc_utils/key_wrap.py +46 -0
  54. py_misc_utils/lazy_import.py +25 -0
  55. py_misc_utils/lockfile.py +164 -0
  56. py_misc_utils/mem_size.py +64 -0
  57. py_misc_utils/mirror_from.py +72 -0
  58. py_misc_utils/mmap.py +16 -0
  59. py_misc_utils/module_utils.py +196 -0
  60. py_misc_utils/moving_average.py +19 -0
  61. py_misc_utils/msgpack_streamer.py +26 -0
  62. py_misc_utils/multi_wait.py +24 -0
  63. py_misc_utils/multiprocessing.py +102 -0
  64. py_misc_utils/named_array.py +224 -0
  65. py_misc_utils/no_break.py +46 -0
  66. py_misc_utils/no_except.py +32 -0
  67. py_misc_utils/np_ml_framework.py +184 -0
  68. py_misc_utils/np_utils.py +346 -0
  69. py_misc_utils/ntuple_utils.py +38 -0
  70. py_misc_utils/num_utils.py +54 -0
  71. py_misc_utils/obj.py +73 -0
  72. py_misc_utils/object_cache.py +100 -0
  73. py_misc_utils/object_tracker.py +88 -0
  74. py_misc_utils/ordered_set.py +71 -0
  75. py_misc_utils/osfd.py +27 -0
  76. py_misc_utils/packet.py +22 -0
  77. py_misc_utils/parquet_streamer.py +69 -0
  78. py_misc_utils/pd_utils.py +254 -0
  79. py_misc_utils/periodic_task.py +61 -0
  80. py_misc_utils/pickle_wrap.py +121 -0
  81. py_misc_utils/pipeline.py +98 -0
  82. py_misc_utils/remap_pickle.py +50 -0
  83. py_misc_utils/resource_manager.py +155 -0
  84. py_misc_utils/rnd_utils.py +56 -0
  85. py_misc_utils/run_once.py +19 -0
  86. py_misc_utils/scheduler.py +135 -0
  87. py_misc_utils/select_params.py +300 -0
  88. py_misc_utils/signal.py +141 -0
  89. py_misc_utils/skl_utils.py +270 -0
  90. py_misc_utils/split.py +147 -0
  91. py_misc_utils/state.py +53 -0
  92. py_misc_utils/std_module.py +56 -0
  93. py_misc_utils/stream_dataframe.py +176 -0
  94. py_misc_utils/streamed_file.py +144 -0
  95. py_misc_utils/tempdir.py +79 -0
  96. py_misc_utils/template_replace.py +51 -0
  97. py_misc_utils/tensor_stream.py +269 -0
  98. py_misc_utils/thread_context.py +33 -0
  99. py_misc_utils/throttle.py +30 -0
  100. py_misc_utils/time_trigger.py +18 -0
  101. py_misc_utils/timegen.py +11 -0
  102. py_misc_utils/traceback.py +49 -0
  103. py_misc_utils/tracking_executor.py +91 -0
  104. py_misc_utils/transform_array.py +42 -0
  105. py_misc_utils/uncompress.py +35 -0
  106. py_misc_utils/url_fetcher.py +157 -0
  107. py_misc_utils/utils.py +538 -0
  108. py_misc_utils/varint.py +50 -0
  109. py_misc_utils/virt_array.py +52 -0
  110. py_misc_utils/weak_call.py +33 -0
  111. py_misc_utils/work_results.py +100 -0
  112. py_misc_utils/writeback_file.py +43 -0
  113. python_misc_utils-0.2.dist-info/METADATA +36 -0
  114. python_misc_utils-0.2.dist-info/RECORD +117 -0
  115. python_misc_utils-0.2.dist-info/WHEEL +5 -0
  116. python_misc_utils-0.2.dist-info/licenses/LICENSE +13 -0
  117. python_misc_utils-0.2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,577 @@
1
+ # NOTE: This module is for APIs which has no local dependecies!
2
+ import array
3
+ import collections
4
+ import copy
5
+ import inspect
6
+ import os
7
+ import re
8
+ import sys
9
+ import threading
10
+ import types
11
+ import yaml
12
+
13
+ _NONE = object()
14
+
15
+
16
+ def ident(x):
17
+ return x
18
+
19
+
20
+ def noop(*args, **kwargs):
21
+ pass
22
+
23
+
24
+ def object_context(sobj, **kwargs):
25
+ ctx_args = vars(sobj).copy()
26
+ ctx_args.update(**kwargs)
27
+
28
+ return types.SimpleNamespace(**ctx_args)
29
+
30
+
31
+ def args(*uargs, **kwargs):
32
+ return uargs, kwargs
33
+
34
+
35
+ def is_builtin_function(obj):
36
+ return isinstance(obj, types.BuiltinFunctionType)
37
+
38
+
39
+ def isdict(value):
40
+ return isinstance(value, collections.abc.Mapping)
41
+
42
+
43
+ def refcount(obj):
44
+ # Discard 2 frame references (our own, and the sys.getrefcount() one).
45
+ return sys.getrefcount(obj) - 2
46
+
47
+
48
+ def denone(**kwargs):
49
+ return {k: v for k, v in kwargs.items() if v is not None}
50
+
51
+
52
+ def vfind(mem, b):
53
+ # Hmmm, a memoryview() should really have a find() API...
54
+ m = re.search(b, mem)
55
+
56
+ return m.start() if m is not None else -1
57
+
58
+
59
+ def seqfirst(s):
60
+ return next(iter(s))
61
+
62
+
63
+ def iter_next(it, defval=None):
64
+ try:
65
+ return next(it)
66
+ except StopIteration:
67
+ return defval
68
+
69
+
70
+ def enum_values(obj):
71
+ if isdict(obj):
72
+ for k, v in obj.items():
73
+ yield k, v
74
+ else:
75
+ for k, v in vars(obj):
76
+ yield k, v
77
+
78
+
79
+ def idx_expand(data, idx, filler=None):
80
+ if idx >= len(data):
81
+ data = data + [filler] * (idx + 1 - len(data))
82
+
83
+ return data
84
+
85
+
86
+ _SEQUENCE_TYPES = (list, tuple, types.GeneratorType)
87
+
88
+ def is_sequence(v):
89
+ return isinstance(v, _SEQUENCE_TYPES)
90
+
91
+
92
+ def expand(data, n):
93
+ return data if is_sequence(data) else (data,) * n
94
+
95
+
96
+ def range_split(n, split, minsize, reverse=False):
97
+ splits = list(range(0, n, split))
98
+ if len(splits) > 1 and (n - splits[-1]) < minsize:
99
+ splits.pop()
100
+
101
+ rsplits = []
102
+ for i, base in enumerate(splits):
103
+ top = splits[i + 1] if (i + 1) < len(splits) else n
104
+ rsplits.append((base, top))
105
+
106
+ return tuple(reversed(rsplits)) if reverse else tuple(rsplits)
107
+
108
+
109
+ def partition(data, n):
110
+ parts = []
111
+ for i in range(n):
112
+ parts.append(tuple(data[j] for j in range(i, len(data), n)))
113
+
114
+ return tuple(parts)
115
+
116
+
117
+ def is_iterator(obj):
118
+ return hasattr(obj, '__iter__') and hasattr(obj, '__next__')
119
+
120
+
121
+ def as_iterator(obj):
122
+ return obj if is_iterator(obj) else iter([obj])
123
+
124
+
125
+ def dmerge(*args):
126
+ mdict = dict()
127
+ for d in args:
128
+ mdict.update(d)
129
+
130
+ return mdict
131
+
132
+
133
+ def dict_extract(d, prefix=None, rx=None):
134
+ if rx is None:
135
+ rx = f'{prefix}(.*)'
136
+ xd = dict()
137
+ for k, v in d.items():
138
+ m = re.match(rx, k)
139
+ if m:
140
+ xd[m.group(1)] = v
141
+
142
+ return xd
143
+
144
+
145
+ def dget(sdict, name, defval, dtype=None):
146
+ v = sdict.get(name, _NONE)
147
+ if v is _NONE:
148
+ return defval
149
+
150
+ if dtype is None and defval is not None:
151
+ dtype = type(defval)
152
+
153
+ return dtype(v) if v is not None and dtype is not None else v
154
+
155
+
156
+ def to_type(v, vtype):
157
+ if isinstance(v, str):
158
+ if vtype in (list, tuple):
159
+ m = re.match(r'\s*\((.*)\)\s*$', v)
160
+ if m:
161
+ v = f'[{m.group(1)}]'
162
+ elif not re.match(r'\s*\[.*\]\s*$', v):
163
+ v = f'[{v}]'
164
+
165
+ v = yaml.safe_load(v)
166
+
167
+ return vtype(v)
168
+
169
+
170
+ def cast(v, vtype):
171
+ return to_type(v, vtype) if v is not None else None
172
+
173
+
174
+ def infer_value(v, vtype=None):
175
+ return yaml.safe_load(v) if vtype is None else to_type(v, vtype)
176
+
177
+
178
+ def splitstrip(data, sep):
179
+ return tuple(s.strip() for s in data.split(sep))
180
+
181
+
182
+ def separate(data, sep, reverse=False, filler=_NONE):
183
+ pos = data.rfind(sep) if reverse else data.find(sep)
184
+ if pos < 0:
185
+ if filler is not _NONE:
186
+ return data.strip(), filler
187
+ else:
188
+ return data.strip(),
189
+
190
+ return data[: pos].strip(), data[pos + 1:].strip()
191
+
192
+
193
+ def root_module(modname):
194
+ return separate(modname, '.')[0]
195
+
196
+
197
+ def parent_module(modname):
198
+ return separate(modname, '.', reverse=True)[0]
199
+
200
+
201
+ def ns_lookup(key, mappings):
202
+ kparts = key.split('.')
203
+ for ns in mappings:
204
+ for part in kparts:
205
+ if isdict(ns):
206
+ ns = ns.get(part)
207
+ else:
208
+ ns = getattr(ns, part, None)
209
+ if ns is None:
210
+ break
211
+
212
+ if ns is not None:
213
+ return ns
214
+
215
+
216
+ def index_select(arr, idx):
217
+ return arr[idx] if isinstance(idx, slice) else [arr[i] for i in idx]
218
+
219
+
220
+ def lindex(l, e, start=0, end=None):
221
+ try:
222
+ return l.index(e, start, end if end is not None else len(l))
223
+ except ValueError:
224
+ return -1
225
+
226
+
227
+ def append_if_missing(arr, elem):
228
+ if elem not in arr:
229
+ arr.append(elem)
230
+
231
+
232
+ def size_str(size):
233
+ syms = ('B', 'KB', 'MB', 'GB', 'TB')
234
+
235
+ for i, sym in enumerate(syms):
236
+ if size < 1024:
237
+ return f'{size} {sym}' if i == 0 else f'{size:.2f} {sym}'
238
+
239
+ size /= 1024
240
+
241
+ return f'{size * 1024:.2f} {syms[-1]}'
242
+
243
+
244
+ def maybe_call(obj, name, *args, **kwargs):
245
+ fn = getattr(obj, name, None)
246
+
247
+ return fn(*args, **kwargs) if callable(fn) else None
248
+
249
+
250
+ def maybe_call_dv(obj, name, defval, *args, **kwargs):
251
+ fn = getattr(obj, name, None)
252
+
253
+ return fn(*args, **kwargs) if callable(fn) else defval
254
+
255
+
256
+ def unique(data):
257
+ udata = collections.defaultdict(lambda: array.array('L'))
258
+ for i, v in enumerate(data):
259
+ udata[v].append(i)
260
+
261
+ return udata
262
+
263
+
264
+ def enum_max(cls):
265
+ return max(x for x in cls)
266
+
267
+
268
+ def enum_bits(cls):
269
+ return enum_max(cls).bit_length()
270
+
271
+
272
+ def signature(v):
273
+ if isdict(v):
274
+ vdata = dict()
275
+ for k in sorted(v.keys()):
276
+ vdata[k] = signature(v[k])
277
+
278
+ return vdata
279
+ elif isinstance(v, (list, tuple)):
280
+ vdata = [signature(e) for e in v]
281
+
282
+ return type(v)(vdata)
283
+
284
+ return type(v)
285
+
286
+
287
+ def equal_signature(a, b, subcls=True):
288
+ if isdict(a):
289
+ if not isdict(b) or len(a) != len(b):
290
+ return False
291
+
292
+ for k, t in a.items():
293
+ tb = b.get(k)
294
+ if tb is None or not equal_signature(t, tb, subcls=subcls):
295
+ return False
296
+
297
+ return True
298
+ elif isinstance(a, (list, tuple)):
299
+ if type(a) != type(b) or len(a) != len(b):
300
+ return False
301
+
302
+ for ea, eb in zip(a, b):
303
+ if not equal_signature(ea, eb, subcls=subcls):
304
+ return False
305
+
306
+ return True
307
+
308
+ return issubclass(a, b) or issubclass(b, a) if subcls else a == b
309
+
310
+
311
+ def genhash(v):
312
+ if isdict(v):
313
+ vdata = []
314
+ for k in sorted(v.keys()):
315
+ vdata.append(genhash(k))
316
+ vdata.append(genhash(v[k]))
317
+
318
+ return hash((type(v), tuple(vdata)))
319
+ elif isinstance(v, (list, tuple)):
320
+ vdata = [genhash(e) for e in v]
321
+
322
+ return hash((type(v), tuple(vdata)))
323
+
324
+ return hash((type(v), v))
325
+
326
+
327
+ def norm_slice(start, stop, size):
328
+ if start is None:
329
+ start = 0
330
+ elif start < 0:
331
+ start = size + start
332
+ if stop is None:
333
+ stop = size
334
+ elif stop < 0:
335
+ stop = size + stop
336
+
337
+ return start, stop
338
+
339
+
340
+ def run_async(fn, *args, **kwargs):
341
+ thread = threading.Thread(target=fn, args=args, kwargs=kwargs, daemon=True)
342
+ thread.start()
343
+
344
+ return thread
345
+
346
+
347
+ def bisect_right(x, key, hi, lo=0):
348
+ tas.check_ge(lo, 0)
349
+ while lo < hi:
350
+ mid = (lo + hi) // 2
351
+ if x < key(mid):
352
+ hi = mid
353
+ else:
354
+ lo = mid + 1
355
+
356
+ return lo
357
+
358
+
359
+ def bisect_left(x, key, hi, lo=0):
360
+ tas.check_ge(lo, 0)
361
+ while lo < hi:
362
+ mid = (lo + hi) // 2
363
+ if key(mid) < x:
364
+ lo = mid + 1
365
+ else:
366
+ hi = mid
367
+
368
+ return lo
369
+
370
+
371
+ def rewrited_exception(ex, msg):
372
+ xmsg = f'{ex}{msg}'
373
+
374
+ return ex.__class__(xmsg).with_traceback(ex.__traceback__)
375
+
376
+
377
+ def obj_from_dict(cls, data):
378
+ args, kwargs = [], dict()
379
+ slots = getattr(cls, '__slots__', None)
380
+ if slots is not None:
381
+ kwargs = {k: data.get(k) for k in slots}
382
+ else:
383
+ sig = inspect.signature(cls)
384
+
385
+ for n, p in sig.parameters.items():
386
+ if p.kind == p.POSITIONAL_ONLY:
387
+ args.append(data.get(n))
388
+ else:
389
+ kwargs[n] = data.get(n)
390
+
391
+ return cls(*args, **kwargs)
392
+
393
+
394
+ def clone(obj):
395
+ clone_fn = getattr(obj, 'clone', None)
396
+
397
+ return clone_fn() if callable(clone_fn) else copy.copy(obj)
398
+
399
+
400
+ def is_namedtuple(obj):
401
+ return isinstance(obj, tuple) and hasattr(obj, '_asdict') and hasattr(obj, '_fields')
402
+
403
+
404
+ def new_with(obj, **kwargs):
405
+ if is_namedtuple(obj):
406
+ return obj._replace(**kwargs)
407
+
408
+ nobj = copy.copy(obj)
409
+ if isdict(nobj):
410
+ nobj.update(kwargs)
411
+ else:
412
+ for k, v in kwargs.items():
413
+ setattr(nobj, k, v)
414
+
415
+ return nobj
416
+
417
+
418
+ def make_ntuple(ntc, args):
419
+ targs = []
420
+ for f in ntc._fields:
421
+ fv = args.get(f, _NONE)
422
+ if fv is _NONE:
423
+ fv = ntc._field_defaults.get(f)
424
+
425
+ targs.append(fv)
426
+
427
+ return ntc._make(targs)
428
+
429
+
430
+ class StringTable:
431
+
432
+ def __init__(self):
433
+ self._tbl = dict()
434
+
435
+ def __len__(self):
436
+ return len(self._tbl)
437
+
438
+ def add(self, s):
439
+ x = self._tbl.get(s)
440
+ if x is None:
441
+ self._tbl[s] = x = s
442
+
443
+ return x
444
+
445
+
446
+ class ValueList(list):
447
+ pass
448
+
449
+ def dict_add(ddict, name, value):
450
+ ivalue = ddict.get(name, _NONE)
451
+ if ivalue is not _NONE:
452
+ if isinstance(ivalue, ValueList):
453
+ ivalue.append(value)
454
+ else:
455
+ ddict[name] = ValueList((ivalue, value))
456
+ else:
457
+ ddict[name] = value
458
+
459
+
460
+ def dict_update_append(d, **kwargs):
461
+ for k, v in kwargs.items():
462
+ dict_add(d, k, v)
463
+
464
+
465
+ def enum_dict_values(ddict, name):
466
+ ivalue = ddict.get(name, _NONE)
467
+ if ivalue is not _NONE:
468
+ if isinstance(ivalue, ValueList):
469
+ for value in ivalue:
470
+ yield value
471
+ else:
472
+ yield ivalue
473
+
474
+
475
+ def enum_unique(data, skip=None):
476
+ uskip = set(skip or ())
477
+ for x in data:
478
+ if x not in uskip:
479
+ uskip.add(x)
480
+ yield x
481
+
482
+
483
+ def get_property(obj, name, defval=None):
484
+ p = getattr(obj, name, _NONE)
485
+ if p is _NONE:
486
+ return defval
487
+
488
+ return p() if callable(p) else p
489
+
490
+
491
+ def data_rewrite(v, rwfn):
492
+ rwv = rwfn(v)
493
+ if rwv is not None:
494
+ return rwv
495
+ elif isinstance(v, (list, tuple)):
496
+ new_values, rewritten = [], False
497
+ for x in v:
498
+ new_obj = data_rewrite(x, rwfn)
499
+ new_values.append(new_obj)
500
+ rewritten = rewritten or new_obj is not x
501
+
502
+ return type(v)(new_values) if rewritten else v
503
+ elif isdict(v):
504
+ new_values, rewritten = [], False
505
+ for k, x in v.items():
506
+ new_k = data_rewrite(k, rwfn)
507
+ new_x = data_rewrite(x, rwfn)
508
+ new_values.append((new_k, new_x))
509
+ rewritten = rewritten or new_k is not k or new_x is not x
510
+
511
+ return type(v)(new_values) if rewritten else v
512
+ elif hasattr(v, '__dict__'):
513
+ new_values, rewritten = [], False
514
+ for k, x in v.__dict__.items():
515
+ new_k = data_rewrite(k, rwfn)
516
+ new_x = data_rewrite(x, rwfn)
517
+ new_values.append((new_k, new_x))
518
+ rewritten = rewritten or new_k is not k or new_x is not x
519
+
520
+ if rewritten:
521
+ new_obj = copy.copy(v)
522
+ new_obj.__dict__.update(**dict(new_values))
523
+
524
+ return new_obj
525
+
526
+ return v
527
+ else:
528
+ return v
529
+
530
+
531
+ def recurse_apply(obj, name, fn):
532
+ if not fn(obj, name):
533
+ if isinstance(obj, (list, tuple)):
534
+ for i, v in enumerate(obj):
535
+ recurse_apply(v, f'{name}[{i}]', fn)
536
+ elif isdict(obj):
537
+ for k, v in obj.items():
538
+ recurse_apply(v, f'{name}.{k}', fn)
539
+ elif hasattr(obj, '__dict__'):
540
+ for k, v in obj.__dict__.items():
541
+ recurse_apply(v, f'{name}.{k}', fn)
542
+
543
+
544
+ def compute_shape(data):
545
+ sp = get_property(data, 'shape')
546
+ if sp is not None:
547
+ return tuple(sp)
548
+ shape = []
549
+ if hasattr(data, '__len__'):
550
+ shape.append(len(data))
551
+ if shape[0] > 0 and hasattr(data, '__getitem__'):
552
+ shape.extend(compute_shape(data[0]))
553
+
554
+ return tuple(shape)
555
+
556
+
557
+ class RevGen:
558
+
559
+ def __init__(self, fmt=None, revbase=0):
560
+ self._fmt = fmt or '{name}_{ver}'
561
+ self._revbase = revbase
562
+ self._revdb = dict()
563
+
564
+ def getver(self, name, defval=None):
565
+ return self._revdb.get(name, defval)
566
+
567
+ def newver(self, name):
568
+ ver = self._revdb.get(name, self._revbase)
569
+ self._revdb[name] = ver + 1
570
+
571
+ return ver
572
+
573
+ def newname(self, name, shortzero=False):
574
+ ver = self.newver(name)
575
+
576
+ return self._fmt.format(name=name, ver=ver) if ver != 0 or not shortzero else name
577
+