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)
This commit is contained in:
Krzysztof kuhy Rudnicki 2026-03-13 20:47:52 +01:00
parent 2bb930db6f
commit 2a61619001
20 changed files with 194 additions and 172 deletions

View File

@ -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))

View File

@ -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))

View File

@ -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))

View File

@ -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))

View File

@ -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))

View File

@ -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))

View File

@ -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)

View File

@ -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))

View File

@ -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))

View File

@ -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))

View File

@ -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))

View File

@ -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))

View File

@ -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))

View File

@ -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))

View File

@ -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))

View File

@ -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))

View File

@ -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))

View File

@ -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))

View File

@ -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))

View File

@ -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))