ominfra 0.0.0.dev148__py3-none-any.whl → 0.0.0.dev150__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 (36) hide show
  1. ominfra/clouds/aws/auth.py +7 -9
  2. ominfra/clouds/aws/cli.py +1 -1
  3. ominfra/clouds/aws/journald2aws/driver.py +4 -4
  4. ominfra/clouds/aws/logs.py +4 -5
  5. ominfra/clouds/gcp/auth.py +1 -1
  6. ominfra/configs.py +3 -4
  7. ominfra/journald/messages.py +3 -3
  8. ominfra/journald/tailer.py +2 -2
  9. ominfra/manage/commands/base.py +2 -2
  10. ominfra/manage/commands/interp.py +3 -3
  11. ominfra/manage/commands/subprocess.py +3 -4
  12. ominfra/manage/deploy/paths.py +12 -15
  13. ominfra/manage/main.py +72 -75
  14. ominfra/manage/remote/_main.py +6 -7
  15. ominfra/manage/remote/execution.py +7 -10
  16. ominfra/manage/remote/spawning.py +3 -3
  17. ominfra/scripts/journald2aws.py +508 -147
  18. ominfra/scripts/manage.py +772 -183
  19. ominfra/scripts/supervisor.py +1144 -783
  20. ominfra/supervisor/dispatchers.py +1 -1
  21. ominfra/supervisor/groupsimpl.py +2 -2
  22. ominfra/supervisor/http.py +7 -7
  23. ominfra/supervisor/inject.py +4 -4
  24. ominfra/supervisor/io.py +1 -1
  25. ominfra/supervisor/main.py +1 -1
  26. ominfra/supervisor/processimpl.py +2 -2
  27. ominfra/supervisor/spawningimpl.py +9 -10
  28. ominfra/supervisor/supervisor.py +3 -3
  29. ominfra/supervisor/types.py +1 -1
  30. ominfra/tailscale/cli.py +1 -1
  31. {ominfra-0.0.0.dev148.dist-info → ominfra-0.0.0.dev150.dist-info}/METADATA +3 -3
  32. {ominfra-0.0.0.dev148.dist-info → ominfra-0.0.0.dev150.dist-info}/RECORD +36 -36
  33. {ominfra-0.0.0.dev148.dist-info → ominfra-0.0.0.dev150.dist-info}/LICENSE +0 -0
  34. {ominfra-0.0.0.dev148.dist-info → ominfra-0.0.0.dev150.dist-info}/WHEEL +0 -0
  35. {ominfra-0.0.0.dev148.dist-info → ominfra-0.0.0.dev150.dist-info}/entry_points.txt +0 -0
  36. {ominfra-0.0.0.dev148.dist-info → ominfra-0.0.0.dev150.dist-info}/top_level.txt +0 -0
@@ -34,6 +34,7 @@
34
34
  # EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35
35
  import abc
36
36
  import base64
37
+ import collections
37
38
  import collections.abc
38
39
  import contextlib
39
40
  import ctypes as ct
@@ -105,6 +106,11 @@ CallableT = ta.TypeVar('CallableT', bound=ta.Callable)
105
106
 
106
107
  # ../../omlish/lite/check.py
107
108
  SizedT = ta.TypeVar('SizedT', bound=ta.Sized)
109
+ CheckMessage = ta.Union[str, ta.Callable[..., ta.Optional[str]], None] # ta.TypeAlias
110
+ CheckLateConfigureFn = ta.Callable[['Checks'], None]
111
+ CheckOnRaiseFn = ta.Callable[[Exception], None] # ta.TypeAlias
112
+ CheckExceptionFactory = ta.Callable[..., Exception] # ta.TypeAlias
113
+ CheckArgsRenderer = ta.Callable[..., ta.Optional[str]] # ta.TypeAlias
108
114
 
109
115
  # ../../omlish/lite/socket.py
110
116
  SocketAddress = ta.Any
@@ -119,12 +125,12 @@ A2 = ta.TypeVar('A2')
119
125
  EventCallback = ta.Callable[['Event'], None]
120
126
  ProcessOutputChannel = ta.Literal['stdout', 'stderr'] # ta.TypeAlias
121
127
 
128
+ # ../../omlish/http/parsing.py
129
+ HttpHeaders = http.client.HTTPMessage # ta.TypeAlias
130
+
122
131
  # ../../omlish/lite/contextmanagers.py
123
132
  ExitStackedT = ta.TypeVar('ExitStackedT', bound='ExitStacked')
124
133
 
125
- # ../../omlish/lite/http/parsing.py
126
- HttpHeaders = http.client.HTTPMessage # ta.TypeAlias
127
-
128
134
  # ../../omlish/lite/inject.py
129
135
  U = ta.TypeVar('U')
130
136
  InjectorKeyCls = ta.Union[type, ta.NewType]
@@ -135,10 +141,10 @@ InjectorBindingOrBindings = ta.Union['InjectorBinding', 'InjectorBindings']
135
141
  # ../configs.py
136
142
  ConfigMapping = ta.Mapping[str, ta.Any]
137
143
 
138
- # ../../omlish/lite/http/handlers.py
144
+ # ../../omlish/http/handlers.py
139
145
  HttpHandler = ta.Callable[['HttpHandlerRequest'], 'HttpHandlerResponse']
140
146
 
141
- # ../../omlish/lite/http/coroserver.py
147
+ # ../../omlish/http/coroserver.py
142
148
  CoroHttpServerFactory = ta.Callable[[SocketAddress], 'CoroHttpServer']
143
149
 
144
150
 
@@ -1431,160 +1437,26 @@ def parse_octal(arg: ta.Union[str, int]) -> int:
1431
1437
 
1432
1438
 
1433
1439
  ########################################
1434
- # ../../../omlish/lite/cached.py
1435
-
1436
-
1437
- ##
1438
-
1439
-
1440
- class _AbstractCachedNullary:
1441
- def __init__(self, fn):
1442
- super().__init__()
1443
- self._fn = fn
1444
- self._value = self._missing = object()
1445
- functools.update_wrapper(self, fn)
1446
-
1447
- def __call__(self, *args, **kwargs): # noqa
1448
- raise TypeError
1449
-
1450
- def __get__(self, instance, owner): # noqa
1451
- bound = instance.__dict__[self._fn.__name__] = self.__class__(self._fn.__get__(instance, owner))
1452
- return bound
1453
-
1454
-
1455
- ##
1456
-
1457
-
1458
- class _CachedNullary(_AbstractCachedNullary):
1459
- def __call__(self, *args, **kwargs): # noqa
1460
- if self._value is self._missing:
1461
- self._value = self._fn()
1462
- return self._value
1463
-
1464
-
1465
- def cached_nullary(fn): # ta.Callable[..., T]) -> ta.Callable[..., T]:
1466
- return _CachedNullary(fn)
1467
-
1468
-
1469
- def static_init(fn: CallableT) -> CallableT:
1470
- fn = cached_nullary(fn)
1471
- fn()
1472
- return fn
1473
-
1474
-
1475
- ##
1476
-
1477
-
1478
- class _AsyncCachedNullary(_AbstractCachedNullary):
1479
- async def __call__(self, *args, **kwargs):
1480
- if self._value is self._missing:
1481
- self._value = await self._fn()
1482
- return self._value
1483
-
1484
-
1485
- def async_cached_nullary(fn): # ta.Callable[..., T]) -> ta.Callable[..., T]:
1486
- return _AsyncCachedNullary(fn)
1487
-
1488
-
1489
- ########################################
1490
- # ../../../omlish/lite/check.py
1491
-
1492
-
1493
- def check_isinstance(v: ta.Any, spec: ta.Union[ta.Type[T], tuple]) -> T:
1494
- if not isinstance(v, spec):
1495
- raise TypeError(v)
1496
- return v
1497
-
1440
+ # ../../../omlish/http/versions.py
1498
1441
 
1499
- def check_not_isinstance(v: T, spec: ta.Union[type, tuple]) -> T:
1500
- if isinstance(v, spec):
1501
- raise TypeError(v)
1502
- return v
1503
-
1504
-
1505
- def check_none(v: T) -> None:
1506
- if v is not None:
1507
- raise ValueError(v)
1508
-
1509
-
1510
- def check_not_none(v: ta.Optional[T]) -> T:
1511
- if v is None:
1512
- raise ValueError
1513
- return v
1514
-
1515
-
1516
- def check_not(v: ta.Any) -> None:
1517
- if v:
1518
- raise ValueError(v)
1519
- return v
1520
-
1521
-
1522
- def check_non_empty_str(v: ta.Optional[str]) -> str:
1523
- if not v:
1524
- raise ValueError
1525
- return v
1526
-
1527
-
1528
- def check_state(v: bool, msg: str = 'Illegal state') -> None:
1529
- if not v:
1530
- raise ValueError(msg)
1531
-
1532
-
1533
- def check_equal(l: T, r: T) -> T:
1534
- if l != r:
1535
- raise ValueError(l, r)
1536
- return l
1537
-
1538
-
1539
- def check_not_equal(l: T, r: T) -> T:
1540
- if l == r:
1541
- raise ValueError(l, r)
1542
- return l
1543
-
1544
-
1545
- def check_is(l: T, r: T) -> T:
1546
- if l is not r:
1547
- raise ValueError(l, r)
1548
- return l
1549
-
1550
-
1551
- def check_is_not(l: T, r: ta.Any) -> T:
1552
- if l is r:
1553
- raise ValueError(l, r)
1554
- return l
1555
-
1556
-
1557
- def check_in(v: T, c: ta.Container[T]) -> T:
1558
- if v not in c:
1559
- raise ValueError(v, c)
1560
- return v
1561
-
1562
-
1563
- def check_not_in(v: T, c: ta.Container[T]) -> T:
1564
- if v in c:
1565
- raise ValueError(v, c)
1566
- return v
1567
-
1568
-
1569
- def check_single(vs: ta.Iterable[T]) -> T:
1570
- [v] = vs
1571
- return v
1572
1442
 
1443
+ class HttpProtocolVersion(ta.NamedTuple):
1444
+ major: int
1445
+ minor: int
1573
1446
 
1574
- def check_empty(v: SizedT) -> SizedT:
1575
- if len(v):
1576
- raise ValueError(v)
1577
- return v
1447
+ def __str__(self) -> str:
1448
+ return f'HTTP/{self.major}.{self.minor}'
1578
1449
 
1579
1450
 
1580
- def check_non_empty(v: SizedT) -> SizedT:
1581
- if not len(v):
1582
- raise ValueError(v)
1583
- return v
1451
+ class HttpProtocolVersions:
1452
+ HTTP_0_9 = HttpProtocolVersion(0, 9)
1453
+ HTTP_1_0 = HttpProtocolVersion(1, 0)
1454
+ HTTP_1_1 = HttpProtocolVersion(1, 1)
1455
+ HTTP_2_0 = HttpProtocolVersion(2, 0)
1584
1456
 
1585
1457
 
1586
1458
  ########################################
1587
- # ../../../omlish/lite/fdio/pollers.py
1459
+ # ../../../omlish/io/fdio/pollers.py
1588
1460
 
1589
1461
 
1590
1462
  ##
@@ -1794,161 +1666,650 @@ else:
1794
1666
 
1795
1667
 
1796
1668
  ########################################
1797
- # ../../../omlish/lite/http/versions.py
1798
-
1669
+ # ../../../omlish/lite/cached.py
1799
1670
 
1800
- class HttpProtocolVersion(ta.NamedTuple):
1801
- major: int
1802
- minor: int
1803
1671
 
1804
- def __str__(self) -> str:
1805
- return f'HTTP/{self.major}.{self.minor}'
1672
+ ##
1806
1673
 
1807
1674
 
1808
- class HttpProtocolVersions:
1809
- HTTP_0_9 = HttpProtocolVersion(0, 9)
1810
- HTTP_1_0 = HttpProtocolVersion(1, 0)
1811
- HTTP_1_1 = HttpProtocolVersion(1, 1)
1812
- HTTP_2_0 = HttpProtocolVersion(2, 0)
1675
+ class _AbstractCachedNullary:
1676
+ def __init__(self, fn):
1677
+ super().__init__()
1678
+ self._fn = fn
1679
+ self._value = self._missing = object()
1680
+ functools.update_wrapper(self, fn)
1813
1681
 
1682
+ def __call__(self, *args, **kwargs): # noqa
1683
+ raise TypeError
1814
1684
 
1815
- ########################################
1816
- # ../../../omlish/lite/json.py
1685
+ def __get__(self, instance, owner): # noqa
1686
+ bound = instance.__dict__[self._fn.__name__] = self.__class__(self._fn.__get__(instance, owner))
1687
+ return bound
1817
1688
 
1818
1689
 
1819
1690
  ##
1820
1691
 
1821
1692
 
1822
- JSON_PRETTY_INDENT = 2
1693
+ class _CachedNullary(_AbstractCachedNullary):
1694
+ def __call__(self, *args, **kwargs): # noqa
1695
+ if self._value is self._missing:
1696
+ self._value = self._fn()
1697
+ return self._value
1823
1698
 
1824
- JSON_PRETTY_KWARGS: ta.Mapping[str, ta.Any] = dict(
1825
- indent=JSON_PRETTY_INDENT,
1826
- )
1827
1699
 
1828
- json_dump_pretty: ta.Callable[..., bytes] = functools.partial(json.dump, **JSON_PRETTY_KWARGS) # type: ignore
1829
- json_dumps_pretty: ta.Callable[..., str] = functools.partial(json.dumps, **JSON_PRETTY_KWARGS)
1700
+ def cached_nullary(fn): # ta.Callable[..., T]) -> ta.Callable[..., T]:
1701
+ return _CachedNullary(fn)
1702
+
1703
+
1704
+ def static_init(fn: CallableT) -> CallableT:
1705
+ fn = cached_nullary(fn)
1706
+ fn()
1707
+ return fn
1830
1708
 
1831
1709
 
1832
1710
  ##
1833
1711
 
1834
1712
 
1835
- JSON_COMPACT_SEPARATORS = (',', ':')
1713
+ class _AsyncCachedNullary(_AbstractCachedNullary):
1714
+ async def __call__(self, *args, **kwargs):
1715
+ if self._value is self._missing:
1716
+ self._value = await self._fn()
1717
+ return self._value
1836
1718
 
1837
- JSON_COMPACT_KWARGS: ta.Mapping[str, ta.Any] = dict(
1838
- indent=None,
1839
- separators=JSON_COMPACT_SEPARATORS,
1840
- )
1841
1719
 
1842
- json_dump_compact: ta.Callable[..., bytes] = functools.partial(json.dump, **JSON_COMPACT_KWARGS) # type: ignore
1843
- json_dumps_compact: ta.Callable[..., str] = functools.partial(json.dumps, **JSON_COMPACT_KWARGS)
1720
+ def async_cached_nullary(fn): # ta.Callable[..., T]) -> ta.Callable[..., T]:
1721
+ return _AsyncCachedNullary(fn)
1844
1722
 
1845
1723
 
1846
1724
  ########################################
1847
- # ../../../omlish/lite/maybes.py
1725
+ # ../../../omlish/lite/check.py
1726
+ """
1727
+ TODO:
1728
+ - def maybe(v: lang.Maybe[T])
1729
+ - patch / override lite.check ?
1730
+ - checker interface?
1731
+ """
1848
1732
 
1849
1733
 
1850
- class Maybe(ta.Generic[T]):
1851
- @property
1852
- @abc.abstractmethod
1853
- def present(self) -> bool:
1854
- raise NotImplementedError
1734
+ ##
1855
1735
 
1856
- @abc.abstractmethod
1857
- def must(self) -> T:
1858
- raise NotImplementedError
1859
1736
 
1860
- @classmethod
1861
- def just(cls, v: T) -> 'Maybe[T]':
1862
- return tuple.__new__(_Maybe, (v,)) # noqa
1737
+ class Checks:
1738
+ def __init__(self) -> None:
1739
+ super().__init__()
1863
1740
 
1864
- _empty: ta.ClassVar['Maybe']
1741
+ self._config_lock = threading.RLock()
1742
+ self._on_raise_fns: ta.Sequence[CheckOnRaiseFn] = []
1743
+ self._exception_factory: CheckExceptionFactory = Checks.default_exception_factory
1744
+ self._args_renderer: ta.Optional[CheckArgsRenderer] = None
1745
+ self._late_configure_fns: ta.Sequence[CheckLateConfigureFn] = []
1865
1746
 
1866
- @classmethod
1867
- def empty(cls) -> 'Maybe[T]':
1868
- return Maybe._empty
1747
+ @staticmethod
1748
+ def default_exception_factory(exc_cls: ta.Type[Exception], *args, **kwargs) -> Exception:
1749
+ return exc_cls(*args, **kwargs) # noqa
1869
1750
 
1751
+ #
1870
1752
 
1871
- class _Maybe(Maybe[T], tuple):
1872
- __slots__ = ()
1753
+ def register_on_raise(self, fn: CheckOnRaiseFn) -> None:
1754
+ with self._config_lock:
1755
+ self._on_raise_fns = [*self._on_raise_fns, fn]
1873
1756
 
1874
- def __init_subclass__(cls, **kwargs):
1875
- raise TypeError
1757
+ def unregister_on_raise(self, fn: CheckOnRaiseFn) -> None:
1758
+ with self._config_lock:
1759
+ self._on_raise_fns = [e for e in self._on_raise_fns if e != fn]
1876
1760
 
1877
- @property
1878
- def present(self) -> bool:
1879
- return bool(self)
1761
+ #
1880
1762
 
1881
- def must(self) -> T:
1882
- if not self:
1883
- raise ValueError
1884
- return self[0]
1763
+ def set_exception_factory(self, factory: CheckExceptionFactory) -> None:
1764
+ self._exception_factory = factory
1885
1765
 
1766
+ def set_args_renderer(self, renderer: ta.Optional[CheckArgsRenderer]) -> None:
1767
+ self._args_renderer = renderer
1886
1768
 
1887
- Maybe._empty = tuple.__new__(_Maybe, ()) # noqa
1769
+ #
1888
1770
 
1771
+ def register_late_configure(self, fn: CheckLateConfigureFn) -> None:
1772
+ with self._config_lock:
1773
+ self._late_configure_fns = [*self._late_configure_fns, fn]
1889
1774
 
1890
- ########################################
1891
- # ../../../omlish/lite/reflect.py
1775
+ def _late_configure(self) -> None:
1776
+ if not self._late_configure_fns:
1777
+ return
1892
1778
 
1779
+ with self._config_lock:
1780
+ if not (lc := self._late_configure_fns):
1781
+ return
1893
1782
 
1894
- _GENERIC_ALIAS_TYPES = (
1895
- ta._GenericAlias, # type: ignore # noqa
1896
- *([ta._SpecialGenericAlias] if hasattr(ta, '_SpecialGenericAlias') else []), # noqa
1897
- )
1783
+ for fn in lc:
1784
+ fn(self)
1898
1785
 
1786
+ self._late_configure_fns = []
1899
1787
 
1900
- def is_generic_alias(obj, *, origin: ta.Any = None) -> bool:
1901
- return (
1902
- isinstance(obj, _GENERIC_ALIAS_TYPES) and
1903
- (origin is None or ta.get_origin(obj) is origin)
1904
- )
1788
+ #
1905
1789
 
1790
+ class _ArgsKwargs:
1791
+ def __init__(self, *args, **kwargs):
1792
+ self.args = args
1793
+ self.kwargs = kwargs
1906
1794
 
1907
- is_union_alias = functools.partial(is_generic_alias, origin=ta.Union)
1908
- is_callable_alias = functools.partial(is_generic_alias, origin=ta.Callable)
1795
+ def _raise(
1796
+ self,
1797
+ exception_type: ta.Type[Exception],
1798
+ default_message: str,
1799
+ message: CheckMessage,
1800
+ ak: _ArgsKwargs = _ArgsKwargs(),
1801
+ *,
1802
+ render_fmt: ta.Optional[str] = None,
1803
+ ) -> ta.NoReturn:
1804
+ exc_args = ()
1805
+ if callable(message):
1806
+ message = ta.cast(ta.Callable, message)(*ak.args, **ak.kwargs)
1807
+ if isinstance(message, tuple):
1808
+ message, *exc_args = message # type: ignore
1909
1809
 
1810
+ if message is None:
1811
+ message = default_message
1910
1812
 
1911
- def is_optional_alias(spec: ta.Any) -> bool:
1912
- return (
1913
- isinstance(spec, _GENERIC_ALIAS_TYPES) and # noqa
1914
- ta.get_origin(spec) is ta.Union and
1915
- len(ta.get_args(spec)) == 2 and
1916
- any(a in (None, type(None)) for a in ta.get_args(spec))
1917
- )
1813
+ self._late_configure()
1918
1814
 
1815
+ if render_fmt is not None and (af := self._args_renderer) is not None:
1816
+ rendered_args = af(render_fmt, *ak.args)
1817
+ if rendered_args is not None:
1818
+ message = f'{message} : {rendered_args}'
1919
1819
 
1920
- def get_optional_alias_arg(spec: ta.Any) -> ta.Any:
1921
- [it] = [it for it in ta.get_args(spec) if it not in (None, type(None))]
1922
- return it
1820
+ exc = self._exception_factory(
1821
+ exception_type,
1822
+ message,
1823
+ *exc_args,
1824
+ *ak.args,
1825
+ **ak.kwargs,
1826
+ )
1923
1827
 
1828
+ for fn in self._on_raise_fns:
1829
+ fn(exc)
1924
1830
 
1925
- def is_new_type(spec: ta.Any) -> bool:
1926
- if isinstance(ta.NewType, type):
1927
- return isinstance(spec, ta.NewType)
1928
- else:
1929
- # Before https://github.com/python/cpython/commit/c2f33dfc83ab270412bf243fb21f724037effa1a
1930
- return isinstance(spec, types.FunctionType) and spec.__code__ is ta.NewType.__code__.co_consts[1] # type: ignore # noqa
1831
+ raise exc
1931
1832
 
1833
+ #
1932
1834
 
1933
- def deep_subclasses(cls: ta.Type[T]) -> ta.Iterator[ta.Type[T]]:
1934
- seen = set()
1935
- todo = list(reversed(cls.__subclasses__()))
1936
- while todo:
1937
- cur = todo.pop()
1938
- if cur in seen:
1939
- continue
1940
- seen.add(cur)
1941
- yield cur
1942
- todo.extend(reversed(cur.__subclasses__()))
1835
+ def _unpack_isinstance_spec(self, spec: ta.Any) -> tuple:
1836
+ if isinstance(spec, type):
1837
+ return (spec,)
1838
+ if not isinstance(spec, tuple):
1839
+ spec = (spec,)
1840
+ if None in spec:
1841
+ spec = tuple(filter(None, spec)) + (None.__class__,) # noqa
1842
+ if ta.Any in spec:
1843
+ spec = (object,)
1844
+ return spec
1845
+
1846
+ def isinstance(self, v: ta.Any, spec: ta.Union[ta.Type[T], tuple], msg: CheckMessage = None) -> T: # noqa
1847
+ if not isinstance(v, self._unpack_isinstance_spec(spec)):
1848
+ self._raise(
1849
+ TypeError,
1850
+ 'Must be instance',
1851
+ msg,
1852
+ Checks._ArgsKwargs(v, spec),
1853
+ render_fmt='not isinstance(%s, %s)',
1854
+ )
1943
1855
 
1856
+ return v
1944
1857
 
1945
- ########################################
1946
- # ../../../omlish/lite/socket.py
1947
- """
1948
- TODO:
1949
- - SocketClientAddress family / tuple pairs
1950
- + codification of https://docs.python.org/3/library/socket.html#socket-families
1951
- """
1858
+ def of_isinstance(self, spec: ta.Union[ta.Type[T], tuple], msg: CheckMessage = None) -> ta.Callable[[ta.Any], T]:
1859
+ def inner(v):
1860
+ return self.isinstance(v, self._unpack_isinstance_spec(spec), msg)
1861
+
1862
+ return inner
1863
+
1864
+ def cast(self, v: ta.Any, cls: ta.Type[T], msg: CheckMessage = None) -> T: # noqa
1865
+ if not isinstance(v, cls):
1866
+ self._raise(
1867
+ TypeError,
1868
+ 'Must be instance',
1869
+ msg,
1870
+ Checks._ArgsKwargs(v, cls),
1871
+ )
1872
+
1873
+ return v
1874
+
1875
+ def of_cast(self, cls: ta.Type[T], msg: CheckMessage = None) -> ta.Callable[[T], T]:
1876
+ def inner(v):
1877
+ return self.cast(v, cls, msg)
1878
+
1879
+ return inner
1880
+
1881
+ def not_isinstance(self, v: T, spec: ta.Any, msg: CheckMessage = None) -> T: # noqa
1882
+ if isinstance(v, self._unpack_isinstance_spec(spec)):
1883
+ self._raise(
1884
+ TypeError,
1885
+ 'Must not be instance',
1886
+ msg,
1887
+ Checks._ArgsKwargs(v, spec),
1888
+ render_fmt='isinstance(%s, %s)',
1889
+ )
1890
+
1891
+ return v
1892
+
1893
+ def of_not_isinstance(self, spec: ta.Any, msg: CheckMessage = None) -> ta.Callable[[T], T]:
1894
+ def inner(v):
1895
+ return self.not_isinstance(v, self._unpack_isinstance_spec(spec), msg)
1896
+
1897
+ return inner
1898
+
1899
+ ##
1900
+
1901
+ def issubclass(self, v: ta.Type[T], spec: ta.Any, msg: CheckMessage = None) -> ta.Type[T]: # noqa
1902
+ if not issubclass(v, spec):
1903
+ self._raise(
1904
+ TypeError,
1905
+ 'Must be subclass',
1906
+ msg,
1907
+ Checks._ArgsKwargs(v, spec),
1908
+ render_fmt='not issubclass(%s, %s)',
1909
+ )
1910
+
1911
+ return v
1912
+
1913
+ def not_issubclass(self, v: ta.Type[T], spec: ta.Any, msg: CheckMessage = None) -> ta.Type[T]: # noqa
1914
+ if issubclass(v, spec):
1915
+ self._raise(
1916
+ TypeError,
1917
+ 'Must not be subclass',
1918
+ msg,
1919
+ Checks._ArgsKwargs(v, spec),
1920
+ render_fmt='issubclass(%s, %s)',
1921
+ )
1922
+
1923
+ return v
1924
+
1925
+ #
1926
+
1927
+ def in_(self, v: T, c: ta.Container[T], msg: CheckMessage = None) -> T:
1928
+ if v not in c:
1929
+ self._raise(
1930
+ ValueError,
1931
+ 'Must be in',
1932
+ msg,
1933
+ Checks._ArgsKwargs(v, c),
1934
+ render_fmt='%s not in %s',
1935
+ )
1936
+
1937
+ return v
1938
+
1939
+ def not_in(self, v: T, c: ta.Container[T], msg: CheckMessage = None) -> T:
1940
+ if v in c:
1941
+ self._raise(
1942
+ ValueError,
1943
+ 'Must not be in',
1944
+ msg,
1945
+ Checks._ArgsKwargs(v, c),
1946
+ render_fmt='%s in %s',
1947
+ )
1948
+
1949
+ return v
1950
+
1951
+ def empty(self, v: SizedT, msg: CheckMessage = None) -> SizedT:
1952
+ if len(v) != 0:
1953
+ self._raise(
1954
+ ValueError,
1955
+ 'Must be empty',
1956
+ msg,
1957
+ Checks._ArgsKwargs(v),
1958
+ render_fmt='%s',
1959
+ )
1960
+
1961
+ return v
1962
+
1963
+ def iterempty(self, v: ta.Iterable[T], msg: CheckMessage = None) -> ta.Iterable[T]:
1964
+ it = iter(v)
1965
+ try:
1966
+ next(it)
1967
+ except StopIteration:
1968
+ pass
1969
+ else:
1970
+ self._raise(
1971
+ ValueError,
1972
+ 'Must be empty',
1973
+ msg,
1974
+ Checks._ArgsKwargs(v),
1975
+ render_fmt='%s',
1976
+ )
1977
+
1978
+ return v
1979
+
1980
+ def not_empty(self, v: SizedT, msg: CheckMessage = None) -> SizedT:
1981
+ if len(v) == 0:
1982
+ self._raise(
1983
+ ValueError,
1984
+ 'Must not be empty',
1985
+ msg,
1986
+ Checks._ArgsKwargs(v),
1987
+ render_fmt='%s',
1988
+ )
1989
+
1990
+ return v
1991
+
1992
+ def unique(self, it: ta.Iterable[T], msg: CheckMessage = None) -> ta.Iterable[T]:
1993
+ dupes = [e for e, c in collections.Counter(it).items() if c > 1]
1994
+ if dupes:
1995
+ self._raise(
1996
+ ValueError,
1997
+ 'Must be unique',
1998
+ msg,
1999
+ Checks._ArgsKwargs(it, dupes),
2000
+ )
2001
+
2002
+ return it
2003
+
2004
+ def single(self, obj: ta.Iterable[T], message: CheckMessage = None) -> T:
2005
+ try:
2006
+ [value] = obj
2007
+ except ValueError:
2008
+ self._raise(
2009
+ ValueError,
2010
+ 'Must be single',
2011
+ message,
2012
+ Checks._ArgsKwargs(obj),
2013
+ render_fmt='%s',
2014
+ )
2015
+
2016
+ return value
2017
+
2018
+ def opt_single(self, obj: ta.Iterable[T], message: CheckMessage = None) -> ta.Optional[T]:
2019
+ it = iter(obj)
2020
+ try:
2021
+ value = next(it)
2022
+ except StopIteration:
2023
+ return None
2024
+
2025
+ try:
2026
+ next(it)
2027
+ except StopIteration:
2028
+ return value # noqa
2029
+
2030
+ self._raise(
2031
+ ValueError,
2032
+ 'Must be empty or single',
2033
+ message,
2034
+ Checks._ArgsKwargs(obj),
2035
+ render_fmt='%s',
2036
+ )
2037
+
2038
+ raise RuntimeError # noqa
2039
+
2040
+ #
2041
+
2042
+ def none(self, v: ta.Any, msg: CheckMessage = None) -> None:
2043
+ if v is not None:
2044
+ self._raise(
2045
+ ValueError,
2046
+ 'Must be None',
2047
+ msg,
2048
+ Checks._ArgsKwargs(v),
2049
+ render_fmt='%s',
2050
+ )
2051
+
2052
+ def not_none(self, v: ta.Optional[T], msg: CheckMessage = None) -> T:
2053
+ if v is None:
2054
+ self._raise(
2055
+ ValueError,
2056
+ 'Must not be None',
2057
+ msg,
2058
+ Checks._ArgsKwargs(v),
2059
+ render_fmt='%s',
2060
+ )
2061
+
2062
+ return v
2063
+
2064
+ #
2065
+
2066
+ def equal(self, v: T, o: ta.Any, msg: CheckMessage = None) -> T:
2067
+ if o != v:
2068
+ self._raise(
2069
+ ValueError,
2070
+ 'Must be equal',
2071
+ msg,
2072
+ Checks._ArgsKwargs(v, o),
2073
+ render_fmt='%s != %s',
2074
+ )
2075
+
2076
+ return v
2077
+
2078
+ def is_(self, v: T, o: ta.Any, msg: CheckMessage = None) -> T:
2079
+ if o is not v:
2080
+ self._raise(
2081
+ ValueError,
2082
+ 'Must be the same',
2083
+ msg,
2084
+ Checks._ArgsKwargs(v, o),
2085
+ render_fmt='%s is not %s',
2086
+ )
2087
+
2088
+ return v
2089
+
2090
+ def is_not(self, v: T, o: ta.Any, msg: CheckMessage = None) -> T:
2091
+ if o is v:
2092
+ self._raise(
2093
+ ValueError,
2094
+ 'Must not be the same',
2095
+ msg,
2096
+ Checks._ArgsKwargs(v, o),
2097
+ render_fmt='%s is %s',
2098
+ )
2099
+
2100
+ return v
2101
+
2102
+ def callable(self, v: T, msg: CheckMessage = None) -> T: # noqa
2103
+ if not callable(v):
2104
+ self._raise(
2105
+ TypeError,
2106
+ 'Must be callable',
2107
+ msg,
2108
+ Checks._ArgsKwargs(v),
2109
+ render_fmt='%s',
2110
+ )
2111
+
2112
+ return v # type: ignore
2113
+
2114
+ def non_empty_str(self, v: ta.Optional[str], msg: CheckMessage = None) -> str:
2115
+ if not isinstance(v, str) or not v:
2116
+ self._raise(
2117
+ ValueError,
2118
+ 'Must be non-empty str',
2119
+ msg,
2120
+ Checks._ArgsKwargs(v),
2121
+ render_fmt='%s',
2122
+ )
2123
+
2124
+ return v
2125
+
2126
+ def replacing(self, expected: ta.Any, old: ta.Any, new: T, msg: CheckMessage = None) -> T:
2127
+ if old != expected:
2128
+ self._raise(
2129
+ ValueError,
2130
+ 'Must be replacing',
2131
+ msg,
2132
+ Checks._ArgsKwargs(expected, old, new),
2133
+ render_fmt='%s -> %s -> %s',
2134
+ )
2135
+
2136
+ return new
2137
+
2138
+ def replacing_none(self, old: ta.Any, new: T, msg: CheckMessage = None) -> T:
2139
+ if old is not None:
2140
+ self._raise(
2141
+ ValueError,
2142
+ 'Must be replacing None',
2143
+ msg,
2144
+ Checks._ArgsKwargs(old, new),
2145
+ render_fmt='%s -> %s',
2146
+ )
2147
+
2148
+ return new
2149
+
2150
+ #
2151
+
2152
+ def arg(self, v: bool, msg: CheckMessage = None) -> None:
2153
+ if not v:
2154
+ self._raise(
2155
+ RuntimeError,
2156
+ 'Argument condition not met',
2157
+ msg,
2158
+ Checks._ArgsKwargs(v),
2159
+ render_fmt='%s',
2160
+ )
2161
+
2162
+ def state(self, v: bool, msg: CheckMessage = None) -> None:
2163
+ if not v:
2164
+ self._raise(
2165
+ RuntimeError,
2166
+ 'State condition not met',
2167
+ msg,
2168
+ Checks._ArgsKwargs(v),
2169
+ render_fmt='%s',
2170
+ )
2171
+
2172
+
2173
+ check = Checks()
2174
+
2175
+
2176
+ ########################################
2177
+ # ../../../omlish/lite/json.py
2178
+
2179
+
2180
+ ##
2181
+
2182
+
2183
+ JSON_PRETTY_INDENT = 2
2184
+
2185
+ JSON_PRETTY_KWARGS: ta.Mapping[str, ta.Any] = dict(
2186
+ indent=JSON_PRETTY_INDENT,
2187
+ )
2188
+
2189
+ json_dump_pretty: ta.Callable[..., bytes] = functools.partial(json.dump, **JSON_PRETTY_KWARGS) # type: ignore
2190
+ json_dumps_pretty: ta.Callable[..., str] = functools.partial(json.dumps, **JSON_PRETTY_KWARGS)
2191
+
2192
+
2193
+ ##
2194
+
2195
+
2196
+ JSON_COMPACT_SEPARATORS = (',', ':')
2197
+
2198
+ JSON_COMPACT_KWARGS: ta.Mapping[str, ta.Any] = dict(
2199
+ indent=None,
2200
+ separators=JSON_COMPACT_SEPARATORS,
2201
+ )
2202
+
2203
+ json_dump_compact: ta.Callable[..., bytes] = functools.partial(json.dump, **JSON_COMPACT_KWARGS) # type: ignore
2204
+ json_dumps_compact: ta.Callable[..., str] = functools.partial(json.dumps, **JSON_COMPACT_KWARGS)
2205
+
2206
+
2207
+ ########################################
2208
+ # ../../../omlish/lite/maybes.py
2209
+
2210
+
2211
+ class Maybe(ta.Generic[T]):
2212
+ @property
2213
+ @abc.abstractmethod
2214
+ def present(self) -> bool:
2215
+ raise NotImplementedError
2216
+
2217
+ @abc.abstractmethod
2218
+ def must(self) -> T:
2219
+ raise NotImplementedError
2220
+
2221
+ @classmethod
2222
+ def just(cls, v: T) -> 'Maybe[T]':
2223
+ return tuple.__new__(_Maybe, (v,)) # noqa
2224
+
2225
+ _empty: ta.ClassVar['Maybe']
2226
+
2227
+ @classmethod
2228
+ def empty(cls) -> 'Maybe[T]':
2229
+ return Maybe._empty
2230
+
2231
+
2232
+ class _Maybe(Maybe[T], tuple):
2233
+ __slots__ = ()
2234
+
2235
+ def __init_subclass__(cls, **kwargs):
2236
+ raise TypeError
2237
+
2238
+ @property
2239
+ def present(self) -> bool:
2240
+ return bool(self)
2241
+
2242
+ def must(self) -> T:
2243
+ if not self:
2244
+ raise ValueError
2245
+ return self[0]
2246
+
2247
+
2248
+ Maybe._empty = tuple.__new__(_Maybe, ()) # noqa
2249
+
2250
+
2251
+ ########################################
2252
+ # ../../../omlish/lite/reflect.py
2253
+
2254
+
2255
+ _GENERIC_ALIAS_TYPES = (
2256
+ ta._GenericAlias, # type: ignore # noqa
2257
+ *([ta._SpecialGenericAlias] if hasattr(ta, '_SpecialGenericAlias') else []), # noqa
2258
+ )
2259
+
2260
+
2261
+ def is_generic_alias(obj, *, origin: ta.Any = None) -> bool:
2262
+ return (
2263
+ isinstance(obj, _GENERIC_ALIAS_TYPES) and
2264
+ (origin is None or ta.get_origin(obj) is origin)
2265
+ )
2266
+
2267
+
2268
+ is_union_alias = functools.partial(is_generic_alias, origin=ta.Union)
2269
+ is_callable_alias = functools.partial(is_generic_alias, origin=ta.Callable)
2270
+
2271
+
2272
+ def is_optional_alias(spec: ta.Any) -> bool:
2273
+ return (
2274
+ isinstance(spec, _GENERIC_ALIAS_TYPES) and # noqa
2275
+ ta.get_origin(spec) is ta.Union and
2276
+ len(ta.get_args(spec)) == 2 and
2277
+ any(a in (None, type(None)) for a in ta.get_args(spec))
2278
+ )
2279
+
2280
+
2281
+ def get_optional_alias_arg(spec: ta.Any) -> ta.Any:
2282
+ [it] = [it for it in ta.get_args(spec) if it not in (None, type(None))]
2283
+ return it
2284
+
2285
+
2286
+ def is_new_type(spec: ta.Any) -> bool:
2287
+ if isinstance(ta.NewType, type):
2288
+ return isinstance(spec, ta.NewType)
2289
+ else:
2290
+ # Before https://github.com/python/cpython/commit/c2f33dfc83ab270412bf243fb21f724037effa1a
2291
+ return isinstance(spec, types.FunctionType) and spec.__code__ is ta.NewType.__code__.co_consts[1] # type: ignore # noqa
2292
+
2293
+
2294
+ def deep_subclasses(cls: ta.Type[T]) -> ta.Iterator[ta.Type[T]]:
2295
+ seen = set()
2296
+ todo = list(reversed(cls.__subclasses__()))
2297
+ while todo:
2298
+ cur = todo.pop()
2299
+ if cur in seen:
2300
+ continue
2301
+ seen.add(cur)
2302
+ yield cur
2303
+ todo.extend(reversed(cur.__subclasses__()))
2304
+
2305
+
2306
+ ########################################
2307
+ # ../../../omlish/lite/socket.py
2308
+ """
2309
+ TODO:
2310
+ - SocketClientAddress family / tuple pairs
2311
+ + codification of https://docs.python.org/3/library/socket.html#socket-families
2312
+ """
1952
2313
 
1953
2314
 
1954
2315
  ##
@@ -2564,250 +2925,7 @@ def get_user(name: str) -> User:
2564
2925
 
2565
2926
 
2566
2927
  ########################################
2567
- # ../../../omlish/lite/contextmanagers.py
2568
-
2569
-
2570
- ##
2571
-
2572
-
2573
- class ExitStacked:
2574
- _exit_stack: ta.Optional[contextlib.ExitStack] = None
2575
-
2576
- def __enter__(self: ExitStackedT) -> ExitStackedT:
2577
- check_state(self._exit_stack is None)
2578
- es = self._exit_stack = contextlib.ExitStack()
2579
- es.__enter__()
2580
- return self
2581
-
2582
- def __exit__(self, exc_type, exc_val, exc_tb):
2583
- if (es := self._exit_stack) is None:
2584
- return None
2585
- self._exit_contexts()
2586
- return es.__exit__(exc_type, exc_val, exc_tb)
2587
-
2588
- def _exit_contexts(self) -> None:
2589
- pass
2590
-
2591
- def _enter_context(self, cm: ta.ContextManager[T]) -> T:
2592
- es = check_not_none(self._exit_stack)
2593
- return es.enter_context(cm)
2594
-
2595
-
2596
- ##
2597
-
2598
-
2599
- @contextlib.contextmanager
2600
- def defer(fn: ta.Callable) -> ta.Generator[ta.Callable, None, None]:
2601
- try:
2602
- yield fn
2603
- finally:
2604
- fn()
2605
-
2606
-
2607
- @contextlib.contextmanager
2608
- def attr_setting(obj, attr, val, *, default=None): # noqa
2609
- not_set = object()
2610
- orig = getattr(obj, attr, not_set)
2611
- try:
2612
- setattr(obj, attr, val)
2613
- if orig is not not_set:
2614
- yield orig
2615
- else:
2616
- yield default
2617
- finally:
2618
- if orig is not_set:
2619
- delattr(obj, attr)
2620
- else:
2621
- setattr(obj, attr, orig)
2622
-
2623
-
2624
- ########################################
2625
- # ../../../omlish/lite/fdio/handlers.py
2626
-
2627
-
2628
- class FdioHandler(abc.ABC):
2629
- @abc.abstractmethod
2630
- def fd(self) -> int:
2631
- raise NotImplementedError
2632
-
2633
- #
2634
-
2635
- @property
2636
- @abc.abstractmethod
2637
- def closed(self) -> bool:
2638
- raise NotImplementedError
2639
-
2640
- @abc.abstractmethod
2641
- def close(self) -> None:
2642
- raise NotImplementedError
2643
-
2644
- #
2645
-
2646
- def readable(self) -> bool:
2647
- return False
2648
-
2649
- def writable(self) -> bool:
2650
- return False
2651
-
2652
- #
2653
-
2654
- def on_readable(self) -> None:
2655
- raise TypeError
2656
-
2657
- def on_writable(self) -> None:
2658
- raise TypeError
2659
-
2660
- def on_error(self, exc: ta.Optional[BaseException] = None) -> None: # noqa
2661
- pass
2662
-
2663
-
2664
- class SocketFdioHandler(FdioHandler, abc.ABC):
2665
- def __init__(
2666
- self,
2667
- addr: SocketAddress,
2668
- sock: socket.socket,
2669
- ) -> None:
2670
- super().__init__()
2671
-
2672
- self._addr = addr
2673
- self._sock: ta.Optional[socket.socket] = sock
2674
-
2675
- def fd(self) -> int:
2676
- return check_not_none(self._sock).fileno()
2677
-
2678
- @property
2679
- def closed(self) -> bool:
2680
- return self._sock is None
2681
-
2682
- def close(self) -> None:
2683
- if self._sock is not None:
2684
- self._sock.close()
2685
- self._sock = None
2686
-
2687
-
2688
- ########################################
2689
- # ../../../omlish/lite/fdio/kqueue.py
2690
-
2691
-
2692
- KqueueFdioPoller: ta.Optional[ta.Type[FdioPoller]]
2693
- if sys.platform == 'darwin' or sys.platform.startswith('freebsd'):
2694
-
2695
- class _KqueueFdioPoller(FdioPoller):
2696
- DEFAULT_MAX_EVENTS = 1000
2697
-
2698
- def __init__(
2699
- self,
2700
- *,
2701
- max_events: int = DEFAULT_MAX_EVENTS,
2702
- ) -> None:
2703
- super().__init__()
2704
-
2705
- self._max_events = max_events
2706
-
2707
- self._kqueue: ta.Optional[ta.Any] = None
2708
-
2709
- #
2710
-
2711
- def _get_kqueue(self) -> 'select.kqueue':
2712
- if (kq := self._kqueue) is not None:
2713
- return kq
2714
- kq = select.kqueue()
2715
- self._kqueue = kq
2716
- return kq
2717
-
2718
- def close(self) -> None:
2719
- if self._kqueue is not None:
2720
- self._kqueue.close()
2721
- self._kqueue = None
2722
-
2723
- def reopen(self) -> None:
2724
- for fd in self._readable:
2725
- self._register_readable(fd)
2726
- for fd in self._writable:
2727
- self._register_writable(fd)
2728
-
2729
- #
2730
-
2731
- def _register_readable(self, fd: int) -> None:
2732
- self._update_registration(fd, 'read', 'add')
2733
-
2734
- def _register_writable(self, fd: int) -> None:
2735
- self._update_registration(fd, 'write', 'add')
2736
-
2737
- def _unregister_readable(self, fd: int) -> None:
2738
- self._update_registration(fd, 'read', 'del')
2739
-
2740
- def _unregister_writable(self, fd: int) -> None:
2741
- self._update_registration(fd, 'write', 'del')
2742
-
2743
- #
2744
-
2745
- _CONTROL_FILTER_BY_READ_OR_WRITE: ta.ClassVar[ta.Mapping[ta.Literal['read', 'write'], int]] = {
2746
- 'read': select.KQ_FILTER_READ,
2747
- 'write': select.KQ_FILTER_WRITE,
2748
- }
2749
-
2750
- _CONTROL_FLAGS_BY_ADD_OR_DEL: ta.ClassVar[ta.Mapping[ta.Literal['add', 'del'], int]] = {
2751
- 'add': select.KQ_EV_ADD,
2752
- 'del': select.KQ_EV_DELETE,
2753
- }
2754
-
2755
- def _update_registration(
2756
- self,
2757
- fd: int,
2758
- read_or_write: ta.Literal['read', 'write'],
2759
- add_or_del: ta.Literal['add', 'del'],
2760
- ) -> None: # noqa
2761
- ke = select.kevent(
2762
- fd,
2763
- filter=self._CONTROL_FILTER_BY_READ_OR_WRITE[read_or_write],
2764
- flags=self._CONTROL_FLAGS_BY_ADD_OR_DEL[add_or_del],
2765
- )
2766
- kq = self._get_kqueue()
2767
- try:
2768
- kq.control([ke], 0)
2769
-
2770
- except OSError as exc:
2771
- if exc.errno == errno.EBADF:
2772
- # log.debug('EBADF encountered in kqueue. Invalid file descriptor %s', ke.ident)
2773
- pass
2774
- elif exc.errno == errno.ENOENT:
2775
- # Can happen when trying to remove an already closed socket
2776
- if add_or_del == 'add':
2777
- raise
2778
- else:
2779
- raise
2780
-
2781
- #
2782
-
2783
- def poll(self, timeout: ta.Optional[float]) -> FdioPoller.PollResult:
2784
- kq = self._get_kqueue()
2785
- try:
2786
- kes = kq.control(None, self._max_events, timeout)
2787
-
2788
- except OSError as exc:
2789
- if exc.errno == errno.EINTR:
2790
- return FdioPoller.PollResult(msg='EINTR encountered in poll', exc=exc)
2791
- else:
2792
- raise
2793
-
2794
- r: ta.List[int] = []
2795
- w: ta.List[int] = []
2796
- for ke in kes:
2797
- if ke.filter == select.KQ_FILTER_READ:
2798
- r.append(ke.ident)
2799
- if ke.filter == select.KQ_FILTER_WRITE:
2800
- w.append(ke.ident)
2801
-
2802
- return FdioPoller.PollResult(r, w)
2803
-
2804
- KqueueFdioPoller = _KqueueFdioPoller
2805
- else:
2806
- KqueueFdioPoller = None
2807
-
2808
-
2809
- ########################################
2810
- # ../../../omlish/lite/http/parsing.py
2928
+ # ../../../omlish/http/parsing.py
2811
2929
  # PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
2812
2930
  # --------------------------------------------
2813
2931
  #
@@ -3182,28 +3300,493 @@ class HttpRequestParser:
3182
3300
  ):
3183
3301
  close_connection = False
3184
3302
 
3185
- # Check for expect directive
3303
+ # Check for expect directive
3304
+
3305
+ expect = headers.get('Expect', '')
3306
+ if (
3307
+ expect.lower() == '100-continue' and
3308
+ version >= HttpProtocolVersions.HTTP_1_1
3309
+ ):
3310
+ expects_continue = True
3311
+ else:
3312
+ expects_continue = False
3313
+
3314
+ # Return
3315
+
3316
+ return ParsedHttpRequest(
3317
+ method=method,
3318
+ path=path,
3319
+ expects_continue=expects_continue,
3320
+ **result_kwargs(),
3321
+ )
3322
+
3323
+ def parse(self, read_line: ta.Callable[[int], bytes]) -> ParseHttpRequestResult:
3324
+ return self._run_read_line_coro(self.coro_parse(), read_line)
3325
+
3326
+
3327
+ ########################################
3328
+ # ../../../omlish/io/buffers.py
3329
+
3330
+
3331
+ class DelimitingBuffer:
3332
+ """
3333
+ https://github.com/python-trio/trio/issues/796 :|
3334
+ """
3335
+
3336
+ #
3337
+
3338
+ class Error(Exception):
3339
+ def __init__(self, buffer: 'DelimitingBuffer') -> None:
3340
+ super().__init__(buffer)
3341
+ self.buffer = buffer
3342
+
3343
+ def __repr__(self) -> str:
3344
+ return attr_repr(self, 'buffer')
3345
+
3346
+ class ClosedError(Error):
3347
+ pass
3348
+
3349
+ #
3350
+
3351
+ DEFAULT_DELIMITERS: bytes = b'\n'
3352
+
3353
+ def __init__(
3354
+ self,
3355
+ delimiters: ta.Iterable[int] = DEFAULT_DELIMITERS,
3356
+ *,
3357
+ keep_ends: bool = False,
3358
+ max_size: ta.Optional[int] = None,
3359
+ ) -> None:
3360
+ super().__init__()
3361
+
3362
+ self._delimiters = frozenset(check.isinstance(d, int) for d in delimiters)
3363
+ self._keep_ends = keep_ends
3364
+ self._max_size = max_size
3365
+
3366
+ self._buf: ta.Optional[io.BytesIO] = io.BytesIO()
3367
+
3368
+ #
3369
+
3370
+ @property
3371
+ def is_closed(self) -> bool:
3372
+ return self._buf is None
3373
+
3374
+ def tell(self) -> int:
3375
+ if (buf := self._buf) is None:
3376
+ raise self.ClosedError(self)
3377
+ return buf.tell()
3378
+
3379
+ def peek(self) -> bytes:
3380
+ if (buf := self._buf) is None:
3381
+ raise self.ClosedError(self)
3382
+ return buf.getvalue()
3383
+
3384
+ def _find_delim(self, data: ta.Union[bytes, bytearray], i: int) -> ta.Optional[int]:
3385
+ r = None # type: int | None
3386
+ for d in self._delimiters:
3387
+ if (p := data.find(d, i)) >= 0:
3388
+ if r is None or p < r:
3389
+ r = p
3390
+ return r
3391
+
3392
+ def _append_and_reset(self, chunk: bytes) -> bytes:
3393
+ buf = check.not_none(self._buf)
3394
+ if not buf.tell():
3395
+ return chunk
3396
+
3397
+ buf.write(chunk)
3398
+ ret = buf.getvalue()
3399
+ buf.seek(0)
3400
+ buf.truncate()
3401
+ return ret
3402
+
3403
+ class Incomplete(ta.NamedTuple):
3404
+ b: bytes
3405
+
3406
+ def feed(self, data: ta.Union[bytes, bytearray]) -> ta.Generator[ta.Union[bytes, Incomplete], None, None]:
3407
+ if (buf := self._buf) is None:
3408
+ raise self.ClosedError(self)
3409
+
3410
+ if not data:
3411
+ self._buf = None
3412
+
3413
+ if buf.tell():
3414
+ yield self.Incomplete(buf.getvalue())
3415
+
3416
+ return
3417
+
3418
+ l = len(data)
3419
+ i = 0
3420
+ while i < l:
3421
+ if (p := self._find_delim(data, i)) is None:
3422
+ break
3423
+
3424
+ n = p + 1
3425
+ if self._keep_ends:
3426
+ p = n
3427
+
3428
+ yield self._append_and_reset(data[i:p])
3429
+
3430
+ i = n
3431
+
3432
+ if i >= l:
3433
+ return
3434
+
3435
+ if self._max_size is None:
3436
+ buf.write(data[i:])
3437
+ return
3438
+
3439
+ while i < l:
3440
+ remaining_data_len = l - i
3441
+ remaining_buf_capacity = self._max_size - buf.tell()
3442
+
3443
+ if remaining_data_len < remaining_buf_capacity:
3444
+ buf.write(data[i:])
3445
+ return
3446
+
3447
+ p = i + remaining_buf_capacity
3448
+ yield self.Incomplete(self._append_and_reset(data[i:p]))
3449
+ i = p
3450
+
3451
+
3452
+ class ReadableListBuffer:
3453
+ def __init__(self) -> None:
3454
+ super().__init__()
3455
+ self._lst: list[bytes] = []
3456
+
3457
+ def feed(self, d: bytes) -> None:
3458
+ if d:
3459
+ self._lst.append(d)
3460
+
3461
+ def _chop(self, i: int, e: int) -> bytes:
3462
+ lst = self._lst
3463
+ d = lst[i]
3464
+
3465
+ o = b''.join([
3466
+ *lst[:i],
3467
+ d[:e],
3468
+ ])
3469
+
3470
+ self._lst = [
3471
+ *([d[e:]] if e < len(d) else []),
3472
+ *lst[i + 1:],
3473
+ ]
3474
+
3475
+ return o
3476
+
3477
+ def read(self, n: ta.Optional[int] = None) -> ta.Optional[bytes]:
3478
+ if n is None:
3479
+ o = b''.join(self._lst)
3480
+ self._lst = []
3481
+ return o
3482
+
3483
+ if not (lst := self._lst):
3484
+ return None
3485
+
3486
+ c = 0
3487
+ for i, d in enumerate(lst):
3488
+ r = n - c
3489
+ if (l := len(d)) >= r:
3490
+ return self._chop(i, r)
3491
+ c += l
3492
+
3493
+ return None
3494
+
3495
+ def read_until(self, delim: bytes = b'\n') -> ta.Optional[bytes]:
3496
+ if not (lst := self._lst):
3497
+ return None
3498
+
3499
+ for i, d in enumerate(lst):
3500
+ if (p := d.find(delim)) >= 0:
3501
+ return self._chop(i, p + len(delim))
3502
+
3503
+ return None
3504
+
3505
+
3506
+ class IncrementalWriteBuffer:
3507
+ def __init__(
3508
+ self,
3509
+ data: bytes,
3510
+ *,
3511
+ write_size: int = 0x10000,
3512
+ ) -> None:
3513
+ super().__init__()
3514
+
3515
+ check.not_empty(data)
3516
+ self._len = len(data)
3517
+ self._write_size = write_size
3518
+
3519
+ self._lst = [
3520
+ data[i:i + write_size]
3521
+ for i in range(0, len(data), write_size)
3522
+ ]
3523
+ self._pos = 0
3524
+
3525
+ @property
3526
+ def rem(self) -> int:
3527
+ return self._len - self._pos
3528
+
3529
+ def write(self, fn: ta.Callable[[bytes], int]) -> int:
3530
+ lst = check.not_empty(self._lst)
3531
+
3532
+ t = 0
3533
+ for i, d in enumerate(lst): # noqa
3534
+ n = fn(check.not_empty(d))
3535
+ if not n:
3536
+ break
3537
+ t += n
3538
+
3539
+ if t:
3540
+ self._lst = [
3541
+ *([d[n:]] if n < len(d) else []),
3542
+ *lst[i + 1:],
3543
+ ]
3544
+ self._pos += t
3545
+
3546
+ return t
3547
+
3548
+
3549
+ ########################################
3550
+ # ../../../omlish/io/fdio/handlers.py
3551
+
3552
+
3553
+ class FdioHandler(abc.ABC):
3554
+ @abc.abstractmethod
3555
+ def fd(self) -> int:
3556
+ raise NotImplementedError
3557
+
3558
+ #
3559
+
3560
+ @property
3561
+ @abc.abstractmethod
3562
+ def closed(self) -> bool:
3563
+ raise NotImplementedError
3564
+
3565
+ @abc.abstractmethod
3566
+ def close(self) -> None:
3567
+ raise NotImplementedError
3568
+
3569
+ #
3570
+
3571
+ def readable(self) -> bool:
3572
+ return False
3573
+
3574
+ def writable(self) -> bool:
3575
+ return False
3576
+
3577
+ #
3578
+
3579
+ def on_readable(self) -> None:
3580
+ raise TypeError
3581
+
3582
+ def on_writable(self) -> None:
3583
+ raise TypeError
3584
+
3585
+ def on_error(self, exc: ta.Optional[BaseException] = None) -> None: # noqa
3586
+ pass
3587
+
3588
+
3589
+ class SocketFdioHandler(FdioHandler, abc.ABC):
3590
+ def __init__(
3591
+ self,
3592
+ addr: SocketAddress,
3593
+ sock: socket.socket,
3594
+ ) -> None:
3595
+ super().__init__()
3596
+
3597
+ self._addr = addr
3598
+ self._sock: ta.Optional[socket.socket] = sock
3599
+
3600
+ def fd(self) -> int:
3601
+ return check.not_none(self._sock).fileno()
3602
+
3603
+ @property
3604
+ def closed(self) -> bool:
3605
+ return self._sock is None
3606
+
3607
+ def close(self) -> None:
3608
+ if self._sock is not None:
3609
+ self._sock.close()
3610
+ self._sock = None
3611
+
3612
+
3613
+ ########################################
3614
+ # ../../../omlish/io/fdio/kqueue.py
3615
+
3616
+
3617
+ KqueueFdioPoller: ta.Optional[ta.Type[FdioPoller]]
3618
+ if sys.platform == 'darwin' or sys.platform.startswith('freebsd'):
3619
+
3620
+ class _KqueueFdioPoller(FdioPoller):
3621
+ DEFAULT_MAX_EVENTS = 1000
3622
+
3623
+ def __init__(
3624
+ self,
3625
+ *,
3626
+ max_events: int = DEFAULT_MAX_EVENTS,
3627
+ ) -> None:
3628
+ super().__init__()
3629
+
3630
+ self._max_events = max_events
3631
+
3632
+ self._kqueue: ta.Optional[ta.Any] = None
3633
+
3634
+ #
3635
+
3636
+ def _get_kqueue(self) -> 'select.kqueue':
3637
+ if (kq := self._kqueue) is not None:
3638
+ return kq
3639
+ kq = select.kqueue()
3640
+ self._kqueue = kq
3641
+ return kq
3642
+
3643
+ def close(self) -> None:
3644
+ if self._kqueue is not None:
3645
+ self._kqueue.close()
3646
+ self._kqueue = None
3647
+
3648
+ def reopen(self) -> None:
3649
+ for fd in self._readable:
3650
+ self._register_readable(fd)
3651
+ for fd in self._writable:
3652
+ self._register_writable(fd)
3653
+
3654
+ #
3655
+
3656
+ def _register_readable(self, fd: int) -> None:
3657
+ self._update_registration(fd, 'read', 'add')
3658
+
3659
+ def _register_writable(self, fd: int) -> None:
3660
+ self._update_registration(fd, 'write', 'add')
3661
+
3662
+ def _unregister_readable(self, fd: int) -> None:
3663
+ self._update_registration(fd, 'read', 'del')
3664
+
3665
+ def _unregister_writable(self, fd: int) -> None:
3666
+ self._update_registration(fd, 'write', 'del')
3667
+
3668
+ #
3669
+
3670
+ _CONTROL_FILTER_BY_READ_OR_WRITE: ta.ClassVar[ta.Mapping[ta.Literal['read', 'write'], int]] = {
3671
+ 'read': select.KQ_FILTER_READ,
3672
+ 'write': select.KQ_FILTER_WRITE,
3673
+ }
3674
+
3675
+ _CONTROL_FLAGS_BY_ADD_OR_DEL: ta.ClassVar[ta.Mapping[ta.Literal['add', 'del'], int]] = {
3676
+ 'add': select.KQ_EV_ADD,
3677
+ 'del': select.KQ_EV_DELETE,
3678
+ }
3679
+
3680
+ def _update_registration(
3681
+ self,
3682
+ fd: int,
3683
+ read_or_write: ta.Literal['read', 'write'],
3684
+ add_or_del: ta.Literal['add', 'del'],
3685
+ ) -> None: # noqa
3686
+ ke = select.kevent(
3687
+ fd,
3688
+ filter=self._CONTROL_FILTER_BY_READ_OR_WRITE[read_or_write],
3689
+ flags=self._CONTROL_FLAGS_BY_ADD_OR_DEL[add_or_del],
3690
+ )
3691
+ kq = self._get_kqueue()
3692
+ try:
3693
+ kq.control([ke], 0)
3694
+
3695
+ except OSError as exc:
3696
+ if exc.errno == errno.EBADF:
3697
+ # log.debug('EBADF encountered in kqueue. Invalid file descriptor %s', ke.ident)
3698
+ pass
3699
+ elif exc.errno == errno.ENOENT:
3700
+ # Can happen when trying to remove an already closed socket
3701
+ if add_or_del == 'add':
3702
+ raise
3703
+ else:
3704
+ raise
3705
+
3706
+ #
3707
+
3708
+ def poll(self, timeout: ta.Optional[float]) -> FdioPoller.PollResult:
3709
+ kq = self._get_kqueue()
3710
+ try:
3711
+ kes = kq.control(None, self._max_events, timeout)
3712
+
3713
+ except OSError as exc:
3714
+ if exc.errno == errno.EINTR:
3715
+ return FdioPoller.PollResult(msg='EINTR encountered in poll', exc=exc)
3716
+ else:
3717
+ raise
3718
+
3719
+ r: ta.List[int] = []
3720
+ w: ta.List[int] = []
3721
+ for ke in kes:
3722
+ if ke.filter == select.KQ_FILTER_READ:
3723
+ r.append(ke.ident)
3724
+ if ke.filter == select.KQ_FILTER_WRITE:
3725
+ w.append(ke.ident)
3726
+
3727
+ return FdioPoller.PollResult(r, w)
3728
+
3729
+ KqueueFdioPoller = _KqueueFdioPoller
3730
+ else:
3731
+ KqueueFdioPoller = None
3732
+
3733
+
3734
+ ########################################
3735
+ # ../../../omlish/lite/contextmanagers.py
3736
+
3737
+
3738
+ ##
3739
+
3740
+
3741
+ class ExitStacked:
3742
+ _exit_stack: ta.Optional[contextlib.ExitStack] = None
3743
+
3744
+ def __enter__(self: ExitStackedT) -> ExitStackedT:
3745
+ check.state(self._exit_stack is None)
3746
+ es = self._exit_stack = contextlib.ExitStack()
3747
+ es.__enter__()
3748
+ return self
3749
+
3750
+ def __exit__(self, exc_type, exc_val, exc_tb):
3751
+ if (es := self._exit_stack) is None:
3752
+ return None
3753
+ self._exit_contexts()
3754
+ return es.__exit__(exc_type, exc_val, exc_tb)
3755
+
3756
+ def _exit_contexts(self) -> None:
3757
+ pass
3758
+
3759
+ def _enter_context(self, cm: ta.ContextManager[T]) -> T:
3760
+ es = check.not_none(self._exit_stack)
3761
+ return es.enter_context(cm)
3762
+
3763
+
3764
+ ##
3186
3765
 
3187
- expect = headers.get('Expect', '')
3188
- if (
3189
- expect.lower() == '100-continue' and
3190
- version >= HttpProtocolVersions.HTTP_1_1
3191
- ):
3192
- expects_continue = True
3193
- else:
3194
- expects_continue = False
3195
3766
 
3196
- # Return
3767
+ @contextlib.contextmanager
3768
+ def defer(fn: ta.Callable) -> ta.Generator[ta.Callable, None, None]:
3769
+ try:
3770
+ yield fn
3771
+ finally:
3772
+ fn()
3197
3773
 
3198
- return ParsedHttpRequest(
3199
- method=method,
3200
- path=path,
3201
- expects_continue=expects_continue,
3202
- **result_kwargs(),
3203
- )
3204
3774
 
3205
- def parse(self, read_line: ta.Callable[[int], bytes]) -> ParseHttpRequestResult:
3206
- return self._run_read_line_coro(self.coro_parse(), read_line)
3775
+ @contextlib.contextmanager
3776
+ def attr_setting(obj, attr, val, *, default=None): # noqa
3777
+ not_set = object()
3778
+ orig = getattr(obj, attr, not_set)
3779
+ try:
3780
+ setattr(obj, attr, val)
3781
+ if orig is not not_set:
3782
+ yield orig
3783
+ else:
3784
+ yield default
3785
+ finally:
3786
+ if orig is not_set:
3787
+ delattr(obj, attr)
3788
+ else:
3789
+ setattr(obj, attr, orig)
3207
3790
 
3208
3791
 
3209
3792
  ########################################
@@ -3350,7 +3933,7 @@ class FnInjectorProvider(InjectorProvider):
3350
3933
  fn: ta.Any
3351
3934
 
3352
3935
  def __post_init__(self) -> None:
3353
- check_not_isinstance(self.fn, type)
3936
+ check.not_isinstance(self.fn, type)
3354
3937
 
3355
3938
  def provider_fn(self) -> InjectorProviderFn:
3356
3939
  def pfn(i: Injector) -> ta.Any:
@@ -3364,7 +3947,7 @@ class CtorInjectorProvider(InjectorProvider):
3364
3947
  cls_: type
3365
3948
 
3366
3949
  def __post_init__(self) -> None:
3367
- check_isinstance(self.cls_, type)
3950
+ check.isinstance(self.cls_, type)
3368
3951
 
3369
3952
  def provider_fn(self) -> InjectorProviderFn:
3370
3953
  def pfn(i: Injector) -> ta.Any:
@@ -3386,7 +3969,7 @@ class SingletonInjectorProvider(InjectorProvider):
3386
3969
  p: InjectorProvider
3387
3970
 
3388
3971
  def __post_init__(self) -> None:
3389
- check_isinstance(self.p, InjectorProvider)
3972
+ check.isinstance(self.p, InjectorProvider)
3390
3973
 
3391
3974
  def provider_fn(self) -> InjectorProviderFn:
3392
3975
  v = not_set = object()
@@ -3406,7 +3989,7 @@ class LinkInjectorProvider(InjectorProvider):
3406
3989
  k: InjectorKey
3407
3990
 
3408
3991
  def __post_init__(self) -> None:
3409
- check_isinstance(self.k, InjectorKey)
3992
+ check.isinstance(self.k, InjectorKey)
3410
3993
 
3411
3994
  def provider_fn(self) -> InjectorProviderFn:
3412
3995
  def pfn(i: Injector) -> ta.Any:
@@ -3603,7 +4186,7 @@ def build_injection_kwargs_target(
3603
4186
 
3604
4187
  skip_names: ta.Set[str] = set()
3605
4188
  if skip_kwargs is not None:
3606
- skip_names.update(check_not_isinstance(skip_kwargs, str))
4189
+ skip_names.update(check.not_isinstance(skip_kwargs, str))
3607
4190
 
3608
4191
  seen: ta.Set[InjectorKey] = set()
3609
4192
  kws: ta.List[InjectionKwarg] = []
@@ -3664,8 +4247,8 @@ class _Injector(Injector):
3664
4247
  def __init__(self, bs: InjectorBindings, p: ta.Optional[Injector] = None) -> None:
3665
4248
  super().__init__()
3666
4249
 
3667
- self._bs = check_isinstance(bs, InjectorBindings)
3668
- self._p: ta.Optional[Injector] = check_isinstance(p, (Injector, type(None)))
4250
+ self._bs = check.isinstance(bs, InjectorBindings)
4251
+ self._p: ta.Optional[Injector] = check.isinstance(p, (Injector, type(None)))
3669
4252
 
3670
4253
  self._pfm = {k: v.provider_fn() for k, v in build_injector_provider_map(bs).items()}
3671
4254
 
@@ -3696,8 +4279,8 @@ class _Injector(Injector):
3696
4279
  return Maybe.empty()
3697
4280
 
3698
4281
  def handle_provision(self, key: InjectorKey, mv: Maybe) -> Maybe:
3699
- check_in(key, self._seen_keys)
3700
- check_not_in(key, self._provisions)
4282
+ check.in_(key, self._seen_keys)
4283
+ check.not_in(key, self._provisions)
3701
4284
  self._provisions[key] = mv
3702
4285
  return mv
3703
4286
 
@@ -3811,7 +4394,7 @@ class InjectorBinder:
3811
4394
 
3812
4395
  @classmethod
3813
4396
  def bind_as_fn(cls, icls: ta.Type[T]) -> ta.Type[T]:
3814
- check_isinstance(icls, type)
4397
+ check.isinstance(icls, type)
3815
4398
  if icls not in cls._FN_TYPES:
3816
4399
  cls._FN_TYPES = (*cls._FN_TYPES, icls)
3817
4400
  return icls
@@ -3868,7 +4451,7 @@ class InjectorBinder:
3868
4451
  to_fn = obj
3869
4452
  if key is None:
3870
4453
  insp = _injection_inspect(obj)
3871
- key_cls: ta.Any = check_valid_injector_key_cls(check_not_none(insp.type_hints.get('return')))
4454
+ key_cls: ta.Any = check_valid_injector_key_cls(check.not_none(insp.type_hints.get('return')))
3872
4455
  key = InjectorKey(key_cls)
3873
4456
  else:
3874
4457
  if to_const is not None:
@@ -4099,228 +4682,6 @@ class Injection:
4099
4682
  inj = Injection
4100
4683
 
4101
4684
 
4102
- ########################################
4103
- # ../../../omlish/lite/io.py
4104
-
4105
-
4106
- class DelimitingBuffer:
4107
- """
4108
- https://github.com/python-trio/trio/issues/796 :|
4109
- """
4110
-
4111
- #
4112
-
4113
- class Error(Exception):
4114
- def __init__(self, buffer: 'DelimitingBuffer') -> None:
4115
- super().__init__(buffer)
4116
- self.buffer = buffer
4117
-
4118
- def __repr__(self) -> str:
4119
- return attr_repr(self, 'buffer')
4120
-
4121
- class ClosedError(Error):
4122
- pass
4123
-
4124
- #
4125
-
4126
- DEFAULT_DELIMITERS: bytes = b'\n'
4127
-
4128
- def __init__(
4129
- self,
4130
- delimiters: ta.Iterable[int] = DEFAULT_DELIMITERS,
4131
- *,
4132
- keep_ends: bool = False,
4133
- max_size: ta.Optional[int] = None,
4134
- ) -> None:
4135
- super().__init__()
4136
-
4137
- self._delimiters = frozenset(check_isinstance(d, int) for d in delimiters)
4138
- self._keep_ends = keep_ends
4139
- self._max_size = max_size
4140
-
4141
- self._buf: ta.Optional[io.BytesIO] = io.BytesIO()
4142
-
4143
- #
4144
-
4145
- @property
4146
- def is_closed(self) -> bool:
4147
- return self._buf is None
4148
-
4149
- def tell(self) -> int:
4150
- if (buf := self._buf) is None:
4151
- raise self.ClosedError(self)
4152
- return buf.tell()
4153
-
4154
- def peek(self) -> bytes:
4155
- if (buf := self._buf) is None:
4156
- raise self.ClosedError(self)
4157
- return buf.getvalue()
4158
-
4159
- def _find_delim(self, data: ta.Union[bytes, bytearray], i: int) -> ta.Optional[int]:
4160
- r = None # type: int | None
4161
- for d in self._delimiters:
4162
- if (p := data.find(d, i)) >= 0:
4163
- if r is None or p < r:
4164
- r = p
4165
- return r
4166
-
4167
- def _append_and_reset(self, chunk: bytes) -> bytes:
4168
- buf = check_not_none(self._buf)
4169
- if not buf.tell():
4170
- return chunk
4171
-
4172
- buf.write(chunk)
4173
- ret = buf.getvalue()
4174
- buf.seek(0)
4175
- buf.truncate()
4176
- return ret
4177
-
4178
- class Incomplete(ta.NamedTuple):
4179
- b: bytes
4180
-
4181
- def feed(self, data: ta.Union[bytes, bytearray]) -> ta.Generator[ta.Union[bytes, Incomplete], None, None]:
4182
- if (buf := self._buf) is None:
4183
- raise self.ClosedError(self)
4184
-
4185
- if not data:
4186
- self._buf = None
4187
-
4188
- if buf.tell():
4189
- yield self.Incomplete(buf.getvalue())
4190
-
4191
- return
4192
-
4193
- l = len(data)
4194
- i = 0
4195
- while i < l:
4196
- if (p := self._find_delim(data, i)) is None:
4197
- break
4198
-
4199
- n = p + 1
4200
- if self._keep_ends:
4201
- p = n
4202
-
4203
- yield self._append_and_reset(data[i:p])
4204
-
4205
- i = n
4206
-
4207
- if i >= l:
4208
- return
4209
-
4210
- if self._max_size is None:
4211
- buf.write(data[i:])
4212
- return
4213
-
4214
- while i < l:
4215
- remaining_data_len = l - i
4216
- remaining_buf_capacity = self._max_size - buf.tell()
4217
-
4218
- if remaining_data_len < remaining_buf_capacity:
4219
- buf.write(data[i:])
4220
- return
4221
-
4222
- p = i + remaining_buf_capacity
4223
- yield self.Incomplete(self._append_and_reset(data[i:p]))
4224
- i = p
4225
-
4226
-
4227
- class ReadableListBuffer:
4228
- def __init__(self) -> None:
4229
- super().__init__()
4230
- self._lst: list[bytes] = []
4231
-
4232
- def feed(self, d: bytes) -> None:
4233
- if d:
4234
- self._lst.append(d)
4235
-
4236
- def _chop(self, i: int, e: int) -> bytes:
4237
- lst = self._lst
4238
- d = lst[i]
4239
-
4240
- o = b''.join([
4241
- *lst[:i],
4242
- d[:e],
4243
- ])
4244
-
4245
- self._lst = [
4246
- *([d[e:]] if e < len(d) else []),
4247
- *lst[i + 1:],
4248
- ]
4249
-
4250
- return o
4251
-
4252
- def read(self, n: ta.Optional[int] = None) -> ta.Optional[bytes]:
4253
- if n is None:
4254
- o = b''.join(self._lst)
4255
- self._lst = []
4256
- return o
4257
-
4258
- if not (lst := self._lst):
4259
- return None
4260
-
4261
- c = 0
4262
- for i, d in enumerate(lst):
4263
- r = n - c
4264
- if (l := len(d)) >= r:
4265
- return self._chop(i, r)
4266
- c += l
4267
-
4268
- return None
4269
-
4270
- def read_until(self, delim: bytes = b'\n') -> ta.Optional[bytes]:
4271
- if not (lst := self._lst):
4272
- return None
4273
-
4274
- for i, d in enumerate(lst):
4275
- if (p := d.find(delim)) >= 0:
4276
- return self._chop(i, p + len(delim))
4277
-
4278
- return None
4279
-
4280
-
4281
- class IncrementalWriteBuffer:
4282
- def __init__(
4283
- self,
4284
- data: bytes,
4285
- *,
4286
- write_size: int = 0x10000,
4287
- ) -> None:
4288
- super().__init__()
4289
-
4290
- check_non_empty(data)
4291
- self._len = len(data)
4292
- self._write_size = write_size
4293
-
4294
- self._lst = [
4295
- data[i:i + write_size]
4296
- for i in range(0, len(data), write_size)
4297
- ]
4298
- self._pos = 0
4299
-
4300
- @property
4301
- def rem(self) -> int:
4302
- return self._len - self._pos
4303
-
4304
- def write(self, fn: ta.Callable[[bytes], int]) -> int:
4305
- lst = check_non_empty(self._lst)
4306
-
4307
- t = 0
4308
- for i, d in enumerate(lst): # noqa
4309
- n = fn(check_non_empty(d))
4310
- if not n:
4311
- break
4312
- t += n
4313
-
4314
- if t:
4315
- self._lst = [
4316
- *([d[n:]] if n < len(d) else []),
4317
- *lst[i + 1:],
4318
- ]
4319
- self._pos += t
4320
-
4321
- return t
4322
-
4323
-
4324
4685
  ########################################
4325
4686
  # ../../../omlish/lite/journald.py
4326
4687
 
@@ -4789,10 +5150,10 @@ class ProxyObjMarshaler(ObjMarshaler):
4789
5150
  m: ta.Optional[ObjMarshaler] = None
4790
5151
 
4791
5152
  def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
4792
- return check_not_none(self.m).marshal(o, ctx)
5153
+ return check.not_none(self.m).marshal(o, ctx)
4793
5154
 
4794
5155
  def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
4795
- return check_not_none(self.m).unmarshal(o, ctx)
5156
+ return check.not_none(self.m).unmarshal(o, ctx)
4796
5157
 
4797
5158
 
4798
5159
  @dc.dataclass(frozen=True)
@@ -4951,19 +5312,19 @@ class DatetimeObjMarshaler(ObjMarshaler):
4951
5312
 
4952
5313
  class DecimalObjMarshaler(ObjMarshaler):
4953
5314
  def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
4954
- return str(check_isinstance(o, decimal.Decimal))
5315
+ return str(check.isinstance(o, decimal.Decimal))
4955
5316
 
4956
5317
  def unmarshal(self, v: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
4957
- return decimal.Decimal(check_isinstance(v, str))
5318
+ return decimal.Decimal(check.isinstance(v, str))
4958
5319
 
4959
5320
 
4960
5321
  class FractionObjMarshaler(ObjMarshaler):
4961
5322
  def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
4962
- fr = check_isinstance(o, fractions.Fraction)
5323
+ fr = check.isinstance(o, fractions.Fraction)
4963
5324
  return [fr.numerator, fr.denominator]
4964
5325
 
4965
5326
  def unmarshal(self, v: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
4966
- num, denom = check_isinstance(v, list)
5327
+ num, denom = check.isinstance(v, list)
4967
5328
  return fractions.Fraction(num, denom)
4968
5329
 
4969
5330
 
@@ -5265,7 +5626,7 @@ def build_config_named_children(
5265
5626
  lst: ta.List[ConfigMapping] = []
5266
5627
  if isinstance(o, ta.Mapping):
5267
5628
  for k, v in o.items():
5268
- check_isinstance(v, ta.Mapping)
5629
+ check.isinstance(v, ta.Mapping)
5269
5630
  if name_key in v:
5270
5631
  n = v[name_key]
5271
5632
  if k != n:
@@ -5275,7 +5636,7 @@ def build_config_named_children(
5275
5636
  lst.append({name_key: k, **v})
5276
5637
 
5277
5638
  else:
5278
- check_not_isinstance(o, str)
5639
+ check.not_isinstance(o, str)
5279
5640
  lst.extend(o)
5280
5641
 
5281
5642
  seen = set()
@@ -5406,7 +5767,7 @@ class SupervisorSetup(abc.ABC):
5406
5767
 
5407
5768
 
5408
5769
  ########################################
5409
- # ../../../omlish/lite/http/handlers.py
5770
+ # ../../../omlish/http/handlers.py
5410
5771
 
5411
5772
 
5412
5773
  @dc.dataclass(frozen=True)
@@ -5581,7 +5942,7 @@ def parse_logging_level(value: ta.Union[str, int]) -> int:
5581
5942
 
5582
5943
 
5583
5944
  ########################################
5584
- # ../../../omlish/lite/http/coroserver.py
5945
+ # ../../../omlish/http/coroserver.py
5585
5946
  # PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
5586
5947
  # --------------------------------------------
5587
5948
  #
@@ -5961,13 +6322,13 @@ class CoroHttpServer:
5961
6322
  yield o
5962
6323
 
5963
6324
  elif isinstance(o, self.AnyReadIo):
5964
- i = check_isinstance((yield o), bytes)
6325
+ i = check.isinstance((yield o), bytes)
5965
6326
 
5966
6327
  elif isinstance(o, self._Response):
5967
6328
  i = None
5968
6329
  r = self._preprocess_response(o)
5969
6330
  b = self._build_response_bytes(r)
5970
- check_none((yield self.WriteIo(b)))
6331
+ check.none((yield self.WriteIo(b)))
5971
6332
 
5972
6333
  else:
5973
6334
  raise TypeError(o)
@@ -5990,7 +6351,7 @@ class CoroHttpServer:
5990
6351
  sz = next(gen)
5991
6352
  while True:
5992
6353
  try:
5993
- line = check_isinstance((yield self.ReadLineIo(sz)), bytes)
6354
+ line = check.isinstance((yield self.ReadLineIo(sz)), bytes)
5994
6355
  sz = gen.send(line)
5995
6356
  except StopIteration as e:
5996
6357
  parsed = e.value
@@ -6009,11 +6370,11 @@ class CoroHttpServer:
6009
6370
  yield self._build_error_response(err)
6010
6371
  return
6011
6372
 
6012
- parsed = check_isinstance(parsed, ParsedHttpRequest)
6373
+ parsed = check.isinstance(parsed, ParsedHttpRequest)
6013
6374
 
6014
6375
  # Log
6015
6376
 
6016
- check_none((yield self.ParsedRequestLogIo(parsed)))
6377
+ check.none((yield self.ParsedRequestLogIo(parsed)))
6017
6378
 
6018
6379
  # Handle CONTINUE
6019
6380
 
@@ -6029,7 +6390,7 @@ class CoroHttpServer:
6029
6390
 
6030
6391
  request_data: ta.Optional[bytes]
6031
6392
  if (cl := parsed.headers.get('Content-Length')) is not None:
6032
- request_data = check_isinstance((yield self.ReadIo(int(cl))), bytes)
6393
+ request_data = check.isinstance((yield self.ReadIo(int(cl))), bytes)
6033
6394
  else:
6034
6395
  request_data = None
6035
6396
 
@@ -6037,7 +6398,7 @@ class CoroHttpServer:
6037
6398
 
6038
6399
  handler_request = HttpHandlerRequest(
6039
6400
  client_address=self._client_address,
6040
- method=check_not_none(parsed.method),
6401
+ method=check.not_none(parsed.method),
6041
6402
  path=parsed.path,
6042
6403
  headers=parsed.headers,
6043
6404
  data=request_data,
@@ -6321,7 +6682,7 @@ class ProcessGroup(
6321
6682
 
6322
6683
 
6323
6684
  ########################################
6324
- # ../../../omlish/lite/fdio/corohttp.py
6685
+ # ../../../omlish/io/fdio/corohttp.py
6325
6686
 
6326
6687
 
6327
6688
  class CoroHttpServerConnectionFdioHandler(SocketFdioHandler):
@@ -6335,7 +6696,7 @@ class CoroHttpServerConnectionFdioHandler(SocketFdioHandler):
6335
6696
  write_size: int = 0x10000,
6336
6697
  log_handler: ta.Optional[ta.Callable[[CoroHttpServer, CoroHttpServer.AnyLogIo], None]] = None,
6337
6698
  ) -> None:
6338
- check_state(not sock.getblocking())
6699
+ check.state(not sock.getblocking())
6339
6700
 
6340
6701
  super().__init__(addr, sock)
6341
6702
 
@@ -6359,7 +6720,7 @@ class CoroHttpServerConnectionFdioHandler(SocketFdioHandler):
6359
6720
  #
6360
6721
 
6361
6722
  def _next_io(self) -> None: # noqa
6362
- coro = check_not_none(self._srv_coro)
6723
+ coro = check.not_none(self._srv_coro)
6363
6724
 
6364
6725
  d: bytes | None = None
6365
6726
  o = self._cur_io
@@ -6392,7 +6753,7 @@ class CoroHttpServerConnectionFdioHandler(SocketFdioHandler):
6392
6753
  o = None
6393
6754
 
6394
6755
  elif isinstance(o, CoroHttpServer.WriteIo):
6395
- check_none(self._write_buf)
6756
+ check.none(self._write_buf)
6396
6757
  self._write_buf = IncrementalWriteBuffer(o.data, write_size=self._write_size)
6397
6758
  break
6398
6759
 
@@ -6413,7 +6774,7 @@ class CoroHttpServerConnectionFdioHandler(SocketFdioHandler):
6413
6774
 
6414
6775
  def on_readable(self) -> None:
6415
6776
  try:
6416
- buf = check_not_none(self._sock).recv(self._read_size)
6777
+ buf = check.not_none(self._sock).recv(self._read_size)
6417
6778
  except BlockingIOError:
6418
6779
  return
6419
6780
  except ConnectionResetError:
@@ -6429,12 +6790,12 @@ class CoroHttpServerConnectionFdioHandler(SocketFdioHandler):
6429
6790
  self._next_io()
6430
6791
 
6431
6792
  def on_writable(self) -> None:
6432
- check_isinstance(self._cur_io, CoroHttpServer.WriteIo)
6433
- wb = check_not_none(self._write_buf)
6793
+ check.isinstance(self._cur_io, CoroHttpServer.WriteIo)
6794
+ wb = check.not_none(self._write_buf)
6434
6795
  while wb.rem > 0:
6435
6796
  def send(d: bytes) -> int:
6436
6797
  try:
6437
- return check_not_none(self._sock).send(d)
6798
+ return check.not_none(self._sock).send(d)
6438
6799
  except ConnectionResetError:
6439
6800
  self.close()
6440
6801
  return 0
@@ -6827,7 +7188,7 @@ class ProcessGroupImpl(ProcessGroup):
6827
7188
 
6828
7189
  by_name: ta.Dict[str, Process] = {}
6829
7190
  for pconfig in self._config.processes or []:
6830
- p = check_isinstance(self._process_factory(pconfig, self), Process)
7191
+ p = check.isinstance(self._process_factory(pconfig, self), Process)
6831
7192
  if p.name in by_name:
6832
7193
  raise KeyError(f'name {p.name} of process {p} already registered by {by_name[p.name]}')
6833
7194
  by_name[pconfig.name] = p
@@ -7380,7 +7741,7 @@ class SocketServerFdioHandler(SocketFdioHandler):
7380
7741
  return True
7381
7742
 
7382
7743
  def on_readable(self) -> None:
7383
- cli_sock, cli_addr = check_not_none(self._sock).accept()
7744
+ cli_sock, cli_addr = check.not_none(self._sock).accept()
7384
7745
  cli_sock.setblocking(False)
7385
7746
 
7386
7747
  self._on_connect(cli_sock, cli_addr)
@@ -7619,7 +7980,7 @@ class ProcessImpl(Process):
7619
7980
  if stdin_fd is None:
7620
7981
  raise OSError(errno.EPIPE, 'Process has no stdin channel')
7621
7982
 
7622
- dispatcher = check_isinstance(self._dispatchers[stdin_fd], ProcessInputDispatcher)
7983
+ dispatcher = check.isinstance(self._dispatchers[stdin_fd], ProcessInputDispatcher)
7623
7984
  if dispatcher.closed:
7624
7985
  raise OSError(errno.EPIPE, "Process' stdin channel is closed")
7625
7986
 
@@ -8178,21 +8539,21 @@ class ProcessSpawningImpl(ProcessSpawning):
8178
8539
  dispatchers: ta.List[FdioHandler] = []
8179
8540
 
8180
8541
  if pipes.stdout is not None:
8181
- dispatchers.append(check_isinstance(self._output_dispatcher_factory(
8542
+ dispatchers.append(check.isinstance(self._output_dispatcher_factory(
8182
8543
  self.process,
8183
8544
  ProcessCommunicationStdoutEvent,
8184
8545
  pipes.stdout,
8185
8546
  ), ProcessOutputDispatcher))
8186
8547
 
8187
8548
  if pipes.stderr is not None:
8188
- dispatchers.append(check_isinstance(self._output_dispatcher_factory(
8549
+ dispatchers.append(check.isinstance(self._output_dispatcher_factory(
8189
8550
  self.process,
8190
8551
  ProcessCommunicationStderrEvent,
8191
8552
  pipes.stderr,
8192
8553
  ), ProcessOutputDispatcher))
8193
8554
 
8194
8555
  if pipes.stdin is not None:
8195
- dispatchers.append(check_isinstance(self._input_dispatcher_factory(
8556
+ dispatchers.append(check.isinstance(self._input_dispatcher_factory(
8196
8557
  self.process,
8197
8558
  'stdin',
8198
8559
  pipes.stdin,
@@ -8282,14 +8643,14 @@ class ProcessSpawningImpl(ProcessSpawning):
8282
8643
  raise RuntimeError('Unreachable')
8283
8644
 
8284
8645
  def _prepare_child_fds(self, pipes: ProcessPipes) -> None:
8285
- os.dup2(check_not_none(pipes.child_stdin), 0)
8646
+ os.dup2(check.not_none(pipes.child_stdin), 0)
8286
8647
 
8287
- os.dup2(check_not_none(pipes.child_stdout), 1)
8648
+ os.dup2(check.not_none(pipes.child_stdout), 1)
8288
8649
 
8289
8650
  if self.config.redirect_stderr:
8290
- os.dup2(check_not_none(pipes.child_stdout), 2)
8651
+ os.dup2(check.not_none(pipes.child_stdout), 2)
8291
8652
  else:
8292
- os.dup2(check_not_none(pipes.child_stderr), 2)
8653
+ os.dup2(check.not_none(pipes.child_stderr), 2)
8293
8654
 
8294
8655
  for i in range(3, self._server_config.min_fds):
8295
8656
  if i in self._inherited_fds:
@@ -8405,7 +8766,7 @@ class Supervisor:
8405
8766
  if self._process_groups.get(config.name) is not None:
8406
8767
  return False
8407
8768
 
8408
- group = check_isinstance(self._process_group_factory(config), ProcessGroup)
8769
+ group = check.isinstance(self._process_group_factory(config), ProcessGroup)
8409
8770
  for process in group:
8410
8771
  process.after_setuid()
8411
8772