Skip to content

Commit 12f5109

Browse files
Feat: 5530 feature updated at inserted at properties on retrieved records (#5540)
# Description <!-- Please include a summary of the changes and the related issue. Please also include relevant motivation and context. List any dependencies that are required for this change. --> Closes #5530 **Type of change** <!-- Please delete options that are not relevant. Remember to title the PR according to the type of change --> - Improvement (change adding some improvement to an existing functionality) **How Has This Been Tested** <!-- Please add some reference about how your feature has been tested. --> **Checklist** <!-- Please go over the list and make sure you've taken everything into account --> - I added relevant documentation - I followed the style guidelines of this project - I did a self-review of my code - I made corresponding changes to the documentation - I confirm My changes generate no new warnings - I have added tests that prove my fix is effective or that my feature works - I have added relevant notes to the CHANGELOG.md file (See https://keepachangelog.com/) --------- Co-authored-by: Francisco Aranda <[email protected]> Co-authored-by: Paco Aranda <[email protected]>
1 parent ebaff3e commit 12f5109

File tree

8 files changed

+83
-10
lines changed

8 files changed

+83
-10
lines changed

argilla-server/src/argilla_server/api/schemas/v1/records.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -283,8 +283,8 @@ class TermsFilter(BaseModel):
283283
class RangeFilter(BaseModel):
284284
type: Literal["range"]
285285
scope: FilterScope
286-
ge: Optional[float]
287-
le: Optional[float]
286+
ge: Optional[Union[float, str]]
287+
le: Optional[Union[float, str]]
288288

289289
@root_validator(skip_on_failure=True)
290290
def check_ge_and_le(cls, values: dict) -> dict:

argilla/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ These are the section headers that we use:
1818

1919
### Added
2020

21+
- Added `inserted_at` and `updated_at` to `Resource` model as properties. ([#5540](https://github.com/argilla-io/argilla/pull/5540))
2122
- Added `limit` argument when fetching records. ([#5525](https://github.com/argilla-io/argilla/pull/5525)
2223

2324
### Changed

argilla/src/argilla/_resource.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
# limitations under the License.
1414
from abc import abstractmethod
1515
from datetime import datetime
16-
from typing import Any, TYPE_CHECKING, Optional
16+
from typing import TYPE_CHECKING, Any, Optional
1717
from uuid import UUID
1818

1919
try:
@@ -25,9 +25,9 @@
2525
from argilla._helpers import LoggingMixin
2626

2727
if TYPE_CHECKING:
28-
from argilla.client import Argilla
29-
from argilla._models import ResourceModel
3028
from argilla._api._base import ResourceAPI
29+
from argilla._models import ResourceModel
30+
from argilla.client import Argilla
3131

3232

3333
class Resource(LoggingMixin):
@@ -63,6 +63,14 @@ def id(self) -> Optional[UUID]:
6363
def id(self, value: UUID) -> None:
6464
self._model.id = value
6565

66+
@property
67+
def inserted_at(self) -> datetime:
68+
return self._model.inserted_at
69+
70+
@property
71+
def updated_at(self) -> datetime:
72+
return self._model.updated_at
73+
6674
@property
6775
def is_outdated(self) -> bool:
6876
"""Checks if the resource is outdated based on the last API call

argilla/src/argilla/records/_resource.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ def serialize(self) -> Dict[str, Any]:
183183
serialized_responses = [response.serialize() for response in self.__responses]
184184
serialized_model["responses"] = serialized_responses
185185
serialized_model["suggestions"] = serialized_suggestions
186+
186187
return serialized_model
187188

188189
def to_dict(self) -> Dict[str, Dict]:
@@ -202,6 +203,7 @@ def to_dict(self) -> Dict[str, Dict]:
202203
responses = self.responses.to_dict()
203204
vectors = self.vectors.to_dict()
204205

206+
# TODO: Review model attributes when to_dict and serialize methods are unified
205207
return {
206208
"id": id,
207209
"fields": fields,
@@ -268,8 +270,9 @@ def from_model(cls, model: RecordModel, dataset: "Dataset") -> "Record":
268270
)
269271

270272
# set private attributes
271-
instance._model.id = model.id
272-
instance._model.status = model.status
273+
instance._dataset = dataset
274+
instance._model = model
275+
273276
# Responses and suggestions are computed separately based on the record model
274277
instance.responses.from_models(model.responses)
275278
instance.suggestions.from_models(model.suggestions)

argilla/tests/integration/test_list_records.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,3 +193,21 @@ def test_list_records_with_responses(client: Argilla, dataset: Dataset):
193193

194194
assert records[1].responses["comment"][0].value == "The comment"
195195
assert records[1].responses["sentiment"][0].value == "negative"
196+
197+
198+
def test_list_records_with_updated_at_and_inserted_at(client: Argilla, dataset: Dataset):
199+
dataset.records.log(
200+
[
201+
{"text": "The record text field", "id": 1},
202+
{"text": "The record text field", "id": 2},
203+
]
204+
)
205+
206+
records = list(dataset.records(with_responses=True))
207+
assert len(records) == 2
208+
209+
assert records[0].inserted_at
210+
assert records[0].updated_at
211+
212+
assert records[1].inserted_at
213+
assert records[1].updated_at

argilla/tests/unit/test_resources/test_records.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
import pytest
1818

19-
from argilla import Record, Response, Suggestion, Dataset, Settings, TextQuestion, TextField
19+
from argilla import Dataset, Record, Response, Settings, Suggestion, TextField, TextQuestion
2020
from argilla._exceptions import ArgillaError
2121
from argilla._models import MetadataModel, RecordModel
2222

@@ -61,6 +61,14 @@ def test_record_external_id(self):
6161
record = Record(fields={"name": "John", "age": "30"})
6262
assert record.id
6363

64+
def test_record_inserted_at(self):
65+
record = Record(fields={"name": "John", "age": "30"})
66+
assert hasattr(record, "inserted_at")
67+
68+
def test_record_updated_at(self):
69+
record = Record(fields={"name": "John", "age": "30"})
70+
assert hasattr(record, "updated_at")
71+
6472
def test_update_record_metadata_by_key(self):
6573
record = Record(fields={"name": "John", "age": "30"}, metadata={"key": "value"})
6674

argilla/tests/unit/test_resources/test_users.py

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@
1616
import uuid
1717
from datetime import datetime
1818

19-
import argilla as rg
2019
import httpx
2120
import pytest
21+
from pytest_httpx import HTTPXMock
22+
23+
import argilla as rg
2224
from argilla._exceptions import (
2325
BadRequestError,
2426
ConflictError,
@@ -28,7 +30,6 @@
2830
UnprocessableEntityError,
2931
)
3032
from argilla._models import UserModel
31-
from pytest_httpx import HTTPXMock
3233

3334

3435
class TestUserSerialization:
@@ -113,6 +114,11 @@ def test_create_user(self, httpx_mock: HTTPXMock, status_code, expected_exceptio
113114
created_user = user.create()
114115
assert user.username == created_user.username
115116
assert user.id == created_user.id
117+
assert user.first_name == created_user.first_name
118+
assert user.last_name == created_user.last_name
119+
assert user.role == created_user.role
120+
assert user.inserted_at == created_user.inserted_at
121+
assert user.updated_at == created_user.updated_at
116122

117123
@pytest.mark.parametrize(
118124
"status_code, expected_exception, expected_message",
@@ -156,6 +162,11 @@ def test_get_user(self, httpx_mock: HTTPXMock, status_code, expected_exception,
156162
gotten_user = user.create()
157163
assert user.username == gotten_user.username
158164
assert user.id == gotten_user.id
165+
assert user.first_name == gotten_user.first_name
166+
assert user.last_name == gotten_user.last_name
167+
assert user.role == gotten_user.role
168+
assert user.inserted_at == gotten_user.inserted_at
169+
assert user.updated_at == gotten_user.updated_at
159170

160171
def test_list_users(self, httpx_mock: HTTPXMock):
161172
mock_return_value = {
@@ -190,6 +201,10 @@ def test_list_users(self, httpx_mock: HTTPXMock):
190201
assert users[i].username == mock_return_value["items"][i]["username"]
191202
assert users[i].role == mock_return_value["items"][i]["role"]
192203
assert users[i].id == uuid.UUID(mock_return_value["items"][i]["id"])
204+
assert users[i].first_name == mock_return_value["items"][i]["first_name"]
205+
assert users[i].last_name == mock_return_value["items"][i]["last_name"]
206+
assert users[i].inserted_at == datetime.fromisoformat(mock_return_value["items"][i]["inserted_at"])
207+
assert users[i].updated_at == datetime.fromisoformat(mock_return_value["items"][i]["updated_at"])
193208

194209

195210
class TestUsersAPI:
@@ -212,6 +227,10 @@ def test_get_me(self, httpx_mock: HTTPXMock):
212227
assert user.username == mock_return_value["username"]
213228
assert user.id == uuid.UUID(mock_return_value["id"])
214229
assert user.role == mock_return_value["role"]
230+
assert user.first_name == mock_return_value["first_name"]
231+
assert user.last_name == mock_return_value["last_name"]
232+
assert user.inserted_at == datetime.fromisoformat(mock_return_value["inserted_at"])
233+
assert user.updated_at == datetime.fromisoformat(mock_return_value["updated_at"])
215234

216235
def test_remove_user_from_workspace(self, httpx_mock: HTTPXMock):
217236
user_id = uuid.uuid4()
@@ -275,6 +294,11 @@ def test_list_workspace_users(self, httpx_mock: HTTPXMock):
275294
for i in range(len(users)):
276295
assert users[i].username == mock_return_value["items"][i]["username"]
277296
assert users[i].id == uuid.UUID(mock_return_value["items"][i]["id"])
297+
assert users[i].first_name == mock_return_value["items"][i]["first_name"]
298+
assert users[i].last_name == mock_return_value["items"][i]["last_name"]
299+
assert users[i].role == mock_return_value["items"][i]["role"]
300+
assert users[i].inserted_at == datetime.fromisoformat(mock_return_value["items"][i]["inserted_at"])
301+
assert users[i].updated_at == datetime.fromisoformat(mock_return_value["items"][i]["updated_at"])
278302

279303
def test_create_user(self, httpx_mock: HTTPXMock):
280304
user_id = uuid.uuid4()

argilla/tests/unit/test_resources/test_workspaces.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ def test_create_workspace(self, httpx_mock: HTTPXMock, status_code, expected_exc
8383
created_workspace = ws.create()
8484
assert created_workspace.name == mock_name
8585
assert created_workspace.id == uuid.UUID(mock_return_value["id"])
86+
assert created_workspace.inserted_at == datetime.fromisoformat(mock_return_value["inserted_at"])
87+
assert created_workspace.updated_at == datetime.fromisoformat(mock_return_value["updated_at"])
8688

8789
@pytest.mark.parametrize(
8890
"status_code, expected_exception, expected_message",
@@ -147,6 +149,8 @@ def test_list_workspaces(self, httpx_mock: HTTPXMock):
147149
for i in range(len(workspaces)):
148150
assert workspaces[i].name == mock_return_value["items"][i]["name"]
149151
assert workspaces[i].id == uuid.UUID(mock_return_value["items"][i]["id"])
152+
assert workspaces[i].inserted_at == datetime.fromisoformat(mock_return_value["items"][i]["inserted_at"])
153+
assert workspaces[i].updated_at == datetime.fromisoformat(mock_return_value["items"][i]["updated_at"])
150154

151155

152156
class TestWorkspacesAPI:
@@ -175,6 +179,8 @@ def test_get_workspace_by_name(self, httpx_mock: HTTPXMock):
175179
assert ws is not None
176180
assert ws.name == "test-workspace"
177181
assert ws.id == uuid.UUID(mock_return_value["items"][0]["id"])
182+
assert ws.inserted_at == datetime.fromisoformat(mock_return_value["items"][0]["inserted_at"])
183+
assert ws.updated_at == datetime.fromisoformat(mock_return_value["items"][0]["updated_at"])
178184

179185
def test_multiple_clients_create_workspace(self, httpx_mock: HTTPXMock):
180186
mock_uuid = str(uuid.uuid4())
@@ -246,3 +252,8 @@ def test_list_workspace_datasets(self, httpx_mock: HTTPXMock):
246252
for i in range(len(datasets)):
247253
assert datasets[i].name == mock_return_value["items"][i]["name"]
248254
assert datasets[i].id == uuid.UUID(mock_return_value["items"][i]["id"])
255+
assert datasets[i].guidelines == mock_return_value["items"][i]["guidelines"]
256+
assert datasets[i].allow_extra_metadata == mock_return_value["items"][i]["allow_extra_metadata"]
257+
assert datasets[i].workspace_id == uuid.UUID(mock_return_value["items"][i]["workspace_id"])
258+
assert datasets[i].inserted_at == datetime.fromisoformat(mock_return_value["items"][i]["inserted_at"])
259+
assert datasets[i].updated_at == datetime.fromisoformat(mock_return_value["items"][i]["updated_at"])

0 commit comments

Comments
 (0)