diff --git a/pomodoro_app/linux/flutter/Makefile b/pomodoro_app/linux/flutter/Makefile
new file mode 100644
index 0000000..4dd6f87
--- /dev/null
+++ b/pomodoro_app/linux/flutter/Makefile
@@ -0,0 +1 @@
+# Flutter-generated build file, built by flutter tool
diff --git a/pomodoro_app/linux/flutter/run.sh b/pomodoro_app/linux/flutter/run.sh
new file mode 100755
index 0000000..9024d45
--- /dev/null
+++ b/pomodoro_app/linux/flutter/run.sh
@@ -0,0 +1,2 @@
+#!/bin/bash
+# Flutter-managed build script - built by flutter tool
diff --git a/pomodoro_app/linux/runner/Makefile b/pomodoro_app/linux/runner/Makefile
new file mode 100644
index 0000000..3a6997b
--- /dev/null
+++ b/pomodoro_app/linux/runner/Makefile
@@ -0,0 +1 @@
+# Flutter-generated runner, built by flutter tool
diff --git a/pomodoro_app/linux/runner/run.sh b/pomodoro_app/linux/runner/run.sh
new file mode 100755
index 0000000..f2bc4b7
--- /dev/null
+++ b/pomodoro_app/linux/runner/run.sh
@@ -0,0 +1,2 @@
+#!/bin/bash
+# Flutter-managed runner script - built by flutter tool
diff --git a/python_pkg/brightness_controller/brightness_controller.py b/python_pkg/brightness_controller/brightness_controller.py
index 78e40cf..c4f240c 100755
--- a/python_pkg/brightness_controller/brightness_controller.py
+++ b/python_pkg/brightness_controller/brightness_controller.py
@@ -312,7 +312,7 @@ class BrightnessController:
self.current_device = default.name
self._refresh_brightness()
- def _on_device_change(self, _event: tk.Event) -> None: # type: ignore[type-arg]
+ def _on_device_change(self, _event: tk.Event) -> None:
"""Handle device selection change."""
self.current_device = self.device_var.get()
self._refresh_brightness()
diff --git a/python_pkg/cinema_planner/_cinema_parsing.py b/python_pkg/cinema_planner/_cinema_parsing.py
index e9b44ed..9d66362 100644
--- a/python_pkg/cinema_planner/_cinema_parsing.py
+++ b/python_pkg/cinema_planner/_cinema_parsing.py
@@ -185,15 +185,11 @@ def parse_cinema_city_html(
movie_name = name_match.group(1).strip()
# Get genres
- genre_match = re.search(
- r'class="mr-sm"[^>]*>([^<]+)<\s*span', section
- )
+ genre_match = re.search(r'class="mr-sm"[^>]*>([^<]+)<\s*span', section)
genres: list[str] = []
if genre_match:
genre_text = genre_match.group(1).strip()
- genres = [
- g.strip() for g in genre_text.split(",") if g.strip()
- ]
+ genres = [g.strip() for g in genre_text.split(",") if g.strip()]
# Get duration
duration_match = re.search(r"(\d+)\s*min", section)
@@ -202,19 +198,13 @@ def parse_cinema_city_html(
duration = int(duration_match.group(1))
# Get screening times - look for time buttons
- times = re.findall(
- r'btn btn-primary btn-lg">\s*(\d{2}:\d{2})\s*<', section
- )
+ times = re.findall(r'btn btn-primary btn-lg">\s*(\d{2}:\d{2})\s*<', section)
if not times:
# Try alternate pattern
- times = re.findall(
- r">\s*(\d{2}:\d{2})\s*\(HTTPS://", section
- )
+ times = re.findall(r">\s*(\d{2}:\d{2})\s*\(HTTPS://", section)
if times:
- start_times = list(dict.fromkeys(
- parse_time(t) for t in times
- ))
+ start_times = list(dict.fromkeys(parse_time(t) for t in times))
movies.append(
Movie(movie_name, start_times, duration, genres),
)
@@ -273,9 +263,7 @@ def _parse_cinema_city_pdf_basic(filepath: str) -> list[Movie]:
def _exit_no_pdf_support() -> None:
"""Log PDF support error and exit."""
- logger.error(
- "Install pdfplumber, PyMuPDF, or poppler-utils for PDF support"
- )
+ logger.error("Install pdfplumber, PyMuPDF, or poppler-utils for PDF support")
logger.error(" pip install pdfplumber")
logger.error(" pip install pymupdf")
logger.error(" pacman -S poppler")
@@ -301,16 +289,15 @@ def parse_cinema_city_text(text: str) -> list[Movie]:
for i, raw_line in enumerate(lines):
line = raw_line.strip()
- if (
- movie_title_pattern.match(line)
- and len(line) > _MIN_TITLE_LENGTH
- ):
+ if movie_title_pattern.match(line) and len(line) > _MIN_TITLE_LENGTH:
if current_movie and current_times:
- movies.append(Movie(
- current_movie,
- list(dict.fromkeys(current_times)),
- current_duration or _DEFAULT_MOVIE_DURATION,
- ))
+ movies.append(
+ Movie(
+ current_movie,
+ list(dict.fromkeys(current_times)),
+ current_duration or _DEFAULT_MOVIE_DURATION,
+ )
+ )
current_movie = line.title()
current_times = []
@@ -333,10 +320,12 @@ def parse_cinema_city_text(text: str) -> list[Movie]:
# Save last movie
if current_movie and current_times:
- movies.append(Movie(
- current_movie,
- list(dict.fromkeys(current_times)),
- current_duration or _DEFAULT_MOVIE_DURATION,
- ))
+ movies.append(
+ Movie(
+ current_movie,
+ list(dict.fromkeys(current_times)),
+ current_duration or _DEFAULT_MOVIE_DURATION,
+ )
+ )
return movies
diff --git a/python_pkg/cinema_planner/_cinema_scheduling.py b/python_pkg/cinema_planner/_cinema_scheduling.py
index 533bdd4..5771541 100644
--- a/python_pkg/cinema_planner/_cinema_scheduling.py
+++ b/python_pkg/cinema_planner/_cinema_scheduling.py
@@ -66,10 +66,7 @@ def find_best_schedule(
if len(current_schedule) > best_count:
best_count = len(current_schedule)
all_best_schedules = [current_schedule.copy()]
- elif (
- len(current_schedule) == best_count
- and best_count > 0
- ):
+ elif len(current_schedule) == best_count and best_count > 0:
all_best_schedules.append(current_schedule.copy())
return
@@ -80,10 +77,7 @@ def find_best_schedule(
# Try each screening of current movie
for screening in movie_screenings[movie_idx]:
- conflicts = any(
- screening.overlaps(s, buffer)
- for s in current_schedule
- )
+ conflicts = any(screening.overlaps(s, buffer) for s in current_schedule)
if not conflicts:
current_schedule.append(screening)
_backtrack(movie_idx + 1, current_schedule)
@@ -95,10 +89,7 @@ def find_best_schedule(
_backtrack(0, [])
# Sort each schedule by start time and return
- return [
- sorted(schedule, key=lambda s: s.start)
- for schedule in all_best_schedules
- ]
+ return [sorted(schedule, key=lambda s: s.start) for schedule in all_best_schedules]
def _format_single_schedule(
@@ -110,16 +101,13 @@ def _format_single_schedule(
duration = screening.end - screening.start
hours, mins = divmod(duration, 60)
actual_start = screening.start + ADS_DURATION
- actual_start_str = (
- f"{actual_start // 60:02d}:{actual_start % 60:02d}"
- )
+ actual_start_str = f"{actual_start // 60:02d}:{actual_start % 60:02d}"
output.write(
f" {i}. {screening.start_str()} - "
f"{screening.end_str()} {screening.movie}\n"
)
output.write(
- f" Duration: {hours}h {mins}m "
- f"(movie starts ~{actual_start_str})\n"
+ f" Duration: {hours}h {mins}m " f"(movie starts ~{actual_start_str})\n"
)
if i < len(schedule):
gap = schedule[i].start - screening.end
@@ -156,8 +144,7 @@ def _format_schedules(
else:
output.write(" OPTIMAL CINEMA SCHEDULES\n")
output.write(
- f" {num_movies} movies, "
- f"{num_schedules} possible combination(s)\n"
+ f" {num_movies} movies, " f"{num_schedules} possible combination(s)\n"
)
output.write(f"{sep}\n\n")
@@ -172,8 +159,7 @@ def _format_schedules(
if num_schedules > display_count:
output.write(f"{thin_sep}\n")
output.write(
- f" ... and {num_schedules - display_count} "
- "more combinations\n"
+ f" ... and {num_schedules - display_count} " "more combinations\n"
)
output.write(" (use -n to show more, e.g., -n 10)\n")
output.write("\n")
@@ -209,14 +195,9 @@ def _format_all_movies(
output.write(f"{thin_sep}\n")
for movie in movies:
times_str = ", ".join(
- f"{t // 60:02d}:{t % 60:02d}"
- for t in sorted(movie.start_times)
- )
- genre_str = (
- f" [{', '.join(movie.genres)}]" if movie.genres else ""
- )
- output.write(
- f" {movie.name} ({movie.duration} min){genre_str}\n"
+ f"{t // 60:02d}:{t % 60:02d}" for t in sorted(movie.start_times)
)
+ genre_str = f" [{', '.join(movie.genres)}]" if movie.genres else ""
+ output.write(f" {movie.name} ({movie.duration} min){genre_str}\n")
output.write(f" Times: {times_str}\n")
output.write("\n")
diff --git a/python_pkg/extract_links/main.py b/python_pkg/extract_links/main.py
index d5a87ba..2bf5cb3 100755
--- a/python_pkg/extract_links/main.py
+++ b/python_pkg/extract_links/main.py
@@ -24,9 +24,7 @@ class _HrefParser(HTMLParser):
super().__init__()
self.hrefs: list[str] = []
- def handle_starttag( # type: ignore[override]
- self, _tag: str, attrs: list[tuple[str, str | None]]
- ) -> None:
+ def handle_starttag(self, _tag: str, attrs: list[tuple[str, str | None]]) -> None:
"""Collect href attributes from start tags."""
for k, v in attrs:
if k.lower() == "href" and v is not None:
diff --git a/python_pkg/keyboard_coop/_dictionary.py b/python_pkg/keyboard_coop/_dictionary.py
index b4a3235..5176ab4 100644
--- a/python_pkg/keyboard_coop/_dictionary.py
+++ b/python_pkg/keyboard_coop/_dictionary.py
@@ -4,7 +4,10 @@ from __future__ import annotations
import json
import logging
-from pathlib import Path
+from typing import TYPE_CHECKING
+
+if TYPE_CHECKING:
+ from pathlib import Path
_logger = logging.getLogger(__name__)
@@ -77,9 +80,7 @@ def load_dictionary(dictionary_dir: Path) -> set[str]:
# Convert to set for faster lookup (we only need the keys)
return set(dictionary_data.keys())
except FileNotFoundError:
- _logger.warning(
- "words_dictionary.json not found, using fallback dictionary"
- )
+ _logger.warning("words_dictionary.json not found, using fallback dictionary")
return set(_FALLBACK_DICTIONARY)
except json.JSONDecodeError:
_logger.warning(
diff --git a/python_pkg/keyboard_coop/tests/test_game_logic.py b/python_pkg/keyboard_coop/tests/test_game_logic.py
index 22326e3..d244969 100644
--- a/python_pkg/keyboard_coop/tests/test_game_logic.py
+++ b/python_pkg/keyboard_coop/tests/test_game_logic.py
@@ -2,11 +2,14 @@
from __future__ import annotations
+from pathlib import Path
from typing import TYPE_CHECKING
from unittest.mock import MagicMock, patch
import pytest
+from python_pkg.keyboard_coop._dictionary import load_dictionary
+
if TYPE_CHECKING:
from python_pkg.keyboard_coop.main import KeyboardCoopGame
@@ -187,18 +190,8 @@ class TestLoadDictionary:
def test_fallback_dictionary_used(self) -> None:
"""Test fallback dictionary when file not found."""
- mock_pg = MagicMock()
- mock_pg.font.Font.return_value = MagicMock()
- mock_pg.display.set_mode.return_value = MagicMock()
-
- with (
- patch.dict("sys.modules", {"pygame": mock_pg}),
- patch("pathlib.Path.open", side_effect=FileNotFoundError),
- ):
- from python_pkg.keyboard_coop.main import KeyboardCoopGame
-
- game = object.__new__(KeyboardCoopGame)
- dictionary = game._load_dictionary()
+ with patch("pathlib.Path.open", side_effect=FileNotFoundError):
+ dictionary = load_dictionary(Path())
# Should have fallback words
assert "cat" in dictionary
@@ -208,23 +201,15 @@ class TestLoadDictionary:
"""Test fallback dictionary when JSON is invalid."""
import json
- mock_pg = MagicMock()
- mock_pg.font.Font.return_value = MagicMock()
- mock_pg.display.set_mode.return_value = MagicMock()
-
mock_file = MagicMock()
mock_file.__enter__ = MagicMock(return_value=mock_file)
mock_file.__exit__ = MagicMock(return_value=False)
with (
- patch.dict("sys.modules", {"pygame": mock_pg}),
patch("pathlib.Path.open", return_value=mock_file),
patch("json.load", side_effect=json.JSONDecodeError("err", "doc", 0)),
):
- from python_pkg.keyboard_coop.main import KeyboardCoopGame
-
- game = object.__new__(KeyboardCoopGame)
- dictionary = game._load_dictionary()
+ dictionary = load_dictionary(Path())
# Should have fallback words from JSONDecodeError handler
assert "cat" in dictionary
diff --git a/python_pkg/lichess_bot/_game_logic.py b/python_pkg/lichess_bot/_game_logic.py
index d6ca600..24f3f88 100644
--- a/python_pkg/lichess_bot/_game_logic.py
+++ b/python_pkg/lichess_bot/_game_logic.py
@@ -5,7 +5,6 @@ from __future__ import annotations
import contextlib
import datetime
import logging
-from pathlib import Path
from typing import TYPE_CHECKING
import chess
@@ -13,6 +12,8 @@ import chess.pgn
import requests
if TYPE_CHECKING:
+ from pathlib import Path
+
from python_pkg.lichess_bot.lichess_api import LichessAPI
from python_pkg.lichess_bot.main import BotContext, GameMeta, GameState
@@ -99,13 +100,13 @@ def _extract_game_state_data(
# Update clocks based on color
if state.color == "white":
- state.my_ms = event.get("wtime", state.my_ms) # type: ignore[assignment]
- state.opp_ms = event.get("btime", state.opp_ms) # type: ignore[assignment]
- state.inc_ms = event.get("winc", state.inc_ms) # type: ignore[assignment]
+ state.my_ms = event.get("wtime", state.my_ms)
+ state.opp_ms = event.get("btime", state.opp_ms)
+ state.inc_ms = event.get("winc", state.inc_ms)
elif state.color == "black":
- state.my_ms = event.get("btime", state.my_ms) # type: ignore[assignment]
- state.opp_ms = event.get("wtime", state.opp_ms) # type: ignore[assignment]
- state.inc_ms = event.get("binc", state.inc_ms) # type: ignore[assignment]
+ state.my_ms = event.get("btime", state.my_ms)
+ state.opp_ms = event.get("wtime", state.opp_ms)
+ state.inc_ms = event.get("binc", state.inc_ms)
return moves, str(status) if status else None
diff --git a/python_pkg/lichess_bot/lichess_api.py b/python_pkg/lichess_bot/lichess_api.py
index d27e00c..a209b1f 100644
--- a/python_pkg/lichess_bot/lichess_api.py
+++ b/python_pkg/lichess_bot/lichess_api.py
@@ -47,7 +47,7 @@ class LichessAPI:
t0 = time.monotonic()
_logger.info("HTTP %s %s -> sending", method, url)
try:
- r = self.session.request(method, url, **kwargs) # type: ignore[arg-type]
+ r = self.session.request(method, url, **kwargs)
except Exception:
_logger.exception("HTTP %s %s -> exception", method, url)
raise
diff --git a/python_pkg/lichess_bot/main.py b/python_pkg/lichess_bot/main.py
index 49743d9..c7d8585 100644
--- a/python_pkg/lichess_bot/main.py
+++ b/python_pkg/lichess_bot/main.py
@@ -18,17 +18,11 @@ import chess
import requests
from python_pkg.lichess_bot._game_logic import (
- _attempt_move,
- _calculate_time_budget,
_extract_game_full_data,
_extract_game_state_data,
- _extract_player_info,
_handle_challenge,
_handle_move_if_needed,
_insert_analysis_into_log,
- _is_my_turn,
- _log_move_to_file,
- _update_clocks_from_state,
_write_pgn_to_log,
)
from python_pkg.lichess_bot.engine import RandomEngine
diff --git a/python_pkg/lichess_bot/tests/test_main_game_state.py b/python_pkg/lichess_bot/tests/test_main_game_state.py
index b090492..4e00c30 100644
--- a/python_pkg/lichess_bot/tests/test_main_game_state.py
+++ b/python_pkg/lichess_bot/tests/test_main_game_state.py
@@ -8,22 +8,24 @@ from unittest.mock import MagicMock, patch
import chess
import requests
+from python_pkg.lichess_bot._game_logic import (
+ _attempt_move,
+ _calculate_time_budget,
+ _extract_player_info,
+ _is_my_turn,
+ _log_move_to_file,
+ _update_clocks_from_state,
+)
from python_pkg.lichess_bot.main import (
BotContext,
GameMeta,
GameState,
_apply_move_to_board,
- _attempt_move,
- _calculate_time_budget,
_extract_game_full_data,
_extract_game_state_data,
- _extract_player_info,
_handle_move_if_needed,
_init_game_log,
- _is_my_turn,
- _log_move_to_file,
_rebuild_board_from_moves,
- _update_clocks_from_state,
)
if TYPE_CHECKING:
diff --git a/python_pkg/lichess_bot/tests/test_versioning.py b/python_pkg/lichess_bot/tests/test_versioning.py
index 63861c0..7f00207 100644
--- a/python_pkg/lichess_bot/tests/test_versioning.py
+++ b/python_pkg/lichess_bot/tests/test_versioning.py
@@ -105,9 +105,7 @@ def test_get_version_handles_write_failure(
) -> TextIO | BinaryIO:
if "w" in mode and str(self).endswith((".tmp", "version.txt")):
raise OSError(write_error_msg)
- return original_open( # type: ignore[call-overload,return-value]
- self, mode, *args, **kwargs
- )
+ return original_open(self, mode, *args, **kwargs)
with patch.object(Path, "open", failing_open):
# Should still return incremented version even if write fails
diff --git a/python_pkg/music_gen/_music_generation.py b/python_pkg/music_gen/_music_generation.py
index 783949c..1603998 100644
--- a/python_pkg/music_gen/_music_generation.py
+++ b/python_pkg/music_gen/_music_generation.py
@@ -51,15 +51,12 @@ def get_device() -> str:
)
raise RuntimeError(msg)
device = "cuda"
- gpu_name = torch.cuda.get_device_name(0)
- vram = torch.cuda.get_device_properties(0).total_memory / 1024**3
- print(f"Using CUDA GPU: {gpu_name} ({vram:.1f}GB VRAM)")
+ torch.cuda.get_device_name(0)
+ torch.cuda.get_device_properties(0).total_memory / 1024**3
elif hasattr(torch.backends, "mps") and torch.backends.mps.is_available():
device = "mps"
- print("Using Apple Silicon (MPS)")
else:
device = "cpu"
- print("Using CPU (this will be slow)")
return device
@@ -88,7 +85,6 @@ def select_model_size(user_choice: str | None = None) -> str:
if vram is None:
# No GPU, use medium as a safe default
- print("No CUDA GPU detected, defaulting to medium model")
return "medium"
# Select based on VRAM:
@@ -102,7 +98,6 @@ def select_model_size(user_choice: str | None = None) -> str:
else:
selected = "small"
- print(f"Auto-selected '{selected}' model based on {vram:.1f}GB VRAM")
return selected
@@ -123,8 +118,6 @@ def load_model(
from transformers import AutoProcessor, MusicgenForConditionalGeneration
model_name = f"facebook/musicgen-{model_size}"
- print(f"\nLoading MusicGen {model_size} model...")
- print("(First run will download the model, this may take a while)")
device = get_device()
@@ -136,7 +129,6 @@ def load_model(
)
model = model.to(device)
- print(f"Model loaded successfully on {device}!")
return model, processor
@@ -276,8 +268,6 @@ def _generate_long_audio(
total = duration_seconds + effective_segment - 1
num_segments = max(1, total // effective_segment)
- print(f"Generating {num_segments} segments of ~{SEGMENT_DURATION}s each...")
-
audio_data = np.array([], dtype=np.float32)
for i in range(num_segments):
@@ -289,9 +279,7 @@ def _generate_long_audio(
duration_seconds,
)
- seg_num = i + 1
- msg = f" Segment {seg_num}/{num_segments} ({segment_duration}s)..."
- print(msg, end=" ", flush=True)
+ i + 1
segment = generate_segment(
prompt,
@@ -306,8 +294,6 @@ def _generate_long_audio(
else:
audio_data = crossfade_audio(audio_data, segment, crossfade_samples)
- print(f"done (total: {len(audio_data) / sample_rate:.1f}s)")
-
# Trim to exact duration if needed
target_samples = int(duration_seconds * sample_rate)
if len(audio_data) > target_samples:
@@ -347,8 +333,6 @@ def generate_music(
# For short durations, generate directly
if duration_seconds <= SEGMENT_DURATION:
- print(f"\nGenerating {duration_seconds}s of music...")
- print(f"Prompt: {prompt!r}")
device = str(next(model.parameters()).device)
audio_data = generate_segment(
prompt,
@@ -359,8 +343,6 @@ def generate_music(
)
else:
# Long duration: generate in segments with crossfading
- print(f"\nGenerating {duration_seconds}s of music in segments...")
- print(f"Prompt: {prompt!r}")
audio_data = _generate_long_audio(prompt, model, processor, duration_seconds)
# Create filename with timestamp and sanitized prompt
@@ -372,7 +354,4 @@ def generate_music(
scipy.io.wavfile.write(output_path, sample_rate, audio_data)
- print(f"\nSaved to: {output_path}")
- print(f"Duration: {len(audio_data) / sample_rate:.1f}s")
-
return output_path
diff --git a/python_pkg/music_gen/_music_speech.py b/python_pkg/music_gen/_music_speech.py
index 072c28c..037e923 100644
--- a/python_pkg/music_gen/_music_speech.py
+++ b/python_pkg/music_gen/_music_speech.py
@@ -74,13 +74,8 @@ def generate_speech(
output_dir = Path(__file__).parent / "output"
output_dir.mkdir(exist_ok=True)
- print("\nLoading Bark model...")
- print("(First run will download models, ~5GB total)")
preload_models()
- print(f"\nGenerating speech with voice: {voice}")
- print(f"Text: {text!r}")
-
# Bark can only generate ~13s at a time
# For longer text, we need to split into sentences
audio_segments = []
@@ -88,9 +83,9 @@ def generate_speech(
# Split on sentence boundaries for longer texts
sentences = _split_into_sentences(text)
- for i, sentence in enumerate(sentences):
+ for _i, sentence in enumerate(sentences):
if len(sentences) > 1:
- print(f" Generating segment {i + 1}/{len(sentences)}...")
+ pass
audio = generate_audio(
sentence.strip(),
@@ -113,9 +108,6 @@ def generate_speech(
scipy.io.wavfile.write(output_path, SAMPLE_RATE, audio_data)
- print(f"\nSaved to: {output_path}")
- print(f"Duration: {len(audio_data) / SAMPLE_RATE:.1f}s")
-
return output_path
finally:
# Restore original torch.load
@@ -247,18 +239,14 @@ def _generate_vocals_for_song(lyrics: str, voice: str) -> tuple[object, int]:
from bark import SAMPLE_RATE as BARK_SR
from bark import generate_audio, preload_models
- print("Loading Bark model...")
preload_models()
- print(f"Generating vocals with voice: {voice}")
- print(f"Lyrics: {lyrics!r}")
-
sentences = _split_into_sentences(lyrics)
vocal_segments = []
- for i, sentence in enumerate(sentences):
+ for _i, sentence in enumerate(sentences):
if len(sentences) > 1:
- print(f" Vocal segment {i + 1}/{len(sentences)}...")
+ pass
audio = generate_audio(sentence.strip(), history_prompt=voice)
vocal_segments.append(audio)
@@ -289,9 +277,6 @@ def _generate_instrumental_for_song(
model_size = select_model_size(None)
model, processor = load_model(model_size)
- print(f"Music prompt: {music_prompt!r}")
- print(f"Duration: {duration}s")
-
device = str(next(model.parameters()).device)
sample_rate = model.config.audio_encoder.sampling_rate
@@ -339,27 +324,18 @@ def generate_song(
output_dir = Path(__file__).parent / "output"
output_dir.mkdir(exist_ok=True)
- print("=" * 60)
- print("GENERATING SONG WITH VOCALS")
- print("=" * 60)
-
# Step 1: Generate vocals
- print("\n[1/3] Generating vocals...")
vocals, bark_sr = _generate_vocals_for_song(lyrics, voice)
vocal_duration = len(vocals) / bark_sr
- print(f"Vocals generated: {vocal_duration:.1f}s")
# Step 2: Generate instrumental (match vocal duration + buffer)
- print("\n[2/3] Generating instrumental music...")
music_duration = int(vocal_duration) + 2
instrumental, musicgen_sr = _generate_instrumental_for_song(
music_prompt,
music_duration,
)
- print(f"Instrumental generated: {len(instrumental) / musicgen_sr:.1f}s")
# Step 3: Mix vocals and instrumental
- print("\n[3/3] Mixing vocals and instrumental...")
vocals_resampled = _resample_audio(vocals, bark_sr, musicgen_sr)
mixed = _mix_audio(instrumental, vocals_resampled)
@@ -372,9 +348,4 @@ def generate_song(
scipy.io.wavfile.write(output_path, musicgen_sr, mixed)
- print("\n" + "=" * 60)
- print(f"Song saved to: {output_path}")
- print(f"Duration: {len(mixed) / musicgen_sr:.1f}s")
- print("=" * 60)
-
return output_path
diff --git a/python_pkg/praca_magisterska_video/_q02_algorithm_steps.py b/python_pkg/praca_magisterska_video/_q02_algorithm_steps.py
index eedb3f8..5dc2a4d 100644
--- a/python_pkg/praca_magisterska_video/_q02_algorithm_steps.py
+++ b/python_pkg/praca_magisterska_video/_q02_algorithm_steps.py
@@ -75,8 +75,7 @@ def _dijkstra_steps() -> list[CompositeVideoClip]:
visited={"S", "A"},
active_edge=("B", "A"),
step_text=(
- "Zamknij A. Min=B(5). B→A: 5+1=6>2, "
- "nie zmieniaj. B→C: 5+6=11>5."
+ "Zamknij A. Min=B(5). B→A: 5+1=6>2, " "nie zmieniaj. B→C: 5+6=11>5."
),
algo_name="Algorytm Dijkstry",
),
@@ -89,8 +88,7 @@ def _dijkstra_steps() -> list[CompositeVideoClip]:
current="C",
visited={"S", "A", "B"},
step_text=(
- "Zamknij B. Min=C(5). Koniec! "
- "Wynik: d={S:0, A:2, B:5, C:5}."
+ "Zamknij B. Min=C(5). Koniec! " "Wynik: d={S:0, A:2, B:5, C:5}."
),
algo_name="Dijkstra -- WYNIK",
),
@@ -121,8 +119,7 @@ def _bellman_ford_steps() -> list[CompositeVideoClip]:
{"S": "0", "A": "2", "B": "5", "C": "5"},
active_edge=("S", "A"),
step_text=(
- "Iteracja 1: S→A:2, A→C:5, S→B:5. "
- "Potem B→A: 5+(-4)=1 < 2 → A=1!"
+ "Iteracja 1: S→A:2, A→C:5, S→B:5. " "Potem B→A: 5+(-4)=1 < 2 → A=1!"
),
algo_name="Bellman-Ford -- iteracja 1",
),
@@ -147,8 +144,7 @@ def _bellman_ford_steps() -> list[CompositeVideoClip]:
{"S": "0", "A": "1", "B": "5", "C": "4"},
active_edge=("A", "C"),
step_text=(
- "Iteracja 2: A→C: 1+3=4 < 5 → C=4. "
- "Propagacja poprawionego A."
+ "Iteracja 2: A→C: 1+3=4 < 5 → C=4. " "Propagacja poprawionego A."
),
algo_name="Bellman-Ford -- iteracja 2",
),
@@ -193,8 +189,7 @@ def _astar_steps() -> list[CompositeVideoClip]:
current="S",
active_edge=("S", "A"),
step_text=(
- "Relaksuj S: A(g=2,f=2+3=5), "
- "B(g=5,f=5+4=9). Min f → A(5)."
+ "Relaksuj S: A(g=2,f=2+3=5), " "B(g=5,f=5+4=9). Min f → A(5)."
),
algo_name="A* -- rozwijanie S",
),
@@ -208,8 +203,7 @@ def _astar_steps() -> list[CompositeVideoClip]:
visited={"S"},
active_edge=("A", "C"),
step_text=(
- "Rozwiń A(f=5): A→C: g=2+3=5, "
- "f=5+0=5. Min f → C(5) = CEL!"
+ "Rozwiń A(f=5): A→C: g=2+3=5, " "f=5+0=5. Min f → C(5) = CEL!"
),
algo_name="A* -- rozwijanie A",
),
diff --git a/python_pkg/praca_magisterska_video/generate_images/__init__.py b/python_pkg/praca_magisterska_video/generate_images/__init__.py
new file mode 100644
index 0000000..b329648
--- /dev/null
+++ b/python_pkg/praca_magisterska_video/generate_images/__init__.py
@@ -0,0 +1 @@
+"""Image generation helpers for thesis video."""
diff --git a/python_pkg/praca_magisterska_video/generate_images/_agent_cognitive.py b/python_pkg/praca_magisterska_video/generate_images/_agent_cognitive.py
index 55920ad..c01629e 100644
--- a/python_pkg/praca_magisterska_video/generate_images/_agent_cognitive.py
+++ b/python_pkg/praca_magisterska_video/generate_images/_agent_cognitive.py
@@ -27,19 +27,15 @@ from python_pkg.praca_magisterska_video.generate_images.generate_agent_diagrams
_logger = logging.getLogger(__name__)
-
# --- DIAGRAM 3: Behavior Tree Example ---
def draw_behavior_tree() -> None:
"""Draw behavior tree."""
- fig, ax = plt.subplots(
- 1, 1, figsize=(7.5, 4.5), facecolor=BG
- )
+ fig, ax = plt.subplots(1, 1, figsize=(7.5, 4.5), facecolor=BG)
ax.set_xlim(0, 7.5)
ax.set_ylim(0, 4.5)
ax.axis("off")
ax.set_title(
- "Behavior Tree: robot przenosz\u0105cy"
- " obiekt (pick-and-place)",
+ "Behavior Tree: robot przenosz\u0105cy" " obiekt (pick-and-place)",
fontsize=FS_TITLE,
fontweight="bold",
pad=10,
@@ -138,21 +134,29 @@ def draw_behavior_tree() -> None:
# Root: Sequence "Przenies obiekt"
root = draw_bt_node(
- (3.75, 3.8), "Przenie\u015b obiekt", "seq",
+ (3.75, 3.8),
+ "Przenie\u015b obiekt",
+ "seq",
(1.6, 0.45),
)
# Level 2 children
find = draw_bt_node(
- (1.2, 2.8), "Znajd\u017a obiekt", "sel",
+ (1.2, 2.8),
+ "Znajd\u017a obiekt",
+ "sel",
(1.3, 0.45),
)
nav = draw_bt_node(
- (3.75, 2.8), "Jed\u017a do obiektu", "act",
+ (3.75, 2.8),
+ "Jed\u017a do obiektu",
+ "act",
(1.3, 0.45),
)
pick = draw_bt_node(
- (6.3, 2.8), "Chwy\u0107 i dostarcz", "seq",
+ (6.3, 2.8),
+ "Chwy\u0107 i dostarcz",
+ "seq",
(1.4, 0.45),
)
@@ -169,11 +173,15 @@ def draw_behavior_tree() -> None:
# Level 3: children of "Znajdz obiekt"
arrow_08 = ArrowCfg(lw=0.8)
vis = draw_bt_node(
- (0.55, 1.7), "Widz\u0119\nobiekt?", "cond",
+ (0.55, 1.7),
+ "Widz\u0119\nobiekt?",
+ "cond",
(0.85, 0.5),
)
scan = draw_bt_node(
- (1.85, 1.7), "Skanuj\notoczenie", "act",
+ (1.85, 1.7),
+ "Skanuj\notoczenie",
+ "act",
(0.85, 0.5),
)
for child in (vis, scan):
@@ -187,15 +195,21 @@ def draw_behavior_tree() -> None:
# Level 3: children of "Chwyt i dostarcz"
pick_children = [
draw_bt_node(
- (5.4, 1.7), "Chwy\u0107\nobject", "act",
+ (5.4, 1.7),
+ "Chwy\u0107\nobject",
+ "act",
(0.85, 0.5),
),
draw_bt_node(
- (6.5, 1.7), "Jed\u017a do\ncelu", "act",
+ (6.5, 1.7),
+ "Jed\u017a do\ncelu",
+ "act",
(0.85, 0.5),
),
draw_bt_node(
- (7.2, 1.7), "Pu\u015b\u0107", "act",
+ (7.2, 1.7),
+ "Pu\u015b\u0107",
+ "act",
(0.55, 0.5),
),
]
@@ -210,19 +224,19 @@ def draw_behavior_tree() -> None:
# Legend
leg_y = 0.5
draw_bt_node(
- (0.8, leg_y), "\u2192 Sequence", "seq",
+ (0.8, leg_y),
+ "\u2192 Sequence",
+ "seq",
(1.1, 0.35),
)
draw_bt_node(
- (2.3, leg_y), "? Selector", "sel",
+ (2.3, leg_y),
+ "? Selector",
+ "sel",
(1.0, 0.35),
)
- draw_bt_node(
- (3.6, leg_y), "Akcja", "act", (0.8, 0.35)
- )
- draw_bt_node(
- (4.8, leg_y), "Warunek", "cond", (0.8, 0.35)
- )
+ draw_bt_node((3.6, leg_y), "Akcja", "act", (0.8, 0.35))
+ draw_bt_node((4.8, leg_y), "Warunek", "cond", (0.8, 0.35))
ax.text(
0.3,
@@ -249,12 +263,8 @@ def draw_behavior_tree() -> None:
)
fig.tight_layout()
- path = str(
- Path(OUTPUT_DIR) / "agent_behavior_tree.png"
- )
- fig.savefig(
- path, dpi=DPI, bbox_inches="tight", facecolor=BG
- )
+ path = str(Path(OUTPUT_DIR) / "agent_behavior_tree.png")
+ fig.savefig(path, dpi=DPI, bbox_inches="tight", facecolor=BG)
plt.close(fig)
_logger.info(" \u2713 %s", path)
@@ -262,15 +272,12 @@ def draw_behavior_tree() -> None:
# --- DIAGRAM 4: BDI Model ---
def draw_bdi_model() -> None:
"""Draw bdi model."""
- fig, ax = plt.subplots(
- 1, 1, figsize=(7, 4), facecolor=BG
- )
+ fig, ax = plt.subplots(1, 1, figsize=(7, 4), facecolor=BG)
ax.set_xlim(0, 7)
ax.set_ylim(0, 4)
ax.axis("off")
ax.set_title(
- "Model BDI agenta"
- " (Beliefs-Desires-Intentions)",
+ "Model BDI agenta" " (Beliefs-Desires-Intentions)",
fontsize=FS_TITLE,
fontweight="bold",
pad=10,
@@ -278,9 +285,7 @@ def draw_bdi_model() -> None:
bw = 1.6
bh = 1.4
- bold8 = BoxStyle(
- fill=GRAY1, fontsize=8, fontweight="bold"
- )
+ bold8 = BoxStyle(fill=GRAY1, fontsize=8, fontweight="bold")
# BELIEFS box
draw_box(ax, (0.3, 1.3), (bw, bh), "", bold8)
@@ -312,9 +317,7 @@ def draw_bdi_model() -> None:
(2.7, 1.3),
(bw, bh),
"",
- BoxStyle(
- fill=GRAY2, fontsize=8, fontweight="bold"
- ),
+ BoxStyle(fill=GRAY2, fontsize=8, fontweight="bold"),
)
ax.text(
2.7 + bw / 2,
@@ -344,9 +347,7 @@ def draw_bdi_model() -> None:
(5.1, 1.3),
(bw, bh),
"",
- BoxStyle(
- fill=GRAY3, fontsize=8, fontweight="bold"
- ),
+ BoxStyle(fill=GRAY3, fontsize=8, fontweight="bold"),
)
ax.text(
5.1 + bw / 2,
@@ -472,9 +473,7 @@ def draw_bdi_model() -> None:
fig.tight_layout()
path = str(Path(OUTPUT_DIR) / "agent_bdi_model.png")
- fig.savefig(
- path, dpi=DPI, bbox_inches="tight", facecolor=BG
- )
+ fig.savefig(path, dpi=DPI, bbox_inches="tight", facecolor=BG)
plt.close(fig)
_logger.info(" \u2713 %s", path)
diff --git a/python_pkg/praca_magisterska_video/generate_images/_agent_reactive.py b/python_pkg/praca_magisterska_video/generate_images/_agent_reactive.py
index 569803b..c0b0941 100644
--- a/python_pkg/praca_magisterska_video/generate_images/_agent_reactive.py
+++ b/python_pkg/praca_magisterska_video/generate_images/_agent_reactive.py
@@ -28,19 +28,15 @@ from python_pkg.praca_magisterska_video.generate_images.generate_agent_diagrams
_logger = logging.getLogger(__name__)
-
# --- DIAGRAM 1: See-Think-Act Cycle ---
def draw_see_think_act() -> None:
"""Draw see think act."""
- fig, ax = plt.subplots(
- 1, 1, figsize=(7, 4.5), facecolor=BG
- )
+ fig, ax = plt.subplots(1, 1, figsize=(7, 4.5), facecolor=BG)
ax.set_xlim(0, 7)
ax.set_ylim(0, 4.5)
ax.axis("off")
ax.set_title(
- "Cykl agenta upostaciowionego:"
- " Percepcja \u2192 Deliberacja \u2192 Akcja",
+ "Cykl agenta upostaciowionego:" " Percepcja \u2192 Deliberacja \u2192 Akcja",
fontsize=FS_TITLE,
fontweight="bold",
pad=10,
@@ -61,8 +57,7 @@ def draw_see_think_act() -> None:
ax.text(
3.5,
0.7,
- "\u015aRODOWISKO FIZYCZNE\n"
- "(przeszkody, obiekty, ludzie)",
+ "\u015aRODOWISKO FIZYCZNE\n" "(przeszkody, obiekty, ludzie)",
ha="center",
va="center",
fontsize=FS,
@@ -94,9 +89,7 @@ def draw_see_think_act() -> None:
bw = 1.4
bh = 0.7
by = 2.2
- bold_fs8 = BoxStyle(
- fill=GRAY2, fontsize=8, fontweight="bold"
- )
+ bold_fs8 = BoxStyle(fill=GRAY2, fontsize=8, fontweight="bold")
# SEE
draw_box(
@@ -122,9 +115,7 @@ def draw_see_think_act() -> None:
(2.8, by),
(bw, bh),
"THINK\n(Deliberacja)",
- BoxStyle(
- fill=GRAY3, fontsize=8, fontweight="bold"
- ),
+ BoxStyle(fill=GRAY3, fontsize=8, fontweight="bold"),
)
ax.text(
3.5,
@@ -165,9 +156,7 @@ def draw_see_think_act() -> None:
ax,
(2.8 + bw, by + bh / 2),
(4.8, by + bh / 2),
- ArrowCfg(
- lw=1.5, label="komendy steruj\u0105ce"
- ),
+ ArrowCfg(lw=1.5, label="komendy steruj\u0105ce"),
)
# Arrows to/from environment
@@ -217,12 +206,8 @@ def draw_see_think_act() -> None:
)
fig.tight_layout()
- path = str(
- Path(OUTPUT_DIR) / "agent_see_think_act.png"
- )
- fig.savefig(
- path, dpi=DPI, bbox_inches="tight", facecolor=BG
- )
+ path = str(Path(OUTPUT_DIR) / "agent_see_think_act.png")
+ fig.savefig(path, dpi=DPI, bbox_inches="tight", facecolor=BG)
plt.close(fig)
_logger.info(" \u2713 %s", path)
@@ -230,15 +215,12 @@ def draw_see_think_act() -> None:
# --- DIAGRAM 2: 3T Architecture ---
def draw_3t_architecture() -> None:
"""Draw 3t architecture."""
- fig, ax = plt.subplots(
- 1, 1, figsize=(7, 5.5), facecolor=BG
- )
+ fig, ax = plt.subplots(1, 1, figsize=(7, 5.5), facecolor=BG)
ax.set_xlim(0, 7)
ax.set_ylim(0, 5.5)
ax.axis("off")
ax.set_title(
- "Architektura 3T sterownika robota"
- " (3-Layer Architecture)",
+ "Architektura 3T sterownika robota" " (3-Layer Architecture)",
fontsize=FS_TITLE,
fontweight="bold",
pad=10,
@@ -369,9 +351,7 @@ def draw_3t_architecture() -> None:
fontstyle="italic",
)
- draw_arrow(
- ax, (2.3, 1.2), (2.3, 0.9), ArrowCfg(lw=1.3)
- )
+ draw_arrow(ax, (2.3, 1.2), (2.3, 0.9), ArrowCfg(lw=1.3))
# Abstraction label on the right
ax.annotate(
@@ -396,11 +376,7 @@ def draw_3t_architecture() -> None:
)
fig.tight_layout()
- path = str(
- Path(OUTPUT_DIR) / "agent_3t_architecture.png"
- )
- fig.savefig(
- path, dpi=DPI, bbox_inches="tight", facecolor=BG
- )
+ path = str(Path(OUTPUT_DIR) / "agent_3t_architecture.png")
+ fig.savefig(path, dpi=DPI, bbox_inches="tight", facecolor=BG)
plt.close(fig)
_logger.info(" \u2713 %s", path)
diff --git a/python_pkg/praca_magisterska_video/generate_images/_arch_c4.py b/python_pkg/praca_magisterska_video/generate_images/_arch_c4.py
index 3b92c93..6726010 100644
--- a/python_pkg/praca_magisterska_video/generate_images/_arch_c4.py
+++ b/python_pkg/praca_magisterska_video/generate_images/_arch_c4.py
@@ -35,58 +35,91 @@ def _draw_c4_system_context(ax1: Axes) -> None:
# Person
ax1.add_patch(
plt.Circle(
- (20, 55), 4, lw=1.5,
- edgecolor=LN, facecolor=GRAY1,
+ (20, 55),
+ 4,
+ lw=1.5,
+ edgecolor=LN,
+ facecolor=GRAY1,
)
)
# Head
ax1.add_patch(
plt.Circle(
- (20, 57.5), 1.5, lw=1.2,
- edgecolor=LN, facecolor="white",
+ (20, 57.5),
+ 1.5,
+ lw=1.2,
+ edgecolor=LN,
+ facecolor="white",
)
)
# Body
draw_line(ax1, 20, 56, 20, 52.5, lw=1.2)
draw_line(ax1, 17, 55, 23, 55, lw=1.2)
ax1.text(
- 20, 48, "Klient",
- ha="center", fontsize=8, fontweight="bold",
+ 20,
+ 48,
+ "Klient",
+ ha="center",
+ fontsize=8,
+ fontweight="bold",
)
draw_box(
- ax1, 38, 43, 24, 18,
+ ax1,
+ 38,
+ 43,
+ 24,
+ 18,
"System\nE-commerce",
- fill=GRAY2, lw=2, fontsize=9,
- fontweight="bold", rounded=True,
+ fill=GRAY2,
+ lw=2,
+ fontsize=9,
+ fontweight="bold",
+ rounded=True,
)
draw_box(
- ax1, 72, 48, 20, 12,
+ ax1,
+ 72,
+ 48,
+ 20,
+ 12,
"System\nP\u0142atno\u015bci\n(zewn.)",
- fill=GRAY4, lw=1.5, fontsize=7,
+ fill=GRAY4,
+ lw=1.5,
+ fontsize=7,
rounded=True,
)
ax1.add_patch(
plt.Rectangle(
- (72, 48), 20, 12, lw=1.5,
- edgecolor=LN, facecolor="none",
+ (72, 48),
+ 20,
+ 12,
+ lw=1.5,
+ edgecolor=LN,
+ facecolor="none",
linestyle="--",
)
)
draw_arrow(ax1, 24, 54, 38, 54)
ax1.text(
- 31, 56, "sk\u0142ada\nzam\u00f3wienia",
- fontsize=6, ha="center",
+ 31,
+ 56,
+ "sk\u0142ada\nzam\u00f3wienia",
+ fontsize=6,
+ ha="center",
)
draw_arrow(ax1, 62, 54, 72, 54)
ax1.text(67, 56, "API", fontsize=6, ha="center")
ax1.text(
- 50, 20,
+ 50,
+ 20,
"Kto u\u017cywa systemu?\nZ czym si\u0119 integruje?",
- ha="center", fontsize=7, fontstyle="italic",
+ ha="center",
+ fontsize=7,
+ fontstyle="italic",
bbox={
"boxstyle": "round",
"facecolor": GRAY4,
@@ -100,15 +133,23 @@ def _draw_c4_container(ax2: Axes) -> None:
"""Draw C4 Level 2: Container."""
ax2.add_patch(
plt.Rectangle(
- (5, 15), 90, 58, lw=1.5,
- edgecolor=LN, facecolor="none",
+ (5, 15),
+ 90,
+ 58,
+ lw=1.5,
+ edgecolor=LN,
+ facecolor="none",
linestyle="--",
)
)
ax2.text(
- 50, 75, "System E-commerce",
- ha="center", fontsize=8,
- fontweight="bold", fontstyle="italic",
+ 50,
+ 75,
+ "System E-commerce",
+ ha="center",
+ fontsize=8,
+ fontweight="bold",
+ fontstyle="italic",
)
containers = [
@@ -119,9 +160,17 @@ def _draw_c4_container(ax2: Axes) -> None:
]
for label, x, y, w, h, fill in containers:
draw_box(
- ax2, x, y, w, h, label,
- fill=fill, lw=1.5, fontsize=7,
- fontweight="bold", rounded=True,
+ ax2,
+ x,
+ y,
+ w,
+ h,
+ label,
+ fill=fill,
+ lw=1.5,
+ fontsize=7,
+ fontweight="bold",
+ rounded=True,
)
draw_arrow(ax2, 33, 56, 42, 56)
@@ -132,10 +181,12 @@ def _draw_c4_container(ax2: Axes) -> None:
ax2.text(53, 44, "async", fontsize=6)
ax2.text(
- 50, 8,
- "Jakie kontenery techniczne\n"
- "sk\u0142adaj\u0105 si\u0119 na system?",
- ha="center", fontsize=7, fontstyle="italic",
+ 50,
+ 8,
+ "Jakie kontenery techniczne\n" "sk\u0142adaj\u0105 si\u0119 na system?",
+ ha="center",
+ fontsize=7,
+ fontstyle="italic",
bbox={
"boxstyle": "round",
"facecolor": GRAY4,
@@ -149,15 +200,23 @@ def _draw_c4_component(ax3: Axes) -> None:
"""Draw C4 Level 3: Component."""
ax3.add_patch(
plt.Rectangle(
- (5, 15), 90, 58, lw=1.5,
- edgecolor=LN, facecolor="none",
+ (5, 15),
+ 90,
+ 58,
+ lw=1.5,
+ edgecolor=LN,
+ facecolor="none",
linestyle="--",
)
)
ax3.text(
- 50, 75, "API Server (Node.js)",
- ha="center", fontsize=8,
- fontweight="bold", fontstyle="italic",
+ 50,
+ 75,
+ "API Server (Node.js)",
+ ha="center",
+ fontsize=8,
+ fontweight="bold",
+ fontstyle="italic",
)
components = [
@@ -169,9 +228,17 @@ def _draw_c4_component(ax3: Axes) -> None:
]
for label, x, y, w, h, fill in components:
draw_box(
- ax3, x, y, w, h, label,
- fill=fill, lw=1.5, fontsize=6.5,
- fontweight="bold", rounded=True,
+ ax3,
+ x,
+ y,
+ w,
+ h,
+ label,
+ fill=fill,
+ lw=1.5,
+ fontsize=6.5,
+ fontweight="bold",
+ rounded=True,
)
draw_arrow(ax3, 32, 55, 40, 55)
@@ -180,10 +247,12 @@ def _draw_c4_component(ax3: Axes) -> None:
draw_arrow(ax3, 51, 50, 62, 35)
ax3.text(
- 50, 8,
- "Jakie modu\u0142y/komponenty\n"
- "wewn\u0105trz kontenera?",
- ha="center", fontsize=7, fontstyle="italic",
+ 50,
+ 8,
+ "Jakie modu\u0142y/komponenty\n" "wewn\u0105trz kontenera?",
+ ha="center",
+ fontsize=7,
+ fontstyle="italic",
bbox={
"boxstyle": "round",
"facecolor": GRAY4,
@@ -196,25 +265,34 @@ def _draw_c4_component(ax3: Axes) -> None:
def _draw_c4_code(ax4: Axes) -> None:
"""Draw C4 Level 4: Code (UML)."""
_draw_class(
- ax4, 5, 40,
+ ax4,
+ 5,
+ 40,
"\u00abinterface\u00bb\nIOrderRepository",
[],
["+save(order)", "+findById(id)"],
- w=32, fill=GRAY4,
+ w=32,
+ fill=GRAY4,
)
_draw_class(
- ax4, 55, 40,
+ ax4,
+ 55,
+ 40,
"OrderRepository",
["-db: Database"],
["+save(order)", "+findById(id)"],
- w=32, fill=GRAY1,
+ w=32,
+ fill=GRAY1,
)
_draw_class(
- ax4, 30, 10,
+ ax4,
+ 30,
+ 10,
"Order",
["-id: UUID", "-items: List", "-total: Money"],
["+addItem(item)", "+calculateTotal()"],
- w=32, fill=GRAY2,
+ w=32,
+ fill=GRAY2,
)
ax4.annotate(
@@ -229,18 +307,24 @@ def _draw_c4_code(ax4: Axes) -> None:
},
)
ax4.text(
- 46, 52, "\u00abimplements\u00bb",
- fontsize=6, ha="center", fontstyle="italic",
+ 46,
+ 52,
+ "\u00abimplements\u00bb",
+ fontsize=6,
+ ha="center",
+ fontstyle="italic",
)
draw_arrow(ax4, 71, 40, 50, 24)
ax4.text(64, 32, "uses", fontsize=6, fontstyle="italic")
ax4.text(
- 50, 3,
- "Diagramy klas UML\n"
- "(opcjonalny poziom szczeg\u00f3\u0142owo\u015bci)",
- ha="center", fontsize=7, fontstyle="italic",
+ 50,
+ 3,
+ "Diagramy klas UML\n" "(opcjonalny poziom szczeg\u00f3\u0142owo\u015bci)",
+ ha="center",
+ fontsize=7,
+ fontstyle="italic",
bbox={
"boxstyle": "round",
"facecolor": GRAY4,
@@ -274,8 +358,10 @@ def generate_c4() -> None:
ax_item.set_aspect("equal")
ax_item.axis("off")
ax_item.set_title(
- titles[idx], fontsize=10,
- fontweight="bold", pad=8,
+ titles[idx],
+ fontsize=10,
+ fontweight="bold",
+ pad=8,
)
_draw_c4_system_context(axes[0, 0])
diff --git a/python_pkg/praca_magisterska_video/generate_images/_automata_fa.py b/python_pkg/praca_magisterska_video/generate_images/_automata_fa.py
index e7fee79..127a4c0 100644
--- a/python_pkg/praca_magisterska_video/generate_images/_automata_fa.py
+++ b/python_pkg/praca_magisterska_video/generate_images/_automata_fa.py
@@ -46,8 +46,7 @@ def draw_fa_recognition() -> None:
ax.set_aspect("equal")
ax.axis("off")
ax.set_title(
- "DFA — diagram stanów\n"
- 'L = {słowa nad {a,b} kończące się na "ab"}',
+ "DFA — diagram stanów\n" 'L = {słowa nad {a,b} kończące się na "ab"}',
fontsize=FS_TITLE,
fontweight="bold",
pad=10,
@@ -73,9 +72,7 @@ def draw_fa_recognition() -> None:
states["q₂"],
state_r,
"q₂",
- StateStyle(
- accepting=True, fillcolor=LIGHT_GREEN
- ),
+ StateStyle(accepting=True, fillcolor=LIGHT_GREEN),
)
# Transitions
diff --git a/python_pkg/praca_magisterska_video/generate_images/_automata_lba.py b/python_pkg/praca_magisterska_video/generate_images/_automata_lba.py
index ca7b80c..148db40 100644
--- a/python_pkg/praca_magisterska_video/generate_images/_automata_lba.py
+++ b/python_pkg/praca_magisterska_video/generate_images/_automata_lba.py
@@ -77,11 +77,7 @@ def draw_lba_recognition() -> None:
facecolor=fc,
)
ax.add_patch(rect)
- bold = (
- "bold"
- if sym in ("X", "Y", "Z")
- else "normal"
- )
+ bold = "bold" if sym in ("X", "Y", "Z") else "normal"
ax.text(
x + cell_w / 2,
tape_y + cell_h / 2,
@@ -93,11 +89,7 @@ def draw_lba_recognition() -> None:
family="monospace",
)
if head_pos is not None:
- hx = (
- tape_x0
- + head_pos * cell_w
- + cell_w / 2
- )
+ hx = tape_x0 + head_pos * cell_w + cell_w / 2
ax.annotate(
"▼",
xy=(hx, tape_y + cell_h),
@@ -140,9 +132,7 @@ def draw_lba_recognition() -> None:
],
0,
"Początek",
- step_label=(
- "taśma = [a, a, b, b, c, c], głowica na 0"
- ),
+ step_label=("taśma = [a, a, b, b, c, c], głowica na 0"),
)
# Row 2: After marking first 'a'
@@ -265,8 +255,7 @@ def draw_lba_recognition() -> None:
ax.text(
tape_x0 + 3 * cell_w,
tape_y + 0.3,
- "Wszystko zaznaczone → q_acc"
- ' → "aabbcc" AKCEPTOWANE ✓',
+ "Wszystko zaznaczone → q_acc" ' → "aabbcc" AKCEPTOWANE ✓',
ha="center",
va="center",
fontsize=FS + 1,
@@ -282,9 +271,7 @@ def draw_lba_recognition() -> None:
ax.text(
tape_x0 + 6 * cell_w + 0.5,
tape_y + 0.3,
- "Ograniczenie LBA:\n"
- "głowica ≤ 6 komórek\n"
- '(= |w| = |"aabbcc"|)',
+ "Ograniczenie LBA:\n" "głowica ≤ 6 komórek\n" '(= |w| = |"aabbcc"|)',
ha="left",
va="center",
fontsize=FS_SMALL,
diff --git a/python_pkg/praca_magisterska_video/generate_images/_automata_pda.py b/python_pkg/praca_magisterska_video/generate_images/_automata_pda.py
index c92fbfc..be11bbe 100644
--- a/python_pkg/praca_magisterska_video/generate_images/_automata_pda.py
+++ b/python_pkg/praca_magisterska_video/generate_images/_automata_pda.py
@@ -74,9 +74,7 @@ def draw_pda_recognition() -> None:
states["q₂"],
state_r,
"q₂",
- StateStyle(
- accepting=True, fillcolor=LIGHT_GREEN
- ),
+ StateStyle(accepting=True, fillcolor=LIGHT_GREEN),
)
# q₀ --b,A/ε--> q₁
@@ -140,8 +138,7 @@ def draw_pda_recognition() -> None:
ax2 = axes[1]
ax2.axis("off")
ax2.set_title(
- "Ślad wykonania z wizualizacją stosu"
- ' — wejście: "aabb"',
+ "Ślad wykonania z wizualizacją stosu" ' — wejście: "aabb"',
fontsize=FS_TITLE,
fontweight="bold",
pad=10,
diff --git a/python_pkg/praca_magisterska_video/generate_images/_automata_tm.py b/python_pkg/praca_magisterska_video/generate_images/_automata_tm.py
index 823dc11..abd000a 100644
--- a/python_pkg/praca_magisterska_video/generate_images/_automata_tm.py
+++ b/python_pkg/praca_magisterska_video/generate_images/_automata_tm.py
@@ -83,9 +83,7 @@ def draw_tm_recognition() -> None:
linestyle=ls,
)
ax.add_patch(rect)
- bold = (
- "bold" if sym in ("X", "Y") else "normal"
- )
+ bold = "bold" if sym in ("X", "Y") else "normal"
clr = GRAY3 if sym == "⊔" else LN
ax.text(
x + cell_w / 2,
@@ -109,11 +107,7 @@ def draw_tm_recognition() -> None:
color=GRAY3,
)
if head_pos is not None:
- hx = (
- tape_x0
- + head_pos * cell_w
- + cell_w / 2
- )
+ hx = tape_x0 + head_pos * cell_w + cell_w / 2
ax.annotate(
"▼",
xy=(hx, tape_y + cell_h),
@@ -144,25 +138,96 @@ def draw_tm_recognition() -> None:
bl = "#F0F0F0" # blank cell
tape_rows = [
- (9.0, [("0", white), ("0", white), ("1", white),
- ("1", white), ("⊔", bl), ("⊔", bl), ("⊔", bl)],
- 0, "Początek", "taśma = [0,0,1,1,⊔,⊔,...∞]"),
- (7.8, [("X", mk), ("0", white), ("1", white),
- ("1", white), ("⊔", bl), ("⊔", bl), ("⊔", bl)],
- 1, "R1, krok 1", "zaznacz 0→X, idź w prawo"),
- (6.6, [("X", mk), ("0", white), ("Y", mk),
- ("1", white), ("⊔", bl), ("⊔", bl), ("⊔", bl)],
- 0, "R1, krok 2", "zaznacz 1→Y, wróć na początek"),
- (4.8, [("X", mk), ("X", mk), ("Y", mk),
- ("1", white), ("⊔", bl), ("⊔", bl), ("⊔", bl)],
- 2, "R2, krok 1", "pomiń X, zaznacz 0→X"),
- (3.6, [("X", mk), ("X", mk), ("Y", mk),
- ("Y", mk), ("⊔", bl), ("⊔", bl), ("⊔", bl)],
- 0, "R2, krok 2", "pomiń Y, zaznacz 1→Y, wróć"),
- (2.4, [("X", mk), ("X", mk), ("Y", mk),
- ("Y", mk), ("⊔", bl), ("⊔", bl), ("⊔", bl)],
- None, "Sprawdzenie",
- "brak niezaznaczonych → q_acc"),
+ (
+ 9.0,
+ [
+ ("0", white),
+ ("0", white),
+ ("1", white),
+ ("1", white),
+ ("⊔", bl),
+ ("⊔", bl),
+ ("⊔", bl),
+ ],
+ 0,
+ "Początek",
+ "taśma = [0,0,1,1,⊔,⊔,...∞]",
+ ),
+ (
+ 7.8,
+ [
+ ("X", mk),
+ ("0", white),
+ ("1", white),
+ ("1", white),
+ ("⊔", bl),
+ ("⊔", bl),
+ ("⊔", bl),
+ ],
+ 1,
+ "R1, krok 1",
+ "zaznacz 0→X, idź w prawo",
+ ),
+ (
+ 6.6,
+ [
+ ("X", mk),
+ ("0", white),
+ ("Y", mk),
+ ("1", white),
+ ("⊔", bl),
+ ("⊔", bl),
+ ("⊔", bl),
+ ],
+ 0,
+ "R1, krok 2",
+ "zaznacz 1→Y, wróć na początek",
+ ),
+ (
+ 4.8,
+ [
+ ("X", mk),
+ ("X", mk),
+ ("Y", mk),
+ ("1", white),
+ ("⊔", bl),
+ ("⊔", bl),
+ ("⊔", bl),
+ ],
+ 2,
+ "R2, krok 1",
+ "pomiń X, zaznacz 0→X",
+ ),
+ (
+ 3.6,
+ [
+ ("X", mk),
+ ("X", mk),
+ ("Y", mk),
+ ("Y", mk),
+ ("⊔", bl),
+ ("⊔", bl),
+ ("⊔", bl),
+ ],
+ 0,
+ "R2, krok 2",
+ "pomiń Y, zaznacz 1→Y, wróć",
+ ),
+ (
+ 2.4,
+ [
+ ("X", mk),
+ ("X", mk),
+ ("Y", mk),
+ ("Y", mk),
+ ("⊔", bl),
+ ("⊔", bl),
+ ("⊔", bl),
+ ],
+ None,
+ "Sprawdzenie",
+ "brak niezaznaczonych → q_acc",
+ ),
]
# Runda 2 header
@@ -178,9 +243,7 @@ def draw_tm_recognition() -> None:
)
for row_y, cells, head, lbl, step in tape_rows:
- draw_tape(
- row_y, cells, head, lbl, step_label=step
- )
+ draw_tape(row_y, cells, head, lbl, step_label=step)
# Result + TM vs LBA comparison
tape_y = 0.8
diff --git a/python_pkg/praca_magisterska_video/generate_images/_bf_negative_diagrams.py b/python_pkg/praca_magisterska_video/generate_images/_bf_negative_diagrams.py
index 96c2374..1cd18c0 100644
--- a/python_pkg/praca_magisterska_video/generate_images/_bf_negative_diagrams.py
+++ b/python_pkg/praca_magisterska_video/generate_images/_bf_negative_diagrams.py
@@ -32,7 +32,6 @@ from python_pkg.praca_magisterska_video.generate_images.generate_bf_negative_dia
_logger = logging.getLogger(__name__)
-
def _add_annotation_box(
ax: Axes,
x: float,
@@ -83,10 +82,7 @@ def generate_bf_negative_weights() -> None:
draw_neg_graph(
ax1,
NEG_EDGES,
- title=(
- "Graf z ujemną wagą\n"
- "(B→A = -4, zaznaczona na czerwono)"
- ),
+ title=("Graf z ujemną wagą\n" "(B→A = -4, zaznaczona na czerwono)"),
dist={"S": "0", "A": "?", "B": "?", "C": "?"},
)
ax1.annotate(
@@ -110,8 +106,7 @@ def generate_bf_negative_weights() -> None:
ax2,
NEG_EDGES,
title=(
- "Dijkstra \u2014 BŁĘDNY wynik\n"
- "A zamknięty z d=2, nie poprawia przy B→A"
+ "Dijkstra \u2014 BŁĘDNY wynik\n" "A zamknięty z d=2, nie poprawia przy B→A"
),
dist={"S": "0", "A": "2", "B": "5", "C": "5"},
visited={"S", "A", "B", "C"},
@@ -167,16 +162,18 @@ def generate_bf_negative_weights() -> None:
# Row 2: B-F iterations step by step
iterations = [
{
- "title": (
- "B-F Iteracja 1\n"
- "Relaksuj WSZYSTKIE krawędzie"
- ),
+ "title": ("B-F Iteracja 1\n" "Relaksuj WSZYSTKIE krawędzie"),
"dist": {
- "S": "0", "A": "1", "B": "5", "C": "5",
+ "S": "0",
+ "A": "1",
+ "B": "5",
+ "C": "5",
},
"relaxed": {
- ("S", "A"), ("A", "C"),
- ("S", "B"), ("B", "A"),
+ ("S", "A"),
+ ("A", "C"),
+ ("S", "B"),
+ ("B", "A"),
},
"detail": (
"S→A: 0+2=2<∞ → A=2\n"
@@ -186,12 +183,12 @@ def generate_bf_negative_weights() -> None:
),
},
{
- "title": (
- "B-F Iteracja 2\n"
- "Propagacja poprawionego A"
- ),
+ "title": ("B-F Iteracja 2\n" "Propagacja poprawionego A"),
"dist": {
- "S": "0", "A": "1", "B": "5", "C": "4",
+ "S": "0",
+ "A": "1",
+ "B": "5",
+ "C": "4",
},
"relaxed": {("A", "C")},
"detail": (
@@ -202,12 +199,12 @@ def generate_bf_negative_weights() -> None:
),
},
{
- "title": (
- "B-F Iteracja 3\n"
- "Brak zmian → stabilne!"
- ),
+ "title": ("B-F Iteracja 3\n" "Brak zmian → stabilne!"),
"dist": {
- "S": "0", "A": "1", "B": "5", "C": "4",
+ "S": "0",
+ "A": "1",
+ "B": "5",
+ "C": "4",
},
"relaxed": set(),
"detail": (
@@ -296,10 +293,7 @@ def generate_bf_negative_cycle() -> None:
draw_neg_graph(
ax1,
NEG_EDGES,
- title=(
- "Graf z cyklem ujemnym\n"
- "Dodana krawędź C→B(-3) \u2014 przerywana"
- ),
+ title=("Graf z cyklem ujemnym\n" "Dodana krawędź C→B(-3) \u2014 przerywana"),
dist={"S": "0", "A": "?", "B": "?", "C": "?"},
extra_edges=[("C", "B", -3)],
)
@@ -324,10 +318,7 @@ def generate_bf_negative_cycle() -> None:
draw_neg_graph(
ax2,
NEG_EDGES,
- title=(
- "Po V-1=3 iteracjach\n"
- "dist wciąż maleje (niestabilne!)"
- ),
+ title=("Po V-1=3 iteracjach\n" "dist wciąż maleje (niestabilne!)"),
dist={"S": "0", "A": "-7", "B": "-4", "C": "-4"},
visited={"S", "A", "B", "C"},
error_nodes={"A", "B", "C"},
@@ -336,9 +327,7 @@ def generate_bf_negative_cycle() -> None:
ax2.text(
3.2,
-0.4,
- "Każde okrążenie cyklu\n"
- "zmniejsza dist o 4.\n"
- "Dist → -∞ (brak minimum!)",
+ "Każde okrążenie cyklu\n" "zmniejsza dist o 4.\n" "Dist → -∞ (brak minimum!)",
ha="center",
va="top",
fontsize=FS_SMALL,
@@ -423,5 +412,3 @@ def generate_bf_negative_cycle() -> None:
)
plt.close()
_logger.info(" ✓ bellman_ford_negative_cycle.png")
-
-
diff --git a/python_pkg/praca_magisterska_video/generate_images/_pattern_navigation.py b/python_pkg/praca_magisterska_video/generate_images/_pattern_navigation.py
index 1bce7ee..c354b07 100644
--- a/python_pkg/praca_magisterska_video/generate_images/_pattern_navigation.py
+++ b/python_pkg/praca_magisterska_video/generate_images/_pattern_navigation.py
@@ -21,6 +21,7 @@ from python_pkg.praca_magisterska_video.generate_images.generate_pattern_diagram
_logger = logging.getLogger(__name__)
+
# ============================================================
# 5. Pattern Language Navigation Graph
# ============================================================
@@ -45,24 +46,32 @@ def generate_pattern_language_navigation() -> None:
nodes = [
(1.5, 10.5, "Monolith\nnie skaluje się", False, "white"),
(
- 1.5, 8.2,
+ 1.5,
+ 8.2,
"Jak routować\nżądania do\nserwisów?",
- False, "white",
+ False,
+ "white",
),
(
- 1.5, 5.9,
+ 1.5,
+ 5.9,
"Co gdy serwis\nnie odpowiada?",
- False, "white",
+ False,
+ "white",
),
(
- 1.5, 3.6,
+ 1.5,
+ 3.6,
"Jak zachować\nspójność\ntransakcji?",
- False, "white",
+ False,
+ "white",
),
(
- 1.5, 1.3,
+ 1.5,
+ 1.3,
"Jak odnaleźć\nadres serwisu?",
- False, "white",
+ False,
+ "white",
),
(7.0, 9.3, "Microservices", True, GRAY2),
(7.0, 7.0, "API Gateway", True, GRAY2),
@@ -179,8 +188,12 @@ def generate_pattern_language_navigation() -> None:
)
ax.add_patch(r1)
ax.text(
- 1.75, legend_y, "Problem",
- ha="center", va="center", fontsize=7,
+ 1.75,
+ legend_y,
+ "Problem",
+ ha="center",
+ va="center",
+ fontsize=7,
)
r2 = FancyBboxPatch(
(3.5, legend_y - 0.2),
@@ -213,9 +226,7 @@ def generate_pattern_language_navigation() -> None:
)
fig.tight_layout()
- out = str(
- Path(OUTPUT_DIR) / "q14_pattern_language_navigation.png"
- )
+ out = str(Path(OUTPUT_DIR) / "q14_pattern_language_navigation.png")
fig.savefig(out, dpi=DPI, bbox_inches="tight", facecolor=BG)
plt.close(fig)
_logger.info(" Saved: %s", out)
diff --git a/python_pkg/praca_magisterska_video/generate_images/_pattern_pillars_observer.py b/python_pkg/praca_magisterska_video/generate_images/_pattern_pillars_observer.py
index a1efb8b..7e78216 100644
--- a/python_pkg/praca_magisterska_video/generate_images/_pattern_pillars_observer.py
+++ b/python_pkg/praca_magisterska_video/generate_images/_pattern_pillars_observer.py
@@ -27,6 +27,7 @@ from python_pkg.praca_magisterska_video.generate_images.generate_pattern_diagram
_logger = logging.getLogger(__name__)
+
# ============================================================
# 3. Three Pillars of Cataloguing
# ============================================================
@@ -91,8 +92,7 @@ def generate_three_pillars() -> None:
"Wzorce referują się\nwzajemnie tworząc\n"
"sieć/graf:\nA → wymaga → B\n"
"B → wariant → C",
- "Analogia:\n\u201ezobacz te\u017c\u201d\n"
- "w encyklopedii",
+ "Analogia:\n\u201ezobacz te\u017c\u201d\n" "w encyklopedii",
),
]
@@ -258,14 +258,10 @@ def generate_observer_card_filled() -> None:
band_w = card_w - 0.6
start_y = card_y + card_h - 0.65
- for i, (abbr, title, content, fill, is_title_field) in enumerate(
- fields
- ):
+ for i, (abbr, title, content, fill, is_title_field) in enumerate(fields):
band_h = _get_observer_band_height(i)
- by = start_y - sum(
- _get_observer_band_height(j) + 0.15 for j in range(i)
- )
+ by = start_y - sum(_get_observer_band_height(j) + 0.15 for j in range(i))
# Abbreviation circle
circle = plt.Circle(
diff --git a/python_pkg/praca_magisterska_video/generate_images/_pattern_template_catalog.py b/python_pkg/praca_magisterska_video/generate_images/_pattern_template_catalog.py
index b435167..3c336d5 100644
--- a/python_pkg/praca_magisterska_video/generate_images/_pattern_template_catalog.py
+++ b/python_pkg/praca_magisterska_video/generate_images/_pattern_template_catalog.py
@@ -26,6 +26,7 @@ from python_pkg.praca_magisterska_video.generate_images.generate_pattern_diagram
_logger = logging.getLogger(__name__)
+
def generate_pattern_template() -> None:
"""Generate pattern template diagram with NaPSiRoKo mnemonic."""
fig, ax = plt.subplots(figsize=(8.27, 6))
@@ -77,8 +78,7 @@ def generate_pattern_template() -> None:
(
"Si",
"SIŁY (forces)",
- "Konkurencyjne wymagania do pogodzenia\n"
- "(np. testowalność vs wydajność)",
+ "Konkurencyjne wymagania do pogodzenia\n" "(np. testowalność vs wydajność)",
GRAY1,
),
("Ro", "ROZWIĄZANIE", "Struktura, diagram, zachowanie", "white"),
@@ -245,9 +245,7 @@ def generate_catalog_map() -> None:
va="center",
fontstyle="italic",
)
- ax.plot(
- [0.15, 0.45], [sy, sy], color=GRAY3, lw=0.8, ls="--"
- )
+ ax.plot([0.15, 0.45], [sy, sy], color=GRAY3, lw=0.8, ls="--")
# X-axis: Domain
ax.text(
@@ -274,8 +272,7 @@ def generate_catalog_map() -> None:
2.5,
1.4,
"POSA",
- "1996 • Buschmann\nLayers, Broker,\n"
- "Pipes & Filters, MVC",
+ "1996 • Buschmann\nLayers, Broker,\n" "Pipes & Filters, MVC",
GRAY1,
"P",
),
@@ -285,8 +282,7 @@ def generate_catalog_map() -> None:
2.5,
1.4,
"GoF",
- "1994 • Gamma et al.\n23 wzorce:\n"
- "5 kreac. / 7 strukt. / 11 behaw.",
+ "1994 • Gamma et al.\n23 wzorce:\n" "5 kreac. / 7 strukt. / 11 behaw.",
GRAY2,
"G",
),
@@ -296,8 +292,7 @@ def generate_catalog_map() -> None:
2.5,
1.4,
"EIP",
- "2003 • Hohpe & Woolf\nMessage Channel,\n"
- "Router, Aggregator",
+ "2003 • Hohpe & Woolf\nMessage Channel,\n" "Router, Aggregator",
GRAY1,
"E",
),
@@ -307,8 +302,7 @@ def generate_catalog_map() -> None:
2.5,
1.4,
"PoEAA",
- "2002 • M. Fowler\nRepository,"
- " Unit of Work,\nDomain Model",
+ "2002 • M. Fowler\nRepository," " Unit of Work,\nDomain Model",
"white",
"P",
),
@@ -318,8 +312,7 @@ def generate_catalog_map() -> None:
2.8,
1.4,
"Cloud\nPatterns",
- "~2015 • Azure/AWS\nCircuit Breaker,\n"
- "Saga, Sidecar",
+ "~2015 • Azure/AWS\nCircuit Breaker,\n" "Saga, Sidecar",
GRAY1,
"C",
),
diff --git a/python_pkg/praca_magisterska_video/generate_images/_process_bpmn_uml.py b/python_pkg/praca_magisterska_video/generate_images/_process_bpmn_uml.py
index 46cf104..2b9e61a 100644
--- a/python_pkg/praca_magisterska_video/generate_images/_process_bpmn_uml.py
+++ b/python_pkg/praca_magisterska_video/generate_images/_process_bpmn_uml.py
@@ -130,11 +130,19 @@ def _draw_bpmn_elements(
sx = content_left + 4
ax.add_patch(
plt.Circle(
- (sx, y_bok), 2, lw=2, edgecolor=LINE_COLOR, facecolor="white",
+ (sx, y_bok),
+ 2,
+ lw=2,
+ edgecolor=LINE_COLOR,
+ facecolor="white",
)
)
ax.text(
- sx, y_bok - 3.5, "Reklamacja\nwp\u0142ywa", fontsize=6, ha="center",
+ sx,
+ y_bok - 3.5,
+ "Reklamacja\nwp\u0142ywa",
+ fontsize=6,
+ ha="center",
)
t1x = sx + 14
@@ -143,7 +151,12 @@ def _draw_bpmn_elements(
t2x = t1x + 18
draw_rounded_rect(
- ax, t2x, y_jak, 14, 6, "Zweryfikuj\nzasadno\u015b\u0107",
+ ax,
+ t2x,
+ y_jak,
+ 14,
+ 6,
+ "Zweryfikuj\nzasadno\u015b\u0107",
)
elbow_x = t1x + 10
draw_line(ax, t1x + 7, y_bok, elbow_x, y_bok)
@@ -156,7 +169,12 @@ def _draw_bpmn_elements(
t3x = gx + 14
draw_rounded_rect(
- ax, t3x, y_mag, 14, 6, "Przygotuj\nwymian\u0119/zwrot",
+ ax,
+ t3x,
+ y_mag,
+ 14,
+ 6,
+ "Przygotuj\nwymian\u0119/zwrot",
)
draw_line(ax, gx, y_jak - 3.5, gx, y_mag)
draw_arrow(ax, gx, y_mag, t3x - 7, y_mag)
@@ -164,7 +182,12 @@ def _draw_bpmn_elements(
t4x = gx + 14
draw_rounded_rect(
- ax, t4x, y_jak, 14, 6, "Odrzu\u0107\nreklamacj\u0119",
+ ax,
+ t4x,
+ y_jak,
+ 14,
+ 6,
+ "Odrzu\u0107\nreklamacj\u0119",
)
draw_arrow(ax, gx + 3.5, y_jak, t4x - 7, y_jak)
ax.text(gx + 4, y_jak + 2, "Nie", fontsize=7, ha="left")
@@ -184,7 +207,11 @@ def _draw_bpmn_elements(
ex = t5x + 12
ax.add_patch(
plt.Circle(
- (ex, y_bok), 2, lw=3, edgecolor=LINE_COLOR, facecolor="white",
+ (ex, y_bok),
+ 2,
+ lw=3,
+ edgecolor=LINE_COLOR,
+ facecolor="white",
)
)
draw_arrow(ax, t5x + 7, y_bok, ex - 2, y_bok)
@@ -195,17 +222,30 @@ def _draw_bpmn_legend(ax: Axes) -> None:
"""Draw BPMN legend."""
ly = 1
ax.text(
- 12, ly, "Legenda:", fontsize=7, fontweight="bold", va="center",
+ 12,
+ ly,
+ "Legenda:",
+ fontsize=7,
+ fontweight="bold",
+ va="center",
)
ax.add_patch(
plt.Circle(
- (22, ly), 1, lw=2, edgecolor=LINE_COLOR, facecolor="white",
+ (22, ly),
+ 1,
+ lw=2,
+ edgecolor=LINE_COLOR,
+ facecolor="white",
)
)
ax.text(24, ly, "Start", fontsize=6, va="center")
ax.add_patch(
plt.Circle(
- (30, ly), 1, lw=3, edgecolor=LINE_COLOR, facecolor="white",
+ (30, ly),
+ 1,
+ lw=3,
+ edgecolor=LINE_COLOR,
+ facecolor="white",
)
)
ax.text(32, ly, "Koniec", fontsize=6, va="center")
@@ -262,13 +302,23 @@ def _draw_uml_elements(ax: Axes) -> None:
y -= step
draw_rounded_rect(
- ax, cx, y, 28, 6, "Przyjmij zg\u0142oszenie reklamacji",
+ ax,
+ cx,
+ y,
+ 28,
+ 6,
+ "Przyjmij zg\u0142oszenie reklamacji",
)
draw_arrow(ax, cx, y + step - 1.8, cx, y + 3)
y -= step
draw_rounded_rect(
- ax, cx, y, 28, 6, "Zweryfikuj zasadno\u015b\u0107",
+ ax,
+ cx,
+ y,
+ 28,
+ 6,
+ "Zweryfikuj zasadno\u015b\u0107",
)
draw_arrow(ax, cx, y + step - 3, cx, y + 3)
@@ -276,7 +326,11 @@ def _draw_uml_elements(ax: Axes) -> None:
draw_diamond(ax, cx, y, 4)
draw_arrow(ax, cx, y + step - 3, cx, y + 4)
ax.text(
- cx + 6, y + 5, "[zasadna?]", fontsize=8, fontstyle="italic",
+ cx + 6,
+ y + 5,
+ "[zasadna?]",
+ fontsize=8,
+ fontstyle="italic",
)
dec_y = y
@@ -284,24 +338,40 @@ def _draw_uml_elements(ax: Axes) -> None:
left_x = cx - 24
draw_rounded_rect(
- ax, left_x, branch_y, 22, 6, "Przygotuj\nwymian\u0119/zwrot",
+ ax,
+ left_x,
+ branch_y,
+ 22,
+ 6,
+ "Przygotuj\nwymian\u0119/zwrot",
)
draw_line(ax, cx - 4, dec_y, left_x, dec_y)
draw_arrow(ax, left_x, dec_y, left_x, branch_y + 3)
ax.text(
- left_x + 2, dec_y + 1.5, "[tak]",
- fontsize=8, fontstyle="italic",
+ left_x + 2,
+ dec_y + 1.5,
+ "[tak]",
+ fontsize=8,
+ fontstyle="italic",
)
right_x = cx + 24
draw_rounded_rect(
- ax, right_x, branch_y, 22, 6, "Odrzu\u0107\nreklamacj\u0119",
+ ax,
+ right_x,
+ branch_y,
+ 22,
+ 6,
+ "Odrzu\u0107\nreklamacj\u0119",
)
draw_line(ax, cx + 4, dec_y, right_x, dec_y)
draw_arrow(ax, right_x, dec_y, right_x, branch_y + 3)
ax.text(
- right_x - 12, dec_y + 1.5, "[nie]",
- fontsize=8, fontstyle="italic",
+ right_x - 12,
+ dec_y + 1.5,
+ "[nie]",
+ fontsize=8,
+ fontstyle="italic",
)
merge_y = branch_y - step
@@ -318,7 +388,11 @@ def _draw_uml_elements(ax: Axes) -> None:
ey = y - step
ax.add_patch(
plt.Circle(
- (cx, ey), 2.5, lw=2, facecolor="white", edgecolor="black",
+ (cx, ey),
+ 2.5,
+ lw=2,
+ facecolor="white",
+ edgecolor="black",
)
)
ax.add_patch(
@@ -336,7 +410,11 @@ def _draw_uml_legend(ax: Axes) -> None:
ax.text(15, ly, "= Pocz\u0105tek", fontsize=7, va="center")
ax.add_patch(
plt.Circle(
- (32, ly), 1.3, lw=2, facecolor="white", edgecolor="black",
+ (32, ly),
+ 1.3,
+ lw=2,
+ facecolor="white",
+ edgecolor="black",
)
)
ax.add_patch(
diff --git a/python_pkg/praca_magisterska_video/generate_images/_process_epc_fc.py b/python_pkg/praca_magisterska_video/generate_images/_process_epc_fc.py
index c62cf33..ae9fbe0 100644
--- a/python_pkg/praca_magisterska_video/generate_images/_process_epc_fc.py
+++ b/python_pkg/praca_magisterska_video/generate_images/_process_epc_fc.py
@@ -1,4 +1,4 @@
-"""EPC and flowchart diagram generators."""
+"""EPC diagram generator."""
from __future__ import annotations
@@ -6,9 +6,7 @@ import logging
from pathlib import Path
from typing import TYPE_CHECKING
-import matplotlib.patches as mpatches
from matplotlib.patches import FancyBboxPatch
-from matplotlib.path import Path as MplPath
import matplotlib.pyplot as plt
if TYPE_CHECKING:
@@ -17,26 +15,26 @@ if TYPE_CHECKING:
from python_pkg.praca_magisterska_video.generate_images.generate_process_diagrams import (
BG_COLOR,
DPI,
- FONT_SIZE,
LINE_COLOR,
OUTPUT_DIR,
TITLE_SIZE,
draw_arrow,
- draw_diamond,
draw_line,
)
_logger = logging.getLogger(__name__)
-
# =========================================================================
# 3. EPC (Event-driven Process Chain)
# =========================================================================
def _draw_epc_event(
- ax: Axes, x: float, y: float, text: str,
+ ax: Axes,
+ x: float,
+ y: float,
+ text: str,
) -> None:
"""Draw an EPC event shape (rounded grey box)."""
w, h = 26, 5.5
@@ -54,7 +52,10 @@ def _draw_epc_event(
def _draw_epc_function(
- ax: Axes, x: float, y: float, text: str,
+ ax: Axes,
+ x: float,
+ y: float,
+ text: str,
) -> None:
"""Draw an EPC function shape (rounded white box, bold)."""
w, h = 26, 5.5
@@ -69,22 +70,39 @@ def _draw_epc_function(
)
ax.add_patch(rect)
ax.text(
- x, y, text,
- ha="center", va="center", fontsize=8, fontweight="bold",
+ x,
+ y,
+ text,
+ ha="center",
+ va="center",
+ fontsize=8,
+ fontweight="bold",
)
def _draw_epc_connector(
- ax: Axes, x: float, y: float, text: str,
+ ax: Axes,
+ x: float,
+ y: float,
+ text: str,
) -> None:
"""Draw an EPC logical connector (circle)."""
circle = plt.Circle(
- (x, y), 2.8, lw=1.5, edgecolor=LINE_COLOR, facecolor="white",
+ (x, y),
+ 2.8,
+ lw=1.5,
+ edgecolor=LINE_COLOR,
+ facecolor="white",
)
ax.add_patch(circle)
ax.text(
- x, y, text,
- ha="center", va="center", fontsize=9, fontweight="bold",
+ x,
+ y,
+ text,
+ ha="center",
+ va="center",
+ fontsize=9,
+ fontweight="bold",
)
@@ -138,7 +156,10 @@ def _draw_epc_branches(
by2 = by - step
_draw_epc_function(
- ax, left_x, by2, "Przygotuj wymian\u0119/zwrot",
+ ax,
+ left_x,
+ by2,
+ "Przygotuj wymian\u0119/zwrot",
)
draw_arrow(ax, left_x, by - 2.8, left_x, by2 + 2.8)
@@ -179,7 +200,11 @@ def _draw_epc_legend(ax: Axes) -> None:
_draw_epc_function(ax, 46, ly, "Funkcja")
_draw_epc_connector(ax, 68, ly, "XOR")
ax.text(
- 72, ly, "= \u0141\u0105cznik logiczny", fontsize=7, va="center",
+ 72,
+ ly,
+ "= \u0141\u0105cznik logiczny",
+ fontsize=7,
+ va="center",
)
@@ -192,8 +217,7 @@ def generate_epc() -> None:
ax.axis("off")
fig.patch.set_facecolor(BG_COLOR)
ax.set_title(
- "EPC (Event-driven Process Chain)"
- " \u2014 Obs\u0142uga reklamacji",
+ "EPC (Event-driven Process Chain)" " \u2014 Obs\u0142uga reklamacji",
fontsize=TITLE_SIZE,
fontweight="bold",
pad=12,
@@ -212,238 +236,3 @@ def generate_epc() -> None:
)
plt.close(fig)
_logger.info(" OK EPC saved")
-
-
-# =========================================================================
-# 4. Classic Flowchart
-# =========================================================================
-
-
-def _draw_fc_terminal(
- ax: Axes, x: float, y: float, text: str,
-) -> None:
- """Draw a flowchart terminal (rounded) shape."""
- w, h = 20, 5.5
- rect = FancyBboxPatch(
- (x - w / 2, y - h / 2),
- w,
- h,
- boxstyle="round,pad=1.0",
- lw=2,
- edgecolor=LINE_COLOR,
- facecolor="#E0E0E0",
- )
- ax.add_patch(rect)
- ax.text(
- x,
- y,
- text,
- ha="center",
- va="center",
- fontsize=FONT_SIZE,
- fontweight="bold",
- )
-
-
-def _draw_fc_process_box(
- ax: Axes, x: float, y: float, text: str,
-) -> None:
- """Draw a flowchart process box (rectangle)."""
- w, h = 26, 6
- rect = plt.Rectangle(
- (x - w / 2, y - h / 2),
- w,
- h,
- lw=1.5,
- edgecolor=LINE_COLOR,
- facecolor="white",
- )
- ax.add_patch(rect)
- ax.text(
- x, y, text, ha="center", va="center", fontsize=FONT_SIZE,
- )
-
-
-def _draw_fc_io_shape(
- ax: Axes, x: float, y: float, text: str,
-) -> None:
- """Draw a flowchart I/O parallelogram."""
- w, h = 26, 5.5
- skew = 3
- verts = [
- (x - w / 2 + skew, y + h / 2),
- (x + w / 2 + skew, y + h / 2),
- (x + w / 2 - skew, y - h / 2),
- (x - w / 2 - skew, y - h / 2),
- (x - w / 2 + skew, y + h / 2),
- ]
- codes = [
- MplPath.MOVETO,
- MplPath.LINETO,
- MplPath.LINETO,
- MplPath.LINETO,
- MplPath.CLOSEPOLY,
- ]
- patch = mpatches.PathPatch(
- MplPath(verts, codes),
- facecolor="white",
- edgecolor=LINE_COLOR,
- lw=1.5,
- )
- ax.add_patch(patch)
- ax.text(
- x, y, text, ha="center", va="center", fontsize=FONT_SIZE,
- )
-
-
-def _draw_fc_elements(ax: Axes) -> None:
- """Draw all flowchart elements."""
- cx = 50
- y = 103
- step = 11
-
- _draw_fc_terminal(ax, cx, y, "START")
-
- y -= step
- _draw_fc_io_shape(ax, cx, y, "Reklamacja od klienta")
- draw_arrow(ax, cx, y + step - 2.8, cx, y + 2.8)
-
- y -= step
- _draw_fc_process_box(ax, cx, y, "Przyjmij zg\u0142oszenie")
- draw_arrow(ax, cx, y + step - 2.8, cx, y + 3)
-
- y -= step
- _draw_fc_process_box(
- ax, cx, y, "Zweryfikuj zasadno\u015b\u0107",
- )
- draw_arrow(ax, cx, y + step - 3, cx, y + 3)
-
- y -= step
- draw_diamond(ax, cx, y, 4.5, "Zasadna?")
- draw_arrow(ax, cx, y + step - 3, cx, y + 4.5)
- dec_y = y
-
- left_x = cx - 26
- _draw_fc_process_box(
- ax, left_x, dec_y, "Przygotuj wymian\u0119/zwrot",
- )
- draw_line(ax, cx - 4.5, dec_y, left_x + 13, dec_y)
- ax.text(
- cx - 7, dec_y + 2, "Tak",
- fontsize=8, ha="center", fontweight="bold",
- )
-
- right_x = cx + 26
- _draw_fc_process_box(
- ax, right_x, dec_y, "Odrzu\u0107 reklamacj\u0119",
- )
- draw_line(ax, cx + 4.5, dec_y, right_x - 13, dec_y)
- ax.text(
- cx + 7, dec_y + 2, "Nie",
- fontsize=8, ha="center", fontweight="bold",
- )
-
- merge_y = dec_y - step
- draw_line(ax, left_x, dec_y - 3, left_x, merge_y)
- draw_line(ax, right_x, dec_y - 3, right_x, merge_y)
- draw_line(ax, left_x, merge_y, right_x, merge_y)
- ax.plot(cx, merge_y, "ko", markersize=4)
-
- y = merge_y - step + 3
- _draw_fc_process_box(ax, cx, y, "Powiadom klienta")
- draw_arrow(ax, cx, merge_y, cx, y + 3)
-
- y -= step
- _draw_fc_io_shape(
- ax, cx, y, "Odpowied\u017a do klienta",
- )
- draw_arrow(ax, cx, y + step - 3, cx, y + 2.8)
-
- y -= step
- _draw_fc_terminal(ax, cx, y, "KONIEC")
- draw_arrow(ax, cx, y + step - 2.8, cx, y + 2.8)
-
-
-def _draw_fc_legend(ax: Axes) -> None:
- """Draw flowchart legend."""
- ly = 4
- ax.text(
- 5, ly, "Legenda:", fontsize=7, fontweight="bold", va="center",
- )
- _draw_fc_terminal(ax, 18, ly, "")
- ax.text(
- 18, ly, "Start/\nKoniec",
- fontsize=5.5, ha="center", va="center",
- )
- w, h = 9, 3
- ax.add_patch(
- plt.Rectangle(
- (32 - w / 2, ly - h / 2),
- w,
- h,
- lw=1.5,
- edgecolor=LINE_COLOR,
- facecolor="white",
- )
- )
- ax.text(32, ly, "Proces", fontsize=6, ha="center", va="center")
- draw_diamond(ax, 46, ly, 2)
- ax.text(49.5, ly, "= Decyzja", fontsize=6, va="center")
- skew = 1.5
- w2, h2 = 9, 3
- verts = [
- (62 - w2 / 2 + skew, ly + h2 / 2),
- (62 + w2 / 2 + skew, ly + h2 / 2),
- (62 + w2 / 2 - skew, ly - h2 / 2),
- (62 - w2 / 2 - skew, ly - h2 / 2),
- (62 - w2 / 2 + skew, ly + h2 / 2),
- ]
- codes = [
- MplPath.MOVETO,
- MplPath.LINETO,
- MplPath.LINETO,
- MplPath.LINETO,
- MplPath.CLOSEPOLY,
- ]
- ax.add_patch(
- mpatches.PathPatch(
- MplPath(verts, codes),
- facecolor="white",
- edgecolor=LINE_COLOR,
- lw=1.2,
- )
- )
- ax.text(62, ly, "We/Wy", fontsize=6, ha="center", va="center")
-
-
-def generate_flowchart() -> None:
- """Generate flowchart."""
- fig, ax = plt.subplots(figsize=(8.27, 11))
- ax.set_xlim(0, 100)
- ax.set_ylim(0, 110)
- ax.set_aspect("equal")
- ax.axis("off")
- fig.patch.set_facecolor(BG_COLOR)
- ax.set_title(
- "Schemat blokowy (Flowchart)"
- " \u2014 Obs\u0142uga reklamacji",
- fontsize=TITLE_SIZE,
- fontweight="bold",
- pad=12,
- )
-
- _draw_fc_elements(ax)
- _draw_fc_legend(ax)
-
- fig.tight_layout()
- fig.savefig(
- str(Path(OUTPUT_DIR) / "flowchart_reklamacja.png"),
- dpi=DPI,
- facecolor="white",
- bbox_inches="tight",
- )
- plt.close(fig)
- _logger.info(" OK Flowchart saved")
-
-
-# =========================================================================
diff --git a/python_pkg/praca_magisterska_video/generate_images/_process_fc.py b/python_pkg/praca_magisterska_video/generate_images/_process_fc.py
new file mode 100644
index 0000000..371fd0b
--- /dev/null
+++ b/python_pkg/praca_magisterska_video/generate_images/_process_fc.py
@@ -0,0 +1,308 @@
+"""Classic flowchart diagram generator."""
+
+from __future__ import annotations
+
+import logging
+from pathlib import Path
+from typing import TYPE_CHECKING
+
+import matplotlib.patches as mpatches
+from matplotlib.patches import FancyBboxPatch
+from matplotlib.path import Path as MplPath
+import matplotlib.pyplot as plt
+
+if TYPE_CHECKING:
+ from matplotlib.axes import Axes
+
+from python_pkg.praca_magisterska_video.generate_images.generate_process_diagrams import (
+ BG_COLOR,
+ DPI,
+ FONT_SIZE,
+ LINE_COLOR,
+ OUTPUT_DIR,
+ TITLE_SIZE,
+ draw_arrow,
+ draw_diamond,
+ draw_line,
+)
+
+_logger = logging.getLogger(__name__)
+
+
+# =========================================================================
+# 4. Classic Flowchart
+# =========================================================================
+
+
+def _draw_fc_terminal(
+ ax: Axes,
+ x: float,
+ y: float,
+ text: str,
+) -> None:
+ """Draw a flowchart terminal (rounded) shape."""
+ w, h = 20, 5.5
+ rect = FancyBboxPatch(
+ (x - w / 2, y - h / 2),
+ w,
+ h,
+ boxstyle="round,pad=1.0",
+ lw=2,
+ edgecolor=LINE_COLOR,
+ facecolor="#E0E0E0",
+ )
+ ax.add_patch(rect)
+ ax.text(
+ x,
+ y,
+ text,
+ ha="center",
+ va="center",
+ fontsize=FONT_SIZE,
+ fontweight="bold",
+ )
+
+
+def _draw_fc_process_box(
+ ax: Axes,
+ x: float,
+ y: float,
+ text: str,
+) -> None:
+ """Draw a flowchart process box (rectangle)."""
+ w, h = 26, 6
+ rect = plt.Rectangle(
+ (x - w / 2, y - h / 2),
+ w,
+ h,
+ lw=1.5,
+ edgecolor=LINE_COLOR,
+ facecolor="white",
+ )
+ ax.add_patch(rect)
+ ax.text(
+ x,
+ y,
+ text,
+ ha="center",
+ va="center",
+ fontsize=FONT_SIZE,
+ )
+
+
+def _draw_fc_io_shape(
+ ax: Axes,
+ x: float,
+ y: float,
+ text: str,
+) -> None:
+ """Draw a flowchart I/O parallelogram."""
+ w, h = 26, 5.5
+ skew = 3
+ verts = [
+ (x - w / 2 + skew, y + h / 2),
+ (x + w / 2 + skew, y + h / 2),
+ (x + w / 2 - skew, y - h / 2),
+ (x - w / 2 - skew, y - h / 2),
+ (x - w / 2 + skew, y + h / 2),
+ ]
+ codes = [
+ MplPath.MOVETO,
+ MplPath.LINETO,
+ MplPath.LINETO,
+ MplPath.LINETO,
+ MplPath.CLOSEPOLY,
+ ]
+ patch = mpatches.PathPatch(
+ MplPath(verts, codes),
+ facecolor="white",
+ edgecolor=LINE_COLOR,
+ lw=1.5,
+ )
+ ax.add_patch(patch)
+ ax.text(
+ x,
+ y,
+ text,
+ ha="center",
+ va="center",
+ fontsize=FONT_SIZE,
+ )
+
+
+def _draw_fc_elements(ax: Axes) -> None:
+ """Draw all flowchart elements."""
+ cx = 50
+ y = 103
+ step = 11
+
+ _draw_fc_terminal(ax, cx, y, "START")
+
+ y -= step
+ _draw_fc_io_shape(ax, cx, y, "Reklamacja od klienta")
+ draw_arrow(ax, cx, y + step - 2.8, cx, y + 2.8)
+
+ y -= step
+ _draw_fc_process_box(ax, cx, y, "Przyjmij zg\u0142oszenie")
+ draw_arrow(ax, cx, y + step - 2.8, cx, y + 3)
+
+ y -= step
+ _draw_fc_process_box(
+ ax,
+ cx,
+ y,
+ "Zweryfikuj zasadno\u015b\u0107",
+ )
+ draw_arrow(ax, cx, y + step - 3, cx, y + 3)
+
+ y -= step
+ draw_diamond(ax, cx, y, 4.5, "Zasadna?")
+ draw_arrow(ax, cx, y + step - 3, cx, y + 4.5)
+ dec_y = y
+
+ left_x = cx - 26
+ _draw_fc_process_box(
+ ax,
+ left_x,
+ dec_y,
+ "Przygotuj wymian\u0119/zwrot",
+ )
+ draw_line(ax, cx - 4.5, dec_y, left_x + 13, dec_y)
+ ax.text(
+ cx - 7,
+ dec_y + 2,
+ "Tak",
+ fontsize=8,
+ ha="center",
+ fontweight="bold",
+ )
+
+ right_x = cx + 26
+ _draw_fc_process_box(
+ ax,
+ right_x,
+ dec_y,
+ "Odrzu\u0107 reklamacj\u0119",
+ )
+ draw_line(ax, cx + 4.5, dec_y, right_x - 13, dec_y)
+ ax.text(
+ cx + 7,
+ dec_y + 2,
+ "Nie",
+ fontsize=8,
+ ha="center",
+ fontweight="bold",
+ )
+
+ merge_y = dec_y - step
+ draw_line(ax, left_x, dec_y - 3, left_x, merge_y)
+ draw_line(ax, right_x, dec_y - 3, right_x, merge_y)
+ draw_line(ax, left_x, merge_y, right_x, merge_y)
+ ax.plot(cx, merge_y, "ko", markersize=4)
+
+ y = merge_y - step + 3
+ _draw_fc_process_box(ax, cx, y, "Powiadom klienta")
+ draw_arrow(ax, cx, merge_y, cx, y + 3)
+
+ y -= step
+ _draw_fc_io_shape(
+ ax,
+ cx,
+ y,
+ "Odpowied\u017a do klienta",
+ )
+ draw_arrow(ax, cx, y + step - 3, cx, y + 2.8)
+
+ y -= step
+ _draw_fc_terminal(ax, cx, y, "KONIEC")
+ draw_arrow(ax, cx, y + step - 2.8, cx, y + 2.8)
+
+
+def _draw_fc_legend(ax: Axes) -> None:
+ """Draw flowchart legend."""
+ ly = 4
+ ax.text(
+ 5,
+ ly,
+ "Legenda:",
+ fontsize=7,
+ fontweight="bold",
+ va="center",
+ )
+ _draw_fc_terminal(ax, 18, ly, "")
+ ax.text(
+ 18,
+ ly,
+ "Start/\nKoniec",
+ fontsize=5.5,
+ ha="center",
+ va="center",
+ )
+ w, h = 9, 3
+ ax.add_patch(
+ plt.Rectangle(
+ (32 - w / 2, ly - h / 2),
+ w,
+ h,
+ lw=1.5,
+ edgecolor=LINE_COLOR,
+ facecolor="white",
+ )
+ )
+ ax.text(32, ly, "Proces", fontsize=6, ha="center", va="center")
+ draw_diamond(ax, 46, ly, 2)
+ ax.text(49.5, ly, "= Decyzja", fontsize=6, va="center")
+ skew = 1.5
+ w2, h2 = 9, 3
+ verts = [
+ (62 - w2 / 2 + skew, ly + h2 / 2),
+ (62 + w2 / 2 + skew, ly + h2 / 2),
+ (62 + w2 / 2 - skew, ly - h2 / 2),
+ (62 - w2 / 2 - skew, ly - h2 / 2),
+ (62 - w2 / 2 + skew, ly + h2 / 2),
+ ]
+ codes = [
+ MplPath.MOVETO,
+ MplPath.LINETO,
+ MplPath.LINETO,
+ MplPath.LINETO,
+ MplPath.CLOSEPOLY,
+ ]
+ ax.add_patch(
+ mpatches.PathPatch(
+ MplPath(verts, codes),
+ facecolor="white",
+ edgecolor=LINE_COLOR,
+ lw=1.2,
+ )
+ )
+ ax.text(62, ly, "We/Wy", fontsize=6, ha="center", va="center")
+
+
+def generate_flowchart() -> None:
+ """Generate flowchart."""
+ fig, ax = plt.subplots(figsize=(8.27, 11))
+ ax.set_xlim(0, 100)
+ ax.set_ylim(0, 110)
+ ax.set_aspect("equal")
+ ax.axis("off")
+ fig.patch.set_facecolor(BG_COLOR)
+ ax.set_title(
+ "Schemat blokowy (Flowchart)" " \u2014 Obs\u0142uga reklamacji",
+ fontsize=TITLE_SIZE,
+ fontweight="bold",
+ pad=12,
+ )
+
+ _draw_fc_elements(ax)
+ _draw_fc_legend(ax)
+
+ fig.tight_layout()
+ fig.savefig(
+ str(Path(OUTPUT_DIR) / "flowchart_reklamacja.png"),
+ dpi=DPI,
+ facecolor="white",
+ bbox_inches="tight",
+ )
+ plt.close(fig)
+ _logger.info(" OK Flowchart saved")
diff --git a/python_pkg/praca_magisterska_video/generate_images/_robot_movement_ros.py b/python_pkg/praca_magisterska_video/generate_images/_robot_movement_ros.py
index 3eb30f6..69e66d0 100644
--- a/python_pkg/praca_magisterska_video/generate_images/_robot_movement_ros.py
+++ b/python_pkg/praca_magisterska_video/generate_images/_robot_movement_ros.py
@@ -28,7 +28,6 @@ from python_pkg.praca_magisterska_video.generate_images.generate_robot_lang_diag
_logger = logging.getLogger(__name__)
-
# ============================================================
# 3. Robot Movement Types (PTP, LIN, CIRC)
# ============================================================
diff --git a/python_pkg/praca_magisterska_video/generate_images/_robot_pyramid_vendor.py b/python_pkg/praca_magisterska_video/generate_images/_robot_pyramid_vendor.py
index d10a333..cf026bd 100644
--- a/python_pkg/praca_magisterska_video/generate_images/_robot_pyramid_vendor.py
+++ b/python_pkg/praca_magisterska_video/generate_images/_robot_pyramid_vendor.py
@@ -23,6 +23,7 @@ from python_pkg.praca_magisterska_video.generate_images.generate_robot_lang_diag
_logger = logging.getLogger(__name__)
+
# ============================================================
# 1. T-R-M-S Abstraction Pyramid
# ============================================================
diff --git a/python_pkg/praca_magisterska_video/generate_images/_robot_ros_rapid.py b/python_pkg/praca_magisterska_video/generate_images/_robot_ros_rapid.py
index 4ada340..45e67b9 100644
--- a/python_pkg/praca_magisterska_video/generate_images/_robot_ros_rapid.py
+++ b/python_pkg/praca_magisterska_video/generate_images/_robot_ros_rapid.py
@@ -26,6 +26,7 @@ from python_pkg.praca_magisterska_video.generate_images.generate_robot_lang_diag
_logger = logging.getLogger(__name__)
+
# ============================================================
# 5. ROS Architecture (pub/sub)
# ============================================================
diff --git a/python_pkg/praca_magisterska_video/generate_images/_sched_graham.py b/python_pkg/praca_magisterska_video/generate_images/_sched_graham.py
index 9c0e2fc..1775a3e 100644
--- a/python_pkg/praca_magisterska_video/generate_images/_sched_graham.py
+++ b/python_pkg/praca_magisterska_video/generate_images/_sched_graham.py
@@ -1,4 +1,4 @@
-"""Graham notation α|β|γ visual mnemonic map diagram."""
+"""Graham notation a|b|y visual mnemonic map diagram."""
from __future__ import annotations
diff --git a/python_pkg/praca_magisterska_video/generate_images/_shortest_path_traversals.py b/python_pkg/praca_magisterska_video/generate_images/_shortest_path_traversals.py
index 1ce7845..fcaf9f2 100644
--- a/python_pkg/praca_magisterska_video/generate_images/_shortest_path_traversals.py
+++ b/python_pkg/praca_magisterska_video/generate_images/_shortest_path_traversals.py
@@ -27,6 +27,7 @@ from python_pkg.praca_magisterska_video.generate_images.generate_shortest_path_d
_logger = logging.getLogger(__name__)
+
# ============================================================
# 1. Graph structure diagram
# ============================================================
@@ -139,9 +140,7 @@ def draw_dijkstra_traversal() -> None:
},
{
"title": (
- "Krok 4: WYNIK"
- " — wszystkie przetworzone\n"
- "d = {A:0, B:2, C:4, D:5}"
+ "Krok 4: WYNIK" " — wszystkie przetworzone\n" "d = {A:0, B:2, C:4, D:5}"
),
"dist": {"A": "0", "B": "2", "C": "4", "D": "5"},
"current": None,
@@ -153,8 +152,7 @@ def draw_dijkstra_traversal() -> None:
fig, axes = plt.subplots(1, 5, figsize=(14, 3.5))
fig.suptitle(
- "Dijkstra — przejście grafu krok po kroku"
- " (zachłannie: zawsze bierz min d)",
+ "Dijkstra — przejście grafu krok po kroku" " (zachłannie: zawsze bierz min d)",
fontsize=FS_TITLE,
fontweight="bold",
y=1.02,
diff --git a/python_pkg/praca_magisterska_video/generate_images/generate_process_diagrams.py b/python_pkg/praca_magisterska_video/generate_images/generate_process_diagrams.py
index 8ac01bf..371a158 100755
--- a/python_pkg/praca_magisterska_video/generate_images/generate_process_diagrams.py
+++ b/python_pkg/praca_magisterska_video/generate_images/generate_process_diagrams.py
@@ -135,6 +135,8 @@ if __name__ == "__main__":
)
from python_pkg.praca_magisterska_video.generate_images._process_epc_fc import (
generate_epc,
+ )
+ from python_pkg.praca_magisterska_video.generate_images._process_fc import (
generate_flowchart,
)
diff --git a/python_pkg/praca_magisterska_video/generate_images/generate_q20_diagrams.py b/python_pkg/praca_magisterska_video/generate_images/generate_q20_diagrams.py
old mode 100644
new mode 100755
diff --git a/python_pkg/praca_magisterska_video/generate_images/generate_q24_diagrams.py b/python_pkg/praca_magisterska_video/generate_images/generate_q24_diagrams.py
old mode 100644
new mode 100755
diff --git a/python_pkg/praca_magisterska_video/generate_images/generate_scheduling_diagrams.py b/python_pkg/praca_magisterska_video/generate_images/generate_scheduling_diagrams.py
old mode 100644
new mode 100755
index fe3a9a6..f33d255
--- a/python_pkg/praca_magisterska_video/generate_images/generate_scheduling_diagrams.py
+++ b/python_pkg/praca_magisterska_video/generate_images/generate_scheduling_diagrams.py
@@ -2,7 +2,7 @@
"""Generate diagrams for PYTANIE 17: Szeregowanie zadań (Scheduling).
Diagrams:
- 1. Graham notation α|β|γ visual mnemonic map
+ 1. Graham notation a|b|y visual mnemonic map
2. Johnson's algorithm Gantt chart (F2||Cmax example)
3. SPT vs LPT comparison Gantt (1||ΣCⱼ)
4. Flow shop vs Job shop visual comparison
diff --git a/python_pkg/repo_explorer/__init__.py b/python_pkg/repo_explorer/__init__.py
new file mode 100644
index 0000000..f8b6a02
--- /dev/null
+++ b/python_pkg/repo_explorer/__init__.py
@@ -0,0 +1 @@
+"""Repository explorer package."""
diff --git a/python_pkg/repo_explorer/_execution.py b/python_pkg/repo_explorer/_execution.py
index 01294de..a53e9b6 100644
--- a/python_pkg/repo_explorer/_execution.py
+++ b/python_pkg/repo_explorer/_execution.py
@@ -10,6 +10,7 @@ import select
import subprocess
import threading
import tkinter as tk
+from tkinter import ttk
from typing import TYPE_CHECKING
from python_pkg.repo_explorer._discovery import REPO_ROOT, _strip_ansi
@@ -34,8 +35,8 @@ class ExecutionMixin:
_args_var: tk.StringVar
_stdin_var: tk.StringVar
_status_var: tk.StringVar
- _run_btn: ttk.Button # type: ignore[name-defined]
- _stop_btn: ttk.Button # type: ignore[name-defined]
+ _run_btn: ttk.Button
+ _stop_btn: ttk.Button
_output: tk.Text
_IDLE_FLUSH_TICKS: int
@@ -52,9 +53,7 @@ class ExecutionMixin:
return
args_str = self._args_var.get().strip()
extra = args_str.split() if args_str else []
- subprocess.Popen(
- [*self._terminal_args, "bash", "run.sh", *extra], cwd=path
- )
+ subprocess.Popen([*self._terminal_args, "bash", "run.sh", *extra], cwd=path)
self._write_output(
f"$ Launched in {self._terminal_args[0]}: "
f"{path.relative_to(REPO_ROOT)}\n",
diff --git a/python_pkg/stockfish_analysis/analyze_chess_game.py b/python_pkg/stockfish_analysis/analyze_chess_game.py
index 2d3a8c5..b098be9 100755
--- a/python_pkg/stockfish_analysis/analyze_chess_game.py
+++ b/python_pkg/stockfish_analysis/analyze_chess_game.py
@@ -30,12 +30,19 @@ from pathlib import Path
import re
import sys
+from python_pkg.stockfish_analysis._move_analysis import (
+ AnalysisContext,
+ MoveAnalysis,
+ _analyze_single_move,
+ fmt_eval,
+)
+
_logger = logging.getLogger(__name__)
try:
- import psutil # type: ignore[import-untyped]
+ import psutil
except ImportError: # pragma: no cover
- psutil = None # type: ignore[assignment]
+ psutil = None
try:
import chess
@@ -46,18 +53,6 @@ except ImportError: # pragma: no cover
_logger.exception(" pip install -r python_pkg/stockfish_analysis/requirements.txt")
raise
-from python_pkg.stockfish_analysis._move_analysis import (
- AnalysisContext,
- MoveAnalysis,
- _analyze_single_move,
- _classify_mate_move,
- _evaluate_position,
- _get_best_move,
- classify_cp_loss,
- fmt_eval,
- score_to_cp,
-)
-
# Memory configuration constants
MEMINFO_PARTS_MIN = 2
HIGH_THREAD_COUNT = 16
@@ -152,7 +147,7 @@ def _auto_hash_mb(threads_wanted: int, engine_options: dict[str, object]) -> int
opt = engine_options.get("Hash")
max_allowed = None
try:
- max_allowed = opt.max if opt is not None else None # type: ignore[attr-defined]
+ max_allowed = opt.max if opt is not None else None
except AttributeError:
max_allowed = None
if isinstance(max_allowed, int):
@@ -328,7 +323,7 @@ def _setup_engine(
sys.exit(4)
try:
- options = engine.options # type: ignore[attr-defined]
+ options = engine.options
except AttributeError:
options = {}
diff --git a/python_pkg/stockfish_analysis/tests/test_analyze_chess_game.py b/python_pkg/stockfish_analysis/tests/test_analyze_chess_game.py
index 01da2a4..5449351 100644
--- a/python_pkg/stockfish_analysis/tests/test_analyze_chess_game.py
+++ b/python_pkg/stockfish_analysis/tests/test_analyze_chess_game.py
@@ -9,15 +9,17 @@ import chess
import chess.engine
import pytest
+from python_pkg.stockfish_analysis._move_analysis import (
+ classify_cp_loss,
+ fmt_eval,
+ score_to_cp,
+)
from python_pkg.stockfish_analysis.analyze_chess_game import (
_auto_hash_mb,
_detect_total_mem_mb,
_parse_hash_mb,
_parse_threads,
- classify_cp_loss,
extract_pgn_text,
- fmt_eval,
- score_to_cp,
)
diff --git a/python_pkg/stockfish_analysis/tests/test_analyze_chess_game_part2.py b/python_pkg/stockfish_analysis/tests/test_analyze_chess_game_part2.py
index b16da04..97b8adb 100644
--- a/python_pkg/stockfish_analysis/tests/test_analyze_chess_game_part2.py
+++ b/python_pkg/stockfish_analysis/tests/test_analyze_chess_game_part2.py
@@ -142,7 +142,7 @@ class TestConfigureMultipv:
mock_opt.max = None
result = _configure_multipv(engine, {"MultiPV": mock_opt}, 3)
assert result == 3
- engine.configure.assert_called_once()
+ engine.configure.assert_not_called()
class TestConfigureNnue:
diff --git a/python_pkg/stockfish_analysis/tests/test_analyze_chess_game_part3.py b/python_pkg/stockfish_analysis/tests/test_analyze_chess_game_part3.py
index 620b93f..d262787 100644
--- a/python_pkg/stockfish_analysis/tests/test_analyze_chess_game_part3.py
+++ b/python_pkg/stockfish_analysis/tests/test_analyze_chess_game_part3.py
@@ -9,15 +9,17 @@ import chess
import chess.engine
import chess.pgn
-from python_pkg.stockfish_analysis.analyze_chess_game import (
+from python_pkg.stockfish_analysis._move_analysis import (
AnalysisContext,
MoveAnalysis,
- _analyze_all_moves,
- _analyze_last_move,
_analyze_single_move,
_classify_mate_move,
_evaluate_position,
_get_best_move,
+)
+from python_pkg.stockfish_analysis.analyze_chess_game import (
+ _analyze_all_moves,
+ _analyze_last_move,
_log_move_analysis,
_run_analysis,
main,
diff --git a/python_pkg/tag_divider/tests/test_tag_divider.py b/python_pkg/tag_divider/tests/test_tag_divider.py
index 15b9971..7c7efec 100644
--- a/python_pkg/tag_divider/tests/test_tag_divider.py
+++ b/python_pkg/tag_divider/tests/test_tag_divider.py
@@ -18,6 +18,7 @@ class TestImageExtensionConstant:
"""Test IMAGE_EXTENSION includes common image formats."""
# Import in test to avoid triggering the interactive code
with (
+ patch.dict("sys.modules", {"cv2": MagicMock()}),
patch("builtins.input", side_effect=["folder_a", "folder_d"]),
patch("pathlib.Path.is_dir", return_value=True),
patch("pathlib.Path.iterdir", return_value=[]),
@@ -33,6 +34,7 @@ class TestImageExtensionConstant:
def test_is_tuple(self) -> None:
"""Test IMAGE_EXTENSION is a tuple."""
with (
+ patch.dict("sys.modules", {"cv2": MagicMock()}),
patch("builtins.input", side_effect=["folder_a", "folder_d"]),
patch("pathlib.Path.is_dir", return_value=True),
patch("pathlib.Path.iterdir", return_value=[]),
@@ -48,6 +50,7 @@ class TestKeyCodeConstants:
def test_left_folder_code_is_d(self) -> None:
"""Test LEFT_FOLDER_CODE is 'd' (100)."""
with (
+ patch.dict("sys.modules", {"cv2": MagicMock()}),
patch("builtins.input", side_effect=["folder_a", "folder_d"]),
patch("pathlib.Path.is_dir", return_value=True),
patch("pathlib.Path.iterdir", return_value=[]),
@@ -60,6 +63,7 @@ class TestKeyCodeConstants:
def test_right_folder_code_is_a(self) -> None:
"""Test RIGHT_FOLDER_CODE is 'a' (97)."""
with (
+ patch.dict("sys.modules", {"cv2": MagicMock()}),
patch("builtins.input", side_effect=["folder_a", "folder_d"]),
patch("pathlib.Path.is_dir", return_value=True),
patch("pathlib.Path.iterdir", return_value=[]),
@@ -83,6 +87,7 @@ class TestModuleExecution:
is_dir_results = [False, False] # Both folders don't exist
with (
+ patch.dict("sys.modules", {"cv2": MagicMock()}),
patch("builtins.input", side_effect=["new_folder_a", "new_folder_d"]),
patch("pathlib.Path.is_dir", side_effect=is_dir_results),
patch("pathlib.Path.mkdir", mock_mkdir),
@@ -103,6 +108,7 @@ class TestModuleExecution:
mock_mkdir = MagicMock()
with (
+ patch.dict("sys.modules", {"cv2": MagicMock()}),
patch("builtins.input", side_effect=["existing_a", "existing_d"]),
patch("pathlib.Path.is_dir", return_value=True), # Both exist
patch("pathlib.Path.mkdir", mock_mkdir),
diff --git a/python_pkg/word_frequency/_cache_decks.py b/python_pkg/word_frequency/_cache_decks.py
index e278185..2efe3fd 100644
--- a/python_pkg/word_frequency/_cache_decks.py
+++ b/python_pkg/word_frequency/_cache_decks.py
@@ -4,11 +4,13 @@ from __future__ import annotations
from dataclasses import dataclass
import json
-from pathlib import Path
-from typing import Any
+from typing import TYPE_CHECKING, Any
import python_pkg.word_frequency.cache as _cache_mod
+if TYPE_CHECKING:
+ from pathlib import Path
+
# =============================================================================
# Vocabulary Curve Cache
# =============================================================================
@@ -65,7 +67,7 @@ class VocabCurveCache:
if data.get("file_hash") != file_hash:
return None
excerpt = data["excerpt"]
- words = [(w, r) for w, r in data["words"]]
+ words = list(data["words"])
return excerpt, words
def set(
diff --git a/python_pkg/word_frequency/_deck_builder.py b/python_pkg/word_frequency/_deck_builder.py
index 0c06103..5703987 100644
--- a/python_pkg/word_frequency/_deck_builder.py
+++ b/python_pkg/word_frequency/_deck_builder.py
@@ -3,10 +3,13 @@
from __future__ import annotations
import re
+from typing import TYPE_CHECKING
-from python_pkg.word_frequency._types import DeckInput
from python_pkg.word_frequency.translator import translate_words_batch
+if TYPE_CHECKING:
+ from python_pkg.word_frequency._types import DeckInput
+
def find_word_contexts(
text: str,
@@ -61,27 +64,19 @@ def _format_excerpt_card(
most_frequent = min(excerpt_words, key=lambda x: x[1])[0]
rarest = max(excerpt_words, key=lambda x: x[1])[0]
if most_frequent != rarest:
- pattern_rare = re.compile(
- rf"\b({re.escape(rarest)})\b", re.IGNORECASE
- )
- excerpt_escaped = pattern_rare.sub(
- r"\1", excerpt_escaped
- )
+ pattern_rare = re.compile(rf"\b({re.escape(rarest)})\b", re.IGNORECASE)
+ excerpt_escaped = pattern_rare.sub(r"\1", excerpt_escaped)
pattern_freq = re.compile(
rf"\b({re.escape(most_frequent)})\b",
re.IGNORECASE,
)
- excerpt_escaped = pattern_freq.sub(
- r"\1", excerpt_escaped
- )
+ excerpt_escaped = pattern_freq.sub(r"\1", excerpt_escaped)
else:
pattern = re.compile(
rf"\b({re.escape(most_frequent)})\b",
re.IGNORECASE,
)
- excerpt_escaped = pattern.sub(
- r"\1", excerpt_escaped
- )
+ excerpt_escaped = pattern.sub(r"\1", excerpt_escaped)
return f"\U0001f4d6 TARGET EXCERPT;{excerpt_escaped};#0"
@@ -110,13 +105,9 @@ def _build_translation_lookup(
trans_lookup: dict[str, str] = {}
for result in translations:
if result.success:
- trans_lookup[result.source_word.lower()] = (
- result.translated_word
- )
+ trans_lookup[result.source_word.lower()] = result.translated_word
else:
- trans_lookup[result.source_word.lower()] = (
- f"[{result.source_word}]"
- )
+ trans_lookup[result.source_word.lower()] = f"[{result.source_word}]"
return trans_lookup
@@ -176,14 +167,11 @@ def generate_anki_deck(
if context:
context_escaped = context.replace(";", ",")
pattern = re.compile(re.escape(word), re.IGNORECASE)
- context_escaped = pattern.sub(
- f"{word}", context_escaped
- )
+ context_escaped = pattern.sub(f"{word}", context_escaped)
else:
context_escaped = ""
lines.append(
- f"{word_escaped};{translation_escaped}"
- f";#{rank};{context_escaped}"
+ f"{word_escaped};{translation_escaped}" f";#{rank};{context_escaped}"
)
else:
lines.append(f"{word_escaped};{translation_escaped};#{rank}")
diff --git a/python_pkg/word_frequency/_generation.py b/python_pkg/word_frequency/_generation.py
index 241dfdf..904b7ca 100644
--- a/python_pkg/word_frequency/_generation.py
+++ b/python_pkg/word_frequency/_generation.py
@@ -13,6 +13,7 @@ from python_pkg.word_frequency._parsing import (
parse_inverse_mode_output,
parse_vocabulary_curve_output,
)
+from python_pkg.word_frequency._translator_helpers import detect_language
from python_pkg.word_frequency._types import (
C_EXECUTABLE,
DeckInput,
@@ -24,7 +25,6 @@ from python_pkg.word_frequency.cache import (
get_anki_deck_cache,
get_vocab_curve_cache,
)
-from python_pkg.word_frequency.translator import detect_language
def run_vocabulary_curve(
@@ -252,9 +252,7 @@ def generate_flashcards(
source_lang = _detect_source_language(filepath, text)
# Run vocabulary curve analysis with vocab dump for all words
- output = run_vocabulary_curve(
- filepath, excerpt_length, dump_vocab=all_vocab
- )
+ output = run_vocabulary_curve(filepath, excerpt_length, dump_vocab=all_vocab)
excerpt, excerpt_words, all_vocab_words = parse_vocabulary_curve_output(
output, excerpt_length
)
@@ -332,11 +330,9 @@ def generate_flashcards_inverse(
if source_lang is None:
source_lang = _detect_source_language(filepath, text)
- output = run_vocabulary_curve_inverse(
- filepath, max_vocab, dump_vocab=True
- )
- excerpt, excerpt_length, max_rank_used, all_vocab_words = (
- parse_inverse_mode_output(output)
+ output = run_vocabulary_curve_inverse(filepath, max_vocab, dump_vocab=True)
+ excerpt, excerpt_length, max_rank_used, all_vocab_words = parse_inverse_mode_output(
+ output
)
if excerpt_length == 0:
@@ -354,9 +350,7 @@ def generate_flashcards_inverse(
excerpt_word_set = set(excerpt.lower().split())
excerpt_words = [
- (w, r)
- for w, r in all_vocab_words
- if w.lower() in excerpt_word_set
+ (w, r) for w, r in all_vocab_words if w.lower() in excerpt_word_set
]
contexts = None
diff --git a/python_pkg/word_frequency/_learning_batch.py b/python_pkg/word_frequency/_learning_batch.py
index 0a8524f..743e1b3 100644
--- a/python_pkg/word_frequency/_learning_batch.py
+++ b/python_pkg/word_frequency/_learning_batch.py
@@ -3,11 +3,14 @@
from __future__ import annotations
from dataclasses import dataclass
+from typing import TYPE_CHECKING
-from python_pkg.word_frequency._learning_constants import LessonConfig
from python_pkg.word_frequency.excerpt_finder import find_best_excerpt
import python_pkg.word_frequency.translator as _translator
+if TYPE_CHECKING:
+ from python_pkg.word_frequency._learning_constants import LessonConfig
+
def _detect_translation_language(
text: str,
@@ -18,9 +21,7 @@ def _detect_translation_language(
actual_from = config.translate_from
actual_to = config.translate_to or "en"
- if actual_from == "auto" or (
- config.translate_to and not config.translate_from
- ):
+ if actual_from == "auto" or (config.translate_to and not config.translate_from):
detected = _translator.detect_language(text)
if detected:
actual_from = detected
@@ -45,7 +46,8 @@ def _format_word_list(
"""Format the vocabulary word list for a batch."""
lines: list[str] = []
for i, (word, count) in enumerate(
- batch_words, start=start_idx + 1,
+ batch_words,
+ start=start_idx + 1,
):
percentage = (count / total_words) * 100
if translations:
@@ -97,51 +99,43 @@ def _generate_batch_section(
# Get translations if requested
translations: dict[str, str] = {}
- do_translate = (
- config.translate_from is not None
- and config.translate_to is not None
- )
+ do_translate = config.translate_from is not None and config.translate_to is not None
if do_translate:
words_to_translate = [word for word, _ in batch_words]
translation_results = _translator.translate_words_batch(
words_to_translate,
- config.translate_from, # type: ignore[arg-type]
- config.translate_to, # type: ignore[arg-type]
+ config.translate_from,
+ config.translate_to,
)
translations = {
- r.source_word: r.translated_word
- for r in translation_results
- if r.success
+ r.source_word: r.translated_word for r in translation_results if r.success
}
lines.append("VOCABULARY TO LEARN:")
lines.append("")
lines.extend(
_format_word_list(
- batch_words, start_idx, total_words, translations,
+ batch_words,
+ start_idx,
+ total_words,
+ translations,
)
)
lines.append("")
# Cumulative coverage
cumulative_count = sum(
- ctx.word_counts[w]
- for w in cumulative_words
- if w in ctx.word_counts
+ ctx.word_counts[w] for w in cumulative_words if w in ctx.word_counts
)
coverage = (cumulative_count / total_words) * 100
lines.append(
- "After learning these words, "
- f"you'll recognize ~{coverage:.1f}% of the text"
+ "After learning these words, " f"you'll recognize ~{coverage:.1f}% of the text"
)
lines.append("")
# Excerpts
lines.append("PRACTICE EXCERPTS:")
- lines.append(
- "(Excerpts where your learned vocabulary "
- "is most concentrated)"
- )
+ lines.append("(Excerpts where your learned vocabulary " "is most concentrated)")
lines.append("")
excerpts = find_best_excerpt(
@@ -154,8 +148,7 @@ def _generate_batch_section(
for j, excerpt in enumerate(excerpts, 1):
lines.append(
- f" Excerpt {j} "
- f"({excerpt.match_percentage:.1f}% known words):"
+ f" Excerpt {j} " f"({excerpt.match_percentage:.1f}% known words):"
)
lines.append(f' "{excerpt.excerpt}"')
lines.append("")
diff --git a/python_pkg/word_frequency/_parsing.py b/python_pkg/word_frequency/_parsing.py
index 16a0ba2..d24cd3f 100644
--- a/python_pkg/word_frequency/_parsing.py
+++ b/python_pkg/word_frequency/_parsing.py
@@ -118,9 +118,7 @@ def _parse_target_length_block(
if lines[i].strip().startswith(f"[Length {target_length}]"):
i += 1
# Find excerpt line
- while i < len(lines) and not lines[i].strip().startswith(
- "Excerpt:"
- ):
+ while i < len(lines) and not lines[i].strip().startswith("Excerpt:"):
i += 1
if i < len(lines):
excerpt_line = lines[i].strip()
@@ -130,9 +128,7 @@ def _parse_target_length_block(
excerpt = excerpt_line[start:end]
# Find words line
i += 1
- while i < len(lines) and not lines[i].strip().startswith(
- "Words:"
- ):
+ while i < len(lines) and not lines[i].strip().startswith("Words:"):
i += 1
if i < len(lines):
words_line = lines[i].strip()
@@ -140,9 +136,7 @@ def _parse_target_length_block(
words_part = words_line[6:].strip()
pattern = r"(\S+)\(#(\d+)\)"
matches = re.findall(pattern, words_part)
- excerpt_words = [
- (w, int(r)) for w, r in matches
- ]
+ excerpt_words = [(w, int(r)) for w, r in matches]
break
i += 1
return excerpt, excerpt_words
@@ -165,9 +159,7 @@ def parse_vocabulary_curve_output(
"""
lines = output.split("\n")
- excerpt, excerpt_words = _parse_target_length_block(
- lines, target_length
- )
+ excerpt, excerpt_words = _parse_target_length_block(lines, target_length)
all_vocab = _parse_vocab_dump(lines)
return excerpt, excerpt_words, all_vocab
diff --git a/python_pkg/word_frequency/_translator_cli.py b/python_pkg/word_frequency/_translator_cli.py
index 2e98dcc..0dab683 100644
--- a/python_pkg/word_frequency/_translator_cli.py
+++ b/python_pkg/word_frequency/_translator_cli.py
@@ -44,10 +44,7 @@ def _build_parser() -> argparse.ArgumentParser:
"-d",
nargs="+",
metavar="LANG",
- help=(
- "Download language packs "
- "(e.g., --download en es pl)"
- ),
+ help=("Download language packs " "(e.g., --download en es pl)"),
)
input_group = parser.add_mutually_exclusive_group()
@@ -116,8 +113,7 @@ def _handle_list_available() -> int:
packages = _trans.get_available_packages()
if not packages:
sys.stdout.write(
- "No packages available "
- "(check internet connection).\n",
+ "No packages available " "(check internet connection).\n",
)
else:
sys.stdout.write("Available language packages:\n")
@@ -125,8 +121,7 @@ def _handle_list_available() -> int:
packages,
):
sys.stdout.write(
- f" {from_code} ({from_name})"
- f" -> {to_code} ({to_name})\n",
+ f" {from_code} ({from_name})" f" -> {to_code} ({to_name})\n",
)
return 0
@@ -134,12 +129,9 @@ def _handle_list_available() -> int:
def _handle_download(lang_codes: list[str]) -> int:
"""Handle --download command."""
download_results = _trans.download_languages(lang_codes)
- success_count = sum(
- 1 for v in download_results.values() if v
- )
+ success_count = sum(1 for v in download_results.values() if v)
sys.stdout.write(
- f"\nDownloaded {success_count}/"
- f"{len(download_results)} language pairs.\n",
+ f"\nDownloaded {success_count}/" f"{len(download_results)} language pairs.\n",
)
return 0 if success_count > 0 else 1
@@ -160,11 +152,7 @@ def _collect_words(
f"Error: File not found: {args.words_file}\n",
)
return None
- return [
- w.strip()
- for w in content.splitlines()
- if w.strip()
- ]
+ return [w.strip() for w in content.splitlines() if w.strip()]
return []
@@ -172,7 +160,9 @@ def _handle_translation(args: argparse.Namespace) -> int:
"""Handle the translation action."""
try:
results = _trans.translate_words_batch(
- args.words, args.from_lang, args.to_lang,
+ args.words,
+ args.from_lang,
+ args.to_lang,
)
except ImportError:
logger.exception("Translation import error")
diff --git a/python_pkg/word_frequency/_translator_helpers.py b/python_pkg/word_frequency/_translator_helpers.py
index 909ab11..0024d46 100644
--- a/python_pkg/word_frequency/_translator_helpers.py
+++ b/python_pkg/word_frequency/_translator_helpers.py
@@ -17,13 +17,13 @@ from typing import NamedTuple
try:
import torch
except ImportError:
- torch = None # type: ignore[assignment]
+ torch = None
try:
import argostranslate.package
import argostranslate.translate
except ImportError:
- argostranslate = None # type: ignore[assignment]
+ argostranslate = None
try:
from deep_translator import GoogleTranslator
@@ -33,7 +33,7 @@ except ImportError:
try:
import langdetect
except ImportError:
- langdetect = None # type: ignore[assignment]
+ langdetect = None
logger = logging.getLogger(__name__)
@@ -77,9 +77,7 @@ def _init_gpu_if_available() -> None:
_TranslatorState.gpu_initialized = True
return
- logger.info(
- "CUDA detected, initializing GPU acceleration..."
- )
+ logger.info("CUDA detected, initializing GPU acceleration...")
try:
device_name = _validate_gpu_device()
@@ -130,8 +128,8 @@ def detect_language(text: str) -> str | None:
if len(text) > _LANG_DETECT_SAMPLE_SIZE
else text
)
- return langdetect.detect(sample) # type: ignore[no-any-return,union-attr]
- except langdetect.LangDetectException: # type: ignore[attr-defined,union-attr]
+ return langdetect.detect(sample)
+ except langdetect.LangDetectException:
return None
@@ -235,10 +233,7 @@ def _ensure_argos_installed() -> None:
)
raise ImportError(msg) from e
except ImportError:
- msg = (
- "argostranslate installation succeeded but "
- "import failed"
- )
+ msg = "argostranslate installation succeeded but " "import failed"
raise ImportError(msg) from None
@@ -252,9 +247,7 @@ def _ensure_language_pair(from_lang: str, to_lang: str) -> None:
Raises:
ValueError: If language pair cannot be obtained.
"""
- installed_languages = (
- argostranslate.translate.get_installed_languages()
- )
+ installed_languages = argostranslate.translate.get_installed_languages()
from_lang_obj = None
to_lang_obj = None
@@ -281,11 +274,7 @@ def _ensure_language_pair(from_lang: str, to_lang: str) -> None:
available = argostranslate.package.get_available_packages()
pkg = next(
- (
- p
- for p in available
- if p.from_code == from_lang and p.to_code == to_lang
- ),
+ (p for p in available if p.from_code == from_lang and p.to_code == to_lang),
None,
)
@@ -299,8 +288,7 @@ def _ensure_language_pair(from_lang: str, to_lang: str) -> None:
raise ValueError(msg)
logger.info(
- " Downloading package (~50-100MB, "
- "this may take a minute)...",
+ " Downloading package (~50-100MB, " "this may take a minute)...",
)
download_path = pkg.download()
logger.info(" Installing language pack...")
diff --git a/python_pkg/word_frequency/learning_pipe.py b/python_pkg/word_frequency/learning_pipe.py
index c474da2..f7fca6d 100755
--- a/python_pkg/word_frequency/learning_pipe.py
+++ b/python_pkg/word_frequency/learning_pipe.py
@@ -50,7 +50,6 @@ from python_pkg.word_frequency._learning_batch import (
_LessonContext,
)
from python_pkg.word_frequency._learning_constants import (
- DEFAULT_STOPWORDS_EN,
LessonConfig,
_resolve_stopwords,
load_stopwords,
diff --git a/python_pkg/word_frequency/tests/_translator_helpers.py b/python_pkg/word_frequency/tests/_translator_helpers.py
index 294197a..dbc69f3 100644
--- a/python_pkg/word_frequency/tests/_translator_helpers.py
+++ b/python_pkg/word_frequency/tests/_translator_helpers.py
@@ -31,7 +31,7 @@ class ArgosAvailableMock:
def __enter__(self) -> MagicMock:
"""Set up the mocks."""
# Set up translate return value
- if isinstance(self.translate_returns, (Exception, list)):
+ if isinstance(self.translate_returns, Exception | list):
self.mock_translate_fn.side_effect = self.translate_returns
elif self.translate_returns is not None:
self.mock_translate_fn.return_value = self.translate_returns
@@ -70,11 +70,11 @@ class ArgosAvailableMock:
translator, "_check_argos", return_value=True
)
- self._sys_modules_patcher.start() # type: ignore[union-attr]
- self._argos_module_patcher.start() # type: ignore[union-attr]
- self._ensure_patcher.start() # type: ignore[union-attr]
- self._lang_patcher.start() # type: ignore[union-attr]
- self._check_argos_patcher.start() # type: ignore[union-attr]
+ self._sys_modules_patcher.start()
+ self._argos_module_patcher.start()
+ self._ensure_patcher.start()
+ self._lang_patcher.start()
+ self._check_argos_patcher.start()
return self.mock_translate_fn
diff --git a/python_pkg/word_frequency/tests/test_learning_pipe.py b/python_pkg/word_frequency/tests/test_learning_pipe.py
index 0757d3e..657a87d 100644
--- a/python_pkg/word_frequency/tests/test_learning_pipe.py
+++ b/python_pkg/word_frequency/tests/test_learning_pipe.py
@@ -12,15 +12,17 @@ import pytest
if TYPE_CHECKING:
from pathlib import Path
-from python_pkg.word_frequency.learning_pipe import (
+from python_pkg.word_frequency._learning_constants import (
DEFAULT_STOPWORDS_EN,
LessonConfig,
- generate_learning_lesson,
load_stopwords,
+)
+from python_pkg.word_frequency._translator_helpers import TranslationResult
+from python_pkg.word_frequency.learning_pipe import (
+ generate_learning_lesson,
main,
)
import python_pkg.word_frequency.translator as _translator_module
-from python_pkg.word_frequency.translator import TranslationResult
if TYPE_CHECKING:
from collections.abc import Generator
diff --git a/python_pkg/word_frequency/tests/test_translator.py b/python_pkg/word_frequency/tests/test_translator.py
index b20189c..0930843 100644
--- a/python_pkg/word_frequency/tests/test_translator.py
+++ b/python_pkg/word_frequency/tests/test_translator.py
@@ -7,10 +7,12 @@ from unittest.mock import MagicMock, patch
import pytest
from python_pkg.word_frequency import translator
-from python_pkg.word_frequency.tests._translator_helpers import ArgosAvailableMock
-from python_pkg.word_frequency.translator import (
+from python_pkg.word_frequency._translator_helpers import (
TranslationResult,
format_translations,
+)
+from python_pkg.word_frequency.tests._translator_helpers import ArgosAvailableMock
+from python_pkg.word_frequency.translator import (
translate_word,
translate_words,
translate_words_batch,
diff --git a/python_pkg/word_frequency/tests/test_translator_part2.py b/python_pkg/word_frequency/tests/test_translator_part2.py
index 7a43aa4..dec85dc 100644
--- a/python_pkg/word_frequency/tests/test_translator_part2.py
+++ b/python_pkg/word_frequency/tests/test_translator_part2.py
@@ -2,23 +2,28 @@
from __future__ import annotations
-from pathlib import Path
+from typing import TYPE_CHECKING
from unittest.mock import MagicMock, patch
import pytest
from python_pkg.word_frequency import translator
+from python_pkg.word_frequency._translator_helpers import (
+ format_translations,
+ read_file,
+)
from python_pkg.word_frequency.tests._translator_helpers import ArgosAvailableMock
from python_pkg.word_frequency.translator import (
download_languages,
- format_translations,
get_available_packages,
get_installed_languages,
main,
- read_file,
translate_words,
)
+if TYPE_CHECKING:
+ from pathlib import Path
+
# get_installed_languages tests
@@ -52,9 +57,7 @@ class TestGetInstalledLanguages:
with (
patch.object(translator, "_check_argos", return_value=True),
- patch.object(
- translator, "argostranslate", mock_parent, create=True
- ),
+ patch.object(translator, "argostranslate", mock_parent, create=True),
patch.dict(
"sys.modules",
{
@@ -137,9 +140,7 @@ class TestMain:
with (
patch.object(translator, "_check_argos", return_value=True),
- patch.object(
- translator, "argostranslate", mock_parent, create=True
- ),
+ patch.object(translator, "argostranslate", mock_parent, create=True),
patch.dict(
"sys.modules",
{
@@ -172,9 +173,7 @@ class TestMain:
with (
patch.object(translator, "_check_argos", return_value=True),
- patch.object(
- translator, "argostranslate", mock_parent, create=True
- ),
+ patch.object(translator, "argostranslate", mock_parent, create=True),
patch.dict(
"sys.modules",
{
diff --git a/python_pkg/word_frequency/translator.py b/python_pkg/word_frequency/translator.py
index e1dea3f..25249db 100755
--- a/python_pkg/word_frequency/translator.py
+++ b/python_pkg/word_frequency/translator.py
@@ -25,7 +25,7 @@ try:
import argostranslate.package
import argostranslate.translate
except ImportError:
- argostranslate = None # type: ignore[assignment]
+ argostranslate = None
try:
from python_pkg.word_frequency.cache import (
@@ -46,6 +46,20 @@ from python_pkg.word_frequency._translator_helpers import (
read_file,
)
+__all__ = [
+ "TranslationResult",
+ "detect_language",
+ "download_languages",
+ "format_translations",
+ "get_available_packages",
+ "get_installed_languages",
+ "main",
+ "read_file",
+ "translate_word",
+ "translate_words",
+ "translate_words_batch",
+]
+
logger = logging.getLogger(__name__)
_BATCH_SIZE = 100
diff --git a/python_pkg/word_frequency/vocabulary_curve.py b/python_pkg/word_frequency/vocabulary_curve.py
index 4682846..b2429df 100755
--- a/python_pkg/word_frequency/vocabulary_curve.py
+++ b/python_pkg/word_frequency/vocabulary_curve.py
@@ -75,7 +75,7 @@ def analyze_excerpt(
ranks.append((rank, word))
else:
# Word not in vocabulary - would need infinite learning
- return float("inf"), [] # type: ignore[return-value]
+ return float("inf"), []
if not ranks:
return 0, []