omlish 0.0.0.dev132__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.
- omlish/.manifests.json +265 -7
- omlish/__about__.py +7 -5
- omlish/antlr/_runtime/__init__.py +0 -22
- omlish/antlr/_runtime/_all.py +24 -0
- omlish/antlr/_runtime/atn/ParserATNSimulator.py +1 -1
- omlish/antlr/_runtime/dfa/DFASerializer.py +1 -1
- omlish/antlr/_runtime/error/DiagnosticErrorListener.py +2 -1
- omlish/antlr/_runtime/xpath/XPath.py +7 -1
- omlish/antlr/_runtime/xpath/XPathLexer.py +1 -1
- omlish/antlr/delimit.py +106 -0
- omlish/antlr/dot.py +31 -0
- omlish/antlr/errors.py +11 -0
- omlish/antlr/input.py +96 -0
- omlish/antlr/parsing.py +19 -0
- omlish/antlr/runtime.py +102 -0
- omlish/antlr/utils.py +38 -0
- omlish/argparse/all.py +45 -0
- omlish/{argparse.py → argparse/cli.py} +112 -107
- omlish/asyncs/__init__.py +0 -35
- omlish/asyncs/all.py +35 -0
- omlish/asyncs/asyncio/all.py +7 -0
- omlish/asyncs/asyncio/channels.py +40 -0
- omlish/asyncs/asyncio/streams.py +45 -0
- omlish/asyncs/asyncio/subprocesses.py +238 -0
- omlish/asyncs/asyncio/timeouts.py +16 -0
- omlish/asyncs/bluelet/LICENSE +6 -0
- omlish/asyncs/bluelet/all.py +67 -0
- omlish/asyncs/bluelet/api.py +23 -0
- omlish/asyncs/bluelet/core.py +178 -0
- omlish/asyncs/bluelet/events.py +78 -0
- omlish/asyncs/bluelet/files.py +80 -0
- omlish/asyncs/bluelet/runner.py +416 -0
- omlish/asyncs/bluelet/sockets.py +214 -0
- omlish/bootstrap/sys.py +3 -3
- omlish/cached.py +2 -2
- omlish/check.py +49 -460
- omlish/codecs/__init__.py +72 -0
- omlish/codecs/base.py +106 -0
- omlish/codecs/bytes.py +119 -0
- omlish/codecs/chain.py +23 -0
- omlish/codecs/funcs.py +39 -0
- omlish/codecs/registry.py +139 -0
- omlish/codecs/standard.py +4 -0
- omlish/codecs/text.py +217 -0
- omlish/collections/cache/impl.py +50 -57
- omlish/collections/coerce.py +1 -0
- omlish/collections/mappings.py +1 -1
- omlish/configs/flattening.py +1 -1
- omlish/defs.py +1 -1
- omlish/diag/_pycharm/runhack.py +8 -2
- omlish/diag/procfs.py +8 -8
- omlish/docker/__init__.py +0 -36
- omlish/docker/all.py +31 -0
- omlish/docker/consts.py +4 -0
- omlish/{lite/docker.py → docker/detect.py} +18 -0
- omlish/docker/{helpers.py → timebomb.py} +0 -21
- omlish/formats/cbor.py +31 -0
- omlish/formats/cloudpickle.py +31 -0
- omlish/formats/codecs.py +93 -0
- omlish/formats/json/codecs.py +29 -0
- omlish/formats/json/delimted.py +4 -0
- omlish/formats/json/stream/errors.py +2 -0
- omlish/formats/json/stream/lex.py +12 -6
- omlish/formats/json/stream/parse.py +38 -22
- omlish/formats/json5.py +31 -0
- omlish/formats/pickle.py +31 -0
- omlish/formats/repr.py +25 -0
- omlish/formats/toml.py +17 -0
- omlish/formats/yaml.py +25 -0
- omlish/funcs/__init__.py +0 -0
- omlish/{genmachine.py → funcs/genmachine.py} +5 -4
- omlish/{matchfns.py → funcs/match.py} +1 -1
- omlish/funcs/pairs.py +215 -0
- omlish/http/__init__.py +0 -48
- omlish/http/all.py +48 -0
- omlish/http/coro/__init__.py +0 -0
- omlish/{lite/fdio/corohttp.py → http/coro/fdio.py} +21 -19
- omlish/{lite/http/coroserver.py → http/coro/server.py} +20 -21
- omlish/{lite/http → http}/handlers.py +3 -2
- omlish/{lite/http → http}/parsing.py +1 -0
- omlish/http/sessions.py +1 -1
- omlish/{lite/http → http}/versions.py +1 -0
- omlish/inject/managed.py +2 -2
- omlish/io/__init__.py +0 -3
- omlish/{lite/io.py → io/buffers.py} +8 -9
- omlish/io/compress/__init__.py +9 -0
- omlish/io/compress/abc.py +104 -0
- omlish/io/compress/adapters.py +148 -0
- omlish/io/compress/base.py +24 -0
- omlish/io/compress/brotli.py +47 -0
- omlish/io/compress/bz2.py +61 -0
- omlish/io/compress/codecs.py +78 -0
- omlish/io/compress/gzip.py +350 -0
- omlish/io/compress/lz4.py +91 -0
- omlish/io/compress/lzma.py +81 -0
- omlish/io/compress/snappy.py +34 -0
- omlish/io/compress/zlib.py +74 -0
- omlish/io/compress/zstd.py +44 -0
- omlish/io/fdio/__init__.py +1 -0
- omlish/{lite → io}/fdio/handlers.py +5 -5
- omlish/{lite → io}/fdio/kqueue.py +8 -8
- omlish/{lite → io}/fdio/manager.py +7 -7
- omlish/{lite → io}/fdio/pollers.py +13 -13
- omlish/io/generators/__init__.py +56 -0
- omlish/io/generators/consts.py +1 -0
- omlish/io/generators/direct.py +13 -0
- omlish/io/generators/readers.py +189 -0
- omlish/io/generators/stepped.py +191 -0
- omlish/io/pyio.py +5 -2
- omlish/iterators/__init__.py +24 -0
- omlish/iterators/iterators.py +132 -0
- omlish/iterators/recipes.py +18 -0
- omlish/iterators/tools.py +96 -0
- omlish/iterators/unique.py +67 -0
- omlish/lang/__init__.py +13 -1
- omlish/lang/functions.py +11 -2
- omlish/lang/generators.py +243 -0
- omlish/lang/iterables.py +46 -49
- omlish/lang/maybes.py +4 -4
- omlish/lite/cached.py +39 -6
- omlish/lite/check.py +438 -75
- omlish/lite/contextmanagers.py +17 -4
- omlish/lite/dataclasses.py +42 -0
- omlish/lite/inject.py +28 -45
- omlish/lite/logs.py +0 -270
- omlish/lite/marshal.py +309 -144
- omlish/lite/pycharm.py +47 -0
- omlish/lite/reflect.py +33 -0
- omlish/lite/resources.py +8 -0
- omlish/lite/runtime.py +4 -4
- omlish/lite/shlex.py +12 -0
- omlish/lite/socketserver.py +2 -2
- omlish/lite/strings.py +31 -0
- omlish/logs/__init__.py +0 -32
- omlish/logs/{_abc.py → abc.py} +0 -1
- omlish/logs/all.py +37 -0
- omlish/logs/{formatters.py → color.py} +1 -2
- omlish/logs/configs.py +7 -38
- omlish/logs/filters.py +10 -0
- omlish/logs/handlers.py +4 -1
- omlish/logs/json.py +56 -0
- omlish/logs/proxy.py +99 -0
- omlish/logs/standard.py +128 -0
- omlish/logs/utils.py +2 -2
- omlish/manifests/__init__.py +2 -0
- omlish/manifests/load.py +209 -0
- omlish/manifests/types.py +17 -0
- omlish/marshal/base.py +1 -1
- omlish/marshal/factories.py +1 -1
- omlish/marshal/forbidden.py +1 -1
- omlish/marshal/iterables.py +1 -1
- omlish/marshal/literals.py +50 -0
- omlish/marshal/mappings.py +1 -1
- omlish/marshal/maybes.py +1 -1
- omlish/marshal/standard.py +5 -1
- omlish/marshal/unions.py +1 -1
- omlish/os/__init__.py +0 -0
- omlish/os/atomics.py +205 -0
- omlish/os/deathsig.py +23 -0
- omlish/{os.py → os/files.py} +0 -9
- omlish/{lite → os}/journald.py +2 -1
- omlish/os/linux.py +484 -0
- omlish/os/paths.py +36 -0
- omlish/{lite → os}/pidfile.py +1 -0
- omlish/os/sizes.py +9 -0
- omlish/reflect/__init__.py +3 -0
- omlish/reflect/subst.py +2 -1
- omlish/reflect/types.py +126 -44
- omlish/secrets/pwhash.py +1 -1
- omlish/secrets/subprocesses.py +3 -1
- omlish/specs/jsonrpc/marshal.py +1 -1
- omlish/specs/openapi/marshal.py +1 -1
- omlish/sql/alchemy/asyncs.py +1 -1
- omlish/sql/queries/__init__.py +9 -1
- omlish/sql/queries/building.py +3 -0
- omlish/sql/queries/exprs.py +10 -27
- omlish/sql/queries/idents.py +48 -10
- omlish/sql/queries/names.py +80 -13
- omlish/sql/queries/params.py +64 -0
- omlish/sql/queries/rendering.py +1 -1
- omlish/subprocesses.py +340 -0
- omlish/term.py +29 -14
- omlish/testing/pytest/marks.py +2 -2
- omlish/testing/pytest/plugins/asyncs.py +6 -1
- omlish/testing/pytest/plugins/logging.py +1 -1
- omlish/testing/pytest/plugins/switches.py +1 -1
- {omlish-0.0.0.dev132.dist-info → omlish-0.0.0.dev177.dist-info}/METADATA +13 -11
- {omlish-0.0.0.dev132.dist-info → omlish-0.0.0.dev177.dist-info}/RECORD +200 -117
- omlish/fnpairs.py +0 -496
- omlish/formats/json/cli/__main__.py +0 -11
- omlish/formats/json/cli/cli.py +0 -298
- omlish/formats/json/cli/formats.py +0 -71
- omlish/formats/json/cli/io.py +0 -74
- omlish/formats/json/cli/parsing.py +0 -82
- omlish/formats/json/cli/processing.py +0 -48
- omlish/formats/json/cli/rendering.py +0 -92
- omlish/iterators.py +0 -300
- omlish/lite/subprocesses.py +0 -130
- /omlish/{formats/json/cli → argparse}/__init__.py +0 -0
- /omlish/{lite/fdio → asyncs/asyncio}/__init__.py +0 -0
- /omlish/asyncs/{asyncio.py → asyncio/asyncio.py} +0 -0
- /omlish/{lite/http → asyncs/bluelet}/__init__.py +0 -0
- /omlish/collections/{_abc.py → abc.py} +0 -0
- /omlish/{fnpipes.py → funcs/pipes.py} +0 -0
- /omlish/io/{_abc.py → abc.py} +0 -0
- /omlish/sql/{_abc.py → abc.py} +0 -0
- {omlish-0.0.0.dev132.dist-info → omlish-0.0.0.dev177.dist-info}/LICENSE +0 -0
- {omlish-0.0.0.dev132.dist-info → omlish-0.0.0.dev177.dist-info}/WHEEL +0 -0
- {omlish-0.0.0.dev132.dist-info → omlish-0.0.0.dev177.dist-info}/entry_points.txt +0 -0
- {omlish-0.0.0.dev132.dist-info → omlish-0.0.0.dev177.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,61 @@
|
|
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 bz2
|
18
|
+
else:
|
19
|
+
bz2 = lang.proxy_import('bz2')
|
20
|
+
|
21
|
+
|
22
|
+
##
|
23
|
+
|
24
|
+
|
25
|
+
@dc.dataclass(frozen=True, kw_only=True)
|
26
|
+
class Bz2Compression(Compression, IncrementalCompression):
|
27
|
+
level: int = 9
|
28
|
+
|
29
|
+
def compress(self, d: bytes) -> bytes:
|
30
|
+
return bz2.compress(
|
31
|
+
d,
|
32
|
+
self.level,
|
33
|
+
)
|
34
|
+
|
35
|
+
def decompress(self, d: bytes) -> bytes:
|
36
|
+
return bz2.decompress(
|
37
|
+
d,
|
38
|
+
)
|
39
|
+
|
40
|
+
def compress_incremental(self) -> BytesSteppedGenerator[None]:
|
41
|
+
return lang.nextgen(CompressorObjectIncrementalAdapter(
|
42
|
+
functools.partial(
|
43
|
+
bz2.BZ2Compressor, # type: ignore
|
44
|
+
self.level,
|
45
|
+
),
|
46
|
+
)())
|
47
|
+
|
48
|
+
def decompress_incremental(self) -> BytesSteppedReaderGenerator[None]:
|
49
|
+
return DecompressorObjectIncrementalAdapter(
|
50
|
+
bz2.BZ2Decompressor, # type: ignore
|
51
|
+
trailing_error=OSError,
|
52
|
+
)()
|
53
|
+
|
54
|
+
|
55
|
+
##
|
56
|
+
|
57
|
+
|
58
|
+
BZ2_CODEC = make_compression_codec('bz2', Bz2Compression)
|
59
|
+
|
60
|
+
# @omlish-manifest
|
61
|
+
_BZ2_LAZY_CODEC = make_compression_lazy_loaded_codec(__name__, 'BZ2_CODEC', BZ2_CODEC)
|
@@ -0,0 +1,78 @@
|
|
1
|
+
import dataclasses as dc
|
2
|
+
import typing as ta
|
3
|
+
|
4
|
+
from ... import codecs
|
5
|
+
from ..generators import buffer_bytes_stepped_reader_generator
|
6
|
+
from .base import Compression
|
7
|
+
from .base import IncrementalCompression
|
8
|
+
|
9
|
+
|
10
|
+
##
|
11
|
+
|
12
|
+
|
13
|
+
@dc.dataclass(frozen=True)
|
14
|
+
class CompressionEagerCodec(codecs.EagerCodec[bytes, bytes]):
|
15
|
+
compression: Compression
|
16
|
+
|
17
|
+
def encode(self, i: bytes) -> bytes:
|
18
|
+
return self.compression.compress(i)
|
19
|
+
|
20
|
+
def decode(self, o: bytes) -> bytes:
|
21
|
+
return self.compression.decompress(o)
|
22
|
+
|
23
|
+
|
24
|
+
##
|
25
|
+
|
26
|
+
|
27
|
+
@dc.dataclass(frozen=True)
|
28
|
+
class CompressionIncrementalCodec(codecs.IncrementalCodec[bytes, bytes]):
|
29
|
+
compression: IncrementalCompression
|
30
|
+
|
31
|
+
def encode_incremental(self) -> ta.Generator[bytes | None, bytes, None]:
|
32
|
+
return self.compression.compress_incremental()
|
33
|
+
|
34
|
+
def decode_incremental(self) -> ta.Generator[bytes | None, bytes, None]:
|
35
|
+
return buffer_bytes_stepped_reader_generator(self.compression.decompress_incremental())
|
36
|
+
|
37
|
+
|
38
|
+
##
|
39
|
+
|
40
|
+
|
41
|
+
class CompressionCodec(codecs.Codec):
|
42
|
+
pass
|
43
|
+
|
44
|
+
|
45
|
+
def make_compression_codec(
|
46
|
+
name: str,
|
47
|
+
cls: type[Compression],
|
48
|
+
*,
|
49
|
+
aliases: ta.Collection[str] | None = None,
|
50
|
+
) -> CompressionCodec:
|
51
|
+
return CompressionCodec(
|
52
|
+
name=name,
|
53
|
+
aliases=aliases,
|
54
|
+
|
55
|
+
input=bytes,
|
56
|
+
output=bytes,
|
57
|
+
|
58
|
+
new=lambda *args, **kwargs: CompressionEagerCodec(cls(*args, **kwargs)),
|
59
|
+
|
60
|
+
new_incremental=(
|
61
|
+
lambda *args, **kwargs: CompressionIncrementalCodec(cls(*args, **kwargs)) # noqa
|
62
|
+
) if issubclass(cls, IncrementalCompression) else None,
|
63
|
+
)
|
64
|
+
|
65
|
+
|
66
|
+
##
|
67
|
+
|
68
|
+
|
69
|
+
def make_compression_lazy_loaded_codec(
|
70
|
+
mod_name: str,
|
71
|
+
attr_name: str,
|
72
|
+
codec: CompressionCodec,
|
73
|
+
) -> codecs.LazyLoadedCodec:
|
74
|
+
return codecs.LazyLoadedCodec.new(
|
75
|
+
mod_name,
|
76
|
+
attr_name,
|
77
|
+
codec,
|
78
|
+
)
|
@@ -0,0 +1,350 @@
|
|
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
|
+
import dataclasses as dc
|
37
|
+
import functools
|
38
|
+
import os.path
|
39
|
+
import struct
|
40
|
+
import time
|
41
|
+
import typing as ta
|
42
|
+
|
43
|
+
from ... import cached
|
44
|
+
from ... import check
|
45
|
+
from ... import lang
|
46
|
+
from ..generators import BytesSteppedGenerator
|
47
|
+
from ..generators import BytesSteppedReaderGenerator
|
48
|
+
from ..generators.readers import PrependableBytesGeneratorReader
|
49
|
+
from .base import Compression
|
50
|
+
from .base import IncrementalCompression
|
51
|
+
from .codecs import make_compression_codec
|
52
|
+
from .codecs import make_compression_lazy_loaded_codec
|
53
|
+
|
54
|
+
|
55
|
+
if ta.TYPE_CHECKING:
|
56
|
+
import gzip
|
57
|
+
import zlib
|
58
|
+
else:
|
59
|
+
gzip = lang.proxy_import('gzip')
|
60
|
+
zlib = lang.proxy_import('zlib')
|
61
|
+
|
62
|
+
|
63
|
+
##
|
64
|
+
|
65
|
+
|
66
|
+
COMPRESS_LEVEL_FAST = 1
|
67
|
+
COMPRESS_LEVEL_TRADEOFF = 6
|
68
|
+
COMPRESS_LEVEL_BEST = 9
|
69
|
+
|
70
|
+
|
71
|
+
@dc.dataclass(frozen=True, kw_only=True)
|
72
|
+
class GzipCompression(Compression, IncrementalCompression):
|
73
|
+
level: int = COMPRESS_LEVEL_BEST
|
74
|
+
|
75
|
+
mtime: float | None = None
|
76
|
+
|
77
|
+
def compress(self, d: bytes) -> bytes:
|
78
|
+
return gzip.compress(
|
79
|
+
d,
|
80
|
+
self.level,
|
81
|
+
mtime=self.mtime,
|
82
|
+
)
|
83
|
+
|
84
|
+
def decompress(self, d: bytes) -> bytes:
|
85
|
+
return gzip.decompress(
|
86
|
+
d,
|
87
|
+
)
|
88
|
+
|
89
|
+
def compress_incremental(self) -> BytesSteppedGenerator[None]:
|
90
|
+
return lang.nextgen(IncrementalGzipCompressor(
|
91
|
+
level=self.level,
|
92
|
+
mtime=self.mtime,
|
93
|
+
)())
|
94
|
+
|
95
|
+
def decompress_incremental(self) -> BytesSteppedReaderGenerator[None]:
|
96
|
+
return IncrementalGzipDecompressor()()
|
97
|
+
|
98
|
+
|
99
|
+
##
|
100
|
+
|
101
|
+
|
102
|
+
@cached.function
|
103
|
+
def _zero_crc() -> int:
|
104
|
+
return zlib.crc32(b'')
|
105
|
+
|
106
|
+
|
107
|
+
##
|
108
|
+
|
109
|
+
|
110
|
+
class IncrementalGzipCompressor:
|
111
|
+
def __init__(
|
112
|
+
self,
|
113
|
+
*,
|
114
|
+
level: int = COMPRESS_LEVEL_BEST,
|
115
|
+
name: str | bytes | None = None,
|
116
|
+
mtime: float | None = None,
|
117
|
+
) -> None:
|
118
|
+
super().__init__()
|
119
|
+
|
120
|
+
self._name = name or ''
|
121
|
+
self._level = level
|
122
|
+
self._mtime = mtime
|
123
|
+
|
124
|
+
def _write_gzip_header(self) -> ta.Generator[bytes, None, None]:
|
125
|
+
check.none((yield b'\037\213')) # magic header
|
126
|
+
check.none((yield b'\010')) # compression method
|
127
|
+
|
128
|
+
try:
|
129
|
+
# RFC 1952 requires the FNAME field to be Latin-1. Do not include filenames that cannot be represented that
|
130
|
+
# way.
|
131
|
+
fname = os.path.basename(self._name)
|
132
|
+
if not isinstance(fname, bytes):
|
133
|
+
fname = fname.encode('latin-1')
|
134
|
+
if fname.endswith(b'.gz'):
|
135
|
+
fname = fname[:-3]
|
136
|
+
except UnicodeEncodeError:
|
137
|
+
fname = b''
|
138
|
+
|
139
|
+
flags = 0
|
140
|
+
if fname:
|
141
|
+
flags = gzip.FNAME
|
142
|
+
check.none((yield chr(flags).encode('latin-1')))
|
143
|
+
|
144
|
+
mtime = self._mtime
|
145
|
+
if mtime is None:
|
146
|
+
mtime = time.time()
|
147
|
+
check.none((yield struct.pack('<L', int(mtime))))
|
148
|
+
|
149
|
+
if self._level == COMPRESS_LEVEL_BEST:
|
150
|
+
xfl = b'\002'
|
151
|
+
elif self._level == COMPRESS_LEVEL_FAST:
|
152
|
+
xfl = b'\004'
|
153
|
+
else:
|
154
|
+
xfl = b'\000'
|
155
|
+
check.none((yield xfl))
|
156
|
+
|
157
|
+
check.none((yield b'\377'))
|
158
|
+
|
159
|
+
if fname:
|
160
|
+
check.none((yield fname + b'\000'))
|
161
|
+
|
162
|
+
def __call__(self) -> BytesSteppedGenerator:
|
163
|
+
crc = _zero_crc()
|
164
|
+
size = 0
|
165
|
+
offset = 0 # Current file offset for seek(), tell(), etc
|
166
|
+
wrote_header = False
|
167
|
+
|
168
|
+
compress = zlib.compressobj(
|
169
|
+
self._level,
|
170
|
+
zlib.DEFLATED,
|
171
|
+
-zlib.MAX_WBITS,
|
172
|
+
zlib.DEF_MEM_LEVEL,
|
173
|
+
0,
|
174
|
+
)
|
175
|
+
|
176
|
+
while True:
|
177
|
+
data: ta.Any = check.isinstance((yield None), bytes)
|
178
|
+
|
179
|
+
if not wrote_header:
|
180
|
+
yield from self._write_gzip_header()
|
181
|
+
wrote_header = True
|
182
|
+
|
183
|
+
if not data:
|
184
|
+
break
|
185
|
+
|
186
|
+
# Called by our self._buffer underlying BufferedWriterDelegate.
|
187
|
+
if isinstance(data, (bytes, bytearray)):
|
188
|
+
length = len(data)
|
189
|
+
else:
|
190
|
+
# accept any data that supports the buffer protocol
|
191
|
+
data = memoryview(data)
|
192
|
+
length = data.nbytes
|
193
|
+
|
194
|
+
if length > 0:
|
195
|
+
if (fl := compress.compress(data)):
|
196
|
+
check.none((yield fl))
|
197
|
+
size += length
|
198
|
+
crc = zlib.crc32(data, crc)
|
199
|
+
offset += length
|
200
|
+
|
201
|
+
if (fl := compress.flush()):
|
202
|
+
check.none((yield fl))
|
203
|
+
|
204
|
+
yield struct.pack('<L', crc)
|
205
|
+
# size may exceed 2 GiB, or even 4 GiB
|
206
|
+
yield struct.pack('<L', size & 0xffffffff)
|
207
|
+
|
208
|
+
yield b''
|
209
|
+
|
210
|
+
|
211
|
+
##
|
212
|
+
|
213
|
+
|
214
|
+
class IncrementalGzipDecompressor:
|
215
|
+
def __init__(self) -> None:
|
216
|
+
super().__init__()
|
217
|
+
|
218
|
+
self._factory = functools.partial(
|
219
|
+
zlib.decompressobj,
|
220
|
+
wbits=-zlib.MAX_WBITS,
|
221
|
+
)
|
222
|
+
|
223
|
+
def _read_gzip_header(
|
224
|
+
self,
|
225
|
+
rdr: PrependableBytesGeneratorReader,
|
226
|
+
) -> ta.Generator[int | None, bytes, int | None]:
|
227
|
+
magic = yield from rdr.read(2)
|
228
|
+
if magic == b'':
|
229
|
+
return None
|
230
|
+
|
231
|
+
if magic != b'\037\213':
|
232
|
+
raise gzip.BadGzipFile(f'Not a gzipped file ({magic!r})')
|
233
|
+
|
234
|
+
buf = yield from rdr.read(8)
|
235
|
+
method, flag, last_mtime = struct.unpack('<BBIxx', buf)
|
236
|
+
if method != 8:
|
237
|
+
raise gzip.BadGzipFile('Unknown compression method')
|
238
|
+
|
239
|
+
if flag & gzip.FEXTRA:
|
240
|
+
# Read & discard the extra field, if present
|
241
|
+
buf = yield from rdr.read(2)
|
242
|
+
extra_len, = struct.unpack('<H', buf)
|
243
|
+
if extra_len:
|
244
|
+
yield from rdr.read(extra_len)
|
245
|
+
|
246
|
+
if flag & gzip.FNAME:
|
247
|
+
# Read and discard a null-terminated string containing the filename
|
248
|
+
while True:
|
249
|
+
s = yield from rdr.read(1)
|
250
|
+
if not s or s == b'\000':
|
251
|
+
break
|
252
|
+
|
253
|
+
if flag & gzip.FCOMMENT:
|
254
|
+
# Read and discard a null-terminated string containing a comment
|
255
|
+
while True:
|
256
|
+
s = yield from rdr.read(1)
|
257
|
+
if not s or s == b'\000':
|
258
|
+
break
|
259
|
+
|
260
|
+
if flag & gzip.FHCRC:
|
261
|
+
yield from rdr.read(2) # Read & discard the 16-bit header CRC
|
262
|
+
|
263
|
+
return last_mtime
|
264
|
+
|
265
|
+
def _read_eof(
|
266
|
+
self,
|
267
|
+
rdr: PrependableBytesGeneratorReader,
|
268
|
+
crc: int,
|
269
|
+
stream_size: int,
|
270
|
+
) -> ta.Generator[int | None, bytes, None]:
|
271
|
+
# We've read to the end of the file.
|
272
|
+
# We check that the computed CRC and size of the uncompressed data matches the stored values. Note that the size
|
273
|
+
# stored is the true file size mod 2**32.
|
274
|
+
buf = yield from rdr.read(8)
|
275
|
+
crc32, isize = struct.unpack('<II', buf)
|
276
|
+
if crc32 != crc:
|
277
|
+
raise gzip.BadGzipFile(f'CRC check failed {hex(crc32)} != {hex(crc)}')
|
278
|
+
elif isize != (stream_size & 0xffffffff):
|
279
|
+
raise gzip.BadGzipFile('Incorrect length of data produced')
|
280
|
+
|
281
|
+
# Gzip files can be padded with zeroes and still have archives. Consume all zero bytes and set the file position
|
282
|
+
# to the first non-zero byte. See http://www.gzip.org/#faq8
|
283
|
+
c = b'\0'
|
284
|
+
while c == b'\0':
|
285
|
+
c = yield from rdr.read(1)
|
286
|
+
if c:
|
287
|
+
rdr.prepend(c)
|
288
|
+
|
289
|
+
def __call__(self) -> BytesSteppedReaderGenerator:
|
290
|
+
rdr = PrependableBytesGeneratorReader()
|
291
|
+
|
292
|
+
pos = 0 # Current offset in decompressed stream
|
293
|
+
|
294
|
+
crc = _zero_crc()
|
295
|
+
stream_size = 0 # Decompressed size of unconcatenated stream
|
296
|
+
new_member = True
|
297
|
+
|
298
|
+
decompressor = self._factory()
|
299
|
+
|
300
|
+
while True:
|
301
|
+
# For certain input data, a single call to decompress() may not return any data. In this case, retry until
|
302
|
+
# we get some data or reach EOF.
|
303
|
+
while True:
|
304
|
+
if decompressor.eof:
|
305
|
+
# Ending case: we've come to the end of a member in the file, so finish up this member, and read a
|
306
|
+
# new gzip header. Check the CRC and file size, and set the flag so we read a new member
|
307
|
+
yield from self._read_eof(rdr, crc, stream_size)
|
308
|
+
new_member = True
|
309
|
+
decompressor = self._factory()
|
310
|
+
|
311
|
+
if new_member:
|
312
|
+
# If the _new_member flag is set, we have to jump to the next member, if there is one.
|
313
|
+
crc = _zero_crc()
|
314
|
+
stream_size = 0 # Decompressed size of unconcatenated stream
|
315
|
+
last_mtime = yield from self._read_gzip_header(rdr)
|
316
|
+
if not last_mtime:
|
317
|
+
check.none((yield b''))
|
318
|
+
return
|
319
|
+
new_member = False
|
320
|
+
|
321
|
+
# Read a chunk of data from the file
|
322
|
+
if not decompressor.unconsumed_tail:
|
323
|
+
buf = yield from rdr.read(None)
|
324
|
+
uncompress = decompressor.decompress(buf)
|
325
|
+
else:
|
326
|
+
uncompress = decompressor.decompress(b'')
|
327
|
+
|
328
|
+
if decompressor.unused_data != b'':
|
329
|
+
# Prepend the already read bytes to the fileobj so they can be seen by _read_eof() and
|
330
|
+
# _read_gzip_header()
|
331
|
+
rdr.prepend(decompressor.unused_data)
|
332
|
+
|
333
|
+
if uncompress != b'':
|
334
|
+
break
|
335
|
+
if buf == b'': # noqa
|
336
|
+
raise EOFError('Compressed file ended before the end-of-stream marker was reached')
|
337
|
+
|
338
|
+
crc = zlib.crc32(uncompress, crc)
|
339
|
+
stream_size += len(uncompress)
|
340
|
+
pos += len(uncompress)
|
341
|
+
check.none((yield uncompress))
|
342
|
+
|
343
|
+
|
344
|
+
##
|
345
|
+
|
346
|
+
|
347
|
+
GZIP_CODEC = make_compression_codec('gzip', GzipCompression, aliases=['gz'])
|
348
|
+
|
349
|
+
# @omlish-manifest
|
350
|
+
_GZIP_LAZY_CODEC = make_compression_lazy_loaded_codec(__name__, 'GZIP_CODEC', GZIP_CODEC)
|
@@ -0,0 +1,91 @@
|
|
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
|
+
from .codecs import make_compression_codec
|
10
|
+
from .codecs import make_compression_lazy_loaded_codec
|
11
|
+
|
12
|
+
|
13
|
+
if ta.TYPE_CHECKING:
|
14
|
+
import lz4.frame as lz4_frame
|
15
|
+
else:
|
16
|
+
lz4_frame = lang.proxy_import('lz4.frame')
|
17
|
+
|
18
|
+
|
19
|
+
##
|
20
|
+
|
21
|
+
|
22
|
+
@dc.dataclass(frozen=True, kw_only=True)
|
23
|
+
class Lz4Compression(Compression, IncrementalCompression):
|
24
|
+
level: int = 0
|
25
|
+
|
26
|
+
block_size: int = 0
|
27
|
+
block_linked: bool = True
|
28
|
+
block_checksum: bool = False
|
29
|
+
content_checksum: bool = False
|
30
|
+
store_size: bool = True
|
31
|
+
auto_flush: bool = False
|
32
|
+
|
33
|
+
def compress(self, d: bytes) -> bytes:
|
34
|
+
return lz4_frame.compress(
|
35
|
+
d,
|
36
|
+
compression_level=self.level,
|
37
|
+
block_size=self.block_size,
|
38
|
+
content_checksum=self.content_checksum,
|
39
|
+
block_linked=self.block_linked,
|
40
|
+
store_size=self.store_size,
|
41
|
+
)
|
42
|
+
|
43
|
+
def decompress(self, d: bytes) -> bytes:
|
44
|
+
return lz4_frame.decompress(
|
45
|
+
d,
|
46
|
+
)
|
47
|
+
|
48
|
+
@lang.autostart
|
49
|
+
def compress_incremental(self) -> BytesSteppedGenerator[None]:
|
50
|
+
with lz4_frame.LZ4FrameCompressor(
|
51
|
+
compression_level=self.level,
|
52
|
+
block_size=self.block_size,
|
53
|
+
block_linked=self.block_linked,
|
54
|
+
block_checksum=self.block_checksum,
|
55
|
+
content_checksum=self.content_checksum,
|
56
|
+
auto_flush=self.auto_flush,
|
57
|
+
) as compressor:
|
58
|
+
started = False
|
59
|
+
while True:
|
60
|
+
i = check.isinstance((yield None), bytes)
|
61
|
+
if not started:
|
62
|
+
yield compressor.begin()
|
63
|
+
started = True
|
64
|
+
if not i:
|
65
|
+
yield compressor.flush()
|
66
|
+
yield b''
|
67
|
+
return
|
68
|
+
if (o := compressor.compress(i)):
|
69
|
+
yield o
|
70
|
+
|
71
|
+
@lang.autostart
|
72
|
+
def decompress_incremental(self) -> BytesSteppedGenerator[None]:
|
73
|
+
# lz4 lib does internal buffering so this is simply a BytesSteppedGenerator not a BytesSteppedReaderGenerator as
|
74
|
+
# it only yields None, accepting any number of bytes at a time.
|
75
|
+
with lz4_frame.LZ4FrameDecompressor() as decompressor:
|
76
|
+
while True:
|
77
|
+
i = check.isinstance((yield None), bytes)
|
78
|
+
if not i:
|
79
|
+
yield b''
|
80
|
+
return
|
81
|
+
if (o := decompressor.decompress(i)):
|
82
|
+
yield o
|
83
|
+
|
84
|
+
|
85
|
+
##
|
86
|
+
|
87
|
+
|
88
|
+
LZ4_CODEC = make_compression_codec('lz4', Lz4Compression)
|
89
|
+
|
90
|
+
# @omlish-manifest
|
91
|
+
_LZ4_LAZY_CODEC = make_compression_lazy_loaded_codec(__name__, 'LZ4_CODEC', LZ4_CODEC)
|
@@ -0,0 +1,81 @@
|
|
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 lzma
|
18
|
+
else:
|
19
|
+
lzma = lang.proxy_import('lzma')
|
20
|
+
|
21
|
+
|
22
|
+
##
|
23
|
+
|
24
|
+
|
25
|
+
@dc.dataclass(frozen=True, kw_only=True)
|
26
|
+
class LzmaCompression(Compression, IncrementalCompression):
|
27
|
+
format: int | None = None
|
28
|
+
|
29
|
+
check: int = -1
|
30
|
+
preset: int | None = None
|
31
|
+
filters: dict | None = None
|
32
|
+
|
33
|
+
mem_limit: int | None = None
|
34
|
+
|
35
|
+
def compress(self, d: bytes) -> bytes:
|
36
|
+
return lzma.compress(
|
37
|
+
d,
|
38
|
+
format=self.format if self.format is not None else lzma.FORMAT_XZ,
|
39
|
+
check=self.check,
|
40
|
+
preset=self.preset,
|
41
|
+
filters=self.filters, # type: ignore[arg-type]
|
42
|
+
)
|
43
|
+
|
44
|
+
def decompress(self, d: bytes) -> bytes:
|
45
|
+
return lzma.decompress(
|
46
|
+
d,
|
47
|
+
format=self.format if self.format is not None else lzma.FORMAT_AUTO,
|
48
|
+
memlimit=self.mem_limit,
|
49
|
+
filters=self.filters, # type: ignore[arg-type]
|
50
|
+
)
|
51
|
+
|
52
|
+
def compress_incremental(self) -> BytesSteppedGenerator[None]:
|
53
|
+
return lang.nextgen(CompressorObjectIncrementalAdapter(
|
54
|
+
functools.partial( # type: ignore
|
55
|
+
lzma.LZMACompressor,
|
56
|
+
format=self.format if self.format is not None else lzma.FORMAT_XZ,
|
57
|
+
check=self.check,
|
58
|
+
preset=self.preset,
|
59
|
+
filters=self.filters, # type: ignore[arg-type]
|
60
|
+
),
|
61
|
+
)())
|
62
|
+
|
63
|
+
def decompress_incremental(self) -> BytesSteppedReaderGenerator[None]:
|
64
|
+
return DecompressorObjectIncrementalAdapter(
|
65
|
+
functools.partial( # type: ignore
|
66
|
+
lzma.LZMADecompressor,
|
67
|
+
format=self.format if self.format is not None else lzma.FORMAT_AUTO,
|
68
|
+
memlimit=self.mem_limit,
|
69
|
+
filters=self.filters, # type: ignore[arg-type]
|
70
|
+
),
|
71
|
+
trailing_error=lzma.LZMAError,
|
72
|
+
)()
|
73
|
+
|
74
|
+
|
75
|
+
##
|
76
|
+
|
77
|
+
|
78
|
+
LZMA_CODEC = make_compression_codec('lzma', LzmaCompression)
|
79
|
+
|
80
|
+
# @omlish-manifest
|
81
|
+
_LZMA_LAZY_CODEC = make_compression_lazy_loaded_codec(__name__, 'LZMA_CODEC', LZMA_CODEC)
|
@@ -0,0 +1,34 @@
|
|
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 snappy
|
12
|
+
else:
|
13
|
+
snappy = lang.proxy_import('snappy')
|
14
|
+
|
15
|
+
|
16
|
+
##
|
17
|
+
|
18
|
+
|
19
|
+
@dc.dataclass(frozen=True)
|
20
|
+
class SnappyCompression(Compression):
|
21
|
+
def compress(self, d: bytes) -> bytes:
|
22
|
+
return snappy.compress(d)
|
23
|
+
|
24
|
+
def decompress(self, d: bytes) -> bytes:
|
25
|
+
return snappy.decompress(d)
|
26
|
+
|
27
|
+
|
28
|
+
##
|
29
|
+
|
30
|
+
|
31
|
+
SNAPPY_CODEC = make_compression_codec('snappy', SnappyCompression)
|
32
|
+
|
33
|
+
# @omlish-manifest
|
34
|
+
_SNAPPY_LAZY_CODEC = make_compression_lazy_loaded_codec(__name__, 'SNAPPY_CODEC', SNAPPY_CODEC)
|