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

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