cmdbox 0.6.5__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.

Files changed (155) hide show
  1. cmdbox/app/client.py +384 -384
  2. cmdbox/app/feature.py +1 -1
  3. cmdbox/app/features/cli/_cmdbox_vision_install.py +0 -9
  4. cmdbox/app/features/cli/_cmdbox_vision_predict.py +0 -9
  5. cmdbox/app/features/cli/cmdbox_audit_createdb.py +1 -11
  6. cmdbox/app/features/cli/cmdbox_audit_delete.py +0 -9
  7. cmdbox/app/features/cli/cmdbox_audit_search.py +0 -9
  8. cmdbox/app/features/cli/cmdbox_audit_write.py +0 -9
  9. cmdbox/app/features/cli/cmdbox_excel_cell_details.py +436 -0
  10. cmdbox/app/features/cli/cmdbox_excel_cell_search.py +276 -0
  11. cmdbox/app/features/cli/cmdbox_excel_cell_values.py +258 -0
  12. cmdbox/app/features/cli/cmdbox_excel_sheet_list.py +159 -0
  13. cmdbox/app/features/cli/cmdbox_tts_install.py +0 -9
  14. cmdbox/app/features/cli/cmdbox_tts_say.py +0 -9
  15. cmdbox/app/features/cli/cmdbox_tts_start.py +0 -9
  16. cmdbox/app/features/cli/cmdbox_tts_stop.py +0 -9
  17. cmdbox/app/features/cli/excel_base.py +301 -0
  18. cmdbox/app/web.py +9 -4
  19. cmdbox/extensions/features.yml +3 -0
  20. cmdbox/extensions/sample_project/sample/app/features/cli/sample_server_time.py +0 -9
  21. cmdbox/licenses/LICENSE_Authlib_1_6_5_BSD_License.txt +29 -0
  22. cmdbox/licenses/LICENSE_Mako_1_3_10_MIT_License.txt +19 -0
  23. cmdbox/licenses/LICENSE_SQLAlchemy_2_0_43_MIT.txt +19 -0
  24. cmdbox/licenses/LICENSE_Werkzeug_3_1_1_BSD_License.txt +28 -0
  25. cmdbox/licenses/LICENSE_absolufy-imports_0_3_1_MIT_License.txt +21 -0
  26. cmdbox/licenses/LICENSE_aiohappyeyeballs_2_6_1_Python_Software_Foundation_License.txt +279 -0
  27. cmdbox/licenses/LICENSE_aiohttp_3_12_15_Apache-2_0_AND_MIT.txt +13 -0
  28. cmdbox/licenses/LICENSE_aiosignal_1_4_0_Apache_Software_License.txt +201 -0
  29. cmdbox/licenses/LICENSE_alembic_1_16_5_UNKNOWN.txt +19 -0
  30. cmdbox/licenses/LICENSE_attrs_25_3_0_UNKNOWN.txt +21 -0
  31. cmdbox/licenses/LICENSE_cachetools_6_2_0_MIT_License.txt +20 -0
  32. cmdbox/licenses/LICENSE_cloudpickle_3_1_1_BSD_License.txt +1 -0
  33. cmdbox/licenses/LICENSE_cyclopts_3_24_0_Apache_Software_License.txt +201 -0
  34. cmdbox/licenses/LICENSE_debugpy_1_8_17_MIT_License.txt +24 -0
  35. cmdbox/licenses/LICENSE_distro_1_9_0_Apache_Software_License.txt +202 -0
  36. cmdbox/licenses/LICENSE_dnspython_2_8_0_ISC_License-ISCL.txt +35 -0
  37. cmdbox/licenses/LICENSE_docstring_parser_0_17_0_MIT_License.txt +21 -0
  38. cmdbox/licenses/LICENSE_email-validator_2_3_0_The_Unlicense-Unlicense.txt +27 -0
  39. cmdbox/licenses/LICENSE_et_xmlfile_2_0_0_MIT_License.txt +298 -0
  40. cmdbox/licenses/LICENSE_exceptiongroup_1_3_0_MIT_License.txt +73 -0
  41. cmdbox/licenses/LICENSE_fastmcp_2_12_4_Apache_Software_License.txt +201 -0
  42. cmdbox/licenses/LICENSE_fastuuid_0_13_5_BSD_License.txt +29 -0
  43. cmdbox/licenses/LICENSE_filelock_3_19_1_The_Unlicense-Unlicense.txt +24 -0
  44. cmdbox/licenses/LICENSE_frozenlist_1_7_0_Apache-2_0.txt +201 -0
  45. cmdbox/licenses/LICENSE_fsspec_2025_9_0_UNKNOWN.txt +29 -0
  46. cmdbox/licenses/LICENSE_google-adk_1_15_1_Apache_Software_License.txt +202 -0
  47. cmdbox/licenses/LICENSE_google-api-core_2_25_2_Apache_Software_License.txt +202 -0
  48. cmdbox/licenses/LICENSE_google-api-python-client_2_184_0_Apache_Software_License.txt +201 -0
  49. cmdbox/licenses/LICENSE_google-auth-httplib2_0_2_0_Apache_Software_License.txt +201 -0
  50. cmdbox/licenses/LICENSE_google-auth_2_41_1_Apache_Software_License.txt +201 -0
  51. cmdbox/licenses/LICENSE_google-cloud-aiplatform_1_119_0_Apache_2_0.txt +202 -0
  52. cmdbox/licenses/LICENSE_google-cloud-appengine-logging_1_6_2_Apache_Software_License.txt +202 -0
  53. cmdbox/licenses/LICENSE_google-cloud-audit-log_0_3_2_Apache_Software_License.txt +202 -0
  54. cmdbox/licenses/LICENSE_google-cloud-bigquery_3_38_0_Apache_Software_License.txt +202 -0
  55. cmdbox/licenses/LICENSE_google-cloud-bigtable_2_32_0_Apache_Software_License.txt +202 -0
  56. cmdbox/licenses/LICENSE_google-cloud-core_2_4_3_Apache_Software_License.txt +202 -0
  57. cmdbox/licenses/LICENSE_google-cloud-logging_3_12_1_Apache_Software_License.txt +202 -0
  58. cmdbox/licenses/LICENSE_google-cloud-monitoring_2_27_2_Apache_Software_License.txt +202 -0
  59. cmdbox/licenses/LICENSE_google-cloud-resource-manager_1_14_2_Apache_Software_License.txt +202 -0
  60. cmdbox/licenses/LICENSE_google-cloud-secret-manager_2_24_0_Apache_Software_License.txt +202 -0
  61. cmdbox/licenses/LICENSE_google-cloud-spanner_3_58_0_Apache_Software_License.txt +202 -0
  62. cmdbox/licenses/LICENSE_google-cloud-speech_2_33_0_Apache_Software_License.txt +202 -0
  63. cmdbox/licenses/LICENSE_google-cloud-storage_2_19_0_Apache_Software_License.txt +202 -0
  64. cmdbox/licenses/LICENSE_google-cloud-trace_1_16_2_Apache_Software_License.txt +202 -0
  65. cmdbox/licenses/LICENSE_google-crc32c_1_7_1_Apache_2_0.txt +202 -0
  66. cmdbox/licenses/LICENSE_google-genai_1_40_0_Apache_Software_License.txt +202 -0
  67. cmdbox/licenses/LICENSE_google-resumable-media_2_7_2_Apache_Software_License.txt +202 -0
  68. cmdbox/licenses/LICENSE_googleapis-common-protos_1_70_0_Apache_Software_License.txt +202 -0
  69. cmdbox/licenses/{LICENSE_hyperframe_6_1_0_MIT_License.txt → LICENSE_graphviz_0_21_UNKNOWN.txt} +1 -1
  70. cmdbox/licenses/LICENSE_grpc-google-iam-v1_0_14_2_Apache_Software_License.txt +202 -0
  71. cmdbox/licenses/LICENSE_grpc-interceptor_0_15_4_MIT_License.txt +21 -0
  72. cmdbox/licenses/LICENSE_grpcio-status_1_75_1_Apache_Software_License.txt +610 -0
  73. cmdbox/licenses/LICENSE_grpcio_1_75_1_Apache_Software_License.txt +610 -0
  74. cmdbox/licenses/LICENSE_httpcore_1_0_9_BSD_License.txt +27 -0
  75. cmdbox/licenses/LICENSE_httplib2_0_31_0_MIT_License.txt +23 -0
  76. cmdbox/licenses/LICENSE_httpx-sse_0_4_1_MIT.txt +21 -0
  77. cmdbox/licenses/LICENSE_httpx_0_28_1_BSD_License.txt +12 -0
  78. cmdbox/licenses/LICENSE_huggingface-hub_0_35_3_Apache_Software_License.txt +201 -0
  79. cmdbox/licenses/LICENSE_isodate_0_7_2_BSD_License.txt +26 -0
  80. cmdbox/licenses/LICENSE_jiter_0_11_0_MIT_License.txt +1 -0
  81. cmdbox/licenses/LICENSE_jsonschema-path_0_3_4_Apache_Software_License.txt +201 -0
  82. cmdbox/licenses/{LICENSE_priority_2_0_0_MIT_License.txt → LICENSE_jsonschema-specifications_2025_9_1_UNKNOWN.txt} +2 -2
  83. cmdbox/licenses/{LICENSE_hpack_4_1_0_MIT_License.txt → LICENSE_jsonschema_4_25_1_UNKNOWN.txt} +1 -3
  84. cmdbox/licenses/LICENSE_lazy-object-proxy_1_12_0_UNKNOWN.txt +20 -0
  85. cmdbox/licenses/LICENSE_litellm_1_77_5_MIT_License.txt +26 -0
  86. cmdbox/licenses/LICENSE_mcp_1_16_0_MIT_License.txt +21 -0
  87. cmdbox/licenses/LICENSE_multidict_6_6_4_Apache_License_2_0.txt +13 -0
  88. cmdbox/licenses/LICENSE_openai_2_1_0_Apache_Software_License.txt +201 -0
  89. cmdbox/licenses/LICENSE_openapi-core_0_19_5_BSD_License.txt +29 -0
  90. cmdbox/licenses/LICENSE_openapi-pydantic_0_5_1_MIT_License.txt +40 -0
  91. cmdbox/licenses/LICENSE_openapi-schema-validator_0_6_3_BSD_License.txt +29 -0
  92. cmdbox/licenses/LICENSE_openapi-spec-validator_0_7_2_Apache_Software_License.txt +201 -0
  93. cmdbox/licenses/LICENSE_openpyxl_3_1_5_MIT_License.txt +23 -0
  94. cmdbox/licenses/LICENSE_opentelemetry-api_1_37_0_UNKNOWN.txt +201 -0
  95. cmdbox/licenses/LICENSE_opentelemetry-exporter-gcp-logging_1_9_0a0_Apache_Software_License.txt +201 -0
  96. cmdbox/licenses/LICENSE_opentelemetry-exporter-gcp-monitoring_1_9_0a0_Apache_Software_License.txt +201 -0
  97. cmdbox/licenses/LICENSE_opentelemetry-exporter-gcp-trace_1_9_0_Apache_Software_License.txt +201 -0
  98. cmdbox/licenses/LICENSE_opentelemetry-exporter-otlp-proto-common_1_37_0_UNKNOWN.txt +201 -0
  99. cmdbox/licenses/LICENSE_opentelemetry-exporter-otlp-proto-http_1_37_0_UNKNOWN.txt +201 -0
  100. cmdbox/licenses/LICENSE_opentelemetry-proto_1_37_0_UNKNOWN.txt +201 -0
  101. cmdbox/licenses/LICENSE_opentelemetry-resourcedetector-gcp_1_9_0a0_Apache_Software_License.txt +201 -0
  102. cmdbox/licenses/LICENSE_opentelemetry-sdk_1_37_0_UNKNOWN.txt +201 -0
  103. cmdbox/licenses/LICENSE_opentelemetry-semantic-conventions_0_58b0_UNKNOWN.txt +201 -0
  104. cmdbox/licenses/LICENSE_parse_1_20_2_MIT_License.txt +19 -0
  105. cmdbox/licenses/LICENSE_pathable_0_4_4_Apache_Software_License.txt +201 -0
  106. cmdbox/licenses/LICENSE_propcache_0_3_2_Apache_Software_License.txt +202 -0
  107. cmdbox/licenses/LICENSE_proto-plus_1_26_1_Apache_Software_License.txt +202 -0
  108. cmdbox/licenses/LICENSE_protobuf_6_32_1_3-Clause_BSD_License.txt +32 -0
  109. cmdbox/licenses/LICENSE_pyasn1_0_6_1_BSD_License.txt +24 -0
  110. cmdbox/licenses/LICENSE_pyasn1_modules_0_4_2_BSD_License.txt +24 -0
  111. cmdbox/licenses/LICENSE_pydantic-settings_2_11_0_MIT_License.txt +21 -0
  112. cmdbox/licenses/LICENSE_pyparsing_3_2_5_UNKNOWN.txt +18 -0
  113. cmdbox/licenses/LICENSE_pyperclip_1_11_0_BSD_License.txt +27 -0
  114. cmdbox/licenses/LICENSE_python-dateutil_2_9_0_post0_Apache_Software_License-BSD_License.txt +54 -0
  115. cmdbox/licenses/LICENSE_python-dotenv_1_1_1_BSD_License.txt +27 -0
  116. cmdbox/licenses/LICENSE_pywin32_311_Python_Software_Foundation_License.txt +1 -0
  117. cmdbox/licenses/LICENSE_referencing_0_36_2_UNKNOWN.txt +19 -0
  118. cmdbox/licenses/LICENSE_regex_2025_9_18_UNKNOWN.txt +208 -0
  119. cmdbox/licenses/LICENSE_rfc3339-validator_0_1_4_MIT_License.txt +22 -0
  120. cmdbox/licenses/LICENSE_rich-rst_1_3_1_MIT_License.txt +7 -0
  121. cmdbox/licenses/LICENSE_rpds-py_0_27_1_UNKNOWN.txt +19 -0
  122. cmdbox/licenses/LICENSE_rsa_4_9_1_Apache_Software_License.txt +13 -0
  123. cmdbox/licenses/LICENSE_shapely_2_1_2_BSD_License.txt +29 -0
  124. cmdbox/licenses/LICENSE_sqlalchemy-spanner_1_16_0_Apache_Software_License.txt +202 -0
  125. cmdbox/licenses/LICENSE_sqlparse_0_5_3_BSD_License.txt +25 -0
  126. cmdbox/licenses/LICENSE_sse-starlette_3_0_2_UNKNOWN.txt +27 -0
  127. cmdbox/licenses/LICENSE_tenacity_8_5_0_Apache_Software_License.txt +202 -0
  128. cmdbox/licenses/LICENSE_tiktoken_0_11_0_MIT_License-Copyright-c-2022_OpenAI-Shantanu_Jain-Permission_is_hereby_granted-free_of_charge-to_any_per.txt +21 -0
  129. cmdbox/licenses/LICENSE_tokenizers_0_22_1_Apache_Software_License.txt +1 -0
  130. cmdbox/licenses/LICENSE_tqdm_4_67_1_MIT_License-Mozilla_Public_License_2_0-MPL_2_0.txt +49 -0
  131. cmdbox/licenses/LICENSE_tzlocal_5_3_1_MIT_License.txt +19 -0
  132. cmdbox/licenses/LICENSE_uritemplate_4_2_0_BSD_3-Clause_OR_Apache-2_0.txt +3 -0
  133. cmdbox/licenses/LICENSE_uvicorn_0_37_0_BSD_License.txt +28 -0
  134. cmdbox/licenses/LICENSE_watchdog_6_0_0_Apache_Software_License.txt +16 -0
  135. cmdbox/licenses/LICENSE_websockets_15_0_1_BSD_License.txt +24 -0
  136. cmdbox/licenses/LICENSE_yarl_1_20_1_Apache_Software_License.txt +202 -0
  137. cmdbox/licenses/files.txt +146 -14
  138. cmdbox/version.py +2 -2
  139. {cmdbox-0.6.5.dist-info → cmdbox-0.6.6.dist-info}/METADATA +27 -29
  140. {cmdbox-0.6.5.dist-info → cmdbox-0.6.6.dist-info}/RECORD +153 -37
  141. cmdbox/licenses/LICENSE_Hypercorn_0_17_3_MIT_License.txt +0 -22
  142. cmdbox/licenses/LICENSE_h2_4_3_0_MIT_License.txt +0 -21
  143. /cmdbox/licenses/{LICENSE_MarkupSafe_3_0_2_BSD_License.txt → LICENSE_MarkupSafe_3_0_3_UNKNOWN.txt} +0 -0
  144. /cmdbox/licenses/{LICENSE_PyYAML_6_0_2_MIT_License.txt → LICENSE_PyYAML_6_0_3_MIT_License.txt} +0 -0
  145. /cmdbox/licenses/{LICENSE_anyio_4_10_0_UNKNOWN.txt → LICENSE_anyio_4_11_0_UNKNOWN.txt} +0 -0
  146. /cmdbox/licenses/{LICENSE_cryptography_46_0_1_UNKNOWN.txt → LICENSE_cryptography_46_0_2_UNKNOWN.txt} +0 -0
  147. /cmdbox/licenses/{LICENSE_fastapi_0_116_2_MIT_License.txt → LICENSE_fastapi_0_118_0_MIT_License.txt} +0 -0
  148. /cmdbox/licenses/{LICENSE_pydantic_2_11_9_MIT_License.txt → LICENSE_pydantic_2_11_10_MIT_License.txt} +0 -0
  149. /cmdbox/licenses/{LICENSE_typing-inspection_0_4_1_UNKNOWN.txt → LICENSE_typing-inspection_0_4_2_UNKNOWN.txt} +0 -0
  150. /cmdbox/licenses/{LICENSE_wcwidth_0_2_13_MIT_License.txt → LICENSE_wcwidth_0_2_14_MIT_License.txt} +0 -0
  151. /cmdbox/licenses/{LICENSE_zope_interface_8_0_Zope_Public_License.txt → LICENSE_zope_interface_8_0_1_Zope_Public_License.txt} +0 -0
  152. {cmdbox-0.6.5.dist-info → cmdbox-0.6.6.dist-info}/WHEEL +0 -0
  153. {cmdbox-0.6.5.dist-info → cmdbox-0.6.6.dist-info}/entry_points.txt +0 -0
  154. {cmdbox-0.6.5.dist-info → cmdbox-0.6.6.dist-info}/licenses/LICENSE +0 -0
  155. {cmdbox-0.6.5.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()