diff --git a/.github/actions/lint/action.yml b/.github/actions/lint/action.yml index 9478550c107b..1efa6aab79a5 100644 --- a/.github/actions/lint/action.yml +++ b/.github/actions/lint/action.yml @@ -47,3 +47,10 @@ runs: python -m black . --check working-directory: pythonFiles shell: bash + + - name: Run Ruff + run: | + python -m pip install -U ruff + python -m ruff check . + working-directory: pythonFiles + shell: bash diff --git a/pythonFiles/installed_check.py b/pythonFiles/installed_check.py index f0e1c268d270..df5d3cb9d082 100644 --- a/pythonFiles/installed_check.py +++ b/pythonFiles/installed_check.py @@ -36,7 +36,7 @@ def parse_requirements(line: str) -> Optional[Requirement]: return req elif req.marker.evaluate(): return req - except: + except Exception: return None @@ -51,7 +51,7 @@ def process_requirements(req_file: pathlib.Path) -> List[Dict[str, Union[str, in try: # Check if package is installed metadata(req.name) - except: + except Exception: diagnostics.append( { "line": n, @@ -79,7 +79,7 @@ def process_pyproject(req_file: pathlib.Path) -> List[Dict[str, Union[str, int]] try: raw_text = req_file.read_text(encoding="utf-8") pyproject = tomli.loads(raw_text) - except: + except Exception: return diagnostics lines = raw_text.splitlines() @@ -91,7 +91,7 @@ def process_pyproject(req_file: pathlib.Path) -> List[Dict[str, Union[str, int]] try: # Check if package is installed metadata(req.name) - except: + except Exception: diagnostics.append( { "line": n, diff --git a/pythonFiles/normalizeSelection.py b/pythonFiles/normalizeSelection.py index 35bc42d6e6fe..0363702717ab 100644 --- a/pythonFiles/normalizeSelection.py +++ b/pythonFiles/normalizeSelection.py @@ -118,7 +118,7 @@ def normalize_lines(selection): # Insert a newline between each top-level statement, and append a newline to the selection. source = "\n".join(statements) + "\n" - except: + except Exception: # If there's a problem when parsing statements, # append a blank line to end the block and send it as-is. source = selection + "\n\n" diff --git a/pythonFiles/pyproject.toml b/pythonFiles/pyproject.toml index 56237999e603..d865e27418e0 100644 --- a/pythonFiles/pyproject.toml +++ b/pythonFiles/pyproject.toml @@ -34,3 +34,34 @@ ignore = [ 'tests/testing_tools/adapter/pytest/test_cli.py', 'tests/testing_tools/adapter/pytest/test_discovery.py', ] + +[tool.ruff] +line-length = 140 +ignore = ["E402"] +exclude = [ + # Ignore testing_tools files same as Pyright way + 'get-pip.py', + 'install_debugpy.py', + 'tensorboard_launcher.py', + 'testlauncher.py', + 'visualstudio_py_testlauncher.py', + 'testing_tools/unittest_discovery.py', + 'testing_tools/adapter/util.py', + 'testing_tools/adapter/pytest/_discovery.py', + 'testing_tools/adapter/pytest/_pytest_item.py', + 'tests/debug_adapter/test_install_debugpy.py', + 'tests/testing_tools/adapter/.data', + 'tests/testing_tools/adapter/test___main__.py', + 'tests/testing_tools/adapter/test_discovery.py', + 'tests/testing_tools/adapter/test_functional.py', + 'tests/testing_tools/adapter/test_report.py', + 'tests/testing_tools/adapter/test_util.py', + 'tests/testing_tools/adapter/pytest/test_cli.py', + 'tests/testing_tools/adapter/pytest/test_discovery.py', + 'pythonFiles/testing_tools/*', + 'pythonFiles/testing_tools/adapter/pytest/__init__.py', + 'pythonFiles/tests/pytestadapter/expected_execution_test_output.py', + 'pythonFiles/tests/unittestadapter/.data/discovery_error/file_one.py', + 'pythonFiles/tests/unittestadapter/test_utils.py', + +] diff --git a/pythonFiles/shell_exec.py b/pythonFiles/shell_exec.py index c521586ca31b..4987399a53ea 100644 --- a/pythonFiles/shell_exec.py +++ b/pythonFiles/shell_exec.py @@ -1,9 +1,8 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. -import os -import sys import subprocess +import sys # This is a simple solution to waiting for completion of commands sent to terminal. # 1. Intercept commands send to a terminal diff --git a/pythonFiles/testing_tools/adapter/pytest/__init__.py b/pythonFiles/testing_tools/adapter/pytest/__init__.py index e894f7bcdb8e..89b7c066a459 100644 --- a/pythonFiles/testing_tools/adapter/pytest/__init__.py +++ b/pythonFiles/testing_tools/adapter/pytest/__init__.py @@ -3,5 +3,5 @@ from __future__ import absolute_import -from ._cli import add_subparser as add_cli_subparser -from ._discovery import discover +from ._cli import add_subparser as add_cli_subparser # noqa: F401 +from ._discovery import discover # noqa: F401 diff --git a/pythonFiles/tests/pytestadapter/expected_execution_test_output.py b/pythonFiles/tests/pytestadapter/expected_execution_test_output.py index fe1d40a55b43..dd8f458d792e 100644 --- a/pythonFiles/tests/pytestadapter/expected_execution_test_output.py +++ b/pythonFiles/tests/pytestadapter/expected_execution_test_output.py @@ -5,7 +5,9 @@ TEST_ADD_FUNCTION = "unittest_folder/test_add.py::TestAddFunction::" SUCCESS = "success" FAILURE = "failure" -TEST_SUBTRACT_FUNCTION_NEGATIVE_NUMBERS_ERROR = "self = \n\n def test_subtract_negative_numbers( # test_marker--test_subtract_negative_numbers\n self,\n ):\n result = subtract(-2, -3)\n> self.assertEqual(result, 100000)\nE AssertionError: 1 != 100000\n\nunittest_folder/test_subtract.py:25: AssertionError" + +TEST_SUBTRACT_FUNCTION_NEGATIVE_NUMBERS_ERROR = "self = \n\n def test_subtract_negative_numbers( # test_marker--test_subtract_negative_numbers\n self,\n ):\n result = subtract(-2, -3)\n> self.assertEqual(result, 100000)\nE AssertionError: 1 != 100000\n\nunittest_folder/test_subtract.py:25: AssertionError" # noqa: E501 + # This is the expected output for the unittest_folder execute tests # └── unittest_folder diff --git a/pythonFiles/tests/pytestadapter/helpers.py b/pythonFiles/tests/pytestadapter/helpers.py index c3e01d52170a..47b4f75d6d60 100644 --- a/pythonFiles/tests/pytestadapter/helpers.py +++ b/pythonFiles/tests/pytestadapter/helpers.py @@ -10,7 +10,7 @@ import sys import threading import uuid -from typing import Any, Dict, List, Optional, Tuple, Union +from typing import Any, Dict, List, Optional, Tuple TEST_DATA_PATH = pathlib.Path(__file__).parent / ".data" from typing_extensions import TypedDict diff --git a/pythonFiles/tests/pytestadapter/test_execution.py b/pythonFiles/tests/pytestadapter/test_execution.py index ffc84955bf54..e3b00386882d 100644 --- a/pythonFiles/tests/pytestadapter/test_execution.py +++ b/pythonFiles/tests/pytestadapter/test_execution.py @@ -4,6 +4,7 @@ import shutil import pytest + from tests.pytestadapter import expected_execution_test_output from .helpers import TEST_DATA_PATH, runner @@ -161,7 +162,7 @@ def test_pytest_execution(test_ids, expected_const): Keyword arguments: test_ids -- an array of test_ids to run. expected_const -- a dictionary of the expected output from running pytest discovery on the files. - """ + """ # noqa: E501 args = test_ids actual = runner(args) assert actual @@ -179,6 +180,6 @@ def test_pytest_execution(test_ids, expected_const): or actual_result_dict[key]["outcome"] == "error" ): actual_result_dict[key]["message"] = "ERROR MESSAGE" - if actual_result_dict[key]["traceback"] != None: + if actual_result_dict[key]["traceback"] is not None: actual_result_dict[key]["traceback"] = "TRACEBACK" assert actual_result_dict == expected_const diff --git a/pythonFiles/tests/test_create_microvenv.py b/pythonFiles/tests/test_create_microvenv.py index f123052c491c..e5d4e68802e9 100644 --- a/pythonFiles/tests/test_create_microvenv.py +++ b/pythonFiles/tests/test_create_microvenv.py @@ -6,7 +6,6 @@ import sys import create_microvenv -import pytest def test_create_microvenv(): @@ -26,4 +25,4 @@ def run_process(args, error_message): create_microvenv.run_process = run_process create_microvenv.main() - assert run_process_called == True + assert run_process_called is True diff --git a/pythonFiles/tests/test_create_venv.py b/pythonFiles/tests/test_create_venv.py index bebe304c13c3..ae3f18be6f3c 100644 --- a/pythonFiles/tests/test_create_venv.py +++ b/pythonFiles/tests/test_create_venv.py @@ -5,9 +5,10 @@ import os import sys -import create_venv import pytest +import create_venv + @pytest.mark.skipif( sys.platform == "win32", reason="Windows does not have micro venv fallback." @@ -35,7 +36,7 @@ def run_process(args, error_message): create_venv.main(["--name", ".test_venv"]) # run_process is called when the venv does not exist - assert run_process_called == True + assert run_process_called is True @pytest.mark.skipif( diff --git a/pythonFiles/tests/unittestadapter/.data/discovery_error/file_one.py b/pythonFiles/tests/unittestadapter/.data/discovery_error/file_one.py index 42f84f046760..031b6f6c9d68 100644 --- a/pythonFiles/tests/unittestadapter/.data/discovery_error/file_one.py +++ b/pythonFiles/tests/unittestadapter/.data/discovery_error/file_one.py @@ -3,7 +3,7 @@ import unittest -import something_else # type: ignore +import something_else # type: ignore # noqa: F401 class DiscoveryErrorOne(unittest.TestCase): diff --git a/pythonFiles/tests/unittestadapter/test_utils.py b/pythonFiles/tests/unittestadapter/test_utils.py index a3bc1dd7693c..e262f877d52c 100644 --- a/pythonFiles/tests/unittestadapter/test_utils.py +++ b/pythonFiles/tests/unittestadapter/test_utils.py @@ -6,6 +6,7 @@ import unittest import pytest + from unittestadapter.utils import ( TestNode, TestNodeTypeEnum, @@ -284,7 +285,8 @@ def test_build_decorated_tree() -> None: def test_build_empty_tree() -> None: - """The build_test_tree function should return None if there are no discovered test suites, and an empty list of errors if there are none in the discovered data.""" + """The build_test_tree function should return None if there are no discovered test suites, + and an empty list of errors if there are none in the discovered data.""" start_dir = os.fsdecode(TEST_DATA_PATH) pattern = "does_not_exist*" diff --git a/pythonFiles/unittestadapter/execution.py b/pythonFiles/unittestadapter/execution.py index dfb6928a2074..f239f81c2d87 100644 --- a/pythonFiles/unittestadapter/execution.py +++ b/pythonFiles/unittestadapter/execution.py @@ -17,8 +17,9 @@ sys.path.append(os.fspath(script_dir)) sys.path.insert(0, os.fspath(script_dir / "lib" / "python")) -from testing_tools import process_json_util, socket_manager from typing_extensions import NotRequired, TypeAlias, TypedDict + +from testing_tools import process_json_util, socket_manager from unittestadapter.utils import parse_unittest_args DEFAULT_PORT = "45454" @@ -194,12 +195,12 @@ def run_tests( # Discover tests at path with the file name as a pattern (if any). loader = unittest.TestLoader() - args = { + args = { # noqa: F841 "start_dir": start_dir, "pattern": pattern, "top_level_dir": top_level_dir, } - suite = loader.discover(start_dir, pattern, top_level_dir) + suite = loader.discover(start_dir, pattern, top_level_dir) # noqa: F841 # Run tests. runner = unittest.TextTestRunner(resultclass=UnittestTestResult) diff --git a/pythonFiles/unittestadapter/utils.py b/pythonFiles/unittestadapter/utils.py index 78000e2a945f..64f08217f38f 100644 --- a/pythonFiles/unittestadapter/utils.py +++ b/pythonFiles/unittestadapter/utils.py @@ -60,11 +60,11 @@ def get_source_line(obj) -> str: """Get the line number of a test case start line.""" try: sourcelines, lineno = inspect.getsourcelines(obj) - except: + except Exception: try: # tornado-specific, see https://github.com/microsoft/vscode-python/issues/17285. sourcelines, lineno = inspect.getsourcelines(obj.orig_method) - except: + except Exception: return "*" # Return the line number of the first line of the test case definition. @@ -226,7 +226,8 @@ def parse_unittest_args(args: List[str]) -> Tuple[str, str, Union[str, None]]: The returned tuple contains the following items - start_directory: The directory where to start discovery, defaults to . - pattern: The pattern to match test files, defaults to test*.py - - top_level_directory: The top-level directory of the project, defaults to None, and unittest will use start_directory behind the scenes. + - top_level_directory: The top-level directory of the project, defaults to None, + and unittest will use start_directory behind the scenes. """ arg_parser = argparse.ArgumentParser() diff --git a/pythonFiles/vscode_datascience_helpers/tests/logParser.py b/pythonFiles/vscode_datascience_helpers/tests/logParser.py index 767f837c5136..e021853fee7a 100644 --- a/pythonFiles/vscode_datascience_helpers/tests/logParser.py +++ b/pythonFiles/vscode_datascience_helpers/tests/logParser.py @@ -1,11 +1,10 @@ -from io import TextIOWrapper -import sys import argparse import os +from io import TextIOWrapper os.system("color") -from pathlib import Path import re +from pathlib import Path parser = argparse.ArgumentParser(description="Parse a test log into its parts") parser.add_argument("testlog", type=str, nargs=1, help="Log to parse") @@ -63,14 +62,14 @@ def splitByPid(testlog): pid = int(match.group(1)) # See if we've created a log for this pid or not - if not pid in pids: + if pid not in pids: pids.add(pid) logFile = "{}_{}.log".format(baseFile, pid) print("Writing to new log: " + logFile) logs[pid] = Path(logFile).open(mode="w") # Add this line to the log - if pid != None: + if pid is not None: logs[pid].write(line) # Close all of the open logs for key in logs: