omlish 0.0.0.dev141__py3-none-any.whl → 0.0.0.dev143__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 (38) hide show
  1. omlish/__about__.py +4 -2
  2. omlish/check.py +2 -0
  3. omlish/collections/coerce.py +1 -0
  4. omlish/docker/__init__.py +2 -1
  5. omlish/docker/helpers.py +0 -6
  6. omlish/funcs/pairs.py +2 -2
  7. omlish/io/compress/__init__.py +9 -0
  8. omlish/io/compress/abc.py +4 -4
  9. omlish/io/compress/adapters.py +12 -11
  10. omlish/io/compress/base.py +24 -0
  11. omlish/io/compress/brotli.py +33 -0
  12. omlish/io/compress/bz2.py +26 -21
  13. omlish/io/compress/gzip.py +43 -10
  14. omlish/io/compress/lz4.py +77 -0
  15. omlish/io/compress/lzma.py +51 -16
  16. omlish/io/compress/snappy.py +20 -0
  17. omlish/io/compress/zlib.py +60 -0
  18. omlish/io/compress/zstd.py +30 -0
  19. omlish/io/generators/__init__.py +53 -0
  20. omlish/io/generators/consts.py +1 -0
  21. omlish/io/generators/direct.py +13 -0
  22. omlish/io/generators/readers.py +15 -9
  23. omlish/io/generators/stepped.py +85 -14
  24. omlish/io/pyio.py +5 -2
  25. omlish/lang/__init__.py +1 -0
  26. omlish/lang/iterables.py +20 -0
  27. omlish/lite/docker.py +3 -0
  28. omlish/lite/marshal.py +213 -141
  29. omlish/lite/pycharm.py +48 -0
  30. omlish/lite/subprocesses.py +13 -0
  31. omlish/logs/abc.py +0 -1
  32. {omlish-0.0.0.dev141.dist-info → omlish-0.0.0.dev143.dist-info}/METADATA +3 -1
  33. {omlish-0.0.0.dev141.dist-info → omlish-0.0.0.dev143.dist-info}/RECORD +37 -29
  34. omlish/io/compress/types.py +0 -29
  35. {omlish-0.0.0.dev141.dist-info → omlish-0.0.0.dev143.dist-info}/LICENSE +0 -0
  36. {omlish-0.0.0.dev141.dist-info → omlish-0.0.0.dev143.dist-info}/WHEEL +0 -0
  37. {omlish-0.0.0.dev141.dist-info → omlish-0.0.0.dev143.dist-info}/entry_points.txt +0 -0
  38. {omlish-0.0.0.dev141.dist-info → omlish-0.0.0.dev143.dist-info}/top_level.txt +0 -0
omlish/__about__.py CHANGED
@@ -1,5 +1,5 @@
1
- __version__ = '0.0.0.dev141'
2
- __revision__ = '3c5f18d26cf70e5f7c52546521cac21f20063258'
1
+ __version__ = '0.0.0.dev143'
2
+ __revision__ = '72813c4e4d25f26261452612724f0bce16c77125'
3
3
 
4
4
 
5
5
  #
@@ -48,6 +48,8 @@ class Project(ProjectBase):
48
48
  'python-snappy ~= 0.7',
49
49
 
50
50
  'zstandard ~= 0.23',
51
+
52
+ 'brotli ~= 1.1',
51
53
  ],
52
54
 
53
55
  'diag': [
omlish/check.py CHANGED
@@ -144,6 +144,8 @@ def _raise(
144
144
 
145
145
 
146
146
  def _unpack_isinstance_spec(spec: ta.Any) -> tuple:
147
+ if _isinstance(spec, type):
148
+ return (spec,)
147
149
  if not _isinstance(spec, tuple):
148
150
  spec = (spec,)
149
151
  if None in spec:
@@ -334,4 +334,5 @@ def map_of_or_none(
334
334
  value_fn = _unpack_fn(value_fn)
335
335
  return inner
336
336
 
337
+
337
338
  # endregion
omlish/docker/__init__.py CHANGED
@@ -14,7 +14,6 @@ from .compose import ( # noqa
14
14
  )
15
15
 
16
16
  from .helpers import ( # noqa
17
- DOCKER_FOR_MAC_HOSTNAME,
18
17
  DOCKER_HOST_PLATFORM_KEY,
19
18
  get_docker_host_platform,
20
19
  timebomb_payload,
@@ -32,5 +31,7 @@ from .hub import ( # noqa
32
31
 
33
32
 
34
33
  from ..lite.docker import ( # noqa
34
+ DOCKER_FOR_MAC_HOSTNAME,
35
+
35
36
  is_likely_in_docker,
36
37
  )
omlish/docker/helpers.py CHANGED
@@ -21,12 +21,6 @@ def timebomb_payload(delay_s: float, name: str = _DEFAULT_TIMEBOMB_NAME) -> str:
21
21
  ##
22
22
 
23
23
 
24
- DOCKER_FOR_MAC_HOSTNAME = 'docker.for.mac.localhost'
25
-
26
-
27
- ##
28
-
29
-
30
24
  # Set by pyproject, docker-dev script
31
25
  DOCKER_HOST_PLATFORM_KEY = 'DOCKER_HOST_PLATFORM'
32
26
 
omlish/funcs/pairs.py CHANGED
@@ -10,9 +10,9 @@ TODO:
10
10
 
11
11
  Compression choice:
12
12
  - lzma if-available minimal-space
13
- - lz4 if-available write-once
13
+ - lz4 if-available read-heavy
14
14
  - zstd if-available
15
- - bz2 write-once (but no parallel decompress)
15
+ - bz2 read-heavy (but no parallel decompress)
16
16
  - gz
17
17
  """
18
18
  import abc
@@ -0,0 +1,9 @@
1
+ """
2
+ TODO:
3
+ - zipfile?
4
+ - tarfile?
5
+ - lzf?
6
+ - blosc?
7
+ - python-lzo?
8
+ - zfp -> fp8?
9
+ """
omlish/io/compress/abc.py CHANGED
@@ -9,7 +9,7 @@ import abc
9
9
  ##
10
10
 
11
11
 
12
- class Compressor(abc.ABC):
12
+ class CompressorObject(abc.ABC):
13
13
  @abc.abstractmethod
14
14
  def compress(self, data: bytes) -> bytes:
15
15
  """
@@ -36,7 +36,7 @@ class Compressor(abc.ABC):
36
36
  ##
37
37
 
38
38
 
39
- class Decompressor(abc.ABC):
39
+ class DecompressorObject(abc.ABC):
40
40
  @property
41
41
  @abc.abstractmethod
42
42
  def unused_data(self) -> bytes:
@@ -68,7 +68,7 @@ class Decompressor(abc.ABC):
68
68
  raise NotImplementedError
69
69
 
70
70
 
71
- class NeedsInputDecompressor(Decompressor):
71
+ class NeedsInputDecompressorObject(DecompressorObject):
72
72
  """
73
73
  Used by:
74
74
  - bz2.BZ2Decompressor
@@ -85,7 +85,7 @@ class NeedsInputDecompressor(Decompressor):
85
85
  raise NotImplementedError
86
86
 
87
87
 
88
- class UnconsumedTailDecompressor(Decompressor):
88
+ class UnconsumedTailDecompressorObject(DecompressorObject):
89
89
  """
90
90
  Used by:
91
91
  - zlib.decompressobj
@@ -37,26 +37,26 @@
37
37
  import typing as ta
38
38
 
39
39
  from ... import check
40
- from .abc import Compressor
41
- from .abc import NeedsInputDecompressor
42
- from .abc import UnconsumedTailDecompressor
43
- from .types import IncrementalCompressor
44
- from .types import IncrementalDecompressor
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
45
 
46
46
 
47
47
  ##
48
48
 
49
49
 
50
- class CompressorIncrementalAdapter:
50
+ class CompressorObjectIncrementalAdapter:
51
51
  def __init__(
52
52
  self,
53
- factory: ta.Callable[..., Compressor],
53
+ factory: ta.Callable[..., CompressorObject],
54
54
  ) -> None:
55
55
  super().__init__()
56
56
 
57
57
  self._factory = factory
58
58
 
59
- def __call__(self) -> IncrementalCompressor:
59
+ def __call__(self) -> BytesSteppedGenerator:
60
60
  compressor = self._factory()
61
61
 
62
62
  while True:
@@ -77,10 +77,10 @@ class CompressorIncrementalAdapter:
77
77
  ##
78
78
 
79
79
 
80
- class DecompressorIncrementalAdapter:
80
+ class DecompressorObjectIncrementalAdapter:
81
81
  def __init__(
82
82
  self,
83
- factory: ta.Callable[..., NeedsInputDecompressor | UnconsumedTailDecompressor],
83
+ factory: ta.Callable[..., NeedsInputDecompressorObject | UnconsumedTailDecompressorObject],
84
84
  *,
85
85
  trailing_error: type[BaseException] | tuple[type[BaseException], ...] = (),
86
86
  ) -> None:
@@ -89,7 +89,7 @@ class DecompressorIncrementalAdapter:
89
89
  self._factory = factory
90
90
  self._trailing_error = trailing_error
91
91
 
92
- def __call__(self) -> IncrementalDecompressor:
92
+ def __call__(self) -> BytesSteppedReaderGenerator:
93
93
  pos = 0
94
94
 
95
95
  data = None # Default if EOF is encountered
@@ -145,3 +145,4 @@ class DecompressorIncrementalAdapter:
145
145
 
146
146
  pos += len(data)
147
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,33 @@
1
+ import dataclasses as dc
2
+ import typing as ta
3
+
4
+ from ... import lang
5
+ from .base import Compression
6
+
7
+
8
+ if ta.TYPE_CHECKING:
9
+ import brotli
10
+ else:
11
+ brotli = lang.proxy_import('brotli')
12
+
13
+
14
+ @dc.dataclass(frozen=True, kw_only=True)
15
+ class SnappyCompression(Compression):
16
+ mode: int | None = None
17
+ quality: int | None = None
18
+ lgwin: int | None = None
19
+ lgblock: int | None = None
20
+
21
+ def compress(self, d: bytes) -> bytes:
22
+ return brotli.compress(
23
+ d,
24
+ **(dict(mode=self.mode) if self.mode is not None else {}),
25
+ **(dict(mode=self.quality) if self.quality is not None else {}),
26
+ **(dict(mode=self.lgwin) if self.lgwin is not None else {}),
27
+ **(dict(mode=self.lgblock) if self.lgblock is not None else {}),
28
+ )
29
+
30
+ def decompress(self, d: bytes) -> bytes:
31
+ return brotli.decompress(
32
+ d,
33
+ )
omlish/io/compress/bz2.py CHANGED
@@ -1,11 +1,14 @@
1
+ import dataclasses as dc
1
2
  import functools
2
3
  import typing as ta
3
4
 
4
5
  from ... import lang
5
- from .adapters import CompressorIncrementalAdapter
6
- from .adapters import DecompressorIncrementalAdapter
7
- from .types import IncrementalCompressor
8
- from .types import IncrementalDecompressor
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
9
12
 
10
13
 
11
14
  if ta.TYPE_CHECKING:
@@ -14,29 +17,31 @@ else:
14
17
  bz2 = lang.proxy_import('bz2')
15
18
 
16
19
 
17
- class IncrementalBz2Compressor:
18
- def __init__(
19
- self,
20
- *,
21
- compresslevel: int = 9,
22
- ) -> None:
23
- super().__init__()
20
+ @dc.dataclass(frozen=True, kw_only=True)
21
+ class Bz2Compression(Compression, IncrementalCompression):
22
+ level: int = 9
24
23
 
25
- self._compresslevel = compresslevel
24
+ def compress(self, d: bytes) -> bytes:
25
+ return bz2.compress(
26
+ d,
27
+ self.level,
28
+ )
26
29
 
27
- @lang.autostart
28
- def __call__(self) -> IncrementalCompressor:
29
- return CompressorIncrementalAdapter(
30
+ def decompress(self, d: bytes) -> bytes:
31
+ return bz2.decompress(
32
+ d,
33
+ )
34
+
35
+ def compress_incremental(self) -> BytesSteppedGenerator[None]:
36
+ return lang.nextgen(CompressorObjectIncrementalAdapter(
30
37
  functools.partial(
31
38
  bz2.BZ2Compressor, # type: ignore
32
- self._compresslevel,
39
+ self.level,
33
40
  ),
34
- )()
35
-
41
+ )())
36
42
 
37
- class IncrementalBz2Decompressor:
38
- def __call__(self) -> IncrementalDecompressor:
39
- return DecompressorIncrementalAdapter(
43
+ def decompress_incremental(self) -> BytesSteppedReaderGenerator[None]:
44
+ return DecompressorObjectIncrementalAdapter(
40
45
  bz2.BZ2Decompressor, # type: ignore
41
46
  trailing_error=OSError,
42
47
  )()
@@ -33,6 +33,7 @@
33
33
  #
34
34
  # 8. By copying, installing or otherwise using Python, Licensee agrees to be bound by the terms and conditions of this
35
35
  # License Agreement.
36
+ import dataclasses as dc
36
37
  import functools
37
38
  import os.path
38
39
  import struct
@@ -42,9 +43,11 @@ import typing as ta
42
43
  from ... import cached
43
44
  from ... import check
44
45
  from ... import lang
46
+ from ..generators import BytesSteppedGenerator
47
+ from ..generators import BytesSteppedReaderGenerator
45
48
  from ..generators.readers import PrependableBytesGeneratorReader
46
- from .types import IncrementalCompressor
47
- from .types import IncrementalDecompressor
49
+ from .base import Compression
50
+ from .base import IncrementalCompression
48
51
 
49
52
 
50
53
  if ta.TYPE_CHECKING:
@@ -63,6 +66,37 @@ COMPRESS_LEVEL_TRADEOFF = 6
63
66
  COMPRESS_LEVEL_BEST = 9
64
67
 
65
68
 
69
+ @dc.dataclass(frozen=True, kw_only=True)
70
+ class GzipCompression(Compression, IncrementalCompression):
71
+ level: int = COMPRESS_LEVEL_BEST
72
+
73
+ mtime: float | None = None
74
+
75
+ def compress(self, d: bytes) -> bytes:
76
+ return gzip.compress(
77
+ d,
78
+ self.level,
79
+ mtime=self.mtime,
80
+ )
81
+
82
+ def decompress(self, d: bytes) -> bytes:
83
+ return gzip.decompress(
84
+ d,
85
+ )
86
+
87
+ def compress_incremental(self) -> BytesSteppedGenerator[None]:
88
+ return lang.nextgen(IncrementalGzipCompressor(
89
+ level=self.level,
90
+ mtime=self.mtime,
91
+ )())
92
+
93
+ def decompress_incremental(self) -> BytesSteppedReaderGenerator[None]:
94
+ return IncrementalGzipDecompressor()()
95
+
96
+
97
+ ##
98
+
99
+
66
100
  @cached.function
67
101
  def _zero_crc() -> int:
68
102
  return zlib.crc32(b'')
@@ -75,14 +109,14 @@ class IncrementalGzipCompressor:
75
109
  def __init__(
76
110
  self,
77
111
  *,
78
- compresslevel: int = COMPRESS_LEVEL_BEST,
112
+ level: int = COMPRESS_LEVEL_BEST,
79
113
  name: str | bytes | None = None,
80
114
  mtime: float | None = None,
81
115
  ) -> None:
82
116
  super().__init__()
83
117
 
84
118
  self._name = name or ''
85
- self._compresslevel = compresslevel
119
+ self._level = level
86
120
  self._mtime = mtime
87
121
 
88
122
  def _write_gzip_header(self) -> ta.Generator[bytes, None, None]:
@@ -110,9 +144,9 @@ class IncrementalGzipCompressor:
110
144
  mtime = time.time()
111
145
  check.none((yield struct.pack('<L', int(mtime))))
112
146
 
113
- if self._compresslevel == COMPRESS_LEVEL_BEST:
147
+ if self._level == COMPRESS_LEVEL_BEST:
114
148
  xfl = b'\002'
115
- elif self._compresslevel == COMPRESS_LEVEL_FAST:
149
+ elif self._level == COMPRESS_LEVEL_FAST:
116
150
  xfl = b'\004'
117
151
  else:
118
152
  xfl = b'\000'
@@ -123,15 +157,14 @@ class IncrementalGzipCompressor:
123
157
  if fname:
124
158
  check.none((yield fname + b'\000'))
125
159
 
126
- @lang.autostart
127
- def __call__(self) -> IncrementalCompressor:
160
+ def __call__(self) -> BytesSteppedGenerator:
128
161
  crc = _zero_crc()
129
162
  size = 0
130
163
  offset = 0 # Current file offset for seek(), tell(), etc
131
164
  wrote_header = False
132
165
 
133
166
  compress = zlib.compressobj(
134
- self._compresslevel,
167
+ self._level,
135
168
  zlib.DEFLATED,
136
169
  -zlib.MAX_WBITS,
137
170
  zlib.DEF_MEM_LEVEL,
@@ -251,7 +284,7 @@ class IncrementalGzipDecompressor:
251
284
  if c:
252
285
  rdr.prepend(c)
253
286
 
254
- def __call__(self) -> IncrementalDecompressor:
287
+ def __call__(self) -> BytesSteppedReaderGenerator:
255
288
  rdr = PrependableBytesGeneratorReader()
256
289
 
257
290
  pos = 0 # Current offset in decompressed stream
@@ -0,0 +1,77 @@
1
+ import dataclasses as dc
2
+ import typing as ta
3
+
4
+ from ... import check
5
+ from ... import lang
6
+ from ..generators import BytesSteppedGenerator
7
+ from .base import Compression
8
+ from .base import IncrementalCompression
9
+
10
+
11
+ if ta.TYPE_CHECKING:
12
+ import lz4.frame as lz4_frame
13
+ else:
14
+ lz4_frame = lang.proxy_import('lz4.frame')
15
+
16
+
17
+ @dc.dataclass(frozen=True, kw_only=True)
18
+ class Lz4Compression(Compression, IncrementalCompression):
19
+ level: int = 0
20
+
21
+ block_size: int = 0
22
+ block_linked: bool = True
23
+ block_checksum: bool = False
24
+ content_checksum: bool = False
25
+ store_size: bool = True
26
+ auto_flush: bool = False
27
+
28
+ def compress(self, d: bytes) -> bytes:
29
+ return lz4_frame.compress(
30
+ d,
31
+ compression_level=self.level,
32
+ block_size=self.block_size,
33
+ content_checksum=self.content_checksum,
34
+ block_linked=self.block_linked,
35
+ store_size=self.store_size,
36
+ )
37
+
38
+ def decompress(self, d: bytes) -> bytes:
39
+ return lz4_frame.decompress(
40
+ d,
41
+ )
42
+
43
+ @lang.autostart
44
+ def compress_incremental(self) -> BytesSteppedGenerator[None]:
45
+ with lz4_frame.LZ4FrameCompressor(
46
+ compression_level=self.level,
47
+ block_size=self.block_size,
48
+ block_linked=self.block_linked,
49
+ block_checksum=self.block_checksum,
50
+ content_checksum=self.content_checksum,
51
+ auto_flush=self.auto_flush,
52
+ ) as compressor:
53
+ started = False
54
+ while True:
55
+ i = check.isinstance((yield None), bytes)
56
+ if not started:
57
+ yield compressor.begin()
58
+ started = True
59
+ if not i:
60
+ yield compressor.flush()
61
+ yield b''
62
+ return
63
+ if (o := compressor.compress(i)):
64
+ yield o
65
+
66
+ @lang.autostart
67
+ def decompress_incremental(self) -> BytesSteppedGenerator[None]:
68
+ # lz4 lib does internal buffering so this is simply a BytesSteppedGenerator not a BytesSteppedReaderGenerator as
69
+ # it only yields None, accepting any number of bytes at a time.
70
+ with lz4_frame.LZ4FrameDecompressor() as decompressor:
71
+ while True:
72
+ i = check.isinstance((yield None), bytes)
73
+ if not i:
74
+ yield b''
75
+ return
76
+ if (o := decompressor.decompress(i)):
77
+ yield o
@@ -1,10 +1,14 @@
1
+ import dataclasses as dc
2
+ import functools
1
3
  import typing as ta
2
4
 
3
5
  from ... import lang
4
- from .adapters import CompressorIncrementalAdapter
5
- from .adapters import DecompressorIncrementalAdapter
6
- from .types import IncrementalCompressor
7
- from .types import IncrementalDecompressor
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
8
12
 
9
13
 
10
14
  if ta.TYPE_CHECKING:
@@ -13,20 +17,51 @@ else:
13
17
  lzma = lang.proxy_import('lzma')
14
18
 
15
19
 
16
- class IncrementalLzmaCompressor:
17
- def __init__(self) -> None:
18
- super().__init__()
20
+ @dc.dataclass(frozen=True, kw_only=True)
21
+ class LzmaCompression(Compression, IncrementalCompression):
22
+ format: int | None = None
19
23
 
20
- @lang.autostart
21
- def __call__(self) -> IncrementalCompressor:
22
- return CompressorIncrementalAdapter(
23
- lzma.LZMACompressor, # type: ignore
24
- )()
24
+ check: int = -1
25
+ preset: int | None = None
26
+ filters: dict | None = None
27
+
28
+ mem_limit: int | None = None
29
+
30
+ def compress(self, d: bytes) -> bytes:
31
+ return lzma.compress(
32
+ d,
33
+ format=self.format if self.format is not None else lzma.FORMAT_XZ,
34
+ check=self.check,
35
+ preset=self.preset,
36
+ filters=self.filters, # type: ignore[arg-type]
37
+ )
38
+
39
+ def decompress(self, d: bytes) -> bytes:
40
+ return lzma.decompress(
41
+ d,
42
+ format=self.format if self.format is not None else lzma.FORMAT_AUTO,
43
+ memlimit=self.mem_limit,
44
+ filters=self.filters, # type: ignore[arg-type]
45
+ )
25
46
 
47
+ def compress_incremental(self) -> BytesSteppedGenerator[None]:
48
+ return lang.nextgen(CompressorObjectIncrementalAdapter(
49
+ functools.partial( # type: ignore
50
+ lzma.LZMACompressor,
51
+ format=self.format if self.format is not None else lzma.FORMAT_XZ,
52
+ check=self.check,
53
+ preset=self.preset,
54
+ filters=self.filters, # type: ignore[arg-type]
55
+ ),
56
+ )())
26
57
 
27
- class IncrementalLzmaDecompressor:
28
- def __call__(self) -> IncrementalDecompressor:
29
- return DecompressorIncrementalAdapter(
30
- lzma.LZMADecompressor, # type: ignore
58
+ def decompress_incremental(self) -> BytesSteppedReaderGenerator[None]:
59
+ return DecompressorObjectIncrementalAdapter(
60
+ functools.partial( # type: ignore
61
+ lzma.LZMADecompressor,
62
+ format=self.format if self.format is not None else lzma.FORMAT_AUTO,
63
+ memlimit=self.mem_limit,
64
+ filters=self.filters, # type: ignore[arg-type]
65
+ ),
31
66
  trailing_error=lzma.LZMAError,
32
67
  )()
@@ -0,0 +1,20 @@
1
+ import dataclasses as dc
2
+ import typing as ta
3
+
4
+ from ... import lang
5
+ from .base import Compression
6
+
7
+
8
+ if ta.TYPE_CHECKING:
9
+ import snappy
10
+ else:
11
+ snappy = lang.proxy_import('snappy')
12
+
13
+
14
+ @dc.dataclass(frozen=True)
15
+ class SnappyCompression(Compression):
16
+ def compress(self, d: bytes) -> bytes:
17
+ return snappy.compress(d)
18
+
19
+ def decompress(self, d: bytes) -> bytes:
20
+ return snappy.decompress(d)
@@ -0,0 +1,60 @@
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
+
13
+
14
+ if ta.TYPE_CHECKING:
15
+ import zlib
16
+ else:
17
+ zlib = lang.proxy_import('zlib')
18
+
19
+
20
+ @dc.dataclass(frozen=True, kw_only=True)
21
+ class ZlibCompression(Compression, IncrementalCompression):
22
+ level: int = 9
23
+
24
+ wbits: int | None = None
25
+ strategy: int | None = None
26
+ zdict: bytes | None = None
27
+
28
+ def compress(self, d: bytes) -> bytes:
29
+ return zlib.compress(
30
+ d,
31
+ self.level,
32
+ **(dict(wbits=self.wbits) if self.wbits is not None else {}),
33
+ )
34
+
35
+ def decompress(self, d: bytes) -> bytes:
36
+ return zlib.decompress(
37
+ d,
38
+ **(dict(wbits=self.wbits) if self.wbits is not None else {}),
39
+ )
40
+
41
+ def compress_incremental(self) -> BytesSteppedGenerator[None]:
42
+ return lang.nextgen(CompressorObjectIncrementalAdapter(
43
+ functools.partial(
44
+ zlib.compressobj, # type: ignore
45
+ self.level,
46
+ **(dict(wbits=self.wbits) if self.wbits is not None else {}), # type: ignore[arg-type]
47
+ **(dict(strategy=self.strategy) if self.strategy is not None else {}), # type: ignore[arg-type]
48
+ **(dict(zdict=self.zdict) if self.zdict is not None else {}), # type: ignore[arg-type]
49
+ ),
50
+ )())
51
+
52
+ def decompress_incremental(self) -> BytesSteppedReaderGenerator[None]:
53
+ return DecompressorObjectIncrementalAdapter(
54
+ functools.partial( # type: ignore
55
+ zlib.decompressobj,
56
+ **(dict(wbits=self.wbits) if self.wbits is not None else {}), # type: ignore[arg-type]
57
+ **(dict(zdict=self.zdict) if self.zdict is not None else {}), # type: ignore[arg-type]
58
+ ),
59
+ trailing_error=OSError,
60
+ )()