-
-
Notifications
You must be signed in to change notification settings - Fork 52
feat: Stdin piping support for log analysis #602
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (3)
Note Other AI code review bot(s) detectedCodeRabbit 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. 📝 WalkthroughWalkthroughThis pull request adds stdin piping support to Cortex's CLI. A new "stdin" subcommand is introduced with configurable truncation strategies (HEAD, TAIL, MIDDLE, SAMPLE), content-type detection, and analysis capabilities. Users can now pipe data (logs, diffs, etc.) directly to Cortex for processing. Changes
Sequence DiagramsequenceDiagram
participant User
participant CLI
participant Handler as run_stdin_handler
participant StdinHandler
participant Detection as detect_content_type
participant Analysis as analyze_stdin
participant Display as display_stdin_info
User->>CLI: cortex stdin --action analyze [--max-lines N] [--truncation MODE]
CLI->>Handler: run_stdin_handler(action, max_lines, truncation, verbose)
Handler->>StdinHandler: has_stdin_data()
StdinHandler-->>Handler: bool (TTY check)
alt stdin available
Handler->>StdinHandler: read_and_truncate()
StdinHandler->>StdinHandler: read_stdin()
StdinHandler->>StdinHandler: truncate() [apply MODE]
StdinHandler-->>Handler: StdinData
Handler->>Detection: detect_content_type(content)
Detection-->>Handler: content_type (e.g., "git_diff", "error_log")
alt action == "analyze"
Handler->>Analysis: analyze_stdin(data, action, verbose)
Analysis-->>Handler: analysis dict (type-specific metrics)
end
Handler->>Display: display_stdin_info(data, analysis)
Display-->>User: Rich panel with summary & preview
else no stdin
Handler-->>User: Error: No stdin data
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. 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. Comment |
Summary of ChangesHello @mikejmorgan-ai, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly enhances the Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request introduces a new cortex stdin command to process piped data, which is a great feature. The implementation includes logic for reading, truncating, and analyzing stdin content, along with comprehensive tests.
My review focuses on a few key areas for improvement:
- Performance: The current implementation reads the entire stdin stream into memory, which could be problematic for very large files. I've suggested a streaming approach to handle this more efficiently.
- Code Clarity: Some parts of the code could be simplified for better readability and maintainability.
- Unused Code: I've pointed out a few unused parameters that should be removed.
Overall, this is a solid contribution with well-structured code and good test coverage. Addressing these points will make the feature more robust and efficient.
| def read_stdin(self) -> StdinData: | ||
| """Read all available stdin data. | ||
| Returns: | ||
| StdinData containing the input and metadata | ||
| """ | ||
| if sys.stdin.isatty(): | ||
| return StdinData(content="", line_count=0, byte_count=0) | ||
|
|
||
| try: | ||
| content = sys.stdin.read() | ||
| except (IOError, OSError): | ||
| return StdinData(content="", line_count=0, byte_count=0) | ||
|
|
||
| lines = content.splitlines(keepends=True) | ||
| byte_count = len(content.encode("utf-8", errors="replace")) | ||
|
|
||
| return StdinData( | ||
| content=content, | ||
| line_count=len(lines), | ||
| byte_count=byte_count, | ||
| original_line_count=len(lines), | ||
| original_byte_count=byte_count, | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The read_stdin method reads the entire standard input into memory using sys.stdin.read(). This can lead to excessive memory consumption and potential crashes when processing large files, which contradicts the goal of supporting large log analysis.
To handle large inputs efficiently, you should process the input in a streaming manner. For example, read line-by-line and stop when max_lines or max_bytes is reached, while keeping track of original counts. For tail truncation, a collections.deque with a maxlen would be an efficient way to keep only the last N lines.
| action=getattr(args, "action", "info"), | ||
| max_lines=getattr(args, "max_lines", 1000), | ||
| truncation=getattr(args, "truncation", "middle"), | ||
| verbose=getattr(args, "verbose", False), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The use of getattr with default values here is redundant. The stdin subparser defines default values for action, max_lines, truncation, and verbose. When args.command == "stdin", these attributes are guaranteed to be present on the args object. Direct access would be cleaner and more readable.
| action=getattr(args, "action", "info"), | |
| max_lines=getattr(args, "max_lines", 1000), | |
| truncation=getattr(args, "truncation", "middle"), | |
| verbose=getattr(args, "verbose", False), | |
| action=args.action, | |
| max_lines=args.max_lines, | |
| truncation=args.truncation, | |
| verbose=args.verbose, |
| return "json" | ||
|
|
||
| # CSV | ||
| if "," in first_line and lines[0].count(",") == lines[1].count(",") if len(lines) > 1 else False: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The logic for CSV detection is a bit complex and hard to read. The nested if/else on a single line can be confusing. You can simplify this for better readability.
| if "," in first_line and lines[0].count(",") == lines[1].count(",") if len(lines) > 1 else False: | |
| if len(lines) > 1 and "," in first_line and lines[0].count(",") == lines[1].count(","): |
| if any( | ||
| pattern in content | ||
| for pattern in ["container", "docker", "kubernetes", "pod"] | ||
| ): | ||
| return "container_log" | ||
|
|
||
| # System logs | ||
| if any( | ||
| pattern in content | ||
| for pattern in ["systemd", "journald", "kernel", "syslog"] | ||
| ): | ||
| return "system_log" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The content detection for "container_log" and "system_log" scans the entire content string. For large inputs, this can be inefficient. Similar to how you check for log patterns in the first 10 lines, you could limit these checks to a prefix of the content to improve performance.
| if any( | |
| pattern in content | |
| for pattern in ["container", "docker", "kubernetes", "pod"] | |
| ): | |
| return "container_log" | |
| # System logs | |
| if any( | |
| pattern in content | |
| for pattern in ["systemd", "journald", "kernel", "syslog"] | |
| ): | |
| return "system_log" | |
| # Docker/container logs | |
| content_prefix = "\n".join(lines[:50]) | |
| if any( | |
| pattern in content_prefix | |
| for pattern in ["container", "docker", "kubernetes", "pod"] | |
| ): | |
| return "container_log" | |
| # System logs | |
| if any( | |
| pattern in content_prefix | |
| for pattern in ["systemd", "journald", "kernel", "syslog"] | |
| ): | |
| return "system_log" |
| def analyze_stdin( | ||
| data: StdinData, | ||
| action: str = "analyze", | ||
| verbose: bool = False, | ||
| ) -> dict: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this 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
🤖 Fix all issues with AI agents
In `@cortex/stdin_handler.py`:
- Around line 105-108: Replace the redundant except tuple catching IOError and
OSError with a single except OSError in the block that reads stdin (the try
around sys.stdin.read() that returns StdinData). Locate the try/except in
stdin_handler.py (the code that builds and returns StdinData(content="",
line_count=0, byte_count=0)) and change the except clause to catch only OSError
to satisfy ruff UP024 while preserving the existing return behavior.
- Line 312: The function annotation for display_stdin_info uses legacy typing
Optional; update its signature from Optional[dict] to the modern PEP 604 union
syntax dict | None (i.e., def display_stdin_info(data: StdinData, analysis: dict
| None = None):) and then remove Optional from the typing imports at the top of
the file if it is no longer used elsewhere; check for other occurrences of
Optional in this file and update/removal similarly.
In `@tests/test_stdin_handler.py`:
- Around line 482-490: The test test_read_error uses patch(...,
side_effect=IOError("Read error")) which triggers a lint UP024; change the
exception to OSError by replacing IOError with OSError in the side_effect so the
patched sys.stdin.read raises OSError("Read error") instead, leaving the rest of
the test and the StdinHandler.read_stdin behavior unchanged.
- Around line 7-22: The import block in tests/test_stdin_handler.py is unsorted
and includes an unused standard-library import; reorder imports into PEP 8
groups (standard library, third-party, local) and sort them alphabetically
within each group, remove the unused "io" import, and keep the references to the
tested symbols (StdinData, StdinHandler, TruncationMode, analyze_stdin,
detect_content_type, display_stdin_info, run_stdin_handler) from
cortex.stdin_handler intact so tests still import the right names.
🧹 Nitpick comments (2)
cortex/stdin_handler.py (2)
139-151: MIDDLE truncation includes extra marker line.The MIDDLE truncation adds a marker line
"... [{skipped} lines truncated] ..."which means the output can havemax_lines + 1lines. This is probably acceptable UX but worth noting. If strict line limits are needed, consider adjustinghalfto account for the marker.
228-234: JSON and CSV detection are heuristic and may have edge cases.The JSON detection on line 229 only checks if the first line starts with
{or[, which could match non-JSON content. The CSV detection on line 233 has a complex conditional. These are reasonable heuristics for the use case, but be aware of potential false positives.Consider adding a validation step for JSON detection:
# JSON - try to parse for more accurate detection if first_line.startswith("{") or first_line.startswith("["): try: import json json.loads(content) return "json" except json.JSONDecodeError: pass # Fall through to other checks
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
cortex/cli.pycortex/stdin_handler.pytests/test_stdin_handler.py
🧰 Additional context used
📓 Path-based instructions (2)
**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
**/*.py: Follow PEP 8 style guide for Python code
Include type hints in Python code
Add docstrings for all public APIs in Python code
Use dry-run mode by default for all installation operations
Do not use silent sudo - require explicit user confirmation for privilege escalation
Implement Firejail sandboxing for execution of untrusted code
Log all operations to ~/.cortex/history.db for audit purposes
Files:
tests/test_stdin_handler.pycortex/cli.pycortex/stdin_handler.py
tests/**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
Maintain test coverage above 80% for pull requests
Files:
tests/test_stdin_handler.py
🧬 Code graph analysis (3)
tests/test_stdin_handler.py (1)
cortex/stdin_handler.py (11)
StdinData(37-50)StdinHandler(53-183)TruncationMode(27-33)analyze_stdin(253-309)detect_content_type(186-250)display_stdin_info(312-352)run_stdin_handler(355-439)is_empty(48-50)has_stdin_data(77-94)read_stdin(96-119)truncate(121-172)
cortex/cli.py (1)
cortex/stdin_handler.py (1)
run_stdin_handler(355-439)
cortex/stdin_handler.py (1)
tests/test_stdin_handler.py (1)
handler(62-64)
🪛 GitHub Actions: CI
cortex/stdin_handler.py
[error] 107-107: ruff check reported: UP024 Replace aliased errors with OSError. Command: 'ruff check . --output-format=github'.
🪛 GitHub Check: lint
tests/test_stdin_handler.py
[failure] 487-487: Ruff (UP024)
tests/test_stdin_handler.py:487:54: UP024 Replace aliased errors with OSError
[failure] 7-22: Ruff (I001)
tests/test_stdin_handler.py:7:1: I001 Import block is un-sorted or un-formatted
cortex/stdin_handler.py
[failure] 312-312: Ruff (UP045)
cortex/stdin_handler.py:312:51: UP045 Use X | None for type annotations
[failure] 107-107: Ruff (UP024)
cortex/stdin_handler.py:107:16: UP024 Replace aliased errors with OSError
🪛 GitHub Check: Lint
tests/test_stdin_handler.py
[failure] 487-487: Ruff (UP024)
tests/test_stdin_handler.py:487:54: UP024 Replace aliased errors with OSError
[failure] 7-22: Ruff (I001)
tests/test_stdin_handler.py:7:1: I001 Import block is un-sorted or un-formatted
cortex/stdin_handler.py
[failure] 312-312: Ruff (UP045)
cortex/stdin_handler.py:312:51: UP045 Use X | None for type annotations
[failure] 107-107: Ruff (UP024)
cortex/stdin_handler.py:107:16: UP024 Replace aliased errors with OSError
⏰ 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). (3)
- GitHub Check: test (3.12)
- GitHub Check: test (3.11)
- GitHub Check: test (3.10)
🔇 Additional comments (11)
cortex/cli.py (2)
2672-2697: Stdin subcommand implementation looks good.The argument structure is well-defined with appropriate defaults and choices. The
actionargument withnargs="?"anddefault="info"provides a clean UX for the default use case.One minor note: the
-v/--verboseflag here (line 2693-2696) is stdin-specific, while there's also a global--verboseflag at line 2272. Consider whether both should be unified or if the stdin-specific flag is intentional for this subcommand.
2753-2760: LGTM - dispatch follows existing patterns.The lazy import of
run_stdin_handlerat dispatch time is consistent with other commands. Thegetattrcalls with defaults are defensive but harmless since these arguments are defined in the parser.tests/test_stdin_handler.py (3)
25-56: Good coverage of basic data structures.The enum and dataclass tests verify the core types work correctly. The
is_emptyproperty test covers both true and false cases.
58-171: Comprehensive StdinHandler tests.Good coverage of initialization, stdin detection (TTY vs pipe), reading, and all truncation modes. The test fixtures and mocking approach are appropriate.
321-420: Run entry point tests are well-structured.The tests cover all action types (info, analyze, passthrough, stats) and the unknown action error path. The mocking pattern correctly intercepts the StdinHandler instantiation to inject controlled behavior.
cortex/stdin_handler.py (6)
1-25: Good module structure with clear documentation.The module docstring clearly explains the purpose and provides usage examples. Imports are well-organized with standard library, then third-party (rich) dependencies.
27-51: Well-designed data structures.
TruncationModeenum andStdinDatadataclass are clean and follow Python best practices. Theis_emptyproperty provides a convenient way to check for empty stdin.
253-309: Solid analysis implementation with content-specific insights.The analysis function provides useful metrics for common content types. The error counting, git diff stats, and JSON structure analysis are all practical features for the stated use case.
312-353: Well-designed display function with Rich formatting.The table layout, truncation status indicators, and syntax-highlighted preview provide good UX for understanding piped input. The 20-line preview limit is reasonable.
355-439: Clean entry point implementation.The
run_stdin_handlerfunction provides a well-structured entry point with:
- Proper truncation mode mapping
- Helpful usage examples when no stdin is detected
- Clear action handling for all supported modes
- Appropriate exit codes
The lazy import of
jsonin the stats branch is fine since it's only needed for that action.
77-95: Clarify Windows compatibility in docstring and exception handler comment.
select.select()does not work with stdin on Windows (only with sockets), so the exception handler correctly catches theValueErrorand falls back to returningTrue. While this handles Windows correctly, add explicit documentation about this platform-specific behavior in the method docstring and the exception handler comment to make the Windows fallback strategy clear.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
| try: | ||
| content = sys.stdin.read() | ||
| except (IOError, OSError): | ||
| return StdinData(content="", line_count=0, byte_count=0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix IOError to OSError - pipeline failure.
The pipeline is failing because IOError is an alias for OSError in Python 3, and ruff UP024 requires using OSError directly.
🔧 Proposed fix
try:
content = sys.stdin.read()
- except (IOError, OSError):
+ except OSError:
return StdinData(content="", line_count=0, byte_count=0)Since IOError is already an alias for OSError, catching just OSError is sufficient.
📝 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.
| try: | |
| content = sys.stdin.read() | |
| except (IOError, OSError): | |
| return StdinData(content="", line_count=0, byte_count=0) | |
| try: | |
| content = sys.stdin.read() | |
| except OSError: | |
| return StdinData(content="", line_count=0, byte_count=0) |
🧰 Tools
🪛 GitHub Actions: CI
[error] 107-107: ruff check reported: UP024 Replace aliased errors with OSError. Command: 'ruff check . --output-format=github'.
🪛 GitHub Check: lint
[failure] 107-107: Ruff (UP024)
cortex/stdin_handler.py:107:16: UP024 Replace aliased errors with OSError
🪛 GitHub Check: Lint
[failure] 107-107: Ruff (UP024)
cortex/stdin_handler.py:107:16: UP024 Replace aliased errors with OSError
🤖 Prompt for AI Agents
In `@cortex/stdin_handler.py` around lines 105 - 108, Replace the redundant except
tuple catching IOError and OSError with a single except OSError in the block
that reads stdin (the try around sys.stdin.read() that returns StdinData).
Locate the try/except in stdin_handler.py (the code that builds and returns
StdinData(content="", line_count=0, byte_count=0)) and change the except clause
to catch only OSError to satisfy ruff UP024 while preserving the existing return
behavior.
| return result | ||
|
|
||
|
|
||
| def display_stdin_info(data: StdinData, analysis: Optional[dict] = None): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use modern type annotation syntax.
Per ruff UP045 and modern Python style, use dict | None instead of Optional[dict].
🔧 Proposed fix
-def display_stdin_info(data: StdinData, analysis: Optional[dict] = None):
+def display_stdin_info(data: StdinData, analysis: dict | None = None):After this change, the Optional import from typing on line 17 can be removed if not used elsewhere.
🧰 Tools
🪛 GitHub Check: lint
[failure] 312-312: Ruff (UP045)
cortex/stdin_handler.py:312:51: UP045 Use X | None for type annotations
🪛 GitHub Check: Lint
[failure] 312-312: Ruff (UP045)
cortex/stdin_handler.py:312:51: UP045 Use X | None for type annotations
🤖 Prompt for AI Agents
In `@cortex/stdin_handler.py` at line 312, The function annotation for
display_stdin_info uses legacy typing Optional; update its signature from
Optional[dict] to the modern PEP 604 union syntax dict | None (i.e., def
display_stdin_info(data: StdinData, analysis: dict | None = None):) and then
remove Optional from the typing imports at the top of the file if it is no
longer used elsewhere; check for other occurrences of Optional in this file and
update/removal similarly.
| import io | ||
| import json | ||
| import sys | ||
| from unittest.mock import patch, MagicMock | ||
|
|
||
| import pytest | ||
|
|
||
| from cortex.stdin_handler import ( | ||
| StdinData, | ||
| StdinHandler, | ||
| TruncationMode, | ||
| analyze_stdin, | ||
| detect_content_type, | ||
| display_stdin_info, | ||
| run_stdin_handler, | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix import block ordering to pass linting.
Static analysis indicates the import block is unsorted. Per PEP 8 and ruff I001, imports should be grouped and sorted.
🔧 Proposed fix for import ordering
-import io
import json
import sys
+from unittest.mock import MagicMock, patch
+
+import pytest
+
+from cortex.stdin_handler import (
+ StdinData,
+ StdinHandler,
+ TruncationMode,
+ analyze_stdin,
+ detect_content_type,
+ display_stdin_info,
+ run_stdin_handler,
+)
-from unittest.mock import patch, MagicMock
-
-import pytest
-
-from cortex.stdin_handler import (
- StdinData,
- StdinHandler,
- TruncationMode,
- analyze_stdin,
- detect_content_type,
- display_stdin_info,
- run_stdin_handler,
-)Note: The io import on line 7 appears to be unused and can be removed.
📝 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.
| import io | |
| import json | |
| import sys | |
| from unittest.mock import patch, MagicMock | |
| import pytest | |
| from cortex.stdin_handler import ( | |
| StdinData, | |
| StdinHandler, | |
| TruncationMode, | |
| analyze_stdin, | |
| detect_content_type, | |
| display_stdin_info, | |
| run_stdin_handler, | |
| ) | |
| import json | |
| import sys | |
| from unittest.mock import MagicMock, patch | |
| import pytest | |
| from cortex.stdin_handler import ( | |
| StdinData, | |
| StdinHandler, | |
| TruncationMode, | |
| analyze_stdin, | |
| detect_content_type, | |
| display_stdin_info, | |
| run_stdin_handler, | |
| ) |
🧰 Tools
🪛 GitHub Check: lint
[failure] 7-22: Ruff (I001)
tests/test_stdin_handler.py:7:1: I001 Import block is un-sorted or un-formatted
🪛 GitHub Check: Lint
[failure] 7-22: Ruff (I001)
tests/test_stdin_handler.py:7:1: I001 Import block is un-sorted or un-formatted
🤖 Prompt for AI Agents
In `@tests/test_stdin_handler.py` around lines 7 - 22, The import block in
tests/test_stdin_handler.py is unsorted and includes an unused standard-library
import; reorder imports into PEP 8 groups (standard library, third-party, local)
and sort them alphabetically within each group, remove the unused "io" import,
and keep the references to the tested symbols (StdinData, StdinHandler,
TruncationMode, analyze_stdin, detect_content_type, display_stdin_info,
run_stdin_handler) from cortex.stdin_handler intact so tests still import the
right names.
| def test_read_error(self): | ||
| """Test handling read errors.""" | ||
| handler = StdinHandler() | ||
|
|
||
| with patch("sys.stdin.isatty", return_value=False): | ||
| with patch("sys.stdin.read", side_effect=IOError("Read error")): | ||
| data = handler.read_stdin() | ||
|
|
||
| assert data.is_empty |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replace IOError with OSError to fix lint failure.
IOError is an alias for OSError in Python 3. The pipeline is failing due to ruff UP024 requiring the use of OSError directly.
🔧 Proposed fix
def test_read_error(self):
"""Test handling read errors."""
handler = StdinHandler()
with patch("sys.stdin.isatty", return_value=False):
- with patch("sys.stdin.read", side_effect=IOError("Read error")):
+ with patch("sys.stdin.read", side_effect=OSError("Read error")):
data = handler.read_stdin()
assert data.is_empty🧰 Tools
🪛 GitHub Check: lint
[failure] 487-487: Ruff (UP024)
tests/test_stdin_handler.py:487:54: UP024 Replace aliased errors with OSError
🪛 GitHub Check: Lint
[failure] 487-487: Ruff (UP024)
tests/test_stdin_handler.py:487:54: UP024 Replace aliased errors with OSError
🤖 Prompt for AI Agents
In `@tests/test_stdin_handler.py` around lines 482 - 490, The test test_read_error
uses patch(..., side_effect=IOError("Read error")) which triggers a lint UP024;
change the exception to OSError by replacing IOError with OSError in the
side_effect so the patched sys.stdin.read raises OSError("Read error") instead,
leaving the rest of the test and the StdinHandler.read_stdin behavior unchanged.
- Detect stdin data automatically (pipe vs TTY) - Truncation modes: head, tail, middle, sample - Content type detection: error logs, git diff, JSON, system logs - Analysis: error counts, diff stats, JSON structure - Machine-readable stats output for scripting - Handles unicode and large inputs gracefully - 36 tests with full coverage Usage: docker logs container | cortex stdin analyze git diff | cortex stdin info cat error.log | cortex stdin --max-lines 500 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
9a45c7d to
1105690
Compare
|



Summary
Implements #271 - Stdin Piping Support for Log Analysis.
Features
Commands
Truncation Modes
head: Keep first N linestail: Keep last N linesmiddle: Keep head + tail, truncate middle (default)sample: Sample lines throughoutTesting
Fixes #271
Summary by CodeRabbit
stdincommand to accept and process piped input data✏️ Tip: You can customize this high-level summary in your review settings.