annofabcli 1.95.0__py3-none-any.whl → 1.96.0__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.
annofabcli/__version__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "1.95.0" # `poetry-dynamic-versioning`を使ってGitHubのバージョンタグを取得している。変更不要
1
+ __version__ = "1.96.0" # `poetry-dynamic-versioning`を使ってGitHubのバージョンタグを取得している。変更不要
@@ -20,15 +20,20 @@ from annofabcli.common.utils import print_according_to_format
20
20
  logger = logging.getLogger(__name__)
21
21
 
22
22
 
23
- class ListAttributeRestriction(CommandLine):
23
+ class ExportAnnotationSpecs(CommandLine):
24
24
  COMMON_MESSAGE = "annofabcli annotation_specs export: error:"
25
25
 
26
26
  def get_history_id_from_before_index(self, project_id: str, before: int) -> Optional[str]:
27
27
  histories, _ = self.service.api.get_annotation_specs_histories(project_id)
28
- if before + 1 > len(histories):
29
- logger.warning(f"アノテーション仕様の履歴は{len(histories)}個のため、最新より{before}個前のアノテーション仕様は見つかりませんでした。")
28
+ sorted_histories = sorted(histories, key=lambda x: x["updated_datetime"], reverse=True)
29
+
30
+ if before + 1 > len(sorted_histories):
31
+ logger.warning(
32
+ f"アノテーション仕様の履歴は{len(sorted_histories)}個のため、最新より{before}個前のアノテーション仕様は見つかりませんでした。"
33
+ )
30
34
  return None
31
- history = histories[-(before + 1)]
35
+
36
+ history = sorted_histories[before]
32
37
  return history["history_id"]
33
38
 
34
39
  def get_exported_annotation_specs(self, project_id: str, history_id: Optional[str]) -> dict[str, Any]:
@@ -107,7 +112,7 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
107
112
  def main(args: argparse.Namespace) -> None:
108
113
  service = build_annofabapi_resource_and_login(args)
109
114
  facade = AnnofabApiFacade(service)
110
- ListAttributeRestriction(service, facade, args).main()
115
+ ExportAnnotationSpecs(service, facade, args).main()
111
116
 
112
117
 
113
118
  def add_parser(subparsers: Optional[argparse._SubParsersAction] = None) -> argparse.ArgumentParser:
@@ -0,0 +1,310 @@
1
+ # pylint: disable=too-many-lines
2
+ from __future__ import annotations
3
+
4
+ import argparse
5
+ import logging
6
+ import sys
7
+ import tempfile
8
+ import zipfile
9
+ from collections.abc import Collection, Iterator
10
+ from pathlib import Path
11
+ from typing import Any, Literal, Optional, Union
12
+
13
+ import pandas
14
+ import pydantic
15
+ from annofabapi.models import ProjectMemberRole
16
+ from annofabapi.parser import (
17
+ SimpleAnnotationParser,
18
+ lazy_parse_simple_annotation_dir,
19
+ lazy_parse_simple_annotation_zip,
20
+ )
21
+
22
+ import annofabcli
23
+ import annofabcli.common.cli
24
+ from annofabcli.common.cli import (
25
+ COMMAND_LINE_ERROR_STATUS_CODE,
26
+ ArgumentParser,
27
+ CommandLine,
28
+ build_annofabapi_resource_and_login,
29
+ )
30
+ from annofabcli.common.download import DownloadingFile
31
+ from annofabcli.common.enums import FormatArgument
32
+ from annofabcli.common.facade import (
33
+ AnnofabApiFacade,
34
+ TaskQuery,
35
+ match_annotation_with_task_query,
36
+ )
37
+ from annofabcli.common.type_util import assert_noreturn
38
+ from annofabcli.common.utils import print_csv, print_json
39
+
40
+ logger = logging.getLogger(__name__)
41
+
42
+
43
+ def lazy_parse_simple_annotation_by_input_data(annotation_path: Path) -> Iterator[SimpleAnnotationParser]:
44
+ if not annotation_path.exists():
45
+ raise RuntimeError(f"'{annotation_path}' は存在しません。")
46
+
47
+ if annotation_path.is_dir():
48
+ return lazy_parse_simple_annotation_dir(annotation_path)
49
+ elif zipfile.is_zipfile(str(annotation_path)):
50
+ return lazy_parse_simple_annotation_zip(annotation_path)
51
+ else:
52
+ raise RuntimeError(f"'{annotation_path}'は、zipファイルまたはディレクトリではありません。")
53
+
54
+
55
+ class AnnotationAttribute(pydantic.BaseModel):
56
+ """
57
+ 入力データまたはタスク単位の区間アノテーションの長さ情報。
58
+ """
59
+
60
+ task_id: str
61
+ task_status: str
62
+ task_phase: str
63
+ task_phase_stage: int
64
+
65
+ input_data_id: str
66
+ input_data_name: str
67
+ annotation_id: str
68
+ label: str
69
+ attributes: dict[str, Union[str, int, bool]]
70
+
71
+
72
+ def get_annotation_attribute_list_from_annotation_json(
73
+ simple_annotation: dict[str, Any], *, target_labels: Collection[str] | None = None
74
+ ) -> list[AnnotationAttribute]:
75
+ """
76
+ 1個のアノテーションJSONに対して、アノテーションの属性情報を取得します。
77
+
78
+ Args:
79
+ simple_annotation: アノテーションJSONファイルの内容
80
+ target_labels: 絞り込むラベルのcollection
81
+ """
82
+ details = simple_annotation["details"]
83
+
84
+ result = []
85
+ for detail in details:
86
+ if target_labels is not None: # noqa: SIM102
87
+ if detail["label"] not in target_labels:
88
+ continue
89
+
90
+ result.append(
91
+ AnnotationAttribute(
92
+ task_id=simple_annotation["task_id"],
93
+ task_status=simple_annotation["task_status"],
94
+ task_phase=simple_annotation["task_phase"],
95
+ task_phase_stage=simple_annotation["task_phase_stage"],
96
+ input_data_id=simple_annotation["input_data_id"],
97
+ input_data_name=simple_annotation["input_data_name"],
98
+ label=detail["label"],
99
+ annotation_id=detail["annotation_id"],
100
+ attributes=detail["attributes"],
101
+ )
102
+ )
103
+ return result
104
+
105
+
106
+ def get_annotation_attribute_list_from_annotation_zipdir_path(
107
+ annotation_zipdir_path: Path,
108
+ *,
109
+ target_task_ids: Optional[Collection[str]] = None,
110
+ task_query: Optional[TaskQuery] = None,
111
+ target_labels: Collection[str] | None = None,
112
+ ) -> list[AnnotationAttribute]:
113
+ """
114
+ アノテーションzipまたはそれを展開したディレクトリから、アノテーションの属性のlistを取得します。
115
+
116
+ Args:
117
+ """
118
+ target_task_ids = set(target_task_ids) if target_task_ids is not None else None
119
+
120
+ iter_parser = lazy_parse_simple_annotation_by_input_data(annotation_zipdir_path)
121
+
122
+ result = []
123
+ logger.debug("アノテーションzipまたはディレクトリを読み込み中")
124
+ for index, parser in enumerate(iter_parser):
125
+ if (index + 1) % 1000 == 0:
126
+ logger.debug(f"{index + 1} 件目のJSONを読み込み中")
127
+
128
+ if target_task_ids is not None and parser.task_id not in target_task_ids:
129
+ continue
130
+
131
+ simple_annotation_dict = parser.load_json()
132
+ if task_query is not None: # noqa: SIM102
133
+ if not match_annotation_with_task_query(simple_annotation_dict, task_query):
134
+ continue
135
+
136
+ sub_result = get_annotation_attribute_list_from_annotation_json(simple_annotation_dict, target_labels=target_labels)
137
+ result.extend(sub_result)
138
+
139
+ return result
140
+
141
+
142
+ def print_annotation_attribute_list_as_csv(annotation_attribute_list: list, output_file: Optional[Path]) -> None:
143
+ df = pandas.json_normalize(annotation_attribute_list)
144
+
145
+ # columns = [
146
+ # "task_id",
147
+ # "task_status"
148
+ # "task_phase",
149
+ # "task_phase_stage",
150
+ # "input_data_id",
151
+ # "input_data_name",
152
+ # "annotation_id",
153
+ # "label",
154
+
155
+ # ]
156
+
157
+ print_csv(df, output_file)
158
+
159
+
160
+ def print_annotation_attribute_list(
161
+ annotation_attribute_list: list[AnnotationAttribute],
162
+ output_file: Path,
163
+ output_format: Literal[FormatArgument.CSV, FormatArgument.JSON, FormatArgument.PRETTY_JSON],
164
+ ) -> None:
165
+ tmp_annotation_attribute_list = [e.model_dump() for e in annotation_attribute_list]
166
+ if output_format == FormatArgument.CSV:
167
+ print_annotation_attribute_list_as_csv(tmp_annotation_attribute_list, output_file)
168
+ elif output_format == FormatArgument.JSON:
169
+ print_json(tmp_annotation_attribute_list, output=output_file, is_pretty=False)
170
+ elif output_format == FormatArgument.PRETTY_JSON:
171
+ print_json(tmp_annotation_attribute_list, output=output_file, is_pretty=True)
172
+ else:
173
+ raise assert_noreturn(output_format)
174
+
175
+
176
+ class ListAnnotationAttribute(CommandLine):
177
+ COMMON_MESSAGE = "annofabcli statistics list_annotation_attribute: error:"
178
+
179
+ def validate(self, args: argparse.Namespace) -> bool:
180
+ if args.project_id is None and args.annotation is None:
181
+ print( # noqa: T201
182
+ f"{self.COMMON_MESSAGE} argument --project_id: '--annotation'が未指定のときは、'--project_id' を指定してください。",
183
+ file=sys.stderr,
184
+ )
185
+ return False
186
+
187
+ return True
188
+
189
+ def main(self) -> None:
190
+ args = self.args
191
+
192
+ if not self.validate(args):
193
+ sys.exit(COMMAND_LINE_ERROR_STATUS_CODE)
194
+
195
+ project_id: Optional[str] = args.project_id
196
+ if project_id is not None:
197
+ super().validate_project(project_id, project_member_roles=[ProjectMemberRole.OWNER, ProjectMemberRole.TRAINING_DATA_USER])
198
+
199
+ annotation_path = Path(args.annotation) if args.annotation is not None else None
200
+
201
+ task_id_list = annofabcli.common.cli.get_list_from_args(args.task_id) if args.task_id is not None else None
202
+ label_name_list = annofabcli.common.cli.get_list_from_args(args.label_name) if args.label_name is not None else None
203
+ task_query = TaskQuery.from_dict(annofabcli.common.cli.get_json_from_args(args.task_query)) if args.task_query is not None else None
204
+
205
+ output_file: Path = args.output
206
+ output_format = FormatArgument(args.format)
207
+
208
+ downloading_obj = DownloadingFile(self.service)
209
+
210
+ def download_and_print_annotation_attribute_list(
211
+ project_id: str, temp_dir: Path, *, is_latest: bool, annotation_path: Optional[Path]
212
+ ) -> None:
213
+ if annotation_path is None:
214
+ annotation_path = temp_dir / f"{project_id}__annotation.zip"
215
+ downloading_obj.download_annotation_zip(
216
+ project_id,
217
+ dest_path=annotation_path,
218
+ is_latest=is_latest,
219
+ )
220
+
221
+ annotation_attribute_list = get_annotation_attribute_list_from_annotation_zipdir_path(
222
+ annotation_zipdir_path=annotation_path, target_task_ids=task_id_list, task_query=task_query, target_labels=label_name_list
223
+ )
224
+ print_annotation_attribute_list(annotation_attribute_list, output_file, output_format) # type: ignore[arg-type]
225
+
226
+ if project_id is not None:
227
+ if args.temp_dir is not None:
228
+ download_and_print_annotation_attribute_list(
229
+ project_id=project_id, temp_dir=args.temp_dir, is_latest=args.latest, annotation_path=annotation_path
230
+ )
231
+ else:
232
+ # `NamedTemporaryFile`を使わない理由: Windowsで`PermissionError`が発生するため
233
+ # https://qiita.com/yuji38kwmt/items/c6f50e1fc03dafdcdda0 参考
234
+ with tempfile.TemporaryDirectory() as str_temp_dir:
235
+ download_and_print_annotation_attribute_list(
236
+ project_id=project_id, temp_dir=Path(str_temp_dir), is_latest=args.latest, annotation_path=annotation_path
237
+ )
238
+ else:
239
+ assert annotation_path is not None
240
+ annotation_attribute_list = get_annotation_attribute_list_from_annotation_zipdir_path(
241
+ annotation_zipdir_path=annotation_path, target_task_ids=task_id_list, task_query=task_query, target_labels=label_name_list
242
+ )
243
+ print_annotation_attribute_list(annotation_attribute_list, output_file, output_format) # type: ignore[arg-type]
244
+
245
+
246
+ def parse_args(parser: argparse.ArgumentParser) -> None:
247
+ argument_parser = ArgumentParser(parser)
248
+
249
+ annotation_group = parser.add_mutually_exclusive_group(required=True)
250
+ annotation_group.add_argument(
251
+ "--annotation",
252
+ type=str,
253
+ help="アノテーションzip、またはzipを展開したディレクトリを指定します。指定しない場合はAnnofabからダウンロードします。",
254
+ )
255
+
256
+ annotation_group.add_argument("-p", "--project_id", type=str, help="対象プロジェクトの project_id")
257
+
258
+ argument_parser.add_format(
259
+ choices=[FormatArgument.CSV, FormatArgument.JSON, FormatArgument.PRETTY_JSON],
260
+ default=FormatArgument.CSV,
261
+ )
262
+
263
+ argument_parser.add_output()
264
+
265
+ parser.add_argument(
266
+ "-tq",
267
+ "--task_query",
268
+ type=str,
269
+ help="集計対象タスクを絞り込むためのクエリ条件をJSON形式で指定します。使用できるキーは task_id, status, phase, phase_stage です。"
270
+ " ``file://`` を先頭に付けると、JSON形式のファイルを指定できます。",
271
+ )
272
+ argument_parser.add_task_id(required=False)
273
+
274
+ parser.add_argument(
275
+ "--label_name",
276
+ type=str,
277
+ nargs="+",
278
+ required=False,
279
+ help="出力対象のアノテーションのラベル名(英語)を指定します。指定しない場合はラベル名で絞り込みません。"
280
+ " ``file://`` を先頭に付けると、ラベル名の一覧が記載されたファイルを指定できます。",
281
+ )
282
+
283
+ parser.add_argument(
284
+ "--latest",
285
+ action="store_true",
286
+ help="``--annotation`` を指定しないとき、最新のアノテーションzipを参照します。このオプションを指定すると、アノテーションzipを更新するのに数分待ちます。", # noqa: E501
287
+ )
288
+
289
+ parser.add_argument(
290
+ "--temp_dir",
291
+ type=Path,
292
+ help="指定したディレクトリに、アノテーションZIPなどの一時ファイルをダウンロードします。",
293
+ )
294
+
295
+ parser.set_defaults(subcommand_func=main)
296
+
297
+
298
+ def main(args: argparse.Namespace) -> None:
299
+ service = build_annofabapi_resource_and_login(args)
300
+ facade = AnnofabApiFacade(service)
301
+ ListAnnotationAttribute(service, facade, args).main()
302
+
303
+
304
+ def add_parser(subparsers: Optional[argparse._SubParsersAction] = None) -> argparse.ArgumentParser:
305
+ subcommand_name = "list_annotation_attribute"
306
+ subcommand_help = "アノテーションZIPを読み込み、アノテーションの属性値の一覧を出力します。"
307
+ epilog = "オーナロールまたはアノテーションユーザロールを持つユーザで実行してください。"
308
+ parser = annofabcli.common.cli.add_parser(subparsers, subcommand_name, subcommand_help, description=subcommand_help, epilog=epilog)
309
+ parse_args(parser)
310
+ return parser
@@ -4,6 +4,7 @@ from typing import Optional
4
4
  import annofabcli
5
5
  import annofabcli.common.cli
6
6
  import annofabcli.stat_visualization.merge_visualization_dir
7
+ import annofabcli.statistics.list_annotation_attribute
7
8
  import annofabcli.statistics.list_annotation_count
8
9
  import annofabcli.statistics.list_annotation_duration
9
10
  import annofabcli.statistics.list_video_duration
@@ -21,6 +22,7 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
21
22
  subparsers = parser.add_subparsers(dest="subcommand_name")
22
23
 
23
24
  # サブコマンドの定義
25
+ annofabcli.statistics.list_annotation_attribute.add_parser(subparsers)
24
26
  annofabcli.statistics.list_annotation_count.add_parser(subparsers)
25
27
  annofabcli.statistics.list_annotation_duration.add_parser(subparsers)
26
28
  annofabcli.statistics.list_video_duration.add_parser(subparsers)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: annofabcli
3
- Version: 1.95.0
3
+ Version: 1.96.0
4
4
  Summary: Utility Command Line Interface for AnnoFab
5
5
  Home-page: https://github.com/kurusugawa-computer/annofab-cli
6
6
  License: MIT
@@ -1,6 +1,6 @@
1
1
  annofabcli/__init__.py,sha256=NMA7kFxmLlCiILQPHJa9mEuqXxtLALw_dwyXYsvz4VM,71
2
2
  annofabcli/__main__.py,sha256=JzfycqVG9ENhWOCxTouZwpHwWTSrI-grLsaMudxjyBM,5283
3
- annofabcli/__version__.py,sha256=qh48jc0AerpxMn6bU6jgOxQqy6_nPvZpVTJ5jCGYCDI,132
3
+ annofabcli/__version__.py,sha256=vUosqVW-MeQrE_vPK0xlTVGwdsd_pcLlczOaCRqUXgg,132
4
4
  annofabcli/annotation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  annofabcli/annotation/annotation_query.py,sha256=ke3W3RT1-WfFzwt-TXcQwGmghG34vcKJkM_jxgbNKjU,15922
6
6
  annofabcli/annotation/change_annotation_attributes.py,sha256=zHXyENZfbMGL_15xiK7Cy4cQ2sV0GjSVmKuPm3sOX7Y,17173
@@ -15,7 +15,7 @@ annofabcli/annotation/list_annotation_count.py,sha256=T9fbaoxWeDJIVgW_YgHRldbwrV
15
15
  annofabcli/annotation/restore_annotation.py,sha256=naUEbt48ION9JSijCBR2aQdaoCrRu005tYq0vgUtyp0,14683
16
16
  annofabcli/annotation/subcommand_annotation.py,sha256=Xu4SOHLpo_kPZbvE8hQHr9NRduPTESqu7pYC4LGDlXg,1872
17
17
  annofabcli/annotation_specs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
- annofabcli/annotation_specs/export_annotation_specs.py,sha256=CGmcyP8DbfFUcWnJgJSgxYS9FkV3mW15zZPDab7LNBE,4685
18
+ annofabcli/annotation_specs/export_annotation_specs.py,sha256=eZF5fj2P5U22_5UKgbpsUhZEUvVPMPerMpN4miIcnSA,4821
19
19
  annofabcli/annotation_specs/get_annotation_specs_with_attribute_id_replaced.py,sha256=L0H0M31Amnm3ZEg9JdQe2A1vprsCLPTpj0LUFnP6GDY,8330
20
20
  annofabcli/annotation_specs/get_annotation_specs_with_choice_id_replaced.py,sha256=mISJAgRTBMvISPk5__0w0MmhTkyQCcGPDin8K97x5Eg,6943
21
21
  annofabcli/annotation_specs/get_annotation_specs_with_label_id_replaced.py,sha256=5tlvSdUXAUn8uQ1BXNWxkR2MIKnV6AJoxveiwD21IAo,7114
@@ -130,12 +130,13 @@ annofabcli/stat_visualization/write_performance_rating_csv.py,sha256=TDn7-poyFt2
130
130
  annofabcli/statistics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
131
131
  annofabcli/statistics/histogram.py,sha256=CvzDxT2cKLSnBGSqkZE6p92PayGxYYja1YyB24M4ALU,3245
132
132
  annofabcli/statistics/linegraph.py,sha256=0kr7jVBNMiM2ECYhv3Ry5RitElKerSl9ZKxbKzfiplI,12494
