Skip to content

Commit cabc67d

Browse files
committed
feat: add legacy exception compatibility aliases
This PR adds backward compatibility for users importing exceptions from `replicate.exceptions` instead of directly from the `replicate` module. The new `replicate/exceptions.py` module re-exports all exception classes from the internal `_exceptions` module, allowing both import patterns to work: - `from replicate import ModelError` (existing) - `from replicate.exceptions import ModelError` (legacy compatibility) This ensures backward compatibility with code that uses the legacy import pattern shown in documentation examples.
1 parent 8c05e64 commit cabc67d

File tree

5 files changed

+132
-3
lines changed

5 files changed

+132
-3
lines changed

requirements-dev.lock

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,10 @@ mypy-extensions==1.0.0
7878
nodeenv==1.8.0
7979
# via pyright
8080
nox==2023.4.22
81-
packaging==23.2
81+
packaging==25.0
8282
# via nox
8383
# via pytest
84+
# via replicate
8485
platformdirs==3.11.0
8586
# via virtualenv
8687
pluggy==1.5.0

requirements.lock

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ idna==3.4
5252
multidict==6.4.4
5353
# via aiohttp
5454
# via yarl
55+
packaging==25.0
56+
# via replicate
5557
propcache==0.3.1
5658
# via aiohttp
5759
# via yarl

src/replicate/exceptions.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
"""
2+
Legacy compatibility module for exception imports.
3+
4+
This module provides backward compatibility for users importing exceptions
5+
from `replicate.exceptions` instead of directly from `replicate`.
6+
7+
All exceptions are also available directly from the `replicate` module.
8+
"""
9+
10+
from __future__ import annotations
11+
12+
# Import all exceptions from the internal module
13+
from ._exceptions import (
14+
APIError,
15+
ModelError,
16+
ConflictError,
17+
NotFoundError,
18+
APIStatusError,
19+
RateLimitError,
20+
ReplicateError,
21+
APITimeoutError,
22+
BadRequestError,
23+
APIConnectionError,
24+
AuthenticationError,
25+
InternalServerError,
26+
PermissionDeniedError,
27+
UnprocessableEntityError,
28+
APIResponseValidationError,
29+
)
30+
31+
__all__ = [
32+
"APIConnectionError",
33+
"APIError",
34+
"APIResponseValidationError",
35+
"APIStatusError",
36+
"APITimeoutError",
37+
"AuthenticationError",
38+
"BadRequestError",
39+
"ConflictError",
40+
"InternalServerError",
41+
"ModelError",
42+
"NotFoundError",
43+
"PermissionDeniedError",
44+
"RateLimitError",
45+
"ReplicateError",
46+
"UnprocessableEntityError",
47+
]

tests/test_api_token_compatibility.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
from __future__ import annotations
44

5-
import os
65
import pytest
76

87
from replicate import Replicate, AsyncReplicate, ReplicateError
@@ -86,4 +85,4 @@ def test_bearer_token_overrides_env(self, monkeypatch: pytest.MonkeyPatch) -> No
8685
"""Test that explicit bearer_token overrides environment variable."""
8786
monkeypatch.setenv("REPLICATE_API_TOKEN", "env_token")
8887
client = Replicate(bearer_token="explicit_token")
89-
assert client.bearer_token == "explicit_token"
88+
assert client.bearer_token == "explicit_token"

tests/test_legacy_exceptions.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
"""Tests for legacy exception import compatibility."""
2+
3+
from __future__ import annotations
4+
5+
import pytest
6+
7+
8+
def test_legacy_exception_imports():
9+
"""Test that exceptions can be imported from replicate.exceptions."""
10+
# Test importing individual exceptions from replicate.exceptions
11+
from replicate.exceptions import (
12+
APIConnectionError,
13+
APIError,
14+
APIResponseValidationError,
15+
APIStatusError,
16+
APITimeoutError,
17+
AuthenticationError,
18+
BadRequestError,
19+
ConflictError,
20+
InternalServerError,
21+
ModelError,
22+
NotFoundError,
23+
PermissionDeniedError,
24+
RateLimitError,
25+
ReplicateError,
26+
UnprocessableEntityError,
27+
)
28+
29+
# Test that imported exceptions are the same as the ones from replicate
30+
import replicate
31+
32+
assert ModelError is replicate._exceptions.ModelError
33+
assert APIError is replicate.APIError
34+
assert ReplicateError is replicate.ReplicateError
35+
assert BadRequestError is replicate.BadRequestError
36+
assert AuthenticationError is replicate.AuthenticationError
37+
assert NotFoundError is replicate.NotFoundError
38+
assert RateLimitError is replicate.RateLimitError
39+
assert InternalServerError is replicate.InternalServerError
40+
assert APIConnectionError is replicate.APIConnectionError
41+
assert APITimeoutError is replicate.APITimeoutError
42+
43+
44+
def test_readme_example_import():
45+
"""Test that the import pattern shown in README works correctly."""
46+
# This is the exact import pattern shown in the README
47+
import replicate
48+
from replicate.exceptions import ModelError
49+
50+
# Verify ModelError is the correct class
51+
assert ModelError is replicate._exceptions.ModelError
52+
53+
54+
def test_exception_module_all_exports():
55+
"""Test that replicate.exceptions.__all__ contains all expected exceptions."""
56+
import replicate.exceptions
57+
58+
expected_exceptions = [
59+
"APIConnectionError",
60+
"APIError",
61+
"APIResponseValidationError",
62+
"APIStatusError",
63+
"APITimeoutError",
64+
"AuthenticationError",
65+
"BadRequestError",
66+
"ConflictError",
67+
"InternalServerError",
68+
"ModelError",
69+
"NotFoundError",
70+
"PermissionDeniedError",
71+
"RateLimitError",
72+
"ReplicateError",
73+
"UnprocessableEntityError",
74+
]
75+
76+
assert set(replicate.exceptions.__all__) == set(expected_exceptions)
77+
78+
# Also verify they can all be accessed
79+
for exc_name in expected_exceptions:
80+
assert hasattr(replicate.exceptions, exc_name)

0 commit comments

Comments
 (0)