diff --git a/.github/workflows/check-python.yml b/.github/workflows/check-python.yml index 5878a9f5..21fa84da 100644 --- a/.github/workflows/check-python.yml +++ b/.github/workflows/check-python.yml @@ -28,4 +28,4 @@ jobs: mypy . --exclude 79_Slalom --exclude 27_Civil_War --exclude 38_Fur_Trader --exclude 81_Splat --exclude 09_Battle --exclude 40_Gomoko --exclude 36_Flip_Flop --exclude 43_Hammurabi --exclude 04_Awari --exclude 78_Sine_Wave --exclude 77_Salvo --exclude 34_Digits --exclude 17_Bullfight --exclude 16_Bug - name: Test with flake8 run: | - flake8 . --ignore E501,W503,E203,E731 + flake8 . --ignore E501,W503,E203,E731,B011 diff --git a/00_Utilities/python/ci-requirements.in b/00_Utilities/python/ci-requirements.in index baf71ecc..7efd7199 100644 --- a/00_Utilities/python/ci-requirements.in +++ b/00_Utilities/python/ci-requirements.in @@ -1,3 +1,4 @@ pytest flake8 +flake8-bugbear mypy diff --git a/00_Utilities/python/ci-requirements.txt b/00_Utilities/python/ci-requirements.txt index 549785af..56923d59 100644 --- a/00_Utilities/python/ci-requirements.txt +++ b/00_Utilities/python/ci-requirements.txt @@ -5,8 +5,14 @@ # pip-compile ci-requirements.in # attrs==21.4.0 - # via pytest + # via + # flake8-bugbear + # pytest flake8==4.0.1 + # via + # -r ci-requirements.in + # flake8-bugbear +flake8-bugbear==22.1.11 # via -r ci-requirements.in iniconfig==1.1.1 # via pytest diff --git a/04_Awari/python/awari.py b/04_Awari/python/awari.py index f648a5c8..4398cb3f 100644 --- a/04_Awari/python/awari.py +++ b/04_Awari/python/awari.py @@ -292,7 +292,7 @@ def do_move(m, home, board): move_stones = board[m] board[m] = 0 - for stones in range(move_stones, 0, -1): + for _stones in range(move_stones, 0, -1): m = m + 1 if m > 13: m = m - 14 diff --git a/06_Banner/python/banner.py b/06_Banner/python/banner.py index 7ef1d507..cd32e87a 100644 --- a/06_Banner/python/banner.py +++ b/06_Banner/python/banner.py @@ -97,11 +97,11 @@ def print_banner(): if s[u] == 1: f[u] = 8 - k break - for t1 in range(1, x + 1): + for _t1 in range(1, x + 1): line_str = " " * int((63 - 4.5 * y) * g1 / len(xStr) + 1) for b in range(0, f[u] + 1): if j[b] == 0: - for i in range(1, y + 1): + for _ in range(1, y + 1): line_str = line_str + " " * len(xStr) else: line_str = line_str + xStr * y diff --git a/14_Bowling/python/bowling.py b/14_Bowling/python/bowling.py index a5d8f079..b2fdd500 100644 --- a/14_Bowling/python/bowling.py +++ b/14_Bowling/python/bowling.py @@ -66,7 +66,7 @@ class Player: print(f"Extra rolls for {self.name}") pins = [0] * 10 # reset the pins score = 0 - for ball in range(extra): + for _ball in range(extra): if score == 10: pins = [0] * 10 simulateRoll(pins) diff --git a/15_Boxing/python/boxing.py b/15_Boxing/python/boxing.py index fe624101..61c2ef43 100755 --- a/15_Boxing/python/boxing.py +++ b/15_Boxing/python/boxing.py @@ -48,7 +48,7 @@ def play(): if opponent_score >= 2 or player_score >= 2: break - for action in range(7): + for _action in range(7): if random.randint(1, 10) > 5: # opponent swings punch = random.randint(1, 4) diff --git a/16_Bug/python/Bug.py b/16_Bug/python/Bug.py index 819e50ef..71344b4c 100644 --- a/16_Bug/python/Bug.py +++ b/16_Bug/python/Bug.py @@ -1,4 +1,5 @@ import random +import time def print_n_whitespaces(n: int): @@ -179,8 +180,7 @@ while not (Y > 0): # 970 X = random.randint(1, 6) print() - for delay in range(2000): - pass + time.sleep(2) print("I ROLLED A", X) if X == 1: diff --git a/21_Calendar/python/calendar.py b/21_Calendar/python/calendar.py index e954d7c7..5332f201 100644 --- a/21_Calendar/python/calendar.py +++ b/21_Calendar/python/calendar.py @@ -109,9 +109,9 @@ def calendar(weekday, leap_year): print(days) print(sep) - for w in range(1, 7): + for _ in range(1, 7): print("\n") - for g in range(1, 8): + for g in range(1, 8): # noqa d += 1 d2 = d - days_count diff --git a/32_Diamond/python/diamond.py b/32_Diamond/python/diamond.py index a622eb58..4d99dacc 100644 --- a/32_Diamond/python/diamond.py +++ b/32_Diamond/python/diamond.py @@ -52,7 +52,7 @@ def main(): count = int(PAGE_WIDTH / width) - for down in range(count): + for _down in range(count): print_diamond(1, width, 2, width, count) print_diamond(width - 2, 1, -2, width, count) diff --git a/33_Dice/python/dice.py b/33_Dice/python/dice.py index 9f46a8d8..c86c4bc4 100644 --- a/33_Dice/python/dice.py +++ b/33_Dice/python/dice.py @@ -51,7 +51,7 @@ while still_playing: n = int(input("How many rolls? ")) # Roll the dice n times - for i in range(n): + for _ in range(n): die1 = random.randint(1, 6) die2 = random.randint(1, 6) roll_total = die1 + die2 diff --git a/34_Digits/python/Digits.py b/34_Digits/python/Digits.py index bda172a9..c6d10977 100644 --- a/34_Digits/python/Digits.py +++ b/34_Digits/python/Digits.py @@ -93,7 +93,7 @@ def main(): z2 = 2 running_correct = 0 - for round in range(1, 4): + for _round in range(1, 4): valid_numbers = False numbers = [] while not valid_numbers: diff --git a/43_Hammurabi/python/hamurabi.py b/43_Hammurabi/python/hamurabi.py index ee224f6d..6bf990df 100644 --- a/43_Hammurabi/python/hamurabi.py +++ b/43_Hammurabi/python/hamurabi.py @@ -225,7 +225,7 @@ def main(): else: print("A FANTASTIC PERFORMANCE!!! CHARLEMANGE, DISRAELI, AND") print("JEFFERSON COMBINED COULD NOT HAVE DONE BETTER!\n") - for N in range(1, 10): + for _ in range(1, 10): print("\a") print("\nSO LONG FOR NOW.\n") diff --git a/46_Hexapawn/python/hexapawn.py b/46_Hexapawn/python/hexapawn.py index 3821b2c6..254b5f17 100644 --- a/46_Hexapawn/python/hexapawn.py +++ b/46_Hexapawn/python/hexapawn.py @@ -418,9 +418,9 @@ def find_board_index_that_matches_board(board): if matches: return board_index, is_reversed - # THE TERMINATION OF THIS LOOP IS IMPOSSIBLE - print("ILLEGAL BOARD PATTERN.") - assert False + # This point should never be reached + # In future, mypy might be able to check exhaustiveness via assert_never + raise RuntimeError("ILLEGAL BOARD PATTERN.") def pick_computer_move(board): diff --git a/47_Hi-Lo/python/hilo.py b/47_Hi-Lo/python/hilo.py index 6341311a..d0badf73 100755 --- a/47_Hi-Lo/python/hilo.py +++ b/47_Hi-Lo/python/hilo.py @@ -21,7 +21,7 @@ def play(): secret = random.randint(1, 100) guessed_correctly = False - for attempt in range(MAX_ATTEMPTS): + for _attempt in range(MAX_ATTEMPTS): print("YOUR GUESS", end=QUESTION_PROMPT) guess = int(input()) diff --git a/55_Life/python/life.py b/55_Life/python/life.py index 71016871..5a8e5062 100644 --- a/55_Life/python/life.py +++ b/55_Life/python/life.py @@ -55,7 +55,7 @@ def main(): pattern_height = len(pattern) pattern_width = 0 - for line_num, line in pattern.items(): + for _line_num, line in pattern.items(): pattern_width = max(pattern_width, len(line)) min_x = 11 - pattern_height // 2 @@ -94,7 +94,7 @@ def main(): p = 0 g += 1 - for x in range(0, min_x): + for _ in range(min_x): print() for x in range(min_x, max_x + 1): @@ -120,7 +120,7 @@ def main(): print("".join(line)) # line 295 - for x in range(max_x + 1, MAX_HEIGHT): + for _ in range(max_x + 1, MAX_HEIGHT): print() print() diff --git a/60_Mastermind/python/mastermind.py b/60_Mastermind/python/mastermind.py index 24897906..fbb94bd1 100644 --- a/60_Mastermind/python/mastermind.py +++ b/60_Mastermind/python/mastermind.py @@ -38,7 +38,7 @@ def main(): print("Guess my combination ...") answer = int(possibilities * random.random()) numeric_answer = [-1] * num_positions - for i in range(0, answer): + for _ in range(0, answer): numeric_answer = get_possibility(numeric_answer) # human_readable_answer = make_human_readable(numeric_answer) while num_moves < 10 and not turn_over: @@ -122,7 +122,7 @@ def main(): inconsistent_information = True else: numeric_guess = [-1] * num_positions - for i in range(0, guess): + for _ in range(0, guess): numeric_guess = get_possibility(numeric_guess) human_readable_guess = make_human_readable(numeric_guess) print(f"My guess is: {human_readable_guess}") @@ -142,7 +142,7 @@ def main(): if all_possibilities[i] == 0: # already ruled out continue numeric_possibility = [-1] * num_positions - for j in range(0, i): + for _ in range(0, i): numeric_possibility = get_possibility( numeric_possibility ) diff --git a/65_Nim/python/Traditional_NIM.py b/65_Nim/python/Traditional_NIM.py index c7b904ce..ce00b40a 100644 --- a/65_Nim/python/Traditional_NIM.py +++ b/65_Nim/python/Traditional_NIM.py @@ -68,7 +68,7 @@ class NIM: def check_for_win(self): sum = 0 - for k, v in self.piles.items(): + for v in self.piles.values(): sum += v if sum == 0: diff --git a/69_Pizza/python/pizza.py b/69_Pizza/python/pizza.py index 0f59262d..0f7d28e2 100644 --- a/69_Pizza/python/pizza.py +++ b/69_Pizza/python/pizza.py @@ -28,7 +28,7 @@ def print_header(title): def print_ticks(): - for t in range(4): + for _ in range(4): print("-") @@ -134,7 +134,7 @@ def deliver_to(customer_index, customer_name, player_name): def play_game(num_turns, player_name): - for turn in range(num_turns): + for _turn in range(num_turns): x = random.randint(1, 4) y = random.randint(1, 4) customer_index = calculate_customer_index(x, y) diff --git a/77_Salvo/python/salvo.py b/77_Salvo/python/salvo.py index 4de418ca..113a97b3 100644 --- a/77_Salvo/python/salvo.py +++ b/77_Salvo/python/salvo.py @@ -209,7 +209,7 @@ def generate_ship_coordinates(ship): coords = [(start_x, start_y)] x_coord = start_x y_coord = start_y - for i in range(ship_len): + for _ in range(ship_len): x_coord = x_coord + d_x y_coord = y_coord + d_y coords.append((x_coord, y_coord)) @@ -356,7 +356,7 @@ def initialize_game(): for ship in SHIPS: print(ship[0]) list = [] - for i in range(ship[1]): + for _ in range(ship[1]): x, y = input_coord() list.append((x, y)) ship_coords.append(list) @@ -443,7 +443,7 @@ def execute_turn(turn): num_shots = num_player_shots shots = [] - for shot in range(num_shots): + for _shot in range(num_shots): valid_shot = False x = -1 y = -1 diff --git a/78_Sine_Wave/python/sinewave.py b/78_Sine_Wave/python/sinewave.py index edb1e03b..5706225b 100644 --- a/78_Sine_Wave/python/sinewave.py +++ b/78_Sine_Wave/python/sinewave.py @@ -46,7 +46,7 @@ radians = 0 width = CENTER - 1 # "Start long loop" -for line_num in range(MAX_LINES): +for _line_num in range(MAX_LINES): # Get string to display on this line curr_string = STRINGS[string_index] diff --git a/84_Super_Star_Trek/python/superstartrek.py b/84_Super_Star_Trek/python/superstartrek.py index dcd879f2..01a0631b 100644 --- a/84_Super_Star_Trek/python/superstartrek.py +++ b/84_Super_Star_Trek/python/superstartrek.py @@ -882,7 +882,7 @@ def new_quadrant(): if b3 > 0: b4, b5 = find_empty_place() # position of starbase (sector) insert_marker(b4, b5, ">!<") - for i in range(s3): + for _ in range(s3): r1, r2 = find_empty_place() insert_marker(r1, r2, " * ") diff --git a/84_Super_Star_Trek/python/superstartrekins.py b/84_Super_Star_Trek/python/superstartrekins.py index 63736e4c..1dae1749 100644 --- a/84_Super_Star_Trek/python/superstartrekins.py +++ b/84_Super_Star_Trek/python/superstartrekins.py @@ -14,7 +14,7 @@ def get_yes_no(prompt): def print_header(): - for i in range(12): + for _ in range(12): print() t10 = " " * 10 print(t10 + "*************************************") @@ -24,7 +24,7 @@ def print_header(): print(t10 + "* *") print(t10 + "* *") print(t10 + "*************************************") - for i in range(8): + for _ in range(8): print() diff --git a/86_Target/python/target.py b/86_Target/python/target.py index 055891b0..14b58df5 100644 --- a/86_Target/python/target.py +++ b/86_Target/python/target.py @@ -55,7 +55,7 @@ def prompt(): def next_target(): - for i in range(5): + for _ in range(5): print() print("NEXT TARGET...") print() diff --git a/95_Weekday/python/test_weekday.py b/95_Weekday/python/test_weekday.py new file mode 100644 index 00000000..67185b72 --- /dev/null +++ b/95_Weekday/python/test_weekday.py @@ -0,0 +1,49 @@ +import datetime + +import pytest +from weekday import calculate_day_of_week + + +@pytest.mark.parametrize( + ("year", "month", "day"), + [ + (yr, m, d) + for yr in range(1600, 2021) + for m in range(1, 12) + for d in range(1, 28) + ], +) +@pytest.mark.slow # Those are 125,037 tests! +def test_weekday_calc(year, month, day): + dt = datetime.date(year, month, day) + python_weekday = dt.weekday() # Monday = 0, Sunday = 6 + + basic_weekday = calculate_day_of_week(year, month, day) # Sunday = 1, Saturday = 7 + + if ((python_weekday + 2) % 7) != (basic_weekday % 7): + print(f"testing yr {year} month {month} day {day}") + print(f"python says {python_weekday}") + print(f"BASIC says {basic_weekday}") + assert False + + +@pytest.mark.parametrize( + ("year", "month", "day"), + [ + (yr, m, d) + for yr in range(2016, 2021) + for m in range(1, 12) + for d in range(1, 28) + ], +) +def test_weekday_calc_4_years(year, month, day): + dt = datetime.date(year, month, day) + python_weekday = dt.weekday() # Monday = 0, Sunday = 6 + + basic_weekday = calculate_day_of_week(year, month, day) # Sunday = 1, Saturday = 7 + + if ((python_weekday + 2) % 7) != (basic_weekday % 7): + print(f"testing yr {year} month {month} day {day}") + print(f"python says {python_weekday}") + print(f"BASIC says {basic_weekday}") + assert False diff --git a/95_Weekday/python/weekday.py b/95_Weekday/python/weekday.py index 808e43e5..133cb391 100644 --- a/95_Weekday/python/weekday.py +++ b/95_Weekday/python/weekday.py @@ -142,7 +142,7 @@ def calculate_day_of_week(year, month, day): def end(): - for i in range(5): + for _ in range(5): print() @@ -259,26 +259,6 @@ def main(): end() -def test_weekday_calc(year, month, day): - dt = datetime.date(year, month, day) - python_weekday = dt.weekday() # Monday = 0, Sunday = 6 - - basic_weekday = calculate_day_of_week(year, month, day) # Sunday = 1, Saturday = 7 - - if ((python_weekday + 2) % 7) != (basic_weekday % 7): - print(f"testing yr {year} month {month} day {day}") - print(f"python says {python_weekday}") - print(f"BASIC says {basic_weekday}") - assert False - - -def test_harness(): - for yr in range(1600, 2021): - for m in range(1, 12): - for d in range(1, 28): - test_weekday_calc(yr, m, d) - - if __name__ == "__main__": main() diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..dff6b32d --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,4 @@ +[tool.pytest.ini_options] +markers = [ + "slow: marks tests as slow (deselect with '-m \"not slow\"')", +]