From f488614bd1869bd5f60df5e8601dfd28effdbbe2 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Sat, 8 Mar 2025 07:10:42 +0100 Subject: [PATCH] Add ruff to pre-commit (#327) --- .pre-commit-config.yaml | 2 +- cpplint.py | 83 +++++++++++++++++++++++------------------ cpplint_clitest.py | 9 +++-- cpplint_unittest.py | 21 ++++++----- pyproject.toml | 78 +++++++++++++++++++++++++++++++++++++- 5 files changed, 140 insertions(+), 53 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6919581..9dc30df 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -15,7 +15,7 @@ repos: - tomli - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.9.9 + rev: v0.9.10 hooks: - id: ruff diff --git a/cpplint.py b/cpplint.py index 0e658d2..b2196da 100755 --- a/cpplint.py +++ b/cpplint.py @@ -1407,9 +1407,9 @@ def AddFilters(self, filters): if clean_filt: self.filters.append(clean_filt) for filt in self.filters: - if not (filt.startswith('+') or filt.startswith('-')): - raise ValueError('Every filter in --filters must start with + or -' - f' ({filt} does not)') + if not filt.startswith(('+', '-')): + msg = f'Every filter in --filters must start with + or - ({filt} does not)' + raise ValueError(msg) def BackupFilters(self): """ Saves the current filter list to backup storage.""" @@ -1618,7 +1618,7 @@ def Check(self, error, filename, linenum): trigger = base_trigger * 2**_VerboseLevel() if self.lines_in_function > trigger: - error_level = int(math.log(self.lines_in_function / base_trigger, 2)) + error_level = int(math.log2(self.lines_in_function / base_trigger)) # 50 => 0, 100 => 1, 200 => 2, 400 => 3, 800 => 4, 1600 => 5, ... if error_level > 5: error_level = 5 @@ -1769,7 +1769,9 @@ def _ShouldPrintError(category, confidence, filename, linenum): if category_match and file_match and line_match: is_filtered = False else: - assert False # should have been checked for in SetFilter. + # should have been checked for in SetFilter. + msg = f'Invalid filter: {one_filter}' + raise ValueError(msg) if is_filtered: return False @@ -2357,7 +2359,8 @@ def CheckForCopyright(filename, lines, error): # We'll say it should occur by line 10. Don't forget there's a # placeholder line at the front. for line in range(1, min(len(lines), 11)): - if re.search(r'Copyright', lines[line], re.I): break + if re.search(r'Copyright', lines[line], re.IGNORECASE): + break else: # means no copyright line was found error(filename, 0, 'legal/copyright', 5, 'No copyright message found. ' @@ -2376,8 +2379,7 @@ def GetIndentLevel(line): indent = re.match(r'^( *)\S', line) if indent: return len(indent.group(1)) - else: - return 0 + return 0 def PathSplitToList(path): """Returns the path split into a list by the separator. @@ -3108,14 +3110,16 @@ def InTemplateArgumentList(self, clean_lines, linenum, pos): # These things do not look like template argument list: # class Suspect { # class Suspect x; } - if token in ('{', '}', ';'): return False + if token in ('{', '}', ';'): + return False # These things look like template argument list: # template # template # template # template - if token in ('>', '=', '[', ']', '.'): return True + if token in ('>', '=', '[', ']', '.'): + return True # Check if token is an unmatched '<'. # If not, move on to the next character. @@ -4912,8 +4916,7 @@ def GetLineWidth(line): width += 1 return width - else: - return len(line) + return len(line) def CheckStyle(filename, clean_lines, linenum, file_extension, nesting_state, @@ -4985,9 +4988,7 @@ def CheckStyle(filename, clean_lines, linenum, file_extension, nesting_state, # Check if the line is a header guard. is_header_guard = False if IsHeaderExtension(file_extension): - if (line.startswith(f'#ifndef {cppvar}') or - line.startswith(f'#define {cppvar}') or - line.startswith(f'#endif // {cppvar}')): + if line.startswith((f'#ifndef {cppvar}', f'#define {cppvar}', f'#endif // {cppvar}')): is_header_guard = True # #include lines and header guards can be long, since there's no clean way to # split them. @@ -5126,8 +5127,7 @@ def _ClassifyInclude(fileinfo, include, used_angle_brackets, include_order="defa return _CPP_SYS_HEADER if is_std_c_header: return _C_SYS_HEADER - else: - return _OTHER_SYS_HEADER + return _OTHER_SYS_HEADER # If the target file and the include we're checking share a # basename when we drop common extensions, and the include @@ -5277,7 +5277,7 @@ def _GetTextInside(text, start_pattern): closing_punctuation = set(dict.values(matching_punctuation)) # Find the position to start extracting text. - match = re.search(start_pattern, text, re.M) + match = re.search(start_pattern, text, re.MULTILINE) if not match: # start_pattern not found in text. return None start_position = match.end(0) @@ -5422,7 +5422,7 @@ def CheckLanguage(filename, clean_lines, linenum, file_extension, match = re.match(r'([\w.\->()]+)$', printf_args) if match and match.group(1) != '__VA_ARGS__': function_name = re.search(r'\b((?:string)?printf)\s*\(', - line, re.I).group(1) + line, re.IGNORECASE).group(1) error(filename, linenum, 'runtime/printf', 4, 'Potential format string bug. Do' f' {function_name}("%s", {match.group(1)}) instead.') @@ -5458,17 +5458,25 @@ def CheckLanguage(filename, clean_lines, linenum, file_extension, skip_next = False continue - if re.search(r'sizeof\(.+\)', tok): continue - if re.search(r'arraysize\(\w+\)', tok): continue + if re.search(r'sizeof\(.+\)', tok): + continue + if re.search(r'arraysize\(\w+\)', tok): + continue tok = tok.lstrip('(') tok = tok.rstrip(')') - if not tok: continue - if re.match(r'\d+', tok): continue - if re.match(r'0[xX][0-9a-fA-F]+', tok): continue - if re.match(r'k[A-Z0-9]\w*', tok): continue - if re.match(r'(.+::)?k[A-Z0-9]\w*', tok): continue - if re.match(r'(.+::)?[A-Z][A-Z0-9_]*', tok): continue + if not tok: + continue + if re.match(r'\d+', tok): + continue + if re.match(r'0[xX][0-9a-fA-F]+', tok): + continue + if re.match(r'k[A-Z0-9]\w*', tok): + continue + if re.match(r'(.+::)?k[A-Z0-9]\w*', tok): + continue + if re.match(r'(.+::)?[A-Z][A-Z0-9_]*', tok): + continue # A catch all for tricky sizeof cases, including 'sizeof expression', # 'sizeof(*type)', 'sizeof(const type)', 'sizeof(struct StructName)' # requires skipping the next token because we split on ' ' and '*'. @@ -5783,7 +5791,7 @@ def CheckForNonConstReference(filename, clean_lines, linenum, r')\s*\(') if re.search(allowed_functions, line): return - elif not re.search(r'\S+\([^)]*$', line): + if not re.search(r'\S+\([^)]*$', line): # Don't see an allowed function on this line. Actually we # didn't see any function name on this line, so this is likely a # multi-line parameter list. Try a bit harder to catch this case. @@ -5955,8 +5963,7 @@ def CheckCStyleCast(filename, clean_lines, linenum, cast_type, pattern, error): return False # operator++(int) and operator--(int) - if (context.endswith(' operator++') or context.endswith(' operator--') or - context.endswith('::operator++') or context.endswith('::operator--')): + if context.endswith((' operator++', ' operator--', '::operator++', '::operator--')): return False # A single unnamed argument for a function tends to look like old style cast. @@ -6273,7 +6280,8 @@ def CheckRedundantVirtual(filename, clean_lines, linenum, error): # Look for "virtual" on current line. line = clean_lines.elided[linenum] virtual = re.match(r'^(.*)(\bvirtual\b)(.*)$', line) - if not virtual: return + if not virtual: + return # Ignore "virtual" keywords that are near access-specifiers. These # are only used in class base-specifier and do not apply to member @@ -6285,7 +6293,8 @@ def CheckRedundantVirtual(filename, clean_lines, linenum, error): # Ignore the "virtual" keyword from virtual base classes. Usually # there is a column on the same line in these cases (virtual base # classes are rare in google3 because multiple inheritance is rare). - if re.match(r'^.*[^:]:[^:].*$', line): return + if re.match(r'^.*[^:]:[^:].*$', line): + return # Look for the next opening parenthesis. This is the start of the # parameter list (possibly on the next line shortly after virtual). @@ -6374,7 +6383,7 @@ def IsBlockInNameSpace(nesting_state, is_forward_declaration): if len(nesting_state.stack) >= 1: if isinstance(nesting_state.stack[-1], _NamespaceInfo): return True - elif (len(nesting_state.stack) > 1 and + if (len(nesting_state.stack) > 1 and isinstance(nesting_state.previous_stack_top, _NamespaceInfo) and isinstance(nesting_state.stack[-2], _NamespaceInfo)): return True @@ -6453,7 +6462,8 @@ def ProcessLine(filename, file_extension, clean_lines, line, nesting_state.Update(filename, clean_lines, line, error) CheckForNamespaceIndentation(filename, nesting_state, clean_lines, line, error) - if nesting_state.InAsmBlock(): return + if nesting_state.InAsmBlock(): + return CheckForFunctionLengths(filename, clean_lines, line, function_state, error) CheckForMultilineCommentsAndStrings(filename, clean_lines, line, error) CheckStyle(filename, clean_lines, line, file_extension, nesting_state, error, cppvar) @@ -6895,9 +6905,8 @@ def _ParseFilterSelector(parameter): second_colon_pos = parameter.find(":", colon_pos + 1) if second_colon_pos == -1: return category, parameter[colon_pos + 1:], -1 - else: - return category, parameter[colon_pos + 1: second_colon_pos], \ - int(parameter[second_colon_pos + 1:]) + return category, parameter[colon_pos + 1: second_colon_pos], \ + int(parameter[second_colon_pos + 1:]) def _ExpandDirectories(filenames): """Searches a list of filenames and replaces directories in the list with diff --git a/cpplint_clitest.py b/cpplint_clitest.py index b23449a..d49d08c 100755 --- a/cpplint_clitest.py +++ b/cpplint_clitest.py @@ -33,11 +33,12 @@ import glob import os -import sys -import subprocess -import unittest import shutil +import subprocess +import sys import tempfile +import unittest + from pytest import mark from testfixtures import compare @@ -101,7 +102,7 @@ def setUpClass(cls): except Exception: try: cls.tearDownClass() - except Exception: + except Exception: # noqa: BLE001 pass raise diff --git a/cpplint_unittest.py b/cpplint_unittest.py index c0a4010..b6c6a2a 100755 --- a/cpplint_unittest.py +++ b/cpplint_unittest.py @@ -43,16 +43,17 @@ import sys import tempfile import unittest -from parameterized import parameterized + import pytest +from parameterized import parameterized import cpplint + def codecs_latin_encode(x): if sys.version_info < (3,): return x - else: - return codecs.latin_1_encode(x)[0] + return codecs.latin_1_encode(x)[0] # This class works as an error collector and replaces cpplint.Error # function for the unit tests. We also verify each category we see @@ -80,8 +81,7 @@ def __call__(self, filename, linenum, def Results(self): if len(self._errors) < 2: return ''.join(self._errors) # Most tests expect to have a string. - else: - return self._errors # Let's give a list if there is more than one. + return self._errors # Let's give a list if there is more than one. def ResultList(self): return self._errors @@ -115,7 +115,7 @@ class EnterableList(list): def __enter__(self): return self - def __exit__(self, type, value, tb): + def __exit__(self, type, value, tb): # noqa: A002 return self self.mock_file = EnterableList(mock_file) @@ -4283,8 +4283,8 @@ def testParseArguments(self): self.assertEqual(set(['hpp', 'h', 'cpp']), cpplint.GetAllExtensions()) finally: - sys.stdout == sys.__stdout__ - sys.stderr == sys.__stderr__ + sys.stdout = sys.__stdout__ + sys.stderr = sys.__stderr__ cpplint._cpplint_state.output_format = old_output_format cpplint._cpplint_state.verbose_level = old_verbose_level cpplint._cpplint_state.filters = old_filters @@ -4657,6 +4657,7 @@ def GetBuildHeaderGuardPreprocessorSymbol(self, file_path): error) if matched is not None: return matched.group(1) + return None def testBuildHeaderGuard(self): file_path = 'mydir/foo.h' @@ -5276,7 +5277,7 @@ def testBuildStorageClass(self): # Make sure that the declaration is logged if there's an error. # Seed generator with an integer for absolute reproducibility. random.seed(25) - for unused_i in range(10): + for _i in range(10): # Build up random list of non-storage-class declaration specs. other_decl_specs = [random.choice(qualifiers), random.choice(signs), random.choice(types)] @@ -5660,7 +5661,7 @@ def testRegression(self): def Format(includes): include_list = [] for item in includes: - if item.startswith('"') or item.startswith('<'): + if item.startswith(('"', '<')): include_list.append('#include %s\n' % item) else: include_list.append(item + '\n') diff --git a/pyproject.toml b/pyproject.toml index 5bc3130..c1e3f74 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -65,7 +65,83 @@ py-modules = [ "cpplint" ] include-package-data = false [tool.ruff] -lint.ignore = [ "E701" ] +target-version = "py38" + +line-length = 116 +lint.select = [ + "A", # flake8-builtins + "AIR", # Airflow + "ASYNC", # flake8-async + "B", # flake8-bugbear + "BLE", # flake8-blind-except + "C90", # McCabe cyclomatic complexity + "DJ", # flake8-django + "DTZ", # flake8-datetimez + "E", # pycodestyle + "EM", # flake8-errmsg + "EXE", # flake8-executable + "F", # Pyflakes + "FA", # flake8-future-annotations + "FAST", # FastAPI + "FBT", # flake8-boolean-trap + "FIX", # flake8-fixme + "FLY", # flynt + "FURB", # refurb + "G", # flake8-logging-format + "I", # isort + "ICN", # flake8-import-conventions + "INP", # flake8-no-pep420 + "INT", # flake8-gettext + "ISC", # flake8-implicit-str-concat + "LOG", # flake8-logging + "NPY", # NumPy-specific rules + "PD", # pandas-vet + "PERF", # Perflint + "PGH", # pygrep-hooks + "PIE", # flake8-pie + "PLC", # Pylint conventions + "PLE", # Pylint errors + "PYI", # flake8-pyi + "RET", # flake8-return + "RSE", # flake8-raise + "SLOT", # flake8-slots + "T10", # flake8-debugger + "TC", # flake8-type-checking + "TID", # flake8-tidy-imports + "TRY", # tryceratops + "W", # pycodestyle + "YTT", # flake8-2020 + # "ANN", # flake8-annotations + # "ARG", # flake8-unused-arguments + # "C4", # flake8-comprehensions + # "COM", # flake8-commas + # "CPY", # flake8-copyright + # "D", # pydocstyle + # "DOC", # pydoclint + # "ERA", # eradicate + # "N", # pep8-naming + # "PLR", # Pylint refactor + # "PLW", # Pylint warnings + # "PT", # flake8-pytest-style + # "PTH", # flake8-use-pathlib + # "Q", # flake8-quotes + # "RUF", # Ruff-specific rules + # "S", # flake8-bandit + # "SIM", # flake8-simplify + # "SLF", # flake8-self + # "T20", # flake8-print + # "TD", # flake8-todos + # "UP", # pyupgrade +] +lint.ignore = [ + "FBT003", # flake8-boolean-trap + "FIX002", # flake8-fixme + "ISC003", # flake8-implicit-str-concat + "PIE790", # Unnecessary `pass` statement +] +lint.per-file-ignores."cpplint.py" = [ "ICN001", "PERF401" ] +lint.per-file-ignores."cpplint_unittest.py" = [ "FLY002" ] +lint.mccabe.max-complexity = 29 [tool.pytest.ini_options] python_files = [ "*test.py" ] pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy