diff --git a/analyzer/codechecker_analyzer/analyzer_context.py b/analyzer/codechecker_analyzer/analyzer_context.py index 7fd15a8a8a..082c508a20 100644 --- a/analyzer/codechecker_analyzer/analyzer_context.py +++ b/analyzer/codechecker_analyzer/analyzer_context.py @@ -10,8 +10,7 @@ """ -# pylint: disable=deprecated-module -from distutils.spawn import find_executable +from shutil import which from argparse import ArgumentTypeError import os @@ -104,7 +103,7 @@ def __parse_cc_analyzer_bin(self): had_error = True continue - resolved_path = find_executable(path) + resolved_path = which(path) if not os.path.isfile(resolved_path): LOG.error(f"'{path}' is not a path to an analyzer binary " @@ -219,7 +218,7 @@ def __populate_analyzers(self): self._data_files_dir_path, value) else: env_path = analyzer_env['PATH'] if analyzer_env else None - compiler_binary = find_executable(value, env_path) + compiler_binary = which(cmd=value, path=env_path) if not compiler_binary: LOG.debug("'%s' binary can not be found in your PATH!", value) @@ -242,7 +241,7 @@ def __populate_replacer(self): self.__replacer = os.path.join(self._data_files_dir_path, replacer_binary) else: - self.__replacer = find_executable(replacer_binary) + self.__replacer = which(replacer_binary) @property def version(self): diff --git a/analyzer/codechecker_analyzer/analyzers/cppcheck/analyzer.py b/analyzer/codechecker_analyzer/analyzers/cppcheck/analyzer.py index cc4e187c89..4977462be3 100644 --- a/analyzer/codechecker_analyzer/analyzers/cppcheck/analyzer.py +++ b/analyzer/codechecker_analyzer/analyzers/cppcheck/analyzer.py @@ -10,9 +10,7 @@ """ from collections import defaultdict -# TODO distutils will be removed in python3.12 -# pylint: disable=deprecated-module -from distutils.version import StrictVersion +from packaging.version import Version from pathlib import Path import os import pickle @@ -347,7 +345,7 @@ def is_binary_version_incompatible(cls, environ): # The analyzer version should be above 1.80 because '--plist-output' # argument was introduced in this release. - if StrictVersion(analyzer_version) >= StrictVersion("1.80"): + if Version(analyzer_version) >= Version("1.80"): return None return "CppCheck binary found is too old at " \ diff --git a/analyzer/codechecker_analyzer/analyzers/gcc/analyzer.py b/analyzer/codechecker_analyzer/analyzers/gcc/analyzer.py index 6ec23aa7fd..f8814be82e 100644 --- a/analyzer/codechecker_analyzer/analyzers/gcc/analyzer.py +++ b/analyzer/codechecker_analyzer/analyzers/gcc/analyzer.py @@ -6,9 +6,7 @@ # # ------------------------------------------------------------------------- from collections import defaultdict -# TODO distutils will be removed in python3.12 -# pylint: disable=deprecated-module -from distutils.version import StrictVersion +from packaging.version import Version import os import pickle import shlex @@ -201,7 +199,7 @@ def is_binary_version_incompatible(cls, environ): # The analyzer version should be above 13.0.0 because the # '-fdiagnostics-format=sarif-file' argument was introduced in this # release. - if analyzer_version >= StrictVersion("13.0.0"): + if Version(analyzer_version) >= Version("13.0.0"): return None return f"GCC binary found is too old at v{analyzer_version.strip()}; "\ diff --git a/analyzer/codechecker_analyzer/buildlog/log_parser.py b/analyzer/codechecker_analyzer/buildlog/log_parser.py index 402c456228..7da28f4974 100644 --- a/analyzer/codechecker_analyzer/buildlog/log_parser.py +++ b/analyzer/codechecker_analyzer/buildlog/log_parser.py @@ -8,8 +8,7 @@ from collections import namedtuple -# pylint: disable=deprecated-module -from distutils.spawn import find_executable +from shutil import which from enum import Enum from pathlib import Path @@ -342,7 +341,7 @@ def cpp(): def is_executable_compiler(compiler): if compiler not in ImplicitCompilerInfo.compiler_isexecutable: ImplicitCompilerInfo.compiler_isexecutable[compiler] = \ - find_executable(compiler) is not None + which(compiler) is not None return ImplicitCompilerInfo.compiler_isexecutable[compiler] diff --git a/analyzer/requirements.txt b/analyzer/requirements.txt index 1fbcd0c57e..b32e65ea8a 100644 --- a/analyzer/requirements.txt +++ b/analyzer/requirements.txt @@ -5,3 +5,4 @@ PyYAML==6.0.1 types-PyYAML==6.0.12.12 sarif-tools==1.0.0 multiprocess==0.70.15 +setuptools==70.2.0 \ No newline at end of file diff --git a/analyzer/tests/functional/fixit/test_fixit.py b/analyzer/tests/functional/fixit/test_fixit.py index 0e85ca2751..8ee0ebe2a4 100644 --- a/analyzer/tests/functional/fixit/test_fixit.py +++ b/analyzer/tests/functional/fixit/test_fixit.py @@ -21,8 +21,7 @@ import time import unittest -# pylint: disable=deprecated-module -from distutils.spawn import find_executable +from shutil import which from libtest import env @@ -71,7 +70,7 @@ def teardown_method(self, _): if os.path.isdir(self.report_dir): shutil.rmtree(self.report_dir) - @unittest.skipIf(find_executable('clang-apply-replacements') is None, + @unittest.skipIf(which('clang-apply-replacements') is None, "clang-apply-replacements clang tool must be available " "in the environment.") def test_fixit_list(self): @@ -167,7 +166,7 @@ def test_fixit_list(self): self.assertIn("v.empty()", new_source_file) self.assertNotIn("v.size()", new_source_file) - @unittest.skipIf(find_executable('clang-apply-replacements') is None, + @unittest.skipIf(which('clang-apply-replacements') is None, "clang-apply-replacements clang tool must be available " "in the environment.") def test_fixit_file_modification(self): @@ -255,7 +254,7 @@ def test_fixit_file_modification(self): self.assertIn('Skipped files due to modification since last analysis', err) - @unittest.skipIf(find_executable('clang-apply-replacements') is None, + @unittest.skipIf(which('clang-apply-replacements') is None, "clang-apply-replacements clang tool must be available " "in the environment.") def test_fixit_by_diff(self): @@ -353,7 +352,7 @@ def test_fixit_by_diff(self): print('\n' + out + '\n') self.assertEqual(out.count("DiagnosticMessage"), 1) - @unittest.skipIf(find_executable('clang-apply-replacements') is None, + @unittest.skipIf(which('clang-apply-replacements') is None, "clang-apply-replacements clang tool must be available " "in the environment.") def test_fixit_apply_failure(self): diff --git a/analyzer/tests/functional/z3/test_z3.py b/analyzer/tests/functional/z3/test_z3.py index 5dd223b322..da2c17fea7 100644 --- a/analyzer/tests/functional/z3/test_z3.py +++ b/analyzer/tests/functional/z3/test_z3.py @@ -10,8 +10,7 @@ """ Z3 feature test. """ -# pylint: disable=deprecated-module -from distutils import util +from codechecker_common.util import strtobool import os import shutil import unittest @@ -117,8 +116,9 @@ def setup_method(self, _): if not self.z3_capable: try: - self.z3_capable = bool(util.strtobool( - os.environ['CC_TEST_FORCE_Z3_CAPABLE'])) + self.z3_capable = strtobool( + os.environ['CC_TEST_FORCE_Z3_CAPABLE'] + ) except (ValueError, KeyError): pass diff --git a/analyzer/tests/libtest/codechecker.py b/analyzer/tests/libtest/codechecker.py index 31f485ebe6..77b35cebfd 100644 --- a/analyzer/tests/libtest/codechecker.py +++ b/analyzer/tests/libtest/codechecker.py @@ -14,8 +14,7 @@ import shlex import subprocess -# pylint: disable=deprecated-module -from distutils import util +from codechecker_common.util import strtobool from codechecker_analyzer import host_check @@ -137,8 +136,7 @@ def check_force_ctu_capable(is_capable): """ if not is_capable: try: - return bool(util.strtobool( - os.environ['CC_TEST_FORCE_CTU_CAPABLE'])) + return strtobool(os.environ['CC_TEST_FORCE_CTU_CAPABLE']) except (ValueError, KeyError): pass diff --git a/analyzer/tests/unit/test_checker_handling.py b/analyzer/tests/unit/test_checker_handling.py index d506cbe1a8..1d62348d76 100644 --- a/analyzer/tests/unit/test_checker_handling.py +++ b/analyzer/tests/unit/test_checker_handling.py @@ -11,8 +11,7 @@ """ -# pylint: disable=deprecated-module -from distutils import util +from codechecker_common.util import strtobool import os import re import tempfile @@ -260,8 +259,9 @@ def f(checks, checkers): # Test if statisticsbased checkers are enabled by --stats flag # by default. - stats_capable = bool(util.strtobool( - os.environ.get('CC_TEST_FORCE_STATS_CAPABLE', 'False'))) + stats_capable = strtobool( + os.environ.get('CC_TEST_FORCE_STATS_CAPABLE', 'False') + ) if stats_capable: cfg_handler = ClangSA.construct_config_handler( diff --git a/codechecker_common/util.py b/codechecker_common/util.py index 3d0e88455b..e389b8d1a0 100644 --- a/codechecker_common/util.py +++ b/codechecker_common/util.py @@ -107,3 +107,8 @@ def path_for_fake_root(full_path: str, root_path: str = '/') -> str: relative_path = os.path.relpath(full_path, '/') fake_root_path = os.path.join(root_path, relative_path) return os.path.realpath(fake_root_path) + + +def strtobool(value: str) -> bool: + """Parse a string value to a boolean.""" + return value.lower() in ('y', 'yes', 't', 'true', 'on', '1') diff --git a/tools/tu_collector/tu_collector/tu_collector.py b/tools/tu_collector/tu_collector/tu_collector.py index dce07a088b..04fa784442 100755 --- a/tools/tu_collector/tu_collector/tu_collector.py +++ b/tools/tu_collector/tu_collector/tu_collector.py @@ -28,7 +28,7 @@ import subprocess import sys import zipfile -from distutils.spawn import find_executable +from shutil import which from pathlib import Path from typing import Iterable, Iterator, List, Optional, Set, Tuple, Union @@ -114,7 +114,7 @@ def __determine_compiler(gcc_command: List[str]) -> str: files or environment variables. """ if gcc_command[0].endswith('ccache'): - if find_executable(gcc_command[1]) is not None: + if which(gcc_command[1]) is not None: return gcc_command[1] return gcc_command[0] diff --git a/web/tests/functional/statistics/test_statistics.py b/web/tests/functional/statistics/test_statistics.py index 03c49733f5..61e3c08e86 100644 --- a/web/tests/functional/statistics/test_statistics.py +++ b/web/tests/functional/statistics/test_statistics.py @@ -10,8 +10,7 @@ """ statistics collector feature test. """ -# pylint: disable=deprecated-module -from distutils import util +from codechecker_common.util import strtobool import os import shutil import sys @@ -120,8 +119,9 @@ def setup_method(self, _): if not self.stats_capable: try: - self.stats_capable = bool(util.strtobool( - os.environ['CC_TEST_FORCE_STATS_CAPABLE'])) + self.stats_capable = strtobool( + os.environ['CC_TEST_FORCE_STATS_CAPABLE'] + ) except (ValueError, KeyError): pass