Skip to content

Commit

Permalink
Change: Message.time was float, becomes datetime (#40)
Browse files Browse the repository at this point in the history
* 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]>
  • Loading branch information
3 people authored Nov 25, 2023
1 parent dd8037c commit d297d88
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 36 deletions.
32 changes: 18 additions & 14 deletions aleph_message/models/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import datetime
import json
from copy import copy
from enum import Enum
Expand All @@ -11,7 +12,7 @@
Literal,
Optional,
Type,
Union,
Union, TypeVar, cast,
)

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

@validator("time")
def convert_float_to_datetime(cls, v, values):
if isinstance(v, float):
v = datetime.datetime.fromtimestamp(v)
assert isinstance(v, datetime.datetime)
return v

class Config:
extra = Extra.forbid
exclude = {"id_", "_id"}
Expand Down Expand Up @@ -334,14 +342,10 @@ class InstanceMessage(BaseMessage):
ForgetMessage,
]

AlephMessageType: TypeAlias = Union[
Type[PostMessage],
Type[AggregateMessage],
Type[StoreMessage],
Type[ProgramMessage],
Type[InstanceMessage],
Type[ForgetMessage],
]

T = TypeVar('T', bound=AlephMessage)

AlephMessageType: TypeAlias = Type[T]

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

def create_new_message(
message_dict: Dict,
factory: Optional[AlephMessageType] = None,
) -> AlephMessage:
factory: Optional[Type[T]] = None,
) -> T:
"""Create a new message from a dict.
Computes the 'item_content' and 'item_hash' fields.
"""
message_content = add_item_content_and_hash(message_dict)
if factory:
return factory.parse_obj(message_content)
return cast(T, factory.parse_obj(message_content))
else:
return parse_message(message_content)
return cast(T, parse_message(message_content))


def create_message_from_json(
Expand Down
13 changes: 9 additions & 4 deletions aleph_message/tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
create_message_from_file,
create_message_from_json,
create_new_message,
parse_message,
parse_message, AlephMessage,
)
from aleph_message.tests.download_messages import MESSAGES_STORAGE_PATH

Expand Down Expand Up @@ -87,7 +87,7 @@ def test_messages_last_page():
if message_dict["item_hash"] in HASHES_TO_IGNORE:
continue

message = parse_message(message_dict)
message: AlephMessage = parse_message(message_dict)
assert message


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

new_message_1 = create_new_message(message_dict, factory=PostMessage)
new_message_1: PostMessage = create_new_message(message_dict, factory=PostMessage)
assert new_message_1
assert new_message_1.type == MessageType.post
# Check that the time was converted to a datetime
assert new_message_1.time.isoformat() == '2021-07-07T10:04:47.017000+00:00'

# The time field can be either a float or a datetime as string
message_dict["time"] = '2021-07-07T10:04:47.017000+00:00'
new_message_2 = create_message_from_json(
json.dumps(message_dict), factory=PostMessage
)
Expand All @@ -303,7 +308,7 @@ def test_messages_from_disk():
data_dict = json.load(page_fd)
for message_dict in data_dict["messages"]:
try:
message = parse_message(message_dict)
message: AlephMessage = parse_message(message_dict)
assert message
except ValidationError as e:
console.print("-" * 79)
Expand Down
18 changes: 0 additions & 18 deletions requirements.txt

This file was deleted.

0 comments on commit d297d88

Please sign in to comment.