pseek 3.1.1__tar.gz → 3.2.0__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pseek
3
- Version: 3.1.1
3
+ Version: 3.2.0
4
4
  Summary: Pseek is a Python CLI toolkit to search files, folders, and text
5
5
  Author: Groot
6
6
  License-Expression: MIT
@@ -112,12 +112,14 @@ psk -- --path
112
112
  | `--re-include`, `--re-exclude` | Limit search results to specific directories or files with regex |
113
113
  | `--word` | Match the whole word only (except when `--expr` is enabled, in which case you can make it match whole word by putting `w` before term: `w"foo"`) |
114
114
  | `--expr` | Enable boolean query expressions. Example: `r"foo.*bar" and ("bar" or "baz") and not "qux"`. Prefixes: `r=regex`, `c=case-sensitive`, `w=whole-word`, `f=fuzzy` |
115
+ | `--context` | Show N context lines before and after matches, or use N:M to specify before:after |
116
+ | `--depth` | Limit directory traversal to given depth range. By default, there is no limit on search depth |
115
117
  | `--timeout` | Stop the search after the specified number of seconds |
116
118
  | `--fuzzy` | Enable fuzzy search (Highlighting and counting matches are disabled in this mode if `--word` is not enabled to prevent the program from slowing down). except when `--expr` is enabled, in which case you can make it fuzzy by putting `f` before term: `f"foo"` |
117
119
  | `--fuzzy-level` | Fuzzy matching threshold (0-99). Higher values require closer matches (default: `80`) |
118
120
  | `--size` | Limit results based on the size of files |
119
121
  | `--archive` | Enable search within archive files (e.g. `zip`, `rar`, `7z`, `gz`, `bz2`, `xz`, `tar`, `tar.gz`, `tar.bz2`, `tar.xz`) |
120
- | `--depth` | Maximum nested archive depth. Example: 2 allows searching up to two archive levels |
122
+ | `--arc-depth` | Limit nested archive to given depth range. By default, there is no limit |
121
123
  | `--arc-ext`, `--arc-exc-ext` | Filter by file extension inside archive files |
122
124
  | `--arc-include`, `--arc-exclude` | Limit search results to specific set of directories or files inside archive files |
123
125
  | `--arc-size` | Limit results based on the size of files in the archive |
@@ -176,7 +178,7 @@ Example:
176
178
  psk "hello world"
177
179
  ```
178
180
 
179
- **Note:** To use case-sensitive, whole-word matching, regular expression search, and fuzzy search when `--expr` is enabled, we can use [expression prefixes](#expression-prefixes).
181
+ > **Note:** To use case-sensitive, whole-word matching, regular expression search, and fuzzy search when `--expr` is enabled, we can use [expression prefixes](#expression-prefixes).
180
182
 
181
183
  ### Case Sensitive Search
182
184
 
@@ -364,7 +366,51 @@ simultaneously.
364
366
 
365
367
  Allowed modes: `r`, `c`, `w`, `f`, `rc`, `cr`, `cw`, `wc`, `cf`, `fc`, `wf`, `fw`, `cwf`, `cfw`, `wcf`, `wfc`, `fcw`, `fwc`
366
368
 
367
- **Note:** Whole word matching and regex matching cannot be used at the same time, because we can use `\b` in regex to enable whole word matching: `r"\btext\b"`
369
+ > **Note:** Whole word matching and regex matching cannot be used at the same time, because we can use `\b` in regex to enable whole word matching: `r"\btext\b"`
370
+
371
+ ## Context
372
+
373
+ Show context lines around each match. The value is specified as `BEFORE:AFTER`:
374
+
375
+ ```bash
376
+ --context 2 # 2 lines before and after
377
+ --context 2:0 # 2 lines before, none after
378
+ --context 0:2 # none before, 2 lines after
379
+ --context 2:5 # 2 lines before, 5 lines after
380
+ --context 2: # 2 lines before, none after
381
+ --context :2 # none before, 2 lines after
382
+ --context 0 # matching lines only
383
+ ```
384
+
385
+ Nearby matches whose context ranges overlap or directly touch are combined into a single group.
386
+
387
+ ## Depth
388
+
389
+ Controls how deep the search goes inside directories.
390
+
391
+ A depth of `0` means that only base path's immediate contents are searched; subdirectories are not entered.
392
+
393
+ ```text
394
+ project/ ← base directory
395
+ ├── file.txt ← depth 0
396
+ ├── folder1/ ← depth 0
397
+ │ ├── file.txt ← depth 1
398
+ │ └── folder2/ ← depth 1
399
+ │ └── file.txt ← depth 2
400
+ ```
401
+
402
+ `--depth` can be specified multiple times to search non-contiguous depth ranges:
403
+
404
+ ```bash
405
+ --depth 0 # Direct contents only
406
+ --depth 1 # One level inside
407
+ --depth 2:4 # Depths 2 through 4
408
+ --depth 2 --depth 5:7 # Depths 2 and 5 through 7
409
+ --depth :2 # Depths 0 through 2
410
+ --depth 3: # Depth 3 and deeper
411
+ ```
412
+
413
+ If `--depth` is not specified, the search has no depth limit.
368
414
 
369
415
  ## Extension Filters
370
416
 
@@ -402,7 +448,7 @@ psk TODO \
402
448
 
403
449
  Skip those paths.
404
450
 
405
- **Note:** The include and exclude paths will be combined with path argument.
451
+ > **Note:** The include and exclude paths will be combined with path argument.
406
452
 
407
453
  ## Regex Path Filters
408
454
 
@@ -455,7 +501,7 @@ psk config \
455
501
 
456
502
  Files between `1 MiB` and `10 MiB` will not match.
457
503
 
458
- **Note:** Directory sizes are not calculated recursively. When `--size` is used, directories are automatically excluded from the search results.
504
+ > **Note:** Directory sizes are not calculated recursively. When `--size` is used, directories are automatically excluded from the search results.
459
505
 
460
506
  ## Archive Search
461
507
 
@@ -487,15 +533,24 @@ backup.zip::source.7z::notes.txt
487
533
 
488
534
  ### Archive Depth
489
535
 
490
- Limit recursion depth:
536
+ The concept of depth in archive is different from `--depth`. Depth in archive is calculated based on nested archives. Each archive that is inside another archive counts as one level of depth.
537
+
538
+ | Syntax | Meaning |
539
+ | ------ | -------------------------------------------------------- |
540
+ | `2` | exactly `2nd` depth |
541
+ | `:2` | `2nd` depth or lower |
542
+ | `2:` | `2nd` depth or higher |
543
+ | `2:4` | between `2` and `4` (Both range boundaries are included) |
544
+
545
+ `--arc-depth` can be specified multiple times:
491
546
 
492
547
  ```bash
493
- psk TODO --archive --depth 2
548
+ psk TODO --archive --arc-depth :2 --arc-depth 5:
494
549
  ```
495
550
 
496
- Meaning `archive level 1` and `archive level 2` will be searched. Deeper levels will be skipped.
551
+ Meaning `archive level 3` and `archive level 4` won't be searched.
497
552
 
498
- **Note:** `--depth 0` means perform the search only within this current archive and don't enter nested archives.
553
+ > **Note:** `--arc-depth 0` means perform the search only within this current archive and don't enter nested archives.
499
554
 
500
555
  ## Archive Filters
501
556
 
@@ -535,7 +590,7 @@ This works exactly like the [--size](#size-filtering) option.
535
590
  psk TODO --archive --arc-size 10m:40m
536
591
  ```
537
592
 
538
- **Note:** Archive directory sizes are usually reported as zero by archive formats, so directory search is disabled if this filter is enabled to avoid incorrect results.
593
+ > **Note:** Archive directory sizes are usually reported as zero by archive formats, so directory search is disabled if this filter is enabled to avoid incorrect results.
539
594
 
540
595
  ## RAR Backend
541
596
 
@@ -83,12 +83,14 @@ psk -- --path
83
83
  | `--re-include`, `--re-exclude` | Limit search results to specific directories or files with regex |
84
84
  | `--word` | Match the whole word only (except when `--expr` is enabled, in which case you can make it match whole word by putting `w` before term: `w"foo"`) |
85
85
  | `--expr` | Enable boolean query expressions. Example: `r"foo.*bar" and ("bar" or "baz") and not "qux"`. Prefixes: `r=regex`, `c=case-sensitive`, `w=whole-word`, `f=fuzzy` |
86
+ | `--context` | Show N context lines before and after matches, or use N:M to specify before:after |
87
+ | `--depth` | Limit directory traversal to given depth range. By default, there is no limit on search depth |
86
88
  | `--timeout` | Stop the search after the specified number of seconds |
87
89
  | `--fuzzy` | Enable fuzzy search (Highlighting and counting matches are disabled in this mode if `--word` is not enabled to prevent the program from slowing down). except when `--expr` is enabled, in which case you can make it fuzzy by putting `f` before term: `f"foo"` |
88
90
  | `--fuzzy-level` | Fuzzy matching threshold (0-99). Higher values require closer matches (default: `80`) |
89
91
  | `--size` | Limit results based on the size of files |
90
92
  | `--archive` | Enable search within archive files (e.g. `zip`, `rar`, `7z`, `gz`, `bz2`, `xz`, `tar`, `tar.gz`, `tar.bz2`, `tar.xz`) |
91
- | `--depth` | Maximum nested archive depth. Example: 2 allows searching up to two archive levels |
93
+ | `--arc-depth` | Limit nested archive to given depth range. By default, there is no limit |
92
94
  | `--arc-ext`, `--arc-exc-ext` | Filter by file extension inside archive files |
93
95
  | `--arc-include`, `--arc-exclude` | Limit search results to specific set of directories or files inside archive files |
94
96
  | `--arc-size` | Limit results based on the size of files in the archive |
@@ -147,7 +149,7 @@ Example:
147
149
  psk "hello world"
148
150
  ```
149
151
 
150
- **Note:** To use case-sensitive, whole-word matching, regular expression search, and fuzzy search when `--expr` is enabled, we can use [expression prefixes](#expression-prefixes).
152
+ > **Note:** To use case-sensitive, whole-word matching, regular expression search, and fuzzy search when `--expr` is enabled, we can use [expression prefixes](#expression-prefixes).
151
153
 
152
154
  ### Case Sensitive Search
153
155
 
@@ -335,7 +337,51 @@ simultaneously.
335
337
 
336
338
  Allowed modes: `r`, `c`, `w`, `f`, `rc`, `cr`, `cw`, `wc`, `cf`, `fc`, `wf`, `fw`, `cwf`, `cfw`, `wcf`, `wfc`, `fcw`, `fwc`
337
339
 
338
- **Note:** Whole word matching and regex matching cannot be used at the same time, because we can use `\b` in regex to enable whole word matching: `r"\btext\b"`
340
+ > **Note:** Whole word matching and regex matching cannot be used at the same time, because we can use `\b` in regex to enable whole word matching: `r"\btext\b"`
341
+
342
+ ## Context
343
+
344
+ Show context lines around each match. The value is specified as `BEFORE:AFTER`:
345
+
346
+ ```bash
347
+ --context 2 # 2 lines before and after
348
+ --context 2:0 # 2 lines before, none after
349
+ --context 0:2 # none before, 2 lines after
350
+ --context 2:5 # 2 lines before, 5 lines after
351
+ --context 2: # 2 lines before, none after
352
+ --context :2 # none before, 2 lines after
353
+ --context 0 # matching lines only
354
+ ```
355
+
356
+ Nearby matches whose context ranges overlap or directly touch are combined into a single group.
357
+
358
+ ## Depth
359
+
360
+ Controls how deep the search goes inside directories.
361
+
362
+ A depth of `0` means that only base path's immediate contents are searched; subdirectories are not entered.
363
+
364
+ ```text
365
+ project/ ← base directory
366
+ ├── file.txt ← depth 0
367
+ ├── folder1/ ← depth 0
368
+ │ ├── file.txt ← depth 1
369
+ │ └── folder2/ ← depth 1
370
+ │ └── file.txt ← depth 2
371
+ ```
372
+
373
+ `--depth` can be specified multiple times to search non-contiguous depth ranges:
374
+
375
+ ```bash
376
+ --depth 0 # Direct contents only
377
+ --depth 1 # One level inside
378
+ --depth 2:4 # Depths 2 through 4
379
+ --depth 2 --depth 5:7 # Depths 2 and 5 through 7
380
+ --depth :2 # Depths 0 through 2
381
+ --depth 3: # Depth 3 and deeper
382
+ ```
383
+
384
+ If `--depth` is not specified, the search has no depth limit.
339
385
 
340
386
  ## Extension Filters
341
387
 
@@ -373,7 +419,7 @@ psk TODO \
373
419
 
374
420
  Skip those paths.
375
421
 
376
- **Note:** The include and exclude paths will be combined with path argument.
422
+ > **Note:** The include and exclude paths will be combined with path argument.
377
423
 
378
424
  ## Regex Path Filters
379
425
 
@@ -426,7 +472,7 @@ psk config \
426
472
 
427
473
  Files between `1 MiB` and `10 MiB` will not match.
428
474
 
429
- **Note:** Directory sizes are not calculated recursively. When `--size` is used, directories are automatically excluded from the search results.
475
+ > **Note:** Directory sizes are not calculated recursively. When `--size` is used, directories are automatically excluded from the search results.
430
476
 
431
477
  ## Archive Search
432
478
 
@@ -458,15 +504,24 @@ backup.zip::source.7z::notes.txt
458
504
 
459
505
  ### Archive Depth
460
506
 
461
- Limit recursion depth:
507
+ The concept of depth in archive is different from `--depth`. Depth in archive is calculated based on nested archives. Each archive that is inside another archive counts as one level of depth.
508
+
509
+ | Syntax | Meaning |
510
+ | ------ | -------------------------------------------------------- |
511
+ | `2` | exactly `2nd` depth |
512
+ | `:2` | `2nd` depth or lower |
513
+ | `2:` | `2nd` depth or higher |
514
+ | `2:4` | between `2` and `4` (Both range boundaries are included) |
515
+
516
+ `--arc-depth` can be specified multiple times:
462
517
 
463
518
  ```bash
464
- psk TODO --archive --depth 2
519
+ psk TODO --archive --arc-depth :2 --arc-depth 5:
465
520
  ```
466
521
 
467
- Meaning `archive level 1` and `archive level 2` will be searched. Deeper levels will be skipped.
522
+ Meaning `archive level 3` and `archive level 4` won't be searched.
468
523
 
469
- **Note:** `--depth 0` means perform the search only within this current archive and don't enter nested archives.
524
+ > **Note:** `--arc-depth 0` means perform the search only within this current archive and don't enter nested archives.
470
525
 
471
526
  ## Archive Filters
472
527
 
@@ -506,7 +561,7 @@ This works exactly like the [--size](#size-filtering) option.
506
561
  psk TODO --archive --arc-size 10m:40m
507
562
  ```
508
563
 
509
- **Note:** Archive directory sizes are usually reported as zero by archive formats, so directory search is disabled if this filter is enabled to avoid incorrect results.
564
+ > **Note:** Archive directory sizes are usually reported as zero by archive formats, so directory search is disabled if this filter is enabled to avoid incorrect results.
510
565
 
511
566
  ## RAR Backend
512
567
 
@@ -1,6 +1,6 @@
1
1
  import io
2
2
  from pathlib import Path
3
- from .utils import get_path_suffix, EXCLUDED_EXTENSIONS
3
+ from .utils import get_path_suffix, is_binary
4
4
  # Archive modules
5
5
  import zipfile, py7zr, tarfile, gzip, bz2, lzma, rarfile
6
6
 
@@ -39,7 +39,7 @@ def archive_should_skip(path_info: Path, config, p_size: float, file_ext, is_dir
39
39
  return False
40
40
 
41
41
 
42
- def extract_names_from_archive(file_path: Path, config, depth: int | None = None,
42
+ def extract_names_from_archive(file_path: Path, config, depth: int = -1,
43
43
  file_bytes: bytes | None = None, parent_label: list[str] | None = None):
44
44
  """
45
45
  Recursively extract files and directories name from archive files.
@@ -57,8 +57,7 @@ def extract_names_from_archive(file_path: Path, config, depth: int | None = None
57
57
 
58
58
  file_ext = get_path_suffix(file_path)
59
59
  label_prefix = [*parent_label, str(file_path)] if parent_label is not None else []
60
- if depth is None:
61
- depth = config.depth
60
+ new_depth = depth + 1
62
61
 
63
62
  try:
64
63
  # Decide the stream source: from disk or memory
@@ -72,8 +71,6 @@ def extract_names_from_archive(file_path: Path, config, depth: int | None = None
72
71
  name = Path(info.filename)
73
72
  new_path_ext = get_path_suffix(name)
74
73
  is_dir = info.is_dir()
75
- # At each recursion, subtract 1 from depth if it's set
76
- new_depth = None if depth is None else depth - 1
77
74
 
78
75
  if not archive_should_skip(
79
76
  name,
@@ -82,10 +79,11 @@ def extract_names_from_archive(file_path: Path, config, depth: int | None = None
82
79
  new_path_ext,
83
80
  is_dir
84
81
  ):
85
- yield label_prefix, name, is_dir
82
+ if any(mi <= new_depth <= ma for mi, ma in config.arc_depth):
83
+ yield label_prefix, name, is_dir
86
84
 
87
85
  # Check if this is a nested archive
88
- if new_path_ext in ARCHIVE_EXTS[:-3] and (new_depth is None or new_depth >= 0):
86
+ if new_path_ext in ARCHIVE_EXTS[:-3] and any(new_depth < d[1] for d in config.arc_depth):
89
87
  yield from extract_names_from_archive(
90
88
  name,
91
89
  config,
@@ -100,7 +98,6 @@ def extract_names_from_archive(file_path: Path, config, depth: int | None = None
100
98
  name = Path(info.filename)
101
99
  new_path_ext = get_path_suffix(name)
102
100
  is_dir = info.is_directory
103
- new_depth = None if depth is None else depth - 1
104
101
 
105
102
  if not archive_should_skip(
106
103
  name,
@@ -109,9 +106,10 @@ def extract_names_from_archive(file_path: Path, config, depth: int | None = None
109
106
  new_path_ext,
110
107
  is_dir
111
108
  ):
112
- yield label_prefix, name, is_dir
109
+ if any(mi <= new_depth <= ma for mi, ma in config.arc_depth):
110
+ yield label_prefix, name, is_dir
113
111
 
114
- if new_path_ext in ARCHIVE_EXTS[:-3] and (new_depth is None or new_depth >= 0):
112
+ if new_path_ext in ARCHIVE_EXTS[:-3] and any(new_depth < d[1] for d in config.arc_depth):
115
113
  file_data = z.read([info.filename]).get(info.filename)
116
114
  if file_data is None:
117
115
  continue
@@ -138,7 +136,6 @@ def extract_names_from_archive(file_path: Path, config, depth: int | None = None
138
136
  name = Path(member.name)
139
137
  new_path_ext = get_path_suffix(name)
140
138
  is_dir = member.isdir()
141
- new_depth = None if depth is None else depth - 1
142
139
 
143
140
  if not archive_should_skip(
144
141
  name,
@@ -147,9 +144,10 @@ def extract_names_from_archive(file_path: Path, config, depth: int | None = None
147
144
  new_path_ext,
148
145
  is_dir
149
146
  ):
150
- yield label_prefix, name, is_dir
147
+ if any(mi <= new_depth <= ma for mi, ma in config.arc_depth):
148
+ yield label_prefix, name, is_dir
151
149
 
152
- if new_path_ext in ARCHIVE_EXTS[:-3] and (new_depth is None or new_depth >= 0):
150
+ if new_path_ext in ARCHIVE_EXTS[:-3] and any(new_depth < d[1] for d in config.arc_depth):
153
151
  f = tf.extractfile(member)
154
152
  if f is None:
155
153
  continue
@@ -165,7 +163,7 @@ def extract_names_from_archive(file_path: Path, config, depth: int | None = None
165
163
  return # silently skip invalid or unreadable archives
166
164
 
167
165
 
168
- def extract_text_from_archive(file_path: Path, config, depth: int | None = None,
166
+ def extract_text_from_archive(file_path: Path, config, depth: int = -1,
169
167
  file_bytes: bytes | None = None, parent_label: list[str] | None = None):
170
168
  """
171
169
  Recursively extract (path_label, text_content) from any archive file.
@@ -183,8 +181,7 @@ def extract_text_from_archive(file_path: Path, config, depth: int | None = None,
183
181
 
184
182
  file_ext = get_path_suffix(file_path)
185
183
  label_prefix = [*parent_label, str(file_path)] if parent_label is not None else []
186
- if depth is None:
187
- depth = config.depth
184
+ new_depth = depth + 1
188
185
 
189
186
  try:
190
187
  # Decide the stream source: from disk or memory
@@ -195,10 +192,10 @@ def extract_text_from_archive(file_path: Path, config, depth: int | None = None,
195
192
  opener = {'zip': zipfile.ZipFile, 'rar': rarfile.RarFile}[file_ext]
196
193
  with opener(file_stream) as f:
197
194
  for info in f.infolist():
195
+ if info.is_dir():
196
+ continue
197
+
198
198
  file_name = Path(info.filename)
199
- data = f.read(info)
200
- # At each recursion, subtract 1 from depth if it's set
201
- new_depth = None if depth is None else depth - 1
202
199
  new_path_ext = get_path_suffix(file_name)
203
200
 
204
201
  if archive_should_skip(
@@ -209,22 +206,33 @@ def extract_text_from_archive(file_path: Path, config, depth: int | None = None,
209
206
  ):
210
207
  continue
211
208
 
209
+ with f.open(info) as entry:
210
+ head = entry.read(8192)
211
+
212
+ if is_binary(head) and new_path_ext not in ARCHIVE_EXTS:
213
+ continue
214
+
215
+ # 8 KiB has already been consumed from stream. If we use entry.read(), we will lose that 8 KiB
216
+ data = head + entry.read()
217
+
212
218
  # Check if this is a nested archive
213
- if new_path_ext in ARCHIVE_EXTS and (new_depth is None or new_depth >= 0):
214
- yield from extract_text_from_archive(file_name, config, new_depth, data, label_prefix)
215
- elif not (info.is_dir() or new_path_ext in EXCLUDED_EXTENSIONS):
219
+ if new_path_ext in ARCHIVE_EXTS:
220
+ if any(new_depth < d[1] for d in config.arc_depth):
221
+ yield from extract_text_from_archive(file_name, config, new_depth, data, label_prefix)
222
+ elif any(mi <= new_depth <= ma for mi, ma in config.arc_depth):
216
223
  yield [*label_prefix, str(file_name)], data
217
224
  # Handle 7Z archives
218
225
  elif file_ext == '7z':
219
226
  with py7zr.SevenZipFile(file_stream, mode='r') as archive:
220
227
  for info in archive.list():
228
+ if info.is_directory:
229
+ continue
230
+
221
231
  file_data = archive.read([info.filename]).get(info.filename)
222
232
  if file_data is None:
223
233
  continue
224
234
 
225
235
  file_name = Path(info.filename)
226
- data = file_data.read()
227
- new_depth = None if depth is None else depth - 1
228
236
  new_path_ext = get_path_suffix(file_name)
229
237
 
230
238
  if archive_should_skip(
@@ -234,10 +242,16 @@ def extract_text_from_archive(file_path: Path, config, depth: int | None = None,
234
242
  new_path_ext
235
243
  ):
236
244
  continue
237
-
238
- if new_path_ext in ARCHIVE_EXTS and (new_depth is None or new_depth >= 0):
239
- yield from extract_text_from_archive(file_name, config, new_depth, data, label_prefix)
240
- elif not (info.is_directory or new_path_ext in EXCLUDED_EXTENSIONS):
245
+
246
+ head = file_data.read(8192)
247
+ if is_binary(head) and new_path_ext not in ARCHIVE_EXTS:
248
+ continue
249
+
250
+ data = head + file_data.read()
251
+ if new_path_ext in ARCHIVE_EXTS:
252
+ if any(new_depth < d[1] for d in config.arc_depth):
253
+ yield from extract_text_from_archive(file_name, config, new_depth, data, label_prefix)
254
+ elif any(mi <= new_depth <= ma for mi, ma in config.arc_depth):
241
255
  yield [*label_prefix, str(file_name)], data
242
256
  # Handle TAR and compressed TAR formats
243
257
  elif file_ext in ('tar', 'tar.gz', 'tar.bz2', 'tar.xz'):
@@ -250,13 +264,14 @@ def extract_text_from_archive(file_path: Path, config, depth: int | None = None,
250
264
 
251
265
  with tarfile.open(fileobj=file_stream, mode=mode) as tf:
252
266
  for member in tf.getmembers():
267
+ if member.isdir():
268
+ continue
269
+
253
270
  f = tf.extractfile(member)
254
271
  if f is None:
255
272
  continue
256
273
 
257
274
  file_name = Path(member.name)
258
- data = f.read()
259
- new_depth = None if depth is None else depth - 1
260
275
  new_path_ext = get_path_suffix(file_name)
261
276
 
262
277
  if archive_should_skip(
@@ -266,10 +281,16 @@ def extract_text_from_archive(file_path: Path, config, depth: int | None = None,
266
281
  new_path_ext
267
282
  ):
268
283
  continue
284
+
285
+ head = f.read(8192)
286
+ if is_binary(head) and new_path_ext not in ARCHIVE_EXTS:
287
+ continue
269
288
 
270
- if new_path_ext in ARCHIVE_EXTS and (new_depth is None or new_depth >= 0):
271
- yield from extract_text_from_archive(file_name, config, new_depth, data, label_prefix)
272
- elif not (member.isdir() or new_path_ext in EXCLUDED_EXTENSIONS):
289
+ data = head + f.read()
290
+ if new_path_ext in ARCHIVE_EXTS:
291
+ if any(new_depth < d[1] for d in config.arc_depth):
292
+ yield from extract_text_from_archive(file_name, config, new_depth, data, label_prefix)
293
+ elif any(mi <= new_depth <= ma for mi, ma in config.arc_depth):
273
294
  yield [*label_prefix, str(file_name)], data
274
295
  # Handle single compressed files like .gz, .bz2, .xz
275
296
  elif file_ext in ARCHIVE_EXTS[-3:]: