annofabcli 1.114.3__py3-none-any.whl → 1.114.5__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/annotation/list_annotation.py +4 -4
- annofabcli/annotation/list_annotation_count.py +4 -4
- annofabcli/annotation_specs/export_annotation_specs.py +4 -4
- annofabcli/annotation_specs/get_annotation_specs_with_attribute_id_replaced.py +4 -4
- annofabcli/annotation_specs/get_annotation_specs_with_choice_id_replaced.py +4 -4
- annofabcli/annotation_specs/get_annotation_specs_with_label_id_replaced.py +4 -4
- annofabcli/annotation_specs/list_annotation_specs_attribute.py +7 -7
- annofabcli/annotation_specs/list_annotation_specs_choice.py +9 -9
- annofabcli/annotation_specs/list_annotation_specs_history.py +2 -2
- annofabcli/annotation_specs/list_annotation_specs_label.py +8 -8
- annofabcli/annotation_specs/list_annotation_specs_label_attribute.py +7 -7
- annofabcli/annotation_specs/list_label_color.py +2 -2
- annofabcli/annotation_zip/list_annotation_3d_bounding_box.py +8 -8
- annofabcli/annotation_zip/list_annotation_bounding_box_2d.py +8 -8
- annofabcli/annotation_zip/list_polygon_annotation.py +8 -8
- annofabcli/annotation_zip/list_polyline_annotation.py +8 -8
- annofabcli/annotation_zip/list_range_annotation.py +8 -8
- annofabcli/annotation_zip/list_single_point_annotation.py +8 -8
- annofabcli/annotation_zip/validate_annotation.py +2 -2
- annofabcli/comment/list_all_comment.py +8 -8
- annofabcli/comment/list_comment.py +8 -8
- annofabcli/common/cli.py +3 -3
- annofabcli/common/enums.py +1 -1
- annofabcli/common/pandas.py +4 -3
- annofabcli/common/utils.py +10 -10
- annofabcli/common/visualize.py +3 -3
- annofabcli/filesystem/mask_user_info.py +3 -2
- annofabcli/input_data/list_all_input_data.py +11 -22
- annofabcli/input_data/list_all_input_data_merged_task.py +7 -7
- annofabcli/input_data/list_input_data.py +67 -18
- annofabcli/instruction/list_instruction_history.py +2 -2
- annofabcli/job/list_job.py +2 -2
- annofabcli/job/list_last_job.py +2 -2
- annofabcli/my_account/get_my_account.py +4 -4
- annofabcli/organization/list_organization.py +5 -5
- annofabcli/organization_member/list_organization_member.py +4 -4
- annofabcli/project/list_project.py +9 -9
- annofabcli/project_member/list_users.py +4 -4
- annofabcli/statistics/list_annotation_area.py +8 -8
- annofabcli/statistics/list_annotation_attribute.py +8 -8
- annofabcli/statistics/list_annotation_attribute_filled_count.py +11 -11
- annofabcli/statistics/list_annotation_count.py +529 -166
- annofabcli/statistics/list_annotation_duration.py +8 -8
- annofabcli/statistics/list_video_duration.py +6 -6
- annofabcli/statistics/summarize_task_count_by_task_id_group.py +2 -2
- annofabcli/statistics/summarize_task_count_by_user.py +2 -2
- annofabcli/statistics/visualization/dataframe/project_performance.py +2 -1
- annofabcli/statistics/visualization/dataframe/task.py +25 -6
- annofabcli/supplementary/list_supplementary_data.py +2 -2
- annofabcli/task/list_all_tasks.py +8 -18
- annofabcli/task/list_all_tasks_added_task_history.py +6 -6
- annofabcli/task/list_tasks.py +73 -37
- annofabcli/task/list_tasks_added_task_history.py +25 -16
- annofabcli/task_history/list_all_task_history.py +6 -6
- annofabcli/task_history/list_task_history.py +6 -6
- annofabcli/task_history_event/list_all_task_history_event.py +6 -6
- annofabcli/task_history_event/list_worktime.py +6 -6
- {annofabcli-1.114.3.dist-info → annofabcli-1.114.5.dist-info}/METADATA +2 -2
- {annofabcli-1.114.3.dist-info → annofabcli-1.114.5.dist-info}/RECORD +62 -62
- {annofabcli-1.114.3.dist-info → annofabcli-1.114.5.dist-info}/WHEEL +0 -0
- {annofabcli-1.114.3.dist-info → annofabcli-1.114.5.dist-info}/entry_points.txt +0 -0
- {annofabcli-1.114.3.dist-info → annofabcli-1.114.5.dist-info}/licenses/LICENSE +0 -0
|
@@ -34,7 +34,7 @@ from annofabcli.common.cli import (
|
|
|
34
34
|
build_annofabapi_resource_and_login,
|
|
35
35
|
)
|
|
36
36
|
from annofabcli.common.download import DownloadingFile
|
|
37
|
-
from annofabcli.common.enums import
|
|
37
|
+
from annofabcli.common.enums import OutputFormat
|
|
38
38
|
from annofabcli.common.facade import (
|
|
39
39
|
AnnofabApiFacade,
|
|
40
40
|
TaskQuery,
|
|
@@ -504,7 +504,7 @@ class ListAnnotationDurationMain:
|
|
|
504
504
|
self,
|
|
505
505
|
annotation_path: Path,
|
|
506
506
|
output_file: Path,
|
|
507
|
-
arg_format:
|
|
507
|
+
arg_format: OutputFormat,
|
|
508
508
|
*,
|
|
509
509
|
project_id: str | None = None,
|
|
510
510
|
input_data_json_path: Path | None = None,
|
|
@@ -527,12 +527,12 @@ class ListAnnotationDurationMain:
|
|
|
527
527
|
|
|
528
528
|
logger.info(f"{len(annotation_duration_list)} 件のタスクに含まれる区間アノテーションの長さ情報を出力します。")
|
|
529
529
|
|
|
530
|
-
if arg_format ==
|
|
530
|
+
if arg_format == OutputFormat.CSV:
|
|
531
531
|
assert csv_type is not None
|
|
532
532
|
self.print_annotation_duration_csv(annotation_duration_list, output_file=output_file, csv_type=csv_type, annotation_specs=annotation_specs)
|
|
533
533
|
|
|
534
|
-
elif arg_format in [
|
|
535
|
-
json_is_pretty = arg_format ==
|
|
534
|
+
elif arg_format in [OutputFormat.PRETTY_JSON, OutputFormat.JSON]:
|
|
535
|
+
json_is_pretty = arg_format == OutputFormat.PRETTY_JSON
|
|
536
536
|
|
|
537
537
|
print_json(
|
|
538
538
|
[e.to_dict(encode_json=True) for e in annotation_duration_list],
|
|
@@ -578,7 +578,7 @@ class ListAnnotationDuration(CommandLine):
|
|
|
578
578
|
|
|
579
579
|
csv_type = CsvType(args.type)
|
|
580
580
|
output_file: Path = args.output
|
|
581
|
-
arg_format =
|
|
581
|
+
arg_format = OutputFormat(args.format)
|
|
582
582
|
main_obj = ListAnnotationDurationMain(self.service)
|
|
583
583
|
|
|
584
584
|
downloading_obj = DownloadingFile(self.service)
|
|
@@ -660,8 +660,8 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
660
660
|
)
|
|
661
661
|
|
|
662
662
|
argument_parser.add_format(
|
|
663
|
-
choices=[
|
|
664
|
-
default=
|
|
663
|
+
choices=[OutputFormat.CSV, OutputFormat.JSON, OutputFormat.PRETTY_JSON],
|
|
664
|
+
default=OutputFormat.CSV,
|
|
665
665
|
)
|
|
666
666
|
|
|
667
667
|
argument_parser.add_output()
|
|
@@ -20,7 +20,7 @@ from annofabcli.common.cli import (
|
|
|
20
20
|
build_annofabapi_resource_and_login,
|
|
21
21
|
)
|
|
22
22
|
from annofabcli.common.download import DownloadingFile
|
|
23
|
-
from annofabcli.common.enums import
|
|
23
|
+
from annofabcli.common.enums import OutputFormat
|
|
24
24
|
from annofabcli.common.facade import AnnofabApiFacade
|
|
25
25
|
from annofabcli.common.utils import print_according_to_format, print_csv
|
|
26
26
|
|
|
@@ -81,7 +81,7 @@ class ListVideoDuration(CommandLine):
|
|
|
81
81
|
self,
|
|
82
82
|
task_json: Path,
|
|
83
83
|
input_data_json: Path,
|
|
84
|
-
output_format:
|
|
84
|
+
output_format: OutputFormat,
|
|
85
85
|
output_file: Path | None,
|
|
86
86
|
) -> None:
|
|
87
87
|
with task_json.open(encoding="utf-8") as f:
|
|
@@ -91,7 +91,7 @@ class ListVideoDuration(CommandLine):
|
|
|
91
91
|
|
|
92
92
|
video_duration_list = get_video_duration_list(task_list=task_list, input_data_list=input_data_list)
|
|
93
93
|
logger.info(f"{len(video_duration_list)} 件のタスクの動画長さを出力します。")
|
|
94
|
-
if output_format ==
|
|
94
|
+
if output_format == OutputFormat.CSV:
|
|
95
95
|
columns = [
|
|
96
96
|
"project_id",
|
|
97
97
|
"task_id",
|
|
@@ -125,7 +125,7 @@ class ListVideoDuration(CommandLine):
|
|
|
125
125
|
)
|
|
126
126
|
sys.exit(COMMAND_LINE_ERROR_STATUS_CODE)
|
|
127
127
|
|
|
128
|
-
func = partial(self.list_video_duration, output_file=args.output, output_format=
|
|
128
|
+
func = partial(self.list_video_duration, output_file=args.output, output_format=OutputFormat(args.format))
|
|
129
129
|
|
|
130
130
|
def wrapper_func(temp_dir: Path) -> None:
|
|
131
131
|
downloading_obj = DownloadingFile(self.service)
|
|
@@ -190,8 +190,8 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
190
190
|
)
|
|
191
191
|
|
|
192
192
|
argument_parser.add_format(
|
|
193
|
-
choices=[
|
|
194
|
-
default=
|
|
193
|
+
choices=[OutputFormat.CSV, OutputFormat.JSON, OutputFormat.PRETTY_JSON],
|
|
194
|
+
default=OutputFormat.CSV,
|
|
195
195
|
)
|
|
196
196
|
|
|
197
197
|
argument_parser.add_output()
|
|
@@ -19,7 +19,7 @@ from annofabcli.common.cli import (
|
|
|
19
19
|
)
|
|
20
20
|
from annofabcli.common.dataclasses import WaitOptions
|
|
21
21
|
from annofabcli.common.download import DownloadingFile
|
|
22
|
-
from annofabcli.common.enums import
|
|
22
|
+
from annofabcli.common.enums import OutputFormat
|
|
23
23
|
from annofabcli.common.facade import AnnofabApiFacade
|
|
24
24
|
from annofabcli.statistics.summarize_task_count import get_step_for_current_phase
|
|
25
25
|
|
|
@@ -144,7 +144,7 @@ class SummarizeTaskCountByTaskId(CommandLine):
|
|
|
144
144
|
columns = ["task_id_group"] + [status.value for status in TaskStatusForSummary] + ["sum"]
|
|
145
145
|
annofabcli.common.utils.print_according_to_format(
|
|
146
146
|
df[columns],
|
|
147
|
-
format=
|
|
147
|
+
format=OutputFormat.CSV,
|
|
148
148
|
output=self.output,
|
|
149
149
|
)
|
|
150
150
|
|
|
@@ -16,7 +16,7 @@ from annofabcli.common.cli import (
|
|
|
16
16
|
)
|
|
17
17
|
from annofabcli.common.dataclasses import WaitOptions
|
|
18
18
|
from annofabcli.common.download import DownloadingFile
|
|
19
|
-
from annofabcli.common.enums import
|
|
19
|
+
from annofabcli.common.enums import OutputFormat
|
|
20
20
|
from annofabcli.common.facade import AnnofabApiFacade
|
|
21
21
|
|
|
22
22
|
logger = logging.getLogger(__name__)
|
|
@@ -112,7 +112,7 @@ class SummarizeTaskCountByUser(CommandLine):
|
|
|
112
112
|
target_df = df[columns].sort_values("user_id")
|
|
113
113
|
annofabcli.common.utils.print_according_to_format(
|
|
114
114
|
target_df,
|
|
115
|
-
format=
|
|
115
|
+
format=OutputFormat.CSV,
|
|
116
116
|
output=self.output,
|
|
117
117
|
)
|
|
118
118
|
|
|
@@ -136,7 +136,8 @@ class ProjectWorktimePerMonth:
|
|
|
136
136
|
series = df.groupby(pandas.Grouper(key="dt_date", freq=get_frequency_of_monthend())).sum(numeric_only=True)[worktime_column.value]
|
|
137
137
|
# indexを"2022-04"という形式にする
|
|
138
138
|
new_index = [str(dt)[0:7] for dt in series.index]
|
|
139
|
-
|
|
139
|
+
# pandas 3.0対応: .valuesではなく.to_numpy()を使用
|
|
140
|
+
result = pandas.Series(series.to_numpy(), index=new_index)
|
|
140
141
|
result["dirname"] = project_dir.project_dir.name
|
|
141
142
|
result["project_title"] = project_dir.get_project_title()
|
|
142
143
|
return result
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import datetime
|
|
3
4
|
import logging
|
|
4
5
|
from pathlib import Path
|
|
5
6
|
from typing import Any
|
|
@@ -9,7 +10,6 @@ import bokeh
|
|
|
9
10
|
import bokeh.layouts
|
|
10
11
|
import numpy
|
|
11
12
|
import pandas
|
|
12
|
-
import pytz
|
|
13
13
|
from bokeh.plotting import figure
|
|
14
14
|
|
|
15
15
|
from annofabcli.common.bokeh import convert_1d_figure_list_to_2d, create_pretext_from_metadata
|
|
@@ -426,10 +426,11 @@ class Task:
|
|
|
426
426
|
# タイムゾーンを指定している理由::
|
|
427
427
|
# すべてがNaNのseriesをdatetimeに変換すると、型にタイムゾーンが指定されない。
|
|
428
428
|
# その状態で加算すると、`TypeError: DatetimeArray subtraction must have the same timezones or no timezones`というエラーが発生するため
|
|
429
|
+
# pandas 3.0対応: pytz.FixedOffsetの代わりにdatetime.timezoneを使用
|
|
429
430
|
if not isinstance(dt1.dtype, pandas.DatetimeTZDtype):
|
|
430
|
-
dt1 = dt1.dt.tz_localize(
|
|
431
|
+
dt1 = dt1.dt.tz_localize(datetime.timezone(datetime.timedelta(hours=9)))
|
|
431
432
|
if not isinstance(dt2.dtype, pandas.DatetimeTZDtype):
|
|
432
|
-
dt2 = dt2.dt.tz_localize(
|
|
433
|
+
dt2 = dt2.dt.tz_localize(datetime.timezone(datetime.timedelta(hours=9)))
|
|
433
434
|
|
|
434
435
|
return (dt1 - dt2).dt.total_seconds() / 3600 / 24
|
|
435
436
|
|
|
@@ -532,9 +533,27 @@ class Task:
|
|
|
532
533
|
if not self._validate_df_for_output(output_file):
|
|
533
534
|
return
|
|
534
535
|
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
536
|
+
# metadata列が存在する場合は展開する
|
|
537
|
+
if "metadata" in self.df.columns:
|
|
538
|
+
# metadata列のみをjson_normalizeで展開
|
|
539
|
+
df_metadata = pandas.json_normalize(self.df["metadata"].tolist())
|
|
540
|
+
# 列名にmetadata.プレフィックスを追加
|
|
541
|
+
df_metadata.columns = [f"metadata.{col}" for col in df_metadata.columns]
|
|
542
|
+
# 元のDataFrameからmetadata列を削除
|
|
543
|
+
df_without_metadata = self.df.drop(columns=["metadata"])
|
|
544
|
+
# 展開したmetadata列を結合
|
|
545
|
+
df_normalized = pandas.concat([df_without_metadata.reset_index(drop=True), df_metadata.reset_index(drop=True)], axis=1)
|
|
546
|
+
else:
|
|
547
|
+
df_normalized = self.df
|
|
548
|
+
|
|
549
|
+
# metadata.*列を検出
|
|
550
|
+
metadata_columns = sorted([col for col in df_normalized.columns if col.startswith("metadata.")])
|
|
551
|
+
|
|
552
|
+
# 出力対象の列を定義
|
|
553
|
+
existing_optional_columns = [col for col in self.optional_columns if col in set(df_normalized.columns)]
|
|
554
|
+
columns = self.required_columns + existing_optional_columns + metadata_columns
|
|
555
|
+
|
|
556
|
+
print_csv(df_normalized[columns], str(output_file))
|
|
538
557
|
|
|
539
558
|
def mask_user_info(
|
|
540
559
|
self,
|
|
@@ -15,7 +15,7 @@ from annofabapi.models import SupplementaryData
|
|
|
15
15
|
import annofabcli.common.cli
|
|
16
16
|
from annofabcli.common.cli import PARALLELISM_CHOICES, ArgumentParser, CommandLine, build_annofabapi_resource_and_login
|
|
17
17
|
from annofabcli.common.download import DownloadingFile
|
|
18
|
-
from annofabcli.common.enums import
|
|
18
|
+
from annofabcli.common.enums import OutputFormat
|
|
19
19
|
from annofabcli.common.facade import AnnofabApiFacade
|
|
20
20
|
|
|
21
21
|
logger = logging.getLogger(__name__)
|
|
@@ -155,7 +155,7 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
155
155
|
),
|
|
156
156
|
)
|
|
157
157
|
|
|
158
|
-
argument_parser.add_format(choices=[
|
|
158
|
+
argument_parser.add_format(choices=[OutputFormat.CSV, OutputFormat.JSON, OutputFormat.PRETTY_JSON], default=OutputFormat.CSV)
|
|
159
159
|
argument_parser.add_output()
|
|
160
160
|
|
|
161
161
|
parser.add_argument(
|
|
@@ -6,17 +6,15 @@ from pathlib import Path
|
|
|
6
6
|
from typing import Any
|
|
7
7
|
|
|
8
8
|
import annofabapi
|
|
9
|
-
import pandas
|
|
10
9
|
from annofabapi.dataclass.task import Task
|
|
11
10
|
|
|
12
11
|
import annofabcli.common.cli
|
|
13
12
|
from annofabcli.common.cli import ArgumentParser, CommandLine, build_annofabapi_resource_and_login
|
|
14
13
|
from annofabcli.common.download import DownloadingFile
|
|
15
|
-
from annofabcli.common.enums import
|
|
14
|
+
from annofabcli.common.enums import OutputFormat
|
|
16
15
|
from annofabcli.common.facade import AnnofabApiFacade, TaskQuery, match_task_with_query
|
|
17
|
-
from annofabcli.common.utils import get_columns_with_priority
|
|
18
16
|
from annofabcli.common.visualize import AddProps
|
|
19
|
-
from annofabcli.task.list_tasks import
|
|
17
|
+
from annofabcli.task.list_tasks import print_task_list
|
|
20
18
|
|
|
21
19
|
logger = logging.getLogger(__name__)
|
|
22
20
|
|
|
@@ -44,9 +42,10 @@ class ListTasksWithJsonMain:
|
|
|
44
42
|
self,
|
|
45
43
|
project_id: str,
|
|
46
44
|
task_json: Path | None,
|
|
45
|
+
*,
|
|
47
46
|
task_id_list: list[str] | None = None,
|
|
48
47
|
task_query: TaskQuery | None = None,
|
|
49
|
-
is_latest: bool = False,
|
|
48
|
+
is_latest: bool = False,
|
|
50
49
|
temp_dir: Path | None = None,
|
|
51
50
|
) -> list[dict[str, Any]]:
|
|
52
51
|
if task_json is None:
|
|
@@ -108,17 +107,8 @@ class ListTasksWithJson(CommandLine):
|
|
|
108
107
|
temp_dir=temp_dir,
|
|
109
108
|
)
|
|
110
109
|
|
|
111
|
-
logger.
|
|
112
|
-
|
|
113
|
-
if len(task_list) > 0:
|
|
114
|
-
if self.str_format == FormatArgument.CSV.value:
|
|
115
|
-
df = pandas.DataFrame(task_list)
|
|
116
|
-
columns = get_columns_with_priority(df, prior_columns=ListTasks.PRIOR_COLUMNS)
|
|
117
|
-
self.print_csv(df[columns])
|
|
118
|
-
else:
|
|
119
|
-
self.print_according_to_format(task_list)
|
|
120
|
-
else:
|
|
121
|
-
logger.info("タスク一覧の件数が0件のため、出力しません。")
|
|
110
|
+
logger.info(f"{len(task_list)}件のタスク情報を出力します。")
|
|
111
|
+
print_task_list(task_list, OutputFormat(args.format), args.output)
|
|
122
112
|
|
|
123
113
|
|
|
124
114
|
def main(args: argparse.Namespace) -> None:
|
|
@@ -155,8 +145,8 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
155
145
|
)
|
|
156
146
|
|
|
157
147
|
argument_parser.add_format(
|
|
158
|
-
choices=[
|
|
159
|
-
default=
|
|
148
|
+
choices=[OutputFormat.CSV, OutputFormat.JSON, OutputFormat.PRETTY_JSON, OutputFormat.TASK_ID_LIST],
|
|
149
|
+
default=OutputFormat.CSV,
|
|
160
150
|
)
|
|
161
151
|
argument_parser.add_output()
|
|
162
152
|
|
|
@@ -21,7 +21,7 @@ from annofabcli.common.cli import (
|
|
|
21
21
|
)
|
|
22
22
|
from annofabcli.common.dataclasses import WaitOptions
|
|
23
23
|
from annofabcli.common.download import DownloadingFile
|
|
24
|
-
from annofabcli.common.enums import
|
|
24
|
+
from annofabcli.common.enums import OutputFormat
|
|
25
25
|
from annofabcli.common.facade import AnnofabApiFacade, TaskQuery, match_task_with_query
|
|
26
26
|
from annofabcli.task.list_tasks_added_task_history import AddingAdditionalInfoToTask, TasksAddedTaskHistoryOutput
|
|
27
27
|
|
|
@@ -118,14 +118,14 @@ class ListAllTasksAddedTaskHistoryMain:
|
|
|
118
118
|
filtered_task_list = [e for e in task_list if self.match_task_with_conditions(e, task_query=task_query, task_id_set=task_id_set)]
|
|
119
119
|
return filtered_task_list
|
|
120
120
|
|
|
121
|
-
def get_task_list_added_task_history(
|
|
121
|
+
def get_task_list_added_task_history(
|
|
122
122
|
self,
|
|
123
123
|
task_json_path: Path | None,
|
|
124
124
|
task_history_json_path: Path | None,
|
|
125
125
|
task_id_list: list[str] | None,
|
|
126
126
|
task_query: TaskQuery | None,
|
|
127
127
|
temp_dir: Path | None,
|
|
128
|
-
):
|
|
128
|
+
) -> list[dict[str, Any]]:
|
|
129
129
|
"""
|
|
130
130
|
タスク履歴情報を加えたタスク一覧を取得する。
|
|
131
131
|
"""
|
|
@@ -178,7 +178,7 @@ class ListAllTasksAddedTaskHistory(CommandLine):
|
|
|
178
178
|
)
|
|
179
179
|
|
|
180
180
|
logger.info(f"タスク一覧の件数: {len(task_list)}")
|
|
181
|
-
TasksAddedTaskHistoryOutput(task_list).output(output_path=args.output, output_format=
|
|
181
|
+
TasksAddedTaskHistoryOutput(task_list).output(output_path=args.output, output_format=OutputFormat(args.format))
|
|
182
182
|
|
|
183
183
|
|
|
184
184
|
def main(args: argparse.Namespace) -> None:
|
|
@@ -216,8 +216,8 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
216
216
|
argument_parser.add_output()
|
|
217
217
|
|
|
218
218
|
argument_parser.add_format(
|
|
219
|
-
choices=[
|
|
220
|
-
default=
|
|
219
|
+
choices=[OutputFormat.CSV, OutputFormat.JSON, OutputFormat.PRETTY_JSON],
|
|
220
|
+
default=OutputFormat.CSV,
|
|
221
221
|
)
|
|
222
222
|
|
|
223
223
|
parser.set_defaults(subcommand_func=main)
|
annofabcli/task/list_tasks.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import argparse
|
|
2
2
|
import logging
|
|
3
|
+
from pathlib import Path
|
|
3
4
|
from typing import Any
|
|
4
5
|
|
|
5
6
|
import annofabapi
|
|
@@ -8,14 +9,77 @@ from annofabapi.models import Task
|
|
|
8
9
|
|
|
9
10
|
import annofabcli.common.cli
|
|
10
11
|
from annofabcli.common.cli import ArgumentParser, CommandLine, build_annofabapi_resource_and_login
|
|
11
|
-
from annofabcli.common.enums import
|
|
12
|
+
from annofabcli.common.enums import OutputFormat
|
|
12
13
|
from annofabcli.common.facade import AnnofabApiFacade
|
|
13
|
-
from annofabcli.common.utils import get_columns_with_priority
|
|
14
|
+
from annofabcli.common.utils import get_columns_with_priority, print_csv, print_id_list, print_json
|
|
14
15
|
from annofabcli.common.visualize import AddProps
|
|
15
16
|
|
|
16
17
|
logger = logging.getLogger(__name__)
|
|
17
18
|
|
|
18
19
|
|
|
20
|
+
def print_task_list(
|
|
21
|
+
task_list: list[dict[str, Any]],
|
|
22
|
+
output_format: OutputFormat,
|
|
23
|
+
output_file: Path | None,
|
|
24
|
+
) -> None:
|
|
25
|
+
"""
|
|
26
|
+
タスク一覧を指定されたフォーマットで出力する。
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
task_list: タスク一覧
|
|
30
|
+
output_format: 出力フォーマット
|
|
31
|
+
output_file: 出力先
|
|
32
|
+
"""
|
|
33
|
+
task_prior_columns = [
|
|
34
|
+
"project_id",
|
|
35
|
+
"task_id",
|
|
36
|
+
"phase",
|
|
37
|
+
"phase_stage",
|
|
38
|
+
"status",
|
|
39
|
+
"started_datetime",
|
|
40
|
+
"updated_datetime",
|
|
41
|
+
"operation_updated_datetime",
|
|
42
|
+
"account_id",
|
|
43
|
+
"user_id",
|
|
44
|
+
"username",
|
|
45
|
+
"worktime_hour",
|
|
46
|
+
"number_of_rejections_by_inspection",
|
|
47
|
+
"number_of_rejections_by_acceptance",
|
|
48
|
+
"sampling",
|
|
49
|
+
"input_data_count",
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
if output_format == OutputFormat.CSV:
|
|
53
|
+
if len(task_list) > 0:
|
|
54
|
+
# json_normalizeでメタデータを自動展開
|
|
55
|
+
df = pandas.json_normalize(task_list)
|
|
56
|
+
|
|
57
|
+
# metadata.*列を検出して優先列リストに追加
|
|
58
|
+
metadata_columns = sorted([col for col in df.columns if col.startswith("metadata.")])
|
|
59
|
+
prior_columns_with_metadata = task_prior_columns + metadata_columns
|
|
60
|
+
columns = get_columns_with_priority(df, prior_columns=prior_columns_with_metadata)
|
|
61
|
+
# work_time_span列を除外(worktime_hourと重複するため)
|
|
62
|
+
# histories_by_phase列を除外(list型のためCSVでは扱いにくいため)
|
|
63
|
+
# input_data_id_list列を除外(list型のためCSVでは扱いにくいため。input_data_countで件数は把握できる)
|
|
64
|
+
columns = [col for col in columns if col not in ["work_time_span", "histories_by_phase", "input_data_id_list"]]
|
|
65
|
+
print_csv(df[columns], output=output_file)
|
|
66
|
+
else:
|
|
67
|
+
df = pandas.DataFrame(columns=task_prior_columns)
|
|
68
|
+
print_csv(df, output=output_file)
|
|
69
|
+
|
|
70
|
+
elif output_format == OutputFormat.PRETTY_JSON:
|
|
71
|
+
print_json(task_list, is_pretty=True, output=output_file)
|
|
72
|
+
|
|
73
|
+
elif output_format == OutputFormat.JSON:
|
|
74
|
+
print_json(task_list, is_pretty=False, output=output_file)
|
|
75
|
+
|
|
76
|
+
elif output_format == OutputFormat.TASK_ID_LIST:
|
|
77
|
+
task_id_list = [e["task_id"] for e in task_list]
|
|
78
|
+
print_id_list(task_id_list, output=output_file)
|
|
79
|
+
else:
|
|
80
|
+
raise ValueError(f"{output_format}は対応していないフォーマットです。")
|
|
81
|
+
|
|
82
|
+
|
|
19
83
|
class ListTasksMain:
|
|
20
84
|
def __init__(self, service: annofabapi.Resource, project_id: str) -> None:
|
|
21
85
|
self.service = service
|
|
@@ -53,7 +117,7 @@ class ListTasksMain:
|
|
|
53
117
|
|
|
54
118
|
"""
|
|
55
119
|
|
|
56
|
-
def remove_key(arg_key: str)
|
|
120
|
+
def remove_key(arg_key: str) -> None:
|
|
57
121
|
if arg_key in task_query:
|
|
58
122
|
logger.info(f"タスク検索クエリから、`{arg_key}` キーを削除しました。")
|
|
59
123
|
task_query.pop(arg_key)
|
|
@@ -96,7 +160,6 @@ class ListTasksMain:
|
|
|
96
160
|
task_query = {}
|
|
97
161
|
|
|
98
162
|
if user_id_list is None:
|
|
99
|
-
logger.debug(f"task_query: {task_query}")
|
|
100
163
|
tasks = self.service.wrapper.get_all_tasks(project_id, query_params=task_query)
|
|
101
164
|
if len(tasks) == 10000:
|
|
102
165
|
logger.warning("タスク一覧は10,000件で打ち切られている可能性があります。")
|
|
@@ -151,27 +214,6 @@ class ListTasks(CommandLine):
|
|
|
151
214
|
super().__init__(service, facade, args)
|
|
152
215
|
self.visualize = AddProps(self.service, args.project_id)
|
|
153
216
|
|
|
154
|
-
PRIOR_COLUMNS = [ # noqa: RUF012
|
|
155
|
-
"project_id",
|
|
156
|
-
"task_id",
|
|
157
|
-
"phase",
|
|
158
|
-
"phase_stage",
|
|
159
|
-
"status",
|
|
160
|
-
"started_datetime",
|
|
161
|
-
"updated_datetime",
|
|
162
|
-
"operation_updated_datetime",
|
|
163
|
-
"account_id",
|
|
164
|
-
"user_id",
|
|
165
|
-
"username",
|
|
166
|
-
"worktime_hour",
|
|
167
|
-
"number_of_rejections_by_inspection",
|
|
168
|
-
"number_of_rejections_by_acceptance",
|
|
169
|
-
"metadata",
|
|
170
|
-
"sampling",
|
|
171
|
-
"input_data_count",
|
|
172
|
-
"input_data_id_list",
|
|
173
|
-
]
|
|
174
|
-
|
|
175
217
|
def main(self) -> None:
|
|
176
218
|
args = self.args
|
|
177
219
|
|
|
@@ -190,17 +232,11 @@ class ListTasks(CommandLine):
|
|
|
190
232
|
user_id_list=user_id_list,
|
|
191
233
|
)
|
|
192
234
|
|
|
193
|
-
logger.
|
|
235
|
+
logger.info(f"{len(task_list)}件のタスク情報を出力します。")
|
|
194
236
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
columns = get_columns_with_priority(df, prior_columns=self.PRIOR_COLUMNS)
|
|
199
|
-
self.print_csv(df[columns])
|
|
200
|
-
else:
|
|
201
|
-
self.print_according_to_format(task_list)
|
|
202
|
-
else:
|
|
203
|
-
logger.info("タスク一覧の件数が0件のため、出力しません。")
|
|
237
|
+
output_file = args.output
|
|
238
|
+
output_format = OutputFormat(args.format)
|
|
239
|
+
print_task_list(task_list, output_format, output_file)
|
|
204
240
|
|
|
205
241
|
|
|
206
242
|
def main(args: argparse.Namespace) -> None:
|
|
@@ -245,8 +281,8 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
245
281
|
)
|
|
246
282
|
|
|
247
283
|
argument_parser.add_format(
|
|
248
|
-
choices=[
|
|
249
|
-
default=
|
|
284
|
+
choices=[OutputFormat.CSV, OutputFormat.JSON, OutputFormat.PRETTY_JSON, OutputFormat.TASK_ID_LIST],
|
|
285
|
+
default=OutputFormat.CSV,
|
|
250
286
|
)
|
|
251
287
|
argument_parser.add_output()
|
|
252
288
|
|
|
@@ -14,7 +14,7 @@ from annofabapi.utils import get_task_history_index_skipped_acceptance, get_task
|
|
|
14
14
|
|
|
15
15
|
import annofabcli.common.cli
|
|
16
16
|
from annofabcli.common.cli import ArgumentParser, CommandLine, build_annofabapi_resource_and_login
|
|
17
|
-
from annofabcli.common.enums import
|
|
17
|
+
from annofabcli.common.enums import OutputFormat
|
|
18
18
|
from annofabcli.common.facade import AnnofabApiFacade
|
|
19
19
|
from annofabcli.common.utils import isoduration_to_hour, print_csv, print_json
|
|
20
20
|
from annofabcli.common.visualize import AddProps
|
|
@@ -384,7 +384,7 @@ class ListTasksAddedTaskHistoryMain:
|
|
|
384
384
|
|
|
385
385
|
for index, task in enumerate(task_list):
|
|
386
386
|
if (index + 1) % 100 == 0:
|
|
387
|
-
logger.
|
|
387
|
+
logger.info(f"{index + 1} 件目のタスク履歴情報を取得します。")
|
|
388
388
|
|
|
389
389
|
obj.add_additional_info_to_task(task)
|
|
390
390
|
task_id = task["task_id"]
|
|
@@ -422,7 +422,6 @@ class TasksAddedTaskHistoryOutput:
|
|
|
422
422
|
"user_id",
|
|
423
423
|
"username",
|
|
424
424
|
"input_data_count",
|
|
425
|
-
"metadata",
|
|
426
425
|
"sampling",
|
|
427
426
|
# 作業時間情報
|
|
428
427
|
"worktime_hour",
|
|
@@ -454,20 +453,30 @@ class TasksAddedTaskHistoryOutput:
|
|
|
454
453
|
]
|
|
455
454
|
)
|
|
456
455
|
|
|
457
|
-
def output(self, output_path: Path, output_format:
|
|
456
|
+
def output(self, output_path: Path, output_format: OutputFormat) -> None:
|
|
458
457
|
task_list = self.task_list
|
|
459
458
|
logger.debug(f"タスク {len(task_list)} 件の情報を出力します。")
|
|
460
|
-
if output_format ==
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
459
|
+
if output_format == OutputFormat.CSV:
|
|
460
|
+
if len(task_list) > 0:
|
|
461
|
+
# json_normalizeでメタデータを自動展開
|
|
462
|
+
df = pandas.json_normalize(task_list)
|
|
463
|
+
|
|
464
|
+
# metadata.*列を検出して出力対象列リストに追加
|
|
465
|
+
metadata_columns = sorted([col for col in df.columns if col.startswith("metadata.")])
|
|
466
|
+
output_columns = self._get_output_target_columns() + metadata_columns
|
|
467
|
+
# 出力列を output_columns に含まれる列のみに限定(意図しない列の混入を防ぐ)
|
|
468
|
+
columns = [col for col in output_columns if col in df.columns]
|
|
469
|
+
print_csv(df[columns], output=output_path)
|
|
470
|
+
else:
|
|
471
|
+
df = pandas.DataFrame(columns=self._get_output_target_columns())
|
|
472
|
+
print_csv(df, output=output_path)
|
|
473
|
+
|
|
474
|
+
elif output_format == OutputFormat.JSON:
|
|
468
475
|
print_json(task_list, is_pretty=False, output=output_path)
|
|
469
|
-
elif output_format ==
|
|
476
|
+
elif output_format == OutputFormat.PRETTY_JSON:
|
|
470
477
|
print_json(task_list, is_pretty=True, output=output_path)
|
|
478
|
+
else:
|
|
479
|
+
raise ValueError(f"{output_format=}は不正な値です。")
|
|
471
480
|
|
|
472
481
|
|
|
473
482
|
class ListTasksAddedTaskHistory(CommandLine):
|
|
@@ -481,7 +490,7 @@ class ListTasksAddedTaskHistory(CommandLine):
|
|
|
481
490
|
task_list = main_obj.main(task_query=task_query, task_id_list=task_id_list)
|
|
482
491
|
|
|
483
492
|
output_obj = TasksAddedTaskHistoryOutput(task_list)
|
|
484
|
-
output_obj.output(args.output, output_format=
|
|
493
|
+
output_obj.output(args.output, output_format=OutputFormat(args.format))
|
|
485
494
|
|
|
486
495
|
|
|
487
496
|
def main(args: argparse.Namespace) -> None:
|
|
@@ -519,8 +528,8 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
519
528
|
argument_parser.add_output()
|
|
520
529
|
|
|
521
530
|
argument_parser.add_format(
|
|
522
|
-
choices=[
|
|
523
|
-
default=
|
|
531
|
+
choices=[OutputFormat.CSV, OutputFormat.JSON, OutputFormat.PRETTY_JSON],
|
|
532
|
+
default=OutputFormat.CSV,
|
|
524
533
|
)
|
|
525
534
|
|
|
526
535
|
parser.set_defaults(subcommand_func=main)
|
|
@@ -10,7 +10,7 @@ from annofabapi.models import TaskHistory
|
|
|
10
10
|
import annofabcli.common.cli
|
|
11
11
|
from annofabcli.common.cli import ArgumentParser, CommandLine, build_annofabapi_resource_and_login
|
|
12
12
|
from annofabcli.common.download import DownloadingFile
|
|
13
|
-
from annofabcli.common.enums import
|
|
13
|
+
from annofabcli.common.enums import OutputFormat
|
|
14
14
|
from annofabcli.common.facade import AnnofabApiFacade
|
|
15
15
|
from annofabcli.common.visualize import AddProps
|
|
16
16
|
|
|
@@ -92,7 +92,7 @@ class ListTaskHistoryWithJson(CommandLine):
|
|
|
92
92
|
project_id: str,
|
|
93
93
|
task_history_json: Path | None,
|
|
94
94
|
task_id_list: list[str] | None,
|
|
95
|
-
arg_format:
|
|
95
|
+
arg_format: OutputFormat,
|
|
96
96
|
temp_dir: Path | None,
|
|
97
97
|
):
|
|
98
98
|
"""
|
|
@@ -111,7 +111,7 @@ class ListTaskHistoryWithJson(CommandLine):
|
|
|
111
111
|
main_obj = ListTaskHistoryWithJsonMain(self.service)
|
|
112
112
|
task_history_dict = main_obj.get_task_history_dict(project_id, task_history_json=task_history_json, task_id_list=task_id_list, temp_dir=temp_dir)
|
|
113
113
|
logger.debug(f"{len(task_history_dict)} 件のタスクの履歴情報を出力します。")
|
|
114
|
-
if arg_format ==
|
|
114
|
+
if arg_format == OutputFormat.CSV:
|
|
115
115
|
all_task_history_list = main_obj.to_all_task_history_list_from_dict(task_history_dict)
|
|
116
116
|
self.print_according_to_format(all_task_history_list)
|
|
117
117
|
else:
|
|
@@ -127,7 +127,7 @@ class ListTaskHistoryWithJson(CommandLine):
|
|
|
127
127
|
args.project_id,
|
|
128
128
|
task_history_json=args.task_history_json,
|
|
129
129
|
task_id_list=task_id_list,
|
|
130
|
-
arg_format=
|
|
130
|
+
arg_format=OutputFormat(args.format),
|
|
131
131
|
temp_dir=temp_dir,
|
|
132
132
|
)
|
|
133
133
|
|
|
@@ -164,8 +164,8 @@ def parse_args(parser: argparse.ArgumentParser) -> None:
|
|
|
164
164
|
)
|
|
165
165
|
|
|
166
166
|
argument_parser.add_format(
|
|
167
|
-
choices=[
|
|
168
|
-
default=
|
|
167
|
+
choices=[OutputFormat.CSV, OutputFormat.JSON, OutputFormat.PRETTY_JSON],
|
|
168
|
+
default=OutputFormat.CSV,
|
|
169
169
|
)
|
|
170
170
|
argument_parser.add_output()
|
|
171
171
|
|