Skip to content

アノテーションクラスの領域数上限をSDKから指定できるようにする - #288

Open
soymd wants to merge 11 commits into
mainfrom
feature/annotation-max-area-count
Open

アノテーションクラスの領域数上限をSDKから指定できるようにする#288
soymd wants to merge 11 commits into
mainfrom
feature/annotation-max-area-count

Conversation

@soymd

@soymd soymd commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

概要

アノテーションクラスの「1アノテーションあたりの領域数上限」(maxAreaCount)を、SDKから指定・変更できるようにしました。

これまでSDKでアノテーションクラスを作成すると、この値がAPI側で常に 1 に固定されていました。1 だと飛び地のセグメンテーションができないため、SDKでクラスを同期している案件では、作成後に画面から1クラスずつ「なし」に直す必要がありました。更新メソッドでも変更できず、既存クラスをまとめて直す手段もありませんでした。

省略時の値は従来どおり 1 です(API側の既定値)。既存の連携の振る舞いが変わらないようにするためです。

対応内容

  • create_annotationmax_area_count を追加。省略時はリクエストに含めず、API側の既定値 1 に委ねる。None を指定すると「なし」(無制限)、整数を指定するとその値
  • update_annotationmax_area_count を追加。省略時はリクエストに含めないため変更されず、None を指定すると「なし」(無制限)
  • 既存の引数の並びは変えず、いずれも末尾に追加しています
  • READMEに使用例と有効範囲(1〜1000)を追記

作成・更新のどちらも「引数を渡さなかった」と「None を渡した」を区別する必要があります。None は「上限なし」という意味でAPIへ送る値なので、「未指定」の意味を兼ねられません。そのためモジュール内にセンチネル _UNSET を置き、それ以外が渡されたときだけ maxAreaCount をリクエストに載せています。センチネルの型注釈は Any にして、公開されるシグネチャが Optional[int] のままになるようにしています。

有効範囲(1〜1000)と整数かどうかの検証はAPI側に委ねています(422が返ります)。同じ Clientlimit などをクライアント側で弾く例はありますが、上限値をリポジトリを跨いで二重に持たないほうがよいと判断しました。

テスト

  • tests/test_annotation.py を追加。作成・更新それぞれで、省略時にキーを送らないこと、None と整数がそのまま載ることを検証
  • テスト用の client fixture とリクエスト記録ヘルパーを tests/conftest.py へ移動。tests/test_workspace_user.py に同じものが定義されていたため、そちらも共有fixtureを使う形に書き換えています(振る舞いの変更はありません)

依存

API側の対応(fastlabel/fastlabel-application#11670)のリリース後に、このPRをマージ・リリースしてください。max_area_count を指定したときだけAPI側の対応が必要で、指定しない既存の呼び出しはリクエスト内容が従来と同一のため、API側のリリース前でも影響ありません。

  • fastlabel/fastlabel-application#11670
  • fastlabel/fastlabel-application#11669

動作確認

pytest tests/            # 20 passed
black --check . && flake8 . && isort --check .

CIはlintとPython 3.10〜3.14のマトリクスが全てpassしています。

あわせて、ローカル環境のAPI(#11670 のブランチのコード)に対してこのSDKから実際にリクエストを投げ、作成(省略時 1 / None / 整数 / 境界値 / 範囲外は422)、更新(省略時は変更なし / None / 整数 / 範囲外は422で既存値も変わらない)、読み出し、max_area_count を渡さない従来どおりの呼び出しを確認しています。

@soymd soymd self-assigned this Aug 19, 2026
@soymd
soymd requested a review from kamei-takuma August 19, 2026 08:12
@soymd
soymd marked this pull request as ready for review August 19, 2026 08:15
Comment thread fastlabel/__init__.py
payload["order"] = order
if attributes:
payload["attributes"] = attributes
if max_area_count is not _UNSET:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

他の箇所では0が無制限、Noneがデフォルトという実装になっており、
_UNSET = デフォルト
という実装について理解に非常に時間がかかりました。
大抵の場合は0が無制限を表し、省略時はデフォルト値を表します。

今回の実装については、maxAreaCountのdb側が無制限= nullだからUNSETという新しい概念を追加したという判断で合ってますか?
かなり特殊な実装なので、なぜこのような実装になっているかコメントがほしいです。次に実装する人が混乱します

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

ご認識のとおりです。maxAreaCount は無制限が null で、null 自体が API へ送る値になるため None が「未指定」を兼ねられず、省略 / null / 整数の三値になっています。

他の項目の二値の慣習から外れる点はご指摘どおりなので、マーカーの定義側と create / update 双方の使用箇所に、三値であることとそれぞれの意味をコメントで残しました。

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

maxAreaCount は無制限が null で、null 自体が API へ送る値になるため None が「未指定」を兼ねられず、省略 / null / 整数の三値になっています。
という点がコメントで確認できませんでした。

この点がないと、次の実装者がdbまで見に行かないと実装意図がわかりません

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

sdkは全てのコメントが英語で書かれているので英語でお願いしますー

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

英語に戻しました!

Comment thread fastlabel/__init__.py
)


class _Unset:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

このようなセンチネルはsdkとして公開する都合上、念のためシングルトンにしておいた方がいいですね。copy.deepcopy や pickle を通ると is 判定が壊れて _Unset が payload に載ってしまうので。

シングルトンとしては普通にこんな感じ

  _instance = None

    def __new__(cls):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

シングルトンにしました。deepcopy / pickle を往復しても is 判定が保たれ、payload にマーカーが載らないことをテストで固定しています。

soymd added 2 commits August 21, 2026 09:45
SDKとして公開する都合上、呼び出し側でキーワード引数がdeepcopyやpickleを
経由することがある。素のインスタンスだと同一性比較が壊れ、マーカー自身が
リクエストに載ってしまうため。
省略時はNoneという二値の慣習に対して、この項目はnull自体がAPIの受け付ける
値になるため三値になる。慣習との違いが読み手に伝わらずレビューで疑問が
出たため、マーカーの定義側と使用箇所の双方に意図を残す。
@soymd
soymd requested a review from h-iwata August 21, 2026 01:04
Comment thread fastlabel/__init__.py
payload["order"] = order
if attributes:
payload["attributes"] = attributes
if max_area_count is not _UNSET:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

maxAreaCount は無制限が null で、null 自体が API へ送る値になるため None が「未指定」を兼ねられず、省略 / null / 整数の三値になっています。
という点がコメントで確認できませんでした。

この点がないと、次の実装者がdbまで見に行かないと実装意図がわかりません

maxAreaCount は API 側で無制限を null で表すため None が「未指定」を兼ねられず
三値になるという理由を、対象フィールド名と API 仕様を名指しする形で明記した。
従来の英語かつ一般化した説明では、レビューで意図が確認できなかったため。

#288 (comment)
@soymd

soymd commented Aug 21, 2026

Copy link
Copy Markdown
Contributor Author

@h-iwata san
すみません意図汲み取れておりませんでした
以下のコメントを書くようにしておりますので確認お願いいたします

このモジュールの任意引数は大半が「送る / 送らない」の二値で、後者を None
    が兼ねられる。一方、null 自体が API へ送る意味のある値になる引数 (領域数
    上限 maxAreaCount は 0 ではなく null が「無制限」を表す) は「省略 / null /
    値」の三値になる。この場合 None は API へ届ける null の側に取られるため
    「呼び出し側が何も言わなかった」を表せず、その状態をこのマーカーが担う。

@soymd
soymd requested a review from h-iwata August 21, 2026 02:24
Comment thread fastlabel/__init__.py
payload["order"] = order
if attributes:
payload["attributes"] = attributes
if max_area_count is not _UNSET:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

sdkは全てのコメントが英語で書かれているので英語でお願いしますー

SDK 全体のコメントが英語で統一されているため、日本語化した分を戻した。
maxAreaCount を名指しし null が無制限を表すという API 仕様を書く具体度は
そのまま英語で維持した。

#288 (comment)
@soymd
soymd requested a review from h-iwata August 21, 2026 04:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants