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.
- ominfra/clouds/aws/auth.py +7 -9
- ominfra/clouds/aws/cli.py +1 -1
- ominfra/clouds/aws/journald2aws/driver.py +4 -4
- ominfra/clouds/aws/logs.py +4 -5
- ominfra/clouds/gcp/auth.py +1 -1
- ominfra/configs.py +3 -4
- ominfra/journald/messages.py +3 -3
- ominfra/journald/tailer.py +2 -2
- ominfra/manage/commands/base.py +2 -2
- ominfra/manage/commands/interp.py +3 -3
- ominfra/manage/commands/subprocess.py +3 -4
- ominfra/manage/deploy/paths.py +12 -15
- ominfra/manage/main.py +72 -75
- ominfra/manage/remote/_main.py +6 -7
- ominfra/manage/remote/execution.py +7 -10
- ominfra/manage/remote/spawning.py +3 -3
- ominfra/scripts/journald2aws.py +508 -147
- ominfra/scripts/manage.py +772 -183
- ominfra/scripts/supervisor.py +1144 -783
- ominfra/supervisor/dispatchers.py +1 -1
- ominfra/supervisor/groupsimpl.py +2 -2
- ominfra/supervisor/http.py +7 -7
- ominfra/supervisor/inject.py +4 -4
- ominfra/supervisor/io.py +1 -1
- ominfra/supervisor/main.py +1 -1
- ominfra/supervisor/processimpl.py +2 -2
- ominfra/supervisor/spawningimpl.py +9 -10
- ominfra/supervisor/supervisor.py +3 -3
- ominfra/supervisor/types.py +1 -1
- ominfra/tailscale/cli.py +1 -1
- {ominfra-0.0.0.dev148.dist-info → ominfra-0.0.0.dev150.dist-info}/METADATA +3 -3
- {ominfra-0.0.0.dev148.dist-info → ominfra-0.0.0.dev150.dist-info}/RECORD +36 -36
- {ominfra-0.0.0.dev148.dist-info → ominfra-0.0.0.dev150.dist-info}/LICENSE +0 -0
- {ominfra-0.0.0.dev148.dist-info → ominfra-0.0.0.dev150.dist-info}/WHEEL +0 -0
- {ominfra-0.0.0.dev148.dist-info → ominfra-0.0.0.dev150.dist-info}/entry_points.txt +0 -0
- {ominfra-0.0.0.dev148.dist-info → ominfra-0.0.0.dev150.dist-info}/top_level.txt +0 -0
ominfra/scripts/supervisor.py
CHANGED
@@ -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/
|
144
|
+
# ../../omlish/http/handlers.py
|
139
145
|
HttpHandler = ta.Callable[['HttpHandlerRequest'], 'HttpHandlerResponse']
|
140
146
|
|
141
|
-
# ../../omlish/
|
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/
|
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
|
1575
|
-
|
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
|
-
|
1581
|
-
|
1582
|
-
|
1583
|
-
|
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/
|
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/
|
1798
|
-
|
1669
|
+
# ../../../omlish/lite/cached.py
|
1799
1670
|
|
1800
|
-
class HttpProtocolVersion(ta.NamedTuple):
|
1801
|
-
major: int
|
1802
|
-
minor: int
|
1803
1671
|
|
1804
|
-
|
1805
|
-
return f'HTTP/{self.major}.{self.minor}'
|
1672
|
+
##
|
1806
1673
|
|
1807
1674
|
|
1808
|
-
class
|
1809
|
-
|
1810
|
-
|
1811
|
-
|
1812
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
1829
|
-
|
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
|
-
|
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
|
-
|
1843
|
-
|
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/
|
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
|
-
|
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
|
-
|
1861
|
-
def
|
1862
|
-
|
1737
|
+
class Checks:
|
1738
|
+
def __init__(self) -> None:
|
1739
|
+
super().__init__()
|
1863
1740
|
|
1864
|
-
|
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
|
-
@
|
1867
|
-
def
|
1868
|
-
return
|
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
|
-
|
1872
|
-
|
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
|
1875
|
-
|
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
|
-
|
1878
|
-
def present(self) -> bool:
|
1879
|
-
return bool(self)
|
1761
|
+
#
|
1880
1762
|
|
1881
|
-
def
|
1882
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
1895
|
-
|
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
|
-
|
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
|
-
|
1908
|
-
|
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
|
-
|
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
|
-
|
1921
|
-
|
1922
|
-
|
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
|
-
|
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
|
1934
|
-
|
1935
|
-
|
1936
|
-
|
1937
|
-
|
1938
|
-
if
|
1939
|
-
|
1940
|
-
|
1941
|
-
|
1942
|
-
|
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
|
-
|
1947
|
-
|
1948
|
-
|
1949
|
-
|
1950
|
-
|
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/
|
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
|
-
|
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
|
-
|
3206
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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(
|
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 =
|
3668
|
-
self._p: ta.Optional[Injector] =
|
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
|
-
|
3700
|
-
|
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
|
-
|
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(
|
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
|
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
|
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(
|
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(
|
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 =
|
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 =
|
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
|
-
|
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
|
-
|
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/
|
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/
|
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 =
|
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
|
-
|
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 =
|
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 =
|
6373
|
+
parsed = check.isinstance(parsed, ParsedHttpRequest)
|
6013
6374
|
|
6014
6375
|
# Log
|
6015
6376
|
|
6016
|
-
|
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 =
|
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=
|
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/
|
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
|
-
|
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 =
|
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
|
-
|
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 =
|
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
|
-
|
6433
|
-
wb =
|
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
|
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 =
|
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 =
|
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 =
|
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(
|
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(
|
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(
|
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(
|
8646
|
+
os.dup2(check.not_none(pipes.child_stdin), 0)
|
8286
8647
|
|
8287
|
-
os.dup2(
|
8648
|
+
os.dup2(check.not_none(pipes.child_stdout), 1)
|
8288
8649
|
|
8289
8650
|
if self.config.redirect_stderr:
|
8290
|
-
os.dup2(
|
8651
|
+
os.dup2(check.not_none(pipes.child_stdout), 2)
|
8291
8652
|
else:
|
8292
|
-
os.dup2(
|
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 =
|
8769
|
+
group = check.isinstance(self._process_group_factory(config), ProcessGroup)
|
8409
8770
|
for process in group:
|
8410
8771
|
process.after_setuid()
|
8411
8772
|
|