Skip to content

Commit

Permalink
Update SDK to version 0.5.9
Browse files Browse the repository at this point in the history
  • Loading branch information
Roboto-Bot-O committed Jul 29, 2024
1 parent a78476a commit f82af35
Show file tree
Hide file tree
Showing 8 changed files with 373 additions and 1 deletion.
9 changes: 9 additions & 0 deletions src/roboto/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
ActionRuntime,
FilesChangesetFileManager,
)
from .association import (
Association,
AssociationType,
)
from .config import RobotoConfig
from .domain.actions import (
Accessibility,
Expand Down Expand Up @@ -87,6 +91,7 @@
Device,
DeviceRecord,
)
from .domain.events import Event, EventRecord
from .domain.files import (
CredentialProvider,
DeleteFileRequest,
Expand Down Expand Up @@ -137,6 +142,8 @@
"ActionRuntime",
"AddMessagePathRepresentationRequest",
"AddMessagePathRequest",
"Association",
"AssociationType",
"BeginManifestTransactionRequest",
"BeginSingleFileUploadRequest",
"CanonicalDataType",
Expand Down Expand Up @@ -176,6 +183,8 @@
"EvaluateTriggersRequest",
"ExecutableProvenance",
"ExecutorContainer",
"Event",
"EventRecord",
"File",
"FilesChangesetFileManager",
"FileRecord",
Expand Down
29 changes: 29 additions & 0 deletions src/roboto/association.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.

import collections.abc
import enum
import typing
import urllib.parse
Expand All @@ -20,13 +21,29 @@ class AssociationType(enum.Enum):

Dataset = "dataset"
File = "file"
Topic = "topic"


class Association(pydantic.BaseModel):
"""Use to declare an association between two Roboto entities."""

URL_ENCODING_SEP: typing.ClassVar[str] = ":"

@staticmethod
def group_by_type(
associations: collections.abc.Collection["Association"],
) -> collections.abc.Mapping[
AssociationType, collections.abc.Sequence["Association"]
]:
response: dict[AssociationType, list[Association]] = {}

for association in associations:
if association.association_type not in response:
response[association.association_type] = []
response[association.association_type].append(association)

return response

@classmethod
def from_url_encoded_value(cls, encoded: str) -> "Association":
"""Reverse of Association::url_encode."""
Expand All @@ -42,6 +59,18 @@ def from_url_encoded_value(cls, encoded: str) -> "Association":
f"Invalid association type '{association_type}'"
) from None

@classmethod
def dataset(cls, dataset_id: str):
return cls(association_id=dataset_id, association_type=AssociationType.Dataset)

@classmethod
def file(cls, file_id: str):
return cls(association_id=file_id, association_type=AssociationType.File)

@classmethod
def topic(cls, topic_id: typing.Union[str, int]):
return cls(association_id=str(topic_id), association_type=AssociationType.Topic)

association_id: str
"""Roboto identifier"""

Expand Down
19 changes: 19 additions & 0 deletions src/roboto/domain/events/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Copyright (c) 2024 Roboto Technologies, Inc.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.

from .event import Event
from .operations import (
CreateEventRequest,
QueryEventsForAssociationsRequest,
)
from .record import EventRecord

__all__ = [
"Event",
"CreateEventRequest",
"EventRecord",
"QueryEventsForAssociationsRequest",
]
127 changes: 127 additions & 0 deletions src/roboto/domain/events/event.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
# Copyright (c) 2024 Roboto Technologies, Inc.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.

import collections.abc
import datetime
import typing

from ...association import Association
from ...http import RobotoClient
from ...time import to_epoch_nanoseconds
from .operations import (
CreateEventRequest,
QueryEventsForAssociationsRequest,
)
from .record import EventRecord


class Event:
"""
An event is a "time anchor" which allows you to relate first class Roboto entities (datasets, files, and topics),
as well as a timespan in which they occurred.
"""

__roboto_client: RobotoClient
__record: EventRecord

@classmethod
def create(
cls,
associations: collections.abc.Sequence[Association],
start_time: typing.Union[int, datetime.datetime],
end_time: typing.Optional[typing.Union[int, datetime.datetime]] = None,
description: typing.Optional[str] = None,
metadata: typing.Optional[dict[str, typing.Any]] = None,
tags: typing.Optional[list[str]] = None,
caller_org_id: typing.Optional[str] = None,
roboto_client: typing.Optional[RobotoClient] = None,
) -> "Event":
roboto_client = RobotoClient.defaulted(roboto_client)
request = CreateEventRequest(
associations=list(associations),
start_time=to_epoch_nanoseconds(start_time),
end_time=to_epoch_nanoseconds(end_time or start_time),
description=description,
metadata=metadata or {},
tags=tags or [],
)
record = roboto_client.post(
"v1/events/create", caller_org_id=caller_org_id, data=request
).to_record(EventRecord)
return cls(record=record, roboto_client=roboto_client)

@classmethod
def for_association(
cls,
association: Association,
roboto_client: typing.Optional[RobotoClient] = None,
) -> collections.abc.Generator["Event", None, None]:
"""
Returns all events associated with the provided association. Any events which you don't have access to will be
filtered out of the response rather than throwing an exception.
"""
return Event.for_associations([association], roboto_client=roboto_client)

@classmethod
def for_associations(
cls,
associations: collections.abc.Collection[Association],
roboto_client: typing.Optional[RobotoClient] = None,
) -> collections.abc.Generator["Event", None, None]:
"""
Returns all events associated with the provided association. Any events which you don't have access to will be
filtered out of the response rather than throwing an exception.
"""
roboto_client = RobotoClient.defaulted(roboto_client)

next_token: typing.Optional[str] = None
while True:
request = QueryEventsForAssociationsRequest(
associations=list(associations), page_token=next_token
)

results = roboto_client.post(
"v1/events/query/for_associations",
data=request,
).to_paginated_list(EventRecord)

for item in results.items:
yield cls(record=item, roboto_client=roboto_client)

next_token = results.next_token
if not next_token:
break

@classmethod
def from_id(
cls, event_id: str, roboto_client: typing.Optional[RobotoClient] = None
):
roboto_client = RobotoClient.defaulted(roboto_client)
record = roboto_client.get(f"v1/events/id/{event_id}").to_record(EventRecord)
return cls(record, roboto_client)

def __init__(
self, record: EventRecord, roboto_client: typing.Optional[RobotoClient] = None
) -> None:
self.__roboto_client = RobotoClient.defaulted(roboto_client)
self.__record = record

def __repr__(self) -> str:
return self.__record.model_dump_json()

@property
def event_id(self) -> str:
return self.__record.event_id

@property
def record(self) -> EventRecord:
return self.__record

def delete(self) -> None:
self.__roboto_client.delete(f"v1/events/id/{self.event_id}")

def to_dict(self) -> dict[str, typing.Any]:
return self.__record.model_dump(mode="json")
63 changes: 63 additions & 0 deletions src/roboto/domain/events/operations.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Copyright (c) 2024 Roboto Technologies, Inc.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.

import typing

import pydantic

from ...association import Association


class CreateEventRequest(pydantic.BaseModel):
"""
Request payload for the Create Event operation.
"""

associations: list[Association] = pydantic.Field(default_factory=list)
"""
Datasets, files, and topics which this event pertains to. At least one must be provided. All referenced
datasets, files, and topics must be owned by the same organization.
"""

description: typing.Optional[str] = None
"""
An optional human-readable description of the event.
"""

end_time: int
"""
The end time of the event, in nanoseconds since epoch (assumed Unix epoch). This can be equal to start_time if
the event is discrete, but can never be less than start_time.
"""

metadata: dict[str, typing.Any] = pydantic.Field(
default_factory=dict,
)
"""
Initial key-value pairs to associate with this event for discovery and search.
"""

start_time: int
"""
The start time of the event, in nanoseconds since epoch (assumed Unix epoch).
"""

tags: list[str] = pydantic.Field(default_factory=list)
"""
Initial tags to associate with this event for discovery and search.
"""


class QueryEventsForAssociationsRequest(pydantic.BaseModel):
"""
Request payload for the Query Events for Associations operation.
"""

associations: list[Association]
"""Associations to query events for."""

page_token: typing.Optional[str] = None
"""Token to use to fetch the next page of results, use None for the first page."""
79 changes: 79 additions & 0 deletions src/roboto/domain/events/record.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# Copyright (c) 2024 Roboto Technologies, Inc.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.

import datetime
import typing

import pydantic

from ...association import Association


class EventRecord(pydantic.BaseModel):
"""
A wire-transmissible representation of an event.
"""

associations: list[Association] = pydantic.Field(default_factory=list)
"""
Datasets, files, and topics which this event pertains to.
"""

created: datetime.datetime
"""
Date/time when this event was created.
"""

created_by: str = pydantic.Field(description="The user who registered this device.")
"""
The user who created this event.
"""

description: typing.Optional[str] = None
"""
An optional human-readable description of the event.
"""

end_time: int
"""
The end time of the event, in nanoseconds since epoch (assumed Unix epoch). This can be equal to start_time if
the event is discrete, but can never be less than start_time.
"""

event_id: str
"""
A globally unique ID used to reference an event.
"""

metadata: dict[str, typing.Any] = pydantic.Field(default_factory=dict)
"""
Key-value pairs to associate with this event for discovery and search.
"""

modified: datetime.datetime
"""
Date/time when this device record was last modified.
"""

modified_by: str
"""
The user who last modified this device record.
"""

org_id: str = pydantic.Field(description="The org to which this device belongs.")
"""
The org to which this device belongs.
"""

start_time: int
"""
The start time of the event, in nanoseconds since epoch (assumed Unix epoch).
"""

tags: list[str] = pydantic.Field(default_factory=list)
"""
Tags to associate with this event for discovery and search.
"""
Loading

0 comments on commit f82af35

Please sign in to comment.