Shoper is a simple shell operator module for Python that provides a clean interface for executing shell commands with features like input/output file tracking, asynchronous execution, and validation. The main class ShellOperator wraps subprocess operations with additional functionality for logging, error handling, and file management.
The project consists of a single main module:
shoper/shelloperator.py: Contains theShellOperatorclass with methods for running shell commands synchronously or asynchronouslyshoper/__init__.py: Exports the main class and defines the package version
Key architectural patterns:
- Uses dataclasses for configuration
- Implements both synchronous (
_shell_c) and asynchronous (_popen) execution modes - Provides file/directory validation before and after command execution
- Supports chaining commands with input/output dependencies
uv sync # Install dependencies and sync environmentuv run ruff check . # Run linter
uv run ruff check . --fix # Auto-fix linting issues
uv run pyright # Run type checkeruv run pytest # Run tests (if available)There are no formal unit tests. Testing is done via:
- GitHub Actions workflow that installs the package and runs basic functionality tests
- Manual testing using the examples from README.md
IMPORTANT: Always run these commands before committing:
# Run linter and fix issues
uv run ruff check . --fix
# Run type checker
uv run pyright
# Run tests (if available)
uv run pytestAll commands must pass before committing changes.
uv sync # Install dependencies in sync
uv pip install -e . # Install in development mode (alternative)- Uses ruff for linting with extensive rule coverage (see pyproject.toml)
- Follows Google docstring convention
- Type hints are required (pyright in strict mode)
- Line length: 88 characters
- Uses dataclasses for configuration objects
The main class accepts configuration parameters:
log_txt: Optional log file pathquiet: Suppress outputexecutable: Shell executable (defaults to /bin/bash)print_command: Whether to print commands before execution
run(): Execute shell commands with extensive configuration optionswait(): Wait for asynchronous processes to complete_validate_results(): Validate command execution and outputs
For tasks requiring web search, always use gemini command instead of the built-in web search tool.
# Basic search query
gemini --sandbox --prompt "WebSearch: <query>"
# Example: Search for latest news
gemini --sandbox --prompt "WebSearch: What are the latest developments in AI?"When users request information that requires web search:
- Use
gemini --sandbox --promptcommand via terminal - Parse and present the Gemini response appropriately
This ensures consistent and reliable web search results through the Gemini API.
This section combines essential guidance from Martin Fowler's refactoring, Kent Beck's tidying, and t_wada's TDD approaches.
- Small, safe, behavior-preserving changes - Every change should be tiny, reversible, and testable
- Separate concerns - Never mix adding features with refactoring/tidying
- Test-driven workflow - Tests provide safety net and drive design
- Economic justification - Only refactor/tidy when it makes immediate work easier
- Red - Write a failing test first (TDD)
- Green - Write minimum code to pass the test
- Refactor/Tidy - Clean up without changing behavior
- Commit - Separate commits for features vs refactoring
- Create TODO list for complex tasks
- Ensure test coverage exists
- Identify code smells (long functions, duplication, etc.)
- Test-First: Write the test before the implementation
- Small Steps: Each change should be easily reversible
- Run Tests Frequently: After each small change
- Two Hats: Either add features OR refactor, never both
- Extract Function/Variable - Improve readability
- Rename - Use meaningful names
- Guard Clauses - Replace nested conditionals
- Remove Dead Code - Delete unused code
- Normalize Symmetries - Make similar code consistent
- Fake It - Start with hardcoded values
- Obvious Implementation - When solution is clear
- Triangulation - Multiple tests to find general solution
- Rule of Three: Refactor on third duplication
- Preparatory: Before adding features to messy code
- Comprehension: As you understand code better
- Opportunistic: Small improvements during daily work
- One assertion per test
- Commit refactoring separately from features
- Delete redundant tests
- Focus on making code understandable to humans
Quote: "Make the change easy, then make the easy change." - Kent Beck