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, []