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
hooks:
- id: check-executables-have-shebangs
- id: check-toml
- id: check-yaml
- id: end-of-file-fixer
types: [python]
@ -14,60 +15,41 @@ repos:
hooks:
- id: auto-walrus
- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: v0.0.255
hooks:
- id: ruff
- repo: https://github.com/psf/black
rev: 23.1.0
hooks:
- id: black
- repo: https://github.com/PyCQA/isort
rev: 5.12.0
- repo: https://github.com/codespell-project/codespell
rev: v2.2.4
hooks:
- id: isort
args:
- --profile=black
- id: codespell
additional_dependencies:
- tomli
- repo: https://github.com/tox-dev/pyproject-fmt
rev: "0.9.2"
hooks:
- 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
rev: v0.12.1
hooks:
- 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
rev: v1.1.1
hooks:
@ -77,25 +59,3 @@ repos:
- --install-types # See mirrors-mypy README.md
- --non-interactive
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 decimal import Decimal
from math import * # noqa: F401, F403
from math import * # noqa: F403
from sympy import diff

View File

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

View File

@ -166,7 +166,6 @@ def test_heap() -> None:
>>> h.get_top()
[9, -40]
"""
pass
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 implementation was tested on the
leetcode: https://leetcode.com/problems/edit-distance/
"""
"""
Levinstein distance
Dynamic Programming: up -> down.
"""
import functools
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")
10
"""
from functools import lru_cache
len_word1 = len(word1)
len_word2 = len(word2)
@lru_cache(maxsize=None)
@functools.cache
def min_distance(index1: int, index2: int) -> int:
# if first word index is overflow - delete all from the second word
if index1 >= len_word1:

View File

@ -22,7 +22,7 @@ Minimum Cost For Tickets
Dynamic Programming: up -> down.
"""
from functools import lru_cache
import functools
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)
@lru_cache(maxsize=None)
@functools.cache
def dynamic_programming(index: int) -> int:
if index > 365:
return 0

View File

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

View File

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

View File

@ -56,7 +56,7 @@ class SVC:
*,
regularization: float = np.inf,
kernel: str = "linear",
gamma: float = 0,
gamma: float = 0.0,
) -> None:
self.regularization = regularization
self.gamma = gamma
@ -65,7 +65,7 @@ class SVC:
elif kernel == "rbf":
if self.gamma == 0:
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")
if not self.gamma > 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
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)]
totients = [i - 1 for i in range(n + 1)]
primes = []
@ -20,25 +35,6 @@ def totient(n: int) -> list:
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__":
import doctest

View File

@ -16,7 +16,7 @@ fib_memoization runtime: 0.0107 ms
fib_binet runtime: 0.0174 ms
"""
from functools import lru_cache
import functools
from math import sqrt
from time import time
@ -110,7 +110,7 @@ def fib_recursive_cached(n: int) -> list[int]:
Exception: n is negative
"""
@lru_cache(maxsize=None)
@functools.cache
def fib_recursive_term(i: int) -> int:
"""
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:
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)
>>> point2 = Point(1, -3, 5)
>>> 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
"""
pass
return math.sqrt(abs((b.x - a.x) ** 2 + (b.y - a.y) ** 2 + (b.z - a.z) ** 2))
if __name__ == "__main__":

View File

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

View File

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

View File

@ -12,8 +12,57 @@ addopts = [
omit = [".env/*"]
sort = "Cover"
#[report]
#sort = Cover
#omit =
# .env/*
# backtracking/*
[tool.codespell]
ignore-words-list = "3rt,ans,crate,damon,fo,followings,hist,iff,kwanza,mater,secant,som,sur,tim,zar"
skip = "./.*,*.json,ciphers/prehistoric_men.txt,project_euler/problem_022/p022_names.txt,pyproject.toml,strings/dictionary.txt,strings/words.txt"
[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 = {}
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

View File

@ -2,7 +2,6 @@
wiki: https://en.wikipedia.org/wiki/Anagram
"""
from collections import defaultdict
from typing import DefaultDict
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
# 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,
# increment count in the corresponding

View File

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

View File

@ -8,7 +8,7 @@ import os
import requests
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", "")
if not API_KEY and not TESTING: