Skip to content

Commit 4bf4eeb

Browse files
[symilar] Migrate from optparse / getopt to argparse
Co-authored-by: Roger Sheu <[email protected]>
1 parent 6bb335f commit 4bf4eeb

File tree

3 files changed

+47
-70
lines changed

3 files changed

+47
-70
lines changed
+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
We migrated ``symilar`` to argparse, from getopt, so the error and help output changed
2+
(for the better). We exit with 2 instead of sometime 1, sometime 2. The error output
3+
is not captured by the runner anymore. It's not possible to use a value for the
4+
boolean option anymore (``--ignore-comments 2`` should become ``--ignore-comments``).
5+
6+
Refs #9731

pylint/checkers/symilar.py

+25-58
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,13 @@
3333
import copy
3434
import functools
3535
import itertools
36+
import logging
3637
import operator
3738
import re
3839
import sys
3940
import warnings
4041
from collections import defaultdict
4142
from collections.abc import Callable, Generator, Iterable, Sequence
42-
from getopt import GetoptError, getopt
4343
from io import BufferedIOBase, BufferedReader, BytesIO
4444
from itertools import chain
4545
from typing import TYPE_CHECKING, NamedTuple, NewType, NoReturn, TextIO, Union
@@ -876,67 +876,34 @@ def register(linter: PyLinter) -> None:
876876
linter.register_checker(SimilaritiesChecker(linter))
877877

878878

879-
def usage(status: int = 0) -> NoReturn:
880-
"""Display command line usage information."""
881-
print("finds copy pasted blocks in a set of files")
882-
print()
883-
print(
884-
"Usage: symilar [-d|--duplicates min_duplicated_lines] \
885-
[-i|--ignore-comments] [--ignore-docstrings] [--ignore-imports] [--ignore-signatures] file1..."
886-
)
887-
sys.exit(status)
888-
889-
890879
def Run(argv: Sequence[str] | None = None) -> NoReturn:
891880
"""Standalone command line access point."""
892-
if argv is None:
893-
argv = sys.argv[1:]
894-
895-
s_opts = "hd:i:"
896-
l_opts = [
897-
"help",
898-
"duplicates=",
899-
"ignore-comments",
900-
"ignore-imports",
901-
"ignore-docstrings",
902-
"ignore-signatures",
903-
]
904-
min_lines = DEFAULT_MIN_SIMILARITY_LINE
905-
ignore_comments = False
906-
ignore_docstrings = False
907-
ignore_imports = False
908-
ignore_signatures = False
909-
try:
910-
opts, args = getopt(list(argv), s_opts, l_opts)
911-
except GetoptError as e:
912-
print(e)
913-
usage(2)
914-
for opt, val in opts:
915-
if opt in {"-d", "--duplicates"}:
916-
try:
917-
min_lines = int(val)
918-
except ValueError as e:
919-
print(e)
920-
usage(2)
921-
elif opt in {"-h", "--help"}:
922-
usage()
923-
elif opt in {"-i", "--ignore-comments"}:
924-
ignore_comments = True
925-
elif opt in {"--ignore-docstrings"}:
926-
ignore_docstrings = True
927-
elif opt in {"--ignore-imports"}:
928-
ignore_imports = True
929-
elif opt in {"--ignore-signatures"}:
930-
ignore_signatures = True
931-
if not args:
932-
usage(1)
933-
sim = Symilar(
934-
min_lines, ignore_comments, ignore_docstrings, ignore_imports, ignore_signatures
881+
logging.error(argv)
882+
parser = argparse.ArgumentParser(
883+
prog="symilar", description="Finds copy pasted blocks in a set of files."
884+
)
885+
parser.add_argument("files", nargs="+")
886+
parser.add_argument(
887+
"-d", "--duplicates", type=int, default=DEFAULT_MIN_SIMILARITY_LINE
888+
)
889+
parser.add_argument("-i", "--ignore-comments", action="store_true")
890+
parser.add_argument("--ignore-docstrings", action="store_true")
891+
parser.add_argument("--ignore-imports", action="store_true")
892+
parser.add_argument("--ignore-signatures", action="store_true")
893+
parsed_args = parser.parse_args(args=argv)
894+
similar_runner = Symilar(
895+
min_lines=parsed_args.duplicates,
896+
ignore_comments=parsed_args.ignore_comments,
897+
ignore_docstrings=parsed_args.ignore_docstrings,
898+
ignore_imports=parsed_args.ignore_imports,
899+
ignore_signatures=parsed_args.ignore_signatures,
935900
)
936-
for filename in args:
901+
logging.error(parsed_args.files)
902+
for filename in parsed_args.files:
937903
with open(filename, encoding="utf-8") as stream:
938-
sim.append_stream(filename, stream)
939-
sim.run()
904+
similar_runner.append_stream(filename, stream)
905+
similar_runner.run()
906+
# the sys exit must be kept because of the unit tests that rely on it
940907
sys.exit(0)
941908

942909

tests/checkers/unittest_symilar.py

+16-12
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from pathlib import Path
88

99
import pytest
10+
from _pytest.capture import CaptureFixture
1011

1112
from pylint.checkers import symilar
1213
from pylint.lint import PyLinter
@@ -364,13 +365,16 @@ def test_help() -> None:
364365
pytest.fail("not system exit")
365366

366367

367-
def test_no_args() -> None:
368+
def test_no_args(capsys: CaptureFixture) -> None:
368369
output = StringIO()
369370
with redirect_stdout(output):
370371
try:
371372
symilar.Run([])
372373
except SystemExit as ex:
373-
assert ex.code == 1
374+
assert ex.code == 2
375+
out, err = capsys.readouterr()
376+
assert not out
377+
assert "the following arguments are required: files" in err
374378
else:
375379
pytest.fail("not system exit")
376380

@@ -494,30 +498,30 @@ def test_set_duplicate_lines_to_zero() -> None:
494498
assert output.getvalue() == ""
495499

496500

497-
@pytest.mark.parametrize("v", ["d"])
498-
def test_bad_equal_short_form_option(v: str) -> None:
501+
def test_equal_short_form_option() -> None:
499502
"""Regression test for https://github.com/pylint-dev/pylint/issues/9343"""
500503
output = StringIO()
501504
with redirect_stdout(output), pytest.raises(SystemExit) as ex:
502-
symilar.Run([f"-{v}=0", SIMILAR1, SIMILAR2])
503-
assert ex.value.code == 2
504-
assert "invalid literal for int() with base 10: '=0'" in output.getvalue()
505+
symilar.Run(["-d=2", SIMILAR1, SIMILAR2])
506+
assert ex.value.code == 0
507+
assert "similar lines in" in output.getvalue()
505508

506509

507-
@pytest.mark.parametrize("v", ["i", "d"])
508-
def test_space_short_form_option(v: str) -> None:
510+
def test_space_short_form_option() -> None:
509511
"""Regression test for https://github.com/pylint-dev/pylint/issues/9343"""
510512
output = StringIO()
511513
with redirect_stdout(output), pytest.raises(SystemExit) as ex:
512-
symilar.Run([f"-{v} 2", SIMILAR1, SIMILAR2])
514+
symilar.Run(["-d 2", SIMILAR1, SIMILAR2])
513515
assert ex.value.code == 0
514516
assert "similar lines in" in output.getvalue()
515517

516518

517-
def test_bad_short_form_option() -> None:
519+
def test_bad_short_form_option(capsys: CaptureFixture) -> None:
518520
"""Regression test for https://github.com/pylint-dev/pylint/issues/9343"""
519521
output = StringIO()
520522
with redirect_stdout(output), pytest.raises(SystemExit) as ex:
521523
symilar.Run(["-j=0", SIMILAR1, SIMILAR2])
524+
out, err = capsys.readouterr()
522525
assert ex.value.code == 2
523-
assert "option -j not recognized" in output.getvalue()
526+
assert not out
527+
assert "unrecognized arguments: -j=0" in err

0 commit comments

Comments
 (0)