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
@@ -1,19 +1,18 @@
1
+ # ruff: noqa: UP006 UP007
2
+ # @omlish-lite
1
3
  import socket
2
4
  import typing as ta
3
5
 
4
- from ..check import check_isinstance
5
- from ..check import check_none
6
- from ..check import check_not_none
7
- from ..check import check_state
8
- from ..http.coroserver import CoroHttpServer
9
- from ..http.handlers import HttpHandler
10
- from ..io import IncrementalWriteBuffer
11
- from ..io import ReadableListBuffer
12
- from ..socket import SocketAddress
13
- from .handlers import SocketFdIoHandler
6
+ from ...io.buffers import IncrementalWriteBuffer
7
+ from ...io.buffers import ReadableListBuffer
8
+ from ...io.fdio.handlers import SocketFdioHandler
9
+ from ...lite.check import check
10
+ from ...lite.socket import SocketAddress
11
+ from ..handlers import HttpHandler
12
+ from .server import CoroHttpServer
14
13
 
15
14
 
16
- class CoroHttpServerConnectionFdIoHandler(SocketFdIoHandler):
15
+ class CoroHttpServerConnectionFdioHandler(SocketFdioHandler):
17
16
  def __init__(
18
17
  self,
19
18
  addr: SocketAddress,
@@ -22,14 +21,16 @@ class CoroHttpServerConnectionFdIoHandler(SocketFdIoHandler):
22
21
  *,
23
22
  read_size: int = 0x10000,
24
23
  write_size: int = 0x10000,
24
+ log_handler: ta.Optional[ta.Callable[[CoroHttpServer, CoroHttpServer.AnyLogIo], None]] = None,
25
25
  ) -> None:
26
- check_state(not sock.getblocking())
26
+ check.state(not sock.getblocking())
27
27
 
28
28
  super().__init__(addr, sock)
29
29
 
30
30
  self._handler = handler
31
31
  self._read_size = read_size
32
32
  self._write_size = write_size
33
+ self._log_handler = log_handler
33
34
 
34
35
  self._read_buf = ReadableListBuffer()
35
36
  self._write_buf: IncrementalWriteBuffer | None = None
@@ -46,7 +47,7 @@ class CoroHttpServerConnectionFdIoHandler(SocketFdIoHandler):
46
47
  #
47
48
 
48
49
  def _next_io(self) -> None: # noqa
49
- coro = check_not_none(self._srv_coro)
50
+ coro = check.not_none(self._srv_coro)
50
51
 
51
52
  d: bytes | None = None
52
53
  o = self._cur_io
@@ -64,7 +65,8 @@ class CoroHttpServerConnectionFdIoHandler(SocketFdIoHandler):
64
65
  break
65
66
 
66
67
  if isinstance(o, CoroHttpServer.AnyLogIo):
67
- print(o)
68
+ if self._log_handler is not None:
69
+ self._log_handler(self._coro_srv, o)
68
70
  o = None
69
71
 
70
72
  elif isinstance(o, CoroHttpServer.ReadIo):
@@ -78,7 +80,7 @@ class CoroHttpServerConnectionFdIoHandler(SocketFdIoHandler):
78
80
  o = None
79
81
 
80
82
  elif isinstance(o, CoroHttpServer.WriteIo):
81
- check_none(self._write_buf)
83
+ check.none(self._write_buf)
82
84
  self._write_buf = IncrementalWriteBuffer(o.data, write_size=self._write_size)
83
85
  break
84
86
 
@@ -99,7 +101,7 @@ class CoroHttpServerConnectionFdIoHandler(SocketFdIoHandler):
99
101
 
100
102
  def on_readable(self) -> None:
101
103
  try:
102
- buf = check_not_none(self._sock).recv(self._read_size)
104
+ buf = check.not_none(self._sock).recv(self._read_size)
103
105
  except BlockingIOError:
104
106
  return
105
107
  except ConnectionResetError:
@@ -115,12 +117,12 @@ class CoroHttpServerConnectionFdIoHandler(SocketFdIoHandler):
115
117
  self._next_io()
116
118
 
117
119
  def on_writable(self) -> None:
118
- check_isinstance(self._cur_io, CoroHttpServer.WriteIo)
119
- wb = check_not_none(self._write_buf)
120
+ check.isinstance(self._cur_io, CoroHttpServer.WriteIo)
121
+ wb = check.not_none(self._write_buf)
120
122
  while wb.rem > 0:
121
123
  def send(d: bytes) -> int:
122
124
  try:
123
- return check_not_none(self._sock).send(d)
125
+ return check.not_none(self._sock).send(d)
124
126
  except ConnectionResetError:
125
127
  self.close()
126
128
  return 0
@@ -1,4 +1,5 @@
1
1
  # ruff: noqa: UP006 UP007
2
+ # @omlish-lite
2
3
  # PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
3
4
  # --------------------------------------------
4
5
  #
@@ -62,20 +63,18 @@ import textwrap
62
63
  import time
63
64
  import typing as ta
64
65
 
65
- from ..check import check_isinstance
66
- from ..check import check_none
67
- from ..check import check_not_none
68
- from ..socket import SocketAddress
69
- from ..socket import SocketHandler
70
- from .handlers import HttpHandler
71
- from .handlers import HttpHandlerRequest
72
- from .handlers import UnsupportedMethodHttpHandlerError
73
- from .parsing import EmptyParsedHttpResult
74
- from .parsing import HttpRequestParser
75
- from .parsing import ParsedHttpRequest
76
- from .parsing import ParseHttpRequestError
77
- from .versions import HttpProtocolVersion
78
- from .versions import HttpProtocolVersions
66
+ from ...lite.check import check
67
+ from ...lite.socket import SocketAddress
68
+ from ...lite.socket import SocketHandler
69
+ from ..handlers import HttpHandler
70
+ from ..handlers import HttpHandlerRequest
71
+ from ..handlers import UnsupportedMethodHttpHandlerError
72
+ from ..parsing import EmptyParsedHttpResult
73
+ from ..parsing import HttpRequestParser
74
+ from ..parsing import ParsedHttpRequest
75
+ from ..parsing import ParseHttpRequestError
76
+ from ..versions import HttpProtocolVersion
77
+ from ..versions import HttpProtocolVersions
79
78
 
80
79
 
81
80
  CoroHttpServerFactory = ta.Callable[[SocketAddress], 'CoroHttpServer']
@@ -406,13 +405,13 @@ class CoroHttpServer:
406
405
  yield o
407
406
 
408
407
  elif isinstance(o, self.AnyReadIo):
409
- i = check_isinstance((yield o), bytes)
408
+ i = check.isinstance((yield o), bytes)
410
409
 
411
410
  elif isinstance(o, self._Response):
412
411
  i = None
413
412
  r = self._preprocess_response(o)
414
413
  b = self._build_response_bytes(r)
415
- check_none((yield self.WriteIo(b)))
414
+ check.none((yield self.WriteIo(b)))
416
415
 
417
416
  else:
418
417
  raise TypeError(o)
@@ -435,7 +434,7 @@ class CoroHttpServer:
435
434
  sz = next(gen)
436
435
  while True:
437
436
  try:
438
- line = check_isinstance((yield self.ReadLineIo(sz)), bytes)
437
+ line = check.isinstance((yield self.ReadLineIo(sz)), bytes)
439
438
  sz = gen.send(line)
440
439
  except StopIteration as e:
441
440
  parsed = e.value
@@ -454,11 +453,11 @@ class CoroHttpServer:
454
453
  yield self._build_error_response(err)
455
454
  return
456
455
 
457
- parsed = check_isinstance(parsed, ParsedHttpRequest)
456
+ parsed = check.isinstance(parsed, ParsedHttpRequest)
458
457
 
459
458
  # Log
460
459
 
461
- check_none((yield self.ParsedRequestLogIo(parsed)))
460
+ check.none((yield self.ParsedRequestLogIo(parsed)))
462
461
 
463
462
  # Handle CONTINUE
464
463
 
@@ -474,7 +473,7 @@ class CoroHttpServer:
474
473
 
475
474
  request_data: ta.Optional[bytes]
476
475
  if (cl := parsed.headers.get('Content-Length')) is not None:
477
- request_data = check_isinstance((yield self.ReadIo(int(cl))), bytes)
476
+ request_data = check.isinstance((yield self.ReadIo(int(cl))), bytes)
478
477
  else:
479
478
  request_data = None
480
479
 
@@ -482,7 +481,7 @@ class CoroHttpServer:
482
481
 
483
482
  handler_request = HttpHandlerRequest(
484
483
  client_address=self._client_address,
485
- method=check_not_none(parsed.method),
484
+ method=check.not_none(parsed.method),
486
485
  path=parsed.path,
487
486
  headers=parsed.headers,
488
487
  data=request_data,
@@ -1,13 +1,14 @@
1
1
  # ruff: noqa: UP006 UP007
2
+ # @omlish-lite
2
3
  import dataclasses as dc
3
4
  import http.server
4
5
  import typing as ta
5
6
 
6
- from ..socket import SocketAddress
7
+ from ..lite.socket import SocketAddress
7
8
  from .parsing import HttpHeaders
8
9
 
9
10
 
10
- HttpHandler = ta.Callable[['HttpHandlerRequest'], 'HttpHandlerResponse']
11
+ HttpHandler = ta.Callable[['HttpHandlerRequest'], 'HttpHandlerResponse'] # ta.TypeAlias
11
12
 
12
13
 
13
14
  @dc.dataclass(frozen=True)
@@ -1,4 +1,5 @@
1
1
  # ruff: noqa: UP006 UP007
2
+ # @omlish-lite
2
3
  # PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
3
4
  # --------------------------------------------
4
5
  #
omlish/http/sessions.py CHANGED
@@ -8,9 +8,9 @@ import time
8
8
  import typing as ta
9
9
  import zlib
10
10
 
11
- from .. import fnpairs as fpa
12
11
  from .. import lang
13
12
  from .. import secrets as sec
13
+ from ..funcs import pairs as fpa
14
14
  from .cookies import dump_cookie
15
15
  from .cookies import parse_cookie
16
16
  from .json import JSON_TAGGER
@@ -1,4 +1,5 @@
1
1
  # ruff: noqa: UP006 UP007
2
+ # @omlish-lite
2
3
  import typing as ta
3
4
 
4
5
 
omlish/inject/managed.py CHANGED
@@ -14,9 +14,9 @@ from .injector import create_injector
14
14
 
15
15
 
16
16
  if ta.TYPE_CHECKING:
17
- from .. import asyncs as _asyncs
17
+ from ..asyncs import all as _asyncs
18
18
  else:
19
- _asyncs = lang.proxy_import('..asyncs', __package__)
19
+ _asyncs = lang.proxy_import('..asyncs.all', __package__)
20
20
 
21
21
 
22
22
  T = ta.TypeVar('T')
omlish/io/__init__.py CHANGED
@@ -1,3 +0,0 @@
1
- from ..lite.io import ( # noqa
2
- DelimitingBuffer,
3
- )
@@ -1,11 +1,10 @@
1
1
  # ruff: noqa: UP007
2
+ # @omlish-lite
2
3
  import io
3
4
  import typing as ta
4
5
 
5
- from .check import check_isinstance
6
- from .check import check_non_empty
7
- from .check import check_not_none
8
- from .strings import attr_repr
6
+ from ..lite.check import check
7
+ from ..lite.strings import attr_repr
9
8
 
10
9
 
11
10
  class DelimitingBuffer:
@@ -39,7 +38,7 @@ class DelimitingBuffer:
39
38
  ) -> None:
40
39
  super().__init__()
41
40
 
42
- self._delimiters = frozenset(check_isinstance(d, int) for d in delimiters)
41
+ self._delimiters = frozenset(check.isinstance(d, int) for d in delimiters)
43
42
  self._keep_ends = keep_ends
44
43
  self._max_size = max_size
45
44
 
@@ -70,7 +69,7 @@ class DelimitingBuffer:
70
69
  return r
71
70
 
72
71
  def _append_and_reset(self, chunk: bytes) -> bytes:
73
- buf = check_not_none(self._buf)
72
+ buf = check.not_none(self._buf)
74
73
  if not buf.tell():
75
74
  return chunk
76
75
 
@@ -192,7 +191,7 @@ class IncrementalWriteBuffer:
192
191
  ) -> None:
193
192
  super().__init__()
194
193
 
195
- check_non_empty(data)
194
+ check.not_empty(data)
196
195
  self._len = len(data)
197
196
  self._write_size = write_size
198
197
 
@@ -207,11 +206,11 @@ class IncrementalWriteBuffer:
207
206
  return self._len - self._pos
208
207
 
209
208
  def write(self, fn: ta.Callable[[bytes], int]) -> int:
210
- lst = check_non_empty(self._lst)
209
+ lst = check.not_empty(self._lst)
211
210
 
212
211
  t = 0
213
212
  for i, d in enumerate(lst): # noqa
214
- n = fn(check_non_empty(d))
213
+ n = fn(check.not_empty(d))
215
214
  if not n:
216
215
  break
217
216
  t += n
@@ -0,0 +1,9 @@
1
+ """
2
+ TODO:
3
+ - zipfile?
4
+ - tarfile?
5
+ - lzf?
6
+ - blosc?
7
+ - python-lzo?
8
+ - zfp -> fp8?
9
+ """
@@ -0,0 +1,104 @@
1
+ """
2
+ https://docs.python.org/3/library/bz2.html#bz2.BZ2Compressor
3
+ https://docs.python.org/3/library/zlib.html#zlib.decompressobj
4
+ https://docs.python.org/3/library/lzma.html#lzma.LZMADecompressor
5
+ """
6
+ import abc
7
+
8
+
9
+ ##
10
+
11
+
12
+ class CompressorObject(abc.ABC):
13
+ @abc.abstractmethod
14
+ def compress(self, data: bytes) -> bytes:
15
+ """
16
+ Provide data to the compressor object. Returns a chunk of compressed data if possible, or an empty byte string
17
+ otherwise.
18
+
19
+ When you have finished providing data to the compressor, call the flush() method to finish the compression
20
+ process.
21
+ """
22
+
23
+ raise NotImplementedError
24
+
25
+ @abc.abstractmethod
26
+ def flush(self) -> bytes:
27
+ """
28
+ Finish the compression process. Returns the compressed data left in internal buffers.
29
+
30
+ The compressor object may not be used after this method has been called.
31
+ """
32
+
33
+ raise NotImplementedError
34
+
35
+
36
+ ##
37
+
38
+
39
+ class DecompressorObject(abc.ABC):
40
+ @property
41
+ @abc.abstractmethod
42
+ def unused_data(self) -> bytes:
43
+ """
44
+ Data found after the end of the compressed stream.
45
+
46
+ If this attribute is accessed before the end of the stream has been reached, its value will be b''.
47
+ """
48
+
49
+ raise NotImplementedError
50
+
51
+ @property
52
+ @abc.abstractmethod
53
+ def eof(self) -> bool:
54
+ """True if the end-of-stream marker has been reached."""
55
+
56
+ raise NotImplementedError
57
+
58
+ @abc.abstractmethod
59
+ def decompress(self, data: bytes, *max_length: int) -> bytes:
60
+ """
61
+ Decompress data, returning a bytes object containing the uncompressed data corresponding to at least part of the
62
+ data in string. This data should be concatenated to the output produced by any preceding calls to the
63
+ decompress() method. Some of the input data may be preserved in internal buffers for later processing.
64
+
65
+ If the optional parameter max_length is non-zero then the return value will be no longer than max_length.
66
+ """
67
+
68
+ raise NotImplementedError
69
+
70
+
71
+ class NeedsInputDecompressorObject(DecompressorObject):
72
+ """
73
+ Used by:
74
+ - bz2.BZ2Decompressor
75
+ - lzma.LZMADecompressor
76
+ """
77
+
78
+ @property
79
+ @abc.abstractmethod
80
+ def needs_input(self) -> bool:
81
+ """
82
+ False if the decompress() method can provide more decompressed data before requiring new uncompressed input.
83
+ """
84
+
85
+ raise NotImplementedError
86
+
87
+
88
+ class UnconsumedTailDecompressorObject(DecompressorObject):
89
+ """
90
+ Used by:
91
+ - zlib.decompressobj
92
+ """
93
+
94
+ @property
95
+ @abc.abstractmethod
96
+ def unconsumed_tail(self) -> bytes:
97
+ """
98
+ A bytes object that contains any data that was not consumed by the last decompress() call because it exceeded
99
+ the limit for the uncompressed data buffer. This data has not yet been seen by the zlib machinery, so you must
100
+ feed it (possibly with further data concatenated to it) back to a subsequent decompress() method call in order
101
+ to get correct output.
102
+ """
103
+
104
+ raise NotImplementedError
@@ -0,0 +1,148 @@
1
+ # PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
2
+ # --------------------------------------------
3
+ #
4
+ # 1. This LICENSE AGREEMENT is between the Python Software Foundation ("PSF"), and the Individual or Organization
5
+ # ("Licensee") accessing and otherwise using this software ("Python") in source or binary form and its associated
6
+ # documentation.
7
+ #
8
+ # 2. Subject to the terms and conditions of this License Agreement, PSF hereby grants Licensee a nonexclusive,
9
+ # royalty-free, world-wide license to reproduce, analyze, test, perform and/or display publicly, prepare derivative
10
+ # works, distribute, and otherwise use Python alone or in any derivative version, provided, however, that PSF's License
11
+ # Agreement and PSF's notice of copyright, i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
12
+ # 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 Python Software Foundation; All Rights Reserved" are retained in Python
13
+ # alone or in any derivative version prepared by Licensee.
14
+ #
15
+ # 3. In the event Licensee prepares a derivative work that is based on or incorporates Python or any part thereof, and
16
+ # wants to make the derivative work available to others as provided herein, then Licensee hereby agrees to include in
17
+ # any such work a brief summary of the changes made to Python.
18
+ #
19
+ # 4. PSF is making Python available to Licensee on an "AS IS" basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES,
20
+ # EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION OR WARRANTY
21
+ # OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT INFRINGE ANY THIRD PARTY
22
+ # RIGHTS.
23
+ #
24
+ # 5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL
25
+ # DAMAGES OR LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, OR ANY DERIVATIVE THEREOF, EVEN IF
26
+ # ADVISED OF THE POSSIBILITY THEREOF.
27
+ #
28
+ # 6. This License Agreement will automatically terminate upon a material breach of its terms and conditions.
29
+ #
30
+ # 7. Nothing in this License Agreement shall be deemed to create any relationship of agency, partnership, or joint
31
+ # venture between PSF and Licensee. This License Agreement does not grant permission to use PSF trademarks or trade
32
+ # name in a trademark sense to endorse or promote products or services of Licensee, or any third party.
33
+ #
34
+ # 8. By copying, installing or otherwise using Python, Licensee agrees to be bound by the terms and conditions of this
35
+ # License Agreement.
36
+ # ~> https://github.com/python/cpython/blob/f19c50a4817ffebb26132182ed8cec6a72342cc0/Lib/_compression.py
37
+ import typing as ta
38
+
39
+ from ... import check
40
+ from ..generators import BytesSteppedGenerator
41
+ from ..generators import BytesSteppedReaderGenerator
42
+ from .abc import CompressorObject
43
+ from .abc import NeedsInputDecompressorObject
44
+ from .abc import UnconsumedTailDecompressorObject
45
+
46
+
47
+ ##
48
+
49
+
50
+ class CompressorObjectIncrementalAdapter:
51
+ def __init__(
52
+ self,
53
+ factory: ta.Callable[..., CompressorObject],
54
+ ) -> None:
55
+ super().__init__()
56
+
57
+ self._factory = factory
58
+
59
+ def __call__(self) -> BytesSteppedGenerator:
60
+ compressor = self._factory()
61
+
62
+ while True:
63
+ data = check.isinstance((yield None), bytes)
64
+ if not data:
65
+ break
66
+
67
+ compressed = compressor.compress(data)
68
+ if compressed:
69
+ check.none((yield compressed))
70
+
71
+ if (fl := compressor.flush()):
72
+ check.none((yield fl))
73
+
74
+ check.none((yield b''))
75
+
76
+
77
+ ##
78
+
79
+
80
+ class DecompressorObjectIncrementalAdapter:
81
+ def __init__(
82
+ self,
83
+ factory: ta.Callable[..., NeedsInputDecompressorObject | UnconsumedTailDecompressorObject],
84
+ *,
85
+ trailing_error: type[BaseException] | tuple[type[BaseException], ...] = (),
86
+ ) -> None:
87
+ super().__init__()
88
+
89
+ self._factory = factory
90
+ self._trailing_error = trailing_error
91
+
92
+ def __call__(self) -> BytesSteppedReaderGenerator:
93
+ pos = 0
94
+
95
+ data = None # Default if EOF is encountered
96
+
97
+ decompressor = self._factory()
98
+
99
+ while True:
100
+ # Depending on the input data, our call to the decompressor may not return any data. In this case, try again
101
+ # after reading another block.
102
+ while True:
103
+ if decompressor.eof:
104
+ rawblock = decompressor.unused_data
105
+ if not rawblock:
106
+ rawblock = check.isinstance((yield None), bytes)
107
+ if not rawblock:
108
+ break
109
+
110
+ # Continue to next stream.
111
+ decompressor = self._factory()
112
+
113
+ try:
114
+ data = decompressor.decompress(rawblock)
115
+ except self._trailing_error:
116
+ # Trailing data isn't a valid compressed stream; ignore it.
117
+ break
118
+
119
+ else:
120
+ if hasattr(decompressor, 'needs_input'):
121
+ if decompressor.needs_input:
122
+ rawblock = check.isinstance((yield None), bytes)
123
+ if not rawblock:
124
+ raise EOFError('Compressed file ended before the end-of-stream marker was reached')
125
+ else:
126
+ rawblock = b''
127
+
128
+ elif hasattr(decompressor, 'unconsumed_tail'):
129
+ if not (rawblock := decompressor.unconsumed_tail):
130
+ rawblock = check.isinstance((yield None), bytes)
131
+ if not rawblock:
132
+ raise EOFError('Compressed file ended before the end-of-stream marker was reached')
133
+
134
+ else:
135
+ raise TypeError(decompressor)
136
+
137
+ data = decompressor.decompress(rawblock)
138
+
139
+ if data:
140
+ break
141
+
142
+ if not data:
143
+ check.none((yield b''))
144
+ return
145
+
146
+ pos += len(data)
147
+ check.none((yield data))
148
+ data = None
@@ -0,0 +1,24 @@
1
+ import abc
2
+
3
+ from ..generators import BytesSteppedGenerator
4
+ from ..generators import BytesSteppedReaderGenerator
5
+
6
+
7
+ class Compression(abc.ABC):
8
+ @abc.abstractmethod
9
+ def compress(self, d: bytes) -> bytes:
10
+ raise NotImplementedError
11
+
12
+ @abc.abstractmethod
13
+ def decompress(self, d: bytes) -> bytes:
14
+ raise NotImplementedError
15
+
16
+
17
+ class IncrementalCompression(abc.ABC):
18
+ @abc.abstractmethod
19
+ def compress_incremental(self) -> BytesSteppedGenerator[None]:
20
+ raise NotImplementedError
21
+
22
+ @abc.abstractmethod
23
+ def decompress_incremental(self) -> BytesSteppedReaderGenerator[None]:
24
+ raise NotImplementedError
@@ -0,0 +1,47 @@
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 brotli
12
+ else:
13
+ brotli = lang.proxy_import('brotli')
14
+
15
+
16
+ ##
17
+
18
+
19
+ @dc.dataclass(frozen=True, kw_only=True)
20
+ class BrotliCompression(Compression):
21
+ mode: int | None = None
22
+ quality: int | None = None
23
+ lgwin: int | None = None
24
+ lgblock: int | None = None
25
+
26
+ def compress(self, d: bytes) -> bytes:
27
+ return brotli.compress(
28
+ d,
29
+ **(dict(mode=self.mode) if self.mode is not None else {}),
30
+ **(dict(mode=self.quality) if self.quality is not None else {}),
31
+ **(dict(mode=self.lgwin) if self.lgwin is not None else {}),
32
+ **(dict(mode=self.lgblock) if self.lgblock is not None else {}),
33
+ )
34
+
35
+ def decompress(self, d: bytes) -> bytes:
36
+ return brotli.decompress(
37
+ d,
38
+ )
39
+
40
+
41
+ ##
42
+
43
+
44
+ BROTLI_CODEC = make_compression_codec('brotli', BrotliCompression)
45
+
46
+ # @omlish-manifest
47
+ _BROTLI_LAZY_CODEC = make_compression_lazy_loaded_codec(__name__, 'BROTLI_CODEC', BROTLI_CODEC)