From 96b9348ab24913137dc92ca35e3506aefb1850d39349c83c48b31d424f4130f8 Mon Sep 17 00:00:00 2001 From: Dirk Mueller Date: Thu, 1 Apr 2021 07:19:39 +0000 Subject: [PATCH] - update to 4.0.0: * Opted back into using Poetry now that the existing issues have been fixed. * Python 2.7 support was no officially dropped. - add pycodestyle-indent-size.patch and use pypi tarball to avoid poetry OBS-URL: https://build.opensuse.org/package/show/devel:languages:python/python-flake8-debugger?expand=0&rev=6 --- 3.2.1.tar.gz | 3 - flake8-debugger-4.0.0.tar.gz | 3 + pycodestyle-indent-size.patch | 10 + python-flake8-debugger.changes | 8 + python-flake8-debugger.spec | 14 +- test_linter.py | 400 +++++++++++++++++++++++++++++++++ 6 files changed, 430 insertions(+), 8 deletions(-) delete mode 100644 3.2.1.tar.gz create mode 100644 flake8-debugger-4.0.0.tar.gz create mode 100644 pycodestyle-indent-size.patch create mode 100644 test_linter.py diff --git a/3.2.1.tar.gz b/3.2.1.tar.gz deleted file mode 100644 index c23898b..0000000 --- a/3.2.1.tar.gz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1591897d08b06399fe18bbb631c74b98871b68ca72f230e1e09c3708c026ce9f -size 5969 diff --git a/flake8-debugger-4.0.0.tar.gz b/flake8-debugger-4.0.0.tar.gz new file mode 100644 index 0000000..cf7640b --- /dev/null +++ b/flake8-debugger-4.0.0.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e43dc777f7db1481db473210101ec2df2bd39a45b149d7218a618e954177eda6 +size 4258 diff --git a/pycodestyle-indent-size.patch b/pycodestyle-indent-size.patch new file mode 100644 index 0000000..454b275 --- /dev/null +++ b/pycodestyle-indent-size.patch @@ -0,0 +1,10 @@ +--- a/test_linter.py 2021-04-01 09:11:21.755700607 +0200 ++++ b/test_linter.py 2021-04-01 09:11:52.280287278 +0200 +@@ -31,6 +31,7 @@ + max_doc_length = None + hang_closing = False + verbose = False ++ indent_size = 4 + benchmark_keys = {"files": 0, "physical lines": 0, "logical lines": 0} + + diff --git a/python-flake8-debugger.changes b/python-flake8-debugger.changes index 9637470..8284f17 100644 --- a/python-flake8-debugger.changes +++ b/python-flake8-debugger.changes @@ -1,3 +1,11 @@ +------------------------------------------------------------------- +Thu Apr 1 07:18:57 UTC 2021 - Dirk Müller + +- update to 4.0.0: + * Opted back into using Poetry now that the existing issues have been fixed. + * Python 2.7 support was no officially dropped. +- add pycodestyle-indent-size.patch and use pypi tarball to avoid poetry + ------------------------------------------------------------------- Thu Apr 16 10:43:35 UTC 2020 - Tomáš Chvátal diff --git a/python-flake8-debugger.spec b/python-flake8-debugger.spec index c8e38bd..0e73406 100644 --- a/python-flake8-debugger.spec +++ b/python-flake8-debugger.spec @@ -1,7 +1,7 @@ # # spec file for package python-flake8-debugger # -# Copyright (c) 2020 SUSE LLC +# Copyright (c) 2021 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -17,15 +17,18 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} +%global skip_python2 1 Name: python-flake8-debugger -Version: 3.2.1 +Version: 4.0.0 Release: 0 Summary: ipdb/pdb statement checker plugin for flake8 License: MIT URL: https://github.com/jbkahn/flake8-debugger -Source: https://github.com/JBKahn/flake8-debugger/archive/%{version}.tar.gz +Source0: https://files.pythonhosted.org/packages/source/f/flake8-debugger/flake8-debugger-%{version}.tar.gz Source1: LICENSE -BuildRequires: %{python_module setuptools} +Source2: https://raw.githubusercontent.com/JBKahn/flake8-debugger/4.0.0/test_linter.py +# https://github.com/JBKahn/flake8-debugger/issues/28 +Patch1: pycodestyle-indent-size.patch BuildRequires: fdupes BuildRequires: python-rpm-macros BuildArch: noarch @@ -42,7 +45,8 @@ ipdb/pdb statement checker plugin for flake8 %prep %setup -q -n flake8-debugger-%{version} cp %{SOURCE1} . -sed -i -e '/pytest-runner/d' setup.py +cp %{SOURCE2} . +%patch1 -p1 %build %python_build diff --git a/test_linter.py b/test_linter.py new file mode 100644 index 0000000..bf2c257 --- /dev/null +++ b/test_linter.py @@ -0,0 +1,400 @@ +import pycodestyle + +from flake8_debugger import DebuggerChecker + +import pytest +import sys + + +class CaptureReport(pycodestyle.BaseReport): + """Collect the results of the checks.""" + + def __init__(self, options): + self._results = [] + super(CaptureReport, self).__init__(options) + + def error(self, line_number, offset, text, check): + """Store each error.""" + code = super(CaptureReport, self).error(line_number, offset, text, check) + if code: + record = {"line": line_number, "col": offset, "message": "{0} {1}".format(code, text[5:])} + self._results.append(record) + return code + + +class DebuggerTestStyleGuide(pycodestyle.StyleGuide): + + logical_checks = [] + physical_checks = [] + ast_checks = [("debugger_usage", DebuggerChecker, ["tree", "filename", "lines"])] + max_line_length = None + max_doc_length = None + hang_closing = False + verbose = False + benchmark_keys = {"files": 0, "physical lines": 0, "logical lines": 0} + + +_debugger_test_style = DebuggerTestStyleGuide() + + +def check_code_for_debugger_statements(code): + """Process code using pycodestyle Checker and return all errors.""" + from tempfile import NamedTemporaryFile + + test_file = NamedTemporaryFile(delete=False) + test_file.write(code.encode()) + test_file.flush() + report = CaptureReport(options=_debugger_test_style) + lines = [line + "\n" for line in code.split("\n")] + checker = pycodestyle.Checker(filename=test_file.name, lines=lines, options=_debugger_test_style, report=report) + + checker.check_all() + return report._results + + +class TestQA(object): + def test_catches_simple_debugger(self): + result = check_code_for_debugger_statements("from ipdb import set_trace as r\nr()") + + expected_result = [ + {"line": 2, "message": "T100 trace found: set_trace used as r", "col": 0}, + {"line": 1, "message": "T100 import for set_trace found as r", "col": 0}, + ] + + assert result == expected_result + + def test_catches_simple_debugger_when_called_off_lib(self): + result = check_code_for_debugger_statements("import ipdb\nipdb.set_trace()") + + expected_result = [ + {"line": 2, "message": "T100 trace found: ipdb.set_trace used", "col": 0}, + {"line": 1, "message": "T100 import for ipdb found", "col": 0}, + ] + + assert result == expected_result + + def test_catches_simple_debugger_when_called_off_global(self): + result = check_code_for_debugger_statements("__import__('ipdb').set_trace()") + + expected_result = [{"line": 1, "message": "T100 trace found: set_trace used", "col": 0}] + + assert result == expected_result + + @pytest.mark.skipif(True, reason="Not supported just yet") + def test_catches_simple_debugger_when_called_off_var(self): + result = check_code_for_debugger_statements("import ipdb\ntest = ipdb.set_trace\ntest()") + + expected_result = [ + {"line": 1, "message": "T100 import for ipdb found", "col": 0}, + {"line": 3, "message": "T100 trace found: ipdb.set_trace used", "col": 0}, + ] + assert result == expected_result + + +class TestBreakpoint(object): + @pytest.mark.skipif(sys.version_info < (3, 7), reason="breakpoint builtin introduced in 3.7") + def test_catches_breakpoint_call_for_python_3_7_and_above(self): + result = check_code_for_debugger_statements("breakpoint()") + + expected_result = [{"line": 1, "message": "T100 trace found: breakpoint used", "col": 0}] + + assert result == expected_result + + @pytest.mark.skipif(sys.version_info < (3, 7), reason="breakpoint builtin introduced in 3.7") + def test_catches_breakpoint_import(self): + result = check_code_for_debugger_statements("from builtins import breakpoint") + + expected_result = [{"line": 1, "message": "T100 import for breakpoint found", "col": 0}] + + assert result == expected_result + + @pytest.mark.skipif(sys.version_info < (3, 7), reason="breakpoint builtin introduced in 3.7") + def test_allows_builtins_import(self): + result = check_code_for_debugger_statements("import builtins") + + expected_result = [] + + assert result == expected_result + + @pytest.mark.skipif(sys.version_info < (3, 7), reason="breakpoint builtin introduced in 3.7") + def test_catches_breakpoint_usage_from_builtins(self): + result = check_code_for_debugger_statements("import builtins\nbuiltins.breakpoint()") + + expected_result = [{"col": 0, "line": 2, "message": "T100 trace found: breakpoint used"}] + + assert result == expected_result + + @pytest.mark.skipif(sys.version_info < (3, 7), reason="breakpoint builtin introduced in 3.7") + def test_catches_breakpoint_imported_as_other_name(self): + result = check_code_for_debugger_statements("from builtins import breakpoint as b\nb()") + + expected_result = [ + {"line": 2, "message": "T100 trace found: breakpoint used as b", "col": 0}, + {"line": 1, "message": "T100 import for breakpoint found as b", "col": 0}, + ] + + assert result == expected_result + + @pytest.mark.skipif(sys.version_info >= (3, 7), reason="breakpoint builtin introduced in 3.7") + def test_allows_breakpoint_call_for_python_below_3_7(self): + result = check_code_for_debugger_statements("breakpoint()") + + expected_result = [] + + assert result == expected_result + + +class TestNoQA(object): + @pytest.mark.skipif(sys.version_info < (2, 7), reason="Python 2.6 does not support noqa") + def test_skip_import(self): + result = check_code_for_debugger_statements("from ipdb import set_trace as r # noqa\nr()") + + expected_result = [{"line": 2, "message": "T100 trace found: set_trace used as r", "col": 0}] + + assert result == expected_result + + @pytest.mark.skipif(sys.version_info < (2, 7), reason="Python 2.6 does not support noqa") + def test_skip_usage(self): + result = check_code_for_debugger_statements("from ipdb import set_trace as r\nr() # noqa") + + expected_result = [{"line": 1, "message": "T100 import for set_trace found as r", "col": 0}] + + assert result == expected_result + + @pytest.mark.skipif(sys.version_info < (2, 7), reason="Python 2.6 does not support noqa") + def test_skip_import_and_usage(self): + result = check_code_for_debugger_statements("from ipdb import set_trace as r # noqa\nr() # noqa") + + expected_result = [] + + assert result == expected_result + + +class TestImportCases(object): + def test_import_multiple(self): + result = check_code_for_debugger_statements("import math, ipdb, collections") + assert result == [{"col": 0, "line": 1, "message": "T100 import for ipdb found"}] + + def test_import(self): + result = check_code_for_debugger_statements("import pdb") + assert result == [{"col": 0, "line": 1, "message": "T100 import for pdb found"}] + + def test_import_interactive_shell_embed(self): + result = check_code_for_debugger_statements("from IPython.terminal.embed import InteractiveShellEmbed") + assert result == [{"col": 0, "line": 1, "message": "T100 import for InteractiveShellEmbed found"}] + + def test_import_both_same_line(self): + result = check_code_for_debugger_statements("import pdb, ipdb") + result = sorted(result, key=lambda debugger: debugger["message"]) + expected_result = [ + {"col": 0, "line": 1, "message": "T100 import for ipdb found"}, + {"col": 0, "line": 1, "message": "T100 import for pdb found"}, + ] + assert result == expected_result + + def test_import_math(self): + result = check_code_for_debugger_statements("import math") + assert result == [] + + def test_import_noqa(self): + result = check_code_for_debugger_statements("import ipdb # noqa") + assert result == [] + + +class TestModuleSetTraceCases(object): + def test_import_ipython_terminal_embed_use_InteractiveShellEmbed(self): + result = check_code_for_debugger_statements( + "from IPython.terminal.embed import InteractiveShellEmbed; InteractiveShellEmbed()()" + ) + + expected_result = [ + {"col": 58, "line": 1, "message": "T100 trace found: InteractiveShellEmbed used"}, + {"col": 0, "line": 1, "message": "T100 import for InteractiveShellEmbed found"}, + ] + + try: + assert result == expected_result + except AssertionError: + for item in expected_result: + item["col"] = 0 + + assert result == expected_result + + def test_import_ipdb_use_set_trace(self): + result = check_code_for_debugger_statements("import ipdb;ipdb.set_trace();") + + expected_result = [ + {"col": 12, "line": 1, "message": "T100 trace found: ipdb.set_trace used"}, + {"col": 0, "line": 1, "message": "T100 import for ipdb found"}, + ] + + try: + assert result == expected_result + except AssertionError: + for item in expected_result: + item["col"] = 0 + + assert result == expected_result + + def test_import_pdb_use_set_trace(self): + result = check_code_for_debugger_statements("import pdb;pdb.set_trace();") + + expected_result = [ + {"col": 11, "line": 1, "message": "T100 trace found: pdb.set_trace used"}, + {"col": 0, "line": 1, "message": "T100 import for pdb found"}, + ] + + try: + assert result == expected_result + except AssertionError: + for item in expected_result: + item["col"] = 0 + + assert result == expected_result + + def test_import_pdb_use_set_trace_twice(self): + result = check_code_for_debugger_statements("import pdb;pdb.set_trace() and pdb.set_trace();") + + expected_result = [ + {"col": 11, "line": 1, "message": "T100 trace found: pdb.set_trace used"}, + {"col": 31, "line": 1, "message": "T100 trace found: pdb.set_trace used"}, + {"col": 0, "line": 1, "message": "T100 import for pdb found"}, + ] + + try: + assert result == expected_result + except AssertionError: + for item in expected_result: + item["col"] = 0 + + assert result == expected_result + + def test_import_other_module_as_set_trace_and_use_it(self): + result = check_code_for_debugger_statements("from math import Max as set_trace\nset_trace()") + assert result == [] + + +class TestImportAsCases(object): + def test_import_ipdb_as(self): + result = check_code_for_debugger_statements("import math, ipdb as sif, collections") + assert result == [{"col": 0, "line": 1, "message": "T100 import for ipdb found as sif"}] + + +class TestModuleASSetTraceCases(object): + def test_import_ipdb_as_use_set_trace(self): + result = check_code_for_debugger_statements("import ipdb as sif;sif.set_trace();") + + expected_result = [ + {"col": 19, "line": 1, "message": "T100 trace found: sif.set_trace used"}, + {"col": 0, "line": 1, "message": "T100 import for ipdb found as sif"}, + ] + + try: + assert result == expected_result + except AssertionError: + for item in expected_result: + item["col"] = 0 + + assert result == expected_result + + +class TestImportSetTraceCases(object): + def test_import_set_trace_ipdb(self): + result = check_code_for_debugger_statements("from ipdb import run, set_trace;set_trace();") + + expected_result = [ + {"col": 32, "line": 1, "message": "T100 trace found: set_trace used"}, + {"col": 0, "line": 1, "message": "T100 import for set_trace found"}, + ] + + try: + assert result == expected_result + except AssertionError: + for item in expected_result: + item["col"] = 0 + + assert result == expected_result + + def test_import_set_trace_pdb(self): + result = check_code_for_debugger_statements("from pdb import set_trace; set_trace();") + + expected_result = [ + {"col": 27, "line": 1, "message": "T100 trace found: set_trace used"}, + {"col": 0, "line": 1, "message": "T100 import for set_trace found"}, + ] + + try: + assert result == expected_result + except AssertionError: + for item in expected_result: + item["col"] = 0 + + assert result == expected_result + + def test_import_set_trace_ipdb_as_and_use(self): + result = check_code_for_debugger_statements("from ipdb import run, set_trace as sif; sif();") + + expected_result = [ + {"col": 40, "line": 1, "message": "T100 trace found: set_trace used as sif"}, + {"col": 0, "line": 1, "message": "T100 import for set_trace found as sif"}, + ] + + try: + assert result == expected_result + except AssertionError: + for item in expected_result: + item["col"] = 0 + + assert result == expected_result + + def test_import_set_trace_ipdb_as_and_use_with_conjunction_and(self): + result = check_code_for_debugger_statements("from ipdb import run, set_trace as sif; True and sif();") + + expected_result = [ + {"col": 49, "line": 1, "message": "T100 trace found: set_trace used as sif"}, + {"col": 0, "line": 1, "message": "T100 import for set_trace found as sif"}, + ] + + try: + assert result == expected_result + except AssertionError: + for item in expected_result: + item["col"] = 0 + + assert result == expected_result + + def test_import_set_trace_ipdb_as_and_use_with_conjunction_or(self): + result = check_code_for_debugger_statements("from ipdb import run, set_trace as sif; True or sif();") + + expected_result = [ + {"col": 48, "line": 1, "message": "T100 trace found: set_trace used as sif"}, + {"col": 0, "line": 1, "message": "T100 import for set_trace found as sif"}, + ] + + try: + assert result == expected_result + except AssertionError: + for item in expected_result: + item["col"] = 0 + + assert result == expected_result + + def test_import_set_trace_ipdb_as_and_use_with_conjunction_or_noqa(self): + result = check_code_for_debugger_statements("from ipdb import run, set_trace as sif; True or sif(); # noqa") + try: + assert result == [] + except AssertionError: + pass + + def test_import_set_trace_ipdb_as_and_use_with_conjunction_or_noqa_import_only(self): + result = check_code_for_debugger_statements("from ipdb import run, set_trace as sif # noqa\nTrue or sif()") + + expected_result = [{"col": 8, "line": 2, "message": "T100 trace found: set_trace used as sif"}] + + try: + assert result == expected_result + except AssertionError: + for item in expected_result: + item["col"] = 0 + + assert result == expected_result