Skip to content

Commit e196653

Browse files
authored
Merge pull request #182 from mull-project/code-climate
Config: dedicate class to store configuration
2 parents 4b97b60 + d6a4593 commit e196653

File tree

9 files changed

+358
-55
lines changed

9 files changed

+358
-55
lines changed

.coverage

52 KB
Binary file not shown.

.coveragerc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# .coveragerc to control coverage.py
2+
[run]
3+
branch = True
4+
omit =
5+
*/.venv/*
6+
7+
[report]
8+
fail_under = 13.63
9+
precision = 2
10+
skip_covered = true
11+
show_missing = true

filecheck/filecheck.py

Lines changed: 87 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -247,25 +247,73 @@ def __init__(self, check: Check):
247247
self.check = check
248248

249249

250+
class Config:
251+
def __init__( # pylint: disable = too-many-arguments
252+
self,
253+
check_file: str,
254+
match_full_lines: bool,
255+
strict_whitespace: bool,
256+
check_prefix: Optional[str],
257+
implicit_check_not: Optional[str],
258+
dump_input: Optional[str],
259+
):
260+
self.check_file: str = check_file
261+
self.match_full_lines: bool = match_full_lines
262+
self.strict_whitespace: bool = strict_whitespace
263+
self.check_prefix: Optional[str] = (
264+
check_prefix if check_prefix else "CHECK"
265+
)
266+
self.implicit_check_not: Optional[str] = implicit_check_not
267+
self.dump_input: Optional[str] = dump_input
268+
self.strict_mode = match_full_lines and strict_whitespace
269+
270+
@staticmethod
271+
def create_parser():
272+
parser = argparse.ArgumentParser()
273+
274+
parser.add_argument("check_file_arg", type=str, help="TODO")
275+
parser.add_argument(
276+
"--strict-whitespace", action="store_true", help="TODO"
277+
)
278+
parser.add_argument(
279+
"--match-full-lines", action="store_true", help="TODO"
280+
)
281+
parser.add_argument("--check-prefix", action="store", help="TODO")
282+
parser.add_argument(
283+
"--implicit-check-not", action="append", help="TODO"
284+
)
285+
parser.add_argument(
286+
"--dump-input", action="store", choices=["fail"], help="TODO"
287+
)
288+
return parser
289+
290+
@staticmethod
291+
def create(args):
292+
return Config(
293+
check_file=args.check_file_arg,
294+
match_full_lines=args.match_full_lines,
295+
strict_whitespace=args.strict_whitespace,
296+
check_prefix=args.check_prefix,
297+
implicit_check_not=args.implicit_check_not,
298+
dump_input=args.dump_input,
299+
)
300+
301+
250302
class CheckParser:
251303
@staticmethod
252304
def parse_checks_from_file(
253-
check_file_path: str, args, strict_mode: bool, check_prefix: str
305+
check_file_path: str, config: Config
254306
) -> List[Check]:
255307
with open(check_file_path, encoding="utf-8") as check_file:
256-
return CheckParser.parse_checks_from_strings(
257-
check_file, args, strict_mode, check_prefix
258-
)
308+
return CheckParser.parse_checks_from_strings(check_file, config)
259309

260310
@staticmethod
261311
def parse_checks_from_strings(
262-
input_strings: Iterable[str], args, strict_mode: bool, check_prefix: str
312+
input_strings: Iterable[str], config: Config
263313
) -> List[Check]:
264314
checks = []
265315
for line_idx, line in enumerate(input_strings):
266-
check = CheckParser.parse_check(
267-
line, line_idx, args, strict_mode, check_prefix
268-
)
316+
check = CheckParser.parse_check(line, line_idx, config)
269317
if check is None:
270318
continue
271319
if check.check_type == CheckType.CHECK_EMPTY and len(checks) == 0:
@@ -274,26 +322,25 @@ def parse_checks_from_strings(
274322
return checks
275323

276324
@staticmethod
277-
def parse_check(
278-
line: str, line_idx, args, strict_mode: bool, check_prefix: str
279-
) -> Optional[Check]:
325+
def parse_check(line: str, line_idx, config: Config) -> Optional[Check]:
280326
line = line.rstrip()
281327

282-
if not args.strict_whitespace:
328+
if not config.strict_whitespace:
283329
line = canonicalize_whitespace(line)
284330

285331
# CHECK and CHECK-NEXT
286-
strict_whitespace_match = "" if strict_mode else " *"
332+
strict_whitespace_match = "" if config.strict_mode else " *"
287333

288334
check_regex = (
289-
f"{BEFORE_PREFIX}({check_prefix}):{strict_whitespace_match}(.*)"
335+
f"{BEFORE_PREFIX}({config.check_prefix}):"
336+
f"{strict_whitespace_match}(.*)"
290337
)
291338

292339
check_match = re.search(check_regex, line)
293340
check_type = CheckType.CHECK
294341
if not check_match:
295342
check_regex = (
296-
f"{BEFORE_PREFIX}({check_prefix}-NEXT):"
343+
f"{BEFORE_PREFIX}({config.check_prefix}-NEXT):"
297344
f"{strict_whitespace_match}(.*)"
298345
)
299346
check_match = re.search(check_regex, line)
@@ -302,7 +349,7 @@ def parse_check(
302349
if check_match:
303350
check_keyword = check_match.group(2)
304351
check_expression = check_match.group(3)
305-
if not strict_mode:
352+
if not config.strict_mode:
306353
check_expression = check_expression.strip(" ")
307354

308355
match_type = MatchType.SUBSTRING
@@ -312,7 +359,7 @@ def parse_check(
312359
regex_line = re.sub(r"\{\{(.*?)\}\}", r"\1", regex_line)
313360
match_type = MatchType.REGEX
314361
check_expression = regex_line
315-
if strict_mode:
362+
if config.strict_mode:
316363
if check_expression[0] != "^":
317364
check_expression = "^" + check_expression
318365
if check_expression[-1] != "$":
@@ -344,7 +391,7 @@ def parse_check(
344391
return check
345392

346393
check_not_regex = (
347-
f"{BEFORE_PREFIX}({check_prefix}-NOT):"
394+
f"{BEFORE_PREFIX}({config.check_prefix}-NOT):"
348395
f"{strict_whitespace_match}(.*)"
349396
)
350397
check_match = re.search(check_not_regex, line)
@@ -353,7 +400,7 @@ def parse_check(
353400

354401
check_keyword = check_match.group(2)
355402
check_expression = check_match.group(3)
356-
if not strict_mode:
403+
if not config.strict_mode:
357404
check_expression = check_expression.strip(" ")
358405

359406
if re.search(r"\{\{.*\}\}", check_expression):
@@ -373,7 +420,7 @@ def parse_check(
373420
)
374421
return check
375422

376-
check_empty_regex = f"{BEFORE_PREFIX}({check_prefix}-EMPTY):"
423+
check_empty_regex = f"{BEFORE_PREFIX}({config.check_prefix}-EMPTY):"
377424
check_match = re.search(check_empty_regex, line)
378425
if check_match:
379426
check_keyword = check_match.group(2)
@@ -395,11 +442,10 @@ def parse_check(
395442
def main():
396443
# Force UTF-8 to be sent to stdout.
397444
# https://stackoverflow.com/a/3597849/598057
398-
sys.stdout = open(
445+
sys.stdout = open( # pylint: disable=consider-using-with
399446
1, "w", encoding="utf-8", closefd=False
400-
) # pylint: disable=consider-using-with
447+
)
401448

402-
args = None
403449
input_lines = None
404450

405451
# TODO: Unify exit_handler() handling.
@@ -408,7 +454,7 @@ def exit_handler(code):
408454
# any additional formatting and hints.
409455
# Eventually it would be great to implement the same behavior.
410456
# https://llvm.org/docs/CommandGuide/FileCheck.html#cmdoption-filecheck-dump-input
411-
if code != 0 and input_lines and args and args.dump_input:
457+
if code != 0 and input_lines and config.dump_input:
412458
print("")
413459
print("Full input was:")
414460
for input_line in input_lines:
@@ -447,26 +493,15 @@ def exit_handler(code):
447493
)
448494
exit_handler(2)
449495

450-
parser = argparse.ArgumentParser()
451-
452-
parser.add_argument("check_file_arg", type=str, help="TODO")
453-
parser.add_argument("--strict-whitespace", action="store_true", help="TODO")
454-
parser.add_argument("--match-full-lines", action="store_true", help="TODO")
455-
parser.add_argument("--check-prefix", action="store", help="TODO")
456-
parser.add_argument("--implicit-check-not", action="append", help="TODO")
457-
parser.add_argument(
458-
"--dump-input", action="store", choices=["fail"], help="TODO"
459-
)
460-
461-
args = parser.parse_args()
496+
parser = Config.create_parser()
497+
config = Config.create(parser.parse_args())
462498

463-
strict_mode = args.match_full_lines and args.strict_whitespace
499+
strict_mode = config.match_full_lines and config.strict_whitespace
464500

465-
check_prefix = args.check_prefix if args.check_prefix else "CHECK"
466501
implicit_check_not_checks = []
467502

468-
if args.implicit_check_not:
469-
for implicit_check_not_arg in args.implicit_check_not:
503+
if config.implicit_check_not:
504+
for implicit_check_not_arg in config.implicit_check_not:
470505
# LLVM FileCheck does rstrip() here for some reason that
471506
# does not seem reasonable. We still prefer to be compatible.
472507
stripped_check = implicit_check_not_arg.rstrip()
@@ -476,7 +511,7 @@ def exit_handler(code):
476511
)
477512
implicit_check_not_checks.append(implicit_check_not)
478513

479-
if not re.search("^[A-Za-z][A-Za-z0-9-_]+$", check_prefix):
514+
if not re.search("^[A-Za-z][A-Za-z0-9-_]+$", config.check_prefix):
480515
sys.stdout.flush()
481516
error_message = (
482517
"Supplied check-prefix is invalid! Prefixes must be unique and "
@@ -487,9 +522,7 @@ def exit_handler(code):
487522
exit_handler(2)
488523

489524
try:
490-
checks = CheckParser.parse_checks_from_file(
491-
check_file_path, args, strict_mode, check_prefix
492-
)
525+
checks = CheckParser.parse_checks_from_file(check_file_path, config)
493526
except CheckParserEmptyCheckException as exception:
494527
print(
495528
f"{check_file_path}:"
@@ -514,7 +547,8 @@ def exit_handler(code):
514547
current_check = next(check_iterator)
515548
except StopIteration:
516549
error_message = (
517-
f"error: no check strings found with prefix '{check_prefix}:'"
550+
f"error: "
551+
f"no check strings found with prefix '{config.check_prefix}:'"
518552
)
519553
print(error_message, file=sys.stderr)
520554
sys.stdout.flush()
@@ -568,16 +602,16 @@ def exit_handler(code):
568602

569603
unstripped_line = line
570604

571-
if not args.strict_whitespace:
605+
if not config.strict_whitespace:
572606
line = canonicalize_whitespace(line)
573-
if args.match_full_lines:
607+
if config.match_full_lines:
574608
line = line.strip(" ")
575609

576610
while True:
577611
if not failed_check:
578612
for current_not_check in current_not_checks:
579613
check_result = check_line(
580-
line, current_not_check, args.match_full_lines
614+
line, current_not_check, config.match_full_lines
581615
)
582616
if check_result == CheckResult.CHECK_NOT_MATCH:
583617
failed_check = FailedCheck(
@@ -596,7 +630,7 @@ def exit_handler(code):
596630
break
597631

598632
check_result = check_line(
599-
line, current_check, args.match_full_lines
633+
line, current_check, config.match_full_lines
600634
)
601635

602636
if check_result == CheckResult.FAIL_FATAL:
@@ -701,7 +735,7 @@ def exit_handler(code):
701735

702736
for not_check in current_not_checks:
703737
if (
704-
check_line(line, not_check, args.match_full_lines)
738+
check_line(line, not_check, config.match_full_lines)
705739
== CheckResult.CHECK_NOT_MATCH
706740
):
707741
current_check_line_idx = line_idx
@@ -800,7 +834,8 @@ def exit_handler(code):
800834
f"{check_file_path}:"
801835
f"{current_check.check_line_idx + 1}:"
802836
f"{current_check.start_index + 1}: "
803-
f"error: {check_prefix}: expected string not found in input"
837+
f"error: {config.check_prefix}: "
838+
f"expected string not found in input"
804839
)
805840

806841
print(current_check.source_line.rstrip())
@@ -853,7 +888,7 @@ def exit_handler(code):
853888
assert current_check_line_idx is not None
854889
last_read_line = input_lines[current_check_line_idx].rstrip()
855890

856-
if not args.strict_whitespace:
891+
if not config.strict_whitespace:
857892
last_read_line = re.sub("\\s+", " ", last_read_line).strip()
858893

859894
print(

0 commit comments

Comments
 (0)