Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions src/sourcerykit/handoff/_preprocess.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from sourcerykit.bootstrap.bootstrap import get_bootstrap
from sourcerykit.errors import SourceryKitBootstrapError
from sourcerykit.logger import get_logger
from sourcerykit.provably._errors import ProvablyNotFoundError
from sourcerykit.provably.service import service

_log = get_logger(__name__)
Expand All @@ -27,8 +28,12 @@ async def run_preprocess() -> None:
_log.error("preprocess_failed_incomplete_bootstrap")
raise SourceryKitBootstrapError("Provably bootstrap incomplete: middleware_id and table_id are required")

# 1. Check if preprocessing is already in progress
status = await service.get_preprocess_status_only(middleware_id, table_id)
# 1. Check if preprocessing is already in progress. A never-preprocessed table has no
# status record yet — treat that as "not started" and start the first run.
try:
status = await service.get_preprocess_status_only(middleware_id, table_id)
except ProvablyNotFoundError:
status = "unknown"
_log.info("preprocess_status_check", status=status)

# 2. If in progress, wait for it to complete first
Expand Down
24 changes: 19 additions & 5 deletions src/sourcerykit/provably/_errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ class ProvablyUnauthorizedError(ProvablyAuthError):
pass


class ProvablyNotFoundError(ProvablyAPIError):
"""Raised when the requested resource does not exist (HTTP 404)."""

pass


@asynccontextmanager
async def provably_auth_error_handler(service: str) -> AsyncIterator[None]:
"""
Expand Down Expand Up @@ -122,17 +128,25 @@ async def provably_error_handler(service: str) -> AsyncIterator[None]:
try:
yield
except httpx.HTTPStatusError as e:
status = e.response.status_code
body = e.response.text
# Log API failures
_log.error(
f"provably_api_rejected_{service}",
status_code=e.response.status_code,
status_code=status,
path=str(e.request.url),
response=e.response.text[:500],
response=body[:500],
)
if status == 404:
raise ProvablyNotFoundError(
message=f"Resource not found for {service_name}: {body}",
status_code=status,
response_body=body,
) from e
raise ProvablyAPIError(
message=f"Provably API rejected {service_name}: {e.response.text}",
status_code=e.response.status_code,
response_body=e.response.text,
message=f"Provably API rejected {service_name}: {body}",
status_code=status,
response_body=body,
) from e

except (ValueError, TypeError, KeyError) as e:
Expand Down
19 changes: 19 additions & 0 deletions tests/unit/test_errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
ProvablyConnectionError,
ProvablyDataError,
ProvablyError,
ProvablyNotFoundError,
ProvablyResourceAlreadyExistsError,
ProvablyUnauthorizedError,
provably_auth_error_handler,
Expand Down Expand Up @@ -43,6 +44,13 @@ def test_api_error_status_code_defaults_to_none(self) -> None:
err = ProvablyAPIError("bad request")
assert err.status_code is None

def test_not_found_is_api_error(self) -> None:
assert issubclass(ProvablyNotFoundError, ProvablyAPIError)

def test_not_found_stores_status_code(self) -> None:
err = ProvablyNotFoundError("not found", status_code=404, response_body="Not Found")
assert err.status_code == 404


# ---------------------------------------------------------------------------
# provably_error_handler
Expand All @@ -66,6 +74,17 @@ async def test_http_status_error_raises_api_error(self) -> None:
assert exc_info.value.status_code == 422
assert "run query" in str(exc_info.value).lower()

async def test_http_404_raises_not_found_error(self) -> None:
mock_request = httpx.Request("GET", "https://api.provably.ai/test")
mock_response = httpx.Response(404, request=mock_request, text="Not Found")
http_err = httpx.HTTPStatusError("404", request=mock_request, response=mock_response)

with pytest.raises(ProvablyNotFoundError) as exc_info:
async with provably_error_handler("get_preprocess_status"):
raise http_err

assert exc_info.value.status_code == 404

async def test_value_error_raises_data_error(self) -> None:
with pytest.raises(ProvablyDataError):
async with provably_error_handler("get_collection"):
Expand Down
Loading