Skip to content
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
edde572
updates
airportyh Mar 13, 2025
f5190e3
refactor
airportyh Mar 13, 2025
766304e
updates to generated test output
airportyh Mar 13, 2025
9b0f693
tests pass
airportyh Mar 13, 2025
29b9353
lint
airportyh Mar 13, 2025
2f545bf
cleanup
airportyh Mar 13, 2025
6b57ec4
use Any
airportyh Mar 13, 2025
7be8c26
allow Any for error type so the existing error types can match them; …
airportyh Mar 13, 2025
c77679e
resnapshotted the tests
airportyh Mar 13, 2025
8dcd439
regened the code
airportyh Mar 13, 2025
cb3aac9
lint
airportyh Mar 14, 2025
cda628f
non-abreviated names
airportyh Mar 14, 2025
70c5ab8
test snapshot
airportyh Mar 14, 2025
1e3aa57
add UnknownRiverError and translate_unknown_error
airportyh Mar 14, 2025
693b174
lint
airportyh Mar 14, 2025
7203fef
fixes
airportyh Mar 14, 2025
26f3867
reverts
airportyh Mar 14, 2025
9b5740a
Merge remote-tracking branch 'origin/main' into th-stricter-error-types
airportyh Mar 14, 2025
86b36a1
fixed test
airportyh Mar 14, 2025
c46e64a
Update src/replit_river/client.py
airportyh Mar 15, 2025
672492f
make error type and translate function dynamic
airportyh Mar 21, 2025
3d4cbf0
Merge branch 'main' into th-stricter-error-types
airportyh Mar 21, 2025
3f959e7
updated snapshots
airportyh Mar 21, 2025
b16f181
lint
airportyh Mar 21, 2025
ada5db6
Make the code more readable
blast-hardcheese Mar 22, 2025
e6edc73
Test for unknown error values
blast-hardcheese Mar 22, 2025
ca6c0fe
Make it possible to request a client that can emit errors
blast-hardcheese Mar 22, 2025
a0db2fe
Adding a streaming method that can emit known and unknown errors
blast-hardcheese Mar 22, 2025
75f3431
Regenerating code
blast-hardcheese Mar 22, 2025
7f98b0c
Only generate the snapshot code once
blast-hardcheese Mar 22, 2025
8f5fce4
Actually write a test for stream errors
blast-hardcheese Mar 22, 2025
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
15 changes: 14 additions & 1 deletion src/replit_river/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
)

from replit_river.client_transport import ClientTransport
from replit_river.error_schema import RiverError, RiverException
from replit_river.error_schema import ERROR_CODE_UNKNOWN, RiverError, RiverException
from replit_river.transport_options import (
HandshakeMetadataType,
TransportOptions,
Expand All @@ -37,6 +37,10 @@ class RiverUnknownValue(BaseModel):
value: Any


class RiverUnknownError(RiverError):
pass


def translate_unknown_value(
value: Any, handler: Callable[[Any], Any], info: ValidationInfo
) -> Any | RiverUnknownValue:
Expand All @@ -46,6 +50,15 @@ def translate_unknown_value(
return RiverUnknownValue(tag="RiverUnknownValue", value=value)


def translate_unknown_error(
value: Any, handler: Callable[[Any], Any], info: ValidationInfo
) -> Any | RiverUnknownError:
try:
return handler(value)
except Exception:
return RiverUnknownError(code=ERROR_CODE_UNKNOWN, message="Unknown error")


class Client(Generic[HandshakeMetadataType]):
def __init__(
self,
Expand Down
11 changes: 6 additions & 5 deletions src/replit_river/codegen/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@

from pydantic import BaseModel, Field, TypeAdapter, WrapValidator
from replit_river.error_schema import RiverError
from replit_river.client import RiverUnknownValue, translate_unknown_value
from replit_river.client import RiverUnknownError, translate_unknown_error

import replit_river as river

Expand Down Expand Up @@ -769,17 +769,18 @@ def _type_adapter_definition(
_type: TypeExpression,
module_info: list[ModuleName],
) -> tuple[list[TypeName], list[ModuleName], list[FileContents]]:
varname = render_type_expr(type_adapter_name)
rendered_type_expr = render_type_expr(_type)
return (
[type_adapter_name],
module_info,
[
FileContents(
dedent(f"""
{render_type_expr(type_adapter_name)}: TypeAdapter[Any] = (
TypeAdapter({rendered_type_expr})
)
""")
{varname}: TypeAdapter[{rendered_type_expr}] = (
TypeAdapter({rendered_type_expr})
)
""")
)
],
)
Expand Down
4 changes: 2 additions & 2 deletions src/replit_river/codegen/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ def render_type_expr(value: TypeExpression) -> str:
case OpenUnionTypeExpr(inner):
return (
"Annotated["
f"{render_type_expr(inner)} | RiverUnknownValue,"
"WrapValidator(translate_unknown_value)"
f"{render_type_expr(inner)} | RiverUnknownError,"
"WrapValidator(translate_unknown_error)"
"]"
)
case TypeName(name):
Expand Down
3 changes: 3 additions & 0 deletions src/replit_river/error_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
# ERROR_CODE_CANCEL is the code used when either server or client cancels the stream.
ERROR_CODE_CANCEL = "CANCEL"

# ERROR_CODE_UNKNOWN is the code for the RiverUnknownError
ERROR_CODE_UNKNOWN = "UNKNOWN"


class RiverError(BaseModel):
"""Error message from the server."""
Expand Down
8 changes: 5 additions & 3 deletions tests/codegen/rpc/generated/test_service/rpc_method.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

from pydantic import BaseModel, Field, TypeAdapter, WrapValidator
from replit_river.error_schema import RiverError
from replit_river.client import RiverUnknownValue, translate_unknown_value
from replit_river.client import RiverUnknownError, translate_unknown_error

import replit_river as river

Expand All @@ -39,11 +39,13 @@ class Rpc_MethodInput(TypedDict):
data: str


Rpc_MethodInputTypeAdapter: TypeAdapter[Any] = TypeAdapter(Rpc_MethodInput)
Rpc_MethodInputTypeAdapter: TypeAdapter[Rpc_MethodInput] = TypeAdapter(Rpc_MethodInput)


class Rpc_MethodOutput(BaseModel):
data: str


Rpc_MethodOutputTypeAdapter: TypeAdapter[Any] = TypeAdapter(Rpc_MethodOutput)
Rpc_MethodOutputTypeAdapter: TypeAdapter[Rpc_MethodOutput] = TypeAdapter(
Rpc_MethodOutput
)
Original file line number Diff line number Diff line change
Expand Up @@ -19,26 +19,40 @@

from pydantic import BaseModel, Field, TypeAdapter, WrapValidator
from replit_river.error_schema import RiverError
from replit_river.client import RiverUnknownValue, translate_unknown_value
from replit_river.client import RiverUnknownError, translate_unknown_error

import replit_river as river


NeedsenumInput = Literal["in_first"] | Literal["in_second"]
encode_NeedsenumInput: Callable[["NeedsenumInput"], Any] = lambda x: x

NeedsenumInputTypeAdapter: TypeAdapter[Any] = TypeAdapter(NeedsenumInput)
NeedsenumInputTypeAdapter: TypeAdapter[NeedsenumInput] = TypeAdapter(NeedsenumInput)

NeedsenumOutput = Annotated[
Literal["out_first"] | Literal["out_second"] | RiverUnknownValue,
WrapValidator(translate_unknown_value),
Literal["out_first"] | Literal["out_second"] | RiverUnknownError,
WrapValidator(translate_unknown_error),
]

NeedsenumOutputTypeAdapter: TypeAdapter[Any] = TypeAdapter(NeedsenumOutput)
NeedsenumOutputTypeAdapter: TypeAdapter[NeedsenumOutput] = TypeAdapter(NeedsenumOutput)


class NeedsenumErrorsOneOf_err_first(RiverError):
code: Literal["err_first"]
message: str


class NeedsenumErrorsOneOf_err_second(RiverError):
code: Literal["err_second"]
message: str


NeedsenumErrors = Annotated[
Literal["err_first"] | Literal["err_second"] | RiverUnknownValue,
WrapValidator(translate_unknown_value),
NeedsenumErrorsOneOf_err_first
| NeedsenumErrorsOneOf_err_second
| RiverUnknownError,
WrapValidator(translate_unknown_error),
]

NeedsenumErrorsTypeAdapter: TypeAdapter[Any] = TypeAdapter(NeedsenumErrors)

NeedsenumErrorsTypeAdapter: TypeAdapter[NeedsenumErrors] = TypeAdapter(NeedsenumErrors)
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

from pydantic import BaseModel, Field, TypeAdapter, WrapValidator
from replit_river.error_schema import RiverError
from replit_river.client import RiverUnknownValue, translate_unknown_value
from replit_river.client import RiverUnknownError, translate_unknown_error

import replit_river as river

Expand Down Expand Up @@ -72,7 +72,9 @@ class NeedsenumobjectInputOneOf_in_second(TypedDict):
else encode_NeedsenumobjectInputOneOf_in_second(x)
)

NeedsenumobjectInputTypeAdapter: TypeAdapter[Any] = TypeAdapter(NeedsenumobjectInput)
NeedsenumobjectInputTypeAdapter: TypeAdapter[NeedsenumobjectInput] = TypeAdapter(
NeedsenumobjectInput
)


class NeedsenumobjectOutputFooOneOf_out_first(BaseModel):
Expand All @@ -96,16 +98,18 @@ class NeedsenumobjectOutputFooOneOf_out_second(BaseModel):
NeedsenumobjectOutputFoo = Annotated[
NeedsenumobjectOutputFooOneOf_out_first
| NeedsenumobjectOutputFooOneOf_out_second
| RiverUnknownValue,
WrapValidator(translate_unknown_value),
| RiverUnknownError,
WrapValidator(translate_unknown_error),
]


class NeedsenumobjectOutput(BaseModel):
foo: Optional[NeedsenumobjectOutputFoo] = None


NeedsenumobjectOutputTypeAdapter: TypeAdapter[Any] = TypeAdapter(NeedsenumobjectOutput)
NeedsenumobjectOutputTypeAdapter: TypeAdapter[NeedsenumobjectOutput] = TypeAdapter(
NeedsenumobjectOutput
)


class NeedsenumobjectErrorsFooAnyOf_0(RiverError):
Expand All @@ -119,13 +123,15 @@ class NeedsenumobjectErrorsFooAnyOf_1(RiverError):
NeedsenumobjectErrorsFoo = Annotated[
NeedsenumobjectErrorsFooAnyOf_0
| NeedsenumobjectErrorsFooAnyOf_1
| RiverUnknownValue,
WrapValidator(translate_unknown_value),
| RiverUnknownError,
WrapValidator(translate_unknown_error),
]


class NeedsenumobjectErrors(RiverError):
foo: Optional[NeedsenumobjectErrorsFoo] = None


NeedsenumobjectErrorsTypeAdapter: TypeAdapter[Any] = TypeAdapter(NeedsenumobjectErrors)
NeedsenumobjectErrorsTypeAdapter: TypeAdapter[NeedsenumobjectErrors] = TypeAdapter(
NeedsenumobjectErrors
)
26 changes: 22 additions & 4 deletions tests/codegen/snapshot/test_enum.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,30 @@
"errors": {
"anyOf": [
{
"type": "string",
"const": "err_first"
"type": "object",
"properties": {
"code": {
"const": "err_first",
"type": "string"
},
"message": {
"type": "string"
}
},
"required": ["code", "message"]
},
{
"type": "string",
"const": "err_second"
"type": "object",
"properties": {
"code": {
"const": "err_second",
"type": "string"
},
"message": {
"type": "string"
}
},
"required": ["code", "message"]
}
]
}
Expand Down
10 changes: 7 additions & 3 deletions tests/codegen/stream/generated/test_service/stream_method.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

from pydantic import BaseModel, Field, TypeAdapter, WrapValidator
from replit_river.error_schema import RiverError
from replit_river.client import RiverUnknownValue, translate_unknown_value
from replit_river.client import RiverUnknownError, translate_unknown_error

import replit_river as river

Expand All @@ -39,11 +39,15 @@ class Stream_MethodInput(TypedDict):
data: str


Stream_MethodInputTypeAdapter: TypeAdapter[Any] = TypeAdapter(Stream_MethodInput)
Stream_MethodInputTypeAdapter: TypeAdapter[Stream_MethodInput] = TypeAdapter(
Stream_MethodInput
)


class Stream_MethodOutput(BaseModel):
data: str


Stream_MethodOutputTypeAdapter: TypeAdapter[Any] = TypeAdapter(Stream_MethodOutput)
Stream_MethodOutputTypeAdapter: TypeAdapter[Stream_MethodOutput] = TypeAdapter(
Stream_MethodOutput
)
Loading