annofabcli 1.106.6__py3-none-any.whl → 1.106.7__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,7 +6,7 @@ import logging
6
6
  import sys
7
7
  from collections import defaultdict
8
8
  from pathlib import Path
9
- from typing import Any, Optional, Union
9
+ from typing import Optional, Union
10
10
 
11
11
  import annofabapi
12
12
  import pandas
@@ -76,7 +76,7 @@ class ChangeAnnotationAttributesPerAnnotationMain(CommandLineWithConfirm):
76
76
  self.dump_annotation_obj = DumpAnnotationMain(service, project_id)
77
77
  super().__init__(all_yes)
78
78
 
79
- def change_annotation_attributes_by_frame(self, task_id: str, input_data_id: str, anno_list: list[TargetAnnotation]) -> bool:
79
+ def change_annotation_attributes_by_frame(self, task_id: str, input_data_id: str, anno_list: list[TargetAnnotation]) -> tuple[int, int]:
80
80
  """
81
81
  フレームごとにアノテーション属性値を変更する。
82
82
 
@@ -85,6 +85,10 @@ class ChangeAnnotationAttributesPerAnnotationMain(CommandLineWithConfirm):
85
85
  input_data_id: 入力データID
86
86
  additional_data_list: 変更後の属性値(`AdditionalDataListV2`スキーマ)
87
87
 
88
+ Returns:
89
+ [1]: 属性値の変更に成功したアノテーション数
90
+ [2]: 属性値を変更できなかった(変更対象のアノテーションが存在しなかった)アノテーション数
91
+
88
92
  """
89
93
  editor_annotation, _ = self.service.api.get_editor_annotation(self.project_id, task_id=task_id, input_data_id=input_data_id, query_params={"v": "2"})
90
94
 
@@ -94,26 +98,47 @@ class ChangeAnnotationAttributesPerAnnotationMain(CommandLineWithConfirm):
94
98
 
95
99
  details_map = {detail["annotation_id"]: detail for detail in editor_annotation["details"]}
96
100
 
97
- def _to_request_body_elm(anno: TargetAnnotation) -> dict[str, Any]:
101
+ request_body = []
102
+ non_target_annotation_count = 0
103
+ for anno in anno_list:
104
+ if anno.annotation_id not in details_map:
105
+ logger.warning(
106
+ f"task_id='{task_id}', input_data_id='{input_data_id}' :: "
107
+ f"annotation_id='{anno.annotation_id}'であるアノテーションが存在しないため、"
108
+ "このアノテーションの属性値の変更をスキップします。"
109
+ )
110
+ non_target_annotation_count += 1
111
+ continue
112
+
113
+ label_id = details_map[anno.annotation_id]["label_id"]
98
114
  additional_data_list = convert_attributes_from_cli_to_additional_data_list_v2(anno.attributes, annotation_specs=self.annotation_specs)
99
- return {
100
- "data": {
101
- "project_id": editor_annotation["project_id"],
102
- "task_id": editor_annotation["task_id"],
103
- "input_data_id": editor_annotation["input_data_id"],
104
- "updated_datetime": editor_annotation["updated_datetime"],
105
- "annotation_id": anno.annotation_id,
106
- "label_id": details_map[anno.annotation_id]["label_id"],
107
- "additional_data_list": additional_data_list,
108
- },
109
- "_type": "PutV2",
110
- }
111
-
112
- request_body = [_to_request_body_elm(annotation) for annotation in anno_list]
113
-
114
- self.service.api.batch_update_annotations(self.project_id, request_body=request_body)
115
- logger.debug(f"task_id='{task_id}', input_data_id='{input_data_id}' :: {len(request_body)}件の属性値を変更しました。")
116
- return True
115
+ request_body.append(
116
+ {
117
+ "data": {
118
+ "project_id": editor_annotation["project_id"],
119
+ "task_id": editor_annotation["task_id"],
120
+ "input_data_id": editor_annotation["input_data_id"],
121
+ "updated_datetime": editor_annotation["updated_datetime"],
122
+ "annotation_id": anno.annotation_id,
123
+ "label_id": label_id,
124
+ "additional_data_list": additional_data_list,
125
+ },
126
+ "_type": "PutV2",
127
+ }
128
+ )
129
+
130
+ if request_body:
131
+ self.service.api.batch_update_annotations(self.project_id, request_body=request_body)
132
+ else:
133
+ logger.debug(f"task_id='{task_id}', input_data_id='{input_data_id}' :: 変更対象のアノテーションがありませんでした。")
134
+
135
+ succeed_to_change_annotation_count = len(request_body)
136
+ logger.debug(
137
+ f"task_id='{task_id}', input_data_id='{input_data_id}' :: "
138
+ f"{succeed_to_change_annotation_count}/{len(anno_list)}件の属性値を変更しました。"
139
+ f"{non_target_annotation_count}件のアノテーションは存在しなかったため、属性値の変更をスキップしました。"
140
+ )
141
+ return succeed_to_change_annotation_count, non_target_annotation_count
117
142
 
118
143
  def change_annotation_attributes_for_task(self, task_id: str, annotation_list_per_input_data_id: dict[str, list[TargetAnnotation]]) -> tuple[bool, int, int]:
119
144
  """
@@ -159,10 +184,9 @@ class ChangeAnnotationAttributesPerAnnotationMain(CommandLineWithConfirm):
159
184
 
160
185
  for input_data_id, sub_anno_list in annotation_list_per_input_data_id.items():
161
186
  try:
162
- if self.change_annotation_attributes_by_frame(task_id, input_data_id, sub_anno_list):
163
- succeed_to_change_annotation_count += len(sub_anno_list)
164
- else:
165
- failed_to_change_annotation_count += len(sub_anno_list)
187
+ tmp_succeed_to_change_annotation_count, tmp_failed_to_change_annotation_count = self.change_annotation_attributes_by_frame(task_id, input_data_id, sub_anno_list)
188
+ succeed_to_change_annotation_count += tmp_succeed_to_change_annotation_count
189
+ failed_to_change_annotation_count += tmp_failed_to_change_annotation_count
166
190
  except Exception:
167
191
  logger.warning(f"task_id='{task_id}', input_data_id='{input_data_id}' :: アノテーションの属性値変更に失敗しました。", exc_info=True)
168
192
  failed_to_change_annotation_count += len(sub_anno_list)
@@ -9,7 +9,6 @@ import uuid
9
9
  import zipfile
10
10
  from collections.abc import Iterator
11
11
  from dataclasses import dataclass
12
- from functools import partial
13
12
  from pathlib import Path
14
13
  from typing import Any, Optional, Union
15
14
 
@@ -408,6 +407,7 @@ class ImportAnnotationMain(CommandLineWithConfirm):
408
407
  is_force: bool,
409
408
  is_merge: bool,
410
409
  is_overwrite: bool,
410
+ converter: AnnotationConverter,
411
411
  ) -> None:
412
412
  self.service = service
413
413
  self.facade = AnnofabApiFacade(service)
@@ -417,8 +417,9 @@ class ImportAnnotationMain(CommandLineWithConfirm):
417
417
  self.is_force = is_force
418
418
  self.is_merge = is_merge
419
419
  self.is_overwrite = is_overwrite
420
+ self.converter = converter
420
421
 
421
- def put_annotation_for_input_data(self, parser: SimpleAnnotationParser, converter: AnnotationConverter) -> bool:
422
+ def put_annotation_for_input_data(self, parser: SimpleAnnotationParser) -> bool:
422
423
  task_id = parser.task_id
423
424
  input_data_id = parser.input_data_id
424
425
 
@@ -444,18 +445,18 @@ class ImportAnnotationMain(CommandLineWithConfirm):
444
445
 
445
446
  logger.info(f"task_id='{task_id}', input_data_id='{input_data_id}' :: {len(simple_annotation.details)} 件のアノテーションを登録します。")
446
447
  if self.is_merge:
447
- request_body = converter.convert_annotation_details(parser, simple_annotation.details, old_details=old_annotation["details"], updated_datetime=old_annotation["updated_datetime"])
448
+ request_body = self.converter.convert_annotation_details(parser, simple_annotation.details, old_details=old_annotation["details"], updated_datetime=old_annotation["updated_datetime"])
448
449
  else:
449
- request_body = converter.convert_annotation_details(parser, simple_annotation.details, old_details=[], updated_datetime=old_annotation["updated_datetime"])
450
+ request_body = self.converter.convert_annotation_details(parser, simple_annotation.details, old_details=[], updated_datetime=old_annotation["updated_datetime"])
450
451
 
451
452
  self.service.api.put_annotation(self.project_id, task_id, input_data_id, request_body=request_body, query_params={"v": "2"})
452
453
  return True
453
454
 
454
- def put_annotation_for_task(self, task_parser: SimpleAnnotationParserByTask, converter: AnnotationConverter) -> int:
455
+ def put_annotation_for_task(self, task_parser: SimpleAnnotationParserByTask) -> int:
455
456
  success_count = 0
456
457
  for parser in task_parser.lazy_parse():
457
458
  try:
458
- if self.put_annotation_for_input_data(parser, converter):
459
+ if self.put_annotation_for_input_data(parser):
459
460
  success_count += 1
460
461
  except Exception: # pylint: disable=broad-except
461
462
  logger.warning(
@@ -465,7 +466,7 @@ class ImportAnnotationMain(CommandLineWithConfirm):
465
466
 
466
467
  return success_count
467
468
 
468
- def execute_task(self, task_parser: SimpleAnnotationParserByTask, converter: AnnotationConverter, task_index: Optional[int] = None) -> bool:
469
+ def execute_task(self, task_parser: SimpleAnnotationParserByTask, task_index: Optional[int] = None) -> bool:
469
470
  """
