Replace bandit, flake8, isort, and pyupgrade with ruff (#8178)

* Replace bandit, flake8, isort, and pyupgrade with ruff

* Comment on ruff rules

* updating DIRECTORY.md

---------

Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com>
This commit is contained in:
Christian Clauss 2023-03-15 13:58:25 +01:00 committed by GitHub
parent adc3ccdabe
commit c96241b5a5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 127 additions and 132 deletions

10
.flake8
View File

@ -1,10 +0,0 @@
[flake8]
max-line-length = 88
# max-complexity should be 10
max-complexity = 19
extend-ignore =
# Formatting style for `black`
# E203 is whitespace before ':'
E203,
# W503 is line break occurred before a binary operator
W503

16
.github/workflows/ruff.yml vendored Normal file
View File

@ -0,0 +1,16 @@
# https://beta.ruff.rs
name: ruff
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
ruff:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: pip install --user ruff
- run: ruff --format=github .

View File

@ -3,6 +3,7 @@ repos:
rev: v4.4.0 rev: v4.4.0
hooks: hooks:
- id: check-executables-have-shebangs - id: check-executables-have-shebangs
- id: check-toml
- id: check-yaml - id: check-yaml
- id: end-of-file-fixer - id: end-of-file-fixer
types: [python] types: [python]
@ -14,60 +15,41 @@ repos:
hooks: hooks:
- id: auto-walrus - id: auto-walrus
- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: v0.0.255
hooks:
- id: ruff
- repo: https://github.com/psf/black - repo: https://github.com/psf/black
rev: 23.1.0 rev: 23.1.0
hooks: hooks:
- id: black - id: black
- repo: https://github.com/PyCQA/isort - repo: https://github.com/codespell-project/codespell
rev: 5.12.0 rev: v2.2.4
hooks: hooks:
- id: isort - id: codespell
args: additional_dependencies:
- --profile=black - tomli
- repo: https://github.com/tox-dev/pyproject-fmt - repo: https://github.com/tox-dev/pyproject-fmt
rev: "0.9.2" rev: "0.9.2"
hooks: hooks:
- id: pyproject-fmt - id: pyproject-fmt
- repo: local
hooks:
- id: validate-filenames
name: Validate filenames
entry: ./scripts/validate_filenames.py
language: script
pass_filenames: false
- repo: https://github.com/abravalheri/validate-pyproject - repo: https://github.com/abravalheri/validate-pyproject
rev: v0.12.1 rev: v0.12.1
hooks: hooks:
- id: validate-pyproject - id: validate-pyproject
- repo: https://github.com/asottile/pyupgrade
rev: v3.3.1
hooks:
- id: pyupgrade
args:
- --py311-plus
- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: v0.0.255
hooks:
- id: ruff
args:
- --ignore=E741
- repo: https://github.com/PyCQA/flake8
rev: 6.0.0
hooks:
- id: flake8 # See .flake8 for args
additional_dependencies: &flake8-plugins
- flake8-bugbear
- flake8-builtins
# - flake8-broken-line
- flake8-comprehensions
- pep8-naming
- repo: https://github.com/asottile/yesqa
rev: v1.4.0
hooks:
- id: yesqa
additional_dependencies:
*flake8-plugins
- repo: https://github.com/pre-commit/mirrors-mypy - repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.1.1 rev: v1.1.1
hooks: hooks:
@ -77,25 +59,3 @@ repos:
- --install-types # See mirrors-mypy README.md - --install-types # See mirrors-mypy README.md
- --non-interactive - --non-interactive
additional_dependencies: [types-requests] additional_dependencies: [types-requests]
- repo: https://github.com/codespell-project/codespell
rev: v2.2.4
hooks:
- id: codespell
args:
- --ignore-words-list=3rt,ans,crate,damon,fo,followings,hist,iff,kwanza,mater,secant,som,sur,tim,zar
exclude: |
(?x)^(
ciphers/prehistoric_men.txt |
strings/dictionary.txt |
strings/words.txt |
project_euler/problem_022/p022_names.txt
)$
- repo: local
hooks:
- id: validate-filenames
name: Validate filenames
entry: ./scripts/validate_filenames.py
language: script
pass_filenames: false

View File

@ -5,7 +5,7 @@
from __future__ import annotations from __future__ import annotations
from decimal import Decimal from decimal import Decimal
from math import * # noqa: F401, F403 from math import * # noqa: F403
from sympy import diff from sympy import diff

View File

@ -8,7 +8,7 @@
# Newton's Method - https://en.wikipedia.org/wiki/Newton's_method # Newton's Method - https://en.wikipedia.org/wiki/Newton's_method
from sympy import diff, lambdify, symbols from sympy import diff, lambdify, symbols
from sympy.functions import * # noqa: F401, F403 from sympy.functions import * # noqa: F403
def newton_raphson( def newton_raphson(

View File

@ -166,7 +166,6 @@ def test_heap() -> None:
>>> h.get_top() >>> h.get_top()
[9, -40] [9, -40]
""" """
pass
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -6,13 +6,13 @@ to find edit distance.
The aim is to demonstate up bottom approach for solving the task. The aim is to demonstate up bottom approach for solving the task.
The implementation was tested on the The implementation was tested on the
leetcode: https://leetcode.com/problems/edit-distance/ leetcode: https://leetcode.com/problems/edit-distance/
"""
"""
Levinstein distance Levinstein distance
Dynamic Programming: up -> down. Dynamic Programming: up -> down.
""" """
import functools
def min_distance_up_bottom(word1: str, word2: str) -> int: def min_distance_up_bottom(word1: str, word2: str) -> int:
""" """
@ -25,13 +25,10 @@ def min_distance_up_bottom(word1: str, word2: str) -> int:
>>> min_distance_up_bottom("zooicoarchaeologist", "zoologist") >>> min_distance_up_bottom("zooicoarchaeologist", "zoologist")
10 10
""" """
from functools import lru_cache
len_word1 = len(word1) len_word1 = len(word1)
len_word2 = len(word2) len_word2 = len(word2)
@lru_cache(maxsize=None) @functools.cache
def min_distance(index1: int, index2: int) -> int: def min_distance(index1: int, index2: int) -> int:
# if first word index is overflow - delete all from the second word # if first word index is overflow - delete all from the second word
if index1 >= len_word1: if index1 >= len_word1:

View File

@ -22,7 +22,7 @@ Minimum Cost For Tickets
Dynamic Programming: up -> down. Dynamic Programming: up -> down.
""" """
from functools import lru_cache import functools
def mincost_tickets(days: list[int], costs: list[int]) -> int: def mincost_tickets(days: list[int], costs: list[int]) -> int:
@ -106,7 +106,7 @@ def mincost_tickets(days: list[int], costs: list[int]) -> int:
days_set = set(days) days_set = set(days)
@lru_cache(maxsize=None) @functools.cache
def dynamic_programming(index: int) -> int: def dynamic_programming(index: int) -> int:
if index > 365: if index > 365:
return 0 return 0

View File

@ -20,7 +20,7 @@ Runtime: O(n * n)
Space: O(n) Space: O(n)
""" """
from functools import lru_cache import functools
from typing import Any from typing import Any
@ -80,7 +80,7 @@ def word_break(string: str, words: list[str]) -> bool:
len_string = len(string) len_string = len(string)
# Dynamic programming method # Dynamic programming method
@lru_cache(maxsize=None) @functools.cache
def is_breakable(index: int) -> bool: def is_breakable(index: int) -> bool:
""" """
>>> string = 'a' >>> string = 'a'

View File

@ -26,7 +26,6 @@ Reference: https://deadhacker.com/2006/02/21/sha-1-illustrated/
import argparse import argparse
import hashlib # hashlib is only used inside the Test class import hashlib # hashlib is only used inside the Test class
import struct import struct
import unittest
class SHA1Hash: class SHA1Hash:
@ -128,14 +127,9 @@ class SHA1Hash:
return "%08x%08x%08x%08x%08x" % tuple(self.h) return "%08x%08x%08x%08x%08x" % tuple(self.h)
class SHA1HashTest(unittest.TestCase): def test_sha1_hash():
""" msg = b"Test String"
Test class for the SHA1Hash class. Inherits the TestCase class from unittest assert SHA1Hash(msg).final_hash() == hashlib.sha1(msg).hexdigest() # noqa: S324
"""
def testMatchHashes(self): # noqa: N802
msg = bytes("Test String", "utf-8")
self.assertEqual(SHA1Hash(msg).final_hash(), hashlib.sha1(msg).hexdigest())
def main(): def main():

View File

@ -56,7 +56,7 @@ class SVC:
*, *,
regularization: float = np.inf, regularization: float = np.inf,
kernel: str = "linear", kernel: str = "linear",
gamma: float = 0, gamma: float = 0.0,
) -> None: ) -> None:
self.regularization = regularization self.regularization = regularization
self.gamma = gamma self.gamma = gamma
@ -65,7 +65,7 @@ class SVC:
elif kernel == "rbf": elif kernel == "rbf":
if self.gamma == 0: if self.gamma == 0:
raise ValueError("rbf kernel requires gamma") raise ValueError("rbf kernel requires gamma")
if not (isinstance(self.gamma, float) or isinstance(self.gamma, int)): if not isinstance(self.gamma, (float, int)):
raise ValueError("gamma must be float or int") raise ValueError("gamma must be float or int")
if not self.gamma > 0: if not self.gamma > 0:
raise ValueError("gamma must be > 0") raise ValueError("gamma must be > 0")

View File

@ -1,5 +1,20 @@
# Eulers Totient function finds the number of relative primes of a number n from 1 to n # Eulers Totient function finds the number of relative primes of a number n from 1 to n
def totient(n: int) -> list: def totient(n: int) -> list:
"""
>>> n = 10
>>> totient_calculation = totient(n)
>>> for i in range(1, n):
... print(f"{i} has {totient_calculation[i]} relative primes.")
1 has 0 relative primes.
2 has 1 relative primes.
3 has 2 relative primes.
4 has 2 relative primes.
5 has 4 relative primes.
6 has 2 relative primes.
7 has 6 relative primes.
8 has 4 relative primes.
9 has 6 relative primes.
"""
is_prime = [True for i in range(n + 1)] is_prime = [True for i in range(n + 1)]
totients = [i - 1 for i in range(n + 1)] totients = [i - 1 for i in range(n + 1)]
primes = [] primes = []
@ -20,25 +35,6 @@ def totient(n: int) -> list:
return totients return totients
def test_totient() -> None:
"""
>>> n = 10
>>> totient_calculation = totient(n)
>>> for i in range(1, n):
... print(f"{i} has {totient_calculation[i]} relative primes.")
1 has 0 relative primes.
2 has 1 relative primes.
3 has 2 relative primes.
4 has 2 relative primes.
5 has 4 relative primes.
6 has 2 relative primes.
7 has 6 relative primes.
8 has 4 relative primes.
9 has 6 relative primes.
"""
pass
if __name__ == "__main__": if __name__ == "__main__":
import doctest import doctest

View File

@ -16,7 +16,7 @@ fib_memoization runtime: 0.0107 ms
fib_binet runtime: 0.0174 ms fib_binet runtime: 0.0174 ms
""" """
from functools import lru_cache import functools
from math import sqrt from math import sqrt
from time import time from time import time
@ -110,7 +110,7 @@ def fib_recursive_cached(n: int) -> list[int]:
Exception: n is negative Exception: n is negative
""" """
@lru_cache(maxsize=None) @functools.cache
def fib_recursive_term(i: int) -> int: def fib_recursive_term(i: int) -> int:
""" """
Calculates the i-th (0-indexed) Fibonacci number using recursion Calculates the i-th (0-indexed) Fibonacci number using recursion

View File

@ -14,17 +14,13 @@ class Point:
def distance(a: Point, b: Point) -> float: def distance(a: Point, b: Point) -> float:
return math.sqrt(abs((b.x - a.x) ** 2 + (b.y - a.y) ** 2 + (b.z - a.z) ** 2))
def test_distance() -> None:
""" """
>>> point1 = Point(2, -1, 7) >>> point1 = Point(2, -1, 7)
>>> point2 = Point(1, -3, 5) >>> point2 = Point(1, -3, 5)
>>> print(f"Distance from {point1} to {point2} is {distance(point1, point2)}") >>> print(f"Distance from {point1} to {point2} is {distance(point1, point2)}")
Distance from Point(2, -1, 7) to Point(1, -3, 5) is 3.0 Distance from Point(2, -1, 7) to Point(1, -3, 5) is 3.0
""" """
pass return math.sqrt(abs((b.x - a.x) ** 2 + (b.y - a.y) ** 2 + (b.z - a.z) ** 2))
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -1,4 +1,5 @@
#!/bin/python3 #!/bin/python3
# ruff: noqa
""" """
Quine: Quine:

View File

@ -29,7 +29,6 @@ Reference: https://en.wikipedia.org/wiki/Pythagorean_triple#Generating_a_triple
from collections import defaultdict from collections import defaultdict
from math import gcd from math import gcd
from typing import DefaultDict
def solution(limit: int = 1500000) -> int: def solution(limit: int = 1500000) -> int:
@ -43,7 +42,7 @@ def solution(limit: int = 1500000) -> int:
>>> solution(50000) >>> solution(50000)
5502 5502
""" """
frequencies: DefaultDict = defaultdict(int) frequencies: defaultdict = defaultdict(int)
euclid_m = 2 euclid_m = 2
while 2 * euclid_m * (euclid_m + 1) <= limit: while 2 * euclid_m * (euclid_m + 1) <= limit:
for euclid_n in range((euclid_m % 2) + 1, euclid_m, 2): for euclid_n in range((euclid_m % 2) + 1, euclid_m, 2):

View File

@ -12,8 +12,57 @@ addopts = [
omit = [".env/*"] omit = [".env/*"]
sort = "Cover" sort = "Cover"
#[report] [tool.codespell]
#sort = Cover ignore-words-list = "3rt,ans,crate,damon,fo,followings,hist,iff,kwanza,mater,secant,som,sur,tim,zar"
#omit = skip = "./.*,*.json,ciphers/prehistoric_men.txt,project_euler/problem_022/p022_names.txt,pyproject.toml,strings/dictionary.txt,strings/words.txt"
# .env/*
# backtracking/* [tool.ruff]
ignore = [ # `ruff rule S101` for a description of that rule
"B904", # B904: Within an `except` clause, raise exceptions with `raise ... from err`
"B905", # B905: `zip()` without an explicit `strict=` parameter
"E741", # E741: Ambiguous variable name 'l'
"G004", # G004 Logging statement uses f-string
"N999", # N999: Invalid module name
"PLC1901", # PLC1901: `{}` can be simplified to `{}` as an empty string is falsey
"PLR2004", # PLR2004: Magic value used in comparison
"PLR5501", # PLR5501: Consider using `elif` instead of `else`
"PLW0120", # PLW0120: `else` clause on loop without a `break` statement
"PLW060", # PLW060: Using global for `{name}` but no assignment is done -- DO NOT FIX
"PLW2901", # PLW2901: Redefined loop variable
"RUF00", # RUF00: Ambiguous unicode character -- DO NOT FIX
"RUF100", # RUF100: Unused `noqa` directive
"S101", # S101: Use of `assert` detected -- DO NOT FIX
"S105", # S105: Possible hardcoded password: 'password'
"S113", # S113: Probable use of requests call without timeout
"UP038", # UP038: Use `X | Y` in `{}` call instead of `(X, Y)` -- DO NOT FIX
]
select = [ # https://beta.ruff.rs/docs/rules
"A", # A: builtins
"B", # B: bugbear
"C40", # C40: comprehensions
"C90", # C90: mccabe code complexity
"E", # E: pycodestyle errors
"F", # F: pyflakes
"G", # G: logging format
"I", # I: isort
"N", # N: pep8 naming
"PL", # PL: pylint
"PIE", # PIE: pie
"PYI", # PYI: type hinting stub files
"RUF", # RUF: ruff
"S", # S: bandit
"TID", # TID: tidy imports
"UP", # UP: pyupgrade
"W", # W: pycodestyle warnings
"YTT", # YTT: year 2020
]
target-version = "py311"
[tool.ruff.mccabe] # DO NOT INCREASE THIS VALUE
max-complexity = 20 # default: 10
[tool.ruff.pylint] # DO NOT INCREASE THESE VALUES
max-args = 10 # default: 5
max-branches = 20 # default: 12
max-returns = 8 # default: 6
max-statements = 88 # default: 50

View File

@ -104,7 +104,7 @@ class FileMerger:
files = {} files = {}
for i in range(len(filenames)): for i in range(len(filenames)):
files[i] = open(filenames[i], "r", buffer_size) files[i] = open(filenames[i], "r", buffer_size) # noqa: UP015
return files return files

View File

@ -2,7 +2,6 @@
wiki: https://en.wikipedia.org/wiki/Anagram wiki: https://en.wikipedia.org/wiki/Anagram
""" """
from collections import defaultdict from collections import defaultdict
from typing import DefaultDict
def check_anagrams(first_str: str, second_str: str) -> bool: def check_anagrams(first_str: str, second_str: str) -> bool:
@ -30,7 +29,7 @@ def check_anagrams(first_str: str, second_str: str) -> bool:
return False return False
# Default values for count should be 0 # Default values for count should be 0
count: DefaultDict[str, int] = defaultdict(int) count: defaultdict[str, int] = defaultdict(int)
# For each character in input strings, # For each character in input strings,
# increment count in the corresponding # increment count in the corresponding

View File

@ -1,7 +1,6 @@
# Created by sarathkaul on 17/11/19 # Created by sarathkaul on 17/11/19
# Modified by Arkadip Bhattacharya(@darkmatter18) on 20/04/2020 # Modified by Arkadip Bhattacharya(@darkmatter18) on 20/04/2020
from collections import defaultdict from collections import defaultdict
from typing import DefaultDict
def word_occurrence(sentence: str) -> dict: def word_occurrence(sentence: str) -> dict:
@ -15,7 +14,7 @@ def word_occurrence(sentence: str) -> dict:
>>> dict(word_occurrence("Two spaces")) >>> dict(word_occurrence("Two spaces"))
{'Two': 1, 'spaces': 1} {'Two': 1, 'spaces': 1}
""" """
occurrence: DefaultDict[str, int] = defaultdict(int) occurrence: defaultdict[str, int] = defaultdict(int)
# Creating a dictionary containing count of each word # Creating a dictionary containing count of each word
for word in sentence.split(): for word in sentence.split():
occurrence[word] += 1 occurrence[word] += 1

View File

@ -8,7 +8,7 @@ import os
import requests import requests
URL_BASE = "https://www.amdoren.com/api/currency.php" URL_BASE = "https://www.amdoren.com/api/currency.php"
TESTING = os.getenv("CI", False) TESTING = os.getenv("CI", "")
API_KEY = os.getenv("AMDOREN_API_KEY", "") API_KEY = os.getenv("AMDOREN_API_KEY", "")
if not API_KEY and not TESTING: if not API_KEY and not TESTING: