Skip to content

Commit

Permalink
OPT: improve docstrings for BaseResponse 📝
Browse files Browse the repository at this point in the history
  • Loading branch information
eigenein committed Nov 19, 2024
1 parent 8b60b1b commit 44258b0
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 14 deletions.
34 changes: 21 additions & 13 deletions combadge/core/response.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@

from abc import ABC, abstractmethod
from collections.abc import Iterable
from typing import Any, ClassVar, Generic, NoReturn
from typing import Any, ClassVar, Generic, Self

from pydantic import BaseModel
from typing_extensions import Self
from typing_extensions import Never

from combadge.core.errors import CombadgeError
from combadge.core.typevars import ResponseT
Expand All @@ -25,15 +25,15 @@ class BaseResponse(ABC, BaseModel):
"""

@abstractmethod
def raise_for_result(self, exception: BaseException | None = None) -> None | NoReturn:
def raise_for_result(self, exception: BaseException | None = None) -> None | Never:
"""
Raise an exception if the service call has failed.
Raises:
ErrorResponse.Error: an error derived from `ErrorResponse`
Returns:
always `None`
always `#!python None`
Tip: Calling `raise_for_result()` is always possible
`#!python BaseResponse`, `#!python SuccessfulResponse`, and
Expand All @@ -43,12 +43,12 @@ def raise_for_result(self, exception: BaseException | None = None) -> None | NoR
raise NotImplementedError

@abstractmethod
def unwrap(self) -> Self | NoReturn:
def unwrap(self) -> Self | Never:
"""
Return itself if the call was successful, raises an exception otherwise.
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 `NoReturn`,
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.
Tip: Calling `unwrap()` is always possible
Expand All @@ -75,7 +75,7 @@ def unwrap(self) -> Self | NoReturn:
ErrorResponse.Error: an error derived from `ErrorResponse`
Returns:
always returns `Self`
returns `self` by default, may be overridden in user response models
"""
raise NotImplementedError

Expand All @@ -91,11 +91,11 @@ def raise_for_result(self, exception: BaseException | None = None) -> None:
"""
Do nothing.
This call is a no-op since the response is successful.
This call is a no-op since the response is successful by definition.
"""

def unwrap(self) -> Self:
"""Return itself since there's no error."""
"""Return the response since there's no error by definition."""
return self


Expand Down Expand Up @@ -178,19 +178,27 @@ class DerivedException(*exception_bases): # type: ignore[misc]
DerivedException.__doc__ = cls.__doc__ or DerivedException.__doc__
cls.Error = DerivedException

def raise_for_result(self, exception: BaseException | None = None) -> NoReturn:
def raise_for_result(self, exception: BaseException | None = None) -> Never:
"""
Raise the derived exception.
Args:
exception: if set, raise the specified exception instead of the derived one.
Raises:
Self.Error: derived error
"""
if not exception:
raise self.Error(self)
raise exception from self.as_exception()

def unwrap(self) -> NoReturn:
"""Raise the derived exception."""
def unwrap(self) -> Never:
"""
Raise the derived exception.
Raises:
Self.Error: derived error
"""
raise self.as_exception()

def as_exception(self) -> _BaseDerivedError:
Expand Down
14 changes: 13 additions & 1 deletion tests/core/test_response.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
from typing import TYPE_CHECKING

import pytest
from typing_extensions import assert_type

from combadge.core.response import ErrorResponse, _BaseDerivedError
from combadge.core.response import BaseResponse, ErrorResponse, SuccessfulResponse, _BaseDerivedError


def test_error_inheritance() -> None:
Expand Down Expand Up @@ -54,3 +57,12 @@ class CustomError(ErrorResponse):
assert CustomError.Error.__module__ == "tests.core.test_response"
assert CustomError.Error.__name__ == "CustomError.Error"
assert CustomError.Error.__qualname__ == "test_derived_error_magic_attributes.<locals>.CustomError.Error"


if TYPE_CHECKING:

def test_unwrap_type() -> None:
class Response(SuccessfulResponse):
pass

assert_type(BaseResponse.unwrap(Response()), Response)

0 comments on commit 44258b0

Please sign in to comment.