470
471
  1個のタスクに対してアノテーションを登録する。
471
472
 
@@ -514,7 +515,7 @@ class ImportAnnotationMain(CommandLineWithConfirm):
514
515
  )
515
516
  return False
516
517
 
517
- result_count = self.put_annotation_for_task(task_parser, converter)
518
+ result_count = self.put_annotation_for_task(task_parser)
518
519
  logger.info(f"{logger_prefix}タスク'{task_parser.task_id}'の入力データ {result_count} 個に対してアノテーションをインポートしました。")
519
520
 
520
521
  if changed_operator:
@@ -531,11 +532,10 @@ class ImportAnnotationMain(CommandLineWithConfirm):
531
532
  def execute_task_wrapper(
532
533
  self,
533
534
  tpl: tuple[int, SimpleAnnotationParserByTask],
534
- converter: AnnotationConverter,
535
535
  ) -> bool:
536
536
  task_index, task_parser = tpl
537
537
  try:
538
- return self.execute_task(task_parser, converter=converter, task_index=task_index)
538
+ return self.execute_task(task_parser, task_index=task_index)
539
539
  except Exception: # pylint: disable=broad-except
540
540
  logger.warning(f"task_id='{task_parser.task_id}' のアノテーションのインポートに失敗しました。", exc_info=True)
541
541
  return False
@@ -543,18 +543,9 @@ class ImportAnnotationMain(CommandLineWithConfirm):
543
543
  def main(
544
544
  self,
545
545
  iter_task_parser: Iterator[SimpleAnnotationParserByTask],
546
- converter: AnnotationConverter,
547
546
  target_task_ids: Optional[set[str]] = None,
548
547
  parallelism: Optional[int] = None,
549
548
  ) -> None:
550
- """
551
- アノテーションのインポート処理を実行するメイン関数です。
552
-
553
- Notes:
554
- `converter`をインスタンス変数でなく引数として渡している理由:
555
- `multiprocessing.Pool`でシリアライズ化する際、"TypeError: cannot pickle '_thread.RLock' object"というエラーが発生するため
556
- """
557
-
558
549
  def get_iter_task_parser_from_task_ids(_iter_task_parser: Iterator[SimpleAnnotationParserByTask], _target_task_ids: set[str]) -> Iterator[SimpleAnnotationParserByTask]:
559
550
  for task_parser in _iter_task_parser:
560
551
  if task_parser.task_id in _target_task_ids:
@@ -571,15 +562,14 @@ class ImportAnnotationMain(CommandLineWithConfirm):
571
562
  task_count = 0
572
563
  if parallelism is not None:
573
564
  with multiprocessing.Pool(parallelism) as pool:
574
- func = partial(self.execute_task_wrapper, converter=converter)
575
- result_bool_list = pool.map(func, enumerate(iter_task_parser))
565
+ result_bool_list = pool.map(self.execute_task_wrapper, enumerate(iter_task_parser))
576
566
  success_count = len([e for e in result_bool_list if e])
577
567
  task_count = len(result_bool_list)
578
568
 
579
569
  else:
580
570
  for task_index, task_parser in enumerate(iter_task_parser):
581
571
  try:
582
- result = self.execute_task(task_parser, converter=converter, task_index=task_index)
572
+ result = self.execute_task(task_parser, task_index=task_index)
583
573
  if result:
584
574
  success_count += 1
585
575
  except Exception:
@@ -618,6 +608,13 @@ class ImportAnnotation(CommandLine):
618
608
  print(f"{COMMON_MESSAGE} argument --annotation: ZIPファイルまたはディレクトリを指定してください。", file=sys.stderr) # noqa: T201
619
609
  return False
620
610
 
611
+ if args.parallelism is not None and annotation_path.is_file() and zipfile.is_zipfile(annotation_path):
612
+ print( # noqa: T201
613
+ f"{COMMON_MESSAGE} argument --parallelism: '--annotation'にZIPファイルを指定した場合は、'--parallelism'を指定できません。",
614
+ file=sys.stderr,
615
+ )
616
+ return False
617
+
621
618
  if args.parallelism is not None and not args.yes:
622
619
  print( # noqa: T201
623
620
  f"{COMMON_MESSAGE} argument --parallelism: '--parallelism'を指定するときは、必ず '--yes' を指定してください。",
@@ -642,7 +639,7 @@ class ImportAnnotation(CommandLine):
642
639
  # Simpleアノテーションの読み込み
643
640
  if annotation_path.is_dir():
644
641
  iter_task_parser = lazy_parse_simple_annotation_dir_by_task(annotation_path)
645
- elif zipfile.is_zipfile(str(annotation_path)):
642
+ elif zipfile.is_zipfile(annotation_path):
646
643
  iter_task_parser = lazy_parse_simple_annotation_zip_by_task(annotation_path)
647
644
  else:
648
645
  logger.warning(f"annotation_path: '{annotation_path}' は、zipファイルまたはディレクトリではありませんでした。")
@@ -659,9 +656,10 @@ class ImportAnnotation(CommandLine):
659
656
  is_merge=args.merge,
660
657
  is_overwrite=args.overwrite,
661
658
  is_force=args.force,
659
+ converter=converter,
662
660
  )
663
661
 
664
- main_obj.main(iter_task_parser, target_task_ids=target_task_ids, converter=converter, parallelism=args.parallelism)
662
+ main_obj.main(iter_task_parser, target_task_ids=target_task_ids, parallelism=args.parallelism)
665
663
 
666
664
 
667
665
  def main(args: argparse.Namespace) -> None:
@@ -717,7 +715,9 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
717
715
  "--parallelism",
718
716
  type=int,
719
717
  choices=PARALLELISM_CHOICES,
720
- help="並列度。指定しない場合は、逐次的に処理します。指定した場合は、``--yes`` も指定してください。",
718
+ help="並列度。指定しない場合は、逐次的に処理します。"
719
+ "ただし ``--annotation`` にZIPファイルを指定した場合は、``--parallelism`` を指定できません。"
720
+ "また、``--parallelism`` を指定した場合は、``--yes`` も指定してください。",
721
721
  )
722
722
 
723
723
  parser.set_defaults(subcommand_func=main)
@@ -26,10 +26,11 @@ logger = logging.getLogger(__name__)
26
26
 
27
27
 
28
28
  class ChangeOperatorMain:
29
- def __init__(self, service: annofabapi.Resource, all_yes: bool) -> None: # noqa: FBT001
29
+ def __init__(self, service: annofabapi.Resource, *, all_yes: bool, include_on_hold: bool = False) -> None:
30
30
  self.service = service
31
31
  self.facade = AnnofabApiFacade(service)
32
32
  self.all_yes = all_yes
33
+ self.include_on_hold = include_on_hold
33
34
 
34
35
  def confirm_processing(self, confirm_message: str) -> bool:
35
36
  """
@@ -55,10 +56,10 @@ class ChangeOperatorMain:
55
56
  return yes
56
57
 
57
58
  def confirm_change_operator(self, task: Task) -> bool:
58
- confirm_message = f"task_id = {task.task_id} のタスクの担当者を変更しますか?"
59
+ confirm_message = f"task_id='{task.task_id}' のタスクの担当者を変更しますか?"
59
60
  return self.confirm_processing(confirm_message)
60
61
 
61
- def change_operator_for_task(
62
+ def change_operator_for_task( # noqa: PLR0911
62
63
  self,
63
64
  project_id: str,
64
65
  task_id: str,
@@ -69,7 +70,7 @@ class ChangeOperatorMain:
69
70
  logging_prefix = f"{task_index + 1} 件目" if task_index is not None else ""
70
71
  dict_task = self.service.wrapper.get_task_or_none(project_id, task_id)
71
72
  if dict_task is None:
72
- logger.warning(f"{logging_prefix}: task_id='{task_id}'のタスクは存在しないので、スキップします。")
73
+ logger.warning(f"{logging_prefix} :: task_id='{task_id}'のタスクは存在しないので、スキップします。")
73
74
  return False
74
75
 
75
76
  task: Task = Task.from_dict(dict_task)
@@ -78,14 +79,23 @@ class ChangeOperatorMain:
78
79
  if task.account_id is not None:
79
80
  now_user_id = self.facade.get_user_id_from_account_id(project_id, task.account_id)
80
81
 
81
- logger.debug(f"{logging_prefix} : task_id = {task.task_id}, status = {task.status.value}, phase = {task.phase.value}, phase_stage = {task.phase_stage}, user_id = {now_user_id}")
82
+ logger.debug(f"{logging_prefix} :: task_id='{task.task_id}', status='{task.status.value}', phase='{task.phase.value}', phase_stage='{task.phase_stage}', user_id='{now_user_id}'")
83
+ if task.account_id == new_account_id:
84
+ logger.info(f"{logging_prefix} :: task_id='{task_id}' :: タスクの担当者はすでにuser_id='{now_user_id}'のユーザーです。担当者を変更する必要がないのでスキップします。")
85
+ return False
82
86
 
83
87
  if task.status in [TaskStatus.COMPLETE, TaskStatus.WORKING]:
84
- logger.warning(f"{logging_prefix} : task_id = {task_id} : タスクのstatusがworking or complete なので、担当者を変更できません。")
88
+ logger.warning(f"{logging_prefix} :: task_id='{task_id}' :: タスクが作業中状態または完了状態なので、担当者を変更できません。 :: status='{task.status.value}'")
89
+ return False
90
+
91
+ if task.status == TaskStatus.ON_HOLD and not self.include_on_hold:
92
+ logger.warning(
93
+ f"{logging_prefix} :: task_id='{task_id}' :: タスクが保留中状態なので、担当者を変更できません。保留中状態のタスクの担当者も変更する場合は、'--include_on_hold'を指定してください。"
94
+ )
85
95
  return False
86
96
 
87
97
  if not match_task_with_query(task, task_query):
88
- logger.debug(f"{logging_prefix} : task_id = {task_id} : `--task_query` の条件にマッチしないため、スキップします。task_query={task_query}")
98
+ logger.debug(f"{logging_prefix} :: task_id='{task_id}' :: `--task_query` の条件にマッチしないため、スキップします。task_query='{task_query}'")
89
99
  return False
90
100
 
91
101
  if not self.confirm_change_operator(task):
@@ -94,11 +104,11 @@ class ChangeOperatorMain:
94
104
  try:
95
105
  # 担当者を変更する
96
106
  self.service.wrapper.change_task_operator(project_id, task_id, operator_account_id=new_account_id)
97
- logger.debug(f"{logging_prefix} : task_id = {task_id}, phase={dict_task['phase']} のタスクの担当者を変更しました。")
107
+ logger.debug(f"{logging_prefix} :: task_id='{task_id}'であるタスクの担当者を変更しました。 :: phase='{dict_task['phase']}'")
98
108
  return True # noqa: TRY300
99
109
 
100
110
  except requests.exceptions.HTTPError:
101
- logger.warning(f"{logging_prefix} : task_id = {task_id} の担当者を変更するのに失敗しました。", exc_info=True)
111
+ logger.warning(f"{logging_prefix} :: task_id='{task_id}'である担当者を変更するのに失敗しました。", exc_info=True)
102
112
  return False
103
113
 
104
114
  def change_operator_for_task_wrapper(
@@ -118,19 +128,21 @@ class ChangeOperatorMain:
118
128
  new_account_id=new_account_id,
119
129
  )
120
130
  except Exception: # pylint: disable=broad-except
121
- logger.warning(f"タスク'{task_id}'の担当者の変更に失敗しました。", exc_info=True)
131
+ logger.warning(f"task_id='{task_id}'であるタスク担当者の変更に失敗しました。", exc_info=True)
122
132
  return False
123
133
 
124
134
  def change_operator(
125
135
  self,
126
136
  project_id: str,
127
137
  task_id_list: list[str],
138
+ *,
128
139
  new_user_id: Optional[str] = None,
129
140
  task_query: Optional[TaskQuery] = None,
130
141
  parallelism: Optional[int] = None,
131
142
  ) -> None:
132
143
  """
133
- 検査コメントを付与して、タスクを差し戻す
144
+ 指定した複数のタスクの担当者を変更します。
145
+
134
146
  Args:
135
147
  project_id:
136
148
  task_id_list:
@@ -143,13 +155,13 @@ class ChangeOperatorMain:
143
155
  if new_user_id is not None:
144
156
  new_account_id = self.facade.get_account_id_from_user_id(project_id, new_user_id)
145
157
  if new_account_id is None:
146
- logger.error(f"ユーザ '{new_user_id}' のaccount_idが見つかりませんでした。終了します。")
158
+ logger.error(f"user_id='{new_user_id}'であるユーザーは、project_id='{project_id}'のプロジェクトのメンバーではありません。終了します。")
147
159
  return
148
160
  else:
149
- logger.info(f"{len(task_id_list)} 件のタスクの担当者を、{new_user_id}に変更します。")
161
+ logger.info(f"{len(task_id_list)} 件のタスクの担当者を、user_id='{new_user_id}'のユーザーに変更します。")
150
162
  else:
151
163
  new_account_id = None
152
- logger.info(f"{len(task_id_list)} 件のタスクの担当者を未割り当てに変更します。")
164
+ logger.info(f"{len(task_id_list)} 件のタスクの担当者を「未割り当て」に変更します。")
153
165
 
154
166
  success_count = 0
155
167
 
@@ -172,7 +184,7 @@ class ChangeOperatorMain:
172
184
  if result:
173
185
  success_count += 1
174
186
  except Exception: # pylint: disable=broad-except
175
- logger.warning(f"タスク'{task_id}'の担当者の変更に失敗しました。", exc_info=True)
187
+ logger.warning(f"task_id='{task_id}'であるタスクの担当者の変更に失敗しました。", exc_info=True)
176
188
  continue
177
189
 
178
190
  logger.info(f"{success_count} / {len(task_id_list)} 件 タスクの担当者を変更しました。")
@@ -212,7 +224,7 @@ class ChangeOperator(CommandLine):
212
224
  project_id = args.project_id
213
225
  super().validate_project(project_id, [ProjectMemberRole.OWNER, ProjectMemberRole.ACCEPTER])
214
226
 
215
- main_obj = ChangeOperatorMain(self.service, all_yes=self.all_yes)
227
+ main_obj = ChangeOperatorMain(self.service, all_yes=self.all_yes, include_on_hold=args.include_on_hold)
216
228
  main_obj.change_operator(
217
229
  project_id,
218
230
  task_id_list=task_id_list,
@@ -242,6 +254,12 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
242
254
 
243
255
  argument_parser.add_task_query()
244
256
 
257
+ parser.add_argument(
258
+ "--include_on_hold",
259
+ action="store_true",
260
+ help="指定した場合、保留中のタスクの担当者も変更します。指定しない場合、保留中のタスクはスキップされます。",
261
+ )
262
+
245
263
  parser.add_argument(
246
264
  "--parallelism",
247
265
  type=int,
@@ -255,7 +273,7 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
255
273
  def add_parser(subparsers: Optional[argparse._SubParsersAction] = None) -> argparse.ArgumentParser:
256
274
  subcommand_name = "change_operator"
257
275
  subcommand_help = "タスクの担当者を変更します。"
258
- description = "タスクの担当者を変更します。ただし、作業中また完了状態のタスクは、担当者を変更できません。"
276
+ description = "タスクの担当者を変更します。作業中状態、完了状態のタスクは、担当者を変更できません。保留中状態のタスクは、デフォルトでは担当者を変更できません。"
259
277
  epilog = "チェッカーまたはオーナロールを持つユーザで実行してください。"
260
278
 
261
279
  parser = annofabcli.common.cli.add_parser(subparsers, subcommand_name, subcommand_help, description, epilog=epilog)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: annofabcli
3
- Version: 1.106.6
3
+ Version: 1.106.7
4
4
  Summary: Utility Command Line Interface for AnnoFab
5
5
  Author: Kurusugawa Computer Inc.
6
6
  License: MIT
@@ -4,13 +4,13 @@ annofabcli/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  annofabcli/annotation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  annofabcli/annotation/annotation_query.py,sha256=VwfPWpLOpVa2SeEJ264LmCKkBGDJvpX8o7GbWIrDE0o,15712
6
6
  annofabcli/annotation/change_annotation_attributes.py,sha256=Zjqax-sb7ujJnTUVv4io0GFmZzfqx0rpN2N1W86uVTs,17092
7
- annofabcli/annotation/change_annotation_attributes_per_annotation.py,sha256=iU199MlMfD-nfyRiHL44Zqrvr12vOeUHXyxCrDgaivI,14130
7
+ annofabcli/annotation/change_annotation_attributes_per_annotation.py,sha256=g_SqH1xzAdA8D1Hy1aoOPlpF86nc7F1PENeUX8XftDs,15529
8
8
  annofabcli/annotation/change_annotation_properties.py,sha256=Kp_LZ5sSoVmmjGE80ABVO3InxsXBIxiFFvVcIJNsOMk,18309
9
9
  annofabcli/annotation/copy_annotation.py,sha256=Pih2k3vvpgfT3Ovb3gZw2L_8fK_ws_wKR7ARYG5hG_8,18407
10
10
  annofabcli/annotation/delete_annotation.py,sha256=hQApNrx2Ci1bBWk0dRGA0oJkIgDHwl6Jy0-33gYF6jo,22989
11
11
  annofabcli/annotation/download_annotation_zip.py,sha256=P_ZpdqIaSFEmB8jjpdykcRhh2tVlHxSlXFrYreJjShE,3282
12
12
  annofabcli/annotation/dump_annotation.py,sha256=Q-p6f5XBs7khDgrfY5Q3CGLBMKEerJWO_CQ8_73UXVM,9972
13
- annofabcli/annotation/import_annotation.py,sha256=hVX2T7gN3pad2KI7TzB2_fnga7fnfRVTMGUa611m3xE,34612
13
+ annofabcli/annotation/import_annotation.py,sha256=w0iSTmkIY8tz3cTUy2FJ6LCVpVUtKzcD7ej2cznot4A,34533
14
14
  annofabcli/annotation/list_annotation.py,sha256=uKcOuGC7lzd6vVbzizkiZtYdXJ7EzY0iifuiqKl2wQM,10707
15
15
  annofabcli/annotation/list_annotation_count.py,sha256=T9fbaoxWeDJIVgW_YgHRldbwrVZWiE-57lfJrDQrj80,6474
16
16
  annofabcli/annotation/merge_segmentation.py,sha256=kIsCeXtJxzd6nobQPpi0fscaRDlTx3tg1qpy5PDfSJI,18107
@@ -182,7 +182,7 @@ annofabcli/supplementary/put_supplementary_data.py,sha256=Pyq9G6xQFyJ8qrdWLOQvIU
182
182
  annofabcli/supplementary/subcommand_supplementary.py,sha256=F8qfuNQzgW5HV1QKB4h0DWN7-kPVQcoFQwPfW_vjZVk,1079
183
183
  annofabcli/task/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
184
184
  annofabcli/task/cancel_acceptance.py,sha256=QG9GhGNfBXntqYTKdYjLUczjD4p_ATkPc_xYCpTO24Y,13851
185
- annofabcli/task/change_operator.py,sha256=1LLpez79ezW_MqcNN608kjxp3xTS1uRRioqcugui9hM,10446
185
+ annofabcli/task/change_operator.py,sha256=q6pMd1SdsTRgMHS0705dnosTSHprTpYgXtNd0rli2Zg,11793
186
186
  annofabcli/task/change_status_to_break.py,sha256=hwdFTFW-zV0VxuinoBB5n6mvHJ7g9ChjrSOXZcNk88w,8621
187
187
  annofabcli/task/change_status_to_on_hold.py,sha256=vWRyk6IK3HcgTWDIbbhXzsrtuoa7OlXCf8CvUpFp_Uw,12981
188
188
  annofabcli/task/complete_tasks.py,sha256=ssg_Z7ADRQRXvXgK2k5TEmvbRjrJQ33cXeb8kG8Y3jc,24917
@@ -209,8 +209,8 @@ annofabcli/task_history_event/download_task_history_event_json.py,sha256=hQLVbQ0
209
209
  annofabcli/task_history_event/list_all_task_history_event.py,sha256=EeKMyPUxGwYCFtWQHHW954ZserGm8lUqrwNnV1iX9X4,6830
210
210
  annofabcli/task_history_event/list_worktime.py,sha256=Y7Pu5DP7scPf7HPt6CTiTvB1_5_Nfi1bStUIaCpkhII,15507
211
211
  annofabcli/task_history_event/subcommand_task_history_event.py,sha256=mJVJoT4RXk4HWnY7-Nrsl4If-gtaIIEXd2z7eFZwM2I,1260
212
- annofabcli-1.106.6.dist-info/METADATA,sha256=6fqjbrE7DWDbXzS3Zo4GPm_oHeqhkdfjqqdUlySo8Rw,5286
213
- annofabcli-1.106.6.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
214
- annofabcli-1.106.6.dist-info/entry_points.txt,sha256=C2uSUc-kkLJpoK_mDL5FEMAdorLEMPfwSf8VBMYnIFM,56
215
- annofabcli-1.106.6.dist-info/licenses/LICENSE,sha256=pcqWYfxFtxBzhvKp3x9MXNM4xciGb2eFewaRhXUNHlo,1081
216
- annofabcli-1.106.6.dist-info/RECORD,,
212
+ annofabcli-1.106.7.dist-info/METADATA,sha256=3zYEhS25YYDmpQ1FV9qAyccpPSLvajgcXFrydflKzUE,5286
213
+ annofabcli-1.106.7.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
214
+ annofabcli-1.106.7.dist-info/entry_points.txt,sha256=C2uSUc-kkLJpoK_mDL5FEMAdorLEMPfwSf8VBMYnIFM,56
215
+ annofabcli-1.106.7.dist-info/licenses/LICENSE,sha256=pcqWYfxFtxBzhvKp3x9MXNM4xciGb2eFewaRhXUNHlo,1081
216
+ annofabcli-1.106.7.dist-info/RECORD,,