Skip to content

[codex] Extract magic literal constants#111

Merged
Ahmed-Hindy merged 1 commit into
mainfrom
dev/magic-literal-cleanup
Jun 16, 2026
Merged

[codex] Extract magic literal constants#111
Ahmed-Hindy merged 1 commit into
mainfrom
dev/magic-literal-cleanup

Conversation

@Ahmed-Hindy

@Ahmed-Hindy Ahmed-Hindy commented Jun 16, 2026

Copy link
Copy Markdown
Owner

Summary

  • centralize contact-sheet label metrics and use them in converter + CLI sizing paths
  • extract module-local constants for UI timing/layout, burn-in placement, FFmpeg/logging policy, and replacement audit naming
  • add a regression test to keep converter contact-sheet resolution aligned with renderer label metrics

Why

Gemini flagged a set of magic literals. Most were maintainability-only, but the contact-sheet label height estimate had drifted from the renderer formula, which could make converter output sizing inconsistent with actual contact-sheet rendering.

Validation

  • uv --native-tls run --extra dev ruff check src tests
  • uv --native-tls run --extra dev pytest tests/test_contact_sheet.py tests/test_converter.py tests/test_cli.py tests/test_ui_logic_preview.py tests/test_main_window_settings.py tests/test_logging_utils.py tests/test_sequence_replacement.py tests/test_video_encoder.py
  • uv --native-tls run --extra dev pytest before hook formatting: 176 passed, 9 skipped

Summary by CodeRabbit

Release Notes

  • Refactor

    • Centralized hardcoded configuration values into module-level constants across rendering and UI systems for improved code maintainability and consistency.
    • Extracted contact sheet label metrics into a shared helper function to ensure consistent label sizing calculations.
    • Improved FFmpeg environment variable handling with dedicated constants.
  • Tests

    • Added integration test to verify consistent contact sheet label metric calculations.

@sonarqubecloud

Copy link
Copy Markdown

@codecov-commenter

Copy link
Copy Markdown

@Ahmed-Hindy Ahmed-Hindy self-assigned this Jun 16, 2026
@Ahmed-Hindy
Ahmed-Hindy marked this pull request as ready for review June 16, 2026 12:55
@coderabbitai

coderabbitai Bot commented Jun 16, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR replaces inline hardcoded literals with named module-level constants across 12 files, and extracts the contact sheet label sizing logic into a new public helper compute_contact_sheet_label_metrics. That helper is adopted by the CLI, converter, and a new regression test.

Changes

Magic Number Extraction and Label Metrics Sharing

Layer / File(s) Summary
Shared contact sheet label metrics helper and adoption
src/renderkit/processing/contact_sheet.py, src/renderkit/cli/main.py, src/renderkit/core/converter.py, tests/test_converter.py
compute_contact_sheet_label_metrics(config) is extracted from ContactSheetGenerator._compute_label_metrics as a module-level public helper returning (label_gap, label_h) or (0, 0) when labels are disabled. The CLI removes its private _label_height function and the converter removes its inline font_size * 2.5 formula; both call the shared helper. A new TestSequenceConverterLayout test stubs dependencies and asserts _resolve_output_resolution incorporates the helper's values.
FFmpeg utils and video encoder constants
src/renderkit/core/ffmpeg_utils.py, src/renderkit/processing/video_encoder.py, src/renderkit/core/sequence_replacement.py
_FFMPEG_ENV_VAR centralizes the IMAGEIO_FFMPEG_EXE key in ensure_ffmpeg_env and get_ffmpeg_exe. video_encoder.py introduces constants for _FFREPORT_ENV_VAR, report verbosity, tail line limit, _QUALITY_MAX, and per-codec CRF/QV tuning; updates quality validation, FFmpeg report lifecycle, and x264/x265/AV1/MPEG-4 codec branches to use them. _DEFAULT_AUDIT_FILENAME replaces the hardcoded JSONL filename in replace_sequence_with_mp4.
Burn-in layout and logging constants
src/renderkit/processing/burnin.py, src/renderkit/logging_utils.py
burnin.py adds _BURNIN_EDGE_MARGIN, _BURNIN_BAR_HEIGHT_MULTIPLIER, and _BURNIN_VERTICAL_CENTER_FACTOR, replacing inline 2.0, pixel offset, and centering literals. logging_utils.py adds the Qt signal error string constant and RotatingFileHandler byte/count constants.
UI module constants for window, preview, and contact sheet
src/renderkit/ui/main_window_logic.py, src/renderkit/ui/main_window_ui.py, src/renderkit/ui/timeline_controller.py, src/renderkit/ui/widgets.py
main_window_logic.py adds _PREVIEW_DEBOUNCE_MS, _THUMBNAIL_MAX_DIM, _THUMBNAIL_JPEG_QUALITY, _LOG_SEPARATOR_WIDTH, and _CONTACT_SHEET_DEFAULT_COLUMNS. main_window_ui.py derives window dimensions, responsive breakpoints, log block count, timeline max height, and contact sheet spinbox defaults from new constants including ContactSheetConfig. timeline_controller.py introduces _SCRUB_DEBOUNCE_MS. widgets.py adds fullscreen minimum size, zoom fit margin, zoom step/clamp, and copy-button reset delay constants.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~15 minutes

Poem

🐇 Hop hop, no more magic tricks,
Each number now has a name that sticks!
Label metrics flow from one shared place,
Constants replace the inline chase.
The warren is tidy, the code is bright —
Named values make everything right! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 76.19% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title '[codex] Extract magic literal constants' clearly and concisely summarizes the main objective of the PR: extracting magic literals into named constants throughout the codebase.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dev/magic-literal-cleanup

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
src/renderkit/processing/video_encoder.py (2)

195-196: ⚠️ Potential issue | 🟠 Major

Store self._process.stdin as a non-optional instance attribute after the None check.

Lines 202 and 209 fail type-checking because self._process.stdin remains typed as Optional[IO] outside __init__. The None guard on line 195 does not narrow the type for later method calls. Assign it to self._stdin immediately after the guard, then use that attribute in append_data() and close().

Proposed patch
 class _RawFfmpegPipeWriter:
@@
         if self._process.stdin is None:
             raise RuntimeError("FFmpeg stdin is not available for writing.")
+        self._stdin = self._process.stdin
 
     def append_data(self, frame: np.ndarray) -> None:
@@
-            self._process.stdin.write(frame.tobytes())
+            self._stdin.write(frame.tobytes())
@@
     def close(self) -> None:
         if self._process.poll() is None:
             try:
-                self._process.stdin.close()
+                self._stdin.close()
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/renderkit/processing/video_encoder.py` around lines 195 - 196, The
type-checker cannot narrow the Optional type of self._process.stdin even after
the None guard on line 195, causing type errors in subsequent operations. After
the None check guard in the method containing the RuntimeError, assign
self._process.stdin to a new instance attribute self._stdin (typed as
non-optional IO), then use self._stdin instead of self._process.stdin in both
the append_data() method (around line 202) and the close() method (around line
209) to satisfy type-checking requirements.

252-252: ⚠️ Potential issue | 🟠 Major

Add explicit type annotations for _writer and __exit__ parameters.

The _writer attribute is initialized as None (line 252) but assigned a _RawFfmpegPipeWriter instance (line 460), causing type checker inference conflicts. The __exit__ method parameters lack type annotations. Both need explicit typing.

Proposed patch
+from types import TracebackType
@@
-        self._writer = None
+        self._writer: Optional[_RawFfmpegPipeWriter] = None
@@
-    def __exit__(self, exc_type, exc_val, exc_tb) -> None:
+    def __exit__(
+        self,
+        exc_type: Optional[type[BaseException]],
+        exc_val: Optional[BaseException],
+        exc_tb: Optional[TracebackType],
+    ) -> None:
         """Context manager exit - close video writer."""
         self.close()
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/renderkit/processing/video_encoder.py` at line 252, The _writer attribute
is initialized as None but later assigned a _RawFfmpegPipeWriter instance,
causing type checker inference conflicts, and the __exit__ method parameters
lack type annotations. Add an explicit type annotation to the _writer attribute
to indicate it can be either None or a _RawFfmpegPipeWriter instance (using
Optional or Union typing), and add proper type annotations to all parameters of
the __exit__ method to specify the types for the exception class, value, and
traceback parameters.

Source: Pipeline failures

src/renderkit/core/ffmpeg_utils.py (1)

122-126: ⚠️ Potential issue | 🟠 Major

Guard Windows-only subprocess attributes to resolve type-check failures.

The subprocess.CREATE_NO_WINDOW and subprocess.CREATE_NEW_PROCESS_GROUP attributes are Windows-specific and not available in type stubs on other platforms, causing mypy to fail. Add runtime guards using getattr() with defaults to ensure type compatibility across environments.

The proposed approach using getattr(subprocess, "CREATE_NO_WINDOW", 0) is valid. However, ensure the patched code follows ruff formatting (line-length: 100, double quotes). Consider whether the codebase prefers getattr() guards over TYPE_CHECKING conditionals for similar platform-specific code.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/renderkit/core/ffmpeg_utils.py` around lines 122 - 126, The
Windows-specific subprocess constants (CREATE_NO_WINDOW and
CREATE_NEW_PROCESS_GROUP) cause type-check failures on non-Windows platforms
because they are not available in type stubs. In the code block where os.name
equals "nt" and the creationflags variable is assigned, replace the direct
attribute access to subprocess.CREATE_NO_WINDOW and
subprocess.CREATE_NEW_PROCESS_GROUP with getattr() calls that provide a default
value of 0 to ensure type compatibility across all platforms. Ensure the
modified code follows ruff formatting standards with line-length of 100
characters and uses double quotes for strings.
src/renderkit/logging_utils.py (1)

40-43: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Replace dynamic handler attributes with built-in handler names to unblock mypy.

Type-check is failing at Line 113, Line 127, and Line 145 because renderkit_handler is not a declared attribute on handler types. Use Handler.set_name() / Handler.get_name() as the handler key contract.

Proposed fix
 def _has_handler(logger: logging.Logger, handler_key: str) -> bool:
-    return any(
-        getattr(handler, "renderkit_handler", None) == handler_key for handler in logger.handlers
-    )
+    return any(handler.get_name() == handler_key for handler in logger.handlers)


 def _get_handler(logger: logging.Logger, handler_key: str) -> logging.Handler | None:
     for handler in logger.handlers:
-        if getattr(handler, "renderkit_handler", None) == handler_key:
+        if handler.get_name() == handler_key:
             return handler
     return None
@@
     if file_handler is None:
         file_handler = RotatingFileHandler(
             log_path,
             maxBytes=_LOG_FILE_MAX_BYTES,
             backupCount=_LOG_FILE_BACKUP_COUNT,
             encoding="utf-8",
         )
-        file_handler.renderkit_handler = "file"
+        file_handler.set_name("file")
         file_handler.setFormatter(file_formatter)
         root_logger.addHandler(file_handler)
@@
         if not _has_handler(root_logger, "console"):
             console_handler = logging.StreamHandler()
-            console_handler.renderkit_handler = "console"
+            console_handler.set_name("console")
             console_handler.setLevel(log_level)
             console_handler.setFormatter(console_formatter)
             root_logger.addHandler(console_handler)
@@
         ui_handler = CallbackHandler(ui_sink)
-        ui_handler.renderkit_handler = "ui"
+        ui_handler.set_name("ui")
         ui_handler.setLevel(log_level)
         ui_handler.setFormatter(ui_formatter)
         root_logger.addHandler(ui_handler)

Also applies to: 47-49, 113-113, 127-127, 145-145

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/renderkit/logging_utils.py` around lines 40 - 43, Replace the dynamic
renderkit_handler attribute with the built-in handler name methods to resolve
mypy type checking failures. In the _has_handler function (lines 40-43), replace
the getattr call that checks for renderkit_handler with a call to
handler.get_name() to retrieve the handler's built-in name. At lines 47-49 where
renderkit_handler is being assigned to handlers, replace this with
handler.set_name() to set the handler's built-in name instead. This same pattern
should be applied consistently at lines 113, 127, and 145 where
renderkit_handler is being used, replacing all getattr calls and assignments
with the corresponding get_name() and set_name() method calls respectively.

Source: Pipeline failures

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/renderkit/core/ffmpeg_utils.py`:
- Around line 122-126: The Windows-specific subprocess constants
(CREATE_NO_WINDOW and CREATE_NEW_PROCESS_GROUP) cause type-check failures on
non-Windows platforms because they are not available in type stubs. In the code
block where os.name equals "nt" and the creationflags variable is assigned,
replace the direct attribute access to subprocess.CREATE_NO_WINDOW and
subprocess.CREATE_NEW_PROCESS_GROUP with getattr() calls that provide a default
value of 0 to ensure type compatibility across all platforms. Ensure the
modified code follows ruff formatting standards with line-length of 100
characters and uses double quotes for strings.

In `@src/renderkit/logging_utils.py`:
- Around line 40-43: Replace the dynamic renderkit_handler attribute with the
built-in handler name methods to resolve mypy type checking failures. In the
_has_handler function (lines 40-43), replace the getattr call that checks for
renderkit_handler with a call to handler.get_name() to retrieve the handler's
built-in name. At lines 47-49 where renderkit_handler is being assigned to
handlers, replace this with handler.set_name() to set the handler's built-in
name instead. This same pattern should be applied consistently at lines 113,
127, and 145 where renderkit_handler is being used, replacing all getattr calls
and assignments with the corresponding get_name() and set_name() method calls
respectively.

In `@src/renderkit/processing/video_encoder.py`:
- Around line 195-196: The type-checker cannot narrow the Optional type of
self._process.stdin even after the None guard on line 195, causing type errors
in subsequent operations. After the None check guard in the method containing
the RuntimeError, assign self._process.stdin to a new instance attribute
self._stdin (typed as non-optional IO), then use self._stdin instead of
self._process.stdin in both the append_data() method (around line 202) and the
close() method (around line 209) to satisfy type-checking requirements.
- Line 252: The _writer attribute is initialized as None but later assigned a
_RawFfmpegPipeWriter instance, causing type checker inference conflicts, and the
__exit__ method parameters lack type annotations. Add an explicit type
annotation to the _writer attribute to indicate it can be either None or a
_RawFfmpegPipeWriter instance (using Optional or Union typing), and add proper
type annotations to all parameters of the __exit__ method to specify the types
for the exception class, value, and traceback parameters.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 26868aeb-4910-401e-823a-dcf665614cb5

📥 Commits

Reviewing files that changed from the base of the PR and between d97fb53 and 145310a.

📒 Files selected for processing (13)
  • src/renderkit/cli/main.py
  • src/renderkit/core/converter.py
  • src/renderkit/core/ffmpeg_utils.py
  • src/renderkit/core/sequence_replacement.py
  • src/renderkit/logging_utils.py
  • src/renderkit/processing/burnin.py
  • src/renderkit/processing/contact_sheet.py
  • src/renderkit/processing/video_encoder.py
  • src/renderkit/ui/main_window_logic.py
  • src/renderkit/ui/main_window_ui.py
  • src/renderkit/ui/timeline_controller.py
  • src/renderkit/ui/widgets.py
  • tests/test_converter.py

@Ahmed-Hindy
Ahmed-Hindy merged commit e26bc2b into main Jun 16, 2026
11 checks passed
@Ahmed-Hindy
Ahmed-Hindy deleted the dev/magic-literal-cleanup branch June 16, 2026 16:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants