Skip to content

Commit 88bf3fc

Browse files
remimdremimd
andauthored
feat: ➖ Remove pydantic
Co-authored-by: remimd <[email protected]>
1 parent 1ada73e commit 88bf3fc

File tree

9 files changed

+213
-228
lines changed

9 files changed

+213
-228
lines changed

cq/__init__.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
from ._core.dispatcher.bus import Bus
22
from ._core.dispatcher.pipe import Pipe
3-
from ._core.dto import DTO
43
from ._core.message import (
54
AnyCommandBus,
65
Command,
76
CommandBus,
87
Event,
98
EventBus,
10-
Message,
119
Query,
1210
QueryBus,
1311
command_handler,
@@ -27,10 +25,8 @@
2725
"CQScope",
2826
"Command",
2927
"CommandBus",
30-
"DTO",
3128
"Event",
3229
"EventBus",
33-
"Message",
3430
"Middleware",
3531
"MiddlewareResult",
3632
"Pipe",

cq/_core/dto.py

Lines changed: 0 additions & 10 deletions
This file was deleted.

cq/_core/message.py

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
from abc import ABC
21
from typing import Any
32

43
import injection
54

65
from cq._core.dispatcher.bus import Bus, SimpleBus, TaskBus
7-
from cq._core.dto import DTO
86
from cq._core.handler import (
97
HandlerDecorator,
108
MultipleHandlerManager,
@@ -13,22 +11,9 @@
1311
from cq._core.scope import CQScope
1412
from cq.middlewares.scope import InjectionScopeMiddleware
1513

16-
17-
class Message(DTO, ABC):
18-
__slots__ = ()
19-
20-
21-
class Command(Message, ABC):
22-
__slots__ = ()
23-
24-
25-
class Event(Message, ABC):
26-
__slots__ = ()
27-
28-
29-
class Query(Message, ABC):
30-
__slots__ = ()
31-
14+
Command = object
15+
Event = object
16+
Query = object
3217

3318
type CommandBus[T] = Bus[Command, T]
3419
type EventBus = Bus[Event, None]

cq/_core/related_events.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ def add(self, *events: Event) -> None:
2020

2121

2222
@dataclass(repr=False, eq=False, frozen=True, slots=True)
23-
class _RelatedEvents(RelatedEvents):
23+
class SimpleRelatedEvents(RelatedEvents):
2424
items: list[Event] = field(default_factory=list)
2525

2626
def add(self, *events: Event) -> None:
@@ -29,7 +29,7 @@ def add(self, *events: Event) -> None:
2929

3030
@injection.scoped(CQScope.ON_COMMAND, mode="fallback")
3131
async def related_events_recipe(event_bus: EventBus) -> AsyncIterator[RelatedEvents]:
32-
yield (instance := _RelatedEvents())
32+
yield (instance := SimpleRelatedEvents())
3333
events = instance.items
3434

3535
if not events:

documentation/fastapi-example.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ The advantage of `python-cq` is that it can be easily integrated into FastAPI.
55
Here's an example of its integration:
66

77
```python
8-
from cq import Command, CommandBus, DTO, command_handler, new_command_bus
8+
import msgspec
9+
from cq import CommandBus, command_handler, new_command_bus
910
from fastapi import FastAPI, status
1011
from injection import injectable, singleton
1112
from injection.integrations.fastapi import Inject
@@ -23,16 +24,16 @@ def override_command_bus_recipe() -> CommandBus:
2324

2425
# ----- Command Definition -----
2526

26-
class ExampleCommand(Command): ...
27+
class ExampleCommand(msgspec.Struct, frozen=True): ...
2728

28-
class HandlerReturnType(DTO): ...
29+
class ExampleReturnType(msgspec.Struct, frozen=True): ...
2930

3031
@command_handler(ExampleCommand)
3132
class ExampleHandler:
3233
def __init__(self, service: ExampleService) -> None:
3334
self.service = service
3435

35-
async def handle(self, command: ExampleCommand) -> HandlerReturnType: ...
36+
async def handle(self, command: ExampleCommand) -> ExampleReturnType: ...
3637

3738
# ----- FastAPI Setup -----
3839

@@ -43,7 +44,8 @@ app = FastAPI()
4344
@app.post("/example", status_code=status.HTTP_204_NO_CONTENT)
4445
async def example(
4546
command: ExampleCommand,
46-
command_bus: CommandBus[HandlerReturnType] = Inject(CommandBus),
47+
command_bus: CommandBus[ExampleReturnType] = Inject(CommandBus),
4748
) -> None:
4849
result = await command_bus.dispatch(command)
50+
# ...
4951
```

documentation/writing-application-layer.md

Lines changed: 10 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,42 +2,29 @@
22

33
Set of tools to simplify application logic writing.
44

5-
* [Data Transfer Object (DTO)](#data-transfer-object-dto)
65
* [Reading](#reading)
76
* [Writing](#writing)
87
* [Side effects](#side-effects)
98
* [Bus Middleware](#bus-middleware)
109

11-
## Data Transfer Object (DTO)
12-
13-
The idea is to have one DTO to enter the application layer and another to exit when needed.
14-
A DTO is a subclass of [Pydantic BaseModel](https://docs.pydantic.dev/latest/), so it contains all these properties.
15-
16-
```python
17-
from cq import DTO
18-
19-
class MyAwesomeDTO(DTO):
20-
my_awesome_value: str
21-
```
22-
2310
## Reading
2411

2512
### Define a query
2613

2714
The purpose of a query is to read data.
28-
The `Query` class is a subclass of DTO.
2915

3016
The `query_handler` decorator associates a query type with a particular logic (handler).
3117
Only one handler can be associated with a query type.
3218
All handler dependencies are injected at runtime using [python-injection](https://github.com/100nm/python-injection).
3319

3420
```python
35-
from cq import DTO, Query, query_handler
21+
import msgspec
22+
from cq import query_handler
3623

37-
class UserProfileView(DTO):
24+
class UserProfileView:
3825
""" Data to retrieve """
3926

40-
class ReadUserProfileQuery(Query):
27+
class ReadUserProfileQuery(msgspec.Struct, frozen=True):
4128
user_id: int
4229

4330
@query_handler(ReadUserProfileQuery)
@@ -69,16 +56,15 @@ async def get_user_profile_1(query_bus: QueryBus[UserProfileView]) -> UserProfil
6956
### Define a command
7057

7158
The purpose of a command is to write data.
72-
The `Command` class is a subclass of DTO.
7359

7460
The `command_handler` decorator associates a command type with a particular logic (handler).
7561
Only one handler can be associated with a command type.
7662
All handler dependencies are injected at runtime using [python-injection](https://github.com/100nm/python-injection).
7763

7864
```python
79-
from cq import Command, command_handler
65+
from cq import command_handler
8066

81-
class UpdateUserProfileCommand(Command):
67+
class UpdateUserProfileCommand:
8268
""" Data required to update user profile """
8369

8470
@command_handler(UpdateUserProfileCommand)
@@ -110,16 +96,15 @@ async def update_user_profile(command_bus: CommandBus[None]) -> None:
11096

11197
The purpose of an event is to execute side effects.
11298
An event is generally propagated at the end of a command.
113-
The `Event` class is a subclass of DTO.
11499

115100
The `event_handler` decorator associates a event type with a particular logic (handler).
116101
Several handlers can be associated with an event type.
117102
All handler dependencies are injected at runtime using [python-injection](https://github.com/100nm/python-injection).
118103

119104
```python
120-
from cq import Event, event_handler
105+
from cq import event_handler
121106

122-
class UserRegistered(Event):
107+
class UserRegistered:
123108
""" Data to process the event """
124109

125110
@event_handler(UserRegistered)
@@ -133,9 +118,9 @@ class SendConfirmationEmailHandler:
133118
To propagate an event, it must be transmitted to `RelatedEvents` instance.
134119

135120
```python
136-
from cq import Command, RelatedEvents, command_handler
121+
from cq import RelatedEvents, command_handler
137122

138-
class UserRegistrationCommand(Command):
123+
class UserRegistrationCommand:
139124
""" Data required to register a user """
140125

141126
@command_handler(UserRegistrationCommand)

pyproject.toml

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ dev = [
1010
]
1111
example = [
1212
"fastapi",
13+
"msgspec",
1314
]
1415
test = [
1516
"pytest",
@@ -41,7 +42,6 @@ classifiers = [
4142
]
4243
dependencies = [
4344
"anyio",
44-
"pydantic (>=2, <3)",
4545
"python-injection",
4646
]
4747

@@ -71,15 +71,9 @@ disallow_subclassing_any = true
7171
disallow_untyped_defs = true
7272
follow_imports = "silent"
7373
no_implicit_reexport = true
74-
plugins = ["pydantic.mypy"]
7574
warn_redundant_casts = true
7675
warn_unused_ignores = true
7776

78-
[tool.pydantic-mypy]
79-
init_forbid_extra = true
80-
init_typed = true
81-
warn_required_dynamic_aliases = true
82-
8377
[tool.pytest.ini_options]
8478
python_files = "test_*.py"
8579
addopts = "--tb short --cov ./ --cov-report term-missing:skip-covered"

tests/test_command_bus.py

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,6 @@
11
from injection import find_instance
22

3-
from cq import (
4-
AnyCommandBus,
5-
Command,
6-
Event,
7-
RelatedEvents,
8-
command_handler,
9-
event_handler,
10-
)
3+
from cq import AnyCommandBus, RelatedEvents, command_handler, event_handler
114
from tests.helpers.history import HistoryMiddleware
125

136

@@ -16,13 +9,13 @@ async def test_dispatch_with_related_events(
169
self,
1710
history: HistoryMiddleware,
1811
) -> None:
19-
class _Event(Event): ...
12+
class _Event: ...
2013

2114
@event_handler(_Event)
2215
class _EventHandler:
2316
async def handle(self, event: _Event) -> None: ...
2417

25-
class _Command(Command): ...
18+
class _Command: ...
2619

2720
@command_handler(_Command)
2821
class _CommandHandler:

0 commit comments

Comments
 (0)