util-resolve-serviceresult-errors
npx skills add https://github.com/dawiddutoit/custom-claude --skill util-resolve-serviceresult-errors
Agent 安装分布
Skill 文档
Resolve ServiceResult Errors
Purpose
Systematic diagnostic and fix workflow for ServiceResult pattern mistakes in tests and service implementations, focusing on mock configuration errors, async patterns, and type safety.
Quick Start
Diagnose and fix common mistakes when working with the ServiceResult pattern in project-watch-mcp, focusing on test failures caused by incorrect mock configurations and improper ServiceResult usage.
Most common use case:
# Test fails with: 'dict' object has no attribute 'success'
â WRONG:
mock_service.get_data = AsyncMock(return_value={"items": []})
â
CORRECT:
from project_watch_mcp.domain.common import ServiceResult
mock_service.get_data = AsyncMock(return_value=ServiceResult.ok({"items": []}))
Result: Test passes, ServiceResult pattern enforced
Table of Contents
- When to Use This Skill
- What This Skill Does
- Instructions
- Usage Examples
- Expected Outcomes
- Requirements
- Troubleshooting
- Red Flags to Avoid
- Automation Scripts
When to Use This Skill
Use this skill when seeing:
- Mock errors:
'dict' object has no attribute 'success' - Async errors:
coroutine object has no attribute 'success' - Type errors:
Incompatible types in assignmentwith ServiceResult[T] - Unwrap errors:
Cannot unwrap None data from successful result - Test failures: Mock assertions failing with ServiceResult
Trigger phrases:
- “Mock not returning ServiceResult”
- “dict object has no attribute success”
- “Fix ServiceResult errors”
- “ServiceResult type errors”
- “Mock configuration incorrect”
What This Skill Does
This skill provides systematic fixes for:
- Mock configuration errors – Fix mocks returning dict instead of ServiceResult
- Async ServiceResult patterns – Configure AsyncMock with proper return_value
- ServiceResult chaining – Use composition utilities (map, bind, flatmap)
- Type error resolution – Fix ServiceResult[T] type mismatches
- Unwrap safety – Handle None data and failure cases correctly
See Instructions section below for detailed diagnostic workflow.
Instructions
Step 1: Identify the Error Pattern
Run the test and classify the error:
uv run pytest tests/path/to/failing_test.py -v
Common Error Signatures:
-
Mock Returns Dict
- Error:
'dict' object has no attribute 'success' - Cause: Mock configured with
return_value = {"key": "value"} - Fix: Use
return_value = ServiceResult.ok({"key": "value"})
- Error:
-
Async Mock Missing Await
- Error:
coroutine object has no attribute 'success' - Cause: AsyncMock returns coroutine, not ServiceResult
- Fix: Use
AsyncMock(return_value=ServiceResult.ok(...))
- Error:
-
Type Error with Chaining
- Error:
Incompatible types in assignment - Cause: ServiceResult[T] type mismatch in chained operations
- Fix: Use proper type annotations and composition utilities
- Error:
-
Unwrap on None Data
- Error:
Cannot unwrap None data from successful result - Cause:
ServiceResult.ok(None).unwrap() - Fix: Check
result.data is not Nonebefore unwrapping
- Error:
Step 2: Fix Mock Configuration
â WRONG – Mock Returns Dict:
mock_service.get_data = AsyncMock(return_value={"items": []})
# Causes: 'dict' object has no attribute 'success'
â CORRECT – Mock Returns ServiceResult:
from project_watch_mcp.domain.common import ServiceResult
mock_service.get_data = AsyncMock(
return_value=ServiceResult.ok({"items": []})
)
Pattern for Multiple Mock Methods: Use MultiEdit to fix all mocks in one operation:
# Fix all mocks in test file at once
mock_repo.file_exists = AsyncMock(return_value=ServiceResult.ok(False))
mock_repo.store_file = AsyncMock(return_value=ServiceResult.ok())
mock_service.create_chunks = AsyncMock(return_value=ServiceResult.ok(chunks))
Step 3: Fix ServiceResult Chaining
Common Chaining Mistakes:
-
Direct Data Access Without Check
# â WRONG - No success check result = service.get_data() data = result.data # Could be None on failure! # â CORRECT - Check success first result = service.get_data() if result.success: data = result.data else: return ServiceResult.fail(result.error) -
Sequential Operations
# â WRONG - Manual chaining result1 = service1.operation() if result1.success: result2 = service2.operation(result1.data) if result2.success: return result2 return result1 if not result1.success else result2 # â CORRECT - Use composition utilities from project_watch_mcp.domain.common.service_result_utils import compose_results result = service1.operation() result = compose_results(lambda d: service2.operation(d), result) return result -
Async Context
# â CORRECT - Async ServiceResult pattern async def process_file(file_path: Path) -> ServiceResult[dict]: result = await self.reader.read_file(file_path) if result.is_failure: return ServiceResult.fail(result.error) # result.success guarantees result.data is not None content = result.data return ServiceResult.ok({"content": content})
Step 4: Use ServiceResult Composition Utilities
Import composition utilities for complex workflows:
from project_watch_mcp.domain.common.service_result_utils import (
compose_results, # Monadic bind (flatMap)
map_result, # Functor map
chain_results, # Chain multiple results
collect_results, # Collect list of results
flatten_results, # Flatten nested results
unwrap_or_fail, # Convert to exception
)
Examples:
# Map over successful result
result = ServiceResult.ok([1, 2, 3])
doubled = map_result(lambda items: [x * 2 for x in items], result)
# Result: ServiceResult.ok([2, 4, 6])
# Compose operations (flatMap)
def validate(data: dict) -> ServiceResult[dict]:
if "required_field" in data:
return ServiceResult.ok(data)
return ServiceResult.fail("Missing required field")
result = ServiceResult.ok({"required_field": "value"})
validated = compose_results(validate, result)
# Chain multiple results
result1 = ServiceResult.ok(10)
result2 = ServiceResult.ok(20)
result3 = ServiceResult.ok(30)
combined = chain_results(result1, result2, result3)
# Result: ServiceResult.ok([10, 20, 30])
Step 5: Fix Type Errors
Common Type Issues:
-
Generic Type Mismatch
# â WRONG - Type mismatch def process() -> ServiceResult[list[str]]: result: ServiceResult[dict] = get_data() return result # Type error! # â CORRECT - Proper type transformation def process() -> ServiceResult[list[str]]: result: ServiceResult[dict] = get_data() if result.is_failure: return ServiceResult.fail(result.error) items = list(result.data.keys()) return ServiceResult.ok(items) -
Optional Data Handling
# â WRONG - Not handling None result = ServiceResult.ok(None) value = result.unwrap() # Raises ValueError! # â CORRECT - Use unwrap_or for optional data result = ServiceResult.ok(None) value = result.unwrap_or([]) # Returns default on None/failure
Step 6: Validate Fix
After fixing mocks and ServiceResult usage:
# Run the specific test
uv run pytest tests/path/to/test_file.py::test_name -v
# Run all related tests
uv run pytest tests/unit/application/ -v -k "service"
# Verify type safety
uv run pyright src/project_watch_mcp/
Usage Examples
Example 1: Fix Mock Returns Dict Error
Scenario: Test fails with 'dict' object has no attribute 'success'
Before (Failing Test):
@pytest.fixture
def mock_repository():
repo = MagicMock(spec=CodeRepository)
# â WRONG - Returns dict, not ServiceResult
repo.get_files = AsyncMock(return_value={"files": []})
return repo
async def test_get_files(mock_repository):
handler = FileHandler(mock_repository)
result = await handler.process()
# Fails: 'dict' object has no attribute 'success'
assert result.success is True
After (Fixed Test):
from project_watch_mcp.domain.common import ServiceResult
@pytest.fixture
def mock_repository():
repo = MagicMock(spec=CodeRepository)
# â
CORRECT - Returns ServiceResult
repo.get_files = AsyncMock(
return_value=ServiceResult.ok({"files": []})
)
return repo
async def test_get_files(mock_repository):
handler = FileHandler(mock_repository)
result = await handler.process()
# Now works correctly
assert result.success is True
assert result.data == {"files": []}
Example 2: Fix Async ServiceResult Pattern
Scenario: Async mock returning coroutine instead of ServiceResult
Fix:
from project_watch_mcp.domain.common import ServiceResult
# â WRONG - AsyncMock without proper return_value
service.embed_text = AsyncMock()
# â
CORRECT - AsyncMock with ServiceResult return_value
service.embed_text = AsyncMock(
return_value=ServiceResult.ok([0.1, 0.2, 0.3])
)
For more examples, see references/troubleshooting.md and templates/serviceresult-patterns.md.
Expected Outcomes
Successful Fix:
- Test passes after mock returns ServiceResult
- AsyncMock configured with proper return_value
- Type annotations match ServiceResult[T]
- No pyright errors
- Unwrap safety checks in place
Refactoring Opportunity Identified:
- Sequential
if result.success:checks detected - Recommendation: Use compose_results() utilities
- See Step 4 in Instructions for composition utilities
Requirements
Imports:
from project_watch_mcp.domain.common import ServiceResultfrom project_watch_mcp.domain.common.service_result_utils import <utility>from unittest.mock import AsyncMock(for async methods)
Tools:
- Read – View test files and service implementations
- Edit/MultiEdit – Fix mock configurations and ServiceResult usage
- Grep – Find all occurrences of pattern
- Glob – Locate test files with ServiceResult issues
Knowledge:
- ServiceResult pattern (success/failure monad)
- AsyncMock vs MagicMock differences
- Python type annotations (ServiceResult[T])
- Composition utilities (map, bind, flatmap)
Optional:
- Understanding of monad pattern
- Familiarity with functional programming concepts
Troubleshooting
For detailed troubleshooting steps and validation workflows, see references/troubleshooting.md.
Quick fixes:
'dict' object has no attribute 'success'â UseServiceResult.ok(data)instead ofdatacoroutine object has no attribute 'success'â Addreturn_valueto AsyncMock- Type errors â Check ServiceResult[T] generic type matches
- Unwrap errors â Use
unwrap_or(default)for optional data
Red Flags to Avoid
-
Forgetting ServiceResult Wrapper
- â
return_value = data - â
return_value = ServiceResult.ok(data)
- â
-
Not Checking Success Before Data Access
- â
data = result.data - â
if result.success: data = result.data
- â
-
Using unwrap() Without Null Check
- â
value = result.unwrap()(raises on None) - â
value = result.unwrap_or(default)
- â
-
Mixing Async and Sync Mocks
- â
MagicMock(return_value=ServiceResult.ok(...))for async method - â
AsyncMock(return_value=ServiceResult.ok(...))for async method
- â
-
Not Propagating Errors
- â Silently ignoring failure results
- â
Returning failure immediately:
if result.is_failure: return result
Automation Scripts
Powerful automation utilities to detect and fix ServiceResult issues automatically.
Available Scripts
- fix_serviceresult_mocks.py – Auto-fix test mock errors
- validate_serviceresult_usage.py – Validate ServiceResult patterns
- find_serviceresult_chains.py – Identify refactoring opportunities
Usage:
# Fix all test mocks automatically
python scripts/fix_serviceresult_mocks.py --all tests/
# Find all violations in codebase
python scripts/validate_serviceresult_usage.py src/
# Get refactoring suggestions
python scripts/find_serviceresult_chains.py --suggest-refactor src/
See Also
Supporting Files
- references/troubleshooting.md – Detailed troubleshooting guide with validation workflows
- references/advanced-patterns.md – Integration points, benefits analysis, and success metrics
- templates/serviceresult-patterns.md – Quick reference templates
- references/monad-pattern.md – Understanding the monad pattern
Related Skills
- test-debug-failures – Fix ServiceResult-specific test failures
- python-best-practices-type-safety – Resolve ServiceResult[T] type mismatches
- test-setup-async – Configure AsyncMock with ServiceResult
- implement-cqrs-handler – Ensure handlers return ServiceResult
- implement-repository-pattern – Validate repository ServiceResult returns