Skip to content

Commit 54271d2

Browse files
committed
feat: add legacy exception compatibility aliases
This 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. Includes comprehensive tests to verify all exception classes are available through the legacy import path.
1 parent a4878ab commit 54271d2

File tree

4 files changed

+129
-1
lines changed

4 files changed

+129
-1
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_legacy_exceptions.py

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

0 commit comments

Comments
 (0)