Skip to content

Commit 5394abb

Browse files
committed
clean up code
1 parent 5008c5c commit 5394abb

25 files changed

+118
-242
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from abc import ABC, abstractmethod
2+
from .http_client.http_client import HttpClient
3+
4+
5+
class AbstractBaseClient(ABC):
6+
@property
7+
@abstractmethod
8+
def http_client(self) -> HttpClient:
9+
raise NotImplementedError()

eventsourcingdb/client.py

Lines changed: 18 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22
from types import TracebackType
33
from typing import Optional, Type, TypeVar, AsyncIterator
44

5+
from eventsourcingdb.abstract_base_client import AbstractBaseClient
6+
57
from .client_configuration import ClientConfiguration
8+
from .event.event import Event
69
from .event.event_candidate import EventCandidate
710
from .event.event_context import EventContext
811
from .handlers.observe_events.observe_events import observe_events
@@ -14,13 +17,12 @@
1417
from .handlers.ping import ping
1518
from .handlers.read_events import read_events, ReadEventsOptions
1619
from .handlers.read_subjects import read_subjects
17-
from .handlers.store_item import StoreItem
1820
from .handlers.write_events import Precondition, write_events
1921

2022

2123
T = TypeVar('T')
2224

23-
class Client:
25+
class Client(AbstractBaseClient):
2426
def __init__(
2527
self,
2628
base_url: str,
@@ -29,7 +31,7 @@ def __init__(
2931
self.__http_client = HttpClient(base_url=base_url, api_token=api_token)
3032

3133
async def __aenter__(self):
32-
await self.__http_client.initialize()
34+
await self.__http_client.__aenter__()
3335
return self
3436

3537
async def __aexit__(
@@ -38,29 +40,28 @@ async def __aexit__(
3840
exc_val: Optional[BaseException],
3941
exc_tb: Optional[TracebackType]
4042
) -> None:
41-
await self.__http_client.close()
43+
await self.__http_client.__aexit__(exc_tb=exc_tb, exc_val=exc_val, exc_type=exc_type)
4244

43-
# Keeping these for backward compatibility and explicit resource management
44-
"""async def initialize(self) -> None:
45+
async def initialize(self) -> None:
4546
await self.__http_client.initialize()
4647

4748
async def close(self) -> None:
48-
await self.__http_client.close() # TODO: should we mix object orientation and functional programming?
49-
"""
50-
def http_client(self) -> # TODO: should we mix object orientation and functional programming?tpClient:
49+
await self.__http_client.close()
50+
51+
@property
52+
def http_client(self) -> HttpClient:
5153
return self.__http_client
5254

53-
# TODO: should we mix object orientation and functional programming?
5455
async def ping(self) -> None:
55-
return await ping(client=self)
56+
return await ping(self)
5657

5758
async def verify_api_token(self) -> None:
58-
...
59+
raise NotImplementedError("verify_api_token is not implemented yet.")
5960

6061
async def write_events(
6162
self,
6263
event_candidates: list[EventCandidate],
63-
preconditions: list[Precondition] = None
64+
preconditions: list[Precondition] = None # type: ignore
6465
) -> list[EventContext]: # TODO: list[Event] of Events (complete)
6566
if preconditions is None:
6667
preconditions = []
@@ -70,30 +71,7 @@ async def read_events(
7071
self,
7172
subject: str,
7273
options: ReadEventsOptions
73-
) -> AsyncGenerator[StoreItem, None]: # no StoreItem ... it is a Event
74-
#TODO: This is a code snippet for abort read events.
75-
"""
76-
https://github.com/thenativeweb/eventsourcingdb-client-javascript/blob/main/src/Client.ts#L134-L152
77-
for await (const event of client.readEvents('/', { recursive: true })) {
78-
console.log(event);
79-
80-
if (event.ID === '100') {
81-
break;
82-
}
83-
}
84-
85-
86-
function handlePostRequest(abortController) {
87-
const signal = abortController.signal;
88-
89-
for await (const event of client.readEvents('/', { recursive: true }), signal) {
90-
console.log(event);
91-
}
92-
93-
return http.status(200);
94-
}
95-
"""
96-
"""Read events with proper cancellation support."""
74+
) -> AsyncGenerator[Event, None]:
9775
generator = read_events(self, subject, options)
9876
try:
9977
async for item in generator:
@@ -105,20 +83,13 @@ async def run_eventql_query(self, query: str) -> AsyncGenerator[Event, None]:
10583
"""
10684
the issue like read_events. can be abort or canceled.
10785
"""
86+
raise NotImplementedError("run_eventql_query is not implemented yet.")
10887

10988
async def observe_events(
11089
self,
11190
subject: str,
11291
options: ObserveEventsOptions
113-
) -> AsyncGenerator[StoreItem, None]: # no StoreItem ... it is a Event
114-
"""
115-
TODO: the same issue like read_events. contextmanager
116-
"""
117-
async def observe_events(
118-
self,
119-
subject: str,
120-
options: ObserveEventsOptions
121-
) -> AsyncGenerator[StoreItem, None]:
92+
) -> AsyncGenerator[Event, None]:
12293
generator = observe_events(self, subject, options)
12394
try:
12495
async for item in generator:
@@ -149,32 +120,4 @@ async def read_event_types(self) -> AsyncGenerator[EventType, None]:
149120
async for item in generator:
150121
yield item
151122
finally:
152-
await generator.aclose()
153-
154-
155-
156-
""" TODO:
157-
158-
f (response.status !== 200) {
159-
throw new Error(
160-
`Failed to read event types, got HTTP status code '${response.status}', expected '200'.`,
161-
);
162-
}
163-
164-
"""
165-
166-
"""
167-
168-
A: Ausdüngen und Exception
169-
170-
B: Contextmanager
171-
172-
C: Neue Methoden
173-
174-
D: Testcontainer: testcontainers.com Python "virtuelle Container für tests"
175-
- EventSourcingDB(DockerContainer):
176-
def __init__(self):
177-
https://github.com/thenativeweb/eventsourcingdb-client-javascript/blob/main/src/EventSourcingDbContainer.ts
178-
"""
179-
180-
Dokumentationslink für Featurecheck: https://docs.eventsourcingdb.io/client-sdks/compliance-criteria/#detailed-requirements
123+
await generator.aclose()

eventsourcingdb/event/event.py

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,6 @@
66

77
Self = TypeVar("Self", bound="Event")
88

9-
# pylint: disable=R0917
10-
# Reason: This class is expected to have many parameters
11-
# due to its business context. Splitting it into smaller
12-
# methods would increase cognitive load and make the
13-
# code less readable.
14-
159

1610
class Event(EventContext):
1711
def __init__(
@@ -25,8 +19,8 @@ def __init__(
2519
time: datetime,
2620
data_content_type: str,
2721
predecessor_hash: str,
28-
trace_parent: str = None,
29-
trace_state: str = None
22+
trace_parent: str | None = None,
23+
trace_state: str | None = None
3024
):
3125
super().__init__(
3226
source,
@@ -43,7 +37,7 @@ def __init__(
4337
self.data = data
4438

4539
@staticmethod
46-
def parse(unknown_object: dict) -> Self:
40+
def parse(unknown_object: dict) -> "Event":
4741
event_context = super(Event, Event).parse(unknown_object)
4842

4943
data = unknown_object.get('data')
@@ -70,4 +64,4 @@ def to_json(self):
7064
json = super().to_json()
7165
json['data'] = self.data
7266

73-
return json
67+
return json

eventsourcingdb/event/event_context.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from dataclasses import dataclass
22
from datetime import datetime
3-
from typing import TypeVar
3+
from typing import Any, TypeVar
44

55
from ..errors.internal_error import InternalError
66
from ..errors.validation_error import ValidationError
@@ -20,11 +20,11 @@ class EventContext:
2020
time: datetime
2121
data_content_type: str
2222
predecessor_hash: str
23-
trace_parent: str = None
24-
trace_state: str = None
23+
trace_parent: str | None = None
24+
trace_state: str | None = None
2525

2626
@staticmethod
27-
def parse(unknown_object: dict) -> Self:
27+
def parse(unknown_object: dict) -> "EventContext":
2828
source = unknown_object.get('source')
2929
if not isinstance(source, str):
3030
raise ValidationError(
@@ -100,7 +100,7 @@ def parse(unknown_object: dict) -> Self:
100100
trace_state=trace_state,
101101
)
102102

103-
def to_json(self):
103+
def to_json(self) -> dict[Any, Any]:
104104
json = {
105105
'specversion': self.spec_version,
106106
'id': self.event_id,

eventsourcingdb/handlers/bound.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from dataclasses import dataclass
2+
from enum import Enum
3+
4+
5+
class BoundType(Enum):
6+
INCLUSIVE = "inclusive"
7+
EXCLUSIVE = "exclusive"
8+
9+
10+
@dataclass
11+
class Bound:
12+
id: str
13+
type: BoundType

eventsourcingdb/handlers/lower_bound.py

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

eventsourcingdb/handlers/observe_events/observe_events.py

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,34 +2,28 @@
22
from collections.abc import AsyncGenerator
33
from http import HTTPStatus
44

5+
from eventsourcingdb.abstract_base_client import AbstractBaseClient
6+
57
from ..is_heartbeat import is_heartbeat
68
from ..is_event import is_event
79
from ..is_stream_error import is_stream_error
810
from ..parse_raw_message import parse_raw_message
9-
from ...client import Client
1011
from ...errors.custom_error import CustomError
1112
from ...errors.internal_error import InternalError
1213
from ...errors.invalid_parameter_error import InvalidParameterError
1314
from ...errors.server_error import ServerError
1415
from ...errors.validation_error import ValidationError
1516
from ...event.event import Event
1617
from ...event.validate_subject import validate_subject
17-
from ..store_item import StoreItem
1818
from .observe_events_options import ObserveEventsOptions
1919
from ...http_client.response import Response
2020

21-
# pylint: disable=R6007
22-
# Reason: This method explicitly specifies the return type as None
23-
# for better readability. Even though it is not necessary,
24-
# it makes the return type clear without needing to read any
25-
# documentation or code.
26-
2721

2822
async def observe_events(
29-
client: Client,
23+
client: AbstractBaseClient,
3024
subject: str,
3125
options: ObserveEventsOptions
32-
) -> AsyncGenerator[StoreItem, None]:
26+
) -> AsyncGenerator[Event, None]:
3327
try:
3428
validate_subject(subject)
3529
except ValidationError as validation_error:
@@ -94,7 +88,7 @@ async def observe_events(
9488
):
9589
continue
9690

97-
yield StoreItem(event, message['payload']['hash'])
91+
yield event
9892
continue
9993

10094
raise ServerError(

eventsourcingdb/handlers/observe_events/observe_events_options.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from dataclasses import dataclass
22

3-
from ..lower_bound import LowerBound
3+
from ..bound import Bound
44
from ...errors.validation_error import ValidationError
55
from ...event.validate_subject import validate_subject
66
from ...event.validate_type import validate_type
@@ -10,13 +10,13 @@
1010
@dataclass
1111
class ObserveEventsOptions:
1212
recursive: bool
13-
lower_bound: LowerBound | None = None
13+
lower_bound: Bound | None = None
1414
from_latest_event: ObserveFromLatestEvent | None = None
1515

1616
def validate(self) -> None:
17-
if self.lower_bound is not None and not isinstance(self.lower_bound, LowerBound):
17+
if self.lower_bound is not None and not isinstance(self.lower_bound, Bound):
1818
raise ValidationError(
19-
'ObserveEventsOptions are invalid: lower_bound must be a LowerBound object.'
19+
'ObserveEventsOptions are invalid: lower_bound must be a Bound object.'
2020
)
2121

2222
if self.from_latest_event is not None:
@@ -43,18 +43,18 @@ def validate(self) -> None:
4343
) from validation_error
4444

4545
def to_json(self):
46-
json = {
46+
result = {
4747
'recursive': self.recursive
4848
}
4949

5050
# Directly use the object
5151
if self.lower_bound is not None:
52-
json['lowerBound'] = {
52+
result['lowerBound'] = {
5353
'id': str(self.lower_bound.id), # Ensure ID is a string
5454
'type': self.lower_bound.type
5555
}
5656

5757
if self.from_latest_event is not None:
58-
json['fromLatestEvent'] = self.from_latest_event.to_json()
58+
result['fromLatestEvent'] = self.from_latest_event.to_json()
5959

60-
return json
60+
return result

eventsourcingdb/handlers/ping.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from http import HTTPStatus
22
import json
3-
from ..client import Client
3+
4+
from ..abstract_base_client import AbstractBaseClient
45
from ..errors.server_error import ServerError
56

67
# Define constants for response values
@@ -13,7 +14,7 @@
1314
PING_RECEIVED_TYPE = "io.eventsourcingdb.api.ping-received"
1415

1516

16-
async def ping(client: Client) -> None:
17+
async def ping(client: AbstractBaseClient) -> None:
1718
response = await client.http_client.get("/api/v1/ping")
1819
response_body = bytes.decode(await response.body.read(), encoding="utf-8")
1920

0 commit comments

Comments
 (0)