Skip to content

Commit 9727540

Browse files
committed
support multiple input files
based on #52 by @Roald87
1 parent 357c45a commit 9727540

File tree

5 files changed

+78
-60
lines changed

5 files changed

+78
-60
lines changed

CHANGELOG.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,14 @@ Changelog
88
* fix build
99

1010
* sorry for leaving the broken 0.10.1 version unfixed for so long
11+
* some code cleanup
12+
* support multiple input files
13+
14+
* thanks to `@Roald87`_ for the suggestion and initial implementation (`#52`_, `#49`_)
15+
16+
.. _@Roald87: https://github.com/Roald87
17+
.. _#52: https://github.com/Findus23/pyLanguagetool/pull/52
18+
.. _#49: https://github.com/Findus23/pyLanguagetool/pull/49
1119

1220

1321
`0.10.1` (2024-07-20)

README.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,10 @@ Parameters
7979
[--disabled-categories DISABLED_CATEGORIES]
8080
[--enabled-only] [--picky] [-U USERNAME] [-P API_KEY]
8181
[--pwl PWL]
82-
[input file]
82+
[input files ...]
8383
8484
positional arguments:
85-
input file input file
85+
input files input file(s)
8686
8787
options:
8888
-h, --help show this help message and exit

pylanguagetool/api.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,5 +222,4 @@ def check(
222222
match for match in matches
223223
if not _is_in_pwl(match, pwl)
224224
]
225-
print(print(data))
226225
return data

pylanguagetool/cli.py

Lines changed: 66 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def init_config() -> tuple[dict[str, Any], ArgumentParser]:
3535
help="if not plaintext")
3636
p.add_argument("-u", "--explain-rule", env_var="EXPLAIN_RULE", action="store_true", default=False,
3737
help="print URLs with more information about rules")
38-
p.add_argument('input file', help='input file', nargs='?')
38+
p.add_argument('input files', help='input file(s)', nargs='*')
3939
p.add_argument("-r", "--rules", env_var="RULES", action='store_true', default=False,
4040
help="show the matching rules")
4141
p.add_argument("--rule-categories", env_var="RULE_CATEGORIES", action='store_true', default=False,
@@ -105,31 +105,33 @@ def get_clipboard() -> str:
105105
return clipboard
106106

107107

108-
def get_input_text(config: dict[str, Any]) -> tuple[Optional[str], Optional[str]]:
108+
def get_input_text(config: dict[str, Any]) -> list[tuple[str, Optional[str]]]:
109109
"""
110110
Return text from stdin, clipboard or file.
111111
112112
Returns:
113113
tuple[Optional[str], Optional[str]]:
114-
A tuple contain of the text and an optional file extension.
115-
If the text does not come from a file, the extension part of the
114+
A tuple contain of the text and an optional filename.
115+
If the text does not come from a file, the filename part of the
116116
tuple will be none.
117117
118118
"""
119-
if not sys.stdin.isatty() and not config["input file"]: # if piped into script
119+
if not sys.stdin.isatty() and not config["input files"]: # if piped into script
120120
lines = [line.rstrip() for line in sys.stdin.readlines() if line.rstrip()]
121-
return "\n".join(lines), None # read text from pipe and remove empty lines
121+
return [("\n".join(lines), None)] # read text from pipe and remove empty lines
122122
if config["clipboard"]:
123-
return get_clipboard(), None
124-
if not config["input file"]:
125-
return None, None
126-
extension = os.path.splitext(config["input file"])[1][1:] # get file extention without .
127-
try:
128-
with open(config["input file"]) as myfile:
129-
return myfile.read(), extension
130-
except UnicodeDecodeError:
131-
print("can't read text")
132-
sys.exit(1)
123+
return [(get_clipboard(), None)]
124+
if not config["input files"]:
125+
return []
126+
inputs = []
127+
for filename in config["input files"]:
128+
try:
129+
with open(filename) as myfile:
130+
inputs.append((myfile.read(), filename))
131+
except UnicodeDecodeError:
132+
print("can't read text")
133+
sys.exit(1)
134+
return inputs
133135

134136

135137
def print_errors(response, api_url: str, print_color: bool = True, rules: bool = False,
@@ -236,52 +238,60 @@ def main() -> None:
236238
else:
237239
config['pwl'] = []
238240

239-
input_text, inputtype = get_input_text(config)
240-
if not input_text:
241+
inputs = get_input_text(config)
242+
if not inputs:
241243
argparser.print_usage()
242244
print("input file is required")
243245
sys.exit(2)
244-
if config["input_type"]:
245-
inputtype = config["input_type"]
246-
if inputtype == "tex":
247-
print("pyLanguagetool doesn't support LaTeX out of the box.")
248-
print("But it doesn't have to:")
249-
print("You can simply use the output of detex")
250-
if config["input file"]:
251-
print(f" $ detex {config['input file']} | pylanguagetool")
252-
print("or use the languagetool integration in TeXstudio.")
253-
sys.exit(3)
254-
check_text = converters.convert(input_text, inputtype)
255-
config_not_needed_in_api = [
256-
"version", "no_color", "clipboard", "single_line",
257-
"input_type", "input file", "explain_rule", "rules",
258-
"rule_categories"
259-
]
260-
config_for_api = {k: v for k, v in config.items() if k not in config_not_needed_in_api}
261-
if config["single_line"]:
262-
found = False
263-
for line in check_text.splitlines():
264-
response = api.check(line, **config_for_api)
246+
found_at_least_one_error = False
247+
for i, (input_text, filename) in enumerate(inputs):
248+
inputtype = None
249+
if filename:
250+
inputtype = os.path.splitext(filename)[1][1:]
251+
if config["input_type"]:
252+
inputtype = config["input_type"]
253+
if inputtype == "tex":
254+
print("pyLanguagetool doesn't support LaTeX out of the box.")
255+
print("But it doesn't have to:")
256+
print("You can simply use the output of detex")
257+
if input_text:
258+
print(f" $ detex {filename} | pylanguagetool")
259+
print("or use the languagetool integration in TeXstudio.")
260+
sys.exit(3)
261+
check_text = converters.convert(input_text, inputtype)
262+
if len(inputs) > 1:
263+
print(filename)
264+
config_not_needed_in_api = [
265+
"version", "no_color", "clipboard", "single_line",
266+
"input_type", "input files", "explain_rule", "rules",
267+
"rule_categories"
268+
]
269+
config_for_api = {k: v for k, v in config.items() if k not in config_not_needed_in_api}
270+
if config["single_line"]:
271+
for line in check_text.splitlines():
272+
response = api.check(line, **config_for_api)
273+
print_errors(response,
274+
config["api_url"],
275+
not config["no_color"],
276+
config["rules"],
277+
config["rule_categories"]
278+
)
279+
if len(response["matches"]) > 0:
280+
found_at_least_one_error = True
281+
282+
else:
283+
response = api.check(check_text, **config_for_api)
265284
print_errors(response,
266285
config["api_url"],
267286
not config["no_color"],
268287
config["rules"],
269-
config["rule_categories"]
288+
config["rule_categories"],
289+
config["explain_rule"]
270290
)
271-
if len(response["matches"]) > 0:
272-
found = True
273-
if found:
274-
sys.exit(1)
275291

276-
else:
277-
response = api.check(check_text, **config_for_api)
278-
print_errors(response,
279-
config["api_url"],
280-
not config["no_color"],
281-
config["rules"],
282-
config["rule_categories"],
283-
config["explain_rule"]
284-
)
285-
286-
if len(response["matches"]) > 0:
287-
sys.exit(1)
292+
if len(response["matches"]) > 0:
293+
found_at_least_one_error = True
294+
if i < len(inputs) - 1:
295+
print()
296+
if found_at_least_one_error:
297+
sys.exit(1)

pylanguagetool/converters.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@
55
import json
66
import sys
77
import xml.etree.ElementTree
8+
from typing import Optional
89

910
supported_extensions = ["txt", "html", "md", "markdown", "rst", "ipynb", "json", "xliff"]
1011

1112

12-
def convert(source: str, texttype: str) -> str:
13+
def convert(source: str, texttype: Optional[str]) -> str:
1314
"""
1415
Convert files of various types to plaintext
1516

0 commit comments

Comments
 (0)