Skip to content

Commit

Permalink
BREAK: merge ErrorResponse.raise_for_result() and expect(), resolves
Browse files Browse the repository at this point in the history
  • Loading branch information
eigenein committed Apr 26, 2023
1 parent 8dbe2f2 commit 13ce120
Show file tree
Hide file tree
Showing 11 changed files with 348 additions and 355 deletions.
4 changes: 2 additions & 2 deletions combadge/core/interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

from abc import abstractmethod
from types import TracebackType
from typing import Any, Optional, Type
from typing import Any, Optional, Protocol, Type

from pydantic import BaseModel
from typing_extensions import Protocol, Self
from typing_extensions import Self

from combadge.core.binder import BaseBoundService, bind
from combadge.core.signature import Signature
Expand Down
3 changes: 1 addition & 2 deletions combadge/core/request.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from typing import Any, Iterable, Mapping, Type, Union
from typing import Any, Iterable, Mapping, NoReturn, Type, Union

from pydantic import validate_model
from typing_extensions import NoReturn

from combadge.core.binder import BaseBoundService
from combadge.core.signature import Signature
Expand Down
40 changes: 13 additions & 27 deletions combadge/core/response.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
from __future__ import annotations

from abc import ABC, abstractmethod
from typing import Any, Generic, Iterable, Type, Union
from typing import Any, Generic, Iterable, NoReturn, Optional, Type, Union

from pydantic import BaseModel
from typing_extensions import NoReturn, Self, TypeAlias
from typing_extensions import Self, TypeAlias

from combadge.core.typevars import ResponseT

Expand All @@ -23,7 +23,7 @@ class BaseResponse(ABC, BaseModel):
"""

@abstractmethod
def raise_for_result(self) -> Union[None, NoReturn]:
def raise_for_result(self, exception: Optional[BaseException] = None) -> Union[None, NoReturn]:
"""
Raise an exception if the service call has failed.
Expand All @@ -44,20 +44,6 @@ def raise_for_result(self) -> Union[None, NoReturn]:
"""
raise NotImplementedError

@abstractmethod
def expect(self, exception_type: Type[BaseException], *args: Any) -> Union[None, NoReturn]:
"""
Raise the specified exception if the service call has failed.
This method is similar to the [`unwrap()`][combadge.core.response.BaseResponse.unwrap],
but allows raising a custom exception instead.
Args:
exception_type: exception class to be raised
args: exception positional arguments
"""
raise NotImplementedError

@abstractmethod
def unwrap(self) -> Union[Self, NoReturn]:
"""
Expand Down Expand Up @@ -96,16 +82,13 @@ class SuccessfulResponse(BaseResponse):
Users should not use it directly, but inherit their response models from it.
"""

def raise_for_result(self) -> None:
def raise_for_result(self, exception: Optional[BaseException] = None) -> None:
"""
Do nothing.
This call is a no-op since the response is successful.
"""

def expect(self, _exception_type: Type[BaseException], *_args: Any) -> None:
"""Do nothing."""

def unwrap(self) -> Self:
"""Return itself since there's no error."""
return self
Expand Down Expand Up @@ -185,13 +168,16 @@ class DerivedException(*exception_bases): # type: ignore
DerivedException.__doc__ = cls.__doc__ or DerivedException.__doc__
cls.Error = DerivedException # type: ignore

def raise_for_result(self) -> NoReturn:
"""Raise the derived exception."""
raise self.Error(self)
def raise_for_result(self, exception: Optional[BaseException] = None) -> NoReturn:
"""
Raise the derived exception.
def expect(self, exception_type: Type[BaseException], *args: Any) -> NoReturn:
"""Raise the specified exception with the derived exception context."""
raise exception_type(*args) from self.Error(self)
Args:
exception: if set, raise the specified exception instead of the derived one.
"""
if not exception:
raise self.Error(self)
raise exception from self.Error(self)

def unwrap(self) -> NoReturn:
"""Raise the derived exception."""
Expand Down
8 changes: 5 additions & 3 deletions combadge/support/soap/response.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Response extensions for SOAP."""

from typing import NoReturn, TypeVar
from typing import NoReturn, Optional, TypeVar

from combadge.core.response import ErrorResponse

Expand All @@ -21,9 +21,11 @@ class BaseSoapFault(ErrorResponse):
code: str
message: str

def raise_for_result(self) -> NoReturn:
def raise_for_result(self, exception: Optional[BaseException] = None) -> NoReturn:
"""Raise the derived error for this fault."""
raise self.Error(self)
if not exception:
raise self.Error(self)
raise exception from self.Error(self)


SoapFaultT = TypeVar("SoapFaultT", bound=BaseSoapFault)
Expand Down
601 changes: 289 additions & 312 deletions poetry.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ mypy = "^1.0.0"
pytest = "^7.2.1"
pytest-cov = "^4.0.0"
types-requests = "^2.28.11.8"
ruff = "^0.0.236"
ruff = "^0.0.263"
pytest-recording = "^0.12.1"
pytest-asyncio = "^0.20.3"

Expand Down
4 changes: 2 additions & 2 deletions tests/core/test_binder.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from abc import abstractmethod
from typing import Any, Callable, Tuple
from typing import Any, Callable, Protocol, Tuple
from unittest.mock import Mock

from typing_extensions import Protocol, assert_type
from typing_extensions import assert_type

from combadge.core.binder import _enumerate_methods, _wrap, bind
from combadge.core.interfaces import SupportsService
Expand Down
29 changes: 29 additions & 0 deletions tests/core/test_response.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from pytest import raises

from combadge.core.response import ErrorResponse


Expand All @@ -15,3 +17,30 @@ class Bar(Foo):
assert issubclass(Bar.Error, Foo.Error)
assert issubclass(Foo.Error, AnotherBaseError)
assert issubclass(Bar.Error, AnotherBaseError)


def test_default_raise_for_result() -> None:
"""Test `raise_for_result()` without the custom exception."""

class Error(ErrorResponse):
pass

with raises(Error.Error):
Error().raise_for_result()


def test_custom_raise_for_result() -> None:
"""Test `raise_for_result()` with the custom exception."""

class Error(ErrorResponse):
pass

class CustomError(Exception):
pass

response = Error()
with raises(CustomError) as e:
response.raise_for_result(CustomError())

assert isinstance(e.value.__cause__, Error.Error)
assert e.value.__cause__.response is response
4 changes: 2 additions & 2 deletions tests/integration/test_country_info_service.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from abc import abstractmethod
from pathlib import Path
from typing import Iterable, List
from typing import Iterable, List, Protocol

from pydantic import BaseModel, Field
from pytest import fixture, mark
from typing_extensions import Annotated, Protocol
from typing_extensions import Annotated
from zeep import Client

from combadge.core.interfaces import SupportsService
Expand Down
4 changes: 2 additions & 2 deletions tests/integration/test_httpbin.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from abc import abstractmethod
from typing import Any, Callable, Dict, Union
from typing import Any, Callable, Dict, Protocol, Union

from httpx import AsyncClient, Client
from pydantic import BaseModel
from pytest import mark
from typing_extensions import Annotated, Protocol
from typing_extensions import Annotated

from combadge.core.interfaces import SupportsService
from combadge.support.http.markers import FormData, FormField, Header, QueryParam, http_method, path
Expand Down
4 changes: 2 additions & 2 deletions tests/integration/test_number_conversion.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from abc import abstractmethod
from pathlib import Path
from typing import Iterable, Union
from typing import Iterable, Literal, Protocol, Union

from pydantic import BaseModel, Field
from pytest import fixture, mark, raises
from typing_extensions import Annotated, Literal, Protocol, assert_type
from typing_extensions import Annotated, assert_type
from zeep import AsyncClient, Client

from combadge.core.interfaces import SupportsService
Expand Down

0 comments on commit 13ce120

Please sign in to comment.