omlish 0.0.0.dev133__py3-none-any.whl → 0.0.0.dev177__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (210) hide show
  1. omlish/.manifests.json +265 -7
  2. omlish/__about__.py +5 -3
  3. omlish/antlr/_runtime/__init__.py +0 -22
  4. omlish/antlr/_runtime/_all.py +24 -0
  5. omlish/antlr/_runtime/atn/ParserATNSimulator.py +1 -1
  6. omlish/antlr/_runtime/dfa/DFASerializer.py +1 -1
  7. omlish/antlr/_runtime/error/DiagnosticErrorListener.py +2 -1
  8. omlish/antlr/_runtime/xpath/XPath.py +7 -1
  9. omlish/antlr/_runtime/xpath/XPathLexer.py +1 -1
  10. omlish/antlr/delimit.py +106 -0
  11. omlish/antlr/dot.py +31 -0
  12. omlish/antlr/errors.py +11 -0
  13. omlish/antlr/input.py +96 -0
  14. omlish/antlr/parsing.py +19 -0
  15. omlish/antlr/runtime.py +102 -0
  16. omlish/antlr/utils.py +38 -0
  17. omlish/argparse/all.py +45 -0
  18. omlish/{argparse.py → argparse/cli.py} +112 -107
  19. omlish/asyncs/__init__.py +0 -35
  20. omlish/asyncs/all.py +35 -0
  21. omlish/asyncs/asyncio/all.py +7 -0
  22. omlish/asyncs/asyncio/channels.py +40 -0
  23. omlish/asyncs/asyncio/streams.py +45 -0
  24. omlish/asyncs/asyncio/subprocesses.py +238 -0
  25. omlish/asyncs/asyncio/timeouts.py +16 -0
  26. omlish/asyncs/bluelet/LICENSE +6 -0
  27. omlish/asyncs/bluelet/all.py +67 -0
  28. omlish/asyncs/bluelet/api.py +23 -0
  29. omlish/asyncs/bluelet/core.py +178 -0
  30. omlish/asyncs/bluelet/events.py +78 -0
  31. omlish/asyncs/bluelet/files.py +80 -0
  32. omlish/asyncs/bluelet/runner.py +416 -0
  33. omlish/asyncs/bluelet/sockets.py +214 -0
  34. omlish/bootstrap/sys.py +3 -3
  35. omlish/cached.py +2 -2
  36. omlish/check.py +49 -460
  37. omlish/codecs/__init__.py +72 -0
  38. omlish/codecs/base.py +106 -0
  39. omlish/codecs/bytes.py +119 -0
  40. omlish/codecs/chain.py +23 -0
  41. omlish/codecs/funcs.py +39 -0
  42. omlish/codecs/registry.py +139 -0
  43. omlish/codecs/standard.py +4 -0
  44. omlish/codecs/text.py +217 -0
  45. omlish/collections/cache/impl.py +50 -57
  46. omlish/collections/coerce.py +1 -0
  47. omlish/collections/mappings.py +1 -1
  48. omlish/configs/flattening.py +1 -1
  49. omlish/defs.py +1 -1
  50. omlish/diag/_pycharm/runhack.py +8 -2
  51. omlish/diag/procfs.py +8 -8
  52. omlish/docker/__init__.py +0 -36
  53. omlish/docker/all.py +31 -0
  54. omlish/docker/consts.py +4 -0
  55. omlish/{lite/docker.py → docker/detect.py} +18 -0
  56. omlish/docker/{helpers.py → timebomb.py} +0 -21
  57. omlish/formats/cbor.py +31 -0
  58. omlish/formats/cloudpickle.py +31 -0
  59. omlish/formats/codecs.py +93 -0
  60. omlish/formats/json/codecs.py +29 -0
  61. omlish/formats/json/delimted.py +4 -0
  62. omlish/formats/json/stream/errors.py +2 -0
  63. omlish/formats/json/stream/lex.py +12 -6
  64. omlish/formats/json/stream/parse.py +38 -22
  65. omlish/formats/json5.py +31 -0
  66. omlish/formats/pickle.py +31 -0
  67. omlish/formats/repr.py +25 -0
  68. omlish/formats/toml.py +17 -0
  69. omlish/formats/yaml.py +25 -0
  70. omlish/funcs/__init__.py +0 -0
  71. omlish/{genmachine.py → funcs/genmachine.py} +5 -4
  72. omlish/{matchfns.py → funcs/match.py} +1 -1
  73. omlish/funcs/pairs.py +215 -0
  74. omlish/http/__init__.py +0 -48
  75. omlish/http/all.py +48 -0
  76. omlish/http/coro/__init__.py +0 -0
  77. omlish/{lite/fdio/corohttp.py → http/coro/fdio.py} +21 -19
  78. omlish/{lite/http/coroserver.py → http/coro/server.py} +20 -21
  79. omlish/{lite/http → http}/handlers.py +3 -2
  80. omlish/{lite/http → http}/parsing.py +1 -0
  81. omlish/http/sessions.py +1 -1
  82. omlish/{lite/http → http}/versions.py +1 -0
  83. omlish/inject/managed.py +2 -2
  84. omlish/io/__init__.py +0 -3
  85. omlish/{lite/io.py → io/buffers.py} +8 -9
  86. omlish/io/compress/__init__.py +9 -0
  87. omlish/io/compress/abc.py +104 -0
  88. omlish/io/compress/adapters.py +148 -0
  89. omlish/io/compress/base.py +24 -0
  90. omlish/io/compress/brotli.py +47 -0
  91. omlish/io/compress/bz2.py +61 -0
  92. omlish/io/compress/codecs.py +78 -0
  93. omlish/io/compress/gzip.py +350 -0
  94. omlish/io/compress/lz4.py +91 -0
  95. omlish/io/compress/lzma.py +81 -0
  96. omlish/io/compress/snappy.py +34 -0
  97. omlish/io/compress/zlib.py +74 -0
  98. omlish/io/compress/zstd.py +44 -0
  99. omlish/io/fdio/__init__.py +1 -0
  100. omlish/{lite → io}/fdio/handlers.py +5 -5
  101. omlish/{lite → io}/fdio/kqueue.py +8 -8
  102. omlish/{lite → io}/fdio/manager.py +7 -7
  103. omlish/{lite → io}/fdio/pollers.py +13 -13
  104. omlish/io/generators/__init__.py +56 -0
  105. omlish/io/generators/consts.py +1 -0
  106. omlish/io/generators/direct.py +13 -0
  107. omlish/io/generators/readers.py +189 -0
  108. omlish/io/generators/stepped.py +191 -0
  109. omlish/io/pyio.py +5 -2
  110. omlish/iterators/__init__.py +24 -0
  111. omlish/iterators/iterators.py +132 -0
  112. omlish/iterators/recipes.py +18 -0
  113. omlish/iterators/tools.py +96 -0
  114. omlish/iterators/unique.py +67 -0
  115. omlish/lang/__init__.py +13 -1
  116. omlish/lang/functions.py +11 -2
  117. omlish/lang/generators.py +243 -0
  118. omlish/lang/iterables.py +46 -49
  119. omlish/lang/maybes.py +4 -4
  120. omlish/lite/cached.py +39 -6
  121. omlish/lite/check.py +438 -75
  122. omlish/lite/contextmanagers.py +17 -4
  123. omlish/lite/dataclasses.py +42 -0
  124. omlish/lite/inject.py +28 -45
  125. omlish/lite/logs.py +0 -270
  126. omlish/lite/marshal.py +309 -144
  127. omlish/lite/pycharm.py +47 -0
  128. omlish/lite/reflect.py +33 -0
  129. omlish/lite/resources.py +8 -0
  130. omlish/lite/runtime.py +4 -4
  131. omlish/lite/shlex.py +12 -0
  132. omlish/lite/socketserver.py +2 -2
  133. omlish/lite/strings.py +31 -0
  134. omlish/logs/__init__.py +0 -32
  135. omlish/logs/{_abc.py → abc.py} +0 -1
  136. omlish/logs/all.py +37 -0
  137. omlish/logs/{formatters.py → color.py} +1 -2
  138. omlish/logs/configs.py +7 -38
  139. omlish/logs/filters.py +10 -0
  140. omlish/logs/handlers.py +4 -1
  141. omlish/logs/json.py +56 -0
  142. omlish/logs/proxy.py +99 -0
  143. omlish/logs/standard.py +128 -0
  144. omlish/logs/utils.py +2 -2
  145. omlish/manifests/__init__.py +2 -0
  146. omlish/manifests/load.py +209 -0
  147. omlish/manifests/types.py +17 -0
  148. omlish/marshal/base.py +1 -1
  149. omlish/marshal/factories.py +1 -1
  150. omlish/marshal/forbidden.py +1 -1
  151. omlish/marshal/iterables.py +1 -1
  152. omlish/marshal/literals.py +50 -0
  153. omlish/marshal/mappings.py +1 -1
  154. omlish/marshal/maybes.py +1 -1
  155. omlish/marshal/standard.py +5 -1
  156. omlish/marshal/unions.py +1 -1
  157. omlish/os/__init__.py +0 -0
  158. omlish/os/atomics.py +205 -0
  159. omlish/os/deathsig.py +23 -0
  160. omlish/{os.py → os/files.py} +0 -9
  161. omlish/{lite → os}/journald.py +2 -1
  162. omlish/os/linux.py +484 -0
  163. omlish/os/paths.py +36 -0
  164. omlish/{lite → os}/pidfile.py +1 -0
  165. omlish/os/sizes.py +9 -0
  166. omlish/reflect/__init__.py +3 -0
  167. omlish/reflect/subst.py +2 -1
  168. omlish/reflect/types.py +126 -44
  169. omlish/secrets/pwhash.py +1 -1
  170. omlish/secrets/subprocesses.py +3 -1
  171. omlish/specs/jsonrpc/marshal.py +1 -1
  172. omlish/specs/openapi/marshal.py +1 -1
  173. omlish/sql/alchemy/asyncs.py +1 -1
  174. omlish/sql/queries/__init__.py +9 -1
  175. omlish/sql/queries/building.py +3 -0
  176. omlish/sql/queries/exprs.py +10 -27
  177. omlish/sql/queries/idents.py +48 -10
  178. omlish/sql/queries/names.py +80 -13
  179. omlish/sql/queries/params.py +64 -0
  180. omlish/sql/queries/rendering.py +1 -1
  181. omlish/subprocesses.py +340 -0
  182. omlish/term.py +29 -14
  183. omlish/testing/pytest/marks.py +2 -2
  184. omlish/testing/pytest/plugins/asyncs.py +6 -1
  185. omlish/testing/pytest/plugins/logging.py +1 -1
  186. omlish/testing/pytest/plugins/switches.py +1 -1
  187. {omlish-0.0.0.dev133.dist-info → omlish-0.0.0.dev177.dist-info}/METADATA +7 -5
  188. {omlish-0.0.0.dev133.dist-info → omlish-0.0.0.dev177.dist-info}/RECORD +200 -117
  189. omlish/fnpairs.py +0 -496
  190. omlish/formats/json/cli/__main__.py +0 -11
  191. omlish/formats/json/cli/cli.py +0 -298
  192. omlish/formats/json/cli/formats.py +0 -71
  193. omlish/formats/json/cli/io.py +0 -74
  194. omlish/formats/json/cli/parsing.py +0 -82
  195. omlish/formats/json/cli/processing.py +0 -48
  196. omlish/formats/json/cli/rendering.py +0 -92
  197. omlish/iterators.py +0 -300
  198. omlish/lite/subprocesses.py +0 -130
  199. /omlish/{formats/json/cli → argparse}/__init__.py +0 -0
  200. /omlish/{lite/fdio → asyncs/asyncio}/__init__.py +0 -0
  201. /omlish/asyncs/{asyncio.py → asyncio/asyncio.py} +0 -0
  202. /omlish/{lite/http → asyncs/bluelet}/__init__.py +0 -0
  203. /omlish/collections/{_abc.py → abc.py} +0 -0
  204. /omlish/{fnpipes.py → funcs/pipes.py} +0 -0
  205. /omlish/io/{_abc.py → abc.py} +0 -0
  206. /omlish/sql/{_abc.py → abc.py} +0 -0
  207. {omlish-0.0.0.dev133.dist-info → omlish-0.0.0.dev177.dist-info}/LICENSE +0 -0
  208. {omlish-0.0.0.dev133.dist-info → omlish-0.0.0.dev177.dist-info}/WHEEL +0 -0
  209. {omlish-0.0.0.dev133.dist-info → omlish-0.0.0.dev177.dist-info}/entry_points.txt +0 -0
  210. {omlish-0.0.0.dev133.dist-info → omlish-0.0.0.dev177.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,74 @@
1
+ import dataclasses as dc
2
+ import functools
3
+ import typing as ta
4
+
5
+ from ... import lang
6
+ from ..generators import BytesSteppedGenerator
7
+ from ..generators import BytesSteppedReaderGenerator
8
+ from .adapters import CompressorObjectIncrementalAdapter
9
+ from .adapters import DecompressorObjectIncrementalAdapter
10
+ from .base import Compression
11
+ from .base import IncrementalCompression
12
+ from .codecs import make_compression_codec
13
+ from .codecs import make_compression_lazy_loaded_codec
14
+
15
+
16
+ if ta.TYPE_CHECKING:
17
+ import zlib
18
+ else:
19
+ zlib = lang.proxy_import('zlib')
20
+
21
+
22
+ ##
23
+
24
+
25
+ @dc.dataclass(frozen=True, kw_only=True)
26
+ class ZlibCompression(Compression, IncrementalCompression):
27
+ level: int = 9
28
+
29
+ wbits: int | None = None
30
+ strategy: int | None = None
31
+ zdict: bytes | None = None
32
+
33
+ def compress(self, d: bytes) -> bytes:
34
+ return zlib.compress(
35
+ d,
36
+ self.level,
37
+ **(dict(wbits=self.wbits) if self.wbits is not None else {}),
38
+ )
39
+
40
+ def decompress(self, d: bytes) -> bytes:
41
+ return zlib.decompress(
42
+ d,
43
+ **(dict(wbits=self.wbits) if self.wbits is not None else {}),
44
+ )
45
+
46
+ def compress_incremental(self) -> BytesSteppedGenerator[None]:
47
+ return lang.nextgen(CompressorObjectIncrementalAdapter(
48
+ functools.partial(
49
+ zlib.compressobj, # type: ignore
50
+ self.level,
51
+ **(dict(wbits=self.wbits) if self.wbits is not None else {}), # type: ignore[arg-type]
52
+ **(dict(strategy=self.strategy) if self.strategy is not None else {}), # type: ignore[arg-type]
53
+ **(dict(zdict=self.zdict) if self.zdict is not None else {}), # type: ignore[arg-type]
54
+ ),
55
+ )())
56
+
57
+ def decompress_incremental(self) -> BytesSteppedReaderGenerator[None]:
58
+ return DecompressorObjectIncrementalAdapter(
59
+ functools.partial( # type: ignore
60
+ zlib.decompressobj,
61
+ **(dict(wbits=self.wbits) if self.wbits is not None else {}), # type: ignore[arg-type]
62
+ **(dict(zdict=self.zdict) if self.zdict is not None else {}), # type: ignore[arg-type]
63
+ ),
64
+ trailing_error=OSError,
65
+ )()
66
+
67
+
68
+ ##
69
+
70
+
71
+ ZLIB_CODEC = make_compression_codec('zlib', ZlibCompression)
72
+
73
+ # @omlish-manifest
74
+ _ZLIB_LAZY_CODEC = make_compression_lazy_loaded_codec(__name__, 'ZLIB_CODEC', ZLIB_CODEC)
@@ -0,0 +1,44 @@
1
+ import dataclasses as dc
2
+ import typing as ta
3
+
4
+ from ... import lang
5
+ from .base import Compression
6
+ from .codecs import make_compression_codec
7
+ from .codecs import make_compression_lazy_loaded_codec
8
+
9
+
10
+ if ta.TYPE_CHECKING:
11
+ import zstandard
12
+ else:
13
+ zstandard = lang.proxy_import('zstandard')
14
+
15
+
16
+ ##
17
+
18
+
19
+ @dc.dataclass(frozen=True, kw_only=True)
20
+ class ZstdCompression(Compression):
21
+ level: int | None = None
22
+
23
+ max_output_size: int = 0
24
+
25
+ def compress(self, d: bytes) -> bytes:
26
+ return zstandard.compress(
27
+ d,
28
+ **(dict(level=self.level) if self.level is not None else {}),
29
+ )
30
+
31
+ def decompress(self, d: bytes) -> bytes:
32
+ return zstandard.decompress(
33
+ d,
34
+ max_output_size=self.max_output_size,
35
+ )
36
+
37
+
38
+ ##
39
+
40
+
41
+ ZSTD_CODEC = make_compression_codec('zstd', ZstdCompression)
42
+
43
+ # @omlish-manifest
44
+ _ZSTD_LAZY_CODEC = make_compression_lazy_loaded_codec(__name__, 'ZSTD_CODEC', ZSTD_CODEC)
@@ -0,0 +1 @@
1
+ # @omlish-lite
@@ -3,11 +3,11 @@ import abc
3
3
  import socket
4
4
  import typing as ta
5
5
 
6
- from ..check import check_not_none
7
- from ..socket import SocketAddress
6
+ from ...lite.check import check
7
+ from ...lite.socket import SocketAddress
8
8
 
9
9
 
10
- class FdIoHandler(abc.ABC):
10
+ class FdioHandler(abc.ABC):
11
11
  @abc.abstractmethod
12
12
  def fd(self) -> int:
13
13
  raise NotImplementedError
@@ -43,7 +43,7 @@ class FdIoHandler(abc.ABC):
43
43
  pass
44
44
 
45
45
 
46
- class SocketFdIoHandler(FdIoHandler, abc.ABC):
46
+ class SocketFdioHandler(FdioHandler, abc.ABC):
47
47
  def __init__(
48
48
  self,
49
49
  addr: SocketAddress,
@@ -55,7 +55,7 @@ class SocketFdIoHandler(FdIoHandler, abc.ABC):
55
55
  self._sock: ta.Optional[socket.socket] = sock
56
56
 
57
57
  def fd(self) -> int:
58
- return check_not_none(self._sock).fileno()
58
+ return check.not_none(self._sock).fileno()
59
59
 
60
60
  @property
61
61
  def closed(self) -> bool:
@@ -4,13 +4,13 @@ import select
4
4
  import sys
5
5
  import typing as ta
6
6
 
7
- from .pollers import FdIoPoller
7
+ from .pollers import FdioPoller
8
8
 
9
9
 
10
- KqueueFdIoPoller: ta.Optional[ta.Type[FdIoPoller]]
10
+ KqueueFdioPoller: ta.Optional[ta.Type[FdioPoller]]
11
11
  if sys.platform == 'darwin' or sys.platform.startswith('freebsd'):
12
12
 
13
- class _KqueueFdIoPoller(FdIoPoller):
13
+ class _KqueueFdioPoller(FdioPoller):
14
14
  DEFAULT_MAX_EVENTS = 1000
15
15
 
16
16
  def __init__(
@@ -98,14 +98,14 @@ if sys.platform == 'darwin' or sys.platform.startswith('freebsd'):
98
98
 
99
99
  #
100
100
 
101
- def poll(self, timeout: ta.Optional[float]) -> FdIoPoller.PollResult:
101
+ def poll(self, timeout: ta.Optional[float]) -> FdioPoller.PollResult:
102
102
  kq = self._get_kqueue()
103
103
  try:
104
104
  kes = kq.control(None, self._max_events, timeout)
105
105
 
106
106
  except OSError as exc:
107
107
  if exc.errno == errno.EINTR:
108
- return FdIoPoller.PollResult(msg='EINTR encountered in poll', exc=exc)
108
+ return FdioPoller.PollResult(msg='EINTR encountered in poll', exc=exc)
109
109
  else:
110
110
  raise
111
111
 
@@ -117,8 +117,8 @@ if sys.platform == 'darwin' or sys.platform.startswith('freebsd'):
117
117
  if ke.filter == select.KQ_FILTER_WRITE:
118
118
  w.append(ke.ident)
119
119
 
120
- return FdIoPoller.PollResult(r, w)
120
+ return FdioPoller.PollResult(r, w)
121
121
 
122
- KqueueFdIoPoller = _KqueueFdIoPoller
122
+ KqueueFdioPoller = _KqueueFdioPoller
123
123
  else:
124
- KqueueFdIoPoller = None
124
+ KqueueFdioPoller = None
@@ -1,27 +1,27 @@
1
1
  # ruff: noqa: UP006 UP007
2
2
  import typing as ta
3
3
 
4
- from .handlers import FdIoHandler
5
- from .pollers import FdIoPoller
4
+ from .handlers import FdioHandler
5
+ from .pollers import FdioPoller
6
6
 
7
7
 
8
- class FdIoManager:
8
+ class FdioManager:
9
9
  def __init__(
10
10
  self,
11
- poller: FdIoPoller,
11
+ poller: FdioPoller,
12
12
  ) -> None:
13
13
  super().__init__()
14
14
 
15
15
  self._poller = poller
16
16
 
17
- self._handlers: ta.Dict[int, FdIoHandler] = {} # Preserves insertion order
17
+ self._handlers: ta.Dict[int, FdioHandler] = {} # Preserves insertion order
18
18
 
19
- def register(self, h: FdIoHandler) -> None:
19
+ def register(self, h: FdioHandler) -> None:
20
20
  if (hid := id(h)) in self._handlers:
21
21
  raise KeyError(h)
22
22
  self._handlers[hid] = h
23
23
 
24
- def unregister(self, h: FdIoHandler) -> None:
24
+ def unregister(self, h: FdioHandler) -> None:
25
25
  del self._handlers[id(h)]
26
26
 
27
27
  def poll(self, *, timeout: float = 1.) -> None:
@@ -9,7 +9,7 @@ import typing as ta
9
9
  ##
10
10
 
11
11
 
12
- class FdIoPoller(abc.ABC):
12
+ class FdioPoller(abc.ABC):
13
13
  def __init__(self) -> None:
14
14
  super().__init__()
15
15
 
@@ -120,8 +120,8 @@ class FdIoPoller(abc.ABC):
120
120
  ##
121
121
 
122
122
 
123
- class SelectFdIoPoller(FdIoPoller):
124
- def poll(self, timeout: ta.Optional[float]) -> FdIoPoller.PollResult:
123
+ class SelectFdioPoller(FdioPoller):
124
+ def poll(self, timeout: ta.Optional[float]) -> FdioPoller.PollResult:
125
125
  try:
126
126
  r, w, x = select.select(
127
127
  self._readable,
@@ -132,22 +132,22 @@ class SelectFdIoPoller(FdIoPoller):
132
132
 
133
133
  except OSError as exc:
134
134
  if exc.errno == errno.EINTR:
135
- return FdIoPoller.PollResult(msg='EINTR encountered in poll', exc=exc)
135
+ return FdioPoller.PollResult(msg='EINTR encountered in poll', exc=exc)
136
136
  elif exc.errno == errno.EBADF:
137
- return FdIoPoller.PollResult(msg='EBADF encountered in poll', exc=exc)
137
+ return FdioPoller.PollResult(msg='EBADF encountered in poll', exc=exc)
138
138
  else:
139
139
  raise
140
140
 
141
- return FdIoPoller.PollResult(r, w)
141
+ return FdioPoller.PollResult(r, w)
142
142
 
143
143
 
144
144
  ##
145
145
 
146
146
 
147
- PollFdIoPoller: ta.Optional[ta.Type[FdIoPoller]]
147
+ PollFdioPoller: ta.Optional[ta.Type[FdioPoller]]
148
148
  if hasattr(select, 'poll'):
149
149
 
150
- class _PollFdIoPoller(FdIoPoller):
150
+ class _PollFdioPoller(FdioPoller):
151
151
  def __init__(self) -> None:
152
152
  super().__init__()
153
153
 
@@ -180,14 +180,14 @@ if hasattr(select, 'poll'):
180
180
 
181
181
  #
182
182
 
183
- def poll(self, timeout: ta.Optional[float]) -> FdIoPoller.PollResult:
183
+ def poll(self, timeout: ta.Optional[float]) -> FdioPoller.PollResult:
184
184
  polled: ta.List[ta.Tuple[int, int]]
185
185
  try:
186
186
  polled = self._poller.poll(timeout * 1000 if timeout is not None else None)
187
187
 
188
188
  except OSError as exc:
189
189
  if exc.errno == errno.EINTR:
190
- return FdIoPoller.PollResult(msg='EINTR encountered in poll', exc=exc)
190
+ return FdioPoller.PollResult(msg='EINTR encountered in poll', exc=exc)
191
191
  else:
192
192
  raise
193
193
 
@@ -205,8 +205,8 @@ if hasattr(select, 'poll'):
205
205
  r.append(fd)
206
206
  if mask & self._WRITE:
207
207
  w.append(fd)
208
- return FdIoPoller.PollResult(r, w, inv=inv)
208
+ return FdioPoller.PollResult(r, w, inv=inv)
209
209
 
210
- PollFdIoPoller = _PollFdIoPoller
210
+ PollFdioPoller = _PollFdioPoller
211
211
  else:
212
- PollFdIoPoller = None
212
+ PollFdioPoller = None
@@ -0,0 +1,56 @@
1
+ from .consts import ( # noqa
2
+ DEFAULT_BUFFER_SIZE,
3
+ )
4
+
5
+ from .direct import ( # noqa
6
+ DirectGenerator,
7
+
8
+ BytesDirectGenerator,
9
+ StrDirectGenerator,
10
+ )
11
+
12
+ from .readers import ( # noqa
13
+ ReaderGenerator,
14
+ BytesReaderGenerator,
15
+ StrReaderGenerator,
16
+
17
+ ExactReaderGenerator,
18
+ BytesExactReaderGenerator,
19
+ StrExactReaderGenerator,
20
+
21
+ GeneratorReader,
22
+
23
+ PrependableGeneratorReader,
24
+ PrependableBytesGeneratorReader,
25
+ PrependableStrGeneratorReader,
26
+ prependable_bytes_generator_reader,
27
+ prependable_str_generator_reader,
28
+
29
+ BufferedGeneratorReader,
30
+ BufferedBytesGeneratorReader,
31
+ BufferedStrGeneratorReader,
32
+ buffered_bytes_generator_reader,
33
+ buffered_str_generator_reader,
34
+ )
35
+
36
+ from .stepped import ( # noqa
37
+ SteppedGenerator,
38
+ BytesSteppedGenerator,
39
+ StrSteppedGenerator,
40
+ BytesToStrSteppedGenerator,
41
+ StrToBytesSteppedGenerator,
42
+
43
+ SteppedReaderGenerator,
44
+ BytesSteppedReaderGenerator,
45
+ StrSteppedReaderGenerator,
46
+
47
+ flatmap_stepped_generator,
48
+
49
+ joined_bytes_stepped_generator,
50
+ joined_str_stepped_generator,
51
+
52
+ read_into_bytes_stepped_generator,
53
+ read_into_str_stepped_generator,
54
+
55
+ buffer_bytes_stepped_reader_generator,
56
+ )
@@ -0,0 +1 @@
1
+ DEFAULT_BUFFER_SIZE = 4 * 0x1000
@@ -0,0 +1,13 @@
1
+ import typing as ta
2
+
3
+
4
+ O = ta.TypeVar('O')
5
+ I = ta.TypeVar('I')
6
+ R = ta.TypeVar('R')
7
+
8
+
9
+ # Direct generators yield outputs 1:1 with inputs.
10
+ DirectGenerator: ta.TypeAlias = ta.Generator[O, I, R]
11
+
12
+ BytesDirectGenerator: ta.TypeAlias = DirectGenerator[bytes, bytes, R]
13
+ StrDirectGenerator: ta.TypeAlias = DirectGenerator[str, str, R]
@@ -0,0 +1,189 @@
1
+ """
2
+ TODO:
3
+ - BufferedBytesGeneratorReader
4
+ - docstrings
5
+ - memoryviews
6
+ """
7
+ import abc
8
+ import typing as ta
9
+
10
+ from ... import check
11
+ from .consts import DEFAULT_BUFFER_SIZE
12
+
13
+
14
+ T = ta.TypeVar('T')
15
+
16
+ O = ta.TypeVar('O')
17
+ I = ta.TypeVar('I')
18
+ R = ta.TypeVar('R')
19
+
20
+ AnyT = ta.TypeVar('AnyT', bound=ta.Any)
21
+
22
+
23
+ # Reader generators yield ints of amounts of data needed, or None for needing any amount of data.
24
+ ReaderGenerator: ta.TypeAlias = ta.Generator[int | None, I, R]
25
+
26
+ BytesReaderGenerator: ta.TypeAlias = ReaderGenerator[bytes, R]
27
+ StrReaderGenerator: ta.TypeAlias = ReaderGenerator[str, R]
28
+
29
+
30
+ # Exact reader generators always specify read sizes.
31
+ ExactReaderGenerator: ta.TypeAlias = ta.Generator[int, I, R]
32
+
33
+ BytesExactReaderGenerator: ta.TypeAlias = ExactReaderGenerator[bytes, R]
34
+ StrExactReaderGenerator: ta.TypeAlias = ExactReaderGenerator[str, R]
35
+
36
+
37
+ ##
38
+
39
+
40
+ class _BytesJoiner:
41
+ def _join(self, lst: list[bytes]) -> bytes:
42
+ return b''.join(lst)
43
+
44
+
45
+ class _StrJoiner:
46
+ def _join(self, lst: list[str]) -> str:
47
+ return ''.join(lst)
48
+
49
+
50
+ ##
51
+
52
+
53
+ class GeneratorReader(abc.ABC, ta.Generic[T]):
54
+ @abc.abstractmethod
55
+ def read(self, sz: int | None) -> ReaderGenerator[T, T]:
56
+ raise NotImplementedError
57
+
58
+ def read_exact(self, sz: int) -> ReaderGenerator[T, T]:
59
+ d: ta.Any = yield from self.read(sz)
60
+ if len(d) != sz:
61
+ raise EOFError(f'GeneratorReader got {len(d)}, expected {sz}')
62
+ return d
63
+
64
+
65
+ ##
66
+
67
+
68
+ class PrependableGeneratorReader(GeneratorReader[AnyT]):
69
+ def __init__(self) -> None:
70
+ super().__init__()
71
+
72
+ self._queue: list[tuple[AnyT, int]] = []
73
+
74
+ @abc.abstractmethod
75
+ def _join(self, lst: list[AnyT]) -> AnyT:
76
+ raise NotImplementedError
77
+
78
+ def read(self, sz: int | None) -> ReaderGenerator[AnyT, AnyT]:
79
+ if not self._queue:
80
+ d: AnyT = check.not_none((yield sz))
81
+ return d
82
+
83
+ if sz is None:
84
+ return self._queue.pop(0)[0]
85
+
86
+ lst: list[AnyT] = []
87
+ rem = sz
88
+ while rem > 0 and self._queue:
89
+ c, p = self._queue[0]
90
+
91
+ if len(c) - p > rem:
92
+ lst.append(c[p:p + rem])
93
+ self._queue[0] = (c, p + rem)
94
+ return self._join(lst)
95
+
96
+ lst.append(c[p:])
97
+ rem -= len(c) - p
98
+ self._queue.pop(0)
99
+
100
+ if rem:
101
+ d = check.not_none((yield rem))
102
+ if d:
103
+ lst.append(d) # type: ignore[unreachable]
104
+
105
+ if len(lst) == 1:
106
+ return lst[0]
107
+ else:
108
+ return self._join(lst)
109
+
110
+ def prepend(self, d: AnyT, p: int | None = None) -> None:
111
+ if d:
112
+ self._queue.insert(0, (d, p or 0))
113
+
114
+
115
+ class PrependableBytesGeneratorReader(
116
+ _BytesJoiner,
117
+ PrependableGeneratorReader[bytes],
118
+ ):
119
+ pass
120
+
121
+
122
+ class PrependableStrGeneratorReader(
123
+ _StrJoiner,
124
+ PrependableGeneratorReader[str],
125
+ ):
126
+ pass
127
+
128
+
129
+ prependable_bytes_generator_reader = PrependableBytesGeneratorReader
130
+ prependable_str_generator_reader = PrependableStrGeneratorReader
131
+
132
+
133
+ ##
134
+
135
+
136
+ class BufferedGeneratorReader(PrependableGeneratorReader[AnyT], abc.ABC):
137
+ def __init__(
138
+ self,
139
+ buffer_size: int = DEFAULT_BUFFER_SIZE,
140
+ ) -> None:
141
+ check.arg(buffer_size > 0)
142
+
143
+ super().__init__()
144
+
145
+ self._buffer_size = buffer_size
146
+
147
+ def read(self, sz: int | None) -> ReaderGenerator[AnyT, AnyT]:
148
+ g = super().read(sz)
149
+ i: ta.Any = None
150
+ while True:
151
+ try:
152
+ q = g.send(i)
153
+ except StopIteration as e:
154
+ return e.value
155
+
156
+ check.state(not self._queue)
157
+
158
+ if q is None:
159
+ i = check.not_none((yield None))
160
+ continue
161
+
162
+ r = max(q, self._buffer_size)
163
+ d: AnyT = check.not_none((yield r))
164
+ if len(d) < q:
165
+ i = d
166
+ continue
167
+
168
+ i = d[:q]
169
+ self.prepend(d, q)
170
+
171
+
172
+ class BufferedBytesGeneratorReader(
173
+ _BytesJoiner,
174
+ BufferedGeneratorReader[bytes],
175
+ PrependableGeneratorReader[bytes],
176
+ ):
177
+ pass
178
+
179
+
180
+ class BufferedStrGeneratorReader(
181
+ _StrJoiner,
182
+ BufferedGeneratorReader[str],
183
+ PrependableGeneratorReader[str],
184
+ ):
185
+ pass
186
+
187
+
188
+ buffered_bytes_generator_reader = BufferedBytesGeneratorReader
189
+ buffered_str_generator_reader = BufferedStrGeneratorReader