Skip to content

Commit da433c1

Browse files
committed
feat: handle multiple files, closes #5
should worked with globbed usage in shells that expand globs now like 'marcgrep --count *.mrc' to do this had to rework the CLI function a bit but also the output of the count command since printing a bunch of numbers with no labels isn't helpful, we should see how many records matched _in each file_ like grep or other tools do that required rewriting a number of the CLI tests
1 parent dbb6d19 commit da433c1

File tree

3 files changed

+64
-36
lines changed

3 files changed

+64
-36
lines changed

marcgrep/cli.py

Lines changed: 41 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
1-
from typing import BinaryIO
1+
import sys
2+
from typing import IO, BinaryIO, List, Union
23

34
import click
4-
from pymarc import MARCReader
5+
from pymarc import Any, MARCReader
56

67
from .color import color_field, color_record
78
from .filter import Filter
89

910

1011
@click.command(help="Find MARC records matching patterns in a file.")
1112
@click.help_option("-h", "--help")
12-
@click.argument("file", type=click.File("rb"), default="-")
13+
@click.argument("files", type=click.File("rb"), nargs=-1)
1314
@click.option("--count", "-c", help="Count matching records", is_flag=True)
1415
@click.option(
1516
"--include", "-i", help="Include matching records (repeatable)", multiple=True
@@ -22,47 +23,57 @@
2223
@click.option("--color", help="Colorize mnemonic MARC output", is_flag=True)
2324
@click.version_option(package_name="marcgrep", message="%(prog)s %(version)s")
2425
def main(
25-
file: BinaryIO,
26+
files: List[BinaryIO],
2627
color: bool,
2728
count: bool,
2829
include: list[str],
2930
exclude: list[str],
3031
fields: str,
3132
limit: int,
3233
):
33-
counter = 0
34-
matched_records = 0
35-
reader = MARCReader(file)
34+
# handle stdin if no files are provided
35+
if not files:
36+
files = [sys.stdin.buffer]
3637

37-
# build a list of filters, start with exclusive because they rule out records quicker
38-
filters: list[Filter] = [Filter(pattern, inclusive=False) for pattern in exclude]
39-
filters.extend(Filter(pattern) for pattern in include)
38+
any_matches = False
4039

41-
for record in reader:
42-
if record:
43-
counter += 1
44-
if all(f.match(record) for f in filters):
45-
matched_records += 1
46-
if not count:
47-
if fields:
48-
for f in record.get_fields(*fields.split(",")):
40+
for file in files:
41+
counter = 0
42+
matched_records = 0
43+
reader = MARCReader(file)
44+
45+
# build a list of filters, start with exclusive because they rule out records quicker
46+
filters: list[Filter] = [
47+
Filter(pattern, inclusive=False) for pattern in exclude
48+
]
49+
filters.extend(Filter(pattern) for pattern in include)
50+
51+
for record in reader:
52+
if record:
53+
counter += 1
54+
if all(f.match(record) for f in filters):
55+
any_matches = True
56+
matched_records += 1
57+
if not count:
58+
if fields:
59+
for f in record.get_fields(*fields.split(",")):
60+
if color:
61+
color_field(f)
62+
else:
63+
print(f)
64+
else:
4965
if color:
50-
color_field(f)
66+
color_record(record)
5167
else:
52-
print(f)
53-
else:
54-
if color:
55-
color_record(record)
56-
else:
57-
print(record)
58-
if limit and counter >= limit:
59-
break
68+
print(record)
69+
if limit and counter >= limit:
70+
break
6071

61-
if count:
62-
print(matched_records)
72+
if count:
73+
print(f"{file.name}: {matched_records}")
6374

6475
# non-zero exit if no records match
65-
return exit(0 if matched_records else 1)
76+
return exit(0 if any_matches else 1)
6677

6778

6879
if __name__ == "__main__":

readme.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ pip install marcgrep # or use pip/pip3
1616
## Usage
1717

1818
```sh
19-
# general command format
20-
marcgrep OPTIONS FILE.mrc
19+
# general command format - pass one or more files or pipe stdin
20+
marcgrep OPTIONS FILE1.mrc FILE2.mrc
2121
cat FILE.mrc | marcgrep OPTIONS
2222
# full usage information
2323
marcgrep -h

test/test_cli.py

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@ def test_count(self):
1717
runner = CliRunner()
1818
result = runner.invoke(main, [ONE_RECORD, "--count"])
1919
assert result.exit_code == 0
20-
assert result.output == "1\n"
20+
assert result.output == f"{ONE_RECORD}: 1\n"
2121
result = runner.invoke(main, [PLAIN_TEXT, "-c"])
2222
assert result.exit_code == 1
23-
assert result.output == "0\n"
23+
assert result.output == f"{PLAIN_TEXT}: 0\n"
2424
result = runner.invoke(main, [OAPEN, "-c"])
2525
assert result.exit_code == 0
26-
assert result.output == "500\n"
26+
assert result.output == f"{OAPEN}: 500\n"
2727

2828
def test_print(self):
2929
runner = CliRunner()
@@ -162,4 +162,21 @@ def test_limit(self, input, expected):
162162
main, [OAPEN, "--limit", input, "-c", "--include", "245"]
163163
)
164164
assert result.exit_code == 0
165-
assert result.output == f"{expected}\n"
165+
assert result.output == f"{OAPEN}: {expected}\n"
166+
167+
def test_glob(self):
168+
runner = CliRunner()
169+
result = runner.invoke(
170+
main,
171+
["--count", OAPEN, ONE_RECORD],
172+
)
173+
assert result.exit_code == 0
174+
assert result.output == f"{OAPEN}: 500\n{ONE_RECORD}: 1\n"
175+
# should still work with stdin
176+
result = runner.invoke(
177+
main,
178+
["-f", "245", "-"],
179+
input=open(ONE_RECORD, "rb").read(),
180+
)
181+
assert result.exit_code == 0
182+
assert len(result.output.splitlines()) == 1

0 commit comments

Comments
 (0)