From 9fb4cd70b598c17f73f8684c253245191e50cb33 Mon Sep 17 00:00:00 2001 From: Zeecka Date: Fri, 26 Dec 2025 22:58:00 +0100 Subject: [PATCH] Lint, typo --- .env | 2 +- .gitignore | 1 - aperisolve/analyzers/foremost.py | 2 +- aperisolve/analyzers/outguess.py | 2 +- aperisolve/analyzers/pngcheck.py | 8 ++--- aperisolve/analyzers/steghide.py | 2 +- aperisolve/analyzers/utils.py | 54 +++++++++++++++++++++++++------- aperisolve/app.py | 14 ++++----- aperisolve/cleanup.py | 12 +++---- aperisolve/config.py | 2 +- aperisolve/models.py | 31 +++++++++--------- 11 files changed, 80 insertions(+), 50 deletions(-) diff --git a/.env b/.env index bdea06b..7d7e694 100644 --- a/.env +++ b/.env @@ -7,4 +7,4 @@ DB_URI=postgresql://aperiuser:aperipass@postgres:5432/aperisolve RQ_DASHBOARD_REDIS_URL=redis://redis:6379/0 POSTGRES_DB=aperisolve POSTGRES_USER=aperiuser -POSTGRES_PASSWORD=aperipass \ No newline at end of file +POSTGRES_PASSWORD=aperipass diff --git a/.gitignore b/.gitignore index 12546d8..646de31 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,3 @@ __pycache__/ .mypy_cache/ results/ -ihdr_crcs.db \ No newline at end of file diff --git a/aperisolve/analyzers/foremost.py b/aperisolve/analyzers/foremost.py index 7e82452..5c55972 100644 --- a/aperisolve/analyzers/foremost.py +++ b/aperisolve/analyzers/foremost.py @@ -24,7 +24,7 @@ def analyze_foremost(input_img: Path, output_dir: Path) -> None: timeout=MAX_PENDING_TIME, ) # Note: foremost use stderr as standard output for results :o) - # So we can't use it as error dectection : + # So we can't use it as error detection : # stderr += data.stderr # Zip extracted files diff --git a/aperisolve/analyzers/outguess.py b/aperisolve/analyzers/outguess.py index 1d6587e..976979b 100644 --- a/aperisolve/analyzers/outguess.py +++ b/aperisolve/analyzers/outguess.py @@ -11,7 +11,7 @@ from .utils import MAX_PENDING_TIME, update_data def analyze_outguess( input_img: Path, output_dir: Path, password: Optional[str] = None ) -> None: - """Analyze an image submission using stehide.""" + """Analyze an image submission using outguess.""" image_name = input_img.name try: diff --git a/aperisolve/analyzers/pngcheck.py b/aperisolve/analyzers/pngcheck.py index fa32faf..5c9a945 100644 --- a/aperisolve/analyzers/pngcheck.py +++ b/aperisolve/analyzers/pngcheck.py @@ -7,7 +7,7 @@ from .utils import MAX_PENDING_TIME, update_data def analyze_pngcheck(input_img: Path, output_dir: Path) -> None: - """Analyze an image submission using strings.""" + """Analyze an image submission using pngcheck.""" try: data = subprocess.run( @@ -24,15 +24,15 @@ def analyze_pngcheck(input_img: Path, output_dir: Path) -> None: # ) # return - data_strings = data.stdout.split("\n") if data else [] - data_strings = [s for s in data_strings if s] + data_pngcheck = data.stdout.split("\n") if data else [] + data_pngcheck = [s for s in data_pngcheck if s] update_data( output_dir, { "pngcheck": { "status": "ok", - "output": data_strings, + "output": data_pngcheck, } }, ) diff --git a/aperisolve/analyzers/steghide.py b/aperisolve/analyzers/steghide.py index 8a12ce9..d74d077 100644 --- a/aperisolve/analyzers/steghide.py +++ b/aperisolve/analyzers/steghide.py @@ -12,7 +12,7 @@ from .utils import MAX_PENDING_TIME, update_data def analyze_steghide( input_img: Path, output_dir: Path, password: Optional[str] = None ) -> None: - """Analyze an image submission using stehide.""" + """Analyze an image submission using steghide.""" image_name = input_img.name try: diff --git a/aperisolve/analyzers/utils.py b/aperisolve/analyzers/utils.py index 13d7196..df7da95 100644 --- a/aperisolve/analyzers/utils.py +++ b/aperisolve/analyzers/utils.py @@ -15,9 +15,6 @@ _thread_lock = threading.Lock() MAX_PENDING_TIME = int(os.getenv("MAX_PENDING_TIME", "600")) # 10 minutes by default -# PATH CONFIGURATION -# Prioritize /data for Docker persistence, fallback to local directory for bare metal - def update_data( output_dir: Path, new_data: dict[Any, Any], json_filename: str = "results.json" @@ -56,7 +53,31 @@ def update_data( def get_resolutions(): - BASE_WIDTHS = ( + """ + Generate a sorted list of common display and image resolutions. + + Creates a comprehensive set of resolution tuples by combining various base widths + with standard aspect ratios used in screens, digital displays, photography, and + paper standards. Includes both portrait and landscape orientations. + + Base widths range from 16px to 10000px, covering: + - Low resolution: 16-256px (16px increments) + - Standard: 320-1024px (32px increments) + - HD/Full HD: 1280-2560px (64px increments) + - 4K: 3000-4096px (128px increments) + - 5K-8K: 5120-8192px (256px increments) + - Upper bound: 10000px + + Aspect ratios include common formats: + - Digital screens: 1:1, 4:3, 3:2, 16:10, 16:9, 21:9 + - Photography/print: 5:4, 7:5, 2:3 + - Paper standards: ISO A-series, US Letter, Legal, Tabloid + + Returns: + list[tuple[int, int]]: Sorted list of (width, height) resolution tuples + with heights constrained between 1 and 10000 pixels. + """ + base_widths = ( list(range(16, 257, 16)) # 16 → 256 + list(range(320, 1025, 32)) # 320 → 1024 + list(range(1280, 2561, 64)) # 1280 → 2560 @@ -64,7 +85,7 @@ def get_resolutions(): + list(range(5120, 8193, 256)) # 5K–8K + [10000] # upper bound ) - ASPECT_RATIOS = [ + aspect_ratios = [ # Screens / digital (1, 1), # square (4, 3), @@ -84,8 +105,8 @@ def get_resolutions(): (17, 11), # Tabloid ] resolutions = set() - for w in BASE_WIDTHS: - for ar_w, ar_h in ASPECT_RATIOS: + for w in base_widths: + for ar_w, ar_h in aspect_ratios: h = math.floor(round(w * ar_h / ar_w)) if 1 <= h <= 10000: resolutions.add((w, h)) @@ -94,14 +115,25 @@ def get_resolutions(): def get_valid_depth_color_pairs(): - VALID_COLOR_DEPTHS = { + """ + Generate valid combinations of color and bit depth values. + + Yields tuples of (depth, color) representing valid color mode and bit depth + combinations. Supports grayscale (0), RGB (2, 3, 4, 6) color modes with + appropriate bit depths (1, 2, 4, 8, 16 bits). + + Yields: + tuple: A tuple of (depth, color) where depth is an integer representing + bit depth and color is an integer representing the color mode. + """ + valid_color_depth = { 0: [1, 2, 4, 8, 16], 2: [8, 16], 3: [1, 2, 4, 8], 4: [8, 16], 6: [8, 16], } - for color, depths in VALID_COLOR_DEPTHS.items(): + for color, depths in valid_color_depth.items(): for depth in depths: yield depth, color @@ -234,8 +266,8 @@ class PNG: IndexError: If the bytearray is shorter than expected for the PNG structure. """ - PNG_SIGNATURE = b"\x89PNG\r\n\x1a\n" - if data[:8] != PNG_SIGNATURE: + png_signature = b"\x89PNG\r\n\x1a\n" + if data[:8] != png_signature: raise ValueError("Invalid PNG signature") offset = 8 # Read IHDR chunk length = struct.unpack(">I", data[offset : offset + 4])[0] diff --git a/aperisolve/app.py b/aperisolve/app.py index 5e92077..e81de53 100644 --- a/aperisolve/app.py +++ b/aperisolve/app.py @@ -1,4 +1,4 @@ -"""AperiSolve Flask application.""" +"""Aperi'Solve Flask application.""" import hashlib import json @@ -41,7 +41,7 @@ def too_large(_: Any) -> tuple[Response, int]: @app.errorhandler(404) def not_found(_: Any) -> str: """Error Handler for 404 not found.""" - return render_template("error.html", message="Ressource not found", statuscode=404) + return render_template("error.html", message="Resource not found", statuscode=404) @app.route("/") @@ -134,12 +134,12 @@ def upload_image() -> tuple[Response, int]: first_submission_date=datetime.now(timezone.utc), last_submission_date=datetime.now(timezone.utc), ) - db.session.add(new_img) - db.session.commit() + db.session.add(new_img) # pylint: disable=no-member + db.session.commit() # pylint: disable=no-member sub_img = Image.query.filter_by(hash=img_hash).first() # type: ignore sub_img.upload_count += 1 - db.session.commit() + db.session.commit() # pylint: disable=no-member # Create new Submission entry submission_path.mkdir(parents=True, exist_ok=True) @@ -152,9 +152,9 @@ def upload_image() -> tuple[Response, int]: date=time.time(), image_hash=sub_img.hash, # type: ignore ) - db.session.add(submission) + db.session.add(submission) # pylint: disable=no-member - db.session.commit() # Commit to save the new Image and Submission + db.session.commit() # pylint: disable=no-member # Start the analysis jobs queue.enqueue("aperisolve.workers.analyze_image", submission.hash, job_timeout=300) diff --git a/aperisolve/cleanup.py b/aperisolve/cleanup.py index 0e59175..402cd25 100644 --- a/aperisolve/cleanup.py +++ b/aperisolve/cleanup.py @@ -43,7 +43,7 @@ def cleanup_old_entries() -> None: and now - submission.date > MAX_PENDING_TIME # type: ignore ): # Processing took too long, delete - db.session.delete(submission) # type: ignore + db.session.delete(submission) # pylint: disable=no-member elif submission.status == "done": # type: ignore # Search for buggy results, delete result_path = ( @@ -51,7 +51,7 @@ def cleanup_old_entries() -> None: ) result_file = result_path / "results.json" if not result_file.exists(): - db.session.delete(submission) # type: ignore + db.session.delete(submission) # pylint: disable=no-member shutil.rmtree(result_path) # Delete "old" images @@ -64,15 +64,15 @@ def cleanup_old_entries() -> None: img_fold = RESULT_FOLDER / img.hash if delay.total_seconds() > MAX_STORE_TIME: for s in img.submissions: - db.session.delete(s) # type: ignore + db.session.delete(s) # pylint: disable=no-member if img_fold.exists(): shutil.rmtree(img_fold) # type: ignore - db.session.delete(img) + db.session.delete(img) # pylint: disable=no-member # Delete Images with missing submission if len(img.submissions) == 0 and delay.total_seconds() > MAX_PENDING_TIME: if img_fold.exists(): shutil.rmtree(img_fold) # type: ignore - db.session.delete(img) + db.session.delete(img) # pylint: disable=no-member - db.session.commit() + db.session.commit() # pylint: disable=no-member diff --git a/aperisolve/config.py b/aperisolve/config.py index fe000d3..117e852 100644 --- a/aperisolve/config.py +++ b/aperisolve/config.py @@ -1,4 +1,4 @@ -"""AperiSolve configuration variables.""" +"""Aperi'Solve configuration variables.""" from pathlib import Path diff --git a/aperisolve/models.py b/aperisolve/models.py index 1f2d897..d0f3d7e 100644 --- a/aperisolve/models.py +++ b/aperisolve/models.py @@ -2,7 +2,6 @@ import itertools from datetime import datetime, timezone -from decimal import Decimal from flask import Flask from flask_sqlalchemy import SQLAlchemy @@ -16,21 +15,21 @@ db: SQLAlchemy = SQLAlchemy() class Image(db.Model): # type: ignore """Model representing an image file in the database.""" - hash: Column[str] = Column( + hash: Column[String] = Column( String(64), primary_key=True, unique=True, nullable=False ) - file: Column[str] = Column(String(128), unique=True, nullable=False) - size: Column[int] = Column(Integer, nullable=False) - first_submission_date: Column[datetime] = Column( + file: Column[String] = Column(String(128), unique=True, nullable=False) + size: Column[Integer] = Column(Integer, nullable=False) + first_submission_date: Column[DateTime] = Column( DateTime, nullable=False, default=lambda: datetime.now(timezone.utc) ) - last_submission_date: Column[datetime] = Column( + last_submission_date: Column[DateTime] = Column( DateTime, nullable=False, default=lambda: datetime.now(timezone.utc), onupdate=lambda: datetime.now(timezone.utc), ) - upload_count: Column[int] = Column(Integer) + upload_count: Column[Integer] = Column(Integer) submissions = db.relationship("Submission", backref="image", lazy=True) @@ -40,14 +39,14 @@ class Submission(db.Model): # type: ignore option. """ - hash: Column[str] = Column( + hash: Column[String] = Column( String(128), primary_key=True, unique=True, nullable=False ) - filename: Column[str] = Column(String(128), nullable=False) - password: Column[str] = Column(String(128)) - deep_analysis: Column[bool] = Column(Boolean, default=False) - status: Column[str] = Column(String(20), default="pending") - date: Column[Decimal] = Column( + filename: Column[String] = Column(String(128), nullable=False) + password: Column[String] = Column(String(128)) + deep_analysis: Column[Boolean] = Column(Boolean, default=False) + status: Column[String] = Column(String(20), default="pending") + date: Column[Float] = Column( Float, nullable=False, default=lambda: datetime.now(timezone.utc) ) @@ -58,9 +57,9 @@ class Submission(db.Model): # type: ignore class IHDR(db.Model): # type: ignore """IHDR CRC lookup table""" - iid = Column(Integer, primary_key=True, autoincrement=True) - crc = Column(BigInteger, nullable=False) - packed = Column(BigInteger, nullable=False) + iid: Column[Integer] = Column(Integer, primary_key=True, autoincrement=True) + crc: Column[BigInteger] = Column(BigInteger, nullable=False) + packed: Column[BigInteger] = Column(BigInteger, nullable=False) def create_crc_db() -> None: