cmdbox 0.6.4.2__py3-none-any.whl → 0.6.6__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.
Potentially problematic release.
This version of cmdbox might be problematic. Click here for more details.
- cmdbox/app/app.py +7 -0
- cmdbox/app/client.py +384 -383
- cmdbox/app/common.py +85 -7
- cmdbox/app/commons/convert.py +3 -1
- cmdbox/app/edge.py +12 -12
- cmdbox/app/feature.py +1 -1
- cmdbox/app/features/cli/{cmdbox_vision_install.py → _cmdbox_vision_install.py} +2 -10
- cmdbox/app/features/cli/_cmdbox_vision_predict.py +487 -0
- cmdbox/app/features/cli/{cmdbox_vision_start.py → _cmdbox_vision_start.py} +5 -1
- cmdbox/app/features/cli/cmdbox_audit_createdb.py +1 -11
- cmdbox/app/features/cli/cmdbox_audit_delete.py +0 -9
- cmdbox/app/features/cli/cmdbox_audit_search.py +0 -9
- cmdbox/app/features/cli/cmdbox_audit_write.py +0 -9
- cmdbox/app/features/cli/cmdbox_cmd_list.py +3 -3
- cmdbox/app/features/cli/cmdbox_cmd_load.py +3 -3
- cmdbox/app/features/cli/cmdbox_excel_cell_details.py +436 -0
- cmdbox/app/features/cli/cmdbox_excel_cell_search.py +276 -0
- cmdbox/app/features/cli/cmdbox_excel_cell_values.py +258 -0
- cmdbox/app/features/cli/cmdbox_excel_sheet_list.py +159 -0
- cmdbox/app/features/cli/cmdbox_tts_install.py +4 -11
- cmdbox/app/features/cli/cmdbox_tts_say.py +2 -10
- cmdbox/app/features/cli/cmdbox_tts_start.py +0 -9
- cmdbox/app/features/cli/cmdbox_tts_stop.py +0 -9
- cmdbox/app/features/cli/cmdbox_web_apikey_add.py +3 -3
- cmdbox/app/features/cli/cmdbox_web_apikey_del.py +3 -3
- cmdbox/app/features/cli/cmdbox_web_group_add.py +3 -3
- cmdbox/app/features/cli/cmdbox_web_group_del.py +3 -3
- cmdbox/app/features/cli/cmdbox_web_group_edit.py +3 -3
- cmdbox/app/features/cli/cmdbox_web_group_list.py +3 -3
- cmdbox/app/features/cli/cmdbox_web_start.py +10 -10
- cmdbox/app/features/cli/cmdbox_web_user_add.py +3 -3
- cmdbox/app/features/cli/cmdbox_web_user_del.py +3 -3
- cmdbox/app/features/cli/cmdbox_web_user_edit.py +3 -3
- cmdbox/app/features/cli/cmdbox_web_user_list.py +3 -3
- cmdbox/app/features/cli/excel_base.py +301 -0
- cmdbox/app/features/web/cmdbox_web_exec_cmd.py +12 -14
- cmdbox/app/filer.py +5 -2
- cmdbox/app/mcp.py +4 -3
- cmdbox/app/options.py +8 -0
- cmdbox/app/web.py +58 -39
- cmdbox/extensions/features.yml +3 -0
- cmdbox/extensions/sample_project/sample/app/features/cli/sample_server_time.py +0 -9
- cmdbox/licenses/LICENSE_Mako_1_3_10_MIT_License.txt +19 -0
- cmdbox/licenses/LICENSE_alembic_1_16_5_UNKNOWN.txt +19 -0
- cmdbox/licenses/{LICENSE_cffi_1_17_1_MIT_License.txt → LICENSE_cffi_2_0_0_UNKNOWN.txt} +2 -5
- cmdbox/licenses/LICENSE_debugpy_1_8_17_MIT_License.txt +24 -0
- cmdbox/licenses/LICENSE_et_xmlfile_2_0_0_MIT_License.txt +298 -0
- cmdbox/licenses/LICENSE_fastuuid_0_13_5_BSD_License.txt +29 -0
- cmdbox/licenses/LICENSE_google-cloud-monitoring_2_27_2_Apache_Software_License.txt +202 -0
- cmdbox/licenses/LICENSE_google-cloud-spanner_3_58_0_Apache_Software_License.txt +202 -0
- cmdbox/licenses/LICENSE_google-genai_1_40_0_Apache_Software_License.txt +202 -0
- cmdbox/licenses/LICENSE_grpc-interceptor_0_15_4_MIT_License.txt +21 -0
- cmdbox/licenses/{LICENSE_lazy-object-proxy_1_11_0_BSD_License.txt → LICENSE_lazy-object-proxy_1_12_0_UNKNOWN.txt} +1 -1
- cmdbox/licenses/LICENSE_openpyxl_3_1_5_MIT_License.txt +23 -0
- cmdbox/licenses/LICENSE_opentelemetry-exporter-otlp-proto-common_1_37_0_UNKNOWN.txt +201 -0
- cmdbox/licenses/LICENSE_opentelemetry-exporter-otlp-proto-http_1_37_0_UNKNOWN.txt +201 -0
- cmdbox/licenses/LICENSE_opentelemetry-proto_1_37_0_UNKNOWN.txt +201 -0
- cmdbox/licenses/LICENSE_opentelemetry-sdk_1_37_0_UNKNOWN.txt +201 -0
- cmdbox/licenses/LICENSE_opentelemetry-semantic-conventions_0_58b0_UNKNOWN.txt +201 -0
- cmdbox/licenses/LICENSE_sqlalchemy-spanner_1_16_0_Apache_Software_License.txt +202 -0
- cmdbox/licenses/LICENSE_sqlparse_0_5_3_BSD_License.txt +25 -0
- cmdbox/licenses/{LICENSE_uvicorn_0_35_0_BSD_License.txt → LICENSE_uvicorn_0_37_0_BSD_License.txt} +2 -1
- cmdbox/licenses/files.txt +82 -71
- cmdbox/version.py +2 -2
- cmdbox/web/assets/cmdbox/svgicon.js +9 -0
- {cmdbox-0.6.4.2.dist-info → cmdbox-0.6.6.dist-info}/METADATA +29 -29
- {cmdbox-0.6.4.2.dist-info → cmdbox-0.6.6.dist-info}/RECORD +133 -117
- cmdbox/app/features/cli/cmdbox_vision_predict.py +0 -192
- cmdbox/licenses/LICENSE_APScheduler_3_11_0_MIT_License.txt +0 -19
- cmdbox/licenses/LICENSE_backoff_2_2_1_MIT_License.txt +0 -21
- cmdbox/licenses/LICENSE_fastapi-sso_0_18_0_MIT_License.txt +0 -21
- cmdbox/licenses/LICENSE_litellm-enterprise_0_1_19_UNKNOWN.txt +0 -37
- cmdbox/licenses/LICENSE_oauthlib_3_3_1_BSD-3-Clause.txt +0 -27
- cmdbox/licenses/LICENSE_orjson_3_11_1_Apache_Software_License-MIT_License.txt +0 -201
- /cmdbox/licenses/{LICENSE_Authlib_1_6_1_BSD_License.txt → LICENSE_Authlib_1_6_5_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_MarkupSafe_3_0_2_BSD_License.txt → LICENSE_MarkupSafe_3_0_3_UNKNOWN.txt} +0 -0
- /cmdbox/licenses/{LICENSE_PyYAML_6_0_2_MIT_License.txt → LICENSE_PyYAML_6_0_3_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_anyio_4_10_0_UNKNOWN.txt → LICENSE_anyio_4_11_0_UNKNOWN.txt} +0 -0
- /cmdbox/licenses/{LICENSE_cachetools_5_5_2_MIT_License.txt → LICENSE_cachetools_6_2_0_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_click_8_2_1_UNKNOWN.txt → LICENSE_click_8_3_0_UNKNOWN.txt} +0 -0
- /cmdbox/licenses/{LICENSE_cryptography_45_0_6_Apache-2_0_OR_BSD-3-Clause.txt → LICENSE_cryptography_46_0_2_UNKNOWN.txt} +0 -0
- /cmdbox/licenses/{LICENSE_cyclopts_3_22_5_Apache_Software_License.txt → LICENSE_cyclopts_3_24_0_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_dnspython_2_7_0_ISC_License-ISCL.txt → LICENSE_dnspython_2_8_0_ISC_License-ISCL.txt} +0 -0
- /cmdbox/licenses/{LICENSE_email_validator_2_2_0_The_Unlicense-Unlicense.txt → LICENSE_email-validator_2_3_0_The_Unlicense-Unlicense.txt} +0 -0
- /cmdbox/licenses/{LICENSE_fastapi_0_116_1_MIT_License.txt → LICENSE_fastapi_0_118_0_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_fastmcp_2_11_3_Apache_Software_License.txt → LICENSE_fastmcp_2_12_4_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_filelock_3_18_0_The_Unlicense-Unlicense.txt → LICENSE_filelock_3_19_1_The_Unlicense-Unlicense.txt} +0 -0
- /cmdbox/licenses/{LICENSE_fsspec_2025_7_0_BSD_License.txt → LICENSE_fsspec_2025_9_0_UNKNOWN.txt} +0 -0
- /cmdbox/licenses/{LICENSE_gevent_25_5_1_MIT.txt → LICENSE_gevent_25_9_1_MIT.txt} +0 -0
- /cmdbox/licenses/{LICENSE_google-adk_1_10_0_Apache_Software_License.txt → LICENSE_google-adk_1_15_1_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_google-api-core_2_25_1_Apache_Software_License.txt → LICENSE_google-api-core_2_25_2_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_google-api-python-client_2_178_0_Apache_Software_License.txt → LICENSE_google-api-python-client_2_184_0_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_google-auth_2_40_3_Apache_Software_License.txt → LICENSE_google-auth_2_41_1_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_google-cloud-aiplatform_1_108_0_Apache_2_0.txt → LICENSE_google-cloud-aiplatform_1_119_0_Apache_2_0.txt} +0 -0
- /cmdbox/licenses/{LICENSE_google-cloud-bigquery_3_35_1_Apache_Software_License.txt → LICENSE_google-cloud-bigquery_3_38_0_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_google-genai_1_29_0_Apache_Software_License.txt → LICENSE_google-cloud-bigtable_2_32_0_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_grpcio-status_1_74_0_Apache_Software_License.txt → LICENSE_grpcio-status_1_75_1_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_grpcio_1_74_0_Apache_Software_License.txt → LICENSE_grpcio_1_75_1_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_httplib2_0_22_0_MIT_License.txt → LICENSE_httplib2_0_31_0_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_huggingface-hub_0_34_4_Apache_Software_License.txt → LICENSE_huggingface-hub_0_35_3_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_jaraco_functools_4_2_1_UNKNOWN.txt → LICENSE_jaraco_functools_4_3_0_UNKNOWN.txt} +0 -0
- /cmdbox/licenses/{LICENSE_jiter_0_10_0_MIT_License.txt → LICENSE_jiter_0_11_0_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_jsonschema-specifications_2025_4_1_UNKNOWN.txt → LICENSE_jsonschema-specifications_2025_9_1_UNKNOWN.txt} +0 -0
- /cmdbox/licenses/{LICENSE_jsonschema_4_25_0_UNKNOWN.txt → LICENSE_jsonschema_4_25_1_UNKNOWN.txt} +0 -0
- /cmdbox/licenses/{LICENSE_litellm_1_75_5_post1_MIT_License.txt → LICENSE_litellm_1_77_5_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_mcp_1_12_4_MIT_License.txt → LICENSE_mcp_1_16_0_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_more-itertools_10_7_0_MIT_License.txt → LICENSE_more-itertools_10_8_0_UNKNOWN.txt} +0 -0
- /cmdbox/licenses/{LICENSE_numpy_2_3_2_BSD_License.txt → LICENSE_numpy_2_3_3_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_openai_1_99_9_Apache_Software_License.txt → LICENSE_openai_2_1_0_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_opentelemetry-api_1_36_0_UNKNOWN.txt → LICENSE_opentelemetry-api_1_37_0_UNKNOWN.txt} +0 -0
- /cmdbox/licenses/{LICENSE_opentelemetry-sdk_1_36_0_UNKNOWN.txt → LICENSE_opentelemetry-exporter-gcp-logging_1_9_0a0_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_opentelemetry-semantic-conventions_0_57b0_UNKNOWN.txt → LICENSE_opentelemetry-exporter-gcp-monitoring_1_9_0a0_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_prompt_toolkit_3_0_51_BSD_License.txt → LICENSE_prompt_toolkit_3_0_52_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_protobuf_6_31_1_3-Clause_BSD_License.txt → LICENSE_protobuf_6_32_1_3-Clause_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_psycopg-binary_3_2_9_GNU_Lesser_General_Public_License_v3-LGPLv3.txt → LICENSE_psycopg-binary_3_2_10_GNU_Lesser_General_Public_License_v3-LGPLv3.txt} +0 -0
- /cmdbox/licenses/{LICENSE_psycopg_3_2_9_GNU_Lesser_General_Public_License_v3-LGPLv3.txt → LICENSE_psycopg_3_2_10_GNU_Lesser_General_Public_License_v3-LGPLv3.txt} +0 -0
- /cmdbox/licenses/{LICENSE_pycparser_2_22_BSD_License.txt → LICENSE_pycparser_2_23_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_pydantic-settings_2_10_1_MIT_License.txt → LICENSE_pydantic-settings_2_11_0_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_pydantic_2_11_7_MIT_License.txt → LICENSE_pydantic_2_11_10_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_pyparsing_3_2_3_MIT_License.txt → LICENSE_pyparsing_3_2_5_UNKNOWN.txt} +0 -0
- /cmdbox/licenses/{LICENSE_pyperclip_1_9_0_BSD_License.txt → LICENSE_pyperclip_1_11_0_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_questionary_2_1_0_MIT_License.txt → LICENSE_questionary_2_1_1_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_regex_2025_7_34_UNKNOWN.txt → LICENSE_regex_2025_9_18_UNKNOWN.txt} +0 -0
- /cmdbox/licenses/{LICENSE_requests_2_32_4_Apache_Software_License.txt → LICENSE_requests_2_32_5_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_rpds-py_0_27_0_UNKNOWN.txt → LICENSE_rpds-py_0_27_1_UNKNOWN.txt} +0 -0
- /cmdbox/licenses/{LICENSE_shapely_2_1_1_BSD_License.txt → LICENSE_shapely_2_1_2_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_sphinx-sitemap_2_7_2_UNKNOWN.txt → LICENSE_sphinx-sitemap_2_8_0_UNKNOWN.txt} +0 -0
- /cmdbox/licenses/{LICENSE_starlette_0_47_2_BSD_License.txt → LICENSE_starlette_0_48_0_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_tenacity_9_1_2_Apache_Software_License.txt → LICENSE_tenacity_8_5_0_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_tokenizers_0_21_4_Apache_Software_License.txt → LICENSE_tokenizers_0_22_1_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_twine_6_1_0_Apache_Software_License.txt → LICENSE_twine_6_2_0_UNKNOWN.txt} +0 -0
- /cmdbox/licenses/{LICENSE_typing-inspection_0_4_1_UNKNOWN.txt → LICENSE_typing-inspection_0_4_2_UNKNOWN.txt} +0 -0
- /cmdbox/licenses/{LICENSE_typing_extensions_4_14_1_UNKNOWN.txt → LICENSE_typing_extensions_4_15_0_UNKNOWN.txt} +0 -0
- /cmdbox/licenses/{LICENSE_wcwidth_0_2_13_MIT_License.txt → LICENSE_wcwidth_0_2_14_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_zope_event_5_1_1_Zope_Public_License.txt → LICENSE_zope_event_6_0_Zope_Public_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_zope_interface_7_2_Zope_Public_License.txt → LICENSE_zope_interface_8_0_1_Zope_Public_License.txt} +0 -0
- {cmdbox-0.6.4.2.dist-info → cmdbox-0.6.6.dist-info}/WHEEL +0 -0
- {cmdbox-0.6.4.2.dist-info → cmdbox-0.6.6.dist-info}/entry_points.txt +0 -0
- {cmdbox-0.6.4.2.dist-info → cmdbox-0.6.6.dist-info}/licenses/LICENSE +0 -0
- {cmdbox-0.6.4.2.dist-info → cmdbox-0.6.6.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
from cmdbox.app import common, filer
|
|
2
|
+
from cmdbox.app.commons import convert, redis_client
|
|
3
|
+
from cmdbox.app.features.cli import excel_base
|
|
4
|
+
from cmdbox.app.options import Options
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Dict, Any, List, Tuple
|
|
7
|
+
import argparse
|
|
8
|
+
import logging
|
|
9
|
+
import json
|
|
10
|
+
import re
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class ExcelCellSearch(excel_base.ExcelBase):
|
|
14
|
+
def get_cmd(self):
|
|
15
|
+
"""
|
|
16
|
+
この機能のコマンドを返します
|
|
17
|
+
|
|
18
|
+
Returns:
|
|
19
|
+
str: コマンド
|
|
20
|
+
"""
|
|
21
|
+
return 'cell_search'
|
|
22
|
+
|
|
23
|
+
def get_option(self):
|
|
24
|
+
"""
|
|
25
|
+
この機能のオプションを返します
|
|
26
|
+
|
|
27
|
+
Returns:
|
|
28
|
+
Dict[str, Any]: オプション
|
|
29
|
+
"""
|
|
30
|
+
opt = super().get_option()
|
|
31
|
+
opt['description_ja'] = "データフォルダ配下のExcelファイルの指定したセルの値を検索します。"
|
|
32
|
+
opt['description_en'] = "Searches for the value in the specified cell of an Excel file located in the data folder."
|
|
33
|
+
opt['choice'] += [
|
|
34
|
+
dict(opt="formula_data_only", type=Options.T_BOOL, default=False, required=True, multi=False, hide=False, choice=[True, False],
|
|
35
|
+
description_ja="数式データのみを参照するかどうかを指定します。このオプションはキャッシュされたデータが存在する場合に有効です。",
|
|
36
|
+
description_en="Specify whether to get only formula data. This option is valid if cached data exists."),
|
|
37
|
+
dict(opt="sheet_name", type=Options.T_STR, default=None, required=False, multi=False, hide=False, choice=None,
|
|
38
|
+
description_ja="セルの値を取得するシートの名前を指定します。省略した場合、すべてのシートが使用されます。",
|
|
39
|
+
description_en="Specify the sheet name to get the cell value.If omitted, all sheets will be used."),
|
|
40
|
+
dict(opt="cell_name", type=Options.T_STR, default=None, required=False, multi=True, hide=False, choice=None,
|
|
41
|
+
description_ja="セルの値を検索するセルの名前を指定します。例えば、`A1`、`B2`、`R5987`。",
|
|
42
|
+
description_en="Specify the cell name to search for the cell value. For example, `A1`, `B2`, `R5987`."),
|
|
43
|
+
dict(opt="cell_top_left", type=Options.T_STR, default=None, required=False, multi=False, hide=False, choice=None,
|
|
44
|
+
description_ja="セルの値を検索する左上セルの名前を指定します。例えば、`A1`、`B2`、`R5987`。",
|
|
45
|
+
description_en="Specify the top-left cell name to search for the cell value. For example, `A1`, `B2`, `R5987`."),
|
|
46
|
+
dict(opt="cell_bottom_right", type=Options.T_STR, default=None, required=False, multi=False, hide=False, choice=None,
|
|
47
|
+
description_ja="セルの値を検索する右下セルの名前を指定します。例えば、`A1`、`B2`、`R5987`。",
|
|
48
|
+
description_en="Specify the bottom-right cell name to search for the cell value. For example, `A1`, `B2`, `R5987`."),
|
|
49
|
+
dict(opt="match_type", type=Options.T_STR, default="partial", required=True, multi=False, hide=False, choice=['full', 'partial', 'regex'],
|
|
50
|
+
description_ja="検索するセルの値に対するマッチ方法を指定します。`full`: 完全一致、`partial`: 部分一致、`regex`: 正規表現。",
|
|
51
|
+
description_en="Specifies the matching method for the value in the search cell. `full`: Exact match, `partial`: Partial match, `regex`: Regular expression."),
|
|
52
|
+
dict(opt="search_value", type=Options.T_STR, default=None, required=True, multi=False, hide=False, choice=None,
|
|
53
|
+
description_ja="検索するセルの値を指定します。指定方法は `match_type` によって異なります。",
|
|
54
|
+
description_en="Specify the value to search for in the cell. The method of specification depends on `match_type`."),
|
|
55
|
+
dict(opt="output_cell_format", type=Options.T_STR, default='json', required=False, multi=False, hide=False, choice=['json', 'csv', 'md', 'html'],
|
|
56
|
+
description_ja="出力フォーマットを指定します。例えば、`json`、`csv`、 `md`、 `html`。",
|
|
57
|
+
description_en="Specify the output format. For example, `json`, `csv`、 `md`、 `html`."),
|
|
58
|
+
]
|
|
59
|
+
return opt
|
|
60
|
+
|
|
61
|
+
def chk_args(self, args:argparse.Namespace, tm:float, pf:List[Dict[str, float]]=[]) -> Tuple[bool, str, Any]:
|
|
62
|
+
"""
|
|
63
|
+
引数のチェックを行います
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
args (argparse.Namespace): 引数
|
|
67
|
+
|
|
68
|
+
Returns:
|
|
69
|
+
Tuple[bool, str]: チェック結果, メッセージ
|
|
70
|
+
"""
|
|
71
|
+
if args.svname is None:
|
|
72
|
+
msg = dict(warn=f"Please specify the --svname option.")
|
|
73
|
+
common.print_format(msg, args.format, tm, args.output_json, args.output_json_append, pf=pf)
|
|
74
|
+
return self.RESP_WARN, msg, None
|
|
75
|
+
if args.scope is None:
|
|
76
|
+
msg = dict(warn=f"Please specify the --scope option.")
|
|
77
|
+
common.print_format(msg, args.format, tm, args.output_json, args.output_json_append, pf=pf)
|
|
78
|
+
return self.RESP_WARN, msg, None
|
|
79
|
+
if args.svpath is None:
|
|
80
|
+
msg = dict(warn=f"Please specify the --svpath option.")
|
|
81
|
+
common.print_format(msg, args.format, tm, args.output_json, args.output_json_append, pf=pf)
|
|
82
|
+
return self.RESP_WARN, msg, None
|
|
83
|
+
if args.match_type is None:
|
|
84
|
+
msg = dict(warn=f"Please specify the --match_type option.")
|
|
85
|
+
common.print_format(msg, args.format, tm, args.output_json, args.output_json_append, pf=pf)
|
|
86
|
+
return self.RESP_WARN, msg, None
|
|
87
|
+
if args.search_value is None:
|
|
88
|
+
msg = dict(warn=f"Please specify the --search_value option.")
|
|
89
|
+
common.print_format(msg, args.format, tm, args.output_json, args.output_json_append, pf=pf)
|
|
90
|
+
return self.RESP_WARN, msg, None
|
|
91
|
+
return self.RESP_SUCCESS, None, None
|
|
92
|
+
|
|
93
|
+
def excel_proc(self, abspath:Path, args:argparse.Namespace, logger:logging.Logger, tm:float, pf:List[Dict[str, float]]=[]) -> Dict[str, Any]:
|
|
94
|
+
"""
|
|
95
|
+
Excel処理のベース
|
|
96
|
+
|
|
97
|
+
Args:
|
|
98
|
+
abspath (Path): Excelファイルの絶対パス
|
|
99
|
+
args (argparse.Namespace): 引数
|
|
100
|
+
logger (logging.Logger): ロガー
|
|
101
|
+
tm (float): 処理時間
|
|
102
|
+
pf (List[Dict[str, float]]): パフォーマンス情報
|
|
103
|
+
|
|
104
|
+
Returns:
|
|
105
|
+
Dict[str, Any]: 結果
|
|
106
|
+
"""
|
|
107
|
+
res_json = self.cell_search(abspath, args.formula_data_only, args.sheet_name,
|
|
108
|
+
args.cell_name, args.cell_top_left, args.cell_bottom_right,
|
|
109
|
+
args.match_type, args.search_value, args.output_cell_format, logger)
|
|
110
|
+
return res_json
|
|
111
|
+
|
|
112
|
+
def get_svparam(self, args:argparse.Namespace) -> List[str]:
|
|
113
|
+
"""
|
|
114
|
+
サーバーに送信するパラメーターを返します
|
|
115
|
+
|
|
116
|
+
Args:
|
|
117
|
+
args (argparse.Namespace): 引数
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
List[str]: サーバーに送信するパラメーター
|
|
121
|
+
"""
|
|
122
|
+
cell_name = json.dumps(args.cell_name, default=common.default_json_enc) if args.cell_name is not None else '[]'
|
|
123
|
+
ret = [convert.str2b64str(str(args.svpath)), str(args.formula_data_only), convert.str2b64str(str(args.sheet_name)),
|
|
124
|
+
convert.str2b64str(cell_name), convert.str2b64str(args.cell_top_left), convert.str2b64str(args.cell_bottom_right),
|
|
125
|
+
convert.str2b64str(args.match_type), convert.str2b64str(args.search_value), convert.str2b64str(args.output_cell_format)]
|
|
126
|
+
return ret
|
|
127
|
+
|
|
128
|
+
def is_cluster_redirect(self):
|
|
129
|
+
"""
|
|
130
|
+
クラスター宛のメッセージの場合、メッセージを転送するかどうかを返します
|
|
131
|
+
|
|
132
|
+
Returns:
|
|
133
|
+
bool: メッセージを転送する場合はTrue
|
|
134
|
+
"""
|
|
135
|
+
return False
|
|
136
|
+
|
|
137
|
+
def svrun(self, data_dir:Path, logger:logging.Logger, redis_cli:redis_client.RedisClient, msg:List[str],
|
|
138
|
+
sessions:Dict[str, Dict[str, Any]]) -> int:
|
|
139
|
+
"""
|
|
140
|
+
この機能のサーバー側の実行を行います
|
|
141
|
+
|
|
142
|
+
Args:
|
|
143
|
+
data_dir (Path): データディレクトリ
|
|
144
|
+
logger (logging.Logger): ロガー
|
|
145
|
+
redis_cli (redis_client.RedisClient): Redisクライアント
|
|
146
|
+
msg (List[str]): 受信メッセージ
|
|
147
|
+
sessions (Dict[str, Dict[str, Any]]): セッション情報
|
|
148
|
+
|
|
149
|
+
Returns:
|
|
150
|
+
int: 終了コード
|
|
151
|
+
"""
|
|
152
|
+
svpath = convert.b64str2str(msg[2])
|
|
153
|
+
formula_data_only = msg[3]=='True'
|
|
154
|
+
sheet_name = convert.b64str2str(msg[4])
|
|
155
|
+
sheet_name = None if sheet_name=='None' else sheet_name
|
|
156
|
+
cell_name = json.loads(convert.b64str2str(msg[5]))
|
|
157
|
+
cell_top_left = convert.b64str2str(msg[6])
|
|
158
|
+
cell_bottom_right = convert.b64str2str(msg[7])
|
|
159
|
+
match_type = convert.b64str2str(msg[8])
|
|
160
|
+
search_value = convert.b64str2str(msg[9])
|
|
161
|
+
output_cell_format = convert.b64str2str(msg[10])
|
|
162
|
+
|
|
163
|
+
try:
|
|
164
|
+
f = filer.Filer(data_dir, logger)
|
|
165
|
+
chk, abspath, res = f._file_exists(svpath)
|
|
166
|
+
if not chk:
|
|
167
|
+
logger.warning(f"File not found. {svpath}")
|
|
168
|
+
redis_cli.rpush(msg[1], res)
|
|
169
|
+
return self.RESP_WARN
|
|
170
|
+
res = self.cell_search(abspath, formula_data_only, sheet_name, cell_name, cell_top_left, cell_bottom_right,
|
|
171
|
+
match_type, search_value, output_cell_format, logger)
|
|
172
|
+
redis_cli.rpush(msg[1], res)
|
|
173
|
+
except Exception as e:
|
|
174
|
+
logger.warning(f"Failed to cell search: {e}", exc_info=True)
|
|
175
|
+
redis_cli.rpush(msg[1], dict(warn=f"Failed to cell search: {e}"))
|
|
176
|
+
return self.RESP_WARN
|
|
177
|
+
return self.RESP_SUCCESS
|
|
178
|
+
|
|
179
|
+
def cell_search(self, filepath:str, formula_data_only:bool, sheet_name:str, cell_name:List[str], cell_top_left:str, cell_bottom_right:str,
|
|
180
|
+
match_type:str, search_value:str, output_cell_format:str, logger:logging.Logger) -> Dict[str, Any]:
|
|
181
|
+
"""
|
|
182
|
+
指定したワークブックのセルの値を検索します。
|
|
183
|
+
|
|
184
|
+
Args:
|
|
185
|
+
filepath (str): ワークブックのパス
|
|
186
|
+
formula_data_only (bool): 数式データのみを参照するかどうか。このオプションはキャッシュされたデータが存在する場合に有効です。
|
|
187
|
+
sheet_name (str): 詳細情報を取得するシートの名前
|
|
188
|
+
cell_name (List[str]): 詳細情報を取得するセルの名前のリスト。例えば、`A1`、`B2`、`R5987`。
|
|
189
|
+
cell_top_left (str): 詳細情報を取得する左上セルの名前。例えば、`A1`、`B2`、`R5987`。
|
|
190
|
+
cell_bottom_right (str): 詳細情報を取得する右下セルの名前。 例えば、`A1`、`B2`、`R5987`。
|
|
191
|
+
match_type (str): 検索するセルの値に対するマッチ方法。`full`: 完全一致、`partial`: 部分一致、`regex`: 正規表現。
|
|
192
|
+
search_value (str): 検索するセルの値。
|
|
193
|
+
output_cell_format (str): 出力フォーマット。例えば、`json`、`csv`、 `md`、 `html`。
|
|
194
|
+
logger (logging.Logger): ロガー
|
|
195
|
+
Returns:
|
|
196
|
+
dict: セルの詳細情報
|
|
197
|
+
"""
|
|
198
|
+
wb:Workbook = None
|
|
199
|
+
try:
|
|
200
|
+
from openpyxl.cell import Cell
|
|
201
|
+
from openpyxl.workbook.workbook import Workbook
|
|
202
|
+
from openpyxl.worksheet.worksheet import Worksheet
|
|
203
|
+
import openpyxl
|
|
204
|
+
|
|
205
|
+
wb:Workbook = openpyxl.load_workbook(filename=filepath, read_only=True, data_only=formula_data_only)
|
|
206
|
+
if sheet_name is not None and sheet_name not in wb.sheetnames:
|
|
207
|
+
msg = dict(warn=f"Sheet '{sheet_name}' does not exist in the workbook. filepath: {filepath}")
|
|
208
|
+
logger.warning(f"Sheet '{sheet_name}' does not exist in the workbook. filepath: {filepath}")
|
|
209
|
+
return msg
|
|
210
|
+
|
|
211
|
+
def match_func(value:str) -> bool:
|
|
212
|
+
if match_type == 'full':
|
|
213
|
+
return value == search_value
|
|
214
|
+
elif match_type == 'partial':
|
|
215
|
+
return search_value in str(value)
|
|
216
|
+
elif match_type == 'regex':
|
|
217
|
+
return re.search(search_value, str(value)) is not None
|
|
218
|
+
return False
|
|
219
|
+
|
|
220
|
+
def _proc(cellinfos:Dict[str, Any], sheet:Worksheet):
|
|
221
|
+
cellinfo = {}
|
|
222
|
+
cellinfos[sheet.title] = cellinfo
|
|
223
|
+
celltxt = ""
|
|
224
|
+
if cell_top_left is not None and cell_bottom_right is not None:
|
|
225
|
+
range_str = ":".join(sorted([cell_top_left, cell_bottom_right]))
|
|
226
|
+
cell_range = sheet[range_str]
|
|
227
|
+
for row in cell_range:
|
|
228
|
+
for cell in row:
|
|
229
|
+
if hasattr(cell, 'coordinate') and match_func(cell.value):
|
|
230
|
+
celltxt += self.format_cell(output_cell_format, celltxt, cell.value, logger)
|
|
231
|
+
cellinfo[cell.coordinate] = cell.value
|
|
232
|
+
celltxt = self.format_newline(output_cell_format, celltxt, logger)
|
|
233
|
+
celltxt = self.format_table(output_cell_format, celltxt, logger)
|
|
234
|
+
|
|
235
|
+
if cell_name is not None and len(cell_name) > 0:
|
|
236
|
+
for cn in cell_name:
|
|
237
|
+
cell:Cell = sheet[cn]
|
|
238
|
+
if match_func(cell.value):
|
|
239
|
+
celltxt += self.format_cell(output_cell_format, celltxt, cell.value, logger)
|
|
240
|
+
cellinfo[cn] = cell.value
|
|
241
|
+
celltxt = self.format_newline(output_cell_format, celltxt, logger)
|
|
242
|
+
celltxt = self.format_table(output_cell_format, celltxt, logger)
|
|
243
|
+
|
|
244
|
+
if (cell_name is None or len(cell_name) <= 0) \
|
|
245
|
+
and cell_top_left is None and cell_bottom_right is None:
|
|
246
|
+
for row in sheet.iter_rows():
|
|
247
|
+
for cell in row:
|
|
248
|
+
if hasattr(cell, 'coordinate') and match_func(cell.value):
|
|
249
|
+
celltxt += self.format_cell(output_cell_format, celltxt, cell.value, logger)
|
|
250
|
+
cellinfo[cell.coordinate] = cell.value
|
|
251
|
+
celltxt = self.format_newline(output_cell_format, celltxt, logger)
|
|
252
|
+
celltxt = self.format_table(output_cell_format, celltxt, logger)
|
|
253
|
+
return celltxt
|
|
254
|
+
|
|
255
|
+
cellinfos = {}
|
|
256
|
+
if sheet_name is not None:
|
|
257
|
+
sheet:Worksheet = wb[sheet_name]
|
|
258
|
+
celltxt = _proc(cellinfos, sheet)
|
|
259
|
+
if output_cell_format!='json':
|
|
260
|
+
cellinfos = {sheet_name: celltxt}
|
|
261
|
+
else:
|
|
262
|
+
for sn in wb.sheetnames:
|
|
263
|
+
sheet:Worksheet = wb[sn]
|
|
264
|
+
celltxt = _proc(cellinfos, sheet)
|
|
265
|
+
if output_cell_format!='json':
|
|
266
|
+
cellinfos[sn] = celltxt
|
|
267
|
+
|
|
268
|
+
res = dict(success=cellinfos)
|
|
269
|
+
return res
|
|
270
|
+
except Exception as e:
|
|
271
|
+
msg = dict(warn=f"Failed to search cell search: {e}")
|
|
272
|
+
logger.warning(f"Failed to search cell search: {e}", exc_info=True)
|
|
273
|
+
return msg
|
|
274
|
+
finally:
|
|
275
|
+
if wb is not None:
|
|
276
|
+
wb.close()
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
from cmdbox.app import common, filer
|
|
2
|
+
from cmdbox.app.commons import convert, redis_client
|
|
3
|
+
from cmdbox.app.features.cli import excel_base
|
|
4
|
+
from cmdbox.app.options import Options
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Dict, Any, List, Tuple
|
|
7
|
+
import argparse
|
|
8
|
+
import logging
|
|
9
|
+
import json
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ExcelCellValues(excel_base.ExcelBase):
|
|
13
|
+
def get_cmd(self):
|
|
14
|
+
"""
|
|
15
|
+
この機能のコマンドを返します
|
|
16
|
+
|
|
17
|
+
Returns:
|
|
18
|
+
str: コマンド
|
|
19
|
+
"""
|
|
20
|
+
return 'cell_values'
|
|
21
|
+
|
|
22
|
+
def get_option(self):
|
|
23
|
+
"""
|
|
24
|
+
この機能のオプションを返します
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
Dict[str, Any]: オプション
|
|
28
|
+
"""
|
|
29
|
+
opt = super().get_option()
|
|
30
|
+
opt['description_ja'] = "データフォルダ配下のExcelファイルの指定したセルの値を取得又は設定します。"
|
|
31
|
+
opt['description_en'] = "Retrieves or sets the value of a specified cell in an Excel file located within the data folder."
|
|
32
|
+
opt['choice'] += [
|
|
33
|
+
dict(opt="formula_data_only", type=Options.T_BOOL, default=False, required=True, multi=False, hide=False, choice=[True, False],
|
|
34
|
+
description_ja="数式データのみを参照するかどうかを指定します。このオプションはキャッシュされたデータが存在する場合に有効です。",
|
|
35
|
+
description_en="Specify whether to get only formula data. This option is valid if cached data exists."),
|
|
36
|
+
dict(opt="sheet_name", type=Options.T_STR, default=None, required=False, multi=False, hide=False, choice=None,
|
|
37
|
+
description_ja="セルの値を取得するシートの名前を指定します。省略した場合、最初のシートが使用されます。",
|
|
38
|
+
description_en="Specify the sheet name to get the cell value.If omitted, the first sheet will be used."),
|
|
39
|
+
dict(opt="cell_name", type=Options.T_STR, default=None, required=False, multi=True, hide=False, choice=None,
|
|
40
|
+
description_ja="セルの値を取得するセルの名前を指定します。例えば、`A1`、`B2`、`R5987`。",
|
|
41
|
+
description_en="Specify the cell name to get the cell value. For example, `A1`, `B2`, `R5987`."),
|
|
42
|
+
dict(opt="cell_top_left", type=Options.T_STR, default=None, required=False, multi=False, hide=False, choice=None,
|
|
43
|
+
description_ja="セルの値を取得する左上セルの名前を指定します。例えば、`A1`、`B2`、`R5987`。",
|
|
44
|
+
description_en="Specify the top-left cell name to get the cell value. For example, `A1`, `B2`, `R5987`."),
|
|
45
|
+
dict(opt="cell_bottom_right", type=Options.T_STR, default=None, required=False, multi=False, hide=False, choice=None,
|
|
46
|
+
description_ja="セルの値を取得する右下セルの名前を指定します。例えば、`A1`、`B2`、`R5987`。",
|
|
47
|
+
description_en="Specify the bottom-right cell name to get the cell value. For example, `A1`, `B2`, `R5987`."),
|
|
48
|
+
dict(opt="cell_value", type=Options.T_DICT, default=None, required=False, multi=True, hide=False, choice=None,
|
|
49
|
+
description_ja="セルに値を設定します。セルの名前と値を指定します。セルの名前は例えば、`A1`、`B2`、`R5987`。",
|
|
50
|
+
description_en="Set a value in a cell. Specify the cell's name and value. Cell names can be, for example, `A1`, `B2`, or `R5987`."),
|
|
51
|
+
dict(opt="output_cell_format", type=Options.T_STR, default='json', required=False, multi=False, hide=False, choice=['json', 'csv', 'md', 'html'],
|
|
52
|
+
description_ja="出力フォーマットを指定します。例えば、`json`、`csv`、 `md`、 `html`。",
|
|
53
|
+
description_en="Specify the output format. For example, `json`, `csv`、 `md`、 `html`."),
|
|
54
|
+
]
|
|
55
|
+
return opt
|
|
56
|
+
|
|
57
|
+
def chk_args(self, args:argparse.Namespace, tm:float, pf:List[Dict[str, float]]=[]) -> Tuple[bool, str, Any]:
|
|
58
|
+
"""
|
|
59
|
+
引数のチェックを行います
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
args (argparse.Namespace): 引数
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
Tuple[bool, str]: チェック結果, メッセージ
|
|
66
|
+
"""
|
|
67
|
+
if args.svname is None:
|
|
68
|
+
msg = dict(warn=f"Please specify the --svname option.")
|
|
69
|
+
common.print_format(msg, args.format, tm, args.output_json, args.output_json_append, pf=pf)
|
|
70
|
+
return self.RESP_WARN, msg, None
|
|
71
|
+
if args.scope is None:
|
|
72
|
+
msg = dict(warn=f"Please specify the --scope option.")
|
|
73
|
+
common.print_format(msg, args.format, tm, args.output_json, args.output_json_append, pf=pf)
|
|
74
|
+
return self.RESP_WARN, msg, None
|
|
75
|
+
if args.svpath is None:
|
|
76
|
+
msg = dict(warn=f"Please specify the --svpath option.")
|
|
77
|
+
common.print_format(msg, args.format, tm, args.output_json, args.output_json_append, pf=pf)
|
|
78
|
+
return self.RESP_WARN, msg, None
|
|
79
|
+
return self.RESP_SUCCESS, None, None
|
|
80
|
+
|
|
81
|
+
def excel_proc(self, abspath:Path, args:argparse.Namespace, logger:logging.Logger, tm:float, pf:List[Dict[str, float]]=[]) -> Dict[str, Any]:
|
|
82
|
+
"""
|
|
83
|
+
Excel処理のベース
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
abspath (Path): Excelファイルの絶対パス
|
|
87
|
+
args (argparse.Namespace): 引数
|
|
88
|
+
logger (logging.Logger): ロガー
|
|
89
|
+
tm (float): 処理時間
|
|
90
|
+
pf (List[Dict[str, float]]): パフォーマンス情報
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
Dict[str, Any]: 結果
|
|
94
|
+
"""
|
|
95
|
+
res_json = self.cell_values(abspath, args.formula_data_only, args.sheet_name,
|
|
96
|
+
args.cell_name, args.cell_top_left, args.cell_bottom_right,
|
|
97
|
+
args.cell_value, args.output_cell_format, logger)
|
|
98
|
+
return res_json
|
|
99
|
+
|
|
100
|
+
def get_svparam(self, args:argparse.Namespace) -> List[str]:
|
|
101
|
+
"""
|
|
102
|
+
サーバーに送信するパラメーターを返します
|
|
103
|
+
|
|
104
|
+
Args:
|
|
105
|
+
args (argparse.Namespace): 引数
|
|
106
|
+
|
|
107
|
+
Returns:
|
|
108
|
+
List[str]: サーバーに送信するパラメーター
|
|
109
|
+
"""
|
|
110
|
+
cell_name = json.dumps(args.cell_name, default=common.default_json_enc) if args.cell_name is not None else '[]'
|
|
111
|
+
cell_value = json.dumps(args.cell_value, default=common.default_json_enc) if args.cell_value is not None else '{}'
|
|
112
|
+
ret = [convert.str2b64str(str(args.svpath)), str(args.formula_data_only), convert.str2b64str(str(args.sheet_name)),
|
|
113
|
+
convert.str2b64str(cell_name), convert.str2b64str(args.cell_top_left), convert.str2b64str(args.cell_bottom_right),
|
|
114
|
+
convert.str2b64str(cell_value), convert.str2b64str(args.output_cell_format)]
|
|
115
|
+
return ret
|
|
116
|
+
|
|
117
|
+
def is_cluster_redirect(self):
|
|
118
|
+
"""
|
|
119
|
+
クラスター宛のメッセージの場合、メッセージを転送するかどうかを返します
|
|
120
|
+
|
|
121
|
+
Returns:
|
|
122
|
+
bool: メッセージを転送する場合はTrue
|
|
123
|
+
"""
|
|
124
|
+
return False
|
|
125
|
+
|
|
126
|
+
def svrun(self, data_dir:Path, logger:logging.Logger, redis_cli:redis_client.RedisClient, msg:List[str],
|
|
127
|
+
sessions:Dict[str, Dict[str, Any]]) -> int:
|
|
128
|
+
"""
|
|
129
|
+
この機能のサーバー側の実行を行います
|
|
130
|
+
|
|
131
|
+
Args:
|
|
132
|
+
data_dir (Path): データディレクトリ
|
|
133
|
+
logger (logging.Logger): ロガー
|
|
134
|
+
redis_cli (redis_client.RedisClient): Redisクライアント
|
|
135
|
+
msg (List[str]): 受信メッセージ
|
|
136
|
+
sessions (Dict[str, Dict[str, Any]]): セッション情報
|
|
137
|
+
|
|
138
|
+
Returns:
|
|
139
|
+
int: 終了コード
|
|
140
|
+
"""
|
|
141
|
+
svpath = convert.b64str2str(msg[2])
|
|
142
|
+
formula_data_only = msg[3]=='True'
|
|
143
|
+
sheet_name = convert.b64str2str(msg[4])
|
|
144
|
+
sheet_name = None if sheet_name=='None' else sheet_name
|
|
145
|
+
cell_name = json.loads(convert.b64str2str(msg[5]))
|
|
146
|
+
cell_top_left = convert.b64str2str(msg[6])
|
|
147
|
+
cell_bottom_right = convert.b64str2str(msg[7])
|
|
148
|
+
cell_value = json.loads(convert.b64str2str(msg[8]))
|
|
149
|
+
output_cell_format = convert.b64str2str(msg[9])
|
|
150
|
+
|
|
151
|
+
try:
|
|
152
|
+
f = filer.Filer(data_dir, logger)
|
|
153
|
+
chk, abspath, res = f._file_exists(svpath)
|
|
154
|
+
if not chk:
|
|
155
|
+
logger.warning(f"File not found. {svpath}")
|
|
156
|
+
redis_cli.rpush(msg[1], res)
|
|
157
|
+
return self.RESP_WARN
|
|
158
|
+
res = self.cell_values(abspath, formula_data_only, sheet_name, cell_name, cell_top_left, cell_bottom_right,
|
|
159
|
+
cell_value, output_cell_format, logger)
|
|
160
|
+
redis_cli.rpush(msg[1], res)
|
|
161
|
+
except Exception as e:
|
|
162
|
+
logger.warning(f"Failed to get cell values: {e}", exc_info=True)
|
|
163
|
+
redis_cli.rpush(msg[1], dict(warn=f"Failed to cell values: {e}"))
|
|
164
|
+
return self.RESP_WARN
|
|
165
|
+
return self.RESP_SUCCESS
|
|
166
|
+
|
|
167
|
+
def cell_values(self, filepath:str, formula_data_only:bool, sheet_name:str, cell_name:List[str], cell_top_left:str, cell_bottom_right:str,
|
|
168
|
+
cell_value:Dict[str, Any], output_cell_format:str, logger:logging.Logger) -> Dict[str, Any]:
|
|
169
|
+
"""
|
|
170
|
+
指定したワークブックのセルの値を取得又は設定します。
|
|
171
|
+
|
|
172
|
+
Args:
|
|
173
|
+
filepath (str): ワークブックのパス
|
|
174
|
+
formula_data_only (bool): 数式データのみを参照するかどうか。このオプションはキャッシュされたデータが存在する場合に有効です。
|
|
175
|
+
sheet_name (str): 詳細情報を取得するシートの名前
|
|
176
|
+
cell_name (List[str]): 詳細情報を取得するセルの名前のリスト。例えば、`A1`、`B2`、`R5987`。
|
|
177
|
+
cell_top_left (str): 詳細情報を取得する左上セルの名前。例えば、`A1`、`B2`、`R5987`。
|
|
178
|
+
cell_bottom_right (str): 詳細情報を取得する右下セルの名前。 例えば、`A1`、`B2`、`R5987`。
|
|
179
|
+
cell_value (Dict[str, Any]): セルに設定する値の辞書。キーがセルの名前、値が設定する値。
|
|
180
|
+
output_cell_format (str): 出力フォーマット。`json`、`csv`、 `md`。
|
|
181
|
+
logger (logging.Logger): ロガー
|
|
182
|
+
Returns:
|
|
183
|
+
dict: セルの詳細情報
|
|
184
|
+
"""
|
|
185
|
+
wb:Workbook = None
|
|
186
|
+
wb2:Workbook = None
|
|
187
|
+
try:
|
|
188
|
+
from openpyxl.cell import Cell
|
|
189
|
+
from openpyxl.workbook.workbook import Workbook
|
|
190
|
+
from openpyxl.worksheet.worksheet import Worksheet
|
|
191
|
+
import openpyxl
|
|
192
|
+
|
|
193
|
+
wb:Workbook = openpyxl.load_workbook(filename=filepath, read_only=True, data_only=formula_data_only)
|
|
194
|
+
if sheet_name not in wb.sheetnames:
|
|
195
|
+
if len(wb.sheetnames) <= 0:
|
|
196
|
+
msg = dict(warn=f"There is no worksheet. filepath: {filepath}")
|
|
197
|
+
logger.warning(f"There is no worksheet. filepath: {filepath}")
|
|
198
|
+
return msg
|
|
199
|
+
sheet_name = wb.sheetnames[0]
|
|
200
|
+
|
|
201
|
+
cellinfo = {}
|
|
202
|
+
sheet:Worksheet = wb[sheet_name]
|
|
203
|
+
celltxt = ""
|
|
204
|
+
if cell_top_left is not None and cell_bottom_right is not None:
|
|
205
|
+
range_str = ":".join(sorted([cell_top_left, cell_bottom_right]))
|
|
206
|
+
cell_range = sheet[range_str]
|
|
207
|
+
for row in cell_range:
|
|
208
|
+
for cell in row:
|
|
209
|
+
if hasattr(cell, 'coordinate'):
|
|
210
|
+
celltxt += self.format_cell(output_cell_format, celltxt, cell.value, logger)
|
|
211
|
+
cellinfo[cell.coordinate] = cell.value
|
|
212
|
+
celltxt = self.format_newline(output_cell_format, celltxt, logger)
|
|
213
|
+
celltxt = self.format_table(output_cell_format, celltxt, logger)
|
|
214
|
+
|
|
215
|
+
if cell_name is not None and len(cell_name) > 0:
|
|
216
|
+
for cn in cell_name:
|
|
217
|
+
cell:Cell = sheet[cn]
|
|
218
|
+
celltxt += self.format_cell(output_cell_format, celltxt, cell.value, logger)
|
|
219
|
+
cellinfo[cn] = cell.value
|
|
220
|
+
celltxt = self.format_newline(output_cell_format, celltxt, logger)
|
|
221
|
+
celltxt = self.format_table(output_cell_format, celltxt, logger)
|
|
222
|
+
|
|
223
|
+
if cell_value is not None and len(cell_value) > 0:
|
|
224
|
+
wb2:Workbook = openpyxl.load_workbook(filename=filepath)
|
|
225
|
+
sheet2:Worksheet = wb2[sheet_name]
|
|
226
|
+
for k, v in cell_value.items():
|
|
227
|
+
cell:Cell = sheet2[k]
|
|
228
|
+
cell.value = v
|
|
229
|
+
celltxt += self.format_cell(output_cell_format, celltxt, cell.value, logger)
|
|
230
|
+
cellinfo[k] = cell.value
|
|
231
|
+
celltxt = self.format_newline(output_cell_format, celltxt, logger)
|
|
232
|
+
celltxt = self.format_table(output_cell_format, celltxt, logger)
|
|
233
|
+
wb2.save(filepath)
|
|
234
|
+
wb2.close()
|
|
235
|
+
|
|
236
|
+
if (cell_name is None or len(cell_name) <= 0) \
|
|
237
|
+
and cell_top_left is None and cell_bottom_right is None \
|
|
238
|
+
and (cell_value is None or len(cell_value) <= 0):
|
|
239
|
+
for row in sheet.iter_rows():
|
|
240
|
+
for cell in row:
|
|
241
|
+
if hasattr(cell, 'coordinate'):
|
|
242
|
+
celltxt = self.append_cell(output_cell_format, celltxt, cell.value, logger)
|
|
243
|
+
cellinfo[cell.coordinate] = cell.value
|
|
244
|
+
celltxt = self.format_newline(output_cell_format, celltxt, logger)
|
|
245
|
+
celltxt = self.format_table(output_cell_format, celltxt, logger)
|
|
246
|
+
|
|
247
|
+
cellinfos = {sheet_name: cellinfo if output_cell_format=='json' else celltxt}
|
|
248
|
+
res = dict(success=cellinfos)
|
|
249
|
+
return res
|
|
250
|
+
except Exception as e:
|
|
251
|
+
msg = dict(warn=f"Failed to cell values: {e}")
|
|
252
|
+
logger.warning(f"Failed to cell values: {e}", exc_info=True)
|
|
253
|
+
return msg
|
|
254
|
+
finally:
|
|
255
|
+
if wb is not None:
|
|
256
|
+
wb.close()
|
|
257
|
+
if wb2 is not None:
|
|
258
|
+
wb2.close()
|