util-resolve-serviceresult-errors

📁 dawiddutoit/custom-claude 📅 Jan 26, 2026
4
总安装量
4
周安装量
#48734
全站排名
安装命令
npx skills add https://github.com/dawiddutoit/custom-claude --skill util-resolve-serviceresult-errors

Agent 安装分布

mcpjam 4
neovate 4
gemini-cli 4
antigravity 4
windsurf 4
zencoder 4

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

  1. When to Use This Skill
  2. What This Skill Does
  3. Instructions
  4. Usage Examples
  5. Expected Outcomes
  6. Requirements
  7. Troubleshooting
  8. Red Flags to Avoid
  9. 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 assignment with 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:

  1. Mock configuration errors – Fix mocks returning dict instead of ServiceResult
  2. Async ServiceResult patterns – Configure AsyncMock with proper return_value
  3. ServiceResult chaining – Use composition utilities (map, bind, flatmap)
  4. Type error resolution – Fix ServiceResult[T] type mismatches
  5. 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:

  1. 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"})
  2. Async Mock Missing Await

    • Error: coroutine object has no attribute 'success'
    • Cause: AsyncMock returns coroutine, not ServiceResult
    • Fix: Use AsyncMock(return_value=ServiceResult.ok(...))
  3. 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
  4. Unwrap on None Data

    • Error: Cannot unwrap None data from successful result
    • Cause: ServiceResult.ok(None).unwrap()
    • Fix: Check result.data is not None before unwrapping

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:

  1. 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)
    
  2. 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
    
  3. 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:

  1. 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)
    
  2. 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 ServiceResult
  • from 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' → Use ServiceResult.ok(data) instead of data
  • coroutine object has no attribute 'success' → Add return_value to AsyncMock
  • Type errors → Check ServiceResult[T] generic type matches
  • Unwrap errors → Use unwrap_or(default) for optional data

Red Flags to Avoid

  1. Forgetting ServiceResult Wrapper

    • ❌ return_value = data
    • ✅ return_value = ServiceResult.ok(data)
  2. Not Checking Success Before Data Access

    • ❌ data = result.data
    • ✅ if result.success: data = result.data
  3. Using unwrap() Without Null Check

    • ❌ value = result.unwrap() (raises on None)
    • ✅ value = result.unwrap_or(default)
  4. Mixing Async and Sync Mocks

    • ❌ MagicMock(return_value=ServiceResult.ok(...)) for async method
    • ✅ AsyncMock(return_value=ServiceResult.ok(...)) for async method
  5. 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

  1. fix_serviceresult_mocks.py – Auto-fix test mock errors
  2. validate_serviceresult_usage.py – Validate ServiceResult patterns
  3. 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

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