Skip to content

Handle success banner encoding fallback on Windows - #29

Merged
leynos merged 4 commits into
mainfrom
codex/fix-unicodeencodeerror-on-windows-ci
Sep 27, 2025
Merged

Handle success banner encoding fallback on Windows#29
leynos merged 4 commits into
mainfrom
codex/fix-unicodeencodeerror-on-windows-ci

Conversation

@leynos

@leynos leynos commented Sep 26, 2025

Copy link
Copy Markdown
Owner

Summary

  • add an ASCII fallback for the CLI success banner when stdout cannot encode emoji
  • expose the helper used to pick the banner and cover it with integration tests

Testing

  • make test

https://chatgpt.com/codex/tasks/task_e_68d6aca53f6083228b7c79965eb82d1f

Summary by Sourcery

Provide an ASCII fallback for the CLI success banner on environments with non-UTF-8 encodings and expose the resolution logic for integration testing

New Features:

  • Add resolve_success_banner to fall back to an ASCII success banner when the output stream encoding cannot represent emojis

Enhancements:

  • Invoke resolve_success_banner when printing the CLI success banner to improve cross-platform compatibility

Tests:

  • Add integration tests for resolve_success_banner with various stream encodings

@sourcery-ai

sourcery-ai Bot commented Sep 26, 2025

Copy link
Copy Markdown
Contributor

Reviewer's Guide

Enhance CLI success banner with an encoding-aware fallback, integrate it into the output logic, and verify behavior through parameterized integration tests.

Sequence diagram for CLI success banner output with encoding fallback

sequenceDiagram
    participant main as "main()"
    participant stdout as "sys.stdout (_EncodingAwareStream)"
    participant banner as "resolve_success_banner()"
    main->>banner: resolve_success_banner(stdout)
    alt stdout encoding supports emoji
        banner-->>main: SUCCESS_BANNER
    else encoding does not support emoji
        banner-->>main: ASCII_SUCCESS_BANNER
    end
    main->>stdout: print(banner, flush=True)
Loading

Class diagram for encoding-aware success banner selection

classDiagram
    class _EncodingAwareStream {
        encoding: str | None
    }
    class cli {
        +SUCCESS_BANNER: str
        +ASCII_SUCCESS_BANNER: str
        +resolve_success_banner(stream: _EncodingAwareStream | None): str
    }
    _EncodingAwareStream <|.. cli: uses
Loading

File-Level Changes

Change Details Files
Implement encoding-aware success banner resolution
  • Define _EncodingAwareStream protocol for type hints
  • Add ASCII_SUCCESS_BANNER constant
  • Implement resolve_success_banner function with encoding fallback logic
nixie/cli.py
Integrate fallback helper into CLI output
  • Replace direct SUCCESS_BANNER print with resolve_success_banner(sys.stdout)
nixie/cli.py
Expose and validate fallback behavior via integration tests
  • Import ASCII_SUCCESS_BANNER and resolve_success_banner in tests
  • Add parameterized tests covering various stream encodings
tests/integration/test_cli_behavior.py

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai

coderabbitai Bot commented Sep 26, 2025

Copy link
Copy Markdown
Contributor

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Summary by CodeRabbit

  • New Features
    • Success message now adapts to your terminal’s encoding, showing emoji where supported and an ASCII-only banner otherwise.
    • Improved compatibility across Windows and legacy code pages.
  • Bug Fixes
    • Prevents garbled or missing characters in the success banner on terminals that don’t support Unicode.
  • Tests
    • Added unit and integration tests covering various terminal encodings to ensure correct banner selection and reliable CLI output.

Walkthrough

Introduce encoding-aware success banner selection in the CLI: add ASCII_SUCCESS_BANNER and resolve_success_banner(stream) to choose emoji or ASCII based on stream.encoding, with safe fallbacks on encoding errors; add TYPE_CHECKING stream typing helpers and print the resolved banner at runtime.

Changes

Cohort / File(s) Summary
CLI banner resolution
nixie/cli.py
Add ASCII_SUCCESS_BANNER. Add resolve_success_banner(stream) that inspects stream.encoding and attempts to encode the emoji banner, falling back to ASCII_SUCCESS_BANNER on LookupError, TypeError, or UnicodeError. Replace direct SUCCESS_BANNER use with resolve_success_banner(sys.stdout). Add _EncodingAwareStream protocol and TextIO alias under TYPE_CHECKING.
Tests (integration & unit)
tests/integration/test_cli_behavior.py, tests/unit/test_cli.py
Add tests for resolve_success_banner and CLI output accepting either SUCCESS_BANNER or ASCII_SUCCESS_BANNER. Simulate streams with varied encoding values (utf-8, cp1252, None, unknown, invalid) and assert expected banners. Import ASCII_SUCCESS_BANNER, resolve_success_banner and use helper stream objects.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant U as User
    participant CLI as CLI main
    participant Resolver as resolve_success_banner
    participant Stdout as sys.stdout

    U->>CLI: Run command
    CLI->>Resolver: resolve_success_banner(Stdout)
    Resolver->>Stdout: Read Stdout.encoding
    alt encoding supports emoji
        Resolver-->>CLI: SUCCESS_BANNER (emoji)
    else encoding missing/doesn't support emoji
        Resolver-->>CLI: ASCII_SUCCESS_BANNER
    end
    CLI->>Stdout: Print chosen banner
    note right of Stdout: Ensure printed banner is representable\nby the stream encoding
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

A banner sings in bytes and beams, 🎉
Where stdout tells its coded dreams.
If emojis fail to take the stage,
ASCII steps in, calm and sage.
The CLI smiles; all streams engage.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 55.56% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed Accept the title as it clearly conveys the CLI success banner encoding fallback on Windows in a concise and specific manner.
Description Check ✅ Passed Accept the description as it directly outlines the ASCII fallback for the CLI success banner and the exposure of the helper function along with accompanying tests, aligning with the changeset.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/fix-unicodeencodeerror-on-windows-ci

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d279e48 and a5e1e4d.

📒 Files selected for processing (2)
  • tests/integration/test_cli_behavior.py (3 hunks)
  • tests/unit/test_cli.py (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: Python changes must pass tests (unit and behavioral) before completion/commit
Python code must pass lint checks (make lint)
Python code must adhere to formatting standards (make check-fmt/make fmt)
Python code must pass type checking (make typecheck)
Follow core Python 3.13 style conventions per .rules/python-00.md
Apply best practices for context managers per .rules/python-context-managers.md
Follow generator and iterator patterns per .rules/python-generators.md
Follow function return conventions per .rules/python-return.md
Apply Python typing best practices per .rules/python-typing.md

**/*.py: Name Python files in snake_case (e.g., http_client.py, task_queue.py)
Classes must use PascalCase
Variables and functions must use snake_case
Module-level constants use UPPER_SNAKE_CASE
Prefix non-exported helpers or internal APIs with a single underscore
Use typing everywhere; maintain full static type coverage with Pyright
Use TypedDict or @DataClass for structured data; prefer @DataClass(slots=True) for internal-only
Avoid Any; use Unknown, generics, or cast() with justification if Any is used
Be explicit with return types for all public functions and class methods (e.g., -> None, -> str)
Favor immutability (prefer tuples to lists; use frozendict or types.MappingProxyType where appropriate)
Use # pyright: ignore sparingly and include an explanation when used
Avoid side effects at import time; modules should not modify global state or perform actions on import
Never hardcode secrets in source code
Write NumPy-style docstrings for public functions, classes, and modules
Add inline comments to explain non-obvious logic or decisions

**/*.py: Use context managers to encapsulate setup/teardown for resources (files, locks, connections) instead of manual management
Use @contextmanager from contextlib for straightforward, linear setup/teardown without persistent internal state
Implement a class-based context manager (enter/exit) when there is internal sta...

Files:

  • tests/integration/test_cli_behavior.py
  • tests/unit/test_cli.py

⚙️ CodeRabbit configuration file

**/*.py: - Keep cyclomatic complexity ≤ 12

  • Follow single responsibility and CQRS (command/query segregation)
  • Docstrings must follow the numpy style guide. Use a single-line summary for private functions and methods, and full structured docs for all public interfaces.
  • Move conditionals with >2 branches to predicate/helper functions
  • Avoid eval, exec, pickle, monkey-patching, ctypes, unsafe shell
  • Every module must begin with a triple-quoted docstring explaining its purpose, utility, and usage, including example calls if appropriate.
  • Comments and docs must follow en-GB-oxendict (-ize / -yse / -our) spelling and grammar
  • Lint suppressions:
    • Blanket # noqa, file-level skips, and categories are forbidden
    • Only narrow in-line disables (# noqa: XYZ) are permitted, and must be accompanied by FIXME: or a ticket link, and used only as a last resort.
  • Use pytest fixtures for shared setup (conftest.py or fixtures/)
  • Replace duplicate tests with @pytest.mark.parametrize
  • Prefer pytest-mock or unittest.mock for stubs/mocks
  • Use assert …, "message" over bare asserts
  • Reflect all API/behaviour changes in docs/ and update roadmap on completion
  • Files must not exceed 400 logical lines:
    • Decompose large modules into subpackages
    • Split large match/case or dispatch tables by domain and collocate with targets if appropriate
    • Move bulky data (fixtures, templates) to external files for parsing at runtime
  • Mutable defaults and shadowed built-ins are forbidden
  • All code must have clear type hints using modern style (A | B, list[str], class Foo[A]:, type Bar = int, etc.), with ABC imports drawn from the correct stdlib module.
  • All path manipulation must be performed using pathlib for cross platform safety. Do not use string manipulation for extraction of path components or filename elements.

Files:

  • tests/integration/test_cli_behavior.py
  • tests/unit/test_cli.py
tests/integration/test_*.py

📄 CodeRabbit inference engine (.rules/python-00.md)

Place integration tests under tests/integration/ with files prefixed with test_

Files:

  • tests/integration/test_cli_behavior.py
{**/unittests/test_*.py,tests/integration/test_*.py}

📄 CodeRabbit inference engine (.rules/python-00.md)

{**/unittests/test_*.py,tests/integration/test_*.py}: Use pytest idioms: prefer fixtures, parametrize broadly, avoid unnecessary mocks
Group related tests using classes with method names prefixed by test_
Write tests from a user's perspective; test public behaviour, not internals
Avoid excessive mocking; use doubles only for external services or non-deterministic behaviour

Files:

  • tests/integration/test_cli_behavior.py
🧬 Code graph analysis (2)
tests/integration/test_cli_behavior.py (2)
nixie/cli.py (3)
  • cli (647-664)
  • main (591-613)
  • resolve_success_banner (110-145)
tests/integration/conftest.py (1)
  • stub_render (11-29)
tests/unit/test_cli.py (1)
nixie/cli.py (2)
  • cli (647-664)
  • resolve_success_banner (110-145)
⏰ Context from checks skipped due to timeout of 120000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Sourcery review

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 Ruff (0.13.1)
tests/integration/test_cli_behavior.py

�[1;31mruff failed�[0m
�[1mCause:�[0m Failed to load configuration /ruff.toml
�[1mCause:�[0m Failed to parse /ruff.toml
�[1mCause:�[0m TOML parse error at line 26, column 3
|
26 | "RSE100", # Use of assert detected
| ^^^^^^^^
Unknown rule selector: RSE100

tests/unit/test_cli.py

�[1;31mruff failed�[0m
�[1mCause:�[0m Failed to load configuration /ruff.toml
�[1mCause:�[0m Failed to parse /ruff.toml
�[1mCause:�[0m TOML parse error at line 26, column 3
|
26 | "RSE100", # Use of assert detected
| ^^^^^^^^
Unknown rule selector: RSE100

Warning

Review ran into problems

🔥 Problems

Errors were encountered while retrieving linked issues.

Errors (1)
  • UTF-8: Entity not found: Issue - Could not find referenced Issue.

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

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hey there - I've reviewed your changes and found some issues that need to be addressed.

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location> `nixie/cli.py:122-124` </location>
<code_context>
+    encoding = getattr(stream, "encoding", None)
+    if not encoding:
+        return SUCCESS_BANNER
+    try:
+        SUCCESS_BANNER.encode(encoding)
+    except UnicodeEncodeError:
+        return ASCII_SUCCESS_BANNER
+    return SUCCESS_BANNER
</code_context>

<issue_to_address>
**suggestion:** Consider catching broader encoding errors, not just UnicodeEncodeError.

Other exceptions like LookupError may also occur during encoding. Consider handling these to improve robustness.
</issue_to_address>

### Comment 2
<location> `tests/integration/test_cli_behavior.py:276-281` </location>
<code_context>
     assert len(end_markers) == 1, "Expected one end marker despite the failure"
+
+
+@pytest.mark.parametrize(
+    ("stream", "expected"),
+    [
+        (SimpleNamespace(encoding="utf-8"), SUCCESS_BANNER),
+        (SimpleNamespace(encoding="cp1252"), ASCII_SUCCESS_BANNER),
+        (SimpleNamespace(encoding=None), SUCCESS_BANNER),
+        (None, SUCCESS_BANNER),
+    ],
+)
+def test_resolve_success_banner_handles_non_utf8_streams(
+    stream: SimpleNamespace | None, expected: str
+) -> None:
</code_context>

<issue_to_address>
**suggestion (testing):** Consider adding a test case for streams with unknown or invalid encodings.

Adding a test with an invalid encoding (e.g., 'unknown-encoding') will help verify that the fallback logic works correctly and handles unexpected values gracefully.

```suggestion
    [
        (SimpleNamespace(encoding="utf-8"), SUCCESS_BANNER),
        (SimpleNamespace(encoding="cp1252"), ASCII_SUCCESS_BANNER),
        (SimpleNamespace(encoding=None), SUCCESS_BANNER),
        (None, SUCCESS_BANNER),
        (SimpleNamespace(encoding="unknown-encoding"), SUCCESS_BANNER),
    ],
```
</issue_to_address>

### Comment 3
<location> `nixie/cli.py:107` </location>
<code_context>
+ASCII_SUCCESS_BANNER: typ.Final[str] = "All diagrams validated successfully!"
+
+
+def resolve_success_banner(stream: _EncodingAwareStream | None) -> str:
+    """Return a stream-compatible success banner.
+
</code_context>

<issue_to_address>
**issue (review_instructions):** Add behavioural and unit tests for the new resolve_success_banner function.

The resolve_success_banner function is a new feature that determines which success banner to display based on stream encoding. You must add both behavioural and unit tests to verify its correct operation, including cases for UTF-8, cp1252, and None encodings.

<details>
<summary>Review instructions:</summary>

**Path patterns:** `**/*`

**Instructions:**
For any new feature or change to an existing feature, both behavioural *and* unit tests are required.

</details>
</issue_to_address>

### Comment 4
<location> `nixie/cli.py:593` </location>
<code_context>
             print(f"<== {path}")
         if all_success:
-            print(SUCCESS_BANNER, flush=True)
+            print(resolve_success_banner(sys.stdout), flush=True)
         return 0 if all_success else 1

</code_context>

<issue_to_address>
**issue (review_instructions):** Add behavioural tests for CLI output with different stream encodings.

Since the CLI now conditionally prints different banners based on stream encoding, you must add behavioural tests that exercise this logic, ensuring the correct banner is printed for various encodings.

<details>
<summary>Review instructions:</summary>

**Path patterns:** `**/*`

**Instructions:**
For any new feature or change to an existing feature, both behavioural *and* unit tests are required.

</details>
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread nixie/cli.py Outdated
Comment thread tests/integration/test_cli_behavior.py

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (2)
tests/integration/test_cli_behavior.py (2)

109-113: Make success‑path assertion encoding‑agnostic.

The CLI now prints either the emoji or ASCII banner depending on sys.stdout.encoding. The current assertion fails on Windows/cp1252.

Apply this diff:

-    if expected_exit == 0:
-        assert captured.out.count(SUCCESS_BANNER) == 1
-    else:
-        assert captured.out.count(SUCCESS_BANNER) == 0
+    if expected_exit == 0:
+        assert any(
+            captured.out.count(banner) == 1
+            for banner in (SUCCESS_BANNER, ASCII_SUCCESS_BANNER)
+        )
+    else:
+        assert captured.out.count(SUCCESS_BANNER) == 0
+        assert captured.out.count(ASCII_SUCCESS_BANNER) == 0

As per coding guidelines


274-289: Add a case for unknown encodings to validate robustness.

Exercise the LookupError path to ensure a safe ASCII fallback once implemented.

Apply this diff after hardening the resolver:

 @pytest.mark.parametrize(
     ("stream", "expected"),
     [
         (SimpleNamespace(encoding="utf-8"), SUCCESS_BANNER),
         (SimpleNamespace(encoding="cp1252"), ASCII_SUCCESS_BANNER),
         (SimpleNamespace(encoding=None), SUCCESS_BANNER),
         (None, SUCCESS_BANNER),
+        (SimpleNamespace(encoding="not-an-encoding"), ASCII_SUCCESS_BANNER),
     ],
 )
 def test_resolve_success_banner_handles_non_utf8_streams(
     stream: SimpleNamespace | None, expected: str
 ) -> None:
     """Prefer the celebratory banner but fall back when encoding rejects it."""
 
     assert resolve_success_banner(stream) == expected

As per coding guidelines

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9e902fd and 2e8c613.

📒 Files selected for processing (2)
  • nixie/cli.py (3 hunks)
  • tests/integration/test_cli_behavior.py (2 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: Python changes must pass tests (unit and behavioral) before completion/commit
Python code must pass lint checks (make lint)
Python code must adhere to formatting standards (make check-fmt/make fmt)
Python code must pass type checking (make typecheck)
Follow core Python 3.13 style conventions per .rules/python-00.md
Apply best practices for context managers per .rules/python-context-managers.md
Follow generator and iterator patterns per .rules/python-generators.md
Follow function return conventions per .rules/python-return.md
Apply Python typing best practices per .rules/python-typing.md

**/*.py: Name Python files in snake_case (e.g., http_client.py, task_queue.py)
Classes must use PascalCase
Variables and functions must use snake_case
Module-level constants use UPPER_SNAKE_CASE
Prefix non-exported helpers or internal APIs with a single underscore
Use typing everywhere; maintain full static type coverage with Pyright
Use TypedDict or @DataClass for structured data; prefer @DataClass(slots=True) for internal-only
Avoid Any; use Unknown, generics, or cast() with justification if Any is used
Be explicit with return types for all public functions and class methods (e.g., -> None, -> str)
Favor immutability (prefer tuples to lists; use frozendict or types.MappingProxyType where appropriate)
Use # pyright: ignore sparingly and include an explanation when used
Avoid side effects at import time; modules should not modify global state or perform actions on import
Never hardcode secrets in source code
Write NumPy-style docstrings for public functions, classes, and modules
Add inline comments to explain non-obvious logic or decisions

**/*.py: Use context managers to encapsulate setup/teardown for resources (files, locks, connections) instead of manual management
Use @contextmanager from contextlib for straightforward, linear setup/teardown without persistent internal state
Implement a class-based context manager (enter/exit) when there is internal sta...

Files:

  • nixie/cli.py
  • tests/integration/test_cli_behavior.py

⚙️ CodeRabbit configuration file

**/*.py: - Keep cyclomatic complexity ≤ 12

  • Follow single responsibility and CQRS (command/query segregation)
  • Docstrings must follow the numpy style guide. Use a single-line summary for private functions and methods, and full structured docs for all public interfaces.
  • Move conditionals with >2 branches to predicate/helper functions
  • Avoid eval, exec, pickle, monkey-patching, ctypes, unsafe shell
  • Every module must begin with a triple-quoted docstring explaining its purpose, utility, and usage, including example calls if appropriate.
  • Comments and docs must follow en-GB-oxendict (-ize / -yse / -our) spelling and grammar
  • Lint suppressions:
    • Blanket # noqa, file-level skips, and categories are forbidden
    • Only narrow in-line disables (# noqa: XYZ) are permitted, and must be accompanied by FIXME: or a ticket link, and used only as a last resort.
  • Use pytest fixtures for shared setup (conftest.py or fixtures/)
  • Replace duplicate tests with @pytest.mark.parametrize
  • Prefer pytest-mock or unittest.mock for stubs/mocks
  • Use assert …, "message" over bare asserts
  • Reflect all API/behaviour changes in docs/ and update roadmap on completion
  • Files must not exceed 400 logical lines:
    • Decompose large modules into subpackages
    • Split large match/case or dispatch tables by domain and collocate with targets if appropriate
    • Move bulky data (fixtures, templates) to external files for parsing at runtime
  • Mutable defaults and shadowed built-ins are forbidden
  • All code must have clear type hints using modern style (A | B, list[str], class Foo[A]:, type Bar = int, etc.), with ABC imports drawn from the correct stdlib module.
  • All path manipulation must be performed using pathlib for cross platform safety. Do not use string manipulation for extraction of path components or filename elements.

Files:

  • nixie/cli.py
  • tests/integration/test_cli_behavior.py
tests/integration/test_*.py

📄 CodeRabbit inference engine (.rules/python-00.md)

Place integration tests under tests/integration/ with files prefixed with test_

Files:

  • tests/integration/test_cli_behavior.py
{**/unittests/test_*.py,tests/integration/test_*.py}

📄 CodeRabbit inference engine (.rules/python-00.md)

{**/unittests/test_*.py,tests/integration/test_*.py}: Use pytest idioms: prefer fixtures, parametrize broadly, avoid unnecessary mocks
Group related tests using classes with method names prefixed by test_
Write tests from a user's perspective; test public behaviour, not internals
Avoid excessive mocking; use doubles only for external services or non-deterministic behaviour

Files:

  • tests/integration/test_cli_behavior.py
🧬 Code graph analysis (1)
tests/integration/test_cli_behavior.py (1)
nixie/cli.py (3)
  • cli (628-645)
  • main (572-594)
  • resolve_success_banner (107-126)
⏰ Context from checks skipped due to timeout of 120000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Sourcery review
🔇 Additional comments (5)
nixie/cli.py (3)

82-86: Keep Protocol type under TYPE_CHECKING; good runtime footprint.

Avoid importing Protocol at runtime; this pattern is correct.


103-105: Add ASCII fallback constant; good default for legacy consoles.

The banner text is stable and suitable for tests.


593-593: Route final output through resolver; correct behaviour.

Print via resolve_success_banner(sys.stdout) to avoid UnicodeEncodeError on Windows.

tests/integration/test_cli_behavior.py (2)

4-4: Import SimpleNamespace for stream doubles; fine.

The test double matches the Protocol surface needed by the resolver.


9-15: Import new public APIs; fine.

The tests import only public symbols exposed by nixie.cli.

Comment thread nixie/cli.py Outdated
@leynos
leynos merged commit 5c53bdf into main Sep 27, 2025
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant