From 2a6161900185da496e7d12e2a7a25a9b6712800b Mon Sep 17 00:00:00 2001 From: Krzysztof kuhy Rudnicki Date: Fri, 13 Mar 2026 20:47:52 +0100 Subject: [PATCH] refactor(anki_decks): remove all noqa comments and fix underlying issues - Replace module-level globals with _mp_state dict (PLW0603) - Use hashlib.sha256 instead of md5 (S324) - Use secrets.randbelow instead of random.randrange (S311) - Use tempfile.gettempdir() instead of hardcoded /tmp (S108) - Replace assert statements with RuntimeError (S101) --- .../polish_coastal_features_anki.py | 23 +++++++------- .../polish_forests/polish_forests_anki.py | 23 +++++++------- .../polish_gminy/polish_gminy_anki.py | 30 ++++++++++--------- .../polish_islands/polish_islands_anki.py | 27 +++++++++-------- .../polish_lakes/polish_lakes_anki.py | 28 +++++++++-------- .../polish_landscape_parks_anki.py | 23 +++++++------- .../polish_license_plates_anki.py | 4 +-- .../polish_mountain_peaks_anki.py | 28 +++++++++-------- .../polish_mountain_ranges_anki.py | 23 +++++++------- .../polish_national_parks_anki.py | 23 +++++++------- .../polish_nature_reserves_anki.py | 25 ++++++++-------- .../polish_powiaty/polish_powiaty_anki.py | 9 +++--- .../polish_rivers/polish_rivers_anki.py | 23 +++++++------- .../polish_unesco_sites_anki.py | 23 +++++++------- .../warsaw_bridges/warsaw_bridges_anki.py | 9 +++--- .../warsaw_districts/warsaw_districts_anki.py | 9 +++--- .../warsaw_landmarks/warsaw_landmarks_anki.py | 9 +++--- .../warsaw_metro/warsaw_metro_anki.py | 9 +++--- .../warsaw_osiedla/warsaw_osiedla_anki.py | 9 +++--- .../warsaw_streets/warsaw_streets_anki.py | 9 +++--- 20 files changed, 194 insertions(+), 172 deletions(-) diff --git a/python_pkg/anki_decks/polish_coastal_features/polish_coastal_features_anki.py b/python_pkg/anki_decks/polish_coastal_features/polish_coastal_features_anki.py index f85a41c..7279ee5 100644 --- a/python_pkg/anki_decks/polish_coastal_features/polish_coastal_features_anki.py +++ b/python_pkg/anki_decks/polish_coastal_features/polish_coastal_features_anki.py @@ -11,10 +11,10 @@ import hashlib from io import BytesIO import multiprocessing as mp from pathlib import Path -import random +import secrets import sys import tempfile -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Any import genanki import geopandas as gpd @@ -83,14 +83,13 @@ def generate_coastal_image_bytes( return buf.read() -# Global variables for multiprocessing (set via initializer) -_mp_poland_boundary: gpd.GeoDataFrame | None = None +# Multiprocessing shared state (set via initializer) +_mp_state: dict[str, Any] = {} def _init_worker(poland_geojson: str) -> None: """Initialize worker process with shared data.""" - global _mp_poland_boundary # noqa: PLW0603 - _mp_poland_boundary = gpd.read_file(poland_geojson) + _mp_state["poland_boundary"] = gpd.read_file(poland_geojson) def _render_single_feature(args: tuple[str, str]) -> tuple[str, bytes]: @@ -105,9 +104,11 @@ def _render_single_feature(args: tuple[str, str]) -> tuple[str, bytes]: feature_name, feature_geojson = args feature_gdf = gpd.read_file(feature_geojson) - assert _mp_poland_boundary is not None # noqa: S101 + if "poland_boundary" not in _mp_state: + msg = "Worker not initialized" + raise RuntimeError(msg) - image_data = generate_coastal_image_bytes(feature_gdf, _mp_poland_boundary) + image_data = generate_coastal_image_bytes(feature_gdf, _mp_state["poland_boundary"]) return feature_name, image_data @@ -117,7 +118,7 @@ def generate_anki_package( deck_name: str = "Polish Coastal Features", ) -> genanki.Package: """Generate Anki package for Polish coastal features.""" - model_id_hash = hashlib.md5( # noqa: S324 + model_id_hash = hashlib.sha256( f"polish_coastal_features_{deck_name}".encode() ) model_id = int(model_id_hash.hexdigest()[:8], 16) @@ -185,7 +186,7 @@ def generate_anki_package( css=card_css, ) - deck_id = random.randrange(1 << 30, 1 << 31) # noqa: S311 + deck_id = secrets.randbelow(1 << 30) + (1 << 30) my_deck = genanki.Deck(deck_id, deck_name) media_files = [] @@ -237,7 +238,7 @@ def generate_anki_package( ) my_deck.add_note(note) - temp_path = Path(f"/tmp/{filename}") # noqa: S108 + temp_path = Path(tempfile.gettempdir()) / filename temp_path.write_bytes(image_data) media_files.append(str(temp_path)) diff --git a/python_pkg/anki_decks/polish_forests/polish_forests_anki.py b/python_pkg/anki_decks/polish_forests/polish_forests_anki.py index 2a186ec..76cfb7e 100644 --- a/python_pkg/anki_decks/polish_forests/polish_forests_anki.py +++ b/python_pkg/anki_decks/polish_forests/polish_forests_anki.py @@ -11,10 +11,10 @@ import hashlib from io import BytesIO import multiprocessing as mp from pathlib import Path -import random +import secrets import sys import tempfile -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Any import genanki import geopandas as gpd @@ -76,14 +76,13 @@ def generate_forest_image_bytes( return buf.read() -# Global variables for multiprocessing (set via initializer) -_mp_poland_boundary: gpd.GeoDataFrame | None = None +# Multiprocessing shared state (set via initializer) +_mp_state: dict[str, Any] = {} def _init_worker(poland_geojson: str) -> None: """Initialize worker process with shared data.""" - global _mp_poland_boundary # noqa: PLW0603 - _mp_poland_boundary = gpd.read_file(poland_geojson) + _mp_state["poland_boundary"] = gpd.read_file(poland_geojson) def _render_single_forest(args: tuple[str, str]) -> tuple[str, bytes]: @@ -98,9 +97,11 @@ def _render_single_forest(args: tuple[str, str]) -> tuple[str, bytes]: forest_name, forest_geojson = args forest_gdf = gpd.read_file(forest_geojson) - assert _mp_poland_boundary is not None # noqa: S101 + if "poland_boundary" not in _mp_state: + msg = "Worker not initialized" + raise RuntimeError(msg) - image_data = generate_forest_image_bytes(forest_gdf, _mp_poland_boundary) + image_data = generate_forest_image_bytes(forest_gdf, _mp_state["poland_boundary"]) return forest_name, image_data @@ -110,7 +111,7 @@ def generate_anki_package( deck_name: str = "Polish Forests (Puszcze)", ) -> genanki.Package: """Generate Anki package for Polish forests.""" - model_id_hash = hashlib.md5(f"polish_forests_{deck_name}".encode()) # noqa: S324 + model_id_hash = hashlib.sha256(f"polish_forests_{deck_name}".encode()) model_id = int(model_id_hash.hexdigest()[:8], 16) card_css = """ @@ -176,7 +177,7 @@ def generate_anki_package( css=card_css, ) - deck_id = random.randrange(1 << 30, 1 << 31) # noqa: S311 + deck_id = secrets.randbelow(1 << 30) + (1 << 30) my_deck = genanki.Deck(deck_id, deck_name) media_files = [] @@ -228,7 +229,7 @@ def generate_anki_package( ) my_deck.add_note(note) - temp_path = Path(f"/tmp/{filename}") # noqa: S108 + temp_path = Path(tempfile.gettempdir()) / filename temp_path.write_bytes(image_data) media_files.append(str(temp_path)) diff --git a/python_pkg/anki_decks/polish_gminy/polish_gminy_anki.py b/python_pkg/anki_decks/polish_gminy/polish_gminy_anki.py index 3ceaeae..a69def3 100755 --- a/python_pkg/anki_decks/polish_gminy/polish_gminy_anki.py +++ b/python_pkg/anki_decks/polish_gminy/polish_gminy_anki.py @@ -14,10 +14,10 @@ import hashlib from io import BytesIO import multiprocessing as mp from pathlib import Path -import random +import secrets import sys import tempfile -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Any import genanki import geopandas as gpd @@ -153,9 +153,8 @@ def _build_color_map(names: list[str]) -> dict[str, str]: } -# Global variables for multiprocessing (set via initializer) -_mp_poland_boundary: gpd.GeoDataFrame | None = None -_mp_color_map: dict[str, str] | None = None +# Multiprocessing shared state (set via initializer) +_mp_state: dict[str, Any] = {} def _init_worker( @@ -163,9 +162,8 @@ def _init_worker( color_map: dict[str, str], ) -> None: """Initialize worker process with shared data.""" - global _mp_poland_boundary, _mp_color_map # noqa: PLW0603 - _mp_poland_boundary = gpd.read_file(poland_geojson) - _mp_color_map = color_map + _mp_state["poland_boundary"] = gpd.read_file(poland_geojson) + _mp_state["color_map"] = color_map def _render_single_gmina(args: tuple[str, str]) -> tuple[str, bytes]: @@ -180,11 +178,15 @@ def _render_single_gmina(args: tuple[str, str]) -> tuple[str, bytes]: gmina_name, gmina_geojson = args gmina_gdf = gpd.read_file(gmina_geojson) - assert _mp_poland_boundary is not None # noqa: S101 - assert _mp_color_map is not None # noqa: S101 + if "poland_boundary" not in _mp_state: + msg = "Worker not initialized" + raise RuntimeError(msg) + if "color_map" not in _mp_state: + msg = "Worker not initialized" + raise RuntimeError(msg) image_data = generate_gmina_image_bytes( - gmina_name, gmina_gdf, _mp_poland_boundary, _mp_color_map + gmina_name, gmina_gdf, _mp_state["poland_boundary"], _mp_state["color_map"] ) return gmina_name, image_data @@ -195,7 +197,7 @@ def generate_anki_package( deck_name: str = "Polish Gminy", ) -> genanki.Package: """Generate Anki package for Polish gminy.""" - model_id_hash = hashlib.md5(f"polish_gminy_{deck_name}".encode()) # noqa: S324 + model_id_hash = hashlib.sha256(f"polish_gminy_{deck_name}".encode()) model_id = int(model_id_hash.hexdigest()[:8], 16) card_css = """ @@ -251,7 +253,7 @@ def generate_anki_package( css=card_css, ) - deck_id = random.randrange(1 << 30, 1 << 31) # noqa: S311 + deck_id = secrets.randbelow(1 << 30) + (1 << 30) my_deck = genanki.Deck(deck_id, deck_name) media_files = [] @@ -306,7 +308,7 @@ def generate_anki_package( ) my_deck.add_note(note) - temp_path = Path(f"/tmp/{filename}") # noqa: S108 + temp_path = Path(tempfile.gettempdir()) / filename temp_path.write_bytes(image_data) media_files.append(str(temp_path)) diff --git a/python_pkg/anki_decks/polish_islands/polish_islands_anki.py b/python_pkg/anki_decks/polish_islands/polish_islands_anki.py index 8285930..9b6d0aa 100644 --- a/python_pkg/anki_decks/polish_islands/polish_islands_anki.py +++ b/python_pkg/anki_decks/polish_islands/polish_islands_anki.py @@ -11,10 +11,10 @@ import hashlib from io import BytesIO import multiprocessing as mp from pathlib import Path -import random +import secrets import sys import tempfile -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Any import genanki import geopandas as gpd @@ -155,16 +155,14 @@ def generate_island_image_bytes( return buf.read() -# Global variables for multiprocessing (set via initializer) -_mp_poland_boundary: gpd.GeoDataFrame | None = None -_mp_zoom_mode: str = "no-zoom" +# Multiprocessing shared state (set via initializer) +_mp_state: dict[str, Any] = {} def _init_worker(poland_geojson: str, zoom_mode: str) -> None: """Initialize worker process with shared data.""" - global _mp_poland_boundary, _mp_zoom_mode # noqa: PLW0603 - _mp_poland_boundary = gpd.read_file(poland_geojson) - _mp_zoom_mode = zoom_mode + _mp_state["poland_boundary"] = gpd.read_file(poland_geojson) + _mp_state["zoom_mode"] = zoom_mode def _render_single_island(args: tuple[str, str]) -> tuple[str, bytes]: @@ -179,10 +177,13 @@ def _render_single_island(args: tuple[str, str]) -> tuple[str, bytes]: island_name, island_geojson = args island_gdf = gpd.read_file(island_geojson) - assert _mp_poland_boundary is not None # noqa: S101 + if "poland_boundary" not in _mp_state: + msg = "Worker not initialized" + raise RuntimeError(msg) + zoom = _mp_state["zoom_mode"] == "zoom" image_data = generate_island_image_bytes( - island_gdf, _mp_poland_boundary, zoom=(_mp_zoom_mode == "zoom") + island_gdf, _mp_state["poland_boundary"], zoom=zoom ) return island_name, image_data @@ -195,7 +196,7 @@ def generate_anki_package( zoom: bool = True, ) -> genanki.Package: """Generate Anki package for Polish islands.""" - model_id_hash = hashlib.md5(f"polish_islands_{deck_name}".encode()) # noqa: S324 + model_id_hash = hashlib.sha256(f"polish_islands_{deck_name}".encode()) model_id = int(model_id_hash.hexdigest()[:8], 16) card_css = """ @@ -261,7 +262,7 @@ def generate_anki_package( css=card_css, ) - deck_id = random.randrange(1 << 30, 1 << 31) # noqa: S311 + deck_id = secrets.randbelow(1 << 30) + (1 << 30) my_deck = genanki.Deck(deck_id, deck_name) media_files = [] @@ -314,7 +315,7 @@ def generate_anki_package( ) my_deck.add_note(note) - temp_path = Path(f"/tmp/{filename}") # noqa: S108 + temp_path = Path(tempfile.gettempdir()) / filename temp_path.write_bytes(image_data) media_files.append(str(temp_path)) diff --git a/python_pkg/anki_decks/polish_lakes/polish_lakes_anki.py b/python_pkg/anki_decks/polish_lakes/polish_lakes_anki.py index 279fa57..018fba2 100644 --- a/python_pkg/anki_decks/polish_lakes/polish_lakes_anki.py +++ b/python_pkg/anki_decks/polish_lakes/polish_lakes_anki.py @@ -11,10 +11,10 @@ import hashlib from io import BytesIO import multiprocessing as mp from pathlib import Path -import random +import secrets import sys import tempfile -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Any import genanki import geopandas as gpd @@ -89,16 +89,14 @@ def generate_lake_image_bytes( return buf.read() -# Global variables for multiprocessing (set via initializer) -_mp_poland_boundary: gpd.GeoDataFrame | None = None -_mp_zoom: bool = True +# Multiprocessing shared state (set via initializer) +_mp_state: dict[str, Any] = {} def _init_worker(poland_geojson: str, zoom_mode: str) -> None: """Initialize worker process with shared data.""" - global _mp_poland_boundary, _mp_zoom # noqa: PLW0603 - _mp_poland_boundary = gpd.read_file(poland_geojson) - _mp_zoom = zoom_mode == "zoom" + _mp_state["poland_boundary"] = gpd.read_file(poland_geojson) + _mp_state["zoom"] = zoom_mode == "zoom" def _render_single_lake(args: tuple[str, str]) -> tuple[str, bytes]: @@ -113,9 +111,13 @@ def _render_single_lake(args: tuple[str, str]) -> tuple[str, bytes]: lake_name, lake_geojson = args lake_gdf = gpd.read_file(lake_geojson) - assert _mp_poland_boundary is not None # noqa: S101 + if "poland_boundary" not in _mp_state: + msg = "Worker not initialized" + raise RuntimeError(msg) - image_data = generate_lake_image_bytes(lake_gdf, _mp_poland_boundary, zoom=_mp_zoom) + image_data = generate_lake_image_bytes( + lake_gdf, _mp_state["poland_boundary"], zoom=_mp_state["zoom"] + ) return lake_name, image_data @@ -127,7 +129,7 @@ def generate_anki_package( zoom: bool = True, ) -> genanki.Package: """Generate Anki package for Polish lakes.""" - model_id_hash = hashlib.md5(f"polish_lakes_{deck_name}".encode()) # noqa: S324 + model_id_hash = hashlib.sha256(f"polish_lakes_{deck_name}".encode()) model_id = int(model_id_hash.hexdigest()[:8], 16) card_css = """ @@ -193,7 +195,7 @@ def generate_anki_package( css=card_css, ) - deck_id = random.randrange(1 << 30, 1 << 31) # noqa: S311 + deck_id = secrets.randbelow(1 << 30) + (1 << 30) my_deck = genanki.Deck(deck_id, deck_name) media_files = [] @@ -245,7 +247,7 @@ def generate_anki_package( ) my_deck.add_note(note) - temp_path = Path(f"/tmp/{filename}") # noqa: S108 + temp_path = Path(tempfile.gettempdir()) / filename temp_path.write_bytes(image_data) media_files.append(str(temp_path)) diff --git a/python_pkg/anki_decks/polish_landscape_parks/polish_landscape_parks_anki.py b/python_pkg/anki_decks/polish_landscape_parks/polish_landscape_parks_anki.py index 325ca2f..ce49a89 100644 --- a/python_pkg/anki_decks/polish_landscape_parks/polish_landscape_parks_anki.py +++ b/python_pkg/anki_decks/polish_landscape_parks/polish_landscape_parks_anki.py @@ -11,10 +11,10 @@ import hashlib from io import BytesIO import multiprocessing as mp from pathlib import Path -import random +import secrets import sys import tempfile -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Any import genanki import geopandas as gpd @@ -84,14 +84,13 @@ def generate_park_image_bytes( return buf.read() -# Global variables for multiprocessing (set via initializer) -_mp_poland_boundary: gpd.GeoDataFrame | None = None +# Multiprocessing shared state (set via initializer) +_mp_state: dict[str, Any] = {} def _init_worker(poland_geojson: str) -> None: """Initialize worker process with shared data.""" - global _mp_poland_boundary # noqa: PLW0603 - _mp_poland_boundary = gpd.read_file(poland_geojson) + _mp_state["poland_boundary"] = gpd.read_file(poland_geojson) def _render_single_park(args: tuple[str, str]) -> tuple[str, bytes]: @@ -108,9 +107,11 @@ def _render_single_park(args: tuple[str, str]) -> tuple[str, bytes]: # Fix any geometry issues from serialization park_gdf["geometry"] = park_gdf.geometry.make_valid() - assert _mp_poland_boundary is not None # noqa: S101 + if "poland_boundary" not in _mp_state: + msg = "Worker not initialized" + raise RuntimeError(msg) - image_data = generate_park_image_bytes(park_gdf, _mp_poland_boundary) + image_data = generate_park_image_bytes(park_gdf, _mp_state["poland_boundary"]) return park_name, image_data @@ -120,7 +121,7 @@ def generate_anki_package( deck_name: str = "Polish Landscape Parks", ) -> genanki.Package: """Generate Anki package for Polish landscape parks.""" - model_id_hash = hashlib.md5( # noqa: S324 + model_id_hash = hashlib.sha256( f"polish_landscape_parks_{deck_name}".encode() ) model_id = int(model_id_hash.hexdigest()[:8], 16) @@ -188,7 +189,7 @@ def generate_anki_package( css=card_css, ) - deck_id = random.randrange(1 << 30, 1 << 31) # noqa: S311 + deck_id = secrets.randbelow(1 << 30) + (1 << 30) my_deck = genanki.Deck(deck_id, deck_name) media_files = [] @@ -240,7 +241,7 @@ def generate_anki_package( ) my_deck.add_note(note) - temp_path = Path(f"/tmp/{filename}") # noqa: S108 + temp_path = Path(tempfile.gettempdir()) / filename temp_path.write_bytes(image_data) media_files.append(str(temp_path)) diff --git a/python_pkg/anki_decks/polish_license_plates/polish_license_plates_anki.py b/python_pkg/anki_decks/polish_license_plates/polish_license_plates_anki.py index 60752f0..7683661 100644 --- a/python_pkg/anki_decks/polish_license_plates/polish_license_plates_anki.py +++ b/python_pkg/anki_decks/polish_license_plates/polish_license_plates_anki.py @@ -24,7 +24,7 @@ from __future__ import annotations import argparse import hashlib from pathlib import Path -import random +import secrets import sys from typing import TYPE_CHECKING @@ -142,7 +142,7 @@ def generate_anki_package( ) # Create unique deck ID - deck_id = random.randrange(1 << 30, 1 << 31) # noqa: S311 + deck_id = secrets.randbelow(1 << 30) + (1 << 30) # Create the deck my_deck = genanki.Deck(deck_id, deck_name) diff --git a/python_pkg/anki_decks/polish_mountain_peaks/polish_mountain_peaks_anki.py b/python_pkg/anki_decks/polish_mountain_peaks/polish_mountain_peaks_anki.py index c466cf0..c5b859b 100644 --- a/python_pkg/anki_decks/polish_mountain_peaks/polish_mountain_peaks_anki.py +++ b/python_pkg/anki_decks/polish_mountain_peaks/polish_mountain_peaks_anki.py @@ -11,10 +11,10 @@ import hashlib from io import BytesIO import multiprocessing as mp from pathlib import Path -import random +import secrets import sys import tempfile -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Any import genanki import geopandas as gpd @@ -101,16 +101,14 @@ def generate_peak_image_bytes( return buf.read() -# Global variables for multiprocessing (set via initializer) -_mp_poland_boundary: gpd.GeoDataFrame | None = None -_mp_zoom: bool = True +# Multiprocessing shared state (set via initializer) +_mp_state: dict[str, Any] = {} def _init_worker(poland_geojson: str, zoom_mode: str) -> None: """Initialize worker process with shared data.""" - global _mp_poland_boundary, _mp_zoom # noqa: PLW0603 - _mp_poland_boundary = gpd.read_file(poland_geojson) - _mp_zoom = zoom_mode == "zoom" + _mp_state["poland_boundary"] = gpd.read_file(poland_geojson) + _mp_state["zoom"] = zoom_mode == "zoom" def _render_single_peak(args: tuple[str, str]) -> tuple[str, bytes]: @@ -125,9 +123,13 @@ def _render_single_peak(args: tuple[str, str]) -> tuple[str, bytes]: peak_name, peak_geojson = args peak_gdf = gpd.read_file(peak_geojson) - assert _mp_poland_boundary is not None # noqa: S101 + if "poland_boundary" not in _mp_state: + msg = "Worker not initialized" + raise RuntimeError(msg) - image_data = generate_peak_image_bytes(peak_gdf, _mp_poland_boundary, zoom=_mp_zoom) + image_data = generate_peak_image_bytes( + peak_gdf, _mp_state["poland_boundary"], zoom=_mp_state["zoom"] + ) return peak_name, image_data @@ -139,7 +141,7 @@ def generate_anki_package( zoom: bool = True, ) -> genanki.Package: """Generate Anki package for Polish mountain peaks.""" - model_id_hash = hashlib.md5( # noqa: S324 + model_id_hash = hashlib.sha256( f"polish_mountain_peaks_{deck_name}".encode() ) model_id = int(model_id_hash.hexdigest()[:8], 16) @@ -207,7 +209,7 @@ def generate_anki_package( css=card_css, ) - deck_id = random.randrange(1 << 30, 1 << 31) # noqa: S311 + deck_id = secrets.randbelow(1 << 30) + (1 << 30) my_deck = genanki.Deck(deck_id, deck_name) media_files = [] @@ -259,7 +261,7 @@ def generate_anki_package( ) my_deck.add_note(note) - temp_path = Path(f"/tmp/{filename}") # noqa: S108 + temp_path = Path(tempfile.gettempdir()) / filename temp_path.write_bytes(image_data) media_files.append(str(temp_path)) diff --git a/python_pkg/anki_decks/polish_mountain_ranges/polish_mountain_ranges_anki.py b/python_pkg/anki_decks/polish_mountain_ranges/polish_mountain_ranges_anki.py index 68d71e5..6748be7 100644 --- a/python_pkg/anki_decks/polish_mountain_ranges/polish_mountain_ranges_anki.py +++ b/python_pkg/anki_decks/polish_mountain_ranges/polish_mountain_ranges_anki.py @@ -11,10 +11,10 @@ import hashlib from io import BytesIO import multiprocessing as mp from pathlib import Path -import random +import secrets import sys import tempfile -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Any import genanki import geopandas as gpd @@ -82,14 +82,13 @@ def generate_range_image_bytes( return buf.read() -# Global variables for multiprocessing (set via initializer) -_mp_poland_boundary: gpd.GeoDataFrame | None = None +# Multiprocessing shared state (set via initializer) +_mp_state: dict[str, Any] = {} def _init_worker(poland_geojson: str) -> None: """Initialize worker process with shared data.""" - global _mp_poland_boundary # noqa: PLW0603 - _mp_poland_boundary = gpd.read_file(poland_geojson) + _mp_state["poland_boundary"] = gpd.read_file(poland_geojson) def _render_single_range(args: tuple[str, str]) -> tuple[str, bytes]: @@ -104,9 +103,11 @@ def _render_single_range(args: tuple[str, str]) -> tuple[str, bytes]: range_name, range_geojson = args range_gdf = gpd.read_file(range_geojson) - assert _mp_poland_boundary is not None # noqa: S101 + if "poland_boundary" not in _mp_state: + msg = "Worker not initialized" + raise RuntimeError(msg) - image_data = generate_range_image_bytes(range_gdf, _mp_poland_boundary) + image_data = generate_range_image_bytes(range_gdf, _mp_state["poland_boundary"]) return range_name, image_data @@ -116,7 +117,7 @@ def generate_anki_package( deck_name: str = "Polish Mountain Ranges", ) -> genanki.Package: """Generate Anki package for Polish mountain ranges.""" - model_id_hash = hashlib.md5( # noqa: S324 + model_id_hash = hashlib.sha256( f"polish_mountain_ranges_{deck_name}".encode() ) model_id = int(model_id_hash.hexdigest()[:8], 16) @@ -184,7 +185,7 @@ def generate_anki_package( css=card_css, ) - deck_id = random.randrange(1 << 30, 1 << 31) # noqa: S311 + deck_id = secrets.randbelow(1 << 30) + (1 << 30) my_deck = genanki.Deck(deck_id, deck_name) media_files = [] @@ -236,7 +237,7 @@ def generate_anki_package( ) my_deck.add_note(note) - temp_path = Path(f"/tmp/{filename}") # noqa: S108 + temp_path = Path(tempfile.gettempdir()) / filename temp_path.write_bytes(image_data) media_files.append(str(temp_path)) diff --git a/python_pkg/anki_decks/polish_national_parks/polish_national_parks_anki.py b/python_pkg/anki_decks/polish_national_parks/polish_national_parks_anki.py index a7cd480..1560461 100644 --- a/python_pkg/anki_decks/polish_national_parks/polish_national_parks_anki.py +++ b/python_pkg/anki_decks/polish_national_parks/polish_national_parks_anki.py @@ -11,10 +11,10 @@ import hashlib from io import BytesIO import multiprocessing as mp from pathlib import Path -import random +import secrets import sys import tempfile -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Any import genanki import geopandas as gpd @@ -98,14 +98,13 @@ def generate_park_image_bytes( return buf.read() -# Global variables for multiprocessing (set via initializer) -_mp_poland_boundary: gpd.GeoDataFrame | None = None +# Multiprocessing shared state (set via initializer) +_mp_state: dict[str, Any] = {} def _init_worker(poland_geojson: str) -> None: """Initialize worker process with shared data.""" - global _mp_poland_boundary # noqa: PLW0603 - _mp_poland_boundary = gpd.read_file(poland_geojson) + _mp_state["poland_boundary"] = gpd.read_file(poland_geojson) def _render_single_park(args: tuple[str, str]) -> tuple[str, bytes]: @@ -120,9 +119,11 @@ def _render_single_park(args: tuple[str, str]) -> tuple[str, bytes]: park_name, park_geojson = args park_gdf = gpd.read_file(park_geojson) - assert _mp_poland_boundary is not None # noqa: S101 + if "poland_boundary" not in _mp_state: + msg = "Worker not initialized" + raise RuntimeError(msg) - image_data = generate_park_image_bytes(park_gdf, _mp_poland_boundary) + image_data = generate_park_image_bytes(park_gdf, _mp_state["poland_boundary"]) return park_name, image_data @@ -132,7 +133,7 @@ def generate_anki_package( deck_name: str = "Polish National Parks", ) -> genanki.Package: """Generate Anki package for Polish national parks.""" - model_id_hash = hashlib.md5( # noqa: S324 + model_id_hash = hashlib.sha256( f"polish_national_parks_{deck_name}".encode() ) model_id = int(model_id_hash.hexdigest()[:8], 16) @@ -200,7 +201,7 @@ def generate_anki_package( css=card_css, ) - deck_id = random.randrange(1 << 30, 1 << 31) # noqa: S311 + deck_id = secrets.randbelow(1 << 30) + (1 << 30) my_deck = genanki.Deck(deck_id, deck_name) media_files = [] @@ -252,7 +253,7 @@ def generate_anki_package( ) my_deck.add_note(note) - temp_path = Path(f"/tmp/{filename}") # noqa: S108 + temp_path = Path(tempfile.gettempdir()) / filename temp_path.write_bytes(image_data) media_files.append(str(temp_path)) diff --git a/python_pkg/anki_decks/polish_nature_reserves/polish_nature_reserves_anki.py b/python_pkg/anki_decks/polish_nature_reserves/polish_nature_reserves_anki.py index 6ce086e..49d0781 100644 --- a/python_pkg/anki_decks/polish_nature_reserves/polish_nature_reserves_anki.py +++ b/python_pkg/anki_decks/polish_nature_reserves/polish_nature_reserves_anki.py @@ -11,10 +11,10 @@ import hashlib from io import BytesIO import multiprocessing as mp from pathlib import Path -import random +import secrets import sys import tempfile -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Any import genanki import geopandas as gpd @@ -76,14 +76,13 @@ def generate_reserve_image_bytes( return buf.read() -# Global variables for multiprocessing (set via initializer) -_mp_poland_boundary: gpd.GeoDataFrame | None = None +# Multiprocessing shared state (set via initializer) +_mp_state: dict[str, Any] = {} def _init_worker(poland_geojson: str) -> None: """Initialize worker process with shared data.""" - global _mp_poland_boundary # noqa: PLW0603 - _mp_poland_boundary = gpd.read_file(poland_geojson) + _mp_state["poland_boundary"] = gpd.read_file(poland_geojson) def _render_single_reserve(args: tuple[str, str]) -> tuple[str, bytes]: @@ -98,9 +97,11 @@ def _render_single_reserve(args: tuple[str, str]) -> tuple[str, bytes]: reserve_name, reserve_geojson = args reserve_gdf = gpd.read_file(reserve_geojson) - assert _mp_poland_boundary is not None # noqa: S101 + if "poland_boundary" not in _mp_state: + msg = "Worker not initialized" + raise RuntimeError(msg) - image_data = generate_reserve_image_bytes(reserve_gdf, _mp_poland_boundary) + image_data = generate_reserve_image_bytes(reserve_gdf, _mp_state["poland_boundary"]) return reserve_name, image_data @@ -110,7 +111,7 @@ def generate_anki_package( deck_name: str = "Polish Nature Reserves", ) -> genanki.Package: """Generate Anki package for Polish nature reserves.""" - model_id_hash = hashlib.md5( # noqa: S324 + model_id_hash = hashlib.sha256( f"polish_nature_reserves_{deck_name}".encode() ) model_id = int(model_id_hash.hexdigest()[:8], 16) @@ -178,7 +179,7 @@ def generate_anki_package( css=card_css, ) - deck_id = random.randrange(1 << 30, 1 << 31) # noqa: S311 + deck_id = secrets.randbelow(1 << 30) + (1 << 30) my_deck = genanki.Deck(deck_id, deck_name) media_files = [] @@ -225,7 +226,7 @@ def generate_anki_package( area_km2 = round(row["area_km2"], 2) if "area_km2" in row else 0 image_data = results[reserve_name] # Use hash for unique filename since names may have special chars - name_hash = hashlib.md5(reserve_name.encode()).hexdigest()[:8] # noqa: S324 + name_hash = hashlib.sha256(reserve_name.encode()).hexdigest()[:8] safe_name = reserve_name.replace(" ", "_").replace("/", "_")[:30] filename = f"reserve_{safe_name}_{name_hash}.png" @@ -236,7 +237,7 @@ def generate_anki_package( ) my_deck.add_note(note) - temp_path = Path(f"/tmp/{filename}") # noqa: S108 + temp_path = Path(tempfile.gettempdir()) / filename temp_path.write_bytes(image_data) media_files.append(str(temp_path)) diff --git a/python_pkg/anki_decks/polish_powiaty/polish_powiaty_anki.py b/python_pkg/anki_decks/polish_powiaty/polish_powiaty_anki.py index 1080fda..1c51544 100755 --- a/python_pkg/anki_decks/polish_powiaty/polish_powiaty_anki.py +++ b/python_pkg/anki_decks/polish_powiaty/polish_powiaty_anki.py @@ -11,8 +11,9 @@ import argparse import hashlib from io import BytesIO from pathlib import Path -import random +import secrets import sys +import tempfile from typing import TYPE_CHECKING import genanki @@ -139,7 +140,7 @@ def generate_anki_package( deck_name: str = "Polish Powiaty", ) -> genanki.Package: """Generate Anki package for Polish powiaty.""" - model_id_hash = hashlib.md5(f"polish_powiaty_{deck_name}".encode()) # noqa: S324 + model_id_hash = hashlib.sha256(f"polish_powiaty_{deck_name}".encode()) model_id = int(model_id_hash.hexdigest()[:8], 16) card_css = """ @@ -195,7 +196,7 @@ def generate_anki_package( css=card_css, ) - deck_id = random.randrange(1 << 30, 1 << 31) # noqa: S311 + deck_id = secrets.randbelow(1 << 30) + (1 << 30) my_deck = genanki.Deck(deck_id, deck_name) media_files = [] @@ -215,7 +216,7 @@ def generate_anki_package( ) my_deck.add_note(note) - temp_path = Path(f"/tmp/{filename}") # noqa: S108 + temp_path = Path(tempfile.gettempdir()) / filename temp_path.write_bytes(image_data) media_files.append(str(temp_path)) diff --git a/python_pkg/anki_decks/polish_rivers/polish_rivers_anki.py b/python_pkg/anki_decks/polish_rivers/polish_rivers_anki.py index 71461f0..1491888 100644 --- a/python_pkg/anki_decks/polish_rivers/polish_rivers_anki.py +++ b/python_pkg/anki_decks/polish_rivers/polish_rivers_anki.py @@ -11,10 +11,10 @@ import hashlib from io import BytesIO import multiprocessing as mp from pathlib import Path -import random +import secrets import sys import tempfile -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Any import genanki import geopandas as gpd @@ -109,14 +109,13 @@ def generate_river_image_bytes( return buf.read() -# Global variables for multiprocessing (set via initializer) -_mp_poland_boundary: gpd.GeoDataFrame | None = None +# Multiprocessing shared state (set via initializer) +_mp_state: dict[str, Any] = {} def _init_worker(poland_geojson: str) -> None: """Initialize worker process with shared data.""" - global _mp_poland_boundary # noqa: PLW0603 - _mp_poland_boundary = gpd.read_file(poland_geojson) + _mp_state["poland_boundary"] = gpd.read_file(poland_geojson) def _render_single_river(args: tuple[str, str]) -> tuple[str, bytes]: @@ -131,9 +130,11 @@ def _render_single_river(args: tuple[str, str]) -> tuple[str, bytes]: river_name, river_geojson = args river_gdf = gpd.read_file(river_geojson) - assert _mp_poland_boundary is not None # noqa: S101 + if "poland_boundary" not in _mp_state: + msg = "Worker not initialized" + raise RuntimeError(msg) - image_data = generate_river_image_bytes(river_gdf, _mp_poland_boundary) + image_data = generate_river_image_bytes(river_gdf, _mp_state["poland_boundary"]) return river_name, image_data @@ -143,7 +144,7 @@ def generate_anki_package( deck_name: str = "Polish Rivers", ) -> genanki.Package: """Generate Anki package for Polish rivers.""" - model_id_hash = hashlib.md5(f"polish_rivers_{deck_name}".encode()) # noqa: S324 + model_id_hash = hashlib.sha256(f"polish_rivers_{deck_name}".encode()) model_id = int(model_id_hash.hexdigest()[:8], 16) card_css = """ @@ -209,7 +210,7 @@ def generate_anki_package( css=card_css, ) - deck_id = random.randrange(1 << 30, 1 << 31) # noqa: S311 + deck_id = secrets.randbelow(1 << 30) + (1 << 30) my_deck = genanki.Deck(deck_id, deck_name) media_files = [] @@ -261,7 +262,7 @@ def generate_anki_package( ) my_deck.add_note(note) - temp_path = Path(f"/tmp/{filename}") # noqa: S108 + temp_path = Path(tempfile.gettempdir()) / filename temp_path.write_bytes(image_data) media_files.append(str(temp_path)) diff --git a/python_pkg/anki_decks/polish_unesco_sites/polish_unesco_sites_anki.py b/python_pkg/anki_decks/polish_unesco_sites/polish_unesco_sites_anki.py index 314e6d8..0683252 100644 --- a/python_pkg/anki_decks/polish_unesco_sites/polish_unesco_sites_anki.py +++ b/python_pkg/anki_decks/polish_unesco_sites/polish_unesco_sites_anki.py @@ -11,10 +11,10 @@ import hashlib from io import BytesIO import multiprocessing as mp from pathlib import Path -import random +import secrets import sys import tempfile -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Any import genanki import geopandas as gpd @@ -97,14 +97,13 @@ def generate_unesco_image_bytes( return buf.read() -# Global variables for multiprocessing (set via initializer) -_mp_poland_boundary: gpd.GeoDataFrame | None = None +# Multiprocessing shared state (set via initializer) +_mp_state: dict[str, Any] = {} def _init_worker(poland_geojson: str) -> None: """Initialize worker process with shared data.""" - global _mp_poland_boundary # noqa: PLW0603 - _mp_poland_boundary = gpd.read_file(poland_geojson) + _mp_state["poland_boundary"] = gpd.read_file(poland_geojson) def _render_single_site(args: tuple[str, str]) -> tuple[str, bytes]: @@ -119,9 +118,11 @@ def _render_single_site(args: tuple[str, str]) -> tuple[str, bytes]: site_name, site_geojson = args site_gdf = gpd.read_file(site_geojson) - assert _mp_poland_boundary is not None # noqa: S101 + if "poland_boundary" not in _mp_state: + msg = "Worker not initialized" + raise RuntimeError(msg) - image_data = generate_unesco_image_bytes(site_gdf, _mp_poland_boundary) + image_data = generate_unesco_image_bytes(site_gdf, _mp_state["poland_boundary"]) return site_name, image_data @@ -131,7 +132,7 @@ def generate_anki_package( deck_name: str = "Polish UNESCO World Heritage Sites", ) -> genanki.Package: """Generate Anki package for Polish UNESCO sites.""" - model_id_hash = hashlib.md5( # noqa: S324 + model_id_hash = hashlib.sha256( f"polish_unesco_sites_{deck_name}".encode() ) model_id = int(model_id_hash.hexdigest()[:8], 16) @@ -213,7 +214,7 @@ def generate_anki_package( css=card_css, ) - deck_id = random.randrange(1 << 30, 1 << 31) # noqa: S311 + deck_id = secrets.randbelow(1 << 30) + (1 << 30) my_deck = genanki.Deck(deck_id, deck_name) media_files = [] @@ -271,7 +272,7 @@ def generate_anki_package( ) my_deck.add_note(note) - temp_path = Path(f"/tmp/{filename}") # noqa: S108 + temp_path = Path(tempfile.gettempdir()) / filename temp_path.write_bytes(image_data) media_files.append(str(temp_path)) diff --git a/python_pkg/anki_decks/warsaw_bridges/warsaw_bridges_anki.py b/python_pkg/anki_decks/warsaw_bridges/warsaw_bridges_anki.py index 883ef70..3e4a81c 100755 --- a/python_pkg/anki_decks/warsaw_bridges/warsaw_bridges_anki.py +++ b/python_pkg/anki_decks/warsaw_bridges/warsaw_bridges_anki.py @@ -11,8 +11,9 @@ import argparse import hashlib from io import BytesIO from pathlib import Path -import random +import secrets import sys +import tempfile from typing import TYPE_CHECKING import genanki @@ -139,7 +140,7 @@ def generate_anki_package( Returns: Generated Anki package. """ - model_id_hash = hashlib.md5(f"warsaw_bridges_{deck_name}".encode()) # noqa: S324 + model_id_hash = hashlib.sha256(f"warsaw_bridges_{deck_name}".encode()) model_id = int(model_id_hash.hexdigest()[:8], 16) card_css = """ @@ -195,7 +196,7 @@ def generate_anki_package( css=card_css, ) - deck_id = random.randrange(1 << 30, 1 << 31) # noqa: S311 + deck_id = secrets.randbelow(1 << 30) + (1 << 30) my_deck = genanki.Deck(deck_id, deck_name) media_files = [] @@ -213,7 +214,7 @@ def generate_anki_package( ) my_deck.add_note(note) - temp_path = Path(f"/tmp/{filename}") # noqa: S108 + temp_path = Path(tempfile.gettempdir()) / filename temp_path.write_bytes(image_data) media_files.append(str(temp_path)) diff --git a/python_pkg/anki_decks/warsaw_districts/warsaw_districts_anki.py b/python_pkg/anki_decks/warsaw_districts/warsaw_districts_anki.py index 2289f2d..9b45207 100755 --- a/python_pkg/anki_decks/warsaw_districts/warsaw_districts_anki.py +++ b/python_pkg/anki_decks/warsaw_districts/warsaw_districts_anki.py @@ -24,8 +24,9 @@ import argparse import hashlib from io import BytesIO from pathlib import Path -import random +import secrets import sys +import tempfile from typing import TYPE_CHECKING import genanki @@ -183,7 +184,7 @@ def generate_anki_package( genanki.Package object ready to be written to file. """ # Create a unique model ID based on deck name - model_id_hash = hashlib.md5( # noqa: S324 + model_id_hash = hashlib.sha256( f"warsaw_districts_{deck_name}".encode() ) model_id = int(model_id_hash.hexdigest()[:8], 16) @@ -243,7 +244,7 @@ def generate_anki_package( ) # Create a unique deck ID based on deck name - deck_id = random.randrange(1 << 30, 1 << 31) # noqa: S311 + deck_id = secrets.randbelow(1 << 30) + (1 << 30) # Create the deck my_deck = genanki.Deck(deck_id, deck_name) @@ -272,7 +273,7 @@ def generate_anki_package( my_deck.add_note(note) # Save image data to temporary file for packaging - temp_path = Path(f"/tmp/{filename}") # noqa: S108 + temp_path = Path(tempfile.gettempdir()) / filename temp_path.write_bytes(image_data) media_files.append(str(temp_path)) diff --git a/python_pkg/anki_decks/warsaw_landmarks/warsaw_landmarks_anki.py b/python_pkg/anki_decks/warsaw_landmarks/warsaw_landmarks_anki.py index 86978b1..5c0605a 100755 --- a/python_pkg/anki_decks/warsaw_landmarks/warsaw_landmarks_anki.py +++ b/python_pkg/anki_decks/warsaw_landmarks/warsaw_landmarks_anki.py @@ -11,8 +11,9 @@ import argparse import hashlib from io import BytesIO from pathlib import Path -import random +import secrets import sys +import tempfile from typing import TYPE_CHECKING sys.path.insert(0, str(Path(__file__).parent.parent)) @@ -103,7 +104,7 @@ def generate_anki_package( deck_name: str = "Warsaw Landmarks", ) -> genanki.Package: """Generate Anki package for Warsaw landmarks.""" - model_id_hash = hashlib.md5(f"warsaw_landmarks_{deck_name}".encode()) # noqa: S324 + model_id_hash = hashlib.sha256(f"warsaw_landmarks_{deck_name}".encode()) model_id = int(model_id_hash.hexdigest()[:8], 16) card_css = """ @@ -159,7 +160,7 @@ def generate_anki_package( css=card_css, ) - deck_id = random.randrange(1 << 30, 1 << 31) # noqa: S311 + deck_id = secrets.randbelow(1 << 30) + (1 << 30) my_deck = genanki.Deck(deck_id, deck_name) media_files = [] @@ -177,7 +178,7 @@ def generate_anki_package( ) my_deck.add_note(note) - temp_path = Path(f"/tmp/{filename}") # noqa: S108 + temp_path = Path(tempfile.gettempdir()) / filename temp_path.write_bytes(image_data) media_files.append(str(temp_path)) diff --git a/python_pkg/anki_decks/warsaw_metro/warsaw_metro_anki.py b/python_pkg/anki_decks/warsaw_metro/warsaw_metro_anki.py index c8d7b50..e50e8df 100755 --- a/python_pkg/anki_decks/warsaw_metro/warsaw_metro_anki.py +++ b/python_pkg/anki_decks/warsaw_metro/warsaw_metro_anki.py @@ -11,8 +11,9 @@ import argparse import hashlib from io import BytesIO from pathlib import Path -import random +import secrets import sys +import tempfile from typing import TYPE_CHECKING sys.path.insert(0, str(Path(__file__).parent.parent)) @@ -115,7 +116,7 @@ def generate_anki_package( deck_name: str = "Warsaw Metro Stations", ) -> genanki.Package: """Generate Anki package for Warsaw metro stations.""" - model_id_hash = hashlib.md5(f"warsaw_metro_{deck_name}".encode()) # noqa: S324 + model_id_hash = hashlib.sha256(f"warsaw_metro_{deck_name}".encode()) model_id = int(model_id_hash.hexdigest()[:8], 16) card_css = """ @@ -181,7 +182,7 @@ def generate_anki_package( css=card_css, ) - deck_id = random.randrange(1 << 30, 1 << 31) # noqa: S311 + deck_id = secrets.randbelow(1 << 30) + (1 << 30) my_deck = genanki.Deck(deck_id, deck_name) media_files = [] @@ -200,7 +201,7 @@ def generate_anki_package( ) my_deck.add_note(note) - temp_path = Path(f"/tmp/{filename}") # noqa: S108 + temp_path = Path(tempfile.gettempdir()) / filename temp_path.write_bytes(image_data) media_files.append(str(temp_path)) diff --git a/python_pkg/anki_decks/warsaw_osiedla/warsaw_osiedla_anki.py b/python_pkg/anki_decks/warsaw_osiedla/warsaw_osiedla_anki.py index 5a3ee77..15a3a5e 100755 --- a/python_pkg/anki_decks/warsaw_osiedla/warsaw_osiedla_anki.py +++ b/python_pkg/anki_decks/warsaw_osiedla/warsaw_osiedla_anki.py @@ -11,8 +11,9 @@ import argparse import hashlib from io import BytesIO from pathlib import Path -import random +import secrets import sys +import tempfile from typing import TYPE_CHECKING sys.path.insert(0, str(Path(__file__).parent.parent)) @@ -156,7 +157,7 @@ def generate_anki_package( deck_name: str = "Warsaw Osiedla", ) -> genanki.Package: """Generate Anki package for Warsaw osiedla.""" - model_id_hash = hashlib.md5(f"warsaw_osiedla_{deck_name}".encode()) # noqa: S324 + model_id_hash = hashlib.sha256(f"warsaw_osiedla_{deck_name}".encode()) model_id = int(model_id_hash.hexdigest()[:8], 16) card_css = """ @@ -212,7 +213,7 @@ def generate_anki_package( css=card_css, ) - deck_id = random.randrange(1 << 30, 1 << 31) # noqa: S311 + deck_id = secrets.randbelow(1 << 30) + (1 << 30) my_deck = genanki.Deck(deck_id, deck_name) media_files = [] @@ -232,7 +233,7 @@ def generate_anki_package( ) my_deck.add_note(note) - temp_path = Path(f"/tmp/{filename}") # noqa: S108 + temp_path = Path(tempfile.gettempdir()) / filename temp_path.write_bytes(image_data) media_files.append(str(temp_path)) diff --git a/python_pkg/anki_decks/warsaw_streets/warsaw_streets_anki.py b/python_pkg/anki_decks/warsaw_streets/warsaw_streets_anki.py index 2eb304c..8ce8b3f 100755 --- a/python_pkg/anki_decks/warsaw_streets/warsaw_streets_anki.py +++ b/python_pkg/anki_decks/warsaw_streets/warsaw_streets_anki.py @@ -17,8 +17,9 @@ import argparse import hashlib from io import BytesIO from pathlib import Path -import random +import secrets import sys +import tempfile from typing import TYPE_CHECKING, Any sys.path.insert(0, str(Path(__file__).parent.parent)) @@ -187,7 +188,7 @@ def generate_anki_package( Returns: genanki.Package object. """ - model_id_hash = hashlib.md5(f"warsaw_streets_{deck_name}".encode()) # noqa: S324 + model_id_hash = hashlib.sha256(f"warsaw_streets_{deck_name}".encode()) model_id = int(model_id_hash.hexdigest()[:8], 16) card_css = """ @@ -243,7 +244,7 @@ def generate_anki_package( css=card_css, ) - deck_id = random.randrange(1 << 30, 1 << 31) # noqa: S311 + deck_id = secrets.randbelow(1 << 30) + (1 << 30) my_deck = genanki.Deck(deck_id, deck_name) media_files = [] @@ -259,7 +260,7 @@ def generate_anki_package( ) my_deck.add_note(note) - temp_path = Path(f"/tmp/{filename}") # noqa: S108 + temp_path = Path(tempfile.gettempdir()) / filename temp_path.write_bytes(image_data) media_files.append(str(temp_path))