133
+ annofabcli/statistics/list_annotation_attribute.py,sha256=WM0-Zw0Pm35olqrSXvbHnrb4mbC02qcjshLCrbPE3zg,12432
133
134
  annofabcli/statistics/list_annotation_count.py,sha256=xsqXxRO21MW7Wbs96PEa8gHb3i7bxjQvoMHLB2eT-0g,50360
134
135
  annofabcli/statistics/list_annotation_duration.py,sha256=9PCg1IA_g4HoHHSfsMVb2zBMLfLJ3u9Id8Qa9L8Qhko,31923
135
136
  annofabcli/statistics/list_video_duration.py,sha256=uNeMteRBX2JG_AWmcgMJj0Jzbq_qF7bvAwr25GmeIiw,9124
136
137
  annofabcli/statistics/list_worktime.py,sha256=C7Yu3IOW2EvhkJJv6gY3hNdS9_TOLmT_9LZsB7vLJ1o,6493
137
138
  annofabcli/statistics/scatter.py,sha256=IUCwXix9GbZb6V82wjjb5q2eamrT5HQsU_bzDTjAFnM,11011
138
- annofabcli/statistics/subcommand_statistics.py,sha256=Exf7fpOnz8jezBEDKdTwVN7_upN0jzwDt8g0kS9H0Hw,2129
139
+ annofabcli/statistics/subcommand_statistics.py,sha256=JPixzhJGClQYVH6Tgby3KTD85df-aEJKvLAjfJCv-1E,2259
139
140
  annofabcli/statistics/summarize_task_count.py,sha256=8OH6BBRYRjHJkWRTjU0A0OfXa7f3NIRHrxPNFlRt_hM,9707
140
141
  annofabcli/statistics/summarize_task_count_by_task_id_group.py,sha256=TSSmcFv615NLcq6uqXmg3ilYqSHl3A5qp90msVQM1gE,8646
141
142
  annofabcli/statistics/summarize_task_count_by_user.py,sha256=TRoJXpt2HOVb8QO2YtRejkOAxyK80_NsPt3Vk9es9C8,6948
@@ -199,8 +200,8 @@ annofabcli/task_history_event/download_task_history_event_json.py,sha256=hQLVbQ0
199
200
  annofabcli/task_history_event/list_all_task_history_event.py,sha256=JQEgwOIXbbTIfeX23AVaoySHViOR9UGm9uoXuhVEBqo,6446
200
201
  annofabcli/task_history_event/list_worktime.py,sha256=9jsRYa2C9bva8E1Aqxv9CCKDuCP0MvbiaIyQFTDpjqY,13150
201
202
  annofabcli/task_history_event/subcommand_task_history_event.py,sha256=mJVJoT4RXk4HWnY7-Nrsl4If-gtaIIEXd2z7eFZwM2I,1260
202
- annofabcli-1.95.0.dist-info/LICENSE,sha256=pcqWYfxFtxBzhvKp3x9MXNM4xciGb2eFewaRhXUNHlo,1081
203
- annofabcli-1.95.0.dist-info/METADATA,sha256=iAatfNNAeWskgaipQQ13ZHVSsEVHvmDTes41DtynbCQ,5626
204
- annofabcli-1.95.0.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
205
- annofabcli-1.95.0.dist-info/entry_points.txt,sha256=A8vlN9fiMhbYRcdBfSpl7piYzAwvkMhRXIPQUAvQFUo,55
206
- annofabcli-1.95.0.dist-info/RECORD,,
203
+ annofabcli-1.96.0.dist-info/LICENSE,sha256=pcqWYfxFtxBzhvKp3x9MXNM4xciGb2eFewaRhXUNHlo,1081
204
+ annofabcli-1.96.0.dist-info/METADATA,sha256=kHn5yPXYeuO3FK-MKUhhRcZ5vAhUakxbnLEOlqM6KsY,5626
205
+ annofabcli-1.96.0.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
206
+ annofabcli-1.96.0.dist-info/entry_points.txt,sha256=A8vlN9fiMhbYRcdBfSpl7piYzAwvkMhRXIPQUAvQFUo,55
207
+ annofabcli-1.96.0.dist-info/RECORD,,