Skip to content

Conversation

@jlumpe
Copy link
Contributor

@jlumpe jlumpe commented Nov 27, 2025

  • Edits to common test module:
    • Added type annotations to many functions
    • Edits to run() function:
      • Documented and added type annotations for many arguments.
      • Allow path and tmpdir to be either string or os.Pathlike.
      • Removed unused subpath argument.
  • Updates to existing logging tests:
    • Added file to test-all Pixi task, I don't think it was actually being run before.
    • Added some helper functions to deduplicate code relating to counting log events.
    • Don't count exact number of LOG_COUNTED events (multiple jobs can be grouped under a single event), just assert at least one exists.
    • Completed test_rule_failure test, add expected log counts.
    • Run workflow in test_logging_config in temporary directory instead of current directory (this maybe should be using the same run() function as all the others, but isn't).
    • Added some more descriptive docstrings and type annotations to test functions.
  • Added new test for logging plugin.

An issue I noticed that existed before this PR and I did not change: the benchmark_extended argument of the run() test function is used in some tests but its value is ignored in the function body.

Summary by CodeRabbit

  • Tests

    • Added centralized helpers to count and validate log events and refactored tests to use them.
    • Added a test logging plugin that emits structured JSONL events (including an initial logger_info record) for improved log capture and verification.
  • Chores

    • Introduced comprehensive type annotations and a new string/path type alias across test utilities for clearer typing and maintainability.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 27, 2025

Important

Review skipped

Review was skipped due to path filters

⛔ Files ignored due to path filters (1)
  • pyproject.toml is excluded by !pyproject.toml

CodeRabbit blocks several paths by default. You can override this behavior by explicitly including those paths in the path filters. For example, including **/dist/** will override the default block on the dist directory, by removing the pattern from both the lists.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

📝 Walkthrough

Walkthrough

Added precise StrPath type and widespread type annotations in tests/common.py; introduced a JSONL-emitting Snakemake test logger plugin; added log-event counting/assertion helpers and refactored logging tests to use them.

Changes

Cohort / File(s) Summary
Type annotations & helpers
tests/common.py
Added `StrPath = str
New test logger plugin
tests/logging/plugins/snakemake_logger_plugin_test/__init__.py
Added DEFAULT_FORMATTER, LogHandlerSettings dataclass and LogHandler class that emits JSONL lines; first emit writes a logger_info JSONL line, subsequent emits write event payloads; supports stdout/stderr/file output, file-close handling, and exposes properties (writes_to_stream, writes_to_file, has_filter, has_formatter, needs_rulegraph, baseFilename).
Test logging helpers & refactors
tests/test_logging.py
Added count_events(caplog) -> dict[LogEvent,int] and check_event_counts(observed, expected) helpers; refactored tests to use centralized counting/assertions; updated test paths/typing usages and expanded parameterized plugin test to validate JSONL plugin behavior.
LoggerManager logfile state fixes
src/snakemake/logging.py
In LoggerManager.setup and LoggerManager.cleanup_logfile, clear self.logfile_handlers to reset internal logfile-handler tracking during setup/cleanup.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Snakemake as Snakemake (emitter)
  participant Handler as LogHandler
  participant Stream as Output Stream (stdout/stderr/file)

  Note right of Handler: initialized with settings (outfile, has_formatter, has_filter, needs_rulegraph)

  Snakemake->>Handler: emit(record) [first call]
  Handler->>Handler: detect first_emit -> build logger_info payload
  Handler->>Stream: _emit({"event":"logger_info", "formatter":..., "filter":...})
  Stream-->>Handler: write OK

  Snakemake->>Handler: emit(record) [subsequent]
  Handler->>Handler: build payload (event, level, formatted message)
  Handler->>Stream: _emit(payload)
  Stream-->>Handler: write OK

  Handler->>Handler: close() (optional)
  Handler->>Stream: close file if opened
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Areas needing extra attention:
    • tests/common.py::run — signature changes, Path conversion, tmpdir fs-decode, return/cleanup semantics and type consistency.
    • tests/logging/plugins/snakemake_logger_plugin_test/__init__.py — JSONL schema, initial logger_info emission, stream vs file handling, and close behavior.
    • tests/test_logging.py — correctness of count_events and check_event_counts, and updated test expectations for refactored assertions.

Possibly related PRs

Suggested reviewers

  • johanneskoester

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% 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 The title 'test: Improve logging tests' clearly and concisely summarizes the main focus of the PR, which is improving logging-related tests.
Description check ✅ Passed The PR description comprehensively covers changes made across multiple files, includes explanations of key modifications, and explicitly addresses the template's QC checkboxes by detailing test coverage and documentation updates.

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.

@jlumpe
Copy link
Contributor Author

jlumpe commented Nov 27, 2025

@cademirch

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: 4

🧹 Nitpick comments (1)
tests/common.py (1)

70-75: Function names suggest boolean return but return str | None.

has_azbatch_account_url and has_zenodo_token return the actual values rather than booleans, which is inconsistent with the has_* naming convention used by other functions in this file (e.g., has_apptainer, has_conda). Consider renaming to get_* or keeping the has_* pattern with boolean returns.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 09c64b7 and d3ad8de.

⛔ Files ignored due to path filters (1)
  • pyproject.toml is excluded by !pyproject.toml
📒 Files selected for processing (3)
  • tests/common.py (10 hunks)
  • tests/logging/plugins/snakemake_logger_plugin_test/__init__.py (1 hunks)
  • tests/test_logging.py (6 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

⚙️ CodeRabbit configuration file

**/*.py: Do not try to improve formatting.
Do not suggest type annotations for functions that are defined inside of functions or methods.
Do not suggest type annotation of the self argument of methods.
Do not suggest type annotation of the cls argument of classmethods.
Do not suggest return type annotation if a function or method does not contain a return statement.

Files:

  • tests/test_logging.py
  • tests/logging/plugins/snakemake_logger_plugin_test/__init__.py
  • tests/common.py
🧠 Learnings (3)
📚 Learning: 2025-01-13T18:50:40.791Z
Learnt from: cademirch
Repo: snakemake/snakemake PR: 3107
File: snakemake/logging.py:20-20
Timestamp: 2025-01-13T18:50:40.791Z
Learning: Dependencies for Snakemake are managed through test-environment.yml file, which includes snakemake-interface-logger-plugins (>= 0.1.0) and other required packages.

Applied to files:

  • tests/logging/plugins/snakemake_logger_plugin_test/__init__.py
📚 Learning: 2024-10-08T17:41:54.542Z
Learnt from: johanneskoester
Repo: snakemake/snakemake PR: 2985
File: tests/tests.py:2051-2051
Timestamp: 2024-10-08T17:41:54.542Z
Learning: In the Snakemake repository, avoid suggesting return type annotations for test functions.

Applied to files:

  • tests/common.py
📚 Learning: 2024-10-13T14:10:37.796Z
Learnt from: johanneskoester
Repo: snakemake/snakemake PR: 3114
File: snakemake/cli.py:708-708
Timestamp: 2024-10-13T14:10:37.796Z
Learning: In the `snakemake/cli.py` file, `ExecutorPluginRegistry()` is a singleton class, so multiple instantiations are acceptable and do not cause unnecessary overhead.

Applied to files:

  • tests/common.py
🧬 Code graph analysis (1)
tests/logging/plugins/snakemake_logger_plugin_test/__init__.py (3)
src/snakemake/persistence.py (1)
  • metadata (467-468)
src/snakemake/gui.py (1)
  • record (102-106)
src/snakemake/common/__init__.py (1)
  • write (421-422)
🪛 Ruff (0.14.6)
tests/test_logging.py

111-111: subprocess call with shell=True identified, security issue

(S602)


224-224: Unused function argument: capfd

(ARG001)


311-311: subprocess call: check for execution of untrusted input

(S603)

tests/common.py

57-57: Consider moving this statement to an else block

(TRY300)


142-142: Uses of tarfile.extractall()

(S202)


169-169: Do not use mutable data structures for argument defaults

Replace with None; initialize within function

(B006)


170-170: Do not use mutable data structures for argument defaults

Replace with None; initialize within function

(B006)


171-171: Do not perform function call os.environ.get in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (46)
  • GitHub Check: tests (9, ubuntu-latest, py313)
  • GitHub Check: tests (10, ubuntu-latest, py311)
  • GitHub Check: tests (10, ubuntu-latest, py312)
  • GitHub Check: tests (10, ubuntu-latest, py313)
  • GitHub Check: tests (8, ubuntu-latest, py311)
  • GitHub Check: tests (8, ubuntu-latest, py313)
  • GitHub Check: tests (4, ubuntu-latest, py311)
  • GitHub Check: tests (9, windows-2022, py313)
  • GitHub Check: tests (7, windows-2022, py313)
  • GitHub Check: tests (9, macos-latest, py313)
  • GitHub Check: tests (10, windows-2022, py313)
  • GitHub Check: tests (8, ubuntu-latest, py312)
  • GitHub Check: tests (9, ubuntu-latest, py311)
  • GitHub Check: tests (7, ubuntu-latest, py313)
  • GitHub Check: tests (6, ubuntu-latest, py312)
  • GitHub Check: tests (6, macos-latest, py313)
  • GitHub Check: tests (9, ubuntu-latest, py312)
  • GitHub Check: tests (8, windows-2022, py313)
  • GitHub Check: tests (7, ubuntu-latest, py312)
  • GitHub Check: tests (6, ubuntu-latest, py313)
  • GitHub Check: tests (6, ubuntu-latest, py311)
  • GitHub Check: tests (3, ubuntu-latest, py312)
  • GitHub Check: tests (6, windows-2022, py313)
  • GitHub Check: tests (4, ubuntu-latest, py312)
  • GitHub Check: tests (7, ubuntu-latest, py311)
  • GitHub Check: tests (1, ubuntu-latest, py313)
  • GitHub Check: tests (3, windows-2022, py313)
  • GitHub Check: tests (5, windows-2022, py313)
  • GitHub Check: tests (5, ubuntu-latest, py312)
  • GitHub Check: tests (5, ubuntu-latest, py313)
  • GitHub Check: tests (3, macos-latest, py313)
  • GitHub Check: tests (2, ubuntu-latest, py313)
  • GitHub Check: tests (1, macos-latest, py313)
  • GitHub Check: tests (2, ubuntu-latest, py311)
  • GitHub Check: tests (1, ubuntu-latest, py311)
  • GitHub Check: tests (4, windows-2022, py313)
  • GitHub Check: tests (3, ubuntu-latest, py313)
  • GitHub Check: tests (5, ubuntu-latest, py311)
  • GitHub Check: tests (3, ubuntu-latest, py311)
  • GitHub Check: tests (4, ubuntu-latest, py313)
  • GitHub Check: tests (2, windows-2022, py313)
  • GitHub Check: tests (1, windows-2022, py313)
  • GitHub Check: tests (2, macos-latest, py313)
  • GitHub Check: tests (2, ubuntu-latest, py312)
  • GitHub Check: tests (1, ubuntu-latest, py312)
  • GitHub Check: apidocs
🔇 Additional comments (9)
tests/test_logging.py (2)

27-37: LGTM!

The helper function cleanly extracts and counts events from captured log records using Counter.


248-283: Well-designed parameterized test for the logger plugin.

Good coverage of the plugin configuration options (stream output, formatter, filter, rulegraph). The test validates both the logger configuration metadata and the expected event counts for each scenario.

Also applies to: 338-354

tests/logging/plugins/snakemake_logger_plugin_test/__init__.py (3)

23-48: LGTM!

Clean dataclass-based settings definition with appropriate metadata for CLI help text.


71-96: LGTM!

The emit/close lifecycle is properly implemented: logger info emitted on first record, proper JSON serialization, and file handle cleanup in close().


98-120: LGTM!

Properties correctly delegate to settings for plugin configuration.

tests/common.py (4)

34-41: LGTM!

Good addition of the StrPath type alias for flexible path handling. The docstring clearly explains its purpose.


157-261: Comprehensive documentation and type annotations for run().

The added docstring with parameter descriptions and return type significantly improves usability. The explicit Path | None return type correctly reflects the cleanup behavior.


298-299: LGTM!

Using os.fsdecode() correctly handles the case where tmpdir is passed as a PathLike object, ensuring compatibility with the rest of the function that expects a string.


539-543: LGTM!

Explicit return values (Path(tmpdir) vs None) clearly communicate the cleanup behavior to callers.

@johanneskoester
Copy link
Contributor

While waiting on @cademirch's thorough review, may I ask you to format your code with pixi run -e dev format?

@jlumpe
Copy link
Contributor Author

jlumpe commented Nov 27, 2025

@johanneskoester Formatted the logger plugin file, which was being missed by the Pixi task:

[tool.pixi.feature.style.tasks]
format = { cmd = "black docs/ apidocs/ src/ tests/*.py", description = "Format the code" }

Maybe this should be changed from tests/*.py to tests/?

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: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between aa40836 and f0efc9d.

📒 Files selected for processing (1)
  • tests/logging/plugins/snakemake_logger_plugin_test/__init__.py (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

⚙️ CodeRabbit configuration file

**/*.py: Do not try to improve formatting.
Do not suggest type annotations for functions that are defined inside of functions or methods.
Do not suggest type annotation of the self argument of methods.
Do not suggest type annotation of the cls argument of classmethods.
Do not suggest return type annotation if a function or method does not contain a return statement.

Files:

  • tests/logging/plugins/snakemake_logger_plugin_test/__init__.py
🧠 Learnings (4)
📓 Common learnings
Learnt from: Hocnonsense
Repo: snakemake/snakemake PR: 3714
File: tests/tests.py:1637-1644
Timestamp: 2025-09-08T12:39:09.146Z
Learning: In Snakemake module tests, targeting log-only files like "aaalog" can be an intentional test pattern to validate module behavior and error handling, even though log files aren't typically producible targets in normal workflows.
📚 Learning: 2025-01-13T18:50:40.791Z
Learnt from: cademirch
Repo: snakemake/snakemake PR: 3107
File: snakemake/logging.py:20-20
Timestamp: 2025-01-13T18:50:40.791Z
Learning: Dependencies for Snakemake are managed through test-environment.yml file, which includes snakemake-interface-logger-plugins (>= 0.1.0) and other required packages.

Applied to files:

  • tests/logging/plugins/snakemake_logger_plugin_test/__init__.py
📚 Learning: 2025-01-17T12:00:09.368Z
Learnt from: leoschwarz
Repo: snakemake/snakemake PR: 3176
File: tests/test_output_index.py:99-157
Timestamp: 2025-01-17T12:00:09.368Z
Learning: New test dependencies for Snakemake should be introduced in separate PRs rather than being added as part of feature or refactoring PRs.

Applied to files:

  • tests/logging/plugins/snakemake_logger_plugin_test/__init__.py
📚 Learning: 2024-08-13T16:22:58.430Z
Learnt from: johanneskoester
Repo: snakemake/snakemake PR: 3014
File: snakemake/workflow.py:1250-1251
Timestamp: 2024-08-13T16:22:58.430Z
Learning: Avoid commenting on trailing commas in code reviews for the Snakemake repository as per the user's preference.

Applied to files:

  • tests/logging/plugins/snakemake_logger_plugin_test/__init__.py
🔇 Additional comments (1)
tests/logging/plugins/snakemake_logger_plugin_test/__init__.py (1)

84-91: Verify the design choice to ignore self.formatter.

The code always uses DEFAULT_FORMATTER to format records (line 88), even when self.formatter is set by the logging manager. While the module docstring mentions this behavior ("formatter not used if set"), it's potentially confusing—why expose has_formatter property and allow the formatter to be set if it's never actually used for formatting?

Please confirm this is the intended design for the test plugin. If the formatter is truly not needed, consider documenting why this plugin differs from typical handlers.

self.stream = sys.stderr
self.needs_close = False
else:
self.stream = open(self.settings.outfile, "w")
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Specify UTF-8 encoding when opening the output file.

For cross-platform compatibility and to ensure consistent JSONL output, explicitly specify encoding='utf-8' when opening the file.

Apply this diff:

-            self.stream = open(self.settings.outfile, "w")
+            self.stream = open(self.settings.outfile, "w", encoding="utf-8")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
self.stream = open(self.settings.outfile, "w")
self.stream = open(self.settings.outfile, "w", encoding="utf-8")
🤖 Prompt for AI Agents
In tests/logging/plugins/snakemake_logger_plugin_test/__init__.py around line 67
the test opens the output file without specifying encoding which can produce
inconsistent cross-platform JSONL; update the open call to include
encoding='utf-8' so the file is opened with explicit UTF-8 encoding to ensure
consistent output across platforms.

@jlumpe
Copy link
Contributor Author

jlumpe commented Nov 27, 2025

Also rebased to fix merge conflicts.

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: 0

♻️ Duplicate comments (1)
tests/test_logging.py (1)

223-245: Remove unused capfd parameter from test_rule_failure.

capfd is injected but never used in this test, and Ruff still flags it (ARG001). Since you only inspect caplog and structured events, capfd can be dropped:

-def test_rule_failure(
-    caplog: pytest.LogCaptureFixture, capfd: pytest.CaptureFixture[str]
-):
+def test_rule_failure(caplog: pytest.LogCaptureFixture):
🧹 Nitpick comments (2)
tests/test_logging.py (2)

27-75: Event counting helpers look solid; consider tightening the event check.

count_events() / check_event_counts() nicely centralize log-event assertions and provide good diagnostics on failure. One minor robustness tweak: in count_events(), if event: will skip falsy-but-valid event values; using if event is not None: would avoid surprises if a future LogEvent member ever evaluates to False.


105-117: Avoid shell=True and unquoted Snakefile path in test_logging_config.

Building a shell command via f-string (f"snakemake -s {snakefile}") with shell=True is an anti-pattern that breaks if the path contains spaces or special characters and introduces unnecessary shell interpretation. Prefer passing an argument list without a shell:

-    snakefile = dpath("logging/test_logging_config") / "Snakefile"
-    p = sp.Popen(
-        f"snakemake -s {snakefile}",
-        shell=True,
-        stdout=sp.PIPE,
-        stderr=sp.PIPE,
-        cwd=tmp_path,
-    )
+    snakefile = dpath("logging/test_logging_config") / "Snakefile"
+    p = sp.Popen(
+        ["snakemake", "-s", str(snakefile)],
+        stdout=sp.PIPE,
+        stderr=sp.PIPE,
+        cwd=tmp_path,
+    )
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f0efc9d and 7df5205.

⛔ Files ignored due to path filters (1)
  • pyproject.toml is excluded by !pyproject.toml
📒 Files selected for processing (3)
  • tests/common.py (11 hunks)
  • tests/logging/plugins/snakemake_logger_plugin_test/__init__.py (1 hunks)
  • tests/test_logging.py (6 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/logging/plugins/snakemake_logger_plugin_test/init.py
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

⚙️ CodeRabbit configuration file

**/*.py: Do not try to improve formatting.
Do not suggest type annotations for functions that are defined inside of functions or methods.
Do not suggest type annotation of the self argument of methods.
Do not suggest type annotation of the cls argument of classmethods.
Do not suggest return type annotation if a function or method does not contain a return statement.

Files:

  • tests/test_logging.py
  • tests/common.py
🧠 Learnings (3)
📓 Common learnings
Learnt from: Hocnonsense
Repo: snakemake/snakemake PR: 3714
File: tests/tests.py:1637-1644
Timestamp: 2025-09-08T12:39:09.146Z
Learning: In Snakemake module tests, targeting log-only files like "aaalog" can be an intentional test pattern to validate module behavior and error handling, even though log files aren't typically producible targets in normal workflows.
📚 Learning: 2024-10-08T17:41:54.542Z
Learnt from: johanneskoester
Repo: snakemake/snakemake PR: 2985
File: tests/tests.py:2051-2051
Timestamp: 2024-10-08T17:41:54.542Z
Learning: In the Snakemake repository, avoid suggesting return type annotations for test functions.

Applied to files:

  • tests/common.py
📚 Learning: 2024-10-13T14:10:37.796Z
Learnt from: johanneskoester
Repo: snakemake/snakemake PR: 3114
File: snakemake/cli.py:708-708
Timestamp: 2024-10-13T14:10:37.796Z
Learning: In the `snakemake/cli.py` file, `ExecutorPluginRegistry()` is a singleton class, so multiple instantiations are acceptable and do not cause unnecessary overhead.

Applied to files:

  • tests/common.py
🪛 Ruff (0.14.6)
tests/test_logging.py

111-111: subprocess call with shell=True identified, security issue

(S602)


224-224: Unused function argument: capfd

(ARG001)


314-314: subprocess call: check for execution of untrusted input

(S603)

tests/common.py

145-145: Uses of tarfile.extractall()

(S202)


172-172: Do not use mutable data structures for argument defaults

Replace with None; initialize within function

(B006)


173-173: Do not use mutable data structures for argument defaults

Replace with None; initialize within function

(B006)


174-174: Do not perform function call os.environ.get in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (46)
  • GitHub Check: tests (10, ubuntu-latest, py313)
  • GitHub Check: tests (9, ubuntu-latest, py313)
  • GitHub Check: tests (9, windows-2022, py313)
  • GitHub Check: tests (10, windows-2022, py313)
  • GitHub Check: tests (9, ubuntu-latest, py312)
  • GitHub Check: tests (10, ubuntu-latest, py311)
  • GitHub Check: tests (10, ubuntu-latest, py312)
  • GitHub Check: tests (8, windows-2022, py313)
  • GitHub Check: tests (9, ubuntu-latest, py311)
  • GitHub Check: tests (8, ubuntu-latest, py311)
  • GitHub Check: tests (8, ubuntu-latest, py312)
  • GitHub Check: tests (7, windows-2022, py313)
  • GitHub Check: tests (7, ubuntu-latest, py311)
  • GitHub Check: tests (6, windows-2022, py313)
  • GitHub Check: tests (8, ubuntu-latest, py313)
  • GitHub Check: tests (7, ubuntu-latest, py312)
  • GitHub Check: tests (7, ubuntu-latest, py313)
  • GitHub Check: tests (6, ubuntu-latest, py312)
  • GitHub Check: tests (6, ubuntu-latest, py313)
  • GitHub Check: tests (4, macos-latest, py313)
  • GitHub Check: tests (5, ubuntu-latest, py312)
  • GitHub Check: tests (5, ubuntu-latest, py311)
  • GitHub Check: tests (6, ubuntu-latest, py311)
  • GitHub Check: tests (5, macos-latest, py313)
  • GitHub Check: tests (5, ubuntu-latest, py313)
  • GitHub Check: tests (5, windows-2022, py313)
  • GitHub Check: tests (3, ubuntu-latest, py311)
  • GitHub Check: tests (4, ubuntu-latest, py312)
  • GitHub Check: tests (4, windows-2022, py313)
  • GitHub Check: tests (4, ubuntu-latest, py313)
  • GitHub Check: tests (3, ubuntu-latest, py312)
  • GitHub Check: tests (4, ubuntu-latest, py311)
  • GitHub Check: tests (3, macos-latest, py313)
  • GitHub Check: tests (3, ubuntu-latest, py313)
  • GitHub Check: tests (3, windows-2022, py313)
  • GitHub Check: tests (2, macos-latest, py313)
  • GitHub Check: tests (2, windows-2022, py313)
  • GitHub Check: tests (2, ubuntu-latest, py313)
  • GitHub Check: tests (2, ubuntu-latest, py312)
  • GitHub Check: tests (2, ubuntu-latest, py311)
  • GitHub Check: tests (1, macos-latest, py313)
  • GitHub Check: tests (1, windows-2022, py313)
  • GitHub Check: tests (1, ubuntu-latest, py311)
  • GitHub Check: tests (1, ubuntu-latest, py313)
  • GitHub Check: tests (1, ubuntu-latest, py312)
  • GitHub Check: apidocs
🔇 Additional comments (6)
tests/test_logging.py (3)

165-181: Dry-run event assertions look well-factored.

Using count_events(caplog) and check_event_counts here makes the expectations explicit and reusable; the mapping of expected events for the dry run looks consistent with the intent of the test.


184-221: Good combination of structured and textual logging checks.

This test nicely validates both structured LogEvent counts via check_event_counts and human-readable stderr output via capfd, which should catch regressions in either layer without duplicating logic.


248-357: Plugin test is comprehensive; small note on event mapping clarity.

The parametrized plugin test covers the key handler configuration knobs and checks both the initial logger_info record and subsequent LogEvent counts via check_event_counts, which is excellent. The conditional expectations for WORKFLOW_STARTED, DEBUG_DAG, and RULEGRAPH correctly encode the interaction between the default filter and plugin options, making this a strong regression test.

tests/common.py (3)

21-89: StrPath alias and added annotations improve clarity without changing behavior.

Introducing StrPath = str | os.PathLike and using it across helpers like dpath, md5sum, copy, get_expected_files, untar_folder, and print_tree aligns signatures with actual usage and keeps call sites flexible. The implementations already worked with os.PathLike, so these are type-level improvements only.


125-158: Path-like handling in filesystem helpers is coherent.

Allowing StrPath for copy, get_expected_files, untar_folder, and exclude in print_tree fits how these functions are used elsewhere (e.g., with Path inputs) and leverages os.fspath in stdlib APIs, so this should be safe while improving typing.


160-229: I'll help you verify the concerns in this review comment. Let me start by searching for call sites of the run() function and how its return value is being used.
<function_calls>


#!/bin/bash

Find usages of run() return value in tests

Look for patterns where run() is called and the result is assigned or used

rg -n "=\s*run(" tests -A 5 -B 2


</function_calls>


#!/bin/bash

Also search for direct usage of run() return value without assignment

rg -n "run([^)]*)." tests -C 3


</function_calls>


#!/bin/bash

Check the actual implementation of the run() function at the mentioned lines

sed -n '160,240p' tests/common.py | head -100


</function_calls>


#!/bin/bash

Look at what the function returns and how tmpdir is used

sed -n '160,330p' tests/common.py


</function_calls>

@jlumpe
Copy link
Contributor Author

jlumpe commented Nov 27, 2025

Also removed unused test fixture as per CodeRabbit suggestion.

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: 0

🧹 Nitpick comments (4)
tests/test_logging.py (4)

27-42: Confirm builtin-generic annotations match supported Python versions

The annotations dict[LogEvent, int] and dict[LogEvent, int | None] require Python ≥3.9 unless from __future__ import annotations is enabled; on 3.8 these would raise at import time. If Snakemake still supports 3.8, consider adding postponed-annotations at the top of this module or switching to Dict[...] from typing; otherwise, this is fine but should be consistent with the declared minimum Python version.

+from __future__ import annotations
+
 import os
 import shutil
 import sys
 import subprocess as sp
 import logging
 from collections import Counter
 from pathlib import Path
 import json

70-73: Make debug printing robust to non-orderable LogEvent enums

If LogEvent does not define ordering, sorted(observed) can raise a TypeError on some Python versions. Sorting by a string representation avoids depending on enum ordering while keeping the output readable.

-        for event in sorted(observed):
+        for event in sorted(observed, key=str):
             print(f"  {event}: {observed[event]}", file=sys.stderr)

105-116: Avoid shell=True and string command to make Snakemake invocation more robust

Popen(f"snakemake -s {snakefile}", shell=True, ...) is unnecessary here and becomes brittle if the Snakefile path ever contains spaces or shell metacharacters. Building an argument list and letting Popen handle it directly avoids quoting issues and sidesteps the shell=True static-analysis warning.

-    snakefile = dpath("logging/test_logging_config") / "Snakefile"
-    p = sp.Popen(
-        f"snakemake -s {snakefile}",
-        shell=True,
-        stdout=sp.PIPE,
-        stderr=sp.PIPE,
-        cwd=tmp_path,
-    )
+    snakefile = dpath("logging/test_logging_config") / "Snakefile"
+    p = sp.Popen(
+        ["snakemake", "-s", str(snakefile)],
+        stdout=sp.PIPE,
+        stderr=sp.PIPE,
+        cwd=tmp_path,
+    )

246-355: Consider preserving existing PYTHONPATH when injecting the plugin directory

In test_plugin, env = dict(os.environ) is good for retaining the base environment, but env["PYTHONPATH"] = str(plugin_dir) overwrites any existing PYTHONPATH. That’s fine for isolated CI, but if tests run in environments that already rely on PYTHONPATH, this could subtly change imports. To be more robust, you could prefix the plugin directory to the existing value instead of replacing it.

-    env = dict(os.environ)
-    env["PYTHONPATH"] = str(plugin_dir)
+    env = dict(os.environ)
+    existing = env.get("PYTHONPATH")
+    env["PYTHONPATH"] = (
+        str(plugin_dir)
+        if not existing
+        else os.pathsep.join([str(plugin_dir), existing])
+    )
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7df5205 and b2e05b3.

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

⚙️ CodeRabbit configuration file

**/*.py: Do not try to improve formatting.
Do not suggest type annotations for functions that are defined inside of functions or methods.
Do not suggest type annotation of the self argument of methods.
Do not suggest type annotation of the cls argument of classmethods.
Do not suggest return type annotation if a function or method does not contain a return statement.

Files:

  • tests/test_logging.py
🧠 Learnings (1)
📓 Common learnings
Learnt from: Hocnonsense
Repo: snakemake/snakemake PR: 3714
File: tests/tests.py:1637-1644
Timestamp: 2025-09-08T12:39:09.146Z
Learning: In Snakemake module tests, targeting log-only files like "aaalog" can be an intentional test pattern to validate module behavior and error handling, even though log files aren't typically producible targets in normal workflows.
🧬 Code graph analysis (1)
tests/test_logging.py (2)
tests/common.py (1)
  • dpath (38-41)
tests/logging/plugins/snakemake_logger_plugin_test/__init__.py (2)
  • has_formatter (116-117)
  • needs_rulegraph (120-121)
🪛 Ruff (0.14.6)
tests/test_logging.py

111-111: subprocess call with shell=True identified, security issue

(S602)


312-312: subprocess call: check for execution of untrusted input

(S603)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (46)
  • GitHub Check: tests (3, ubuntu-latest, py313)
  • GitHub Check: tests (5, ubuntu-latest, py312)
  • GitHub Check: tests (3, ubuntu-latest, py312)
  • GitHub Check: tests (4, ubuntu-latest, py311)
  • GitHub Check: tests (7, ubuntu-latest, py313)
  • GitHub Check: tests (7, ubuntu-latest, py312)
  • GitHub Check: tests (6, ubuntu-latest, py313)
  • GitHub Check: tests (10, ubuntu-latest, py313)
  • GitHub Check: tests (4, ubuntu-latest, py313)
  • GitHub Check: tests (6, ubuntu-latest, py312)
  • GitHub Check: tests (5, windows-2022, py313)
  • GitHub Check: tests (6, ubuntu-latest, py311)
  • GitHub Check: tests (8, ubuntu-latest, py312)
  • GitHub Check: tests (10, ubuntu-latest, py311)
  • GitHub Check: tests (10, macos-latest, py313)
  • GitHub Check: tests (6, windows-2022, py313)
  • GitHub Check: tests (10, windows-2022, py313)
  • GitHub Check: tests (7, macos-latest, py313)
  • GitHub Check: tests (8, windows-2022, py313)
  • GitHub Check: tests (5, ubuntu-latest, py311)
  • GitHub Check: tests (9, windows-2022, py313)
  • GitHub Check: tests (8, ubuntu-latest, py313)
  • GitHub Check: tests (9, ubuntu-latest, py312)
  • GitHub Check: tests (7, ubuntu-latest, py311)
  • GitHub Check: tests (7, windows-2022, py313)
  • GitHub Check: tests (9, ubuntu-latest, py313)
  • GitHub Check: tests (3, windows-2022, py313)
  • GitHub Check: tests (10, ubuntu-latest, py312)
  • GitHub Check: tests (4, windows-2022, py313)
  • GitHub Check: tests (8, ubuntu-latest, py311)
  • GitHub Check: tests (4, ubuntu-latest, py312)
  • GitHub Check: tests (5, ubuntu-latest, py313)
  • GitHub Check: tests (9, macos-latest, py313)
  • GitHub Check: tests (9, ubuntu-latest, py311)
  • GitHub Check: tests (2, ubuntu-latest, py311)
  • GitHub Check: tests (2, macos-latest, py313)
  • GitHub Check: tests (1, windows-2022, py313)
  • GitHub Check: tests (1, ubuntu-latest, py313)
  • GitHub Check: tests (1, ubuntu-latest, py312)
  • GitHub Check: tests (3, ubuntu-latest, py311)
  • GitHub Check: tests (2, ubuntu-latest, py313)
  • GitHub Check: tests (2, windows-2022, py313)
  • GitHub Check: tests (2, ubuntu-latest, py312)
  • GitHub Check: tests (1, ubuntu-latest, py311)
  • GitHub Check: tests (1, macos-latest, py313)
  • GitHub Check: apidocs
🔇 Additional comments (3)
tests/test_logging.py (3)

165-181: Dry-run event-count test cleanly uses the new helpers

The structure of test_log_events_dryrun—capturing at INFO, then delegating counting and assertions to count_events/check_event_counts—looks good and keeps the expectations explicit without duplicating logic.


184-206: Workflow run event expectations and stderr checks look consistent

The combination of event-count assertions (including JOB_STARTED: None for “at least one”) with explicit stderr content checks gives good coverage of both structured logging and human-readable output; nothing stands out as problematic here.


223-243: Failure-path event coverage for rule errors is thorough

test_rule_failure exercises the failing-workflow path and asserts a detailed set of LogEvent counts (including both ERROR and JOB_ERROR plus JOB_STARTED as “at least one”), which should catch regressions in how failures are logged.

@jlumpe
Copy link
Contributor Author

jlumpe commented Nov 27, 2025

CodeRabbit keeps coming up with good suggestions. Extended PYTHONPATH in test rather than replacing it.

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: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b2e05b3 and 5b08bb0.

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

⚙️ CodeRabbit configuration file

**/*.py: Do not try to improve formatting.
Do not suggest type annotations for functions that are defined inside of functions or methods.
Do not suggest type annotation of the self argument of methods.
Do not suggest type annotation of the cls argument of classmethods.
Do not suggest return type annotation if a function or method does not contain a return statement.

Files:

  • tests/test_logging.py
🧬 Code graph analysis (1)
tests/test_logging.py (1)
src/snakemake/shell.py (2)
  • shell (43-371)
  • executable (68-79)
🪛 Ruff (0.14.6)
tests/test_logging.py

111-111: subprocess call with shell=True identified, security issue

(S602)


318-318: subprocess call: check for execution of untrusted input

(S603)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (46)
  • GitHub Check: tests (7, ubuntu-latest, py311)
  • GitHub Check: tests (10, ubuntu-latest, py313)
  • GitHub Check: tests (9, ubuntu-latest, py313)
  • GitHub Check: tests (10, windows-2022, py313)
  • GitHub Check: tests (9, windows-2022, py313)
  • GitHub Check: tests (10, ubuntu-latest, py311)
  • GitHub Check: tests (10, ubuntu-latest, py312)
  • GitHub Check: tests (9, ubuntu-latest, py312)
  • GitHub Check: tests (8, ubuntu-latest, py312)
  • GitHub Check: tests (8, windows-2022, py313)
  • GitHub Check: tests (9, ubuntu-latest, py311)
  • GitHub Check: tests (8, ubuntu-latest, py313)
  • GitHub Check: tests (7, ubuntu-latest, py313)
  • GitHub Check: tests (6, windows-2022, py313)
  • GitHub Check: tests (7, windows-2022, py313)
  • GitHub Check: tests (8, ubuntu-latest, py311)
  • GitHub Check: tests (7, ubuntu-latest, py312)
  • GitHub Check: tests (6, ubuntu-latest, py313)
  • GitHub Check: tests (5, ubuntu-latest, py312)
  • GitHub Check: tests (6, ubuntu-latest, py311)
  • GitHub Check: tests (6, ubuntu-latest, py312)
  • GitHub Check: tests (6, macos-latest, py313)
  • GitHub Check: tests (5, ubuntu-latest, py313)
  • GitHub Check: tests (5, ubuntu-latest, py311)
  • GitHub Check: tests (4, windows-2022, py313)
  • GitHub Check: tests (5, windows-2022, py313)
  • GitHub Check: tests (3, macos-latest, py313)
  • GitHub Check: tests (4, macos-latest, py313)
  • GitHub Check: tests (4, ubuntu-latest, py313)
  • GitHub Check: tests (4, ubuntu-latest, py312)
  • GitHub Check: tests (2, ubuntu-latest, py313)
  • GitHub Check: tests (3, ubuntu-latest, py311)
  • GitHub Check: tests (2, ubuntu-latest, py312)
  • GitHub Check: tests (1, macos-latest, py313)
  • GitHub Check: tests (4, ubuntu-latest, py311)
  • GitHub Check: tests (3, windows-2022, py313)
  • GitHub Check: tests (2, macos-latest, py313)
  • GitHub Check: tests (2, windows-2022, py313)
  • GitHub Check: tests (3, ubuntu-latest, py313)
  • GitHub Check: tests (3, ubuntu-latest, py312)
  • GitHub Check: tests (2, ubuntu-latest, py311)
  • GitHub Check: tests (1, ubuntu-latest, py313)
  • GitHub Check: tests (1, ubuntu-latest, py312)
  • GitHub Check: tests (1, ubuntu-latest, py311)
  • GitHub Check: tests (1, windows-2022, py313)
  • GitHub Check: apidocs
🔇 Additional comments (8)
tests/test_logging.py (8)

27-37: LGTM! Clean helper implementation.

The count_events function correctly tallies log records by event type using Counter and properly handles records that may not have an event attribute.


40-76: LGTM! Well-designed validation helper.

The check_event_counts function provides clear validation with helpful error messages and debug output. The pattern of using None to indicate "at least one occurrence" is intuitive and flexible.


105-123: LGTM! Good test isolation improvement.

The modifications properly isolate the test by running in a temporary directory and add clear documentation. The shell=True flag is acceptable here since the command uses known, controlled paths in a test context.


125-129: LGTM! Clear documentation added.

The docstring clearly explains the test purpose and references the relevant issue.


165-182: LGTM! Clean refactoring using new helpers.

The test has been successfully refactored to use the new helper functions, reducing code duplication while maintaining clear assertions for dry run event counts.


184-221: LGTM! Comprehensive test with good coverage.

The test properly validates both event counts and stderr output. The use of None for JOB_STARTED correctly handles variable job grouping behavior.


223-244: LGTM! Complete failure scenario test.

The test properly validates event counts for a failing workflow, including appropriate expectations for ERROR and JOB_ERROR events.


246-281: Well-designed comprehensive plugin test.

The parametrized test thoroughly covers different plugin configurations. The logic for conditional event count expectations based on plugin properties (has_filter, needs_rulegraph) is correct. The subprocess call flagged by static analysis (S603) is acceptable in this test context with controlled inputs.

Also applies to: 296-361

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: 0

🧹 Nitpick comments (1)
tests/test_logging.py (1)

111-117: Consider avoiding shell=True for better robustness.

While acceptable in test code with controlled inputs, using shell=True with string formatting can be fragile. Consider refactoring to use a list of arguments instead.

Apply this diff to improve robustness:

-    p = sp.Popen(
-        f"snakemake -s {snakefile}",
-        shell=True,
-        stdout=sp.PIPE,
-        stderr=sp.PIPE,
-        cwd=tmp_path,
-    )
+    p = sp.Popen(
+        ["snakemake", "-s", str(snakefile)],
+        stdout=sp.PIPE,
+        stderr=sp.PIPE,
+        cwd=tmp_path,
+    )
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5b08bb0 and 790058a.

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

⚙️ CodeRabbit configuration file

**/*.py: Do not try to improve formatting.
Do not suggest type annotations for functions that are defined inside of functions or methods.
Do not suggest type annotation of the self argument of methods.
Do not suggest type annotation of the cls argument of classmethods.
Do not suggest return type annotation if a function or method does not contain a return statement.

Files:

  • tests/test_logging.py
🪛 Ruff (0.14.6)
tests/test_logging.py

111-111: subprocess call with shell=True identified, security issue

(S602)


318-318: subprocess call: check for execution of untrusted input

(S603)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (46)
  • GitHub Check: tests (10, ubuntu-latest, py312)
  • GitHub Check: tests (9, macos-latest, py313)
  • GitHub Check: tests (10, ubuntu-latest, py311)
  • GitHub Check: tests (10, ubuntu-latest, py313)
  • GitHub Check: tests (10, windows-2022, py313)
  • GitHub Check: tests (9, windows-2022, py313)
  • GitHub Check: tests (8, ubuntu-latest, py312)
  • GitHub Check: tests (9, ubuntu-latest, py312)
  • GitHub Check: tests (7, macos-latest, py313)
  • GitHub Check: tests (8, ubuntu-latest, py313)
  • GitHub Check: tests (7, windows-2022, py313)
  • GitHub Check: tests (9, ubuntu-latest, py313)
  • GitHub Check: tests (9, ubuntu-latest, py311)
  • GitHub Check: tests (8, windows-2022, py313)
  • GitHub Check: tests (6, windows-2022, py313)
  • GitHub Check: tests (6, ubuntu-latest, py312)
  • GitHub Check: tests (7, ubuntu-latest, py311)
  • GitHub Check: tests (7, ubuntu-latest, py313)
  • GitHub Check: tests (6, ubuntu-latest, py311)
  • GitHub Check: tests (8, ubuntu-latest, py311)
  • GitHub Check: tests (7, ubuntu-latest, py312)
  • GitHub Check: tests (3, macos-latest, py313)
  • GitHub Check: tests (5, windows-2022, py313)
  • GitHub Check: tests (5, ubuntu-latest, py311)
  • GitHub Check: tests (5, macos-latest, py313)
  • GitHub Check: tests (4, windows-2022, py313)
  • GitHub Check: tests (5, ubuntu-latest, py312)
  • GitHub Check: tests (5, ubuntu-latest, py313)
  • GitHub Check: tests (6, ubuntu-latest, py313)
  • GitHub Check: tests (3, windows-2022, py313)
  • GitHub Check: tests (3, ubuntu-latest, py311)
  • GitHub Check: tests (2, ubuntu-latest, py311)
  • GitHub Check: tests (2, macos-latest, py313)
  • GitHub Check: tests (3, ubuntu-latest, py312)
  • GitHub Check: tests (4, ubuntu-latest, py311)
  • GitHub Check: tests (3, ubuntu-latest, py313)
  • GitHub Check: tests (4, ubuntu-latest, py312)
  • GitHub Check: tests (4, ubuntu-latest, py313)
  • GitHub Check: tests (2, windows-2022, py313)
  • GitHub Check: tests (1, windows-2022, py313)
  • GitHub Check: tests (1, ubuntu-latest, py313)
  • GitHub Check: tests (2, ubuntu-latest, py313)
  • GitHub Check: tests (2, ubuntu-latest, py312)
  • GitHub Check: tests (1, ubuntu-latest, py312)
  • GitHub Check: tests (1, ubuntu-latest, py311)
  • GitHub Check: apidocs
🔇 Additional comments (1)
tests/test_logging.py (1)

318-325: Static analysis warning is a false positive.

The subprocess call is safe in this test context—all command arguments are constructed from controlled values (sys.executable, test paths from dpath()). The S603 warning can be safely ignored here.

@jlumpe
Copy link
Contributor Author

jlumpe commented Nov 29, 2025

@cademirch Looks like the /test_logging.py::test_logfile test is failing in the CI. I'm having trouble telling what the problem is from the logs, not sure if you can help shed some light on it. It seems like the echo {log} command in the onsuccess block is failing somehow. It's definitely being passed way too many files, I think because the list is not getting properly reset from one test to the next. I'm not sure why echo should fail, though.

@jlumpe
Copy link
Contributor Author

jlumpe commented Nov 30, 2025

@cademirch looks like your edit fixed it, thanks!

@cademirch cademirch merged commit cd265bb into snakemake:main Dec 4, 2025
59 checks passed
@jlumpe jlumpe deleted the logging-testing branch December 5, 2025 07:33
kjohnsen pushed a commit to kjohnsen/snakemake that referenced this pull request Dec 15, 2025
- Edits to `common` test module:
  - Added type annotations to many functions
  - Edits to `run()` function:
    - Documented and added type annotations for many arguments.
    - Allow `path` and `tmpdir` to be either string or `os.Pathlike`.
    - Removed unused `subpath` argument.
- Updates to existing logging tests:
- Added file to `test-all` Pixi task, I don't think it was actually
being run before.
- Added some helper functions to deduplicate code relating to counting
log events.
- Don't count exact number of `LOG_COUNTED` events (multiple jobs can be
grouped under a single event), just assert at least one exists.
  - Completed `test_rule_failure` test, add expected log counts.
- Run workflow in `test_logging_config` in temporary directory instead
of current directory (this maybe should be using the same `run()`
function as all the others, but isn't).
- Added some more descriptive docstrings and type annotations to test
functions.
- Added new test for logging plugin.

An issue I noticed that existed before this PR and I did not change: the
`benchmark_extended` argument of the `run()` test function is used in
some tests but its value is ignored in the function body.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Tests**
* Added centralized helpers to count and validate log events and
refactored tests to use them.
* Added a test logging plugin that emits structured JSONL events
(including an initial logger_info record) for improved log capture and
verification.

* **Chores**
* Introduced comprehensive type annotations and a new string/path type
alias across test utilities for clearer typing and maintainability.

<sub>✏️ Tip: You can customize this high-level summary in your review
settings.</sub>
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Cade Mirchandani <cmirchan@ucsc.edu>
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.

3 participants