From c91cbb84219633a09bc5a7c668d7efd542c98d70 Mon Sep 17 00:00:00 2001 From: Subhash Bhushan Date: Sat, 27 Jul 2024 01:44:54 -0700 Subject: [PATCH] Simplify IncorrectUsageError exception --- docs/guides/change-state/commands.md | 5 +- docs/guides/domain-definition/entities.md | 4 +- docs/guides/domain-definition/events.md | 6 +- .../guides/domain-definition/value-objects.md | 6 +- src/protean/core/aggregate.py | 12 +-- src/protean/core/command.py | 6 +- src/protean/core/command_handler.py | 6 +- src/protean/core/domain_service.py | 6 +- src/protean/core/entity.py | 6 +- src/protean/core/event.py | 6 +- src/protean/core/event_handler.py | 6 +- src/protean/core/event_sourced_repository.py | 16 +--- src/protean/core/model.py | 6 +- src/protean/core/repository.py | 12 +-- src/protean/core/subscriber.py | 12 +-- src/protean/core/value_object.py | 26 ++----- src/protean/core/view.py | 14 +--- src/protean/domain/__init__.py | 74 +++++-------------- src/protean/exceptions.py | 2 +- src/protean/fields/association.py | 6 +- src/protean/fields/embedded.py | 10 +-- src/protean/utils/eventing.py | 14 +--- src/protean/utils/mixins.py | 2 +- src/protean/utils/reflection.py | 12 +-- tests/command/test_command_field_types.py | 9 +-- tests/command/test_command_meta.py | 9 +-- tests/command_handler/test_basics.py | 25 +++---- .../test_command_handler_options.py | 9 +-- tests/entity/test_entity_provider_option.py | 7 +- tests/event/test_event_field_types.py | 8 +- tests/event/test_event_meta.py | 9 +-- tests/event/tests.py | 2 +- tests/event_sourced_aggregates/test_apply.py | 33 ++++----- .../test_event_association_with_aggregate.py | 10 +-- tests/event_sourced_repository/test_add.py | 4 +- ...est_retrieving_event_sourced_repository.py | 17 ++--- tests/event_store/test_appending_commands.py | 9 +-- tests/field/test_list.py | 10 +-- tests/field/test_vo.py | 8 +- tests/message/test_message_to_object.py | 2 +- tests/reflection/test_declared_fields.py | 10 +-- tests/reflection/test_fields.py | 10 +-- .../test_repository_registration.py | 8 +- tests/repository/tests.py | 4 +- tests/value_object/test_immutability.py | 9 +-- .../value_object/test_vo_field_properties.py | 26 ++----- .../views/test_view_validations_for_fields.py | 9 +-- 47 files changed, 160 insertions(+), 362 deletions(-) diff --git a/docs/guides/change-state/commands.md b/docs/guides/change-state/commands.md index 9dedc83d..d6844a9d 100644 --- a/docs/guides/change-state/commands.md +++ b/docs/guides/change-state/commands.md @@ -81,9 +81,6 @@ Out[3]: diff --git a/docs/guides/domain-definition/events.md b/docs/guides/domain-definition/events.md index eea1fb85..1dfceafa 100644 --- a/docs/guides/domain-definition/events.md +++ b/docs/guides/domain-definition/events.md @@ -195,9 +195,5 @@ In [2]: renamed = UserRenamed(user_id=user.id, name="John Doe Jr.") In [3]: renamed.name = "John Doe Sr." ... -IncorrectUsageError: { - '_message': [ - 'Event/Command Objects are immutable and cannot be modified once created' - ] -} +IncorrectUsageError: 'Event/Command Objects are immutable and cannot be modified once created' ``` diff --git a/docs/guides/domain-definition/value-objects.md b/docs/guides/domain-definition/value-objects.md index 552d7461..a67beebc 100644 --- a/docs/guides/domain-definition/value-objects.md +++ b/docs/guides/domain-definition/value-objects.md @@ -228,7 +228,7 @@ In [3]: class Balance(BaseValueObject): ...: currency = String(max_length=3, unique=True) ...: amount = Float() ... -IncorrectUsageError: {'_value_object': ["Value Objects cannot contain fields marked 'unique' (field 'currency')"]} +IncorrectUsageError: "Value Objects cannot contain fields marked 'unique' (field 'currency')" ``` Same case if you try to find a Value Object's `id_field`: @@ -238,7 +238,7 @@ In [4]: from protean.reflection import id_field In [5]: id_field(Balance) ... -IncorrectUsageError: {"identity": [" does not have identity fields"]} +IncorrectUsageError: " does not have identity fields" ``` ## Immutability @@ -250,5 +250,5 @@ In [1]: bal1 = Balance(currency='USD', amount=100.0) In [2]: bal1.currency = "CAD" ... -IncorrectUsageError: {'_value_object': ["Value Objects are immutable and cannot be modified once created"]} +IncorrectUsageError: "Value Objects are immutable and cannot be modified once created" ``` diff --git a/src/protean/core/aggregate.py b/src/protean/core/aggregate.py index 0697095b..c027a7c8 100644 --- a/src/protean/core/aggregate.py +++ b/src/protean/core/aggregate.py @@ -257,11 +257,7 @@ def apply(fn): if len(typing.get_type_hints(fn)) > 2: raise IncorrectUsageError( - { - "_entity": [ - f"Handler method `{fn.__name__}` has incorrect number of arguments" - ] - } + f"Handler method `{fn.__name__}` has incorrect number of arguments" ) try: @@ -276,11 +272,7 @@ def apply(fn): ) except StopIteration: raise IncorrectUsageError( - { - "_entity": [ - f"Apply method `{fn.__name__}` should accept an argument annotated with the Event class" - ] - } + f"Apply method `{fn.__name__}` should accept an argument annotated with the Event class" ) @functools.wraps(fn) diff --git a/src/protean/core/command.py b/src/protean/core/command.py index a4919b95..1a3265a0 100644 --- a/src/protean/core/command.py +++ b/src/protean/core/command.py @@ -59,11 +59,7 @@ def command_factory(element_cls, domain, **opts): if not element_cls.meta_.part_of and not element_cls.meta_.abstract: raise IncorrectUsageError( - { - "_command": [ - f"Command `{element_cls.__name__}` needs to be associated with an aggregate or a stream" - ] - } + f"Command `{element_cls.__name__}` needs to be associated with an aggregate or a stream" ) return element_cls diff --git a/src/protean/core/command_handler.py b/src/protean/core/command_handler.py index 94a588a9..49d7e236 100644 --- a/src/protean/core/command_handler.py +++ b/src/protean/core/command_handler.py @@ -28,11 +28,7 @@ def command_handler_factory(element_cls, domain, **opts): if not element_cls.meta_.part_of: raise IncorrectUsageError( - { - "_entity": [ - f"Command Handler `{element_cls.__name__}` needs to be associated with an Aggregate" - ] - } + f"Command Handler `{element_cls.__name__}` needs to be associated with an Aggregate" ) return element_cls diff --git a/src/protean/core/domain_service.py b/src/protean/core/domain_service.py index b238ac1a..b9fbe9d7 100644 --- a/src/protean/core/domain_service.py +++ b/src/protean/core/domain_service.py @@ -114,11 +114,7 @@ def domain_service_factory(element_cls, domain, **opts): if not element_cls.meta_.part_of or len(element_cls.meta_.part_of) < 2: raise IncorrectUsageError( - { - "_entity": [ - f"Domain Service `{element_cls.__name__}` needs to be associated with two or more Aggregates" - ] - } + f"Domain Service `{element_cls.__name__}` needs to be associated with two or more Aggregates" ) # Iterate through methods marked as `@invariant` and record them for later use diff --git a/src/protean/core/entity.py b/src/protean/core/entity.py index 428a9268..2d0feae0 100644 --- a/src/protean/core/entity.py +++ b/src/protean/core/entity.py @@ -621,11 +621,7 @@ def entity_factory(element_cls, domain, **opts): if not element_cls.meta_.part_of: raise IncorrectUsageError( - { - "_entity": [ - f"Entity `{element_cls.__name__}` needs to be associated with an Aggregate" - ] - } + f"Entity `{element_cls.__name__}` needs to be associated with an Aggregate" ) # Set up reference fields diff --git a/src/protean/core/event.py b/src/protean/core/event.py index 7396b05f..cedaeb37 100644 --- a/src/protean/core/event.py +++ b/src/protean/core/event.py @@ -58,11 +58,7 @@ def domain_event_factory(element_cls, domain, **opts): if not element_cls.meta_.part_of and not element_cls.meta_.abstract: raise IncorrectUsageError( - { - "_event": [ - f"Event `{element_cls.__name__}` needs to be associated with an aggregate or a stream" - ] - } + f"Event `{element_cls.__name__}` needs to be associated with an aggregate or a stream" ) return element_cls diff --git a/src/protean/core/event_handler.py b/src/protean/core/event_handler.py index 44b2d0dc..a832d794 100644 --- a/src/protean/core/event_handler.py +++ b/src/protean/core/event_handler.py @@ -36,11 +36,7 @@ def event_handler_factory(element_cls, domain, **opts): if not (element_cls.meta_.part_of or element_cls.meta_.stream_category): raise IncorrectUsageError( - { - "_entity": [ - f"Event Handler `{element_cls.__name__}` needs to be associated with an aggregate or a stream" - ] - } + f"Event Handler `{element_cls.__name__}` needs to be associated with an aggregate or a stream" ) return element_cls diff --git a/src/protean/core/event_sourced_repository.py b/src/protean/core/event_sourced_repository.py index 291898cf..33b23e6a 100644 --- a/src/protean/core/event_sourced_repository.py +++ b/src/protean/core/event_sourced_repository.py @@ -33,9 +33,7 @@ def __init__(self, domain) -> None: def add(self, aggregate: BaseAggregate) -> None: if aggregate is None: - raise IncorrectUsageError( - {"_entity": ["Aggregate object to persist is invalid"]} - ) + raise IncorrectUsageError("Aggregate object to persist is invalid") # Proceed only if aggregate has events if len(aggregate._events) > 0: @@ -105,20 +103,12 @@ def event_sourced_repository_factory(element_cls, domain, **opts): if not element_cls.meta_.part_of: raise IncorrectUsageError( - { - "_entity": [ - f"Repository `{element_cls.__name__}` should be associated with an Aggregate" - ] - } + f"Repository `{element_cls.__name__}` should be associated with an Aggregate" ) if not element_cls.meta_.part_of.meta_.is_event_sourced: raise IncorrectUsageError( - { - "_entity": [ - f"Repository `{element_cls.__name__}` can only be associated with an Event Sourced Aggregate" - ] - } + f"Repository `{element_cls.__name__}` can only be associated with an Event Sourced Aggregate" ) return element_cls diff --git a/src/protean/core/model.py b/src/protean/core/model.py index 4da9b289..301ee4f9 100644 --- a/src/protean/core/model.py +++ b/src/protean/core/model.py @@ -41,11 +41,7 @@ def model_factory(element_cls, domain, **opts): if not element_cls.meta_.part_of: raise IncorrectUsageError( - { - "_entity": [ - f"Model `{element_cls.__name__}` should be associated with an Entity or Aggregate" - ] - } + f"Model `{element_cls.__name__}` should be associated with an Entity or Aggregate" ) return element_cls diff --git a/src/protean/core/repository.py b/src/protean/core/repository.py index b518119b..8fc7bb84 100644 --- a/src/protean/core/repository.py +++ b/src/protean/core/repository.py @@ -266,11 +266,7 @@ def repository_factory(element_cls, domain, **opts): if not element_cls.meta_.part_of: raise IncorrectUsageError( - { - "_entity": [ - f"Repository `{element_cls.__name__}` should be associated with an Aggregate" - ] - } + f"Repository `{element_cls.__name__}` should be associated with an Aggregate" ) # FIXME Uncomment @@ -284,11 +280,7 @@ def repository_factory(element_cls, domain, **opts): database.value for database in Database ]: raise IncorrectUsageError( - { - "_entity": [ - f"Repository `{element_cls.__name__}` should be associated with a valid Database" - ] - } + f"Repository `{element_cls.__name__}` should be associated with a valid Database" ) return element_cls diff --git a/src/protean/core/subscriber.py b/src/protean/core/subscriber.py index 074bd1ef..b1b092ea 100644 --- a/src/protean/core/subscriber.py +++ b/src/protean/core/subscriber.py @@ -39,20 +39,12 @@ def subscriber_factory(element_cls, domain, **opts): if not element_cls.meta_.event: raise IncorrectUsageError( - { - "_entity": [ - f"Subscriber `{element_cls.__name__}` needs to be associated with an Event" - ] - } + f"Subscriber `{element_cls.__name__}` needs to be associated with an Event" ) if not element_cls.meta_.broker: raise IncorrectUsageError( - { - "_entity": [ - f"Subscriber `{element_cls.__name__}` needs to be associated with a Broker" - ] - } + f"Subscriber `{element_cls.__name__}` needs to be associated with a Broker" ) return element_cls diff --git a/src/protean/core/value_object.py b/src/protean/core/value_object.py index 8498522a..1b3ca9b9 100644 --- a/src/protean/core/value_object.py +++ b/src/protean/core/value_object.py @@ -44,12 +44,8 @@ def __validate_for_basic_field_types(subclass): # Value objects can hold all kinds of fields, except associations if isinstance(field_obj, (Reference, Association)): raise IncorrectUsageError( - { - "_value_object": [ - f"Value Objects cannot have associations. " - f"Remove {field_name} ({field_obj.__class__.__name__}) from class {subclass.__name__}" - ] - } + f"Value Objects cannot have associations. " + f"Remove {field_name} ({field_obj.__class__.__name__}) from class {subclass.__name__}" ) @classmethod @@ -57,11 +53,7 @@ def __validate_for_non_identifier_fields(subclass): for field_name, field_obj in fields(subclass).items(): if field_obj.identifier: raise IncorrectUsageError( - { - "_value_object": [ - f"Value Objects cannot contain fields marked 'identifier' (field '{field_name}')" - ] - } + f"Value Objects cannot contain fields marked 'identifier' (field '{field_name}')" ) @classmethod @@ -69,11 +61,7 @@ def __validate_for_non_unique_fields(subclass): for field_name, field_obj in fields(subclass).items(): if field_obj.unique: raise IncorrectUsageError( - { - "_value_object": [ - f"Value Objects cannot contain fields marked 'unique' (field '{field_name}')" - ] - } + f"Value Objects cannot contain fields marked 'unique' (field '{field_name}')" ) def __init__(self, *template, **kwargs): # noqa: C901 @@ -176,11 +164,7 @@ def __setattr__(self, name, value): return super().__setattr__(name, value) else: raise IncorrectUsageError( - { - "_value_object": [ - "Value Objects are immutable and cannot be modified once created" - ] - } + "Value Objects are immutable and cannot be modified once created" ) def _postcheck(self, return_errors=False): diff --git a/src/protean/core/view.py b/src/protean/core/view.py index 051197e0..e833d335 100644 --- a/src/protean/core/view.py +++ b/src/protean/core/view.py @@ -65,12 +65,8 @@ def __validate_for_basic_field_types(subclass): for field_name, field_obj in declared_fields(subclass).items(): if isinstance(field_obj, (Reference, Association, ValueObject)): raise IncorrectUsageError( - { - "_entity": [ - f"Views can only contain basic field types. " - f"Remove {field_name} ({field_obj.__class__.__name__}) from class {subclass.__name__}" - ] - } + f"Views can only contain basic field types. " + f"Remove {field_name} ({field_obj.__class__.__name__}) from class {subclass.__name__}" ) def __init__(self, *template, **kwargs): @@ -110,11 +106,7 @@ def view_factory(element_cls, domain, **opts): if not element_cls.meta_.abstract and not hasattr(element_cls, _ID_FIELD_NAME): raise IncorrectUsageError( - { - "_entity": [ - f"View `{element_cls.__name__}` needs to have at least one identifier" - ] - } + f"View `{element_cls.__name__}` needs to have at least one identifier" ) element_cls.meta_.provider = ( diff --git a/src/protean/domain/__init__.py b/src/protean/domain/__init__.py index b40d84ac..2fb4ca3d 100644 --- a/src/protean/domain/__init__.py +++ b/src/protean/domain/__init__.py @@ -431,7 +431,7 @@ def factory_for(self, domain_object_type): if domain_object_type.value not in factories: raise IncorrectUsageError( - {"_entity": [f"Unknown Element Type `{domain_object_type.value}`"]} + f"Unknown Element Type `{domain_object_type.value}`" ) return factories[domain_object_type.value] @@ -693,21 +693,13 @@ def _validate_domain(self): if isinstance(field_obj, (HasOne, HasMany)): if isinstance(field_obj.to_cls, str): raise IncorrectUsageError( - { - "element": ( - f"Unresolved target `{field_obj.to_cls}` for field " - f"`{aggregate.__name__}:{field_obj.name}`" - ) - } + f"Unresolved target `{field_obj.to_cls}` for field " + f"`{aggregate.__name__}:{field_obj.name}`" ) if field_obj.to_cls.element_type != DomainObjects.ENTITY: raise IncorrectUsageError( - { - "element": ( - f"Field `{field_obj.field_name}` in `{aggregate.cls.__name__}` " - "is not linked to an Entity class" - ) - } + f"Field `{field_obj.field_name}` in `{aggregate.cls.__name__}` " + "is not linked to an Entity class" ) # Check that no two event sourced aggregates have the same event class in their @@ -733,12 +725,8 @@ def _validate_domain(self): ) if len(duplicate_event_class_names) != 0: raise IncorrectUsageError( - { - "_event": [ - f"Events are associated with multiple event sourced aggregates: " - f"{', '.join(duplicate_event_class_names)}" - ] - } + f"Events are associated with multiple event sourced aggregates: " + f"{', '.join(duplicate_event_class_names)}" ) # Check that entities have the same provider as the aggregate @@ -748,12 +736,8 @@ def _validate_domain(self): != entity.cls.meta_.provider ): raise IncorrectUsageError( - { - "element": ( - f"Entity `{entity.cls.__name__}` has a different provider " - f"than its aggregate `{entity.cls.meta_.aggregate_cluster.__name__}`" - ) - } + f"Entity `{entity.cls.__name__}` has a different provider " + f"than its aggregate `{entity.cls.meta_.aggregate_cluster.__name__}`" ) def _assign_aggregate_clusters(self): @@ -822,9 +806,7 @@ def register_external_event(self, event_cls: Type[BaseEvent], type_string: str): not issubclass(event_cls, BaseEvent) or event_cls.element_type != DomainObjects.EVENT ): - raise IncorrectUsageError( - {"element": [f"Class `{event_cls.__name__}` is not an Event"]} - ) + raise IncorrectUsageError(f"Class `{event_cls.__name__}` is not an Event") self._events_and_commands[type_string] = event_cls @@ -845,23 +827,15 @@ def _setup_command_handlers(self): method._target_cls ) or not issubclass(method._target_cls, BaseCommand): raise IncorrectUsageError( - { - "_command_handler": [ - f"Method `{method_name}` in Command Handler `{element.cls.__name__}` " - "is not associated with a command" - ] - } + f"Method `{method_name}` in Command Handler `{element.cls.__name__}` " + "is not associated with a command" ) # Throw error if target_cls is not associated with an aggregate if not method._target_cls.meta_.part_of: raise IncorrectUsageError( - { - "_command_handler": [ - f"Command `{method._target_cls.__name__}` in Command Handler `{element.cls.__name__}` " - "is not associated with an aggregate" - ] - } + f"Command `{method._target_cls.__name__}` in Command Handler `{element.cls.__name__}` " + "is not associated with an aggregate" ) if ( @@ -869,12 +843,8 @@ def _setup_command_handlers(self): != element.cls.meta_.part_of ): raise IncorrectUsageError( - { - "_command_handler": [ - f"Command `{method._target_cls.__name__}` in Command Handler `{element.cls.__name__}` " - "is not associated with the same aggregate as the Command Handler" - ] - } + f"Command `{method._target_cls.__name__}` in Command Handler `{element.cls.__name__}` " + "is not associated with the same aggregate as the Command Handler" ) command_type = ( @@ -1101,11 +1071,7 @@ def process(self, command: BaseCommand, asynchronous: bool = True) -> Optional[A not in self.registry._elements[DomainObjects.COMMAND.value] ): raise IncorrectUsageError( - { - "element": [ - f"Element {command.__class__.__name__} is not registered in domain {self.name}" - ] - } + f"Element {command.__class__.__name__} is not registered in domain {self.name}" ) command_with_metadata = self._enrich_command(command) @@ -1154,11 +1120,7 @@ def handlers_for(self, event: BaseEvent) -> List[BaseEventHandler]: def repository_for(self, element_cls) -> BaseRepository: if isinstance(element_cls, str): raise IncorrectUsageError( - { - "element": [ - f"Element {element_cls} is not registered in domain {self.name}" - ] - } + f"Element {element_cls} is not registered in domain {self.name}" ) if ( diff --git a/src/protean/exceptions.py b/src/protean/exceptions.py index 2573cfe9..47e9cc45 100644 --- a/src/protean/exceptions.py +++ b/src/protean/exceptions.py @@ -72,7 +72,7 @@ class NotSupportedError(ProteanException): """Object does not support the operation being performed""" -class IncorrectUsageError(ProteanExceptionWithMessage): +class IncorrectUsageError(ProteanException): """Usage of a Domain Element violates principles""" diff --git a/src/protean/fields/association.py b/src/protean/fields/association.py index b68f46d5..dc9d5d82 100644 --- a/src/protean/fields/association.py +++ b/src/protean/fields/association.py @@ -727,11 +727,7 @@ def get(self, instance, **kwargs): if len(data) > 1: raise exceptions.TooManyObjectsError( - { - "self.field_name": [ - "Multiple linked entities matching criteria found" - ] - } + "Multiple linked entities matching criteria found" ) return data[0] diff --git a/src/protean/fields/embedded.py b/src/protean/fields/embedded.py index e7524cf5..3091d660 100644 --- a/src/protean/fields/embedded.py +++ b/src/protean/fields/embedded.py @@ -73,14 +73,8 @@ def _validate_value_object_cls(self, value_object_cls): if not issubclass(value_object_cls, BaseValueObject): raise IncorrectUsageError( - { - "_value_object": [ - ( - f"`{value_object_cls.__name__}` is not a valid Value Object " - "and cannot be embedded in a Value Object field" - ) - ] - } + f"`{value_object_cls.__name__}` is not a valid Value Object " + "and cannot be embedded in a Value Object field" ) @property diff --git a/src/protean/utils/eventing.py b/src/protean/utils/eventing.py index 94caa658..4ac0b800 100644 --- a/src/protean/utils/eventing.py +++ b/src/protean/utils/eventing.py @@ -83,12 +83,8 @@ def __validate_for_basic_field_types(subclass): # Value objects can hold all kinds of fields, except associations if isinstance(field_obj, (Reference, Association)): raise IncorrectUsageError( - { - "_message": [ - f"Events/Commands cannot have associations. " - f"Remove {field_name} ({field_obj.__class__.__name__}) from class {subclass.__name__}" - ] - } + f"Events/Commands cannot have associations. " + f"Remove {field_name} ({field_obj.__class__.__name__}) from class {subclass.__name__}" ) def __setattr__(self, name, value): @@ -96,11 +92,7 @@ def __setattr__(self, name, value): return super().__setattr__(name, value) else: raise IncorrectUsageError( - { - "_message": [ - "Event/Command Objects are immutable and cannot be modified once created" - ] - } + "Event/Command Objects are immutable and cannot be modified once created" ) @classmethod diff --git a/src/protean/utils/mixins.py b/src/protean/utils/mixins.py index 285ace78..60647389 100644 --- a/src/protean/utils/mixins.py +++ b/src/protean/utils/mixins.py @@ -88,7 +88,7 @@ def to_object(self) -> Union[BaseEvent, BaseCommand]: ]: # We are dealing with a malformed or unknown message raise InvalidDataError( - {"_message": ["Message type is not supported for deserialization"]} + {"kind": ["Message type is not supported for deserialization"]} ) element_cls = current_domain._events_and_commands.get(self.metadata.type, None) diff --git a/src/protean/utils/reflection.py b/src/protean/utils/reflection.py index 1d672b8c..59d4e927 100644 --- a/src/protean/utils/reflection.py +++ b/src/protean/utils/reflection.py @@ -23,9 +23,7 @@ def fields(class_or_instance: Type[Element] | Element) -> dict[str, Field]: try: fields_dict = getattr(class_or_instance, _FIELDS) except AttributeError: - raise IncorrectUsageError( - {"field": [f"{class_or_instance} does not have fields"]} - ) + raise IncorrectUsageError(f"{class_or_instance} does not have fields") return fields_dict @@ -42,9 +40,7 @@ def data_fields(class_or_instance: Type[Element] | Element) -> dict[str, Field]: # Remove internal fields fields_dict.pop("_metadata", None) except AttributeError: - raise IncorrectUsageError( - {"field": [f"{class_or_instance} does not have fields"]} - ) + raise IncorrectUsageError(f"{class_or_instance} does not have fields") return fields_dict @@ -125,9 +121,7 @@ def declared_fields(class_or_instance: Type[Element] | Element) -> dict[str, Fie fields_dict.pop("_version", None) fields_dict.pop("_metadata", None) except AttributeError: - raise IncorrectUsageError( - {"field": [f"{class_or_instance} does not have fields"]} - ) + raise IncorrectUsageError(f"{class_or_instance} does not have fields") return fields_dict diff --git a/tests/command/test_command_field_types.py b/tests/command/test_command_field_types.py index e279e5d5..7f3d1162 100644 --- a/tests/command/test_command_field_types.py +++ b/tests/command/test_command_field_types.py @@ -33,8 +33,7 @@ class Register(BaseCommand): name = String() account = HasOne(Account) - assert exc.value.messages == { - "_message": [ - "Events/Commands cannot have associations. Remove account (HasOne) from class Register" - ] - } + assert ( + exc.value.args[0] + == "Events/Commands cannot have associations. Remove account (HasOne) from class Register" + ) diff --git a/tests/command/test_command_meta.py b/tests/command/test_command_meta.py index b3a2a1dc..945fc740 100644 --- a/tests/command/test_command_meta.py +++ b/tests/command/test_command_meta.py @@ -27,11 +27,10 @@ def test_command_definition_without_aggregate_or_stream(test_domain): with pytest.raises(IncorrectUsageError) as exc: test_domain.register(Register) - assert exc.value.messages == { - "_command": [ - "Command `Register` needs to be associated with an aggregate or a stream" - ] - } + assert ( + exc.value.args[0] + == "Command `Register` needs to be associated with an aggregate or a stream" + ) def test_that_abstract_commands_can_be_defined_without_aggregate_or_stream(test_domain): diff --git a/tests/command_handler/test_basics.py b/tests/command_handler/test_basics.py index ccdfc2ed..9b460521 100644 --- a/tests/command_handler/test_basics.py +++ b/tests/command_handler/test_basics.py @@ -43,11 +43,9 @@ def something(self, _: Registered): with pytest.raises(IncorrectUsageError) as exc: test_domain.init(traverse=False) - assert exc.value.messages == { - "_command_handler": [ - "Method `something` in Command Handler `UserCommandHandlers` is not associated with a command" - ] - } + assert exc.value.args[0] == ( + "Method `something` in Command Handler `UserCommandHandlers` is not associated with a command" + ) def test_commands_have_to_be_registered_with_an_aggregate(test_domain): @@ -62,11 +60,9 @@ def something(self, _: Register): with pytest.raises(IncorrectUsageError) as exc: test_domain.init(traverse=False) - assert exc.value.messages == { - "_command_handler": [ - "Command `Register` in Command Handler `UserCommandHandlers` is not associated with an aggregate" - ] - } + assert exc.value.args[0] == ( + "Command `Register` in Command Handler `UserCommandHandlers` is not associated with an aggregate" + ) def test_command_and_command_handler_have_to_be_associated_with_same_aggregate( @@ -89,10 +85,9 @@ class User2(BaseAggregate): with pytest.raises(IncorrectUsageError) as exc: test_domain.init(traverse=False) - assert exc.value.messages == { - "_command_handler": [ - "Command `Register` in Command Handler `UserCommandHandlers` is not associated with the same aggregate as the Command Handler" - ] - } + assert exc.value.args[0] == ( + "Command `Register` in Command Handler `UserCommandHandlers` is not " + "associated with the same aggregate as the Command Handler" + ) test_domain.register(UserCommandHandlers, part_of=User) diff --git a/tests/command_handler/test_command_handler_options.py b/tests/command_handler/test_command_handler_options.py index cb1a6f3a..fa09e157 100644 --- a/tests/command_handler/test_command_handler_options.py +++ b/tests/command_handler/test_command_handler_options.py @@ -24,11 +24,10 @@ class UserCommandHandlers(BaseCommandHandler): with pytest.raises(IncorrectUsageError) as exc: test_domain.register(UserCommandHandlers) - assert exc.value.messages == { - "_entity": [ - "Command Handler `UserCommandHandlers` needs to be associated with an Aggregate" - ] - } + assert ( + exc.value.args[0] + == "Command Handler `UserCommandHandlers` needs to be associated with an Aggregate" + ) def test_part_of_specified_as_a_meta_attribute(test_domain): diff --git a/tests/entity/test_entity_provider_option.py b/tests/entity/test_entity_provider_option.py index 67b287d7..122b6652 100644 --- a/tests/entity/test_entity_provider_option.py +++ b/tests/entity/test_entity_provider_option.py @@ -52,6 +52,7 @@ def test_entity_provider_is_same_as_aggregate_provider(self, test_domain): with pytest.raises(IncorrectUsageError) as exc: test_domain.init(traverse=False) - assert exc.value.messages == { - "element": "Entity `Dean` has a different provider than its aggregate `Department`" - } + assert ( + exc.value.args[0] + == "Entity `Dean` has a different provider than its aggregate `Department`" + ) diff --git a/tests/event/test_event_field_types.py b/tests/event/test_event_field_types.py index d9d631cf..0a0814e2 100644 --- a/tests/event/test_event_field_types.py +++ b/tests/event/test_event_field_types.py @@ -33,8 +33,6 @@ class UserRegistered(BaseEvent): name = String() account = HasOne(Account) - assert exc.value.messages == { - "_message": [ - "Events/Commands cannot have associations. Remove account (HasOne) from class UserRegistered" - ] - } + assert exc.value.args[0] == ( + "Events/Commands cannot have associations. Remove account (HasOne) from class UserRegistered" + ) diff --git a/tests/event/test_event_meta.py b/tests/event/test_event_meta.py index 805fb046..76db6b25 100644 --- a/tests/event/test_event_meta.py +++ b/tests/event/test_event_meta.py @@ -28,11 +28,10 @@ def test_event_definition_without_aggregate_or_stream(test_domain): with pytest.raises(IncorrectUsageError) as exc: test_domain.register(UserLoggedIn) - assert exc.value.messages == { - "_event": [ - "Event `UserLoggedIn` needs to be associated with an aggregate or a stream" - ] - } + assert ( + exc.value.args[0] + == "Event `UserLoggedIn` needs to be associated with an aggregate or a stream" + ) def test_that_abstract_events_can_be_defined_without_aggregate_or_stream(test_domain): diff --git a/tests/event/tests.py b/tests/event/tests.py index 6b9df9ca..757e2271 100644 --- a/tests/event/tests.py +++ b/tests/event/tests.py @@ -182,7 +182,7 @@ class Dummy: with pytest.raises(IncorrectUsageError) as exc: test_domain.register_external_event(Dummy, "Bar.ExternalEvent.v1") - assert exc.value.messages == {"element": ["Class `Dummy` is not an Event"]} + assert exc.value.args[0] == "Class `Dummy` is not an Event" class TestDomainEventEquivalence: diff --git a/tests/event_sourced_aggregates/test_apply.py b/tests/event_sourced_aggregates/test_apply.py index 461c721e..f40c7680 100644 --- a/tests/event_sourced_aggregates/test_apply.py +++ b/tests/event_sourced_aggregates/test_apply.py @@ -98,9 +98,9 @@ class _(BaseAggregate): def sent(self, event: Sent, _: str) -> None: pass - assert exc.value.messages == { - "_entity": ["Handler method `sent` has incorrect number of arguments"] - } + assert ( + exc.value.args[0] == "Handler method `sent` has incorrect number of arguments" + ) def test_that_apply_decorator_without_event_cls_raises_error(): @@ -117,11 +117,10 @@ class _(BaseAggregate): def sent(self, _: Send) -> None: pass - assert exc.value.messages == { - "_entity": [ - "Apply method `sent` should accept an argument annotated with the Event class" - ] - } + assert ( + exc.value.args[0] + == "Apply method `sent` should accept an argument annotated with the Event class" + ) # Argument should be annotated with pytest.raises(IncorrectUsageError) as exc: @@ -133,11 +132,10 @@ class _(BaseAggregate): def sent(self, _) -> None: pass - assert exc.value.messages == { - "_entity": [ - "Apply method `sent` should accept an argument annotated with the Event class" - ] - } + assert ( + exc.value.args[0] + == "Apply method `sent` should accept an argument annotated with the Event class" + ) # Argument should be supplied with pytest.raises(IncorrectUsageError) as exc: @@ -149,11 +147,10 @@ class _(BaseAggregate): def sent(self) -> None: pass - assert exc.value.messages == { - "_entity": [ - "Apply method `sent` should accept an argument annotated with the Event class" - ] - } + assert ( + exc.value.args[0] + == "Apply method `sent` should accept an argument annotated with the Event class" + ) def test_event_to_be_applied_should_have_a_projection(test_domain): diff --git a/tests/event_sourced_aggregates/test_event_association_with_aggregate.py b/tests/event_sourced_aggregates/test_event_association_with_aggregate.py index 6883d09e..5fc9e7ec 100644 --- a/tests/event_sourced_aggregates/test_event_association_with_aggregate.py +++ b/tests/event_sourced_aggregates/test_event_association_with_aggregate.py @@ -96,12 +96,10 @@ def test_that_trying_to_associate_an_event_with_multiple_aggregates_throws_an_er with pytest.raises(IncorrectUsageError) as exc: test_domain.init(traverse=False) - assert exc.value.messages == { - "_event": [ - "Events are associated with multiple event sourced aggregates: " - "tests.event_sourced_aggregates.test_event_association_with_aggregate.UserRegistered" - ] - } + assert exc.value.args[0] == ( + "Events are associated with multiple event sourced aggregates: " + "tests.event_sourced_aggregates.test_event_association_with_aggregate.UserRegistered" + ) @pytest.mark.eventstore diff --git a/tests/event_sourced_repository/test_add.py b/tests/event_sourced_repository/test_add.py index 912b1456..74df8ac1 100644 --- a/tests/event_sourced_repository/test_add.py +++ b/tests/event_sourced_repository/test_add.py @@ -37,9 +37,7 @@ def test_exception_on_empty_aggregate_object(test_domain): with pytest.raises(IncorrectUsageError) as exception: test_domain.repository_for(User).add(None) - assert exception.value.messages == { - "_entity": ["Aggregate object to persist is invalid"] - } + assert exception.value.args[0] == "Aggregate object to persist is invalid" def test_successful_persistence_of_aggregate(test_domain): diff --git a/tests/event_sourced_repository/test_retrieving_event_sourced_repository.py b/tests/event_sourced_repository/test_retrieving_event_sourced_repository.py index ac0a361f..7523dc5d 100644 --- a/tests/event_sourced_repository/test_retrieving_event_sourced_repository.py +++ b/tests/event_sourced_repository/test_retrieving_event_sourced_repository.py @@ -32,11 +32,10 @@ class CustomUserRepository(BaseEventSourcedRepository): with pytest.raises(IncorrectUsageError) as exc: test_domain.register(CustomUserRepository) - assert exc.value.messages == { - "_entity": [ - "Repository `CustomUserRepository` should be associated with an Aggregate" - ] - } + assert ( + exc.value.args[0] + == "Repository `CustomUserRepository` should be associated with an Aggregate" + ) def test_that_an_event_sourced_repository_can_only_be_associated_with_an_event_sourced_aggregate( @@ -52,8 +51,6 @@ class CustomRepository(BaseEventSourcedRepository): test_domain.register(CustomAggregate) test_domain.register(CustomRepository, part_of=CustomAggregate) - assert exc.value.messages == { - "_entity": [ - "Repository `CustomRepository` can only be associated with an Event Sourced Aggregate" - ] - } + assert exc.value.args[0] == ( + "Repository `CustomRepository` can only be associated with an Event Sourced Aggregate" + ) diff --git a/tests/event_store/test_appending_commands.py b/tests/event_store/test_appending_commands.py index f44bda86..afccff93 100644 --- a/tests/event_store/test_appending_commands.py +++ b/tests/event_store/test_appending_commands.py @@ -28,11 +28,10 @@ def test_command_submission_without_aggregate(test_domain): with pytest.raises(IncorrectUsageError) as exc: test_domain.register(Register) - assert exc.value.messages == { - "_command": [ - "Command `Register` needs to be associated with an aggregate or a stream" - ] - } + assert ( + exc.value.args[0] + == "Command `Register` needs to be associated with an aggregate or a stream" + ) @pytest.mark.eventstore diff --git a/tests/field/test_list.py b/tests/field/test_list.py index 36ef06ae..e0cf29f7 100644 --- a/tests/field/test_list.py +++ b/tests/field/test_list.py @@ -108,12 +108,10 @@ class VO(BaseEntity): with pytest.raises(IncorrectUsageError) as exc: List(content_type=ValueObject(VO)) - assert exc.value.messages == { - "_value_object": [ - "`VO` is not a valid Value Object and cannot be embedded in " - "a Value Object field" - ] - } + assert exc.value.args[0] == ( + "`VO` is not a valid Value Object and cannot be embedded in " + "a Value Object field" + ) def test_list_field_with_value_object_string_is_resolved(self, test_domain): class VO(BaseValueObject): diff --git a/tests/field/test_vo.py b/tests/field/test_vo.py index 7f69a387..3bb3da39 100644 --- a/tests/field/test_vo.py +++ b/tests/field/test_vo.py @@ -29,8 +29,6 @@ class User(BaseAggregate): email = String() address = ValueObject(Address) - assert exc.value.messages == { - "_value_object": [ - "`Address` is not a valid Value Object and cannot be embedded in a Value Object field" - ] - } + assert exc.value.args[0] == ( + "`Address` is not a valid Value Object and cannot be embedded in a Value Object field" + ) diff --git a/tests/message/test_message_to_object.py b/tests/message/test_message_to_object.py index 152e988c..5aab8cc6 100644 --- a/tests/message/test_message_to_object.py +++ b/tests/message/test_message_to_object.py @@ -83,5 +83,5 @@ def test_invalid_message_throws_exception(): message.to_object() assert exc.value.messages == { - "_message": ["Message type is not supported for deserialization"] + "kind": ["Message type is not supported for deserialization"] } diff --git a/tests/reflection/test_declared_fields.py b/tests/reflection/test_declared_fields.py index 3f253059..6b20d10f 100644 --- a/tests/reflection/test_declared_fields.py +++ b/tests/reflection/test_declared_fields.py @@ -23,9 +23,7 @@ class Dummy: with pytest.raises(IncorrectUsageError) as exception: declared_fields(Dummy) - assert exception.value.messages == { - "field": [ - ".Dummy'> " - "does not have fields" - ] - } + assert exception.value.args[0] == ( + ".Dummy'> " + "does not have fields" + ) diff --git a/tests/reflection/test_fields.py b/tests/reflection/test_fields.py index ae95e347..48415c62 100644 --- a/tests/reflection/test_fields.py +++ b/tests/reflection/test_fields.py @@ -23,9 +23,7 @@ class Dummy: with pytest.raises(IncorrectUsageError) as exception: fields(Dummy) - assert exception.value.messages == { - "field": [ - ".Dummy'> " - "does not have fields" - ] - } + assert exception.value.args[0] == ( + ".Dummy'> " + "does not have fields" + ) diff --git a/tests/repository/test_repository_registration.py b/tests/repository/test_repository_registration.py index 055fa0f5..959d576d 100644 --- a/tests/repository/test_repository_registration.py +++ b/tests/repository/test_repository_registration.py @@ -147,8 +147,6 @@ class CustomUserRepository: def special_method(self): pass - assert exc.value.messages == { - "_entity": [ - "Repository `CustomUserRepository` should be associated with a valid Database" - ] - } + assert exc.value.args[0] == ( + "Repository `CustomUserRepository` should be associated with a valid Database" + ) diff --git a/tests/repository/tests.py b/tests/repository/tests.py index a238de4d..e6e8d0da 100644 --- a/tests/repository/tests.py +++ b/tests/repository/tests.py @@ -37,6 +37,4 @@ def test_that_incorrectusageerror_is_raised_when_retrieving_nonexistent_aggregat with pytest.raises(IncorrectUsageError) as exc: test_domain.repository_for("Invalid") - assert exc.value.messages == { - "element": ["Element Invalid is not registered in domain Test"] - } + assert exc.value.args[0] == ("Element Invalid is not registered in domain Test") diff --git a/tests/value_object/test_immutability.py b/tests/value_object/test_immutability.py index 20702dce..f93b4df5 100644 --- a/tests/value_object/test_immutability.py +++ b/tests/value_object/test_immutability.py @@ -25,12 +25,9 @@ def test_value_objects_are_immutable(): with pytest.raises(IncorrectUsageError) as exception: balance.currency = "INR" - assert str(exception.value) == str( - { - "_value_object": [ - "Value Objects are immutable and cannot be modified once created" - ] - } + assert ( + str(exception.value) + == "Value Objects are immutable and cannot be modified once created" ) diff --git a/tests/value_object/test_vo_field_properties.py b/tests/value_object/test_vo_field_properties.py index 9a07225c..fdcefb05 100644 --- a/tests/value_object/test_vo_field_properties.py +++ b/tests/value_object/test_vo_field_properties.py @@ -13,12 +13,9 @@ class Balance(BaseValueObject): currency = String(max_length=3, required=True, unique=True) amount = Float(required=True) - assert str(exception.value) == str( - { - "_value_object": [ - "Value Objects cannot contain fields marked 'unique' (field 'currency')" - ] - } + assert ( + str(exception.value) + == "Value Objects cannot contain fields marked 'unique' (field 'currency')" ) @@ -29,12 +26,9 @@ class Balance(BaseValueObject): currency = String(max_length=3, required=True, identifier=True) amount = Float(required=True) - assert str(exception.value) == str( - { - "_value_object": [ - "Value Objects cannot contain fields marked 'identifier' (field 'currency')" - ] - } + assert ( + str(exception.value) + == "Value Objects cannot contain fields marked 'identifier' (field 'currency')" ) @@ -47,10 +41,6 @@ class Address(BaseEntity): class Office(BaseValueObject): addresses = HasMany(Address) - assert str(exception.value) == str( - { - "_value_object": [ - "Value Objects cannot have associations. Remove addresses (HasMany) from class Office" - ] - } + assert str(exception.value) == ( + "Value Objects cannot have associations. Remove addresses (HasMany) from class Office" ) diff --git a/tests/views/test_view_validations_for_fields.py b/tests/views/test_view_validations_for_fields.py index bb949039..48e32589 100644 --- a/tests/views/test_view_validations_for_fields.py +++ b/tests/views/test_view_validations_for_fields.py @@ -28,8 +28,7 @@ class User(BaseView): test_domain.register(User) assert ( - exception.value.messages["_entity"][0] - == "View `User` needs to have at least one identifier" + exception.value.args[0] == "View `User` needs to have at least one identifier" ) @@ -41,7 +40,7 @@ class User(BaseView): email = ValueObject(Email) assert ( - exception.value.messages["_entity"][0] + exception.value.args[0] == "Views can only contain basic field types. Remove email (ValueObject) from class User" ) @@ -54,7 +53,7 @@ class User(BaseView): role = Reference(Role) assert ( - exception.value.messages["_entity"][0] + exception.value.args[0] == "Views can only contain basic field types. Remove role (Reference) from class User" ) @@ -67,6 +66,6 @@ class User(BaseView): role = HasOne(Role) assert ( - exception.value.messages["_entity"][0] + exception.value.args[0] == "Views can only contain basic field types. Remove role (HasOne) from class User" )