Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions rossum_api/clients/external_async_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
from rossum_api.models.queue import Queue
from rossum_api.models.relation import Relation
from rossum_api.models.rule import Rule
from rossum_api.models.rules_execution_logs import RulesExecutionLog
from rossum_api.models.schema import Schema
from rossum_api.models.task import Task
from rossum_api.models.upload import Upload
Expand All @@ -74,6 +75,7 @@
OrganizationType,
QueueType,
RelationType,
RulesExecutionLogType,
RuleType,
SchemaType,
TaskType,
Expand Down Expand Up @@ -101,6 +103,7 @@
QueueOrdering,
RelationOrdering,
RuleOrdering,
RulesExecutionLogOrdering,
SchemaOrdering,
UserOrdering,
UserRoleOrdering,
Expand Down Expand Up @@ -130,6 +133,7 @@ class AsyncRossumAPIClient(
QueueType,
RelationType,
RuleType,
RulesExecutionLogType,
SchemaType,
TaskType,
UploadType,
Expand Down Expand Up @@ -2139,6 +2143,50 @@ async def delete_rule(self, rule_id: int) -> None:
"""
return await self._http_client.delete(Resource.Rule, rule_id)

# ##### RULES EXECUTION LOGS #####
async def list_rules_execution_logs(
self, ordering: Sequence[RulesExecutionLogOrdering] = (), **filters: Any
) -> AsyncIterator[RulesExecutionLogType]:
"""Retrieve all :class:`~rossum_api.models.rules_execution_logs.RulesExecutionLog` objects.

The iterator transparently fetches subsequent pages until exhausted.

Parameters
----------
ordering
List of object names. Their URLs are used for sorting the results.
filters
rule: ID of a :class:`~rossum_api.models.rule.Rule` (or multiple IDs,
comma-separated).

queue: ID of a :class:`~rossum_api.models.queue.Queue`.

annotation: ID of a :class:`~rossum_api.models.annotation.Annotation`.

created_at_before: ISO 8601 timestamp, filter logs created before this time.

created_at_after: ISO 8601 timestamp, filter logs created after this time.

execution_result: ``success`` | ``failure`` | ``partial_success``
(or multiple values, comma-separated).

trigger_event: Trigger event (or multiple events, comma-separated).

request_id: Filter by exact request ID.

search: Full text search across log entry fields.

page_size: Number of results per page (1-100, default 100).

References
----------
https://rossum.app/api/docs/openapi/api/rules-execution-log/
"""
async for d in self._http_client.fetch_all(
Resource.RulesExecutionLog, ordering, **filters
):
yield self._deserializer(Resource.RulesExecutionLog, d)

# ##### USER ROLES #####
async def list_user_roles(
self, ordering: Sequence[UserRoleOrdering] = (), **filters: Any
Expand Down Expand Up @@ -2239,6 +2287,7 @@ async def fetch_sideload(sideload: Sideload) -> dict[str, Any] | None:
Queue,
Relation,
Rule,
RulesExecutionLog,
Schema,
Task,
Upload,
Expand Down
50 changes: 50 additions & 0 deletions rossum_api/clients/external_sync_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
from rossum_api.models.queue import Queue
from rossum_api.models.relation import Relation
from rossum_api.models.rule import Rule
from rossum_api.models.rules_execution_logs import RulesExecutionLog
from rossum_api.models.schema import Schema
from rossum_api.models.task import Task
from rossum_api.models.upload import Upload
Expand All @@ -73,6 +74,7 @@
OrganizationType,
QueueType,
RelationType,
RulesExecutionLogType,
RuleType,
SchemaType,
TaskType,
Expand Down Expand Up @@ -100,6 +102,7 @@
QueueOrdering,
RelationOrdering,
RuleOrdering,
RulesExecutionLogOrdering,
SchemaOrdering,
UserOrdering,
UserRoleOrdering,
Expand Down Expand Up @@ -130,6 +133,7 @@ class SyncRossumAPIClient(
QueueType,
RelationType,
RuleType,
RulesExecutionLogType,
SchemaType,
TaskType,
UploadType,
Expand Down Expand Up @@ -2074,6 +2078,51 @@ def delete_rule(self, rule_id: int) -> None:
"""
return self.internal_client.delete(Resource.Rule, rule_id)

# ##### RULES EXECUTION LOGS #####

def list_rules_execution_logs(
self, ordering: Sequence[RulesExecutionLogOrdering] = (), **filters: Any
) -> Iterator[RulesExecutionLogType]:
"""Retrieve all :class:`~rossum_api.models.rules_execution_logs.RulesExecutionLog` objects.

The iterator transparently fetches subsequent pages until exhausted.

Parameters
----------
ordering
List of object names. Their URLs are used for sorting the results.
filters
rule: ID of a :class:`~rossum_api.models.rule.Rule` (or multiple IDs,
comma-separated).

queue: ID of a :class:`~rossum_api.models.queue.Queue`.

annotation: ID of a :class:`~rossum_api.models.annotation.Annotation`.

created_at_before: ISO 8601 timestamp, filter logs created before this time.

created_at_after: ISO 8601 timestamp, filter logs created after this time.

execution_result: ``success`` | ``failure`` | ``partial_success``
(or multiple values, comma-separated).

trigger_event: Trigger event (or multiple events, comma-separated).

request_id: Filter by exact request ID.

search: Full text search across log entry fields.

page_size: Number of results per page (1-100, default 100).

References
----------
https://rossum.app/api/docs/openapi/api/rules-execution-log/
"""
for d in self.internal_client.fetch_resources(
Resource.RulesExecutionLog, ordering, **filters
):
yield self._deserializer(Resource.RulesExecutionLog, d)

# ##### USER ROLES #####

def list_user_roles(
Expand Down Expand Up @@ -2139,6 +2188,7 @@ def authenticate(self) -> None: # noqa: D102
Queue,
Relation,
Rule,
RulesExecutionLog,
Schema,
Task,
Upload,
Expand Down
4 changes: 4 additions & 0 deletions rossum_api/clients/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@

RuleOrdering: TypeAlias = Literal["id", "name", "organization"]

RulesExecutionLogOrdering: TypeAlias = Literal[
"rule_id", "queue_id", "annotation_id", "created_at", "execution_result"
]

SchemaOrdering: TypeAlias = Literal["id"]

UserOrdering: TypeAlias = Literal[
Expand Down
1 change: 1 addition & 0 deletions rossum_api/domain_logic/resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class Resource(Enum):
Queue = "queues"
Relation = "relations"
Rule = "rules"
RulesExecutionLog = "rules_execution_logs"
Schema = "schemas"
Task = "tasks"
Upload = "uploads"
Expand Down
2 changes: 2 additions & 0 deletions rossum_api/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
from rossum_api.models.queue import Queue
from rossum_api.models.relation import Relation
from rossum_api.models.rule import Rule
from rossum_api.models.rules_execution_logs import RulesExecutionLog
from rossum_api.models.schema import Schema
from rossum_api.models.task import Task
from rossum_api.models.upload import Upload
Expand Down Expand Up @@ -60,6 +61,7 @@
Resource.Queue: Queue,
Resource.Relation: Relation,
Resource.Rule: Rule,
Resource.RulesExecutionLog: RulesExecutionLog,
Resource.Schema: Schema,
Resource.Task: Task,
Resource.Upload: Upload,
Expand Down
70 changes: 70 additions & 0 deletions rossum_api/models/rules_execution_logs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
from __future__ import annotations

from dataclasses import dataclass
from typing import Any, Literal

ExecutionResult = Literal["success", "failure", "partial_success"]


@dataclass
class RulesExecutionLog:
"""One firing of a :class:`~rossum_api.models.rule.Rule` on a single annotation.

Each record captures the trigger condition expression evaluated at firing
time, the field values it saw (``trigger_condition_values``), whether the
condition matched (``trigger_condition_results``), and the actions that were
executed. For line-item rules, the result/values/actions arrays are aligned
by index — one element per line-item row.

Attributes
----------
rule_id
ID of the :class:`~rossum_api.models.rule.Rule` that was executed.
rule_name
Name of the rule at the time of execution.
queue_id
ID of the :class:`~rossum_api.models.queue.Queue` where the rule was triggered.
annotation_id
ID of the :class:`~rossum_api.models.annotation.Annotation` that triggered the rule.
request_id
Unique identifier for this rule execution request.
created_at
Timestamp when the rule was executed.
trigger_event
Event that triggered the rule evaluation (e.g. ``annotation_imported``).
trigger_condition
The trigger condition expression that was evaluated.
execution_result
Overall result: ``success``, ``failure``, or ``partial_success``
(the latter applies to line-item rules where some rows succeeded and others failed).
trigger_condition_results
Boolean per evaluation: a single-element array for regular rules,
one element per row for line-item rules.
trigger_condition_values
Field values passed to the condition. Keys are schema IDs referenced
in the trigger condition. Aligned by index with ``trigger_condition_results``.
execution_error
Error message if the rule execution failed.
actions
Actions executed per condition result. ``None`` if all conditions
evaluated to ``False``. Aligned by index with ``trigger_condition_results``;
elements are ``None`` for rows where the condition was ``False``.

References
----------
https://rossum.app/api/docs/openapi/api/rules-execution-log/
"""

rule_id: int
rule_name: str
queue_id: int
annotation_id: int
request_id: str
created_at: str
trigger_event: str
trigger_condition: str
execution_result: ExecutionResult
trigger_condition_results: list[bool] | None = None
trigger_condition_values: list[dict[str, Any]] | None = None
execution_error: str | None = None
actions: list[list[dict[str, Any]] | None] | None = None
1 change: 1 addition & 0 deletions rossum_api/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
QueueType = typing.TypeVar("QueueType")
RelationType = typing.TypeVar("RelationType")
RuleType = typing.TypeVar("RuleType")
RulesExecutionLogType = typing.TypeVar("RulesExecutionLogType")
SchemaType = typing.TypeVar("SchemaType")
TaskType = typing.TypeVar("TaskType", bound=ObjectWithStatus)
UploadType = typing.TypeVar("UploadType")
Expand Down
10 changes: 2 additions & 8 deletions tests/elis_api_client/test_relations.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,7 @@ async def test_list_relations_with_filters(
http_client.fetch_all.return_value = mock_generator(dummy_relation)

relations = client.list_relations(
type=RelationType.EDIT.value,
parent=123,
key=None,
annotation=456,
type=RelationType.EDIT.value, parent=123, key=None, annotation=456
)

async for r in relations:
Expand Down Expand Up @@ -104,10 +101,7 @@ def test_list_relations_with_filters(
http_client.fetch_resources.return_value = iter((dummy_relation,))

relations = client.list_relations(
type=RelationType.EDIT.value,
parent=123,
key=None,
annotation=456,
type=RelationType.EDIT.value, parent=123, key=None, annotation=456
)

for r in relations:
Expand Down
Loading
Loading