Skip to content

Commit

Permalink
Fix 5381 feature improve unprocessableentityerror due to mis aligned …
Browse files Browse the repository at this point in the history
…id UUID (#5396)

# 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 #5381 

**Type of change**
<!-- Please delete options that are not relevant. Remember to title the
PR according to the type of change -->

- Bug fix (non-breaking change which fixes an issue)

**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: burtenshaw <[email protected]>
  • Loading branch information
davidberenstein1957 and burtenshaw authored Aug 12, 2024
1 parent 93abc78 commit e97dced
Show file tree
Hide file tree
Showing 7 changed files with 132 additions and 39 deletions.
1 change: 1 addition & 0 deletions argilla/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ These are the section headers that we use:

- Fixed error when creating optional fields. ([#5362](https://github.com/argilla-io/argilla/pull/5362))
- Fixed error creating integer and float metadata with `visible_for_annotators`. ([#5364](https://github.com/argilla-io/argilla/pull/5364))
- Fixed error when logging records with `suggestions` or `responses` for non-existent questions. ([#5396](https://github.com/argilla-io/argilla/pull/5396))

### Changed

Expand Down
19 changes: 19 additions & 0 deletions argilla/src/argilla/_exceptions/_responses.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Copyright 2024-present, Argilla, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from argilla._exceptions._base import ArgillaError


class RecordResponsesError(ArgillaError):
pass
19 changes: 19 additions & 0 deletions argilla/src/argilla/_exceptions/_suggestions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Copyright 2024-present, Argilla, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from argilla._exceptions._base import ArgillaError


class RecordSuggestionsError(ArgillaError):
pass
5 changes: 5 additions & 0 deletions argilla/src/argilla/responses.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from typing import TYPE_CHECKING, Any, Dict, Iterable, List, Optional, Union
from uuid import UUID

from argilla._exceptions._responses import RecordResponsesError
from argilla._models import ResponseStatus as ResponseStatusModel
from argilla._models import UserResponseModel
from argilla._resource import Resource
Expand Down Expand Up @@ -183,6 +184,10 @@ def api_model(self):
values = self.__responses_as_model_values(self.responses)
for question_name, value in values.items():
question = self._record.dataset.settings.questions[question_name]
if question is None:
raise RecordResponsesError(
f"Record response is invalid because question with name={question_name} does not exist in the dataset ({self._record.dataset.name}). Available questions are: {list(self._record.dataset.settings.questions._properties_by_name.keys())}"
)
if isinstance(question, RankingQuestion):
value["value"] = self.__ranking_to_model_value(value["value"])

Expand Down
28 changes: 17 additions & 11 deletions argilla/src/argilla/suggestions.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from typing import Any, Optional, Literal, Union, List, TYPE_CHECKING, Dict
from typing import TYPE_CHECKING, Any, Dict, List, Literal, Optional, Union

from argilla._exceptions._suggestions import RecordSuggestionsError
from argilla._models import SuggestionModel
from argilla._resource import Resource
from argilla.settings import RankingQuestion

if TYPE_CHECKING:
from argilla import QuestionType, Record, Dataset
from argilla import Dataset, QuestionType, Record

__all__ = ["Suggestion"]

Expand Down Expand Up @@ -119,15 +120,20 @@ def api_model(self) -> SuggestionModel:
return self._model

question = self.record.dataset.settings.questions[self.question_name]
return SuggestionModel(
value=self.__to_model_value(self.value, question),
question_name=question.name,
question_id=question.id,
type=self._model.type,
score=self._model.score,
agent=self._model.agent,
id=self._model.id,
)
if question:
return SuggestionModel(
value=self.__to_model_value(self.value, question),
question_name=None if not question else question.name,
question_id=None if not question else question.id,
type=self._model.type,
score=self._model.score,
agent=self._model.agent,
id=self._model.id,
)
else:
raise RecordSuggestionsError(
f"Record suggestion is invalid because question with name={self.question_name} does not exist in the dataset ({self.record.dataset.name}). Available questions are: {list(self.record.dataset.settings.questions._properties_by_name.keys())}"
)

@classmethod
def __to_model_value(cls, value: Any, question: "QuestionType") -> Any:
Expand Down
90 changes: 66 additions & 24 deletions argilla/tests/integration/test_add_records.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,35 +12,14 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import random
import uuid
from datetime import datetime


import argilla as rg
import pytest
from argilla import Argilla, Workspace


def test_create_dataset(client):
workspace = client.workspaces.default
mock_dataset_name = f"test_create_dataset{datetime.now().strftime('%Y%m%d%H%M%S')}"
dataset = rg.Dataset(
name=mock_dataset_name,
workspace=workspace,
settings=rg.Settings(
fields=[
rg.TextField(name="text"),
],
questions=[
rg.TextQuestion(name="response"),
],
),
client=client,
)
dataset.create()
gotten_dataset = dataset.get()
assert dataset.id == gotten_dataset.id
assert dataset.name == mock_dataset_name
from argilla._exceptions._responses import RecordResponsesError
from argilla._exceptions._suggestions import RecordSuggestionsError


def test_add_records(client):
Expand Down Expand Up @@ -205,6 +184,33 @@ def test_add_records_with_suggestions(client) -> None:
assert dataset_records[2].suggestions["topics"].score == [0.9, 0.8, 0.7]


def test_add_records_with_suggestions_non_existent_question(client) -> None:
mock_dataset_name = (
f"test_add_record_with_suggestions_non_existent_question {datetime.now().strftime('%Y%m%d%H%M%S')}"
)
mock_data = [
rg.Record(
fields={"text": "value"}, suggestions=[rg.Suggestion(question_name="non_existent_question", value="mock")]
)
]
settings = rg.Settings(
fields=[
rg.TextField(name="text"),
],
questions=[
rg.TextQuestion(name="comment", use_markdown=False),
],
)
dataset = rg.Dataset(
name=mock_dataset_name,
settings=settings,
client=client,
)
dataset.create()
with pytest.raises(RecordSuggestionsError, match="Argilla SDK error: RecordSuggestionsError: Record suggestion"):
dataset.records.log(mock_data)


def test_add_records_with_responses(client, username: str) -> None:
mock_dataset_name = f"test_modify_record_responses_locally {uuid.uuid4()}"
mock_data = [
Expand Down Expand Up @@ -263,6 +269,42 @@ def test_add_records_with_responses(client, username: str) -> None:
assert record.responses["label"][0].user_id == user.id


def test_add_records_with_responses_non_existent_question(client, username: str) -> None:
mock_dataset_name = (
f"test_add_record_with_responses_non_existent_question {datetime.now().strftime('%Y%m%d%H%M%S')}"
)

settings = rg.Settings(
fields=[
rg.TextField(name="text"),
],
questions=[
rg.TextQuestion(name="comment", use_markdown=False),
],
)
dataset = rg.Dataset(
name=mock_dataset_name,
settings=settings,
client=client,
)
dataset.create()
user = rg.User(
username=username,
first_name="test",
password="testtesttest",
client=client,
)
user.create()
mock_data = [
rg.Record(
fields={"text": "value"},
responses=[rg.Response(question_name="non_existent_question", value="mock", user_id=user.id)],
)
]
with pytest.raises(RecordResponsesError, match="Argilla SDK error: RecordResponsesError: Record response"):
dataset.records.log(mock_data)


def test_add_records_with_responses_and_suggestions(client, username: str) -> None:
mock_dataset_name = f"test_modify_record_responses_locally {uuid.uuid4()}"
mock_data = [
Expand Down
9 changes: 5 additions & 4 deletions argilla/tests/integration/test_create_datasets.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,17 @@
# See the License for the specific language governing permissions and
# limitations under the License.


from argilla import (
Argilla,
Dataset,
LabelQuestion,
RatingQuestion,
Settings,
TermsMetadataProperty,
TextField,
RatingQuestion,
LabelQuestion,
Workspace,
VectorField,
TermsMetadataProperty,
Workspace,
)
from argilla.settings._task_distribution import TaskDistribution

Expand Down

0 comments on commit e97dced

Please sign in to comment.