Skip to content

Commit d297d88

Browse files
hohMHHukiewitz
andauthored
Change: Message.time was float, becomes datetime (#40)
* Change: Message.time was float, becomes datetime Change the type if BaseMessage.time to a datetime. This allows easier manipulation of the field, and parsing from strings as well as floats. New APIs introduced in PyAleph 0.5.0 store the message time as timestampz and return it as ISO strings. This changes is compatible with both the old and new APIs. * Add time validator for auto-conversion from float to datetime * Fix missing parameter * Fix Dockerfile dependency installation * Fix typing issues with mypy by using a generic type for AlephMessage * Rename to convert_float_to_datetime Co-authored-by: Hugo Herter <[email protected]> --------- Co-authored-by: mhh <[email protected]> Co-authored-by: Mike Hukiewitz <[email protected]>
1 parent dd8037c commit d297d88

File tree

3 files changed

+27
-36
lines changed

3 files changed

+27
-36
lines changed

aleph_message/models/__init__.py

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import datetime
12
import json
23
from copy import copy
34
from enum import Enum
@@ -11,7 +12,7 @@
1112
Literal,
1213
Optional,
1314
Type,
14-
Union,
15+
Union, TypeVar, cast,
1516
)
1617

1718
from pydantic import BaseModel, Extra, Field, validator
@@ -203,7 +204,7 @@ class BaseMessage(BaseModel):
203204
size: Optional[int] = Field(
204205
default=None, description="Size of the content"
205206
) # Almost always present
206-
time: float = Field(description="Unix timestamp when the message was published")
207+
time: datetime.datetime = Field(description="Unix timestamp or datetime when the message was published")
207208
item_type: ItemType = Field(description="Storage method used for the content")
208209
item_content: Optional[str] = Field(
209210
default=None,
@@ -265,6 +266,13 @@ def check_confirmed(cls, v, values):
265266
raise ValueError("Message cannot be 'confirmed' without 'confirmations'")
266267
return v
267268

269+
@validator("time")
270+
def convert_float_to_datetime(cls, v, values):
271+
if isinstance(v, float):
272+
v = datetime.datetime.fromtimestamp(v)
273+
assert isinstance(v, datetime.datetime)
274+
return v
275+
268276
class Config:
269277
extra = Extra.forbid
270278
exclude = {"id_", "_id"}
@@ -334,14 +342,10 @@ class InstanceMessage(BaseMessage):
334342
ForgetMessage,
335343
]
336344

337-
AlephMessageType: TypeAlias = Union[
338-
Type[PostMessage],
339-
Type[AggregateMessage],
340-
Type[StoreMessage],
341-
Type[ProgramMessage],
342-
Type[InstanceMessage],
343-
Type[ForgetMessage],
344-
]
345+
346+
T = TypeVar('T', bound=AlephMessage)
347+
348+
AlephMessageType: TypeAlias = Type[T]
345349

346350
message_classes: List[AlephMessageType] = [
347351
PostMessage,
@@ -383,16 +387,16 @@ def add_item_content_and_hash(message_dict: Dict, inplace: bool = False):
383387

384388
def create_new_message(
385389
message_dict: Dict,
386-
factory: Optional[AlephMessageType] = None,
387-
) -> AlephMessage:
390+
factory: Optional[Type[T]] = None,
391+
) -> T:
388392
"""Create a new message from a dict.
389393
Computes the 'item_content' and 'item_hash' fields.
390394
"""
391395
message_content = add_item_content_and_hash(message_dict)
392396
if factory:
393-
return factory.parse_obj(message_content)
397+
return cast(T, factory.parse_obj(message_content))
394398
else:
395-
return parse_message(message_content)
399+
return cast(T, parse_message(message_content))
396400

397401

398402
def create_message_from_json(

aleph_message/tests/test_models.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
create_message_from_file,
2626
create_message_from_json,
2727
create_new_message,
28-
parse_message,
28+
parse_message, AlephMessage,
2929
)
3030
from aleph_message.tests.download_messages import MESSAGES_STORAGE_PATH
3131

@@ -87,7 +87,7 @@ def test_messages_last_page():
8787
if message_dict["item_hash"] in HASHES_TO_IGNORE:
8888
continue
8989

90-
message = parse_message(message_dict)
90+
message: AlephMessage = parse_message(message_dict)
9191
assert message
9292

9393

@@ -285,9 +285,14 @@ def test_create_new_message():
285285
"signature": "0x123456789", # Signature validation requires using aleph-client
286286
}
287287

288-
new_message_1 = create_new_message(message_dict, factory=PostMessage)
288+
new_message_1: PostMessage = create_new_message(message_dict, factory=PostMessage)
289289
assert new_message_1
290290
assert new_message_1.type == MessageType.post
291+
# Check that the time was converted to a datetime
292+
assert new_message_1.time.isoformat() == '2021-07-07T10:04:47.017000+00:00'
293+
294+
# The time field can be either a float or a datetime as string
295+
message_dict["time"] = '2021-07-07T10:04:47.017000+00:00'
291296
new_message_2 = create_message_from_json(
292297
json.dumps(message_dict), factory=PostMessage
293298
)
@@ -303,7 +308,7 @@ def test_messages_from_disk():
303308
data_dict = json.load(page_fd)
304309
for message_dict in data_dict["messages"]:
305310
try:
306-
message = parse_message(message_dict)
311+
message: AlephMessage = parse_message(message_dict)
307312
assert message
308313
except ValidationError as e:
309314
console.print("-" * 79)

requirements.txt

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

0 commit comments

Comments
 (0)