mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-07-04 14:43:01 +02:00
Enable D100-D107 docstring rules: add docstrings to all modules, classes, methods, and functions
- Added module docstrings to 19 Python files - Added class docstrings to 5 classes (ScreenLocker, PokerModifierApp, etc.) - Added method docstrings to 22 methods - Added function docstrings to 25 functions - Added __init__ docstrings to 5 classes - Removed D100-D107 from ruff ignore list (docstrings now enforced) - Removed deprecated ANN101, ANN102, UP038 rules from ignore list - Fixed UP038: use union types in isinstance() calls - All ruff checks now pass with full docstring enforcement
This commit is contained in:
parent
1bc09449b5
commit
3ac56e541e
@ -1,3 +1,8 @@
|
||||
"""Download cat images from TheCatAPI.
|
||||
|
||||
Fetches cat images in batches and saves them to a local directory.
|
||||
"""
|
||||
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
|
||||
@ -55,6 +55,7 @@ def extract_hosts_from_html(html_text: str) -> list[str]:
|
||||
|
||||
|
||||
def main() -> int:
|
||||
"""Parse command-line arguments and extract hosts from an HTML file."""
|
||||
ap = argparse.ArgumentParser(
|
||||
description="Extract hosts from hrefs in an HTML file."
|
||||
)
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
"""Unit tests for link extraction functionality."""
|
||||
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
import sys
|
||||
@ -10,10 +12,12 @@ SCRIPT = ROOT / "main.py"
|
||||
|
||||
|
||||
def read_lines(p: Path):
|
||||
"""Read lines from a file, stripping newlines."""
|
||||
return [l.rstrip("\n") for l in p.read_text(encoding="utf-8").splitlines()]
|
||||
|
||||
|
||||
def test_extract_hosts_function():
|
||||
"""Test extract_hosts_from_html extracts unique hosts in order."""
|
||||
from main import extract_hosts_from_html
|
||||
|
||||
html = (
|
||||
@ -28,6 +32,7 @@ def test_extract_hosts_function():
|
||||
|
||||
|
||||
def test_cli_writes_expected_output(tmp_path: Path):
|
||||
"""Test CLI writes correctly formatted output file."""
|
||||
# copy sample1.html to tmpdir and run the script
|
||||
sample = ROOT / "tests" / "sample1.html"
|
||||
html_copy = tmp_path / "sample1.html"
|
||||
@ -49,6 +54,7 @@ def test_cli_writes_expected_output(tmp_path: Path):
|
||||
|
||||
|
||||
def test_cli_default_output_name(tmp_path: Path):
|
||||
"""Test CLI generates default output filename from input."""
|
||||
sample = ROOT / "tests" / "sample2.html"
|
||||
html_copy = tmp_path / "sample2.html"
|
||||
html_copy.write_text(sample.read_text(encoding="utf-8"), encoding="utf-8")
|
||||
|
||||
@ -1,3 +1,8 @@
|
||||
"""Keyboard cooperative word game using Pygame.
|
||||
|
||||
Players take turns selecting adjacent keys to form valid English words.
|
||||
"""
|
||||
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
@ -62,7 +67,10 @@ KEY_ADJACENCY = {
|
||||
|
||||
|
||||
class KeyboardCoopGame:
|
||||
"""Main game class for the keyboard cooperative word game."""
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize the game window, fonts, and game state."""
|
||||
self.screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
|
||||
pygame.display.set_caption("Keyboard Coop Game")
|
||||
self.clock = pygame.time.Clock()
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
"""Chess engine wrapper for the C-based random/scoring engine."""
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
@ -23,6 +25,7 @@ class RandomEngine:
|
||||
max_time_sec: float = 2.0,
|
||||
depth: int | None = None,
|
||||
):
|
||||
"""Initialize the engine wrapper with path and time settings."""
|
||||
self.max_time_sec = max_time_sec
|
||||
# depth is accepted for compatibility with existing callers but is unused;
|
||||
# the C engine handles its own scoring/selection.
|
||||
@ -67,6 +70,7 @@ class RandomEngine:
|
||||
return (proc.stdout or "").strip()
|
||||
|
||||
def choose_move(self, board: chess.Board) -> chess.Move:
|
||||
"""Choose a move for the given board position."""
|
||||
mv, _ = self.choose_move_with_explanation(
|
||||
board, time_budget_sec=self.max_time_sec
|
||||
)
|
||||
@ -75,6 +79,7 @@ class RandomEngine:
|
||||
def choose_move_with_explanation(
|
||||
self, board: chess.Board, *, time_budget_sec: float
|
||||
) -> tuple[chess.Move | None, str]:
|
||||
"""Choose a move and return explanation for the decision."""
|
||||
# Collect legal moves and send to engine as plain UCI tokens.
|
||||
legal = list(board.legal_moves)
|
||||
if not legal:
|
||||
@ -135,7 +140,7 @@ class RandomEngine:
|
||||
# candidate score if provided
|
||||
analyze = data.get("analyze") or {}
|
||||
cs = analyze.get("candidate_score")
|
||||
if isinstance(cs, (int, float)):
|
||||
if isinstance(cs, int | float):
|
||||
cand_score = float(cs)
|
||||
# best move
|
||||
chosen = data.get("chosen_move")
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
"""Lichess API client for bot interactions."""
|
||||
|
||||
from collections.abc import Generator
|
||||
import contextlib
|
||||
import json
|
||||
@ -11,7 +13,10 @@ LICHESS_API = "https://lichess.org"
|
||||
|
||||
|
||||
class LichessAPI:
|
||||
"""Client for interacting with the Lichess Bot API."""
|
||||
|
||||
def __init__(self, token: str, session: requests.Session | None = None):
|
||||
"""Initialize the API client with authentication token."""
|
||||
self.token = token
|
||||
self.session = session or requests.Session()
|
||||
self.session.headers.update(
|
||||
@ -62,6 +67,7 @@ class LichessAPI:
|
||||
return r
|
||||
|
||||
def stream_events(self) -> Generator[dict, None, None]:
|
||||
"""Stream incoming events (challenges, game starts, etc.)."""
|
||||
url = f"{LICHESS_API}/api/stream/event"
|
||||
backoff = 0.5
|
||||
while True:
|
||||
@ -90,10 +96,12 @@ class LichessAPI:
|
||||
raise
|
||||
|
||||
def accept_challenge(self, challenge_id: str) -> None:
|
||||
"""Accept a challenge by its ID."""
|
||||
url = f"{LICHESS_API}/api/challenge/{challenge_id}/accept"
|
||||
self._request("POST", url, timeout=30, raise_for_status=True)
|
||||
|
||||
def decline_challenge(self, challenge_id: str, reason: str = "generic") -> None:
|
||||
"""Decline a challenge with an optional reason."""
|
||||
url = f"{LICHESS_API}/api/challenge/{challenge_id}/decline"
|
||||
data = {"reason": reason}
|
||||
self._request("POST", url, data=data, timeout=30, raise_for_status=True)
|
||||
@ -135,6 +143,7 @@ class LichessAPI:
|
||||
return board, color
|
||||
|
||||
def stream_game_events(self, game_id: str) -> Generator[dict, None, None]:
|
||||
"""Stream game state events for a specific game."""
|
||||
url = f"{LICHESS_API}/api/board/game/stream/{game_id}"
|
||||
headers = {"Accept": "application/x-ndjson"}
|
||||
with self._request("GET", url, headers=headers, stream=True, timeout=None) as r:
|
||||
@ -148,6 +157,7 @@ class LichessAPI:
|
||||
logging.debug(f"Skipping non-JSON line in game {game_id}: {line}")
|
||||
|
||||
def make_move(self, game_id: str, move: chess.Move) -> None:
|
||||
"""Submit a move to an active game."""
|
||||
url = f"{LICHESS_API}/api/board/game/{game_id}/move/{move.uci()}"
|
||||
r = self._request("POST", url, timeout=30)
|
||||
if r.status_code in (400, 409):
|
||||
@ -165,6 +175,7 @@ class LichessAPI:
|
||||
return None
|
||||
|
||||
def get_my_user_id(self) -> str | None:
|
||||
"""Fetch the authenticated user's ID."""
|
||||
url = f"{LICHESS_API}/api/account"
|
||||
r = self._request("GET", url, timeout=30)
|
||||
if r.status_code == 200:
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
"""Main entry point for the Lichess bot."""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import logging
|
||||
@ -15,6 +17,7 @@ from PYTHON.lichess_bot.utils import backoff_sleep, get_and_increment_version
|
||||
|
||||
|
||||
def run_bot(log_level: str = "INFO", decline_correspondence: bool = False) -> None:
|
||||
"""Start the bot and listen for incoming events."""
|
||||
logging.basicConfig(
|
||||
level=getattr(logging, log_level.upper(), logging.INFO),
|
||||
format="[%(asctime)s] %(levelname)s %(threadName)s: %(message)s",
|
||||
@ -448,6 +451,7 @@ def run_bot(log_level: str = "INFO", decline_correspondence: bool = False) -> No
|
||||
|
||||
|
||||
def main():
|
||||
"""Parse arguments and run the Lichess bot."""
|
||||
parser = argparse.ArgumentParser(description="Run a minimal Lichess bot")
|
||||
parser.add_argument(
|
||||
"--log-level", default="INFO", help="Logging level (default: INFO)"
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
"""Test the engine against Lichess puzzles."""
|
||||
|
||||
import csv
|
||||
import os
|
||||
|
||||
@ -9,6 +11,7 @@ from PYTHON.lichess_bot.engine import RandomEngine
|
||||
|
||||
def _load_top_puzzles(csv_path: str, limit: int = 8) -> list[tuple[str, str]]:
|
||||
"""Return a list of (FEN, solution_moves_str) for the first `limit` rows in the CSV.
|
||||
|
||||
CSV columns: PuzzleId,FEN,Moves,...
|
||||
"""
|
||||
puzzles: list[tuple[str, str]] = []
|
||||
@ -31,6 +34,7 @@ def _load_top_puzzles(csv_path: str, limit: int = 8) -> list[tuple[str, str]]:
|
||||
),
|
||||
)
|
||||
def test_puzzle_engine_follow_solution(fen: str, moves_str: str):
|
||||
"""Verify the engine follows puzzle solutions correctly."""
|
||||
board = chess.Board(fen)
|
||||
eng = RandomEngine(max_time_sec=1.0)
|
||||
|
||||
|
||||
@ -1,7 +1,10 @@
|
||||
"""Tests for utility functions."""
|
||||
|
||||
from PYTHON.lichess_bot.utils import backoff_sleep
|
||||
|
||||
|
||||
def test_backoff_sleep_increments_and_caps(monkeypatch):
|
||||
"""Test that backoff sleep increments and respects the cap."""
|
||||
slept = []
|
||||
|
||||
def fake_sleep(sec):
|
||||
|
||||
@ -1,7 +1,10 @@
|
||||
"""Tests for bot version management."""
|
||||
|
||||
from PYTHON.lichess_bot.utils import get_and_increment_version
|
||||
|
||||
|
||||
def test_version_file_increments_and_persists(tmp_path, monkeypatch):
|
||||
"""Test that version increments and persists to file."""
|
||||
version_file = tmp_path / "version.txt"
|
||||
monkeypatch.setenv("LICHESS_BOT_VERSION_FILE", str(version_file))
|
||||
|
||||
|
||||
@ -48,6 +48,8 @@ logging.basicConfig(level=logging.INFO)
|
||||
|
||||
@dataclass
|
||||
class Blunder:
|
||||
"""Data class representing a blunder move from analysis."""
|
||||
|
||||
ply: int
|
||||
side: str # 'W' or 'B'
|
||||
san: str # SAN of the played blunder
|
||||
@ -55,6 +57,7 @@ class Blunder:
|
||||
|
||||
|
||||
def parse_columns_for_blunders(text: str) -> list[Blunder]:
|
||||
"""Parse the Columns section of a log file to extract blunders."""
|
||||
lines = text.splitlines()
|
||||
# Find start of "Columns:" block
|
||||
try:
|
||||
@ -107,6 +110,7 @@ def parse_columns_for_blunders(text: str) -> list[Blunder]:
|
||||
|
||||
|
||||
def extract_pgn(text: str) -> str | None:
|
||||
"""Extract the PGN block from a log file."""
|
||||
# Extract the PGN block after a line that is exactly 'PGN:' or starts with it
|
||||
m = re.search(r"^PGN:\s*$", text, flags=re.MULTILINE)
|
||||
if not m:
|
||||
@ -117,6 +121,7 @@ def extract_pgn(text: str) -> str | None:
|
||||
|
||||
|
||||
def san_list_from_game(game: chess.pgn.Game) -> list[str]:
|
||||
"""Extract the list of SAN moves from a PGN game."""
|
||||
san_moves: list[str] = []
|
||||
node = game
|
||||
while node.variations:
|
||||
@ -128,6 +133,7 @@ def san_list_from_game(game: chess.pgn.Game) -> list[str]:
|
||||
def fen_and_uci_for_blunders(
|
||||
pgn_text: str, blunders: list[Blunder]
|
||||
) -> list[tuple[str, str, str, Blunder]]:
|
||||
"""Convert blunders to (FEN, UCI, best_UCI, Blunder) tuples."""
|
||||
game = chess.pgn.read_game(io.StringIO(pgn_text))
|
||||
if game is None:
|
||||
msg = "Failed to parse PGN from log"
|
||||
@ -173,6 +179,7 @@ def fen_and_uci_for_blunders(
|
||||
|
||||
|
||||
def ensure_unified_test_file(target_path: str) -> None:
|
||||
"""Create the unified test file skeleton if it doesn't exist."""
|
||||
os.makedirs(os.path.dirname(target_path), exist_ok=True)
|
||||
if os.path.exists(target_path):
|
||||
return
|
||||
@ -370,6 +377,7 @@ def _process_single_log(log_path: str) -> int:
|
||||
|
||||
|
||||
def main(argv: list[str]) -> int:
|
||||
"""Process log files and generate blunder test cases."""
|
||||
script_dir = os.path.dirname(__file__)
|
||||
past_dir = os.path.abspath(os.path.join(script_dir, "past_games"))
|
||||
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
"""Utility functions for the Lichess bot."""
|
||||
|
||||
import logging
|
||||
import os
|
||||
import time
|
||||
|
||||
@ -1,7 +1,10 @@
|
||||
"""Mitmproxy addon to simulate connection failures."""
|
||||
|
||||
from mitmproxy import http
|
||||
|
||||
|
||||
def request(flow: http.HTTPFlow) -> None:
|
||||
"""Intercept requests and simulate failures for specific hosts."""
|
||||
# Only intercept traffic to example.com
|
||||
if "example.com" in flow.request.host:
|
||||
flow.response = http.Response.make(
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
"""Generate random colorful JPEG images with configurable parameters."""
|
||||
|
||||
import argparse
|
||||
from datetime import datetime
|
||||
import logging
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
"""Randomize numbers by applying a random percentage variation."""
|
||||
|
||||
import contextlib
|
||||
import logging
|
||||
import random
|
||||
@ -8,6 +10,7 @@ logging.basicConfig(level=logging.INFO)
|
||||
|
||||
|
||||
def randomize_numbers(numbers, min_percentage=1, max_percentage=20):
|
||||
"""Apply random percentage variation to a list of numbers."""
|
||||
randomized_numbers = []
|
||||
for number in numbers:
|
||||
percentage = random.uniform(min_percentage, max_percentage) / 100
|
||||
@ -20,6 +23,7 @@ def randomize_numbers(numbers, min_percentage=1, max_percentage=20):
|
||||
|
||||
|
||||
def parse_input(input_string):
|
||||
"""Parse a string of numbers and return floats with decimal counts."""
|
||||
# Replace commas with dots and remove non-numeric characters
|
||||
# except dots, commas, and digits
|
||||
cleaned_input = re.sub(r"[^\d.,\s]", "", input_string).replace(",", ".")
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
"""Download comic images from a website using Selenium."""
|
||||
|
||||
import argparse
|
||||
import logging
|
||||
import os
|
||||
@ -27,6 +29,7 @@ driver.get(url)
|
||||
|
||||
# A function to download images by URL
|
||||
def download_image(url):
|
||||
"""Download an image from a URL and save it locally."""
|
||||
# Extract image name from URL
|
||||
image_name = os.path.basename(urlparse(url).path)
|
||||
|
||||
|
||||
@ -14,7 +14,10 @@ logging.basicConfig(level=logging.INFO)
|
||||
|
||||
|
||||
class ScreenLocker:
|
||||
"""Screen locker that requires workout logging to unlock."""
|
||||
|
||||
def __init__(self, demo_mode=True):
|
||||
"""Initialize screen locker with optional demo mode."""
|
||||
# Set up log file path
|
||||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
self.log_file = os.path.join(script_dir, "workout_log.json")
|
||||
@ -74,10 +77,12 @@ class ScreenLocker:
|
||||
self.root.grab_set_global()
|
||||
|
||||
def clear_container(self):
|
||||
"""Remove all widgets from the main container."""
|
||||
for widget in self.container.winfo_children():
|
||||
widget.destroy()
|
||||
|
||||
def ask_workout_done(self):
|
||||
"""Display the initial workout question dialog."""
|
||||
self.clear_container()
|
||||
|
||||
question = tk.Label(
|
||||
@ -117,6 +122,7 @@ class ScreenLocker:
|
||||
no_btn.pack(side="left", padx=20)
|
||||
|
||||
def lockout(self):
|
||||
"""Display lockout screen with countdown timer."""
|
||||
self.clear_container()
|
||||
|
||||
self.lockout_label = tk.Label(
|
||||
@ -141,6 +147,7 @@ class ScreenLocker:
|
||||
self.update_lockout_countdown()
|
||||
|
||||
def update_lockout_countdown(self):
|
||||
"""Update the lockout countdown timer display."""
|
||||
if self.remaining_time > 0:
|
||||
self.countdown_label.config(text=str(self.remaining_time))
|
||||
self.remaining_time -= 1
|
||||
@ -149,6 +156,7 @@ class ScreenLocker:
|
||||
self.ask_workout_done()
|
||||
|
||||
def ask_workout_type(self):
|
||||
"""Display workout type selection dialog."""
|
||||
self.clear_container()
|
||||
|
||||
question = tk.Label(
|
||||
@ -188,6 +196,7 @@ class ScreenLocker:
|
||||
strength_btn.pack(side="left", padx=20)
|
||||
|
||||
def ask_running_details(self):
|
||||
"""Display running workout input form."""
|
||||
self.clear_container()
|
||||
self.workout_data["type"] = "running"
|
||||
|
||||
@ -277,6 +286,7 @@ class ScreenLocker:
|
||||
self.update_submit_timer()
|
||||
|
||||
def verify_running_data(self):
|
||||
"""Validate running workout data and unlock if valid."""
|
||||
try:
|
||||
distance = float(self.distance_entry.get())
|
||||
time_mins = float(self.time_entry.get())
|
||||
@ -314,6 +324,7 @@ class ScreenLocker:
|
||||
self.show_error("Please enter valid numbers")
|
||||
|
||||
def ask_strength_details(self):
|
||||
"""Display strength training input form."""
|
||||
self.clear_container()
|
||||
self.workout_data["type"] = "strength"
|
||||
|
||||
@ -435,6 +446,7 @@ class ScreenLocker:
|
||||
self.update_submit_timer()
|
||||
|
||||
def verify_strength_data(self):
|
||||
"""Validate strength workout data and unlock if valid."""
|
||||
try:
|
||||
exercises = [e.strip() for e in self.exercises_entry.get().split(",")]
|
||||
sets = [int(s.strip()) for s in self.sets_entry.get().split(",")]
|
||||
@ -539,6 +551,7 @@ class ScreenLocker:
|
||||
pass
|
||||
|
||||
def show_error(self, message):
|
||||
"""Display error message with retry option."""
|
||||
self.clear_container()
|
||||
|
||||
error_label = tk.Label(
|
||||
@ -573,6 +586,7 @@ class ScreenLocker:
|
||||
retry_btn.pack(pady=30)
|
||||
|
||||
def unlock_screen(self):
|
||||
"""Save workout log and display success message."""
|
||||
# Save workout data to log
|
||||
self.save_workout_log()
|
||||
|
||||
@ -638,10 +652,12 @@ class ScreenLocker:
|
||||
logging.warning(f"Could not save workout log: {e}")
|
||||
|
||||
def close(self):
|
||||
"""Close the application and exit."""
|
||||
self.root.destroy()
|
||||
sys.exit(0)
|
||||
|
||||
def run(self):
|
||||
"""Start the Tkinter main event loop."""
|
||||
self.root.mainloop()
|
||||
|
||||
|
||||
|
||||
@ -1,3 +1,6 @@
|
||||
"""Distribute values symmetrically across N parts."""
|
||||
|
||||
|
||||
def calculate_symmetric_weights(N, middle_weight, factors=None):
|
||||
"""Calculate symmetric weights for both even and odd N.
|
||||
|
||||
|
||||
@ -125,6 +125,7 @@ def classify_cp_loss(cp_loss: int | None) -> str:
|
||||
|
||||
|
||||
def fmt_eval(cp: int | None, mate_in: int | None) -> str:
|
||||
"""Format evaluation score as human-readable string."""
|
||||
if mate_in is not None:
|
||||
sign = "+" if mate_in > 0 else ""
|
||||
return f"M{sign}{mate_in}"
|
||||
@ -201,6 +202,7 @@ def _auto_hash_mb(threads_wanted: int, engine_options) -> int:
|
||||
|
||||
|
||||
def main():
|
||||
"""Parse arguments and run chess game analysis."""
|
||||
logging.basicConfig(level=logging.INFO, format="%(message)s")
|
||||
ap = argparse.ArgumentParser(
|
||||
description="Analyze a chess game's moves with Stockfish and rate each move."
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
"""Sort images into folders using keyboard input."""
|
||||
|
||||
import logging
|
||||
import os # for: os.getcwd; os.mkdir; os.listdir;
|
||||
from os import path # for: os.path.abspath
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
"""Integration tests for the articles C server API."""
|
||||
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
@ -9,7 +11,8 @@ import urllib.request
|
||||
|
||||
|
||||
def _req(url, method="GET", data=None):
|
||||
if data is not None and not isinstance(data, (bytes, bytearray)):
|
||||
"""Send an HTTP request and return status code and body."""
|
||||
if data is not None and not isinstance(data, bytes | bytearray):
|
||||
data = json.dumps(data).encode("utf-8")
|
||||
req = urllib.request.Request(url, data=data, method=method)
|
||||
req.add_header("Content-Type", "application/json")
|
||||
@ -19,6 +22,7 @@ def _req(url, method="GET", data=None):
|
||||
|
||||
|
||||
def test_crud_roundtrip(tmp_path):
|
||||
"""Test full CRUD lifecycle for articles API."""
|
||||
# Build C server
|
||||
here = Path(__file__).resolve().parent
|
||||
subprocess.run(["make", "-s", "server_c"], check=True, cwd=str(here))
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
"""Tests to ensure website stays within size budget."""
|
||||
|
||||
import os
|
||||
|
||||
# Budget for the entire website (single file) in bytes
|
||||
@ -8,9 +10,11 @@ SITE_FILE = os.path.join(HERE, "index.html")
|
||||
|
||||
|
||||
def test_site_file_exists():
|
||||
"""Verify the main site HTML file exists."""
|
||||
assert os.path.exists(SITE_FILE), f"Missing site file: {SITE_FILE}"
|
||||
|
||||
|
||||
def test_site_size_under_budget():
|
||||
"""Verify site size is under the defined budget."""
|
||||
size = os.path.getsize(SITE_FILE)
|
||||
assert size <= BUDGET, f"Site size {size} bytes exceeds budget {BUDGET}"
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
"""Texas Hold'em poker game modifier application."""
|
||||
|
||||
import logging
|
||||
import random
|
||||
import tkinter as tk
|
||||
@ -7,7 +9,10 @@ logging.basicConfig(level=logging.INFO)
|
||||
|
||||
|
||||
class PokerModifierApp:
|
||||
"""GUI application for poker game modifiers."""
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize the poker modifier app with default settings."""
|
||||
self.modifiers = [
|
||||
# Hand Bonus Modifiers (Balatro-inspired)
|
||||
{
|
||||
@ -515,6 +520,7 @@ class PokerModifierApp:
|
||||
self.setup_gui()
|
||||
|
||||
def setup_gui(self):
|
||||
"""Create and configure the main GUI window."""
|
||||
# Create main window
|
||||
self.root = tk.Tk()
|
||||
self.root.title("🃏 Texas Hold'em Modifier")
|
||||
|
||||
@ -33,15 +33,7 @@ ignore = [
|
||||
"D213", # Multi-line docstring summary should start at second line (conflicts with D212)
|
||||
"COM812", # Trailing comma missing (conflicts with formatter)
|
||||
"ISC001", # Implicit string concatenation (conflicts with formatter)
|
||||
"ANN101", # Missing type annotation for self (deprecated)
|
||||
"ANN102", # Missing type annotation for cls (deprecated)
|
||||
# Relaxed for script-heavy repository
|
||||
"D100", # Missing docstring in public module - scripts don't need module docstrings
|
||||
"D101", # Missing docstring in public class - relaxed
|
||||
"D102", # Missing docstring in public method - relaxed
|
||||
"D103", # Missing docstring in public function - relaxed
|
||||
"D104", # Missing docstring in public package - relaxed
|
||||
"D107", # Missing docstring in __init__ - relaxed
|
||||
"D205", # Missing blank line after summary - relaxed
|
||||
"D415", # Missing terminal punctuation - relaxed for scripts
|
||||
"INP001", # Implicit namespace package - this is a scripts repo
|
||||
@ -98,11 +90,9 @@ ignore = [
|
||||
"B023", # function-uses-loop-variable - common pattern with closures
|
||||
"B904", # raise-without-from - style preference
|
||||
"DTZ005", # datetime.now without tz - acceptable for local scripts
|
||||
"UP038", # isinstance union type - py3.10+ style, not required
|
||||
"E741", # ambiguous-variable-name - sometimes intentional (e.g. l for list)
|
||||
"DTZ004", # datetime.utcfromtimestamp - acceptable
|
||||
"E722", # bare-except - will be fixed where critical
|
||||
"E741", # ambiguous-variable-name - sometimes intentional
|
||||
"PT017", # pytest-assert-in-except - acceptable pattern
|
||||
]
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user