omlish 0.0.0.dev123__py3-none-any.whl → 0.0.0.dev125__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.
- omlish/__about__.py +3 -2
- omlish/__init__.py +3 -0
- omlish/antlr/_runtime/LICENSE.txt +28 -0
- omlish/c3.py +35 -37
- omlish/dataclasses/__init__.py +4 -0
- omlish/dataclasses/utils.py +22 -4
- omlish/http/consts.py +2 -0
- omlish/inject/impl/inspect.py +4 -2
- omlish/lang/__init__.py +3 -0
- omlish/lang/typing.py +8 -0
- omlish/lite/check.py +5 -0
- omlish/lite/http/__init__.py +0 -0
- omlish/lite/http/coroserver.py +585 -0
- omlish/lite/http/handlers.py +36 -0
- omlish/lite/http/parsing.py +376 -0
- omlish/lite/http/versions.py +17 -0
- omlish/lite/inject.py +153 -82
- omlish/lite/journald.py +0 -1
- omlish/lite/runtime.py +1 -2
- omlish/lite/socket.py +77 -0
- omlish/lite/socketserver.py +66 -0
- omlish/lite/typing.py +13 -0
- omlish-0.0.0.dev125.dist-info/METADATA +100 -0
- {omlish-0.0.0.dev123.dist-info → omlish-0.0.0.dev125.dist-info}/RECORD +28 -19
- {omlish-0.0.0.dev123.dist-info → omlish-0.0.0.dev125.dist-info}/WHEEL +1 -1
- omlish-0.0.0.dev123.dist-info/METADATA +0 -94
- {omlish-0.0.0.dev123.dist-info → omlish-0.0.0.dev125.dist-info}/LICENSE +0 -0
- {omlish-0.0.0.dev123.dist-info → omlish-0.0.0.dev125.dist-info}/entry_points.txt +0 -0
- {omlish-0.0.0.dev123.dist-info → omlish-0.0.0.dev125.dist-info}/top_level.txt +0 -0
omlish/lite/inject.py
CHANGED
@@ -9,10 +9,12 @@ import weakref
|
|
9
9
|
|
10
10
|
from .check import check_isinstance
|
11
11
|
from .check import check_not_isinstance
|
12
|
+
from .check import check_not_none
|
12
13
|
from .maybes import Maybe
|
13
14
|
from .reflect import get_optional_alias_arg
|
14
15
|
from .reflect import is_new_type
|
15
16
|
from .reflect import is_optional_alias
|
17
|
+
from .typing import Func
|
16
18
|
|
17
19
|
|
18
20
|
T = ta.TypeVar('T')
|
@@ -30,12 +32,28 @@ InjectorBindingOrBindings = ta.Union['InjectorBinding', 'InjectorBindings']
|
|
30
32
|
|
31
33
|
|
32
34
|
@dc.dataclass(frozen=True)
|
33
|
-
class InjectorKey:
|
34
|
-
cls
|
35
|
+
class InjectorKey(ta.Generic[T]):
|
36
|
+
# Before PEP-560 typing.Generic was a metaclass with a __new__ that takes a 'cls' arg, so instantiating a dataclass
|
37
|
+
# with kwargs (such as through dc.replace) causes `TypeError: __new__() got multiple values for argument 'cls'`.
|
38
|
+
# See:
|
39
|
+
# - https://github.com/python/cpython/commit/d911e40e788fb679723d78b6ea11cabf46caed5a
|
40
|
+
# - https://gist.github.com/wrmsr/4468b86efe9f373b6b114bfe85b98fd3
|
41
|
+
cls_: InjectorKeyCls
|
42
|
+
|
35
43
|
tag: ta.Any = None
|
36
44
|
array: bool = False
|
37
45
|
|
38
46
|
|
47
|
+
def is_valid_injector_key_cls(cls: ta.Any) -> bool:
|
48
|
+
return isinstance(cls, type) or is_new_type(cls)
|
49
|
+
|
50
|
+
|
51
|
+
def check_valid_injector_key_cls(cls: T) -> T:
|
52
|
+
if not is_valid_injector_key_cls(cls):
|
53
|
+
raise TypeError(cls)
|
54
|
+
return cls
|
55
|
+
|
56
|
+
|
39
57
|
##
|
40
58
|
|
41
59
|
|
@@ -79,6 +97,12 @@ class Injector(abc.ABC):
|
|
79
97
|
def inject(self, obj: ta.Any) -> ta.Any:
|
80
98
|
raise NotImplementedError
|
81
99
|
|
100
|
+
def __getitem__(
|
101
|
+
self,
|
102
|
+
target: ta.Union[InjectorKey[T], ta.Type[T]],
|
103
|
+
) -> T:
|
104
|
+
return self.provide(target)
|
105
|
+
|
82
106
|
|
83
107
|
###
|
84
108
|
# exceptions
|
@@ -111,7 +135,7 @@ def as_injector_key(o: ta.Any) -> InjectorKey:
|
|
111
135
|
raise TypeError(o)
|
112
136
|
if isinstance(o, InjectorKey):
|
113
137
|
return o
|
114
|
-
if
|
138
|
+
if is_valid_injector_key_cls(o):
|
115
139
|
return InjectorKey(o)
|
116
140
|
raise TypeError(o)
|
117
141
|
|
@@ -136,14 +160,14 @@ class FnInjectorProvider(InjectorProvider):
|
|
136
160
|
|
137
161
|
@dc.dataclass(frozen=True)
|
138
162
|
class CtorInjectorProvider(InjectorProvider):
|
139
|
-
|
163
|
+
cls_: type
|
140
164
|
|
141
165
|
def __post_init__(self) -> None:
|
142
|
-
check_isinstance(self.
|
166
|
+
check_isinstance(self.cls_, type)
|
143
167
|
|
144
168
|
def provider_fn(self) -> InjectorProviderFn:
|
145
169
|
def pfn(i: Injector) -> ta.Any:
|
146
|
-
return i.inject(self.
|
170
|
+
return i.inject(self.cls_)
|
147
171
|
|
148
172
|
return pfn
|
149
173
|
|
@@ -292,19 +316,42 @@ def build_injector_provider_map(bs: InjectorBindings) -> ta.Mapping[InjectorKey,
|
|
292
316
|
# inspection
|
293
317
|
|
294
318
|
|
295
|
-
|
319
|
+
# inspect.signature(eval_str=True) was added in 3.10 and we have to support 3.8, so we have to get_type_hints to eval
|
320
|
+
# str annotations *in addition to* getting the signature for parameter information.
|
321
|
+
class _InjectionInspection(ta.NamedTuple):
|
322
|
+
signature: inspect.Signature
|
323
|
+
type_hints: ta.Mapping[str, ta.Any]
|
324
|
+
|
325
|
+
|
326
|
+
_INJECTION_INSPECTION_CACHE: ta.MutableMapping[ta.Any, _InjectionInspection] = weakref.WeakKeyDictionary()
|
327
|
+
|
296
328
|
|
329
|
+
def _do_injection_inspect(obj: ta.Any) -> _InjectionInspection:
|
330
|
+
uw = obj
|
331
|
+
while True:
|
332
|
+
if isinstance(uw, functools.partial):
|
333
|
+
uw = uw.func
|
334
|
+
else:
|
335
|
+
if (uw2 := inspect.unwrap(uw)) is uw:
|
336
|
+
break
|
337
|
+
uw = uw2
|
338
|
+
|
339
|
+
return _InjectionInspection(
|
340
|
+
inspect.signature(obj),
|
341
|
+
ta.get_type_hints(uw),
|
342
|
+
)
|
297
343
|
|
298
|
-
|
344
|
+
|
345
|
+
def _injection_inspect(obj: ta.Any) -> _InjectionInspection:
|
299
346
|
try:
|
300
|
-
return
|
347
|
+
return _INJECTION_INSPECTION_CACHE[obj]
|
301
348
|
except TypeError:
|
302
|
-
return
|
349
|
+
return _do_injection_inspect(obj)
|
303
350
|
except KeyError:
|
304
351
|
pass
|
305
|
-
|
306
|
-
|
307
|
-
return
|
352
|
+
insp = _do_injection_inspect(obj)
|
353
|
+
_INJECTION_INSPECTION_CACHE[obj] = insp
|
354
|
+
return insp
|
308
355
|
|
309
356
|
|
310
357
|
class InjectionKwarg(ta.NamedTuple):
|
@@ -325,20 +372,20 @@ def build_injection_kwargs_target(
|
|
325
372
|
skip_kwargs: ta.Optional[ta.Iterable[ta.Any]] = None,
|
326
373
|
raw_optional: bool = False,
|
327
374
|
) -> InjectionKwargsTarget:
|
328
|
-
|
375
|
+
insp = _injection_inspect(obj)
|
329
376
|
|
330
377
|
seen: ta.Set[InjectorKey] = set(map(as_injector_key, skip_kwargs)) if skip_kwargs is not None else set()
|
331
378
|
kws: ta.List[InjectionKwarg] = []
|
332
|
-
for p in list(
|
379
|
+
for p in list(insp.signature.parameters.values())[skip_args:]:
|
333
380
|
if p.annotation is inspect.Signature.empty:
|
334
381
|
if p.default is not inspect.Parameter.empty:
|
335
382
|
raise KeyError(f'{obj}, {p.name}')
|
336
383
|
continue
|
337
384
|
|
338
385
|
if p.kind not in (inspect.Parameter.POSITIONAL_OR_KEYWORD, inspect.Parameter.KEYWORD_ONLY):
|
339
|
-
raise TypeError(
|
386
|
+
raise TypeError(insp)
|
340
387
|
|
341
|
-
ann = p.annotation
|
388
|
+
ann = insp.type_hints.get(p.name, p.annotation)
|
342
389
|
if (
|
343
390
|
not raw_optional and
|
344
391
|
is_optional_alias(ann)
|
@@ -363,6 +410,66 @@ def build_injection_kwargs_target(
|
|
363
410
|
)
|
364
411
|
|
365
412
|
|
413
|
+
###
|
414
|
+
# injector
|
415
|
+
|
416
|
+
|
417
|
+
_INJECTOR_INJECTOR_KEY: InjectorKey[Injector] = InjectorKey(Injector)
|
418
|
+
|
419
|
+
|
420
|
+
class _Injector(Injector):
|
421
|
+
def __init__(self, bs: InjectorBindings, p: ta.Optional[Injector] = None) -> None:
|
422
|
+
super().__init__()
|
423
|
+
|
424
|
+
self._bs = check_isinstance(bs, InjectorBindings)
|
425
|
+
self._p: ta.Optional[Injector] = check_isinstance(p, (Injector, type(None)))
|
426
|
+
|
427
|
+
self._pfm = {k: v.provider_fn() for k, v in build_injector_provider_map(bs).items()}
|
428
|
+
|
429
|
+
if _INJECTOR_INJECTOR_KEY in self._pfm:
|
430
|
+
raise DuplicateInjectorKeyError(_INJECTOR_INJECTOR_KEY)
|
431
|
+
|
432
|
+
def try_provide(self, key: ta.Any) -> Maybe[ta.Any]:
|
433
|
+
key = as_injector_key(key)
|
434
|
+
|
435
|
+
if key == _INJECTOR_INJECTOR_KEY:
|
436
|
+
return Maybe.just(self)
|
437
|
+
|
438
|
+
fn = self._pfm.get(key)
|
439
|
+
if fn is not None:
|
440
|
+
return Maybe.just(fn(self))
|
441
|
+
|
442
|
+
if self._p is not None:
|
443
|
+
pv = self._p.try_provide(key)
|
444
|
+
if pv is not None:
|
445
|
+
return Maybe.empty()
|
446
|
+
|
447
|
+
return Maybe.empty()
|
448
|
+
|
449
|
+
def provide(self, key: ta.Any) -> ta.Any:
|
450
|
+
v = self.try_provide(key)
|
451
|
+
if v.present:
|
452
|
+
return v.must()
|
453
|
+
raise UnboundInjectorKeyError(key)
|
454
|
+
|
455
|
+
def provide_kwargs(self, obj: ta.Any) -> ta.Mapping[str, ta.Any]:
|
456
|
+
kt = build_injection_kwargs_target(obj)
|
457
|
+
ret: ta.Dict[str, ta.Any] = {}
|
458
|
+
for kw in kt.kwargs:
|
459
|
+
if kw.has_default:
|
460
|
+
if not (mv := self.try_provide(kw.key)).present:
|
461
|
+
continue
|
462
|
+
v = mv.must()
|
463
|
+
else:
|
464
|
+
v = self.provide(kw.key)
|
465
|
+
ret[kw.name] = v
|
466
|
+
return ret
|
467
|
+
|
468
|
+
def inject(self, obj: ta.Any) -> ta.Any:
|
469
|
+
kws = self.provide_kwargs(obj)
|
470
|
+
return obj(**kws)
|
471
|
+
|
472
|
+
|
366
473
|
###
|
367
474
|
# binder
|
368
475
|
|
@@ -412,7 +519,7 @@ class InjectorBinder:
|
|
412
519
|
to_key: ta.Any = None,
|
413
520
|
|
414
521
|
singleton: bool = False,
|
415
|
-
) ->
|
522
|
+
) -> InjectorBindingOrBindings:
|
416
523
|
if obj is None or obj is inspect.Parameter.empty:
|
417
524
|
raise TypeError(obj)
|
418
525
|
if isinstance(obj, cls._BANNED_BIND_TYPES):
|
@@ -442,9 +549,9 @@ class InjectorBinder:
|
|
442
549
|
elif cls._is_fn(obj) and not has_to:
|
443
550
|
to_fn = obj
|
444
551
|
if key is None:
|
445
|
-
|
446
|
-
|
447
|
-
key = InjectorKey(
|
552
|
+
insp = _injection_inspect(obj)
|
553
|
+
key_cls: ta.Any = check_valid_injector_key_cls(check_not_none(insp.type_hints.get('return')))
|
554
|
+
key = InjectorKey(key_cls)
|
448
555
|
else:
|
449
556
|
if to_const is not None:
|
450
557
|
raise TypeError('Cannot bind instance with to_const')
|
@@ -495,67 +602,21 @@ class InjectorBinder:
|
|
495
602
|
|
496
603
|
|
497
604
|
###
|
498
|
-
#
|
499
|
-
|
500
|
-
|
501
|
-
_INJECTOR_INJECTOR_KEY = InjectorKey(Injector)
|
502
|
-
|
503
|
-
|
504
|
-
class _Injector(Injector):
|
505
|
-
def __init__(self, bs: InjectorBindings, p: ta.Optional[Injector] = None) -> None:
|
506
|
-
super().__init__()
|
507
|
-
|
508
|
-
self._bs = check_isinstance(bs, InjectorBindings)
|
509
|
-
self._p: ta.Optional[Injector] = check_isinstance(p, (Injector, type(None)))
|
510
|
-
|
511
|
-
self._pfm = {k: v.provider_fn() for k, v in build_injector_provider_map(bs).items()}
|
512
|
-
|
513
|
-
if _INJECTOR_INJECTOR_KEY in self._pfm:
|
514
|
-
raise DuplicateInjectorKeyError(_INJECTOR_INJECTOR_KEY)
|
515
|
-
|
516
|
-
def try_provide(self, key: ta.Any) -> Maybe[ta.Any]:
|
517
|
-
key = as_injector_key(key)
|
518
|
-
|
519
|
-
if key == _INJECTOR_INJECTOR_KEY:
|
520
|
-
return Maybe.just(self)
|
521
|
-
|
522
|
-
fn = self._pfm.get(key)
|
523
|
-
if fn is not None:
|
524
|
-
return Maybe.just(fn(self))
|
525
|
-
|
526
|
-
if self._p is not None:
|
527
|
-
pv = self._p.try_provide(key)
|
528
|
-
if pv is not None:
|
529
|
-
return Maybe.empty()
|
530
|
-
|
531
|
-
return Maybe.empty()
|
605
|
+
# injection helpers
|
532
606
|
|
533
|
-
def provide(self, key: ta.Any) -> ta.Any:
|
534
|
-
v = self.try_provide(key)
|
535
|
-
if v.present:
|
536
|
-
return v.must()
|
537
|
-
raise UnboundInjectorKeyError(key)
|
538
607
|
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
v = self.provide(kw.key)
|
549
|
-
ret[kw.name] = v
|
550
|
-
return ret
|
608
|
+
def make_injector_factory(
|
609
|
+
factory_cls: ta.Any,
|
610
|
+
factory_fn: ta.Callable[..., T],
|
611
|
+
) -> ta.Callable[..., Func[T]]:
|
612
|
+
def outer(injector: Injector) -> factory_cls:
|
613
|
+
def inner(*args, **kwargs):
|
614
|
+
return injector.inject(functools.partial(factory_fn, *args, **kwargs))
|
615
|
+
return Func(inner)
|
616
|
+
return outer
|
551
617
|
|
552
|
-
def inject(self, obj: ta.Any) -> ta.Any:
|
553
|
-
kws = self.provide_kwargs(obj)
|
554
|
-
return obj(**kws)
|
555
618
|
|
556
|
-
|
557
|
-
###
|
558
|
-
# injection helpers
|
619
|
+
##
|
559
620
|
|
560
621
|
|
561
622
|
class Injection:
|
@@ -586,6 +647,12 @@ class Injection:
|
|
586
647
|
def override(cls, p: InjectorBindings, *args: InjectorBindingOrBindings) -> InjectorBindings:
|
587
648
|
return injector_override(p, *args)
|
588
649
|
|
650
|
+
# injector
|
651
|
+
|
652
|
+
@classmethod
|
653
|
+
def create_injector(cls, *args: InjectorBindingOrBindings, p: ta.Optional[Injector] = None) -> Injector:
|
654
|
+
return _Injector(as_injector_bindings(*args), p)
|
655
|
+
|
589
656
|
# binder
|
590
657
|
|
591
658
|
@classmethod
|
@@ -603,7 +670,7 @@ class Injection:
|
|
603
670
|
to_key: ta.Any = None,
|
604
671
|
|
605
672
|
singleton: bool = False,
|
606
|
-
) ->
|
673
|
+
) -> InjectorBindingOrBindings:
|
607
674
|
return InjectorBinder.bind(
|
608
675
|
obj,
|
609
676
|
|
@@ -619,11 +686,15 @@ class Injection:
|
|
619
686
|
singleton=singleton,
|
620
687
|
)
|
621
688
|
|
622
|
-
#
|
689
|
+
# helpers
|
623
690
|
|
624
691
|
@classmethod
|
625
|
-
def
|
626
|
-
|
692
|
+
def bind_factory(
|
693
|
+
cls,
|
694
|
+
factory_cls: ta.Any,
|
695
|
+
factory_fn: ta.Callable[..., T],
|
696
|
+
) -> InjectorBindingOrBindings:
|
697
|
+
return cls.bind(make_injector_factory(factory_cls, factory_fn))
|
627
698
|
|
628
699
|
|
629
700
|
inj = Injection
|
omlish/lite/journald.py
CHANGED
@@ -29,7 +29,6 @@ sd_iovec._fields_ = [
|
|
29
29
|
def sd_libsystemd() -> ta.Any:
|
30
30
|
lib = ct.CDLL('libsystemd.so.0')
|
31
31
|
|
32
|
-
lib.sd_journal_sendv = lib['sd_journal_sendv'] # type: ignore
|
33
32
|
lib.sd_journal_sendv.restype = ct.c_int
|
34
33
|
lib.sd_journal_sendv.argtypes = [ct.POINTER(sd_iovec), ct.c_int]
|
35
34
|
|
omlish/lite/runtime.py
CHANGED
@@ -14,5 +14,4 @@ REQUIRED_PYTHON_VERSION = (3, 8)
|
|
14
14
|
|
15
15
|
def check_runtime_version() -> None:
|
16
16
|
if sys.version_info < REQUIRED_PYTHON_VERSION:
|
17
|
-
raise OSError(
|
18
|
-
f'Requires python {REQUIRED_PYTHON_VERSION}, got {sys.version_info} from {sys.executable}') # noqa
|
17
|
+
raise OSError(f'Requires python {REQUIRED_PYTHON_VERSION}, got {sys.version_info} from {sys.executable}') # noqa
|
omlish/lite/socket.py
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
# ruff: noqa: UP006 UP007
|
2
|
+
"""
|
3
|
+
TODO:
|
4
|
+
- SocketClientAddress family / tuple pairs
|
5
|
+
+ codification of https://docs.python.org/3/library/socket.html#socket-families
|
6
|
+
"""
|
7
|
+
import abc
|
8
|
+
import dataclasses as dc
|
9
|
+
import socket
|
10
|
+
import typing as ta
|
11
|
+
|
12
|
+
|
13
|
+
SocketAddress = ta.Any
|
14
|
+
|
15
|
+
|
16
|
+
SocketHandlerFactory = ta.Callable[[SocketAddress, ta.BinaryIO, ta.BinaryIO], 'SocketHandler']
|
17
|
+
|
18
|
+
|
19
|
+
##
|
20
|
+
|
21
|
+
|
22
|
+
@dc.dataclass(frozen=True)
|
23
|
+
class SocketAddressInfoArgs:
|
24
|
+
host: ta.Optional[str]
|
25
|
+
port: ta.Union[str, int, None]
|
26
|
+
family: socket.AddressFamily = socket.AddressFamily.AF_UNSPEC
|
27
|
+
type: int = 0
|
28
|
+
proto: int = 0
|
29
|
+
flags: socket.AddressInfo = socket.AddressInfo(0)
|
30
|
+
|
31
|
+
|
32
|
+
@dc.dataclass(frozen=True)
|
33
|
+
class SocketAddressInfo:
|
34
|
+
family: socket.AddressFamily
|
35
|
+
type: int
|
36
|
+
proto: int
|
37
|
+
canonname: ta.Optional[str]
|
38
|
+
sockaddr: SocketAddress
|
39
|
+
|
40
|
+
|
41
|
+
def get_best_socket_family(
|
42
|
+
host: ta.Optional[str],
|
43
|
+
port: ta.Union[str, int, None],
|
44
|
+
family: ta.Union[int, socket.AddressFamily] = socket.AddressFamily.AF_UNSPEC,
|
45
|
+
) -> ta.Tuple[socket.AddressFamily, SocketAddress]:
|
46
|
+
"""https://github.com/python/cpython/commit/f289084c83190cc72db4a70c58f007ec62e75247"""
|
47
|
+
|
48
|
+
infos = socket.getaddrinfo(
|
49
|
+
host,
|
50
|
+
port,
|
51
|
+
family,
|
52
|
+
type=socket.SOCK_STREAM,
|
53
|
+
flags=socket.AI_PASSIVE,
|
54
|
+
)
|
55
|
+
ai = SocketAddressInfo(*next(iter(infos)))
|
56
|
+
return ai.family, ai.sockaddr
|
57
|
+
|
58
|
+
|
59
|
+
##
|
60
|
+
|
61
|
+
|
62
|
+
class SocketHandler(abc.ABC):
|
63
|
+
def __init__(
|
64
|
+
self,
|
65
|
+
client_address: SocketAddress,
|
66
|
+
rfile: ta.BinaryIO,
|
67
|
+
wfile: ta.BinaryIO,
|
68
|
+
) -> None:
|
69
|
+
super().__init__()
|
70
|
+
|
71
|
+
self._client_address = client_address
|
72
|
+
self._rfile = rfile
|
73
|
+
self._wfile = wfile
|
74
|
+
|
75
|
+
@abc.abstractmethod
|
76
|
+
def handle(self) -> None:
|
77
|
+
raise NotImplementedError
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# ruff: noqa: UP006 UP007
|
2
|
+
import socket
|
3
|
+
import socketserver
|
4
|
+
import typing as ta
|
5
|
+
|
6
|
+
from omlish.lite.check import check_not_none
|
7
|
+
|
8
|
+
from .socket import SocketAddress
|
9
|
+
from .socket import SocketHandlerFactory
|
10
|
+
|
11
|
+
|
12
|
+
##
|
13
|
+
|
14
|
+
|
15
|
+
class SocketServerBaseRequestHandler_: # noqa
|
16
|
+
request: socket.socket
|
17
|
+
client_address: SocketAddress
|
18
|
+
server: socketserver.TCPServer
|
19
|
+
|
20
|
+
|
21
|
+
class SocketServerStreamRequestHandler_(SocketServerBaseRequestHandler_): # noqa
|
22
|
+
rbufsize: int
|
23
|
+
wbufsize: int
|
24
|
+
|
25
|
+
timeout: ta.Optional[float]
|
26
|
+
|
27
|
+
disable_nagle_algorithm: bool
|
28
|
+
|
29
|
+
connection: socket.socket
|
30
|
+
rfile: ta.BinaryIO
|
31
|
+
wfile: ta.BinaryIO
|
32
|
+
|
33
|
+
|
34
|
+
##
|
35
|
+
|
36
|
+
|
37
|
+
class SocketHandlerSocketServerStreamRequestHandler( # type: ignore[misc]
|
38
|
+
socketserver.StreamRequestHandler,
|
39
|
+
SocketServerStreamRequestHandler_,
|
40
|
+
):
|
41
|
+
socket_handler_factory: ta.Optional[SocketHandlerFactory] = None
|
42
|
+
|
43
|
+
def __init__(
|
44
|
+
self,
|
45
|
+
request: socket.socket,
|
46
|
+
client_address: SocketAddress,
|
47
|
+
server: socketserver.TCPServer,
|
48
|
+
*,
|
49
|
+
socket_handler_factory: ta.Optional[SocketHandlerFactory] = None,
|
50
|
+
) -> None:
|
51
|
+
if socket_handler_factory is not None:
|
52
|
+
self.socket_handler_factory = socket_handler_factory
|
53
|
+
|
54
|
+
super().__init__(
|
55
|
+
request,
|
56
|
+
client_address,
|
57
|
+
server,
|
58
|
+
)
|
59
|
+
|
60
|
+
def handle(self) -> None:
|
61
|
+
target = check_not_none(self.socket_handler_factory)(
|
62
|
+
self.client_address,
|
63
|
+
self.rfile, # type: ignore[arg-type]
|
64
|
+
self.wfile, # type: ignore[arg-type]
|
65
|
+
)
|
66
|
+
target.handle()
|
omlish/lite/typing.py
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
import dataclasses as dc
|
2
|
+
import typing as ta
|
3
|
+
|
4
|
+
|
5
|
+
T = ta.TypeVar('T')
|
6
|
+
|
7
|
+
|
8
|
+
@dc.dataclass(frozen=True)
|
9
|
+
class Func(ta.Generic[T]):
|
10
|
+
fn: ta.Callable[..., T]
|
11
|
+
|
12
|
+
def __call__(self, *args: ta.Any, **kwargs: ta.Any) -> T:
|
13
|
+
return self.fn(*args, **kwargs)
|
@@ -0,0 +1,100 @@
|
|
1
|
+
Metadata-Version: 2.1
|
2
|
+
Name: omlish
|
3
|
+
Version: 0.0.0.dev125
|
4
|
+
Summary: omlish
|
5
|
+
Author: wrmsr
|
6
|
+
License: BSD-3-Clause
|
7
|
+
Project-URL: source, https://github.com/wrmsr/omlish
|
8
|
+
Classifier: License :: OSI Approved :: BSD License
|
9
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
10
|
+
Classifier: Intended Audience :: Developers
|
11
|
+
Classifier: Operating System :: OS Independent
|
12
|
+
Classifier: Operating System :: POSIX
|
13
|
+
Requires-Python: >=3.12
|
14
|
+
License-File: LICENSE
|
15
|
+
Provides-Extra: all
|
16
|
+
Requires-Dist: anyio~=4.6; extra == "all"
|
17
|
+
Requires-Dist: sniffio~=1.3; extra == "all"
|
18
|
+
Requires-Dist: greenlet~=3.1; extra == "all"
|
19
|
+
Requires-Dist: trio~=0.27; extra == "all"
|
20
|
+
Requires-Dist: trio-asyncio~=0.15; extra == "all"
|
21
|
+
Requires-Dist: lz4~=4.3; extra == "all"
|
22
|
+
Requires-Dist: python-snappy~=0.7; extra == "all"
|
23
|
+
Requires-Dist: zstandard~=0.23; extra == "all"
|
24
|
+
Requires-Dist: asttokens~=2.4; extra == "all"
|
25
|
+
Requires-Dist: executing~=2.1; extra == "all"
|
26
|
+
Requires-Dist: psutil~=6.0; extra == "all"
|
27
|
+
Requires-Dist: orjson~=3.10; extra == "all"
|
28
|
+
Requires-Dist: ujson~=5.10; extra == "all"
|
29
|
+
Requires-Dist: json5~=0.9; extra == "all"
|
30
|
+
Requires-Dist: pyyaml~=6.0; extra == "all"
|
31
|
+
Requires-Dist: cbor2~=5.6; extra == "all"
|
32
|
+
Requires-Dist: cloudpickle~=3.1; extra == "all"
|
33
|
+
Requires-Dist: httpx[http2]~=0.27; extra == "all"
|
34
|
+
Requires-Dist: wrapt~=1.14; extra == "all"
|
35
|
+
Requires-Dist: cryptography~=43.0; extra == "all"
|
36
|
+
Requires-Dist: sqlalchemy[asyncio]~=2.0; extra == "all"
|
37
|
+
Requires-Dist: pg8000~=1.31; extra == "all"
|
38
|
+
Requires-Dist: pymysql~=1.1; extra == "all"
|
39
|
+
Requires-Dist: aiomysql~=0.2; extra == "all"
|
40
|
+
Requires-Dist: aiosqlite~=0.20; extra == "all"
|
41
|
+
Requires-Dist: asyncpg~=0.30; extra == "all"
|
42
|
+
Requires-Dist: apsw~=3.46; extra == "all"
|
43
|
+
Requires-Dist: sqlean.py~=3.45; extra == "all"
|
44
|
+
Requires-Dist: duckdb~=1.1; extra == "all"
|
45
|
+
Requires-Dist: pytest~=8.0; extra == "all"
|
46
|
+
Requires-Dist: anyio~=4.6; extra == "all"
|
47
|
+
Requires-Dist: sniffio~=1.3; extra == "all"
|
48
|
+
Requires-Dist: asttokens~=2.4; extra == "all"
|
49
|
+
Requires-Dist: executing~=2.1; extra == "all"
|
50
|
+
Requires-Dist: orjson~=3.10; extra == "all"
|
51
|
+
Requires-Dist: pyyaml~=6.0; extra == "all"
|
52
|
+
Requires-Dist: wrapt~=1.14; extra == "all"
|
53
|
+
Provides-Extra: async
|
54
|
+
Requires-Dist: anyio~=4.6; extra == "async"
|
55
|
+
Requires-Dist: sniffio~=1.3; extra == "async"
|
56
|
+
Requires-Dist: greenlet~=3.1; extra == "async"
|
57
|
+
Requires-Dist: trio~=0.27; extra == "async"
|
58
|
+
Requires-Dist: trio-asyncio~=0.15; extra == "async"
|
59
|
+
Provides-Extra: compress
|
60
|
+
Requires-Dist: lz4~=4.3; extra == "compress"
|
61
|
+
Requires-Dist: python-snappy~=0.7; extra == "compress"
|
62
|
+
Requires-Dist: zstandard~=0.23; extra == "compress"
|
63
|
+
Provides-Extra: diag
|
64
|
+
Requires-Dist: asttokens~=2.4; extra == "diag"
|
65
|
+
Requires-Dist: executing~=2.1; extra == "diag"
|
66
|
+
Requires-Dist: psutil~=6.0; extra == "diag"
|
67
|
+
Provides-Extra: formats
|
68
|
+
Requires-Dist: orjson~=3.10; extra == "formats"
|
69
|
+
Requires-Dist: ujson~=5.10; extra == "formats"
|
70
|
+
Requires-Dist: json5~=0.9; extra == "formats"
|
71
|
+
Requires-Dist: pyyaml~=6.0; extra == "formats"
|
72
|
+
Requires-Dist: cbor2~=5.6; extra == "formats"
|
73
|
+
Requires-Dist: cloudpickle~=3.1; extra == "formats"
|
74
|
+
Provides-Extra: http
|
75
|
+
Requires-Dist: httpx[http2]~=0.27; extra == "http"
|
76
|
+
Provides-Extra: misc
|
77
|
+
Requires-Dist: wrapt~=1.14; extra == "misc"
|
78
|
+
Provides-Extra: secrets
|
79
|
+
Requires-Dist: cryptography~=43.0; extra == "secrets"
|
80
|
+
Provides-Extra: sqlalchemy
|
81
|
+
Requires-Dist: sqlalchemy[asyncio]~=2.0; extra == "sqlalchemy"
|
82
|
+
Provides-Extra: sqldrivers
|
83
|
+
Requires-Dist: pg8000~=1.31; extra == "sqldrivers"
|
84
|
+
Requires-Dist: pymysql~=1.1; extra == "sqldrivers"
|
85
|
+
Requires-Dist: aiomysql~=0.2; extra == "sqldrivers"
|
86
|
+
Requires-Dist: aiosqlite~=0.20; extra == "sqldrivers"
|
87
|
+
Requires-Dist: asyncpg~=0.30; extra == "sqldrivers"
|
88
|
+
Requires-Dist: apsw~=3.46; extra == "sqldrivers"
|
89
|
+
Requires-Dist: sqlean.py~=3.45; extra == "sqldrivers"
|
90
|
+
Requires-Dist: duckdb~=1.1; extra == "sqldrivers"
|
91
|
+
Provides-Extra: testing
|
92
|
+
Requires-Dist: pytest~=8.0; extra == "testing"
|
93
|
+
Provides-Extra: plus
|
94
|
+
Requires-Dist: anyio~=4.6; extra == "plus"
|
95
|
+
Requires-Dist: sniffio~=1.3; extra == "plus"
|
96
|
+
Requires-Dist: asttokens~=2.4; extra == "plus"
|
97
|
+
Requires-Dist: executing~=2.1; extra == "plus"
|
98
|
+
Requires-Dist: orjson~=3.10; extra == "plus"
|
99
|
+
Requires-Dist: pyyaml~=6.0; extra == "plus"
|
100
|
+
Requires-Dist: wrapt~=1.14; extra == "plus"
|