ominfra 0.0.0.dev148__py3-none-any.whl → 0.0.0.dev149__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -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):