ominfra 0.0.0.dev148__py3-none-any.whl → 0.0.0.dev149__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.
@@ -1431,160 +1431,7 @@ def parse_octal(arg: ta.Union[str, int]) -> int:
1431
1431
 
1432
1432
 
1433
1433
  ########################################
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
-
1498
-
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
-
1573
-
1574
- def check_empty(v: SizedT) -> SizedT:
1575
- if len(v):
1576
- raise ValueError(v)
1577
- return v
1578
-
1579
-
1580
- def check_non_empty(v: SizedT) -> SizedT:
1581
- if not len(v):
1582
- raise ValueError(v)
1583
- return v
1584
-
1585
-
1586
- ########################################
1587
- # ../../../omlish/lite/fdio/pollers.py
1434
+ # ../../../omlish/io/fdio/pollers.py
1588
1435
 
1589
1436
 
1590
1437
  ##
@@ -1794,91 +1641,249 @@ else:
1794
1641
 
1795
1642
 
1796
1643
  ########################################
1797
- # ../../../omlish/lite/http/versions.py
1798
-
1644
+ # ../../../omlish/lite/cached.py
1799
1645
 
1800
- class HttpProtocolVersion(ta.NamedTuple):
1801
- major: int
1802
- minor: int
1803
1646
 
1804
- def __str__(self) -> str:
1805
- return f'HTTP/{self.major}.{self.minor}'
1647
+ ##
1806
1648
 
1807
1649
 
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)
1650
+ class _AbstractCachedNullary:
1651
+ def __init__(self, fn):
1652
+ super().__init__()
1653
+ self._fn = fn
1654
+ self._value = self._missing = object()
1655
+ functools.update_wrapper(self, fn)
1813
1656
 
1657
+ def __call__(self, *args, **kwargs): # noqa
1658
+ raise TypeError
1814
1659
 
1815
- ########################################
1816
- # ../../../omlish/lite/json.py
1660
+ def __get__(self, instance, owner): # noqa
1661
+ bound = instance.__dict__[self._fn.__name__] = self.__class__(self._fn.__get__(instance, owner))
1662
+ return bound
1817
1663
 
1818
1664
 
1819
1665
  ##
1820
1666
 
1821
1667
 
1822
- JSON_PRETTY_INDENT = 2
1668
+ class _CachedNullary(_AbstractCachedNullary):
1669
+ def __call__(self, *args, **kwargs): # noqa
1670
+ if self._value is self._missing:
1671
+ self._value = self._fn()
1672
+ return self._value
1823
1673
 
1824
- JSON_PRETTY_KWARGS: ta.Mapping[str, ta.Any] = dict(
1825
- indent=JSON_PRETTY_INDENT,
1826
- )
1827
1674
 
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)
1675
+ def cached_nullary(fn): # ta.Callable[..., T]) -> ta.Callable[..., T]:
1676
+ return _CachedNullary(fn)
1677
+
1678
+
1679
+ def static_init(fn: CallableT) -> CallableT:
1680
+ fn = cached_nullary(fn)
1681
+ fn()
1682
+ return fn
1830
1683
 
1831
1684
 
1832
1685
  ##
1833
1686
 
1834
1687
 
1835
- JSON_COMPACT_SEPARATORS = (',', ':')
1688
+ class _AsyncCachedNullary(_AbstractCachedNullary):
1689
+ async def __call__(self, *args, **kwargs):
1690
+ if self._value is self._missing:
1691
+ self._value = await self._fn()
1692
+ return self._value
1836
1693
 
1837
- JSON_COMPACT_KWARGS: ta.Mapping[str, ta.Any] = dict(
1838
- indent=None,
1839
- separators=JSON_COMPACT_SEPARATORS,
1840
- )
1841
1694
 
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)
1695
+ def async_cached_nullary(fn): # ta.Callable[..., T]) -> ta.Callable[..., T]:
1696
+ return _AsyncCachedNullary(fn)
1844
1697
 
1845
1698
 
1846
1699
  ########################################
1847
- # ../../../omlish/lite/maybes.py
1700
+ # ../../../omlish/lite/check.py
1848
1701
 
1849
1702
 
1850
- class Maybe(ta.Generic[T]):
1851
- @property
1852
- @abc.abstractmethod
1853
- def present(self) -> bool:
1854
- raise NotImplementedError
1703
+ def check_isinstance(v: ta.Any, spec: ta.Union[ta.Type[T], tuple]) -> T:
1704
+ if not isinstance(v, spec):
1705
+ raise TypeError(v)
1706
+ return v
1855
1707
 
1856
- @abc.abstractmethod
1857
- def must(self) -> T:
1858
- raise NotImplementedError
1859
1708
 
1860
- @classmethod
1861
- def just(cls, v: T) -> 'Maybe[T]':
1862
- return tuple.__new__(_Maybe, (v,)) # noqa
1709
+ def check_not_isinstance(v: T, spec: ta.Union[type, tuple]) -> T:
1710
+ if isinstance(v, spec):
1711
+ raise TypeError(v)
1712
+ return v
1863
1713
 
1864
- _empty: ta.ClassVar['Maybe']
1865
1714
 
1866
- @classmethod
1867
- def empty(cls) -> 'Maybe[T]':
1868
- return Maybe._empty
1715
+ def check_none(v: T) -> None:
1716
+ if v is not None:
1717
+ raise ValueError(v)
1869
1718
 
1870
1719
 
1871
- class _Maybe(Maybe[T], tuple):
1872
- __slots__ = ()
1720
+ def check_not_none(v: ta.Optional[T]) -> T:
1721
+ if v is None:
1722
+ raise ValueError
1723
+ return v
1873
1724
 
1874
- def __init_subclass__(cls, **kwargs):
1875
- raise TypeError
1876
1725
 
1877
- @property
1878
- def present(self) -> bool:
1879
- return bool(self)
1726
+ def check_not(v: ta.Any) -> None:
1727
+ if v:
1728
+ raise ValueError(v)
1729
+ return v
1880
1730
 
1881
- def must(self) -> T:
1731
+
1732
+ def check_non_empty_str(v: ta.Optional[str]) -> str:
1733
+ if not v:
1734
+ raise ValueError
1735
+ return v
1736
+
1737
+
1738
+ def check_arg(v: bool, msg: str = 'Illegal argument') -> None:
1739
+ if not v:
1740
+ raise ValueError(msg)
1741
+
1742
+
1743
+ def check_state(v: bool, msg: str = 'Illegal state') -> None:
1744
+ if not v:
1745
+ raise ValueError(msg)
1746
+
1747
+
1748
+ def check_equal(l: T, r: T) -> T:
1749
+ if l != r:
1750
+ raise ValueError(l, r)
1751
+ return l
1752
+
1753
+
1754
+ def check_not_equal(l: T, r: T) -> T:
1755
+ if l == r:
1756
+ raise ValueError(l, r)
1757
+ return l
1758
+
1759
+
1760
+ def check_is(l: T, r: T) -> T:
1761
+ if l is not r:
1762
+ raise ValueError(l, r)
1763
+ return l
1764
+
1765
+
1766
+ def check_is_not(l: T, r: ta.Any) -> T:
1767
+ if l is r:
1768
+ raise ValueError(l, r)
1769
+ return l
1770
+
1771
+
1772
+ def check_in(v: T, c: ta.Container[T]) -> T:
1773
+ if v not in c:
1774
+ raise ValueError(v, c)
1775
+ return v
1776
+
1777
+
1778
+ def check_not_in(v: T, c: ta.Container[T]) -> T:
1779
+ if v in c:
1780
+ raise ValueError(v, c)
1781
+ return v
1782
+
1783
+
1784
+ def check_single(vs: ta.Iterable[T]) -> T:
1785
+ [v] = vs
1786
+ return v
1787
+
1788
+
1789
+ def check_empty(v: SizedT) -> SizedT:
1790
+ if len(v):
1791
+ raise ValueError(v)
1792
+ return v
1793
+
1794
+
1795
+ def check_not_empty(v: SizedT) -> SizedT:
1796
+ if not len(v):
1797
+ raise ValueError(v)
1798
+ return v
1799
+
1800
+
1801
+ ########################################
1802
+ # ../../../omlish/lite/http/versions.py
1803
+
1804
+
1805
+ class HttpProtocolVersion(ta.NamedTuple):
1806
+ major: int
1807
+ minor: int
1808
+
1809
+ def __str__(self) -> str:
1810
+ return f'HTTP/{self.major}.{self.minor}'
1811
+
1812
+
1813
+ class HttpProtocolVersions:
1814
+ HTTP_0_9 = HttpProtocolVersion(0, 9)
1815
+ HTTP_1_0 = HttpProtocolVersion(1, 0)
1816
+ HTTP_1_1 = HttpProtocolVersion(1, 1)
1817
+ HTTP_2_0 = HttpProtocolVersion(2, 0)
1818
+
1819
+
1820
+ ########################################
1821
+ # ../../../omlish/lite/json.py
1822
+
1823
+
1824
+ ##
1825
+
1826
+
1827
+ JSON_PRETTY_INDENT = 2
1828
+
1829
+ JSON_PRETTY_KWARGS: ta.Mapping[str, ta.Any] = dict(
1830
+ indent=JSON_PRETTY_INDENT,
1831
+ )
1832
+
1833
+ json_dump_pretty: ta.Callable[..., bytes] = functools.partial(json.dump, **JSON_PRETTY_KWARGS) # type: ignore
1834
+ json_dumps_pretty: ta.Callable[..., str] = functools.partial(json.dumps, **JSON_PRETTY_KWARGS)
1835
+
1836
+
1837
+ ##
1838
+
1839
+
1840
+ JSON_COMPACT_SEPARATORS = (',', ':')
1841
+
1842
+ JSON_COMPACT_KWARGS: ta.Mapping[str, ta.Any] = dict(
1843
+ indent=None,
1844
+ separators=JSON_COMPACT_SEPARATORS,
1845
+ )
1846
+
1847
+ json_dump_compact: ta.Callable[..., bytes] = functools.partial(json.dump, **JSON_COMPACT_KWARGS) # type: ignore
1848
+ json_dumps_compact: ta.Callable[..., str] = functools.partial(json.dumps, **JSON_COMPACT_KWARGS)
1849
+
1850
+
1851
+ ########################################
1852
+ # ../../../omlish/lite/maybes.py
1853
+
1854
+
1855
+ class Maybe(ta.Generic[T]):
1856
+ @property
1857
+ @abc.abstractmethod
1858
+ def present(self) -> bool:
1859
+ raise NotImplementedError
1860
+
1861
+ @abc.abstractmethod
1862
+ def must(self) -> T:
1863
+ raise NotImplementedError
1864
+
1865
+ @classmethod
1866
+ def just(cls, v: T) -> 'Maybe[T]':
1867
+ return tuple.__new__(_Maybe, (v,)) # noqa
1868
+
1869
+ _empty: ta.ClassVar['Maybe']
1870
+
1871
+ @classmethod
1872
+ def empty(cls) -> 'Maybe[T]':
1873
+ return Maybe._empty
1874
+
1875
+
1876
+ class _Maybe(Maybe[T], tuple):
1877
+ __slots__ = ()
1878
+
1879
+ def __init_subclass__(cls, **kwargs):
1880
+ raise TypeError
1881
+
1882
+ @property
1883
+ def present(self) -> bool:
1884
+ return bool(self)
1885
+
1886
+ def must(self) -> T:
1882
1887
  if not self:
1883
1888
  raise ValueError
1884
1889
  return self[0]
@@ -2564,65 +2569,229 @@ def get_user(name: str) -> User:
2564
2569
 
2565
2570
 
2566
2571
  ########################################
2567
- # ../../../omlish/lite/contextmanagers.py
2572
+ # ../../../omlish/io/buffers.py
2568
2573
 
2569
2574
 
2570
- ##
2575
+ class DelimitingBuffer:
2576
+ """
2577
+ https://github.com/python-trio/trio/issues/796 :|
2578
+ """
2571
2579
 
2580
+ #
2572
2581
 
2573
- class ExitStacked:
2574
- _exit_stack: ta.Optional[contextlib.ExitStack] = None
2582
+ class Error(Exception):
2583
+ def __init__(self, buffer: 'DelimitingBuffer') -> None:
2584
+ super().__init__(buffer)
2585
+ self.buffer = buffer
2575
2586
 
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
2587
+ def __repr__(self) -> str:
2588
+ return attr_repr(self, 'buffer')
2581
2589
 
2582
- def __exit__(self, exc_type, exc_val, exc_tb):
2583
- if (es := self._exit_stack) is None:
2590
+ class ClosedError(Error):
2591
+ pass
2592
+
2593
+ #
2594
+
2595
+ DEFAULT_DELIMITERS: bytes = b'\n'
2596
+
2597
+ def __init__(
2598
+ self,
2599
+ delimiters: ta.Iterable[int] = DEFAULT_DELIMITERS,
2600
+ *,
2601
+ keep_ends: bool = False,
2602
+ max_size: ta.Optional[int] = None,
2603
+ ) -> None:
2604
+ super().__init__()
2605
+
2606
+ self._delimiters = frozenset(check_isinstance(d, int) for d in delimiters)
2607
+ self._keep_ends = keep_ends
2608
+ self._max_size = max_size
2609
+
2610
+ self._buf: ta.Optional[io.BytesIO] = io.BytesIO()
2611
+
2612
+ #
2613
+
2614
+ @property
2615
+ def is_closed(self) -> bool:
2616
+ return self._buf is None
2617
+
2618
+ def tell(self) -> int:
2619
+ if (buf := self._buf) is None:
2620
+ raise self.ClosedError(self)
2621
+ return buf.tell()
2622
+
2623
+ def peek(self) -> bytes:
2624
+ if (buf := self._buf) is None:
2625
+ raise self.ClosedError(self)
2626
+ return buf.getvalue()
2627
+
2628
+ def _find_delim(self, data: ta.Union[bytes, bytearray], i: int) -> ta.Optional[int]:
2629
+ r = None # type: int | None
2630
+ for d in self._delimiters:
2631
+ if (p := data.find(d, i)) >= 0:
2632
+ if r is None or p < r:
2633
+ r = p
2634
+ return r
2635
+
2636
+ def _append_and_reset(self, chunk: bytes) -> bytes:
2637
+ buf = check_not_none(self._buf)
2638
+ if not buf.tell():
2639
+ return chunk
2640
+
2641
+ buf.write(chunk)
2642
+ ret = buf.getvalue()
2643
+ buf.seek(0)
2644
+ buf.truncate()
2645
+ return ret
2646
+
2647
+ class Incomplete(ta.NamedTuple):
2648
+ b: bytes
2649
+
2650
+ def feed(self, data: ta.Union[bytes, bytearray]) -> ta.Generator[ta.Union[bytes, Incomplete], None, None]:
2651
+ if (buf := self._buf) is None:
2652
+ raise self.ClosedError(self)
2653
+
2654
+ if not data:
2655
+ self._buf = None
2656
+
2657
+ if buf.tell():
2658
+ yield self.Incomplete(buf.getvalue())
2659
+
2660
+ return
2661
+
2662
+ l = len(data)
2663
+ i = 0
2664
+ while i < l:
2665
+ if (p := self._find_delim(data, i)) is None:
2666
+ break
2667
+
2668
+ n = p + 1
2669
+ if self._keep_ends:
2670
+ p = n
2671
+
2672
+ yield self._append_and_reset(data[i:p])
2673
+
2674
+ i = n
2675
+
2676
+ if i >= l:
2677
+ return
2678
+
2679
+ if self._max_size is None:
2680
+ buf.write(data[i:])
2681
+ return
2682
+
2683
+ while i < l:
2684
+ remaining_data_len = l - i
2685
+ remaining_buf_capacity = self._max_size - buf.tell()
2686
+
2687
+ if remaining_data_len < remaining_buf_capacity:
2688
+ buf.write(data[i:])
2689
+ return
2690
+
2691
+ p = i + remaining_buf_capacity
2692
+ yield self.Incomplete(self._append_and_reset(data[i:p]))
2693
+ i = p
2694
+
2695
+
2696
+ class ReadableListBuffer:
2697
+ def __init__(self) -> None:
2698
+ super().__init__()
2699
+ self._lst: list[bytes] = []
2700
+
2701
+ def feed(self, d: bytes) -> None:
2702
+ if d:
2703
+ self._lst.append(d)
2704
+
2705
+ def _chop(self, i: int, e: int) -> bytes:
2706
+ lst = self._lst
2707
+ d = lst[i]
2708
+
2709
+ o = b''.join([
2710
+ *lst[:i],
2711
+ d[:e],
2712
+ ])
2713
+
2714
+ self._lst = [
2715
+ *([d[e:]] if e < len(d) else []),
2716
+ *lst[i + 1:],
2717
+ ]
2718
+
2719
+ return o
2720
+
2721
+ def read(self, n: ta.Optional[int] = None) -> ta.Optional[bytes]:
2722
+ if n is None:
2723
+ o = b''.join(self._lst)
2724
+ self._lst = []
2725
+ return o
2726
+
2727
+ if not (lst := self._lst):
2584
2728
  return None
2585
- self._exit_contexts()
2586
- return es.__exit__(exc_type, exc_val, exc_tb)
2587
2729
 
2588
- def _exit_contexts(self) -> None:
2589
- pass
2730
+ c = 0
2731
+ for i, d in enumerate(lst):
2732
+ r = n - c
2733
+ if (l := len(d)) >= r:
2734
+ return self._chop(i, r)
2735
+ c += l
2590
2736
 
2591
- def _enter_context(self, cm: ta.ContextManager[T]) -> T:
2592
- es = check_not_none(self._exit_stack)
2593
- return es.enter_context(cm)
2737
+ return None
2594
2738
 
2739
+ def read_until(self, delim: bytes = b'\n') -> ta.Optional[bytes]:
2740
+ if not (lst := self._lst):
2741
+ return None
2595
2742
 
2596
- ##
2743
+ for i, d in enumerate(lst):
2744
+ if (p := d.find(delim)) >= 0:
2745
+ return self._chop(i, p + len(delim))
2597
2746
 
2747
+ return None
2598
2748
 
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
2749
 
2750
+ class IncrementalWriteBuffer:
2751
+ def __init__(
2752
+ self,
2753
+ data: bytes,
2754
+ *,
2755
+ write_size: int = 0x10000,
2756
+ ) -> None:
2757
+ super().__init__()
2606
2758
 
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)
2759
+ check_not_empty(data)
2760
+ self._len = len(data)
2761
+ self._write_size = write_size
2762
+
2763
+ self._lst = [
2764
+ data[i:i + write_size]
2765
+ for i in range(0, len(data), write_size)
2766
+ ]
2767
+ self._pos = 0
2768
+
2769
+ @property
2770
+ def rem(self) -> int:
2771
+ return self._len - self._pos
2772
+
2773
+ def write(self, fn: ta.Callable[[bytes], int]) -> int:
2774
+ lst = check_not_empty(self._lst)
2775
+
2776
+ t = 0
2777
+ for i, d in enumerate(lst): # noqa
2778
+ n = fn(check_not_empty(d))
2779
+ if not n:
2780
+ break
2781
+ t += n
2782
+
2783
+ if t:
2784
+ self._lst = [
2785
+ *([d[n:]] if n < len(d) else []),
2786
+ *lst[i + 1:],
2787
+ ]
2788
+ self._pos += t
2789
+
2790
+ return t
2622
2791
 
2623
2792
 
2624
2793
  ########################################
2625
- # ../../../omlish/lite/fdio/handlers.py
2794
+ # ../../../omlish/io/fdio/handlers.py
2626
2795
 
2627
2796
 
2628
2797
  class FdioHandler(abc.ABC):
@@ -2686,7 +2855,7 @@ class SocketFdioHandler(FdioHandler, abc.ABC):
2686
2855
 
2687
2856
 
2688
2857
  ########################################
2689
- # ../../../omlish/lite/fdio/kqueue.py
2858
+ # ../../../omlish/io/fdio/kqueue.py
2690
2859
 
2691
2860
 
2692
2861
  KqueueFdioPoller: ta.Optional[ta.Type[FdioPoller]]
@@ -2785,25 +2954,83 @@ if sys.platform == 'darwin' or sys.platform.startswith('freebsd'):
2785
2954
  try:
2786
2955
  kes = kq.control(None, self._max_events, timeout)
2787
2956
 
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
2957
+ except OSError as exc:
2958
+ if exc.errno == errno.EINTR:
2959
+ return FdioPoller.PollResult(msg='EINTR encountered in poll', exc=exc)
2960
+ else:
2961
+ raise
2962
+
2963
+ r: ta.List[int] = []
2964
+ w: ta.List[int] = []
2965
+ for ke in kes:
2966
+ if ke.filter == select.KQ_FILTER_READ:
2967
+ r.append(ke.ident)
2968
+ if ke.filter == select.KQ_FILTER_WRITE:
2969
+ w.append(ke.ident)
2970
+
2971
+ return FdioPoller.PollResult(r, w)
2972
+
2973
+ KqueueFdioPoller = _KqueueFdioPoller
2974
+ else:
2975
+ KqueueFdioPoller = None
2976
+
2977
+
2978
+ ########################################
2979
+ # ../../../omlish/lite/contextmanagers.py
2980
+
2981
+
2982
+ ##
2983
+
2984
+
2985
+ class ExitStacked:
2986
+ _exit_stack: ta.Optional[contextlib.ExitStack] = None
2987
+
2988
+ def __enter__(self: ExitStackedT) -> ExitStackedT:
2989
+ check_state(self._exit_stack is None)
2990
+ es = self._exit_stack = contextlib.ExitStack()
2991
+ es.__enter__()
2992
+ return self
2993
+
2994
+ def __exit__(self, exc_type, exc_val, exc_tb):
2995
+ if (es := self._exit_stack) is None:
2996
+ return None
2997
+ self._exit_contexts()
2998
+ return es.__exit__(exc_type, exc_val, exc_tb)
2999
+
3000
+ def _exit_contexts(self) -> None:
3001
+ pass
3002
+
3003
+ def _enter_context(self, cm: ta.ContextManager[T]) -> T:
3004
+ es = check_not_none(self._exit_stack)
3005
+ return es.enter_context(cm)
3006
+
3007
+
3008
+ ##
3009
+
2793
3010
 
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)
3011
+ @contextlib.contextmanager
3012
+ def defer(fn: ta.Callable) -> ta.Generator[ta.Callable, None, None]:
3013
+ try:
3014
+ yield fn
3015
+ finally:
3016
+ fn()
2801
3017
 
2802
- return FdioPoller.PollResult(r, w)
2803
3018
 
2804
- KqueueFdioPoller = _KqueueFdioPoller
2805
- else:
2806
- KqueueFdioPoller = None
3019
+ @contextlib.contextmanager
3020
+ def attr_setting(obj, attr, val, *, default=None): # noqa
3021
+ not_set = object()
3022
+ orig = getattr(obj, attr, not_set)
3023
+ try:
3024
+ setattr(obj, attr, val)
3025
+ if orig is not not_set:
3026
+ yield orig
3027
+ else:
3028
+ yield default
3029
+ finally:
3030
+ if orig is not_set:
3031
+ delattr(obj, attr)
3032
+ else:
3033
+ setattr(obj, attr, orig)
2807
3034
 
2808
3035
 
2809
3036
  ########################################
@@ -4099,228 +4326,6 @@ class Injection:
4099
4326
  inj = Injection
4100
4327
 
4101
4328
 
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
4329
  ########################################
4325
4330
  # ../../../omlish/lite/journald.py
4326
4331
 
@@ -6321,7 +6326,7 @@ class ProcessGroup(
6321
6326
 
6322
6327
 
6323
6328
  ########################################
6324
- # ../../../omlish/lite/fdio/corohttp.py
6329
+ # ../../../omlish/io/fdio/corohttp.py
6325
6330
 
6326
6331
 
6327
6332
  class CoroHttpServerConnectionFdioHandler(SocketFdioHandler):