From 4488c8cce69130d9de6a17dedae1e8bd83419c9a Mon Sep 17 00:00:00 2001 From: yuji38kwmt Date: Sun, 10 May 2026 18:24:35 +0900 Subject: [PATCH 1/2] Add descriptions to restriction AST type schema --- annofabapi/util/attribute_restrictions.py | 42 ++++++++++++++++++++++- tests/util/test_attribute_restrictions.py | 12 +++++++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/annofabapi/util/attribute_restrictions.py b/annofabapi/util/attribute_restrictions.py index e146a912..1f7bc910 100644 --- a/annofabapi/util/attribute_restrictions.py +++ b/annofabapi/util/attribute_restrictions.py @@ -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 @@ -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] + + @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 + + +_RESTRICTION_AST_TYPE_DESCRIPTIONS: dict[RestrictionAstType, str] = { + RestrictionAstType.CHECKED: "チェックボックス属性がチェックされていることを表すAST種別です。", + RestrictionAstType.UNCHECKED: "チェックボックス属性がチェックされていないことを表すAST種別です。", + RestrictionAstType.IS_EMPTY: "属性値が空であることを表すAST種別です。", + RestrictionAstType.IS_NOT_EMPTY: "属性値が空でないことを表すAST種別です。", + 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): """属性の制約を表すクラス。""" diff --git a/tests/util/test_attribute_restrictions.py b/tests/util/test_attribute_restrictions.py index edfbd3fc..af54bce7 100644 --- a/tests/util/test_attribute_restrictions.py +++ b/tests/util/test_attribute_restrictions.py @@ -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: From 79a4d38fc6604dfa21cdafbee28c9982da12c9fb Mon Sep 17 00:00:00 2001 From: yuji38kwmt Date: Tue, 12 May 2026 22:39:42 +0900 Subject: [PATCH 2/2] =?UTF-8?q?=E5=B1=9E=E6=80=A7=E5=80=A4=E3=81=8C?= =?UTF-8?q?=E7=A9=BA=E3=81=A7=E3=81=AA=E3=81=84=E3=81=93=E3=81=A8=E3=82=92?= =?UTF-8?q?=E8=A1=A8=E3=81=99AST=E7=A8=AE=E5=88=A5=E3=81=AE=E8=AA=AC?= =?UTF-8?q?=E6=98=8E=E3=82=92=E6=9B=B4=E6=96=B0=E3=81=97=E3=80=81=E5=BF=85?= =?UTF-8?q?=E9=A0=88=E5=88=B6=E7=B4=84=E3=81=AB=E7=9B=B8=E5=BD=93=E3=81=99?= =?UTF-8?q?=E3=82=8B=E3=81=93=E3=81=A8=E3=82=92=E6=98=8E=E8=A8=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- annofabapi/util/attribute_restrictions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/annofabapi/util/attribute_restrictions.py b/annofabapi/util/attribute_restrictions.py index 1f7bc910..60897388 100644 --- a/annofabapi/util/attribute_restrictions.py +++ b/annofabapi/util/attribute_restrictions.py @@ -51,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" @@ -102,7 +102,7 @@ def __get_pydantic_json_schema__(cls, core_schema: CoreSchema, handler: GetJsonS RestrictionAstType.CHECKED: "チェックボックス属性がチェックされていることを表すAST種別です。", RestrictionAstType.UNCHECKED: "チェックボックス属性がチェックされていないことを表すAST種別です。", RestrictionAstType.IS_EMPTY: "属性値が空であることを表すAST種別です。", - RestrictionAstType.IS_NOT_EMPTY: "属性値が空でないことを表すAST種別です。", + RestrictionAstType.IS_NOT_EMPTY: "属性値が空でないことを表すAST種別です。必須制約に相当します。", RestrictionAstType.EQUALS_STRING: "文字列属性またはtracking属性が指定文字列と一致することを表すAST種別です。", RestrictionAstType.NOT_EQUALS_STRING: "文字列属性またはtracking属性が指定文字列と一致しないことを表すAST種別です。", RestrictionAstType.MATCHES_STRING: "文字列属性が指定した正規表現に一致することを表すAST種別です。",