Files
wehub-resource-sync 7a0da7932b
OSV-Scanner (Scheduled) / scan-scheduled (push) Failing after 0s
Create Release / test-gate (push) Has been cancelled
Create Release / release-gate (push) Has been cancelled
Create Release / ci-gate (push) Has been cancelled
Create Release / version-check (push) Has been cancelled
Create Release / e2e-test-gate (push) Has been cancelled
Create Release / responsive-test-gate (push) Has been cancelled
Create Release / compat-test-gate (push) Has been cancelled
Create Release / compose-integration-gate (push) Has been cancelled
Create Release / vulture-gate (push) Has been cancelled
Create Release / build (push) Has been cancelled
Create Release / provenance (push) Has been cancelled
Create Release / prerelease-docker (push) Has been cancelled
Create Release / publish-docker (push) Has been cancelled
Create Release / create-release (push) Has been cancelled
Create Release / cleanup-changelog (push) Has been cancelled
Create Release / trigger-pypi (push) Has been cancelled
Create Release / monitor-pypi (push) Has been cancelled
Create Release / Clean up orphan prerelease tags and signatures (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-form] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-metrics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-workflow] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-core] (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [history-news] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [library] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [link-analytics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-core] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-lifecycle] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [error-benchmark] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) (push) Has been cancelled
Docker Tests (Consolidated) / Accessibility Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Unit Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Example Tests (push) Has been cancelled
Docker Tests (Consolidated) / Production Image Smoke Test (push) Has been cancelled
Docker Tests (Consolidated) / Infrastructure Tests (push) Has been cancelled
OSSF Scorecard / OSSF Security Scorecard Analysis (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [mobile] (push) Has been cancelled
Backwards Compatibility / Verify Encryption Constants (push) Has been cancelled
Backwards Compatibility / PyPI Version Compatibility (push) Has been cancelled
Backwards Compatibility / Database Migration Tests (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Docker Tests (Consolidated) / detect-changes (push) Has been cancelled
Docker Tests (Consolidated) / Build Test Image (push) Has been cancelled
Docker Tests (Consolidated) / All Pytest Tests + Coverage (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [accessibility] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [api-crud] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-login] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-register] (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:08:55 +08:00

5.8 KiB

News API Exception Handling

Overview

The news API module now uses a structured exception handling approach instead of returning error dictionaries. This provides better error handling, cleaner code, and consistent API responses.

Exception Hierarchy

All news API exceptions inherit from NewsAPIException, which provides:

  • Human-readable error messages
  • HTTP status codes
  • Machine-readable error codes
  • Optional additional details
from local_deep_research.news.exceptions import NewsAPIException

class NewsAPIException(Exception):
    def __init__(self, message: str, status_code: int = 500,
                 error_code: Optional[str] = None,
                 details: Optional[Dict[str, Any]] = None)

Available Exceptions

InvalidLimitException

  • Status Code: 400
  • Error Code: INVALID_LIMIT
  • Usage: When an invalid limit parameter is provided
  • Example:
if limit < 1:
    raise InvalidLimitException(limit)

SubscriptionNotFoundException

  • Status Code: 404
  • Error Code: SUBSCRIPTION_NOT_FOUND
  • Usage: When a requested subscription doesn't exist
  • Example:
if not subscription:
    raise SubscriptionNotFoundException(subscription_id)

SubscriptionCreationException

  • Status Code: 500
  • Error Code: SUBSCRIPTION_CREATE_FAILED
  • Usage: When subscription creation fails
  • Example:
except Exception as e:
    raise SubscriptionCreationException(str(e), {"query": query})

SubscriptionUpdateException

  • Status Code: 500
  • Error Code: SUBSCRIPTION_UPDATE_FAILED
  • Usage: When subscription update fails

SubscriptionDeletionException

  • Status Code: 500
  • Error Code: SUBSCRIPTION_DELETE_FAILED
  • Usage: When subscription deletion fails

DatabaseAccessException

  • Status Code: 500
  • Error Code: DATABASE_ERROR
  • Usage: When database operations fail
  • Example:
except Exception as e:
    raise DatabaseAccessException("operation_name", str(e))

NewsFeedGenerationException

  • Status Code: 500
  • Error Code: FEED_GENERATION_FAILED
  • Usage: When news feed generation fails

ResearchProcessingException

  • Status Code: 500
  • Error Code: RESEARCH_PROCESSING_FAILED
  • Usage: When processing research items fails

NotImplementedException

  • Status Code: 501
  • Error Code: NOT_IMPLEMENTED
  • Usage: For features not yet implemented
  • Example:
raise NotImplementedException("feature_name")

InvalidParameterException

  • Status Code: 400
  • Error Code: INVALID_PARAMETER
  • Usage: When invalid parameters are provided

SchedulerNotificationException

  • Status Code: 500
  • Error Code: SCHEDULER_NOTIFICATION_FAILED
  • Usage: When scheduler notification fails (non-critical)

Flask Integration

Error Handlers

The Flask application automatically handles NewsAPIException and its subclasses:

@app.errorhandler(NewsAPIException)
def handle_news_api_exception(error):
    return jsonify(error.to_dict()), error.status_code

Response Format

All exceptions are converted to consistent JSON responses:

{
    "error": "Human-readable error message",
    "error_code": "MACHINE_READABLE_CODE",
    "status_code": 400,
    "details": {
        "additional": "context",
        "if": "available"
    }
}

Migration Guide

Before (Error Dictionaries)

def get_news_feed(limit):
    if limit < 1:
        return {
            "error": "Limit must be at least 1",
            "news_items": []
        }

    try:
        # ... code ...
    except Exception as e:
        logger.exception("Error getting news feed")
        return {"error": str(e), "news_items": []}

After (Exceptions)

def get_news_feed(limit):
    if limit < 1:
        raise InvalidLimitException(limit)

    try:
        # ... code ...
    except NewsAPIException:
        raise  # Re-raise our custom exceptions
    except Exception as e:
        logger.exception("Error getting news feed")
        raise NewsFeedGenerationException(str(e))

Benefits

  1. Cleaner Code: Functions focus on their primary logic without error response formatting
  2. Consistent Error Handling: All errors follow the same format
  3. Better Testing: Easier to test exception cases with pytest.raises
  4. Type Safety: IDEs can better understand return types
  5. Centralized Logging: Error logging can be handled in one place
  6. HTTP Status Codes: Proper HTTP status codes are automatically set

Testing

Test exception handling using pytest:

import pytest
from local_deep_research.news.exceptions import InvalidLimitException

def test_invalid_limit():
    with pytest.raises(InvalidLimitException) as exc_info:
        news_api.get_news_feed(limit=-1)

    assert exc_info.value.status_code == 400
    assert exc_info.value.details["provided_limit"] == -1

Best Practices

  1. Always catch and re-raise NewsAPIException subclasses:
except NewsAPIException:
    raise  # Let Flask handle it
except Exception as e:
    # Convert to appropriate NewsAPIException
    raise DatabaseAccessException("operation", str(e))
  1. Include relevant details:
raise SubscriptionCreationException(
    "Database constraint violated",
    details={"query": query, "type": subscription_type}
)
  1. Use appropriate exception types: Choose the most specific exception that matches the error condition

  2. Log before raising: For unexpected errors, log the full exception before converting to NewsAPIException

Future Improvements

  • Add retry logic for transient errors
  • Implement exception metrics/monitoring
  • Add internationalization support for error messages
  • Create exception middleware for advanced error handling