FastWARC 1.0.2__tar.gz → 1.0.3__tar.gz
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.
- {fastwarc-1.0.2 → fastwarc-1.0.3}/FastWARC.egg-info/PKG-INFO +1 -1
- {fastwarc-1.0.2 → fastwarc-1.0.3}/PKG-INFO +1 -1
- {fastwarc-1.0.2 → fastwarc-1.0.3}/fastwarc/cli.py +31 -116
- {fastwarc-1.0.2 → fastwarc-1.0.3}/fastwarc/stream_io.pyi +8 -7
- {fastwarc-1.0.2 → fastwarc-1.0.3}/fastwarc/warc.pyi +1 -0
- {fastwarc-1.0.2 → fastwarc-1.0.3}/pyproject.toml +1 -1
- {fastwarc-1.0.2 → fastwarc-1.0.3}/FastWARC.egg-info/SOURCES.txt +0 -0
- {fastwarc-1.0.2 → fastwarc-1.0.3}/FastWARC.egg-info/dependency_links.txt +0 -0
- {fastwarc-1.0.2 → fastwarc-1.0.3}/FastWARC.egg-info/entry_points.txt +0 -0
- {fastwarc-1.0.2 → fastwarc-1.0.3}/FastWARC.egg-info/requires.txt +0 -0
- {fastwarc-1.0.2 → fastwarc-1.0.3}/FastWARC.egg-info/top_level.txt +0 -0
- {fastwarc-1.0.2 → fastwarc-1.0.3}/MANIFEST.in +0 -0
- {fastwarc-1.0.2 → fastwarc-1.0.3}/README.md +0 -0
- {fastwarc-1.0.2 → fastwarc-1.0.3}/fastwarc/__init__.py +0 -0
- {fastwarc-1.0.2 → fastwarc-1.0.3}/fastwarc/__init__.pyi +0 -0
- {fastwarc-1.0.2 → fastwarc-1.0.3}/fastwarc/legacy/__init__.pxd +0 -0
- {fastwarc-1.0.2 → fastwarc-1.0.3}/fastwarc/legacy/__init__.py +0 -0
- {fastwarc-1.0.2 → fastwarc-1.0.3}/fastwarc/legacy/__init__.pyi +0 -0
- {fastwarc-1.0.2 → fastwarc-1.0.3}/fastwarc/legacy/_shims.py +0 -0
- {fastwarc-1.0.2 → fastwarc-1.0.3}/fastwarc/legacy/stream_io.pxd +0 -0
- {fastwarc-1.0.2 → fastwarc-1.0.3}/fastwarc/legacy/stream_io.pyi +0 -0
- {fastwarc-1.0.2 → fastwarc-1.0.3}/fastwarc/legacy/stream_io.pyx +0 -0
- {fastwarc-1.0.2 → fastwarc-1.0.3}/fastwarc/legacy/tools.pyi +0 -0
- {fastwarc-1.0.2 → fastwarc-1.0.3}/fastwarc/legacy/tools.pyx +0 -0
- {fastwarc-1.0.2 → fastwarc-1.0.3}/fastwarc/legacy/warc.pxd +0 -0
- {fastwarc-1.0.2 → fastwarc-1.0.3}/fastwarc/legacy/warc.pyi +0 -0
- {fastwarc-1.0.2 → fastwarc-1.0.3}/fastwarc/legacy/warc.pyx +0 -0
- {fastwarc-1.0.2 → fastwarc-1.0.3}/fastwarc/py.typed +0 -0
- {fastwarc-1.0.2 → fastwarc-1.0.3}/resiliparse_common/__init__.pxd +0 -0
- {fastwarc-1.0.2 → fastwarc-1.0.3}/resiliparse_common/string_util.pxd +0 -0
- {fastwarc-1.0.2 → fastwarc-1.0.3}/resiliparse_inc/__init__.pxd +0 -0
- {fastwarc-1.0.2 → fastwarc-1.0.3}/resiliparse_inc/algorithm.pxd +0 -0
- {fastwarc-1.0.2 → fastwarc-1.0.3}/resiliparse_inc/atomic.pxd +0 -0
- {fastwarc-1.0.2 → fastwarc-1.0.3}/resiliparse_inc/boost_regex.pxd +0 -0
- {fastwarc-1.0.2 → fastwarc-1.0.3}/resiliparse_inc/cctype.pxd +0 -0
- {fastwarc-1.0.2 → fastwarc-1.0.3}/resiliparse_inc/cstdlib.pxd +0 -0
- {fastwarc-1.0.2 → fastwarc-1.0.3}/resiliparse_inc/cstring.pxd +0 -0
- {fastwarc-1.0.2 → fastwarc-1.0.3}/resiliparse_inc/dlfcn.pxd +0 -0
- {fastwarc-1.0.2 → fastwarc-1.0.3}/resiliparse_inc/errno.pxd +0 -0
- {fastwarc-1.0.2 → fastwarc-1.0.3}/resiliparse_inc/lexbor.pxd +0 -0
- {fastwarc-1.0.2 → fastwarc-1.0.3}/resiliparse_inc/lz4frame.pxd +0 -0
- {fastwarc-1.0.2 → fastwarc-1.0.3}/resiliparse_inc/lz4hc.pxd +0 -0
- {fastwarc-1.0.2 → fastwarc-1.0.3}/resiliparse_inc/pthread.pxd +0 -0
- {fastwarc-1.0.2 → fastwarc-1.0.3}/resiliparse_inc/re2.pxd +0 -0
- {fastwarc-1.0.2 → fastwarc-1.0.3}/resiliparse_inc/stdio.pxd +0 -0
- {fastwarc-1.0.2 → fastwarc-1.0.3}/resiliparse_inc/string_view.pxd +0 -0
- {fastwarc-1.0.2 → fastwarc-1.0.3}/resiliparse_inc/time.pxd +0 -0
- {fastwarc-1.0.2 → fastwarc-1.0.3}/resiliparse_inc/uchardet.pxd +0 -0
- {fastwarc-1.0.2 → fastwarc-1.0.3}/resiliparse_inc/unistd.pxd +0 -0
- {fastwarc-1.0.2 → fastwarc-1.0.3}/resiliparse_inc/utility.pxd +0 -0
- {fastwarc-1.0.2 → fastwarc-1.0.3}/resiliparse_inc/zlib.pxd +0 -0
- {fastwarc-1.0.2 → fastwarc-1.0.3}/setup.cfg +0 -0
- {fastwarc-1.0.2 → fastwarc-1.0.3}/setup.py +0 -0
|
@@ -14,7 +14,6 @@
|
|
|
14
14
|
|
|
15
15
|
import getpass
|
|
16
16
|
import importlib
|
|
17
|
-
from enum import IntFlag
|
|
18
17
|
from itertools import chain
|
|
19
18
|
import json
|
|
20
19
|
import os
|
|
@@ -25,13 +24,14 @@ import urllib.request
|
|
|
25
24
|
import click
|
|
26
25
|
from tqdm import tqdm
|
|
27
26
|
|
|
28
|
-
from fastwarc.stream_io import
|
|
27
|
+
from fastwarc.stream_io import FileStream, StreamError, FastWARCError, PythonIOStreamAdapter
|
|
29
28
|
from fastwarc.warc import ArchiveIterator, WarcRecordType
|
|
30
|
-
from fastwarc.legacy.tools import CompressionAlg, detect_compression_algorithm, wrap_warc_stream,
|
|
29
|
+
from fastwarc.legacy.tools import CompressionAlg, detect_compression_algorithm, wrap_warc_stream, \
|
|
30
|
+
recompress_warc_interactive, verify_digests
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
def exception_handler(exctype, value, _):
|
|
34
|
-
if exctype ==
|
|
34
|
+
if exctype == FastWARCError:
|
|
35
35
|
click.echo(str(value), err=True)
|
|
36
36
|
sys.exit(1)
|
|
37
37
|
|
|
@@ -56,132 +56,46 @@ def _human_readable_bytes(byte_num):
|
|
|
56
56
|
byte_num /= 1024
|
|
57
57
|
|
|
58
58
|
|
|
59
|
-
class CompressionAlg(IntFlag):
|
|
60
|
-
UNCOMPRESSED = 0
|
|
61
|
-
GZIP = 1
|
|
62
|
-
ZSTD = 2
|
|
63
|
-
LZ4 = 3
|
|
64
|
-
AUTO = 65535
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
def detect_compression_algorithm(infile):
|
|
68
|
-
"""
|
|
69
|
-
Try to detect the used compression algorithm from the given filename.
|
|
70
|
-
|
|
71
|
-
:param infile: filename or file object
|
|
72
|
-
:return: compression algorithm
|
|
73
|
-
"""
|
|
74
|
-
|
|
75
|
-
if os.fspath(infile):
|
|
76
|
-
infile = str(infile)
|
|
77
|
-
elif hasattr(infile, 'name'):
|
|
78
|
-
infile = infile.name
|
|
79
|
-
else:
|
|
80
|
-
raise ValueError('Invalid infile type.')
|
|
81
|
-
|
|
82
|
-
if type(infile) is str:
|
|
83
|
-
if infile.endswith('.gz'):
|
|
84
|
-
return CompressionAlg.GZIP
|
|
85
|
-
if infile.endswith('.zst'):
|
|
86
|
-
return CompressionAlg.ZSTD
|
|
87
|
-
if infile.endswith('.lz4'):
|
|
88
|
-
return CompressionAlg.LZ4
|
|
89
|
-
if infile.endswith('.warc'):
|
|
90
|
-
return CompressionAlg.UNCOMPRESSED
|
|
91
|
-
|
|
92
|
-
if not os.path.isfile(infile):
|
|
93
|
-
raise click.UsageError('Could not determine compression algorithm.')
|
|
94
|
-
|
|
95
|
-
with open(infile, 'rb') as infile:
|
|
96
|
-
magic_bytes = infile.read(5)
|
|
97
|
-
|
|
98
|
-
if magic_bytes[:3] == b'\x1F\x8B\x08':
|
|
99
|
-
return CompressionAlg.GZIP
|
|
100
|
-
elif magic_bytes[:4] == b'\x28\xB5\x2F\xFD' or magic_bytes[:4] == b'\x5D\x2A\x4D\x18':
|
|
101
|
-
return CompressionAlg.ZSTD
|
|
102
|
-
elif magic_bytes[:4] == b'\x04\x22\x4D\x18':
|
|
103
|
-
return CompressionAlg.LZ4
|
|
104
|
-
elif magic_bytes == b'WARC/':
|
|
105
|
-
return CompressionAlg.UNCOMPRESSED
|
|
106
|
-
|
|
107
|
-
raise click.FileError('No compression algorithm detected.')
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
def get_compressor(filename, alg, level):
|
|
111
|
-
if alg == CompressionAlg.AUTO:
|
|
112
|
-
alg = detect_compression_algorithm(filename)
|
|
113
|
-
if alg == CompressionAlg.UNCOMPRESSED:
|
|
114
|
-
return open(filename, 'wb')
|
|
115
|
-
elif alg == CompressionAlg.GZIP:
|
|
116
|
-
return GzipWriter(filename, compression_level=level or 9)
|
|
117
|
-
elif alg == CompressionAlg.ZSTD:
|
|
118
|
-
return ZstdWriter(filename, compression_level=level or 3)
|
|
119
|
-
elif alg == CompressionAlg.LZ4:
|
|
120
|
-
return Lz4Writer(filename) # compression_level currently unsupported
|
|
121
|
-
else:
|
|
122
|
-
raise ValueError(f'Unknown compression algorithm: {alg}')
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
def get_decompressor(filename, decompress_alg):
|
|
126
|
-
if os.fspath(filename) and not decompress_alg:
|
|
127
|
-
# Use plain filename to avoid Python IO stack
|
|
128
|
-
return str(filename)
|
|
129
|
-
|
|
130
|
-
if decompress_alg:
|
|
131
|
-
alg = decompress_alg
|
|
132
|
-
else:
|
|
133
|
-
alg = detect_compression_algorithm(filename)
|
|
134
|
-
if alg == CompressionAlg.UNCOMPRESSED:
|
|
135
|
-
return open(filename, 'rb')
|
|
136
|
-
if alg == CompressionAlg.GZIP:
|
|
137
|
-
return GzipReader(filename)
|
|
138
|
-
if alg == CompressionAlg.ZSTD:
|
|
139
|
-
return ZstdReader(filename)
|
|
140
|
-
if alg == CompressionAlg.LZ4:
|
|
141
|
-
return Lz4Reader(filename) # compression_level currently unsupported
|
|
142
|
-
|
|
143
|
-
raise ValueError(f'Unknown compression algorithm: {alg}')
|
|
144
|
-
|
|
145
|
-
|
|
146
59
|
@main.command()
|
|
147
60
|
@click.argument('infile', type=click.Path(dir_okay=False, exists=True))
|
|
148
61
|
@click.argument('outfile', type=click.Path(dir_okay=False, exists=False))
|
|
149
|
-
@click.option('-c', '--compress-alg', type=click.Choice(['
|
|
62
|
+
@click.option('-c', '--compress-alg', type=click.Choice(['gzip', 'lz4', 'uncompressed', 'auto']),
|
|
150
63
|
default='auto', show_default=True, help='Compression algorithm to use for output file')
|
|
151
|
-
@click.option('-d', '--decompress-alg', type=click.Choice(['
|
|
64
|
+
@click.option('-d', '--decompress-alg', type=click.Choice(['gzip', 'lz4', 'uncompressed', 'auto']),
|
|
152
65
|
default='auto', show_default=True,
|
|
153
66
|
help='Decompression algorithm for decoding input file (auto tries to detect based on file extension)')
|
|
154
|
-
@click.option('-l', '--compress-level', type=int, default=None, help='Compression level')
|
|
67
|
+
@click.option('-l', '--compress-level', type=int, default=None, help='Compression level (defaults to max)')
|
|
155
68
|
@click.option('-q', '--quiet', is_flag=True, help='Do not print progress information')
|
|
156
69
|
def recompress(infile, outfile, compress_alg, decompress_alg, compress_level, quiet):
|
|
157
70
|
"""
|
|
158
71
|
Recompress a WARC file.
|
|
159
72
|
|
|
160
|
-
This command allows you to recompress a WARC file if it is uncompressed
|
|
161
|
-
properly at the record-level
|
|
73
|
+
This command allows you to recompress a WARC file if it is uncompressed or not compressed
|
|
74
|
+
properly at the record-level if or you want to recompress a GZip WARC as LZ4 or vice versa.
|
|
162
75
|
"""
|
|
163
76
|
|
|
164
|
-
compress_alg = getattr(CompressionAlg, compress_alg
|
|
165
|
-
decompress_alg = getattr(CompressionAlg, decompress_alg
|
|
77
|
+
compress_alg = getattr(CompressionAlg, compress_alg)
|
|
78
|
+
decompress_alg = getattr(CompressionAlg, decompress_alg)
|
|
166
79
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
80
|
+
comp_args = {}
|
|
81
|
+
if compress_level is None:
|
|
82
|
+
if compress_alg == CompressionAlg.gzip:
|
|
83
|
+
comp_args['compression_level'] = 9
|
|
84
|
+
elif compress_alg == CompressionAlg.lz4:
|
|
85
|
+
comp_args['compression_level'] = 12
|
|
170
86
|
|
|
87
|
+
bytes_written = 0
|
|
171
88
|
num = 0
|
|
172
|
-
start = time.
|
|
89
|
+
start = time.time()
|
|
173
90
|
try:
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
r.write(out)
|
|
180
|
-
if compress_alg != CompressionAlg.UNCOMPRESSED:
|
|
181
|
-
out.finish()
|
|
91
|
+
for _, b in tqdm(recompress_warc_interactive(infile, outfile, decompress_alg, compress_alg, **comp_args),
|
|
92
|
+
desc='Recompressing WARC file', unit=' record(s)', leave=False,
|
|
93
|
+
disable=quiet, mininterval=0.2):
|
|
94
|
+
num += 1
|
|
95
|
+
bytes_written += b
|
|
182
96
|
|
|
183
|
-
|
|
184
|
-
|
|
97
|
+
if not quiet:
|
|
98
|
+
click.echo('Recompression completed.')
|
|
185
99
|
except KeyboardInterrupt:
|
|
186
100
|
if not quiet:
|
|
187
101
|
click.echo('Recompression aborted.')
|
|
@@ -189,8 +103,8 @@ def recompress(infile, outfile, compress_alg, decompress_alg, compress_level, qu
|
|
|
189
103
|
finally:
|
|
190
104
|
if not quiet and num > 0:
|
|
191
105
|
click.echo(f' - Records recompressed: {num}')
|
|
192
|
-
click.echo(f' - Bytes written: {_human_readable_bytes(
|
|
193
|
-
click.echo(f' - Completed in: {time.
|
|
106
|
+
click.echo(f' - Bytes written: {_human_readable_bytes(bytes_written)}')
|
|
107
|
+
click.echo(f' - Completed in: {time.time() - start:.02f} seconds')
|
|
194
108
|
|
|
195
109
|
|
|
196
110
|
@main.command()
|
|
@@ -525,8 +439,9 @@ def benchmark(input_url, decompress_alg, endpoint_url, aws_access_key, aws_secre
|
|
|
525
439
|
return num, time.monotonic() - start, interrupted
|
|
526
440
|
|
|
527
441
|
def _fastwarc_iterator(f):
|
|
528
|
-
s = _get_raw_stream_from_url(f, use_python_stream)
|
|
529
|
-
s = wrap_warc_stream(s, 'rb', decompress_alg)
|
|
442
|
+
# s = _get_raw_stream_from_url(f, use_python_stream)
|
|
443
|
+
# s = wrap_warc_stream(s, 'rb', decompress_alg)
|
|
444
|
+
s = '/home/roce3528/code-in-progress/code-research/web-search/chatnoir/chatnoir-resiliparse/tmpfs/CC-MAIN-20231005012006-20231005042006-00899.warc'
|
|
530
445
|
return ArchiveIterator(s, rec_type_filter, parse_http=parse_http, verify_digests=verify_digests)
|
|
531
446
|
|
|
532
447
|
n, t_fastwarc, interrupted = _bench(input_url, _fastwarc_iterator, 'FastWARC')
|
|
@@ -128,18 +128,19 @@ _WriterInput = WarcWriter | BinaryIO | _GenericWriter | PathLike[str] | str
|
|
|
128
128
|
|
|
129
129
|
@disjoint_base
|
|
130
130
|
class GzipReader(WarcReader):
|
|
131
|
-
def __new__(cls, inner: _ReaderInput, buffer_size: int =
|
|
131
|
+
def __new__(cls, inner: _ReaderInput, buffer_size: int = 64 << 10, zlib: bool = False,
|
|
132
|
+
fsspec_args=None) -> Self: ...
|
|
132
133
|
|
|
133
134
|
|
|
134
135
|
@disjoint_base
|
|
135
136
|
class GzipWriter(WarcWriter):
|
|
136
|
-
def __new__(cls, inner: _WriterInput, compression_level: int = 9, buffer_size=8192, zlib=False,
|
|
137
|
+
def __new__(cls, inner: _WriterInput, compression_level: int = 9, buffer_size: int = 8192, zlib=False,
|
|
137
138
|
fsspec_args=None) -> Self: ...
|
|
138
139
|
|
|
139
140
|
|
|
140
141
|
@disjoint_base
|
|
141
142
|
class ZstdReader(WarcReader):
|
|
142
|
-
def __new__(cls, inner: _ReaderInput, buffer_size: int =
|
|
143
|
+
def __new__(cls, inner: _ReaderInput, buffer_size: int = 64 << 10, fsspec_args=None,
|
|
143
144
|
dictionary: bytes | None = None) -> Self: ...
|
|
144
145
|
|
|
145
146
|
|
|
@@ -151,7 +152,7 @@ class ZstdWriter(WarcWriter):
|
|
|
151
152
|
|
|
152
153
|
@disjoint_base
|
|
153
154
|
class Lz4Reader(WarcReader):
|
|
154
|
-
def __new__(cls, inner: _ReaderInput, buffer_size: int =
|
|
155
|
+
def __new__(cls, inner: _ReaderInput, buffer_size: int = 64 << 10, fsspec_args=None) -> Self: ...
|
|
155
156
|
|
|
156
157
|
|
|
157
158
|
@disjoint_base
|
|
@@ -161,7 +162,7 @@ class Lz4Writer(WarcWriter):
|
|
|
161
162
|
|
|
162
163
|
@disjoint_base
|
|
163
164
|
class BrotliReader(WarcReader):
|
|
164
|
-
def __new__(cls, inner: _ReaderInput, buffer_size: int =
|
|
165
|
+
def __new__(cls, inner: _ReaderInput, buffer_size: int = 64 << 10, fsspec_args=None) -> Self: ...
|
|
165
166
|
|
|
166
167
|
|
|
167
168
|
@disjoint_base
|
|
@@ -171,12 +172,12 @@ class BrotliWriter(WarcWriter):
|
|
|
171
172
|
|
|
172
173
|
@disjoint_base
|
|
173
174
|
class ChunkedReader(WarcReader):
|
|
174
|
-
def __new__(cls, inner: _ReaderInput, buffer_size: int =
|
|
175
|
+
def __new__(cls, inner: _ReaderInput, buffer_size: int = 4096, fsspec_args=None) -> Self: ...
|
|
175
176
|
|
|
176
177
|
|
|
177
178
|
@disjoint_base
|
|
178
179
|
class ChunkedWriter(WarcWriter):
|
|
179
|
-
def __new__(cls, inner: _WriterInput, min_chunk_size: int =
|
|
180
|
+
def __new__(cls, inner: _WriterInput, min_chunk_size: int = 1024, fsspec_args=None) -> Self: ...
|
|
180
181
|
|
|
181
182
|
|
|
182
183
|
def zstd_train_dictionary_from_continuous(sample_data: bytes, sample_sizes: list[int], max_size: int) -> bytes: ...
|
|
@@ -333,6 +333,7 @@ class ArchiveIterator(Iterable[WarcRecord]):
|
|
|
333
333
|
quirks_mode: bool = False,
|
|
334
334
|
auto_decode: Literal['none', 'content', 'transfer', 'all'] = 'none',
|
|
335
335
|
stream_detect: bool = True,
|
|
336
|
+
buffer_size: int = 64 << 10,
|
|
336
337
|
fsspec_args=None,
|
|
337
338
|
*,
|
|
338
339
|
strict_mode: bool = True
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|