Skip to content

Add verbose option for subcommand logging#7

Merged
leynos merged 4 commits intomainfrom
5d6gfp-codex/add-verbose-option-for-sub-command-logging
Aug 6, 2025
Merged

Add verbose option for subcommand logging#7
leynos merged 4 commits intomainfrom
5d6gfp-codex/add-verbose-option-for-sub-command-logging

Conversation

@leynos
Copy link
Owner

@leynos leynos commented Aug 6, 2025

Summary

  • add --verbose flag to print the command used for each diagram
  • document the new option in README
  • test verbose behavior and CLI flag propagation

Testing

  • ruff check nixie tests
  • pyright
  • python -m pytest

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

Summary by Sourcery

Introduce a verbose mode that prints the exact mermaid-cli invocation for each diagram, update the CLI and core functions to accept and propagate the flag, document it in the README, and add tests to ensure correct behavior.

New Features:

  • Add a --verbose CLI flag to enable printing of the mermaid-cli command for each diagram

Enhancements:

  • Propagate the verbose flag through main, check_file, and render_block functions to control logging

Documentation:

  • Update README to document the new --verbose option

Tests:

  • Add unit and integration tests to verify verbose flag parsing and command emission

@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Aug 6, 2025

Reviewer's Guide

This PR introduces a new --verbose flag that is parsed from the CLI, propagated through render_block, check_file, and main functions, and conditionally prints each mermaid-cli invocation; it also updates documentation and adds comprehensive tests to verify verbose behavior and flag propagation.

Sequence diagram for --verbose flag propagation and command printing

sequenceDiagram
    actor User
    participant CLI as cli()
    participant Args as parse_args()
    participant Main as main()
    participant Check as check_file()
    participant Render as render_block()

    User->>CLI: Run nixie --verbose FILE
    CLI->>Args: parse_args()
    Args-->>CLI: Namespace with verbose=True
    CLI->>Main: main(paths, concurrency, verbose=True)
    Main->>Check: check_file(path, cfg_path, semaphore, verbose=True)
    Check->>Render: render_block(..., verbose=True)
    Render->>Render: print(shlex.join(cmd)) if verbose
Loading

Class diagram for CLI argument propagation with --verbose flag

classDiagram
    class CLI {
        +cli()
    }
    class parse_args {
        +parse_args() : argparse.Namespace
    }
    class main {
        +main(paths, max_concurrent, verbose=False)
    }
    class check_file {
        +check_file(path, cfg_path, semaphore, verbose=False)
    }
    class render_block {
        +render_block(block, tmpdir, cfg_path, path, idx, semaphore, timeout=30.0, verbose=False)
    }

    CLI --> parse_args : calls
    CLI --> main : calls
    parse_args --> main : passes parsed.verbose
    main --> check_file : passes verbose
    check_file --> render_block : passes verbose
Loading

File-Level Changes

Change Details Files
Add and propagate verbose flag through CLI and rendering logic
  • Added verbose parameter to render_block signature
  • Print command via shlex.join when verbose is true
  • Propagate verbose argument through check_file and main functions
  • Extended parse_args and cli to include and pass --verbose flag
nixie/cli.py
Document new verbose option in usage instructions
  • Added --verbose flag to the command usage in README
  • Provided description of verbose behavior in README
README.md
Add tests to verify verbose behavior and flag propagation
  • Updated integration tests to assert stub_render receives verbose=True
  • Extended conftest stub functions to accept verbose parameter
  • Created unit tests for parse_args and render_block verbose output
tests/integration/test_cli_behavior.py
tests/integration/conftest.py
nixie/unittests/test_verbose.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
Copy link
Contributor

coderabbitai bot commented Aug 6, 2025

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

  • Documentation
    • Updated the README to include information on the new optional --verbose command-line flag, explaining its effect on logging.
  • New Features
    • Added a --verbose flag to the command-line interface to enable logging of the exact Mermaid CLI commands executed.
  • Tests
    • Introduced new tests to verify verbose logging behaviour and correct argument parsing for the --verbose flag.

Walkthrough

Update the nixie CLI tool to support a new --verbose flag, enabling INFO-level logging of the exact Mermaid CLI commands executed. Adjust the README to document this flag. Refactor argument parsing and logging setup. Add new unit tests to verify verbose logging behaviour and argument parsing accuracy.

Changes

Cohort / File(s) Change Summary
README and Documentation
README.md
Update usage instructions to include the new --verbose flag and describe its effect on command logging.
CLI Implementation
nixie/cli.py
Add --verbose argument, configure logging accordingly, log Mermaid CLI commands when verbose is enabled, and refactor function signatures for clarity.
Verbose Logging Tests
nixie/unittests/test_verbose.py
Introduce tests for verbose argument parsing and logging, including async tests for command logging behaviour with and without verbose mode.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant CLI
    participant Logger
    participant MermaidCLI

    User->>CLI: Run nixie [--verbose] [--concurrency N] <files>
    CLI->>CLI: Parse arguments
    alt --verbose flag set
        CLI->>Logger: Set level to INFO
    else
        CLI->>Logger: Set level to WARNING
    end
    CLI->>MermaidCLI: Build command
    alt --verbose flag set
        CLI->>Logger: Log executed command (INFO)
    end
    CLI->>MermaidCLI: Execute command
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~7 minutes

Possibly related PRs

Poem

A whisper grows into a shout,
With --verbose, the logs spill out.
Commands once hidden, now in light,
For every Mermaid's rendered sight.
Tests and docs in tidy rows,
Where clarity and insight flows!
🐚✨


📜 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 5ca6372 and e68c144.

📒 Files selected for processing (1)
  • nixie/cli.py (6 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

📄 CodeRabbit Inference Engine (AGENTS.md)

For Python files: Pass all relevant unit and behavioral tests, pass lint checks (ruff check), adhere to formatting standards (ruff format), and pass type checking (pyright).

**/*.py: Use snake_case.py for file names, naming files for their contents (e.g., http_client.py, task_queue.py)
Use PascalCase for class names in Python files
Use snake_case for variable and function names in Python files
Use UPPER_SNAKE_CASE for module-level constants in Python files
Prefix private/internal helpers or APIs with a single underscore (_) in Python files
Use typing everywhere and maintain full static type coverage in Python files; use Pyright for type-checking
Use TypedDict or Dataclass for structured data where appropriate; for internal-only usage, prefer @DataClass(slots=True)
Avoid Any in type annotations; use Unknown, generics, or cast() when necessary, and always document why Any is acceptable if used
Be explicit with return types in public functions and class methods (e.g., use -> None, -> str, etc.)
Favor immutability in Python files; prefer tuples over lists, and frozendict or types.MappingProxyType where appropriate
Enable Ruff for linting and formatting; use Ruff to lint for performance, security, consistency, and style issues, and let Ruff handle whitespace and formatting entirely
Enforce strict mode in Pyright and treat all Pyright warnings as CI errors; use # pyright: ignore sparingly and with explanation
Avoid side effects at import time in Python modules; modules should not modify global state or perform actions on import
Use docstrings to document public functions, classes, and modules using NumPy format
Explain tricky code with inline comments for non-obvious logic or decisions in Python files

**/*.py: Use context managers to encapsulate setup and teardown logic cleanly and safely, especially for resource management (files, locks, connections, etc.), instead of manual try/finally blocks.
Use @contextmanager from contextlib for straightforward proce...

Files:

  • nixie/cli.py

⚙️ CodeRabbit Configuration File

**/*.py: How about the following?

- 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 / -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.

Files:

  • nixie/cli.py
🔇 Additional comments (7)
nixie/cli.py (7)

7-7: LGTM: Import additions are appropriate.

The logging and shlex imports are correctly placed and necessary for the verbose logging functionality.

Also applies to: 10-10


118-146: LGTM: Docstring addresses the past review comment.

The expanded NumPy-style docstring now properly documents all parameters including the new verbose behaviour. This resolves the previous suggestion about documenting the verbose parameter.


154-154: LGTM: Command logging implementation is correct.

The use of shlex.join(cmd) ensures proper shell escaping of the logged command, and logging at INFO level aligns with the verbose flag behaviour.


194-214: LGTM: Function signature reformatting improves readability.

The multi-line parameter formatting in check_file and the render_block call enhances code readability whilst maintaining identical functionality.


249-249: LGTM: Return type annotation follows guidelines.

Adding the explicit -> argparse.Namespace return type annotation adheres to the coding guideline requiring explicit return types for public functions.


266-270: LGTM: Verbose flag implementation is correct.

The --verbose argument uses appropriate store_true action and provides clear help text explaining its purpose.


277-280: LGTM: Logging configuration correctly implements verbose behaviour.

The conditional logging level configuration properly enables INFO-level logging when verbose is set, otherwise defaults to WARNING level. Outputting to sys.stderr is appropriate for logging.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 5d6gfp-codex/add-verbose-option-for-sub-command-logging

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

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

  • Rather than sprinkling print statements for verbose output, consider using the Python logging module at a DEBUG or INFO level so users can configure verbosity without mixing it into functional stdout.
  • The verbose flag is being threaded through main, check_file, and render_block; you might simplify this by encapsulating CLI options in a context or class to avoid changing every function signature.
  • Since verbose info is primarily diagnostic, it would be better sent to stderr instead of stdout, preventing it from interfering with normal CLI output or piping scenarios.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- Rather than sprinkling print statements for verbose output, consider using the Python logging module at a DEBUG or INFO level so users can configure verbosity without mixing it into functional stdout.
- The `verbose` flag is being threaded through `main`, `check_file`, and `render_block`; you might simplify this by encapsulating CLI options in a context or class to avoid changing every function signature.
- Since verbose info is primarily diagnostic, it would be better sent to stderr instead of stdout, preventing it from interfering with normal CLI output or piping scenarios.

## Individual Comments

### Comment 1
<location> `nixie/cli.py:116` </location>
<code_context>
     idx: int,
     semaphore: asyncio.Semaphore,
     timeout: float = 30.0,
+    verbose: bool = False,
 ) -> bool:
     """Render a single mermaid block using the CLI asynchronously."""
</code_context>

<issue_to_address>
Consider documenting the new 'verbose' parameter in the function docstring.

Adding this detail will make the function's usage clearer for future maintainers.
</issue_to_address>

<suggested_fix>
<<<<<<< SEARCH
) -> bool:
    """Render a single mermaid block using the CLI asynchronously."""
=======
) -> bool:
    """
    Render a single mermaid block using the CLI asynchronously.

    Args:
        idx (int): Index of the block.
        semaphore (asyncio.Semaphore): Semaphore to limit concurrency.
        timeout (float, optional): Timeout for the operation. Defaults to 30.0.
        verbose (bool, optional): If True, prints the CLI command being executed. Defaults to False.
    """
>>>>>>> REPLACE

</suggested_fix>

### Comment 2
<location> `nixie/unittests/test_verbose.py:21` </location>
<code_context>
     assert "Simulated processing error" in captured.out
+
+
+@pytest.mark.asyncio
+async def test_cli_passes_verbose_flag(tmp_path: Path, stub_render: AsyncMock) -> None:
+    file_a = tmp_path / "a.md"
+    file_a.write_text("```mermaid\nA-->B\n```")
+
+    await main([file_a], 2, verbose=True)
+
+    assert stub_render.await_count == 1
+    assert stub_render.await_args_list[0].kwargs["verbose"] is True
</code_context>

<issue_to_address>
Test for render_block with verbose covers output, but could use an error case.

Consider adding a test for when verbose is False to ensure no command output is printed, preventing unintended verbose output in the future.
</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.

nixie/cli.py Outdated
Comment on lines 117 to 118
) -> bool:
"""Render a single mermaid block using the CLI asynchronously."""
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion: Consider documenting the new 'verbose' parameter in the function docstring.

Adding this detail will make the function's usage clearer for future maintainers.

Suggested change
) -> bool:
"""Render a single mermaid block using the CLI asynchronously."""
) -> bool:
"""
Render a single mermaid block using the CLI asynchronously.
Args:
idx (int): Index of the block.
semaphore (asyncio.Semaphore): Semaphore to limit concurrency.
timeout (float, optional): Timeout for the operation. Defaults to 30.0.
verbose (bool, optional): If True, prints the CLI command being executed. Defaults to False.
"""

Copy link
Owner Author

Choose a reason for hiding this comment

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

Has this now been resolved?

Copy link
Contributor

Choose a reason for hiding this comment

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

It looks like the suggestion to document the 'verbose' parameter in the render_block function's docstring has not yet been addressed. The current docstring does not mention the 'verbose' parameter or its purpose. To fully resolve the suggestion, please update the docstring to include a description of the 'verbose' argument and its effect on the function's behavior.

Copy link
Owner Author

Choose a reason for hiding this comment

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

Has this now been resolved?

Copy link
Contributor

Choose a reason for hiding this comment

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

The suggestion to document the 'verbose' parameter in the render_block function's docstring has not yet been resolved. In the current state of the PR, while the verbose parameter is being added to the function signature, the docstring does not mention this new parameter or its effect. To fully address the suggestion, please update the docstring for render_block to include a description of the verbose argument and how it influences the function's behavior (e.g., printing/logging the CLI command when enabled).

Copy link
Owner Author

Choose a reason for hiding this comment

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

New GitHub issue, please

Copy link
Contributor

Choose a reason for hiding this comment

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

I have created an issue for your comment: #8

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

♻️ Duplicate comments (1)
nixie/cli.py (1)

109-117: Add documentation for the verbose functionality.

The function signature is missing documentation for how the verbose logging behaviour is controlled, which was previously suggested in a past review.

Add the verbose parameter documentation to the docstring:

 async def render_block(
     block: str,
     tmpdir: Path,
     cfg_path: Path,
     path: Path,
     idx: int,
     semaphore: asyncio.Semaphore,
     timeout: float = 30.0,
 ) -> bool:
-    """Render a single mermaid block using the CLI asynchronously."""
+    """
+    Render a single mermaid block using the CLI asynchronously.
+
+    Logs the exact mermaid-cli command at INFO level when verbose logging is enabled.
+    """
📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 40cde41 and 4b9f4c0.

📒 Files selected for processing (3)
  • README.md (1 hunks)
  • nixie/cli.py (6 hunks)
  • nixie/unittests/test_verbose.py (1 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
**/*.md

📄 CodeRabbit Inference Engine (AGENTS.md)

For Markdown files (.md only): Pass lint checks (markdownlint filename.md).

Files:

  • README.md

⚙️ CodeRabbit Configuration File

**/*.md: * Avoid 2nd person or 1st person pronouns ("I", "you", "we")

  • Use en-GB-oxendict (-ize / -our) spelling and grammar
  • Paragraphs and bullets must be wrapped to 80 columns, except where a long URL would prevent this (in which case, silence MD013 for that line)
  • Code blocks should be wrapped to 120 columns.
  • Headings must not be wrapped.
  • Documents must start with a level 1 heading
  • Headings must correctly increase or decrease by no more than one level at a time
  • Use GitHub-flavoured Markdown style for footnotes and endnotes.
  • Numbered footnotes must be numbered by order of appearance in the document.

Files:

  • README.md
{**/README.md,**/docs/**}

📄 CodeRabbit Inference Engine (.rules/python-00.mdc)

Colocate documentation by keeping README.md or docs/ near reusable packages and include usage examples

Files:

  • README.md
**/*.py

📄 CodeRabbit Inference Engine (AGENTS.md)

For Python files: Pass all relevant unit and behavioral tests, pass lint checks (ruff check), adhere to formatting standards (ruff format), and pass type checking (pyright).

**/*.py: Use snake_case.py for file names, naming files for their contents (e.g., http_client.py, task_queue.py)
Use PascalCase for class names in Python files
Use snake_case for variable and function names in Python files
Use UPPER_SNAKE_CASE for module-level constants in Python files
Prefix private/internal helpers or APIs with a single underscore (_) in Python files
Use typing everywhere and maintain full static type coverage in Python files; use Pyright for type-checking
Use TypedDict or Dataclass for structured data where appropriate; for internal-only usage, prefer @DataClass(slots=True)
Avoid Any in type annotations; use Unknown, generics, or cast() when necessary, and always document why Any is acceptable if used
Be explicit with return types in public functions and class methods (e.g., use -> None, -> str, etc.)
Favor immutability in Python files; prefer tuples over lists, and frozendict or types.MappingProxyType where appropriate
Enable Ruff for linting and formatting; use Ruff to lint for performance, security, consistency, and style issues, and let Ruff handle whitespace and formatting entirely
Enforce strict mode in Pyright and treat all Pyright warnings as CI errors; use # pyright: ignore sparingly and with explanation
Avoid side effects at import time in Python modules; modules should not modify global state or perform actions on import
Use docstrings to document public functions, classes, and modules using NumPy format
Explain tricky code with inline comments for non-obvious logic or decisions in Python files

**/*.py: Use context managers to encapsulate setup and teardown logic cleanly and safely, especially for resource management (files, locks, connections, etc.), instead of manual try/finally blocks.
Use @contextmanager from contextlib for straightforward proce...

Files:

  • nixie/cli.py
  • nixie/unittests/test_verbose.py

⚙️ CodeRabbit Configuration File

**/*.py: How about the following?

- 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 / -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.

Files:

  • nixie/cli.py
  • nixie/unittests/test_verbose.py
**/unittests/test_*.py

📄 CodeRabbit Inference Engine (.rules/python-00.mdc)

Colocate unit tests with code using a unittests subdirectory and a test_ prefix for test files

Files:

  • nixie/unittests/test_verbose.py
**/test_*.py

📄 CodeRabbit Inference Engine (.rules/python-00.mdc)

**/test_*.py: Use pytest idioms in test files: prefer fixtures over setup/teardown methods, parametrize broadly, and avoid unnecessary mocks
Group related tests using class with method names prefixed by test_ in test files

Files:

  • nixie/unittests/test_verbose.py
🪛 Ruff (0.12.2)
nixie/unittests/test_verbose.py

15-15: Missing type annotation for function argument monkeypatch

(ANN001)


24-24: Missing type annotation for function argument monkeypatch

(ANN001)


24-24: Trailing comma missing

Add trailing comma

(COM812)


31-31: Missing return type annotation for private function fake_create_subprocess_exec

(ANN202)


31-31: Missing type annotation for *cmd

(ANN002)


31-31: Unused function argument: cmd

(ARG001)


31-31: Missing type annotation for **kwargs

(ANN003)


31-31: Unused function argument: kwargs

(ARG001)


34-34: Missing return type annotation for private function fake_wait_for_proc

(ANN202)


34-34: Missing type annotation for function argument proc

(ANN001)


34-34: Unused function argument: proc

(ARG001)


34-34: Missing type annotation for function argument path

(ANN001)


34-34: Unused function argument: path

(ARG001)


34-34: Missing type annotation for function argument idx

(ANN001)


34-34: Unused function argument: idx

(ARG001)


34-34: Async function definition with a timeout parameter

(ASYNC109)


34-34: Missing type annotation for function argument timeout

(ANN001)


34-34: Unused function argument: timeout

(ARG001)


39-39: Unused lambda argument: cmd

(ARG005)


53-53: Missing type annotation for function argument monkeypatch

(ANN001)


53-53: Trailing comma missing

Add trailing comma

(COM812)


60-60: Missing return type annotation for private function fake_create_subprocess_exec

(ANN202)


60-60: Missing type annotation for *cmd

(ANN002)


60-60: Unused function argument: cmd

(ARG001)


60-60: Missing type annotation for **kwargs

(ANN003)


60-60: Unused function argument: kwargs

(ARG001)


63-63: Missing return type annotation for private function fake_wait_for_proc

(ANN202)


63-63: Missing type annotation for function argument proc

(ANN001)


63-63: Unused function argument: proc

(ARG001)


63-63: Missing type annotation for function argument path

(ANN001)


63-63: Unused function argument: path

(ARG001)


63-63: Missing type annotation for function argument idx

(ANN001)


63-63: Unused function argument: idx

(ARG001)


63-63: Async function definition with a timeout parameter

(ASYNC109)


63-63: Missing type annotation for function argument timeout

(ANN001)


63-63: Unused function argument: timeout

(ARG001)


68-68: Unused lambda argument: cmd

(ARG005)

🔇 Additional comments (8)
README.md (2)

43-43: LGTM!

The usage syntax correctly shows the new optional --verbose flag alongside the existing --concurrency option.


50-51: LGTM!

The explanation clearly describes the purpose of the --verbose flag, matching the implementation that logs the exact mermaid-cli command for each diagram.

nixie/cli.py (5)

7-7: LGTM!

The logging and shlex imports are correctly added to support the new verbose functionality.

Also applies to: 10-10


126-126: LGTM!

The verbose logging implementation correctly uses the module logger and shlex.join() to create a shell-safe command string. The logging happens at INFO level, which is appropriate for this type of operational information.


221-221: LGTM!

Adding the explicit return type annotation improves type safety and follows the coding guidelines.


238-242: LGTM!

The --verbose argument implementation is correct with appropriate help text that clearly describes the functionality.


249-252: LGTM!

The logging configuration correctly sets INFO level when verbose is enabled and WARNING otherwise, with output directed to stderr as expected for CLI tools.

nixie/unittests/test_verbose.py (1)

15-77: LGTM on test logic!

The test coverage is comprehensive and correctly validates both the argument parsing and the verbose logging behaviour. The tests properly mock the subprocess execution and verify that commands are logged only when verbose mode is enabled.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (1)
nixie/cli.py (1)

118-142: Well-documented function with comprehensive NumPy-style docstring.

The docstring properly documents all parameters and return values in the required NumPy format. The documentation clearly explains the new logging behaviour when verbose mode is enabled.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4b9f4c0 and 5ca6372.

📒 Files selected for processing (2)
  • nixie/cli.py (6 hunks)
  • nixie/unittests/test_verbose.py (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.py

📄 CodeRabbit Inference Engine (AGENTS.md)

For Python files: Pass all relevant unit and behavioral tests, pass lint checks (ruff check), adhere to formatting standards (ruff format), and pass type checking (pyright).

**/*.py: Use snake_case.py for file names, naming files for their contents (e.g., http_client.py, task_queue.py)
Use PascalCase for class names in Python files
Use snake_case for variable and function names in Python files
Use UPPER_SNAKE_CASE for module-level constants in Python files
Prefix private/internal helpers or APIs with a single underscore (_) in Python files
Use typing everywhere and maintain full static type coverage in Python files; use Pyright for type-checking
Use TypedDict or Dataclass for structured data where appropriate; for internal-only usage, prefer @DataClass(slots=True)
Avoid Any in type annotations; use Unknown, generics, or cast() when necessary, and always document why Any is acceptable if used
Be explicit with return types in public functions and class methods (e.g., use -> None, -> str, etc.)
Favor immutability in Python files; prefer tuples over lists, and frozendict or types.MappingProxyType where appropriate
Enable Ruff for linting and formatting; use Ruff to lint for performance, security, consistency, and style issues, and let Ruff handle whitespace and formatting entirely
Enforce strict mode in Pyright and treat all Pyright warnings as CI errors; use # pyright: ignore sparingly and with explanation
Avoid side effects at import time in Python modules; modules should not modify global state or perform actions on import
Use docstrings to document public functions, classes, and modules using NumPy format
Explain tricky code with inline comments for non-obvious logic or decisions in Python files

**/*.py: Use context managers to encapsulate setup and teardown logic cleanly and safely, especially for resource management (files, locks, connections, etc.), instead of manual try/finally blocks.
Use @contextmanager from contextlib for straightforward proce...

Files:

  • nixie/unittests/test_verbose.py
  • nixie/cli.py

⚙️ CodeRabbit Configuration File

**/*.py: How about the following?

- 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 / -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.

Files:

  • nixie/unittests/test_verbose.py
  • nixie/cli.py
**/unittests/test_*.py

📄 CodeRabbit Inference Engine (.rules/python-00.mdc)

Colocate unit tests with code using a unittests subdirectory and a test_ prefix for test files

Files:

  • nixie/unittests/test_verbose.py
**/test_*.py

📄 CodeRabbit Inference Engine (.rules/python-00.mdc)

**/test_*.py: Use pytest idioms in test files: prefer fixtures over setup/teardown methods, parametrize broadly, and avoid unnecessary mocks
Group related tests using class with method names prefixed by test_ in test files

Files:

  • nixie/unittests/test_verbose.py
🪛 Ruff (0.12.2)
nixie/unittests/test_verbose.py

33-33: Unused function argument: cmd

(ARG001)


33-33: Unused function argument: kwargs

(ARG001)


37-37: Unused function argument: proc

(ARG001)


37-37: Unused function argument: path

(ARG001)


37-37: Unused function argument: idx

(ARG001)


37-37: Async function definition with a timeout parameter

(ASYNC109)


37-37: Unused function argument: timeout

(ARG001)


37-37: Trailing comma missing

Add trailing comma

(COM812)


66-66: Unused function argument: cmd

(ARG001)


66-66: Unused function argument: kwargs

(ARG001)


70-70: Unused function argument: proc

(ARG001)


70-70: Unused function argument: path

(ARG001)


70-70: Unused function argument: idx

(ARG001)


70-70: Async function definition with a timeout parameter

(ASYNC109)


70-70: Unused function argument: timeout

(ARG001)


70-70: Trailing comma missing

Add trailing comma

(COM812)

🔇 Additional comments (11)
nixie/cli.py (7)

7-7: LGTM! Import additions support the verbose logging feature.

The addition of logging and shlex imports is appropriate for the new verbose functionality that logs command-line invocations.

Also applies to: 10-10


150-150: LGTM! Appropriate use of structured logging.

The command-line logging uses the module-specific logger and shlex.join() for proper shell escaping, which is exactly what's needed for debugging command execution.


190-194: Good formatting improvement for function signature readability.

The multi-line parameter formatting enhances readability without changing the function's semantics.


203-211: Consistent formatting applied to function call.

The multi-line parameter formatting matches the function definition style and improves code consistency.


245-245: Add explicit return type annotation as required by coding guidelines.

The function now properly declares its return type as argparse.Namespace, which improves type safety and follows the coding standards for explicit return types in public functions.


262-266: Well-implemented verbose flag with clear help text.

The --verbose argument follows standard CLI conventions with store_true action and descriptive help text that clearly explains its purpose.


273-276: Proper logging configuration based on verbose flag.

The logging setup correctly configures INFO level for verbose mode and WARNING level otherwise, directing output to stderr as appropriate for a CLI tool.

nixie/unittests/test_verbose.py (4)

1-13: LGTM! Proper module setup and imports.

The imports are well-organised and include all necessary dependencies for testing the verbose logging functionality. The module follows the coding guidelines for import structure.


15-20: Well-structured test for argument parsing.

The test properly verifies that the --verbose flag is parsed correctly and that file paths are handled as expected. The use of monkeypatching sys.argv is appropriate for testing CLI argument parsing.


45-52: Effective test for verbose logging behaviour.

The test correctly verifies that the command line is logged at INFO level when verbose mode is enabled. The use of caplog.at_level() and comparison with the expected command string is appropriate.


78-85: Excellent test for silent operation.

This test properly verifies that command logging is suppressed when verbose mode is disabled by checking at WARNING level and asserting the command is not present in the log output.

@leynos leynos merged commit a568800 into main Aug 6, 2025
1 check 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