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
44 changes: 42 additions & 2 deletions annofabapi/util/attribute_restrictions.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@
from enum import Enum
from typing import Any, NoReturn, cast

from pydantic import BaseModel, ConfigDict, Field, field_serializer, model_validator
from pydantic import BaseModel, ConfigDict, Field, GetJsonSchemaHandler, field_serializer, model_validator
from pydantic.json_schema import JsonSchemaValue
from pydantic_core import CoreSchema

from annofabapi.pydantic_models.additional_data_definition_type import AdditionalDataDefinitionType
from annofabapi.util.annotation_specs import AnnotationSpecsAccessor, AttributeChoice, AttributeDefinition, get_choice, get_english_message
Expand All @@ -49,7 +51,7 @@ class RestrictionAstType(str, Enum):
IS_EMPTY = "is_empty"
"""属性値が空であることを表すAST種別です。"""
IS_NOT_EMPTY = "is_not_empty"
"""属性値が空でないことを表すAST種別です。"""
"""属性値が空でないことを表すAST種別です。必須制約に相当します。"""
EQUALS_STRING = "equals_string"
"""文字列属性またはtracking属性が指定文字列と一致することを表すAST種別です。"""
NOT_EQUALS_STRING = "not_equals_string"
Expand All @@ -76,6 +78,44 @@ class RestrictionAstType(str, Enum):
def __str__(self) -> str:
return self.value

@property
def description(self) -> str:
"""AST種別の説明文を返します。"""
return _RESTRICTION_AST_TYPE_DESCRIPTIONS[self]
Comment on lines +82 to +84
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: マッピングに漏れがあると KeyError になる可能性があるため、dict.get を使ってデフォルト値を返すようにガードしてください。 [general, importance: 3]

Suggested change
def description(self) -> str:
"""AST種別の説明文を返します。"""
return _RESTRICTION_AST_TYPE_DESCRIPTIONS[self]
@property
def description(self) -> str:
"""AST種別の説明文を返します。"""
return _RESTRICTION_AST_TYPE_DESCRIPTIONS.get(self, "")


@classmethod
def __get_pydantic_json_schema__(cls, core_schema: CoreSchema, handler: GetJsonSchemaHandler) -> JsonSchemaValue:
"""AST種別ごとの説明を含むJSON Schemaを返します。"""
json_schema = handler(core_schema)
json_schema["oneOf"] = [
{
"const": ast_type.value,
"title": ast_type.name,
"description": ast_type.description,
}
for ast_type in cls
]
return json_schema
Comment on lines +88 to +98
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: JSON Schema のルートに enum 全体の説明が含まれていないため、json_schema["description"] を追加して明示的に説明文を設定してください。テストで期待される "属性制約ASTの種別です。" を指定するとマッチします。 [possible issue, importance: 9]

Suggested change
"""AST種別ごとの説明を含むJSON Schemaを返します。"""
json_schema = handler(core_schema)
json_schema["oneOf"] = [
{
"const": ast_type.value,
"title": ast_type.name,
"description": ast_type.description,
}
for ast_type in cls
]
return json_schema
def __get_pydantic_json_schema__(cls, core_schema: CoreSchema, handler: GetJsonSchemaHandler) -> JsonSchemaValue:
"""AST種別ごとの説明を含むJSON Schemaを返します。"""
json_schema = handler(core_schema)
json_schema["description"] = "属性制約ASTの種別です。"
json_schema["oneOf"] = [
{
"const": ast_type.value,
"title": ast_type.name,
"description": ast_type.description,
}
for ast_type in cls
]
return json_schema



_RESTRICTION_AST_TYPE_DESCRIPTIONS: dict[RestrictionAstType, str] = {
RestrictionAstType.CHECKED: "チェックボックス属性がチェックされていることを表すAST種別です。",
RestrictionAstType.UNCHECKED: "チェックボックス属性がチェックされていないことを表すAST種別です。",
RestrictionAstType.IS_EMPTY: "属性値が空であることを表すAST種別です。",
RestrictionAstType.IS_NOT_EMPTY: "属性値が空でないことを表すAST種別です。必須制約に相当します。",
Comment on lines +101 to +105
RestrictionAstType.EQUALS_STRING: "文字列属性またはtracking属性が指定文字列と一致することを表すAST種別です。",
RestrictionAstType.NOT_EQUALS_STRING: "文字列属性またはtracking属性が指定文字列と一致しないことを表すAST種別です。",
RestrictionAstType.MATCHES_STRING: "文字列属性が指定した正規表現に一致することを表すAST種別です。",
RestrictionAstType.NOT_MATCHES_STRING: "文字列属性が指定した正規表現に一致しないことを表すAST種別です。",
RestrictionAstType.EQUALS_INTEGER: "整数属性が指定した整数値と一致することを表すAST種別です。",
RestrictionAstType.NOT_EQUALS_INTEGER: "整数属性が指定した整数値と一致しないことを表すAST種別です。",
RestrictionAstType.HAS_CHOICE: "選択属性で指定した選択肢が選ばれていることを表すAST種別です。",
RestrictionAstType.NOT_HAS_CHOICE: "選択属性で指定した選択肢が選ばれていないことを表すAST種別です。",
RestrictionAstType.HAS_LABEL: "リンク属性が指定したラベル群のいずれかを指すことを表すAST種別です。",
RestrictionAstType.CAN_INPUT: "属性が編集可能かどうかを表すAST種別です。",
RestrictionAstType.IMPLY: "前提を満たす場合に結論を要求する含意制約を表すAST種別です。",
}


class Restriction(ABC):
"""属性の制約を表すクラス。"""
Expand Down
12 changes: 12 additions & 0 deletions tests/util/test_attribute_restrictions.py
Original file line number Diff line number Diff line change
Expand Up @@ -437,10 +437,22 @@ def test__invalid_field_type(self):
def test__model_json_schema(self):
actual = RestrictionAst.model_json_schema()
properties = actual["$defs"]["RestrictionAst"]["properties"]
ast_type_schema = actual["$defs"]["RestrictionAstType"]

assert properties["type"]["description"] == "ASTノードの種類です。"
assert properties["attribute_name"]["description"] == "対象属性の名前です。"
assert properties["premise"]["description"] == "`imply` ノードの前提です。"
assert ast_type_schema["description"] == "属性制約ASTの種別です。"
assert {
"const": "checked",
"title": "CHECKED",
"description": "チェックボックス属性がチェックされていることを表すAST種別です。",
} in ast_type_schema["oneOf"]
assert {
"const": "imply",
"title": "IMPLY",
"description": "前提を満たす場合に結論を要求する含意制約を表すAST種別です。",
} in ast_type_schema["oneOf"]


class Test__get_attribute_restriction_catalog:
Expand Down
Loading