Skip to content

Commit

Permalink
[API] rename our errors so that they have a bit more concise names
Browse files Browse the repository at this point in the history
  • Loading branch information
olivierphi committed Sep 30, 2018
1 parent a488a92 commit d07405e
Show file tree
Hide file tree
Showing 7 changed files with 23 additions and 23 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,16 +111,16 @@ The `CommandBus` is a specialised version of a `MessageBus` (technically it's ju

The API is thus exactly the same than the MessageBus, with the following technical differences:

- the `add_handler(message_class, handler)` method will raise a `api.CommandHandlerAlreadyRegisteredForATypeError` exception if one tries to register a handler for a class of message for which another handler has already been registered before.
- the `handle(message)` method returns a single result rather than a list of result (as we can - and must - have only one single handler for a given message class). If no handler has been registered for this message class, a `api.CommandHandlerNotFoundError` exception is raised.
- the `add_handler(message_class, handler)` method will raise a `api.CommandHandlerAlreadyRegisteredForAType` exception if one tries to register a handler for a class of message for which another handler has already been registered before.
- the `handle(message)` method returns a single result rather than a list of result (as we can - and must - have only one single handler for a given message class). If no handler has been registered for this message class, a `api.CommandHandlerNotFound` exception is raised.

##### Additional options for the CommandBus

The CommandBus constructor have additional options that you can use to customise its behaviour:

- `allow_result`: it's possible to be stricter about the implementation of the CommandBus pattern, by using the `allow_result=True` named parameter when the class is instanciated (the default value being `False`).
In that case the result of the `handle(message)` will always be `None`. By doing this one can follow a more pure version of the design pattern. (and access the result of the Command handling via the application repositories, though a pre-generated id attached to the message for example)
- `locking`: by default the CommandBus will raise a `api.CommandBusAlreadyRunningAMessageError` exception if a message is sent to it while another message is still processed (which can happen if one of the Command Handlers sends a message to the bus).
- `locking`: by default the CommandBus will raise a `api.CommandBusAlreadyProcessingAMessage` exception if a message is sent to it while another message is still processed (which can happen if one of the Command Handlers sends a message to the bus).
You can disable this behaviour by setting the named argument `locking=False` (the default value being `True`).

#### Middlewares
Expand Down
6 changes: 3 additions & 3 deletions src/pymessagebus/_commandbus.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,18 @@ def __init__(

def add_handler(self, message_class: type, message_handler: t.Callable) -> None:
if self._messagebus.has_handler_for(message_class):
raise api.CommandHandlerAlreadyRegisteredForATypeError(
raise api.CommandHandlerAlreadyRegisteredForAType(
f"A command handler is already registed for message class '{message_class}'."
)
self._messagebus.add_handler(message_class, message_handler)

def handle(self, message: object) -> t.Any:
if not self._messagebus.has_handler_for(message.__class__):
raise api.CommandHandlerNotFoundError(
raise api.CommandHandlerNotFound(
f"No command handler is registered for message class '{message.__class__}'."
)
if self._locking and self._is_processing_a_message:
raise api.CommandBusAlreadyRunningAMessageError(
raise api.CommandBusAlreadyProcessingAMessage(
f"CommandBus already processing a message when received a '{message.__class__}' one." # pylint: disable=line-too-long
)
self._is_processing_a_message = True
Expand Down
4 changes: 2 additions & 2 deletions src/pymessagebus/_messagebus.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ def __init__(self, *, middleswares: t.List[api.Middleware] = None) -> None:

def add_handler(self, message_class: type, message_handler: t.Callable) -> None:
if not isinstance(message_class, type):
raise api.MessageHandlerMappingRequiresATypeError(
raise api.MessageHandlerMappingRequiresAType(
f"add_handler() first argument must be a type, got '{type(message_class)}"
)
if not callable(message_handler):
raise api.MessageHandlerMappingRequiresACallableError(
raise api.MessageHandlerMappingRequiresACallable(
f"add_handler() second argument must be a callable, got '{type(message_handler)}"
)

Expand Down
12 changes: 6 additions & 6 deletions src/pymessagebus/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,25 +33,25 @@ def has_handler_for(self, message_class: type) -> bool:
pass


class MessageBusError(BaseException):
class MessageBusError(BaseException, ABC):
pass


class MessageHandlerMappingRequiresATypeError(MessageBusError):
class MessageHandlerMappingRequiresAType(MessageBusError):
pass


class MessageHandlerMappingRequiresACallableError(MessageBusError):
class MessageHandlerMappingRequiresACallable(MessageBusError):
pass


class CommandHandlerNotFoundError(MessageBusError):
class CommandHandlerNotFound(MessageBusError):
pass


class CommandHandlerAlreadyRegisteredForATypeError(MessageBusError):
class CommandHandlerAlreadyRegisteredForAType(MessageBusError):
pass


class CommandBusAlreadyRunningAMessageError(MessageBusError):
class CommandBusAlreadyProcessingAMessage(MessageBusError):
pass
8 changes: 4 additions & 4 deletions tests/_commandbus_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,23 +46,23 @@ def test_handler_must_be_registered_for_a_message_type():
sut = CommandBus()

message = EmptyMessage()
with pytest.raises(api.CommandHandlerNotFoundError):
with pytest.raises(api.CommandHandlerNotFound):
sut.handle(message)


def test_handler_message_must_be_a_type():
sut = CommandBus()

not_a_type = EmptyMessage()
with pytest.raises(api.MessageHandlerMappingRequiresATypeError):
with pytest.raises(api.MessageHandlerMappingRequiresAType):
sut.add_handler(not_a_type, get_one)


def test_multiple_handlers_for_single_message_triggers_error():
sut = CommandBus()
sut.add_handler(EmptyMessage, get_one)

with pytest.raises(api.CommandHandlerAlreadyRegisteredForATypeError):
with pytest.raises(api.CommandHandlerAlreadyRegisteredForAType):
sut.add_handler(EmptyMessage, get_one)


Expand Down Expand Up @@ -150,7 +150,7 @@ def handler_two(msg):
sut.add_handler(MessageWithPayload, handler_which_triggers_handler_two)
sut.add_handler(OtherMessageWithPayload, handler_two)

with pytest.raises(api.CommandBusAlreadyRunningAMessageError):
with pytest.raises(api.CommandBusAlreadyProcessingAMessage):
sut.handle(message)

# But by setting the "locking" option to `False` we should be able to process a message even in such a case:
Expand Down
4 changes: 2 additions & 2 deletions tests/_messagebus_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,15 @@ def test_handler_message_must_be_a_type():
sut = MessageBus()

not_a_type = EmptyMessage()
with pytest.raises(api.MessageHandlerMappingRequiresATypeError):
with pytest.raises(api.MessageHandlerMappingRequiresAType):
sut.add_handler(not_a_type, get_one)


def test_handler_handler_must_be_a_callable():
sut = MessageBus()

not_a_callable = 2
with pytest.raises(api.MessageHandlerMappingRequiresACallableError):
with pytest.raises(api.MessageHandlerMappingRequiresACallable):
sut.add_handler(EmptyMessage, not_a_callable)


Expand Down
6 changes: 3 additions & 3 deletions tests/default/commandbus_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import pytest

from pymessagebus.api import CommandHandlerAlreadyRegisteredForATypeError
from pymessagebus.api import CommandHandlerAlreadyRegisteredForAType


@contextmanager
Expand Down Expand Up @@ -50,7 +50,7 @@ def handler(msg):
from pymessagebus.default import commandbus as default_commandbus

# Now we should trigger an error, since we're re-using the same singleton:
with pytest.raises(CommandHandlerAlreadyRegisteredForATypeError):
with pytest.raises(CommandHandlerAlreadyRegisteredForAType):
default_commandbus.add_handler(EmptyMessage, handler)

test2()
Expand Down Expand Up @@ -116,7 +116,7 @@ def test_multiple_decorators_for_same_message_type_triggers_an_error():
def handler_one(msg):
return 1

with pytest.raises(CommandHandlerAlreadyRegisteredForATypeError):
with pytest.raises(CommandHandlerAlreadyRegisteredForAType):

@sut.register_handler(MessageClassOne)
def handler_two(msg):
Expand Down

0 comments on commit d07405e

Please sign in to comment.