omlish 0.0.0.dev23__py3-none-any.whl → 0.0.0.dev25__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 (46) hide show
  1. omlish/__about__.py +16 -4
  2. omlish/_manifests.json +1 -0
  3. omlish/bootstrap/diag.py +2 -2
  4. omlish/check.py +202 -24
  5. omlish/collections/__init__.py +2 -2
  6. omlish/collections/utils.py +3 -3
  7. omlish/concurrent/threadlets.py +5 -0
  8. omlish/dataclasses/__init__.py +1 -0
  9. omlish/dataclasses/impl/LICENSE +279 -0
  10. omlish/dataclasses/impl/init.py +10 -2
  11. omlish/dataclasses/impl/metadata.py +3 -3
  12. omlish/dataclasses/impl/reflect.py +1 -1
  13. omlish/dataclasses/utils.py +16 -3
  14. omlish/diag/pycharm.py +69 -10
  15. omlish/docker.py +16 -11
  16. omlish/genmachine.py +2 -1
  17. omlish/graphs/trees.py +1 -1
  18. omlish/lang/__init__.py +14 -1
  19. omlish/lang/cached.py +5 -2
  20. omlish/lang/descriptors.py +33 -16
  21. omlish/lang/resources.py +60 -0
  22. omlish/lang/typing.py +32 -0
  23. omlish/lite/logs.py +133 -4
  24. omlish/logs/__init__.py +17 -2
  25. omlish/logs/configs.py +13 -1
  26. omlish/logs/formatters.py +0 -1
  27. omlish/marshal/__init__.py +2 -0
  28. omlish/marshal/helpers.py +27 -0
  29. omlish/specs/jsonschema/keywords/base.py +2 -2
  30. omlish/specs/jsonschema/keywords/parse.py +1 -1
  31. omlish/specs/jsonschema/schemas/draft202012/metaschema.json +58 -0
  32. omlish/specs/jsonschema/schemas/draft202012/vocabularies/applicator.json +48 -0
  33. omlish/specs/jsonschema/schemas/draft202012/vocabularies/content.json +17 -0
  34. omlish/specs/jsonschema/schemas/draft202012/vocabularies/core.json +51 -0
  35. omlish/specs/jsonschema/schemas/draft202012/vocabularies/format-annotation.json +14 -0
  36. omlish/specs/jsonschema/schemas/draft202012/vocabularies/format-assertion.json +14 -0
  37. omlish/specs/jsonschema/schemas/draft202012/vocabularies/format.json +14 -0
  38. omlish/specs/jsonschema/schemas/draft202012/vocabularies/meta-data.json +37 -0
  39. omlish/specs/jsonschema/schemas/draft202012/vocabularies/unevaluated.json +15 -0
  40. omlish/specs/jsonschema/schemas/draft202012/vocabularies/validation.json +98 -0
  41. omlish/stats.py +1 -0
  42. {omlish-0.0.0.dev23.dist-info → omlish-0.0.0.dev25.dist-info}/METADATA +1 -1
  43. {omlish-0.0.0.dev23.dist-info → omlish-0.0.0.dev25.dist-info}/RECORD +46 -33
  44. {omlish-0.0.0.dev23.dist-info → omlish-0.0.0.dev25.dist-info}/LICENSE +0 -0
  45. {omlish-0.0.0.dev23.dist-info → omlish-0.0.0.dev25.dist-info}/WHEEL +0 -0
  46. {omlish-0.0.0.dev23.dist-info → omlish-0.0.0.dev25.dist-info}/top_level.txt +0 -0
omlish/__about__.py CHANGED
@@ -1,5 +1,5 @@
1
- __version__ = '0.0.0.dev23'
2
- __revision__ = '1d019b6879a9552ea31622e40f50d260d6b08824'
1
+ __version__ = '0.0.0.dev25'
2
+ __revision__ = '123812c0156cbb06af42b6e2ee3b7912d5bf5fc8'
3
3
 
4
4
 
5
5
  #
@@ -111,8 +111,6 @@ class SetuptoolsBase:
111
111
  'global-exclude **/conftest.py',
112
112
  ]
113
113
 
114
- include_package_data = False
115
-
116
114
  find_packages = {
117
115
  'exclude': [
118
116
  '*.tests',
@@ -120,6 +118,20 @@ class SetuptoolsBase:
120
118
  ],
121
119
  }
122
120
 
121
+ package_data = {
122
+ '*': [
123
+ '*.c',
124
+ '*.cc',
125
+ '*.h',
126
+
127
+ '*.json',
128
+
129
+ '*.sql',
130
+
131
+ 'LICENSE',
132
+ ],
133
+ }
134
+
123
135
 
124
136
  class Setuptools(SetuptoolsBase):
125
137
  find_packages = {
omlish/_manifests.json ADDED
@@ -0,0 +1 @@
1
+ []
omlish/bootstrap/diag.py CHANGED
@@ -166,12 +166,12 @@ class PycharmBootstrap(SimpleBootstrap['PycharmBootstrap.Config']):
166
166
  class Config(Bootstrap.Config):
167
167
  debug_host: ta.Optional[str] = None
168
168
  debug_port: ta.Optional[int] = None
169
- debug_version: ta.Optional[str] = None
169
+ version: ta.Optional[str] = None
170
170
 
171
171
  def run(self) -> None:
172
172
  if self._config.debug_port is not None:
173
173
  diagpc.pycharm_remote_debugger_attach(
174
174
  self._config.debug_host,
175
175
  self._config.debug_port,
176
- version=self._config.debug_version,
176
+ version=self._config.version,
177
177
  )
omlish/check.py CHANGED
@@ -75,6 +75,9 @@ def enable_args_rendering() -> bool:
75
75
  return True
76
76
 
77
77
 
78
+ enable_args_rendering()
79
+
80
+
78
81
  #
79
82
 
80
83
 
@@ -142,7 +145,14 @@ def _unpack_isinstance_spec(spec: ta.Any) -> tuple:
142
145
 
143
146
  def isinstance(v: ta.Any, spec: type[T] | tuple, msg: Message = None) -> T: # noqa
144
147
  if not _isinstance(v, _unpack_isinstance_spec(spec)):
145
- _raise(TypeError, 'Must be instance', msg, _Args(v, spec))
148
+ _raise(
149
+ TypeError,
150
+ 'Must be instance',
151
+ msg,
152
+ _Args(v, spec),
153
+ render_fmt='not isinstance(%s, %s)',
154
+ )
155
+
146
156
  return v
147
157
 
148
158
 
@@ -155,7 +165,13 @@ def of_isinstance(spec: type[T] | tuple, msg: Message = None) -> ta.Callable[[ta
155
165
 
156
166
  def cast(v: ta.Any, cls: type[T], msg: Message = None) -> T: # noqa
157
167
  if not _isinstance(v, cls):
158
- _raise(TypeError, 'Must be instance', msg, _Args(v, cls))
168
+ _raise(
169
+ TypeError,
170
+ 'Must be instance',
171
+ msg,
172
+ _Args(v, cls),
173
+ )
174
+
159
175
  return v
160
176
 
161
177
 
@@ -168,7 +184,14 @@ def of_cast(cls: type[T], msg: Message = None) -> ta.Callable[[T], T]:
168
184
 
169
185
  def not_isinstance(v: T, spec: ta.Any, msg: Message = None) -> T: # noqa
170
186
  if _isinstance(v, _unpack_isinstance_spec(spec)):
171
- _raise(TypeError, 'Must not be instance', msg, _Args(v, spec))
187
+ _raise(
188
+ TypeError,
189
+ 'Must not be instance',
190
+ msg,
191
+ _Args(v, spec),
192
+ render_fmt='isinstance(%s, %s)',
193
+ )
194
+
172
195
  return v
173
196
 
174
197
 
@@ -184,13 +207,27 @@ def of_not_isinstance(spec: ta.Any, msg: Message = None) -> ta.Callable[[T], T]:
184
207
 
185
208
  def issubclass(v: type[T], spec: ta.Any, msg: Message = None) -> type[T]: # noqa
186
209
  if not _issubclass(v, spec):
187
- _raise(TypeError, 'Must be subclass', msg, _Args(v, spec))
210
+ _raise(
211
+ TypeError,
212
+ 'Must be subclass',
213
+ msg,
214
+ _Args(v, spec),
215
+ render_fmt='not issubclass(%s, %s)',
216
+ )
217
+
188
218
  return v
189
219
 
190
220
 
191
221
  def not_issubclass(v: type[T], spec: ta.Any, msg: Message = None) -> type[T]: # noqa
192
222
  if _issubclass(v, spec):
193
- _raise(TypeError, 'Must not be subclass', msg, _Args(v, spec))
223
+ _raise(
224
+ TypeError,
225
+ 'Must not be subclass',
226
+ msg,
227
+ _Args(v, spec),
228
+ render_fmt='issubclass(%s, %s)',
229
+ )
230
+
194
231
  return v
195
232
 
196
233
 
@@ -199,19 +236,40 @@ def not_issubclass(v: type[T], spec: ta.Any, msg: Message = None) -> type[T]: #
199
236
 
200
237
  def in_(v: T, c: ta.Container[T], msg: Message = None) -> T:
201
238
  if v not in c:
202
- _raise(ValueError, 'Must be in', msg, _Args(v, c))
239
+ _raise(
240
+ ValueError,
241
+ 'Must be in',
242
+ msg,
243
+ _Args(v, c),
244
+ render_fmt='%s not in %s',
245
+ )
246
+
203
247
  return v
204
248
 
205
249
 
206
250
  def not_in(v: T, c: ta.Container[T], msg: Message = None) -> T:
207
251
  if v in c:
208
- _raise(ValueError, 'Must not be in', msg, _Args(v, c))
252
+ _raise(
253
+ ValueError,
254
+ 'Must not be in',
255
+ msg,
256
+ _Args(v, c),
257
+ render_fmt='%s in %s',
258
+ )
259
+
209
260
  return v
210
261
 
211
262
 
212
263
  def empty(v: SizedT, msg: Message = None) -> SizedT:
213
264
  if len(v) != 0:
214
- _raise(ValueError, 'Must be empty', msg, _Args(v))
265
+ _raise(
266
+ ValueError,
267
+ 'Must be empty',
268
+ msg,
269
+ _Args(v),
270
+ render_fmt='%s',
271
+ )
272
+
215
273
  return v
216
274
 
217
275
 
@@ -222,20 +280,40 @@ def iterempty(v: ta.Iterable[T], msg: Message = None) -> ta.Iterable[T]:
222
280
  except StopIteration:
223
281
  pass
224
282
  else:
225
- _raise(ValueError, 'Must be empty', msg, _Args(v))
283
+ _raise(
284
+ ValueError,
285
+ 'Must be empty',
286
+ msg,
287
+ _Args(v),
288
+ render_fmt='%s',
289
+ )
290
+
226
291
  return v
227
292
 
228
293
 
229
294
  def not_empty(v: SizedT, msg: Message = None) -> SizedT:
230
295
  if len(v) == 0:
231
- _raise(ValueError, 'Must not be empty', msg, _Args(v))
296
+ _raise(
297
+ ValueError,
298
+ 'Must not be empty',
299
+ msg,
300
+ _Args(v),
301
+ render_fmt='%s',
302
+ )
303
+
232
304
  return v
233
305
 
234
306
 
235
307
  def unique(it: ta.Iterable[T], msg: Message = None) -> ta.Iterable[T]:
236
308
  dupes = [e for e, c in collections.Counter(it).items() if c > 1]
237
309
  if dupes:
238
- _raise(ValueError, 'Must be unique', msg, _Args(it, dupes))
310
+ _raise(
311
+ ValueError,
312
+ 'Must be unique',
313
+ msg,
314
+ _Args(it, dupes),
315
+ )
316
+
239
317
  return it
240
318
 
241
319
 
@@ -243,9 +321,15 @@ def single(obj: ta.Iterable[T], message: Message = None) -> T:
243
321
  try:
244
322
  [value] = obj
245
323
  except ValueError:
246
- _raise(ValueError, 'Must be single', message, _Args(obj))
247
- else:
248
- return value
324
+ _raise(
325
+ ValueError,
326
+ 'Must be single',
327
+ message,
328
+ _Args(obj),
329
+ render_fmt='%s',
330
+ )
331
+
332
+ return value
249
333
 
250
334
 
251
335
  def optional_single(obj: ta.Iterable[T], message: Message = None) -> T | None:
@@ -254,11 +338,19 @@ def optional_single(obj: ta.Iterable[T], message: Message = None) -> T | None:
254
338
  value = next(it)
255
339
  except StopIteration:
256
340
  return None
341
+
257
342
  try:
258
343
  next(it)
259
344
  except StopIteration:
260
345
  return value # noqa
261
- _raise(ValueError, 'Must be empty or single', message, _Args(obj))
346
+
347
+ _raise(
348
+ ValueError,
349
+ 'Must be empty or single',
350
+ message,
351
+ _Args(obj),
352
+ render_fmt='%s',
353
+ )
262
354
 
263
355
 
264
356
  ##
@@ -266,12 +358,25 @@ def optional_single(obj: ta.Iterable[T], message: Message = None) -> T | None:
266
358
 
267
359
  def none(v: ta.Any, msg: Message = None) -> None:
268
360
  if v is not None:
269
- _raise(ValueError, 'Must be None', msg, _Args(v))
361
+ _raise(
362
+ ValueError,
363
+ 'Must be None',
364
+ msg,
365
+ _Args(v),
366
+ render_fmt='%s',
367
+ )
270
368
 
271
369
 
272
370
  def not_none(v: T | None, msg: Message = None) -> T:
273
371
  if v is None:
274
- _raise(ValueError, 'Must not be None', msg, _Args(v))
372
+ _raise(
373
+ ValueError,
374
+ 'Must not be None',
375
+ msg,
376
+ _Args(v),
377
+ render_fmt='%s',
378
+ )
379
+
275
380
  return v
276
381
 
277
382
 
@@ -280,42 +385,115 @@ def not_none(v: T | None, msg: Message = None) -> T:
280
385
 
281
386
  def equal(v: T, o: ta.Any, msg: Message = None) -> T:
282
387
  if o != v:
283
- _raise(ValueError, 'Must be equal', msg, _Args(v, o), render_fmt='%s != %s')
388
+ _raise(
389
+ ValueError,
390
+ 'Must be equal',
391
+ msg,
392
+ _Args(v, o),
393
+ render_fmt='%s != %s',
394
+ )
395
+
284
396
  return v
285
397
 
286
398
 
287
399
  def is_(v: T, o: ta.Any, msg: Message = None) -> T:
288
400
  if o is not v:
289
- _raise(ValueError, 'Must be the same', msg, _Args(v, o), render_fmt='%s is not %s')
401
+ _raise(
402
+ ValueError,
403
+ 'Must be the same',
404
+ msg,
405
+ _Args(v, o),
406
+ render_fmt='%s is not %s',
407
+ )
408
+
290
409
  return v
291
410
 
292
411
 
293
412
  def is_not(v: T, o: ta.Any, msg: Message = None) -> T:
294
413
  if o is v:
295
- _raise(ValueError, 'Must not be the same', msg, _Args(v, o), render_fmt='%s is %s')
414
+ _raise(
415
+ ValueError,
416
+ 'Must not be the same',
417
+ msg,
418
+ _Args(v, o),
419
+ render_fmt='%s is %s',
420
+ )
421
+
296
422
  return v
297
423
 
298
424
 
299
425
  def callable(v: T, msg: Message = None) -> T: # noqa
300
426
  if not _callable(v):
301
- _raise(TypeError, 'Must be callable', msg, _Args(v))
427
+ _raise(
428
+ TypeError,
429
+ 'Must be callable',
430
+ msg,
431
+ _Args(v),
432
+ render_fmt='%s',
433
+ )
434
+
302
435
  return v # type: ignore
303
436
 
304
437
 
305
438
  def non_empty_str(v: str | None, msg: Message = None) -> str:
306
439
  if not _isinstance(v, str) or not v:
307
- _raise(ValueError, 'Must be non-empty str', msg, _Args(v))
440
+ _raise(
441
+ ValueError,
442
+ 'Must be non-empty str',
443
+ msg,
444
+ _Args(v),
445
+ render_fmt='%s',
446
+ )
447
+
308
448
  return v
309
449
 
310
450
 
451
+ def replacing(expected: ta.Any, old: ta.Any, new: T, msg: Message = None) -> T:
452
+ if old != expected:
453
+ _raise(
454
+ ValueError,
455
+ 'Must be replacing',
456
+ msg,
457
+ _Args(expected, old, new),
458
+ render_fmt='%s -> %s -> %s',
459
+ )
460
+
461
+ return new
462
+
463
+
464
+ def replacing_none(old: ta.Any, new: T, msg: Message = None) -> T:
465
+ if old is not None:
466
+ _raise(
467
+ ValueError,
468
+ 'Must be replacing None',
469
+ msg,
470
+ _Args(old, new),
471
+ render_fmt='%s -> %s',
472
+ )
473
+
474
+ return new
475
+
476
+
311
477
  ##
312
478
 
313
479
 
314
480
  def arg(v: bool, msg: Message = None) -> None:
315
481
  if not v:
316
- _raise(RuntimeError, 'Argument condition not met', msg)
482
+ _raise(
483
+ RuntimeError,
484
+ 'Argument condition not met',
485
+ msg,
486
+ _Args(v),
487
+ render_fmt='%s',
488
+ )
317
489
 
318
490
 
319
491
  def state(v: bool, msg: Message = None) -> None:
320
492
  if not v:
321
- _raise(RuntimeError, 'State condition not met', msg)
493
+ _raise(
494
+ RuntimeError,
495
+ 'State condition not met',
496
+ msg,
497
+ _Args(v),
498
+ render_fmt='%s',
499
+ )
@@ -95,12 +95,12 @@ from .utils import ( # noqa
95
95
  all_not_equal,
96
96
  indexes,
97
97
  key_cmp,
98
+ make_map,
99
+ make_map_by,
98
100
  multi_map,
99
101
  multi_map_by,
100
102
  mut_toposort,
101
103
  partition,
102
104
  toposort,
103
105
  unique,
104
- unique_map,
105
- unique_map_by,
106
106
  )
@@ -72,7 +72,7 @@ def unique(
72
72
  return ret
73
73
 
74
74
 
75
- def unique_map(
75
+ def make_map(
76
76
  kvs: ta.Iterable[tuple[K, V]],
77
77
  *,
78
78
  identity: bool = False,
@@ -88,14 +88,14 @@ def unique_map(
88
88
  return d
89
89
 
90
90
 
91
- def unique_map_by(
91
+ def make_map_by(
92
92
  fn: ta.Callable[[V], K],
93
93
  vs: ta.Iterable[V],
94
94
  *,
95
95
  identity: bool = False,
96
96
  strict: bool = False,
97
97
  ) -> ta.MutableMapping[K, V]:
98
- return unique_map(
98
+ return make_map(
99
99
  ((fn(v), v) for v in vs),
100
100
  identity=identity,
101
101
  strict=strict,
@@ -1,3 +1,8 @@
1
+ """
2
+ An abstraction over greenlet's api. Greenlet doesn't currently support nogil but its functionality is needed for async
3
+ bridge code (both here and in sqlalchemy). This can be implemented with real threads at the expense of overhead, but
4
+ this code is only intended to be used in already fairly heavy situations (bootstrap, db calls).
5
+ """
1
6
  import abc
2
7
  import dataclasses as dc
3
8
  import typing as ta
@@ -94,6 +94,7 @@ from .utils import ( # noqa
94
94
  field_modifier,
95
95
  maybe_post_init,
96
96
  opt_repr,
97
+ update_class_metadata,
97
98
  update_field_extras,
98
99
  update_field_metadata,
99
100
  update_fields,