Errors¶
In Pydantic you can define a model as a Union
of possible models: whichever validates first – that one gets returned. For us, it means that you can simply Union[...]
all possible successful and error models – and use the Union
as a return type.
Discriminated unions
Consider using discriminated unions to define error models for different error codes.
In addition, Combadge provides some base response classes, which come in handy:
combadge.core.response.BaseResponse ¶
Base model representing any possible service response.
It's got a few abstract methods, which are then implemented by SuccessfulResponse
and ErrorResponse
.
Notes
BaseResponse
is the lower-level API, users should consider inheriting fromSuccessfulResponse
andErrorResponse
.
Source code in combadge/core/response.py
raise_for_result
abstractmethod
¶
Raise an exception if the service call has failed.
Raises:
Type | Description |
---|---|
Error
|
an error derived from |
Returns:
Type | Description |
---|---|
None | Never
|
always |
Calling raise_for_result()
is always possible
BaseResponse
, SuccessfulResponse
, and
ErrorResponse
are designed so that calling raise_for_result()
on any
response would either result in an exception, or guarantee a valid successful response otherwise.
Source code in combadge/core/response.py
unwrap
abstractmethod
¶
Return a response if the call was successful, raise an exception otherwise.
This method allows «unpacking» a response with proper type hinting.
The trick here is that all error responses' unwrap()
are annotated with Never
,
which suggests a type linter, that unwrap()
may never return an error.
Calling unwrap()
is always possible
BaseResponse
, SuccessfulResponse
, and
ErrorResponse
are designed so that calling unwrap()
on any
response would either result in an exception, or return a valid successful response otherwise.
Futhermore, Mypy should be able to figure out the correct type afterwards.
Examples:
>>> class MyResponse(SuccessfulResponse): ...
>>>
>>> class MyErrorResponse(ErrorResponse): ...
>>>
>>> class Service(Protocol):
>>> def call(self) -> MyResponse | MyErrorResponse: ...
>>>
>>> service: Service
>>>
>>> assert_type(service.call(), Union[MyResponse, MyErrorResponse])
>>> assert_type(service.call().unwrap(), MyResponse)
Raises:
Type | Description |
---|---|
Error
|
an error derived from |
Returns:
Type | Description |
---|---|
Self | Never
|
returns |
Source code in combadge/core/response.py
That looks rusty, huh
The resemblance with Rust is not concidential: the author was inspired by std::result::Result
.
combadge.core.response.SuccessfulResponse ¶
Parent model for successful responses.
Users should not use it directly, but inherit their response models from it.
Source code in combadge/core/response.py
raise_for_result ¶
Do nothing.
This call is a no-op since the response is successful by definition.
combadge.core.response.ErrorResponse ¶
Parent model for error responses.
Users should not use it directly, but inherit their response models from it.
Source code in combadge/core/response.py
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 |
|
Error
class-attribute
¶
Dynamically derived exception class.
For each model inherited from ErrorResponse
Combadge generates an exception
class, which is accessible through the <ModelClass>.Error
attribute.
Examples:
>>> class InvalidInput(ErrorResponse):
>>> code: Literal["INVALID_INPUT"]
>>>
>>> try:
>>> service.call(...).raise_for_result()
>>> except InvalidInput.Error:
>>> ...
Why dynamically constructed class?
The problem with Pydantic is that you can't inherit from BaseModel
and Exception
at the same time. Thus, Combadge dynamically constructs a derived exception class,
which is available via the class attribute and raised by raise_for_result()
and unwrap()
.
raise_for_result ¶
Raise the derived exception.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
exception
|
BaseException | None
|
if set, raise the specified exception instead of the derived one. |
None
|
Raises:
Type | Description |
---|---|
Error
|
derived error |