cmdbox 0.6.4.2__py3-none-any.whl → 0.6.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.

Potentially problematic release.


This version of cmdbox might be problematic. Click here for more details.

Files changed (165) hide show
  1. cmdbox/app/app.py +7 -0
  2. cmdbox/app/client.py +4 -3
  3. cmdbox/app/common.py +85 -7
  4. cmdbox/app/commons/convert.py +3 -1
  5. cmdbox/app/edge.py +12 -12
  6. cmdbox/app/features/cli/{cmdbox_vision_install.py → _cmdbox_vision_install.py} +2 -1
  7. cmdbox/app/features/cli/_cmdbox_vision_predict.py +496 -0
  8. cmdbox/app/features/cli/{cmdbox_vision_start.py → _cmdbox_vision_start.py} +5 -1
  9. cmdbox/app/features/cli/cmdbox_cmd_list.py +3 -3
  10. cmdbox/app/features/cli/cmdbox_cmd_load.py +3 -3
  11. cmdbox/app/features/cli/cmdbox_tts_install.py +4 -2
  12. cmdbox/app/features/cli/cmdbox_tts_say.py +2 -1
  13. cmdbox/app/features/cli/cmdbox_web_apikey_add.py +3 -3
  14. cmdbox/app/features/cli/cmdbox_web_apikey_del.py +3 -3
  15. cmdbox/app/features/cli/cmdbox_web_group_add.py +3 -3
  16. cmdbox/app/features/cli/cmdbox_web_group_del.py +3 -3
  17. cmdbox/app/features/cli/cmdbox_web_group_edit.py +3 -3
  18. cmdbox/app/features/cli/cmdbox_web_group_list.py +3 -3
  19. cmdbox/app/features/cli/cmdbox_web_start.py +10 -10
  20. cmdbox/app/features/cli/cmdbox_web_user_add.py +3 -3
  21. cmdbox/app/features/cli/cmdbox_web_user_del.py +3 -3
  22. cmdbox/app/features/cli/cmdbox_web_user_edit.py +3 -3
  23. cmdbox/app/features/cli/cmdbox_web_user_list.py +3 -3
  24. cmdbox/app/features/web/cmdbox_web_exec_cmd.py +12 -14
  25. cmdbox/app/filer.py +5 -2
  26. cmdbox/app/mcp.py +4 -3
  27. cmdbox/app/options.py +8 -0
  28. cmdbox/app/web.py +50 -36
  29. cmdbox/licenses/LICENSE_Hypercorn_0_17_3_MIT_License.txt +22 -0
  30. cmdbox/licenses/{LICENSE_cffi_1_17_1_MIT_License.txt → LICENSE_cffi_2_0_0_UNKNOWN.txt} +2 -5
  31. cmdbox/licenses/{LICENSE_jsonschema-specifications_2025_4_1_UNKNOWN.txt → LICENSE_h2_4_3_0_MIT_License.txt} +3 -1
  32. cmdbox/licenses/{LICENSE_backoff_2_2_1_MIT_License.txt → LICENSE_hpack_4_1_0_MIT_License.txt} +1 -1
  33. cmdbox/licenses/{LICENSE_graphviz_0_21_UNKNOWN.txt → LICENSE_hyperframe_6_1_0_MIT_License.txt} +1 -1
  34. cmdbox/licenses/{LICENSE_jsonschema_4_25_0_UNKNOWN.txt → LICENSE_priority_2_0_0_MIT_License.txt} +2 -2
  35. cmdbox/licenses/files.txt +26 -147
  36. cmdbox/version.py +2 -2
  37. cmdbox/web/assets/cmdbox/svgicon.js +9 -0
  38. {cmdbox-0.6.4.2.dist-info → cmdbox-0.6.5.dist-info}/METADATA +3 -1
  39. {cmdbox-0.6.4.2.dist-info → cmdbox-0.6.5.dist-info}/RECORD +63 -163
  40. cmdbox/app/features/cli/cmdbox_vision_predict.py +0 -192
  41. cmdbox/licenses/LICENSE_APScheduler_3_11_0_MIT_License.txt +0 -19
  42. cmdbox/licenses/LICENSE_Authlib_1_6_1_BSD_License.txt +0 -29
  43. cmdbox/licenses/LICENSE_SQLAlchemy_2_0_43_MIT.txt +0 -19
  44. cmdbox/licenses/LICENSE_Werkzeug_3_1_1_BSD_License.txt +0 -28
  45. cmdbox/licenses/LICENSE_absolufy-imports_0_3_1_MIT_License.txt +0 -21
  46. cmdbox/licenses/LICENSE_aiohttp_3_12_15_Apache-2_0_AND_MIT.txt +0 -13
  47. cmdbox/licenses/LICENSE_aiosignal_1_4_0_Apache_Software_License.txt +0 -201
  48. cmdbox/licenses/LICENSE_attrs_25_3_0_UNKNOWN.txt +0 -21
  49. cmdbox/licenses/LICENSE_cachetools_5_5_2_MIT_License.txt +0 -20
  50. cmdbox/licenses/LICENSE_cloudpickle_3_1_1_BSD_License.txt +0 -1
  51. cmdbox/licenses/LICENSE_cyclopts_3_22_5_Apache_Software_License.txt +0 -201
  52. cmdbox/licenses/LICENSE_distro_1_9_0_Apache_Software_License.txt +0 -202
  53. cmdbox/licenses/LICENSE_dnspython_2_7_0_ISC_License-ISCL.txt +0 -35
  54. cmdbox/licenses/LICENSE_docstring_parser_0_17_0_MIT_License.txt +0 -21
  55. cmdbox/licenses/LICENSE_email_validator_2_2_0_The_Unlicense-Unlicense.txt +0 -27
  56. cmdbox/licenses/LICENSE_exceptiongroup_1_3_0_MIT_License.txt +0 -73
  57. cmdbox/licenses/LICENSE_fastapi-sso_0_18_0_MIT_License.txt +0 -21
  58. cmdbox/licenses/LICENSE_fastmcp_2_11_3_Apache_Software_License.txt +0 -201
  59. cmdbox/licenses/LICENSE_filelock_3_18_0_The_Unlicense-Unlicense.txt +0 -24
  60. cmdbox/licenses/LICENSE_frozenlist_1_7_0_Apache-2_0.txt +0 -201
  61. cmdbox/licenses/LICENSE_fsspec_2025_7_0_BSD_License.txt +0 -29
  62. cmdbox/licenses/LICENSE_google-adk_1_10_0_Apache_Software_License.txt +0 -202
  63. cmdbox/licenses/LICENSE_google-api-core_2_25_1_Apache_Software_License.txt +0 -202
  64. cmdbox/licenses/LICENSE_google-api-python-client_2_178_0_Apache_Software_License.txt +0 -201
  65. cmdbox/licenses/LICENSE_google-auth-httplib2_0_2_0_Apache_Software_License.txt +0 -201
  66. cmdbox/licenses/LICENSE_google-auth_2_40_3_Apache_Software_License.txt +0 -201
  67. cmdbox/licenses/LICENSE_google-cloud-aiplatform_1_108_0_Apache_2_0.txt +0 -202
  68. cmdbox/licenses/LICENSE_google-cloud-appengine-logging_1_6_2_Apache_Software_License.txt +0 -202
  69. cmdbox/licenses/LICENSE_google-cloud-audit-log_0_3_2_Apache_Software_License.txt +0 -202
  70. cmdbox/licenses/LICENSE_google-cloud-bigquery_3_35_1_Apache_Software_License.txt +0 -202
  71. cmdbox/licenses/LICENSE_google-cloud-core_2_4_3_Apache_Software_License.txt +0 -202
  72. cmdbox/licenses/LICENSE_google-cloud-logging_3_12_1_Apache_Software_License.txt +0 -202
  73. cmdbox/licenses/LICENSE_google-cloud-resource-manager_1_14_2_Apache_Software_License.txt +0 -202
  74. cmdbox/licenses/LICENSE_google-cloud-secret-manager_2_24_0_Apache_Software_License.txt +0 -202
  75. cmdbox/licenses/LICENSE_google-cloud-speech_2_33_0_Apache_Software_License.txt +0 -202
  76. cmdbox/licenses/LICENSE_google-cloud-storage_2_19_0_Apache_Software_License.txt +0 -202
  77. cmdbox/licenses/LICENSE_google-cloud-trace_1_16_2_Apache_Software_License.txt +0 -202
  78. cmdbox/licenses/LICENSE_google-crc32c_1_7_1_Apache_2_0.txt +0 -202
  79. cmdbox/licenses/LICENSE_google-genai_1_29_0_Apache_Software_License.txt +0 -202
  80. cmdbox/licenses/LICENSE_google-resumable-media_2_7_2_Apache_Software_License.txt +0 -202
  81. cmdbox/licenses/LICENSE_googleapis-common-protos_1_70_0_Apache_Software_License.txt +0 -202
  82. cmdbox/licenses/LICENSE_grpc-google-iam-v1_0_14_2_Apache_Software_License.txt +0 -202
  83. cmdbox/licenses/LICENSE_grpcio-status_1_74_0_Apache_Software_License.txt +0 -610
  84. cmdbox/licenses/LICENSE_grpcio_1_74_0_Apache_Software_License.txt +0 -610
  85. cmdbox/licenses/LICENSE_httpcore_1_0_9_BSD_License.txt +0 -27
  86. cmdbox/licenses/LICENSE_httplib2_0_22_0_MIT_License.txt +0 -23
  87. cmdbox/licenses/LICENSE_httpx-sse_0_4_1_MIT.txt +0 -21
  88. cmdbox/licenses/LICENSE_httpx_0_28_1_BSD_License.txt +0 -12
  89. cmdbox/licenses/LICENSE_huggingface-hub_0_34_4_Apache_Software_License.txt +0 -201
  90. cmdbox/licenses/LICENSE_isodate_0_7_2_BSD_License.txt +0 -26
  91. cmdbox/licenses/LICENSE_jiter_0_10_0_MIT_License.txt +0 -1
  92. cmdbox/licenses/LICENSE_jsonschema-path_0_3_4_Apache_Software_License.txt +0 -201
  93. cmdbox/licenses/LICENSE_lazy-object-proxy_1_11_0_BSD_License.txt +0 -20
  94. cmdbox/licenses/LICENSE_litellm-enterprise_0_1_19_UNKNOWN.txt +0 -37
  95. cmdbox/licenses/LICENSE_litellm_1_75_5_post1_MIT_License.txt +0 -26
  96. cmdbox/licenses/LICENSE_mcp_1_12_4_MIT_License.txt +0 -21
  97. cmdbox/licenses/LICENSE_multidict_6_6_4_Apache_License_2_0.txt +0 -13
  98. cmdbox/licenses/LICENSE_oauthlib_3_3_1_BSD-3-Clause.txt +0 -27
  99. cmdbox/licenses/LICENSE_openai_1_99_9_Apache_Software_License.txt +0 -201
  100. cmdbox/licenses/LICENSE_openapi-core_0_19_5_BSD_License.txt +0 -29
  101. cmdbox/licenses/LICENSE_openapi-pydantic_0_5_1_MIT_License.txt +0 -40
  102. cmdbox/licenses/LICENSE_openapi-schema-validator_0_6_3_BSD_License.txt +0 -29
  103. cmdbox/licenses/LICENSE_openapi-spec-validator_0_7_2_Apache_Software_License.txt +0 -201
  104. cmdbox/licenses/LICENSE_opentelemetry-api_1_36_0_UNKNOWN.txt +0 -201
  105. cmdbox/licenses/LICENSE_opentelemetry-exporter-gcp-trace_1_9_0_Apache_Software_License.txt +0 -201
  106. cmdbox/licenses/LICENSE_opentelemetry-resourcedetector-gcp_1_9_0a0_Apache_Software_License.txt +0 -201
  107. cmdbox/licenses/LICENSE_opentelemetry-sdk_1_36_0_UNKNOWN.txt +0 -201
  108. cmdbox/licenses/LICENSE_opentelemetry-semantic-conventions_0_57b0_UNKNOWN.txt +0 -201
  109. cmdbox/licenses/LICENSE_orjson_3_11_1_Apache_Software_License-MIT_License.txt +0 -201
  110. cmdbox/licenses/LICENSE_parse_1_20_2_MIT_License.txt +0 -19
  111. cmdbox/licenses/LICENSE_pathable_0_4_4_Apache_Software_License.txt +0 -201
  112. cmdbox/licenses/LICENSE_propcache_0_3_2_Apache_Software_License.txt +0 -202
  113. cmdbox/licenses/LICENSE_proto-plus_1_26_1_Apache_Software_License.txt +0 -202
  114. cmdbox/licenses/LICENSE_protobuf_6_31_1_3-Clause_BSD_License.txt +0 -32
  115. cmdbox/licenses/LICENSE_pyasn1_0_6_1_BSD_License.txt +0 -24
  116. cmdbox/licenses/LICENSE_pyasn1_modules_0_4_2_BSD_License.txt +0 -24
  117. cmdbox/licenses/LICENSE_pydantic-settings_2_10_1_MIT_License.txt +0 -21
  118. cmdbox/licenses/LICENSE_pyparsing_3_2_3_MIT_License.txt +0 -18
  119. cmdbox/licenses/LICENSE_pyperclip_1_9_0_BSD_License.txt +0 -27
  120. cmdbox/licenses/LICENSE_python-dateutil_2_9_0_post0_Apache_Software_License-BSD_License.txt +0 -54
  121. cmdbox/licenses/LICENSE_python-dotenv_1_1_1_BSD_License.txt +0 -27
  122. cmdbox/licenses/LICENSE_pywin32_311_Python_Software_Foundation_License.txt +0 -1
  123. cmdbox/licenses/LICENSE_referencing_0_36_2_UNKNOWN.txt +0 -19
  124. cmdbox/licenses/LICENSE_regex_2025_7_34_UNKNOWN.txt +0 -208
  125. cmdbox/licenses/LICENSE_rfc3339-validator_0_1_4_MIT_License.txt +0 -22
  126. cmdbox/licenses/LICENSE_rich-rst_1_3_1_MIT_License.txt +0 -7
  127. cmdbox/licenses/LICENSE_rpds-py_0_27_0_UNKNOWN.txt +0 -19
  128. cmdbox/licenses/LICENSE_rsa_4_9_1_Apache_Software_License.txt +0 -13
  129. cmdbox/licenses/LICENSE_shapely_2_1_1_BSD_License.txt +0 -29
  130. cmdbox/licenses/LICENSE_sse-starlette_3_0_2_UNKNOWN.txt +0 -27
  131. cmdbox/licenses/LICENSE_tenacity_9_1_2_Apache_Software_License.txt +0 -202
  132. 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 +0 -21
  133. cmdbox/licenses/LICENSE_tokenizers_0_21_4_Apache_Software_License.txt +0 -1
  134. cmdbox/licenses/LICENSE_tqdm_4_67_1_MIT_License-Mozilla_Public_License_2_0-MPL_2_0.txt +0 -49
  135. cmdbox/licenses/LICENSE_typing_extensions_4_14_1_UNKNOWN.txt +0 -279
  136. cmdbox/licenses/LICENSE_tzlocal_5_3_1_MIT_License.txt +0 -19
  137. cmdbox/licenses/LICENSE_uritemplate_4_2_0_BSD_3-Clause_OR_Apache-2_0.txt +0 -3
  138. cmdbox/licenses/LICENSE_uvicorn_0_35_0_BSD_License.txt +0 -27
  139. cmdbox/licenses/LICENSE_watchdog_6_0_0_Apache_Software_License.txt +0 -16
  140. cmdbox/licenses/LICENSE_websockets_15_0_1_BSD_License.txt +0 -24
  141. cmdbox/licenses/LICENSE_yarl_1_20_1_Apache_Software_License.txt +0 -202
  142. /cmdbox/licenses/{LICENSE_click_8_2_1_UNKNOWN.txt → LICENSE_click_8_3_0_UNKNOWN.txt} +0 -0
  143. /cmdbox/licenses/{LICENSE_cryptography_45_0_6_Apache-2_0_OR_BSD-3-Clause.txt → LICENSE_cryptography_46_0_1_UNKNOWN.txt} +0 -0
  144. /cmdbox/licenses/{LICENSE_fastapi_0_116_1_MIT_License.txt → LICENSE_fastapi_0_116_2_MIT_License.txt} +0 -0
  145. /cmdbox/licenses/{LICENSE_gevent_25_5_1_MIT.txt → LICENSE_gevent_25_9_1_MIT.txt} +0 -0
  146. /cmdbox/licenses/{LICENSE_jaraco_functools_4_2_1_UNKNOWN.txt → LICENSE_jaraco_functools_4_3_0_UNKNOWN.txt} +0 -0
  147. /cmdbox/licenses/{LICENSE_more-itertools_10_7_0_MIT_License.txt → LICENSE_more-itertools_10_8_0_UNKNOWN.txt} +0 -0
  148. /cmdbox/licenses/{LICENSE_numpy_2_3_2_BSD_License.txt → LICENSE_numpy_2_3_3_BSD_License.txt} +0 -0
  149. /cmdbox/licenses/{LICENSE_prompt_toolkit_3_0_51_BSD_License.txt → LICENSE_prompt_toolkit_3_0_52_BSD_License.txt} +0 -0
  150. /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
  151. /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
  152. /cmdbox/licenses/{LICENSE_pycparser_2_22_BSD_License.txt → LICENSE_pycparser_2_23_BSD_License.txt} +0 -0
  153. /cmdbox/licenses/{LICENSE_pydantic_2_11_7_MIT_License.txt → LICENSE_pydantic_2_11_9_MIT_License.txt} +0 -0
  154. /cmdbox/licenses/{LICENSE_questionary_2_1_0_MIT_License.txt → LICENSE_questionary_2_1_1_MIT_License.txt} +0 -0
  155. /cmdbox/licenses/{LICENSE_requests_2_32_4_Apache_Software_License.txt → LICENSE_requests_2_32_5_Apache_Software_License.txt} +0 -0
  156. /cmdbox/licenses/{LICENSE_sphinx-sitemap_2_7_2_UNKNOWN.txt → LICENSE_sphinx-sitemap_2_8_0_UNKNOWN.txt} +0 -0
  157. /cmdbox/licenses/{LICENSE_starlette_0_47_2_BSD_License.txt → LICENSE_starlette_0_48_0_BSD_License.txt} +0 -0
  158. /cmdbox/licenses/{LICENSE_twine_6_1_0_Apache_Software_License.txt → LICENSE_twine_6_2_0_UNKNOWN.txt} +0 -0
  159. /cmdbox/licenses/{LICENSE_aiohappyeyeballs_2_6_1_Python_Software_Foundation_License.txt → LICENSE_typing_extensions_4_15_0_UNKNOWN.txt} +0 -0
  160. /cmdbox/licenses/{LICENSE_zope_event_5_1_1_Zope_Public_License.txt → LICENSE_zope_event_6_0_Zope_Public_License.txt} +0 -0
  161. /cmdbox/licenses/{LICENSE_zope_interface_7_2_Zope_Public_License.txt → LICENSE_zope_interface_8_0_Zope_Public_License.txt} +0 -0
  162. {cmdbox-0.6.4.2.dist-info → cmdbox-0.6.5.dist-info}/WHEEL +0 -0
  163. {cmdbox-0.6.4.2.dist-info → cmdbox-0.6.5.dist-info}/entry_points.txt +0 -0
  164. {cmdbox-0.6.4.2.dist-info → cmdbox-0.6.5.dist-info}/licenses/LICENSE +0 -0
  165. {cmdbox-0.6.4.2.dist-info → cmdbox-0.6.5.dist-info}/top_level.txt +0 -0
cmdbox/app/app.py CHANGED
@@ -118,6 +118,13 @@ class CmdBoxApp:
118
118
  args = argparse.Namespace(**{k:common.chopdq(v) for k,v in args_dict.items()})
119
119
  eargsparsetime = time.perf_counter()
120
120
 
121
+ if args.debug_attach:
122
+ import debugpy
123
+ debugpy.listen(("", args.debug_attach_port))
124
+ self.default_logger.info(f"Waiting for debugger attach on port {args.debug_attach_port}...")
125
+ debugpy.wait_for_client()
126
+ self.default_logger.info("Debugger attached.")
127
+
121
128
  ret = dict(success=f"Start command. {args}")
122
129
  if args.saveopt:
123
130
  if args.useopt is None:
cmdbox/app/client.py CHANGED
@@ -1,5 +1,5 @@
1
1
  from pathlib import Path
2
- from cmdbox.app import filer
2
+ from cmdbox.app import common, filer
3
3
  from cmdbox.app.commons import convert, redis_client
4
4
  import base64
5
5
  import logging
@@ -196,12 +196,13 @@ class Client(object):
196
196
  if download_file.exists():
197
197
  self.logger.warning(f"download_file {download_file} already exists.")
198
198
  return dict(warn=f"download_file {download_file} already exists.")
199
- with open(download_file, "wb") as f:
199
+ def _wd(f):
200
200
  f.write(base64.b64decode(res_json["success"]["data"]))
201
201
  del res_json["success"]["data"]
202
202
  res_json["success"]["download_file"] = str(download_file.absolute())
203
+ common.save_file(download_file, _wd, mode='wb')
203
204
  return res_json
204
-
205
+
205
206
  def file_upload(self, svpath:str, upload_file:Path, scope:str="client", client_data:Path=None, mkdir:bool=False, orverwrite:bool=False,
206
207
  retry_count:int=3, retry_interval:int=5, timeout:int=60):
207
208
  """
cmdbox/app/common.py CHANGED
@@ -80,8 +80,9 @@ def load_yml(yml_path:Path) -> dict:
80
80
  Returns:
81
81
  dict: 読み込んだYAMLファイルの内容
82
82
  """
83
- with open(yml_path, encoding="utf-8") as f:
83
+ def _r(f):
84
84
  return yaml.safe_load(f)
85
+ return load_file(yml_path, _r)
85
86
 
86
87
  def save_yml(yml_path:Path, data:dict) -> None:
87
88
  """
@@ -91,8 +92,83 @@ def save_yml(yml_path:Path, data:dict) -> None:
91
92
  yml_path (Path): YAMLファイルのパス
92
93
  data (dict): 書き込むデータ
93
94
  """
94
- with open(yml_path, 'w') as f:
95
+ def _w(f):
95
96
  yaml.dump(data, f, default_flow_style=False, sort_keys=False)
97
+ save_file(yml_path, _w)
98
+
99
+ def load_file(file_path:Path, func, mode='r', encoding='utf-8') -> None:
100
+ """
101
+ ファイルを読み込みます。読み込み時に排他ロックします。
102
+
103
+ Args:
104
+ file_path (Path): ファイルのパス
105
+ func: 読み込んだデータを処理する関数
106
+ mode (str, optional): ファイルモード. Defaults to 'r'.
107
+ encoding (str, optional): エンコーディング. Defaults to 'utf-8'.
108
+ """
109
+ lock_file = f'{file_path}.lock'
110
+ try:
111
+ with open(lock_file, 'w') as fd:
112
+ try:
113
+ if sys.platform == 'win32':
114
+ import msvcrt
115
+ msvcrt.locking(fd.fileno(), msvcrt.LK_LOCK, 0)
116
+ else:
117
+ import fcntl
118
+ fcntl.lockf(fd, fcntl.LOCK_EX)
119
+ if 'b' in mode:
120
+ with open(file_path, mode) as f:
121
+ return func(f)
122
+ else:
123
+ with open(file_path, mode, encoding=encoding) as f:
124
+ return func(f)
125
+ finally:
126
+ if sys.platform == 'win32':
127
+ msvcrt.locking(fd.fileno(), msvcrt.LK_UNLCK, 0)
128
+ else:
129
+ fcntl.lockf(fd, fcntl.LOCK_UN)
130
+ finally:
131
+ try:
132
+ os.remove(lock_file)
133
+ except:
134
+ pass
135
+
136
+ def save_file(file_path:Path, func, mode='w', encoding='utf-8') -> None:
137
+ """
138
+ ファイルに書き込みます。書き込み時に排他ロックします。
139
+
140
+ Args:
141
+ file_path (Path): ファイルのパス
142
+ func: 書き込む関数
143
+ mode (str, optional): ファイルモード. Defaults to 'w'.
144
+ encoding (str, optional): エンコーディング. Defaults to 'utf-8'.
145
+ """
146
+ lock_file = f'{file_path}.lock'
147
+ try:
148
+ with open(lock_file, 'w') as fd:
149
+ try:
150
+ if sys.platform == 'win32':
151
+ import msvcrt
152
+ msvcrt.locking(fd.fileno(), msvcrt.LK_LOCK, 0)
153
+ else:
154
+ import fcntl
155
+ fcntl.lockf(fd, fcntl.LOCK_EX)
156
+ if 'b' in mode:
157
+ with open(file_path, mode) as f:
158
+ func(f)
159
+ else:
160
+ with open(file_path, mode, encoding=encoding) as f:
161
+ func(f)
162
+ finally:
163
+ if sys.platform == 'win32':
164
+ msvcrt.locking(fd.fileno(), msvcrt.LK_UNLCK, 0)
165
+ else:
166
+ fcntl.lockf(fd, fcntl.LOCK_UN)
167
+ finally:
168
+ try:
169
+ os.remove(lock_file)
170
+ except:
171
+ pass
96
172
 
97
173
  class CommonValue:
98
174
  _map = dict()
@@ -251,8 +327,7 @@ def load_config(mode:str, debug:bool=False, data=HOME_DIR, webcall:bool=False, v
251
327
  if not log_conf_path.exists():
252
328
  log_conf_path = Path(version.__file__).parent / f"logconf_{ver.__appid__}.yml"
253
329
  log_name = mode
254
- with open(log_conf_path) as f:
255
- log_config = yaml.safe_load(f)
330
+ log_config = load_yml(log_conf_path)
256
331
  std_key = None
257
332
  set_common_value('webcall', webcall)
258
333
  for k, h in log_config['handlers'].items():
@@ -343,8 +418,9 @@ def saveopt(opt:dict, opt_path:Path, webmode:bool=False) -> None:
343
418
  k = r['opt']
344
419
  d = r['default'] if 'default' in r else None
345
420
  opt[k] = d if k not in lopts else lopts.get(k, d)
346
- with open(opt_path, 'w') as f:
421
+ def _w(f):
347
422
  json.dump(opt, f, indent=4, default=default_json_enc)
423
+ save_file(opt_path, _w)
348
424
 
349
425
  def saveuser(user_data:dict, user_path:Path) -> None:
350
426
  """
@@ -552,9 +628,10 @@ def print_format(data:dict, format:bool, tm:float, output_json:str=None, output_
552
628
  pass
553
629
  if output_json is not None:
554
630
  try:
555
- with open(output_json, 'a' if output_json_append else 'w', encoding='utf-8') as f:
631
+ def _w(f):
556
632
  json.dump(data, f, default=default_json_enc, ensure_ascii=False)
557
633
  print('', file=f)
634
+ save_file(Path(output_json), _w, mode='a' if output_json_append else 'w')
558
635
  except Exception as e:
559
636
  pass
560
637
  return txt
@@ -584,8 +661,9 @@ def download_file(url:str, save_path:Path) -> Path:
584
661
  Path: 保存したファイルのパス
585
662
  """
586
663
  r = requests.get(url, stream=True)
587
- with open(save_path, 'wb') as f:
664
+ def _w(f):
588
665
  f.write(r.content)
666
+ save_file(Path(save_path), _w)
589
667
  return save_path
590
668
 
591
669
  def cmd(cmd:str, logger:logging.Logger, slise:int=100, newenv:Dict=None) -> Tuple[int, str, str]:
@@ -99,8 +99,10 @@ def npy2imgfile(npy, output_image_file:Path=None, image_type:str='jpeg') -> byte
99
99
  image_type = 'jpeg' if image_type == 'jpg' else image_type
100
100
  img_byte = img2byte(image, format=image_type)
101
101
  if output_image_file is not None:
102
- with open(output_image_file, 'wb') as f:
102
+ from cmdbox.app import common
103
+ def _w(f):
103
104
  f.write(img_byte)
105
+ common.save_file(output_image_file, _w, mode='wb')
104
106
  return img_byte
105
107
 
106
108
  def bytes2b64str(img:bytes) -> str:
cmdbox/app/edge.py CHANGED
@@ -515,9 +515,9 @@ class Edge(object):
515
515
  except Exception as e:
516
516
  raise HTTPException(status_code=500, detail=f'Failed to get token. {e}')
517
517
 
518
- if not hasattr(self, 'thUvicorn') or not self.thUvicorn.is_alive():
519
- self.thUvicorn = web.ThreadedUvicorn(config=Config(app=fastapi, host='localhost', port=oauth2_port))
520
- self.thUvicorn.start()
518
+ if not hasattr(self, 'thHttp') or not self.thHttp.is_alive():
519
+ self.thHttp = web.ThreadedASGI(config=Config(app=fastapi, host='localhost', port=oauth2_port))
520
+ self.thHttp.start()
521
521
  time.sleep(1)
522
522
 
523
523
  # OAuth2認証のリクエストを送信
@@ -581,9 +581,9 @@ class Edge(object):
581
581
  except Exception as e:
582
582
  raise HTTPException(status_code=500, detail=f'Failed to get token. {e}')
583
583
 
584
- if not hasattr(self, 'thUvicorn') or not self.thUvicorn.is_alive():
585
- self.thUvicorn = web.ThreadedUvicorn(config=Config(app=fastapi, host='localhost', port=oauth2_port))
586
- self.thUvicorn.start()
584
+ if not hasattr(self, 'thHttp') or not self.thHttp.is_alive():
585
+ self.thHttp = web.ThreadedASGI(config=Config(app=fastapi, host='localhost', port=oauth2_port))
586
+ self.thHttp.start()
587
587
  time.sleep(1)
588
588
 
589
589
  # OAuth2認証のリクエストを送信
@@ -652,9 +652,9 @@ class Edge(object):
652
652
  except Exception as e:
653
653
  raise HTTPException(status_code=500, detail=f'Failed to get token. {e}')
654
654
 
655
- if not hasattr(self, 'thUvicorn') or not self.thUvicorn.is_alive():
656
- self.thUvicorn = web.ThreadedUvicorn(self.logger, Config(app=fastapi, host='localhost', port=oauth2_port), {})
657
- self.thUvicorn.start()
655
+ if not hasattr(self, 'thHttp') or not self.thHttp.is_alive():
656
+ self.thHttp = web.ThreadedASGI(config=Config(app=fastapi, host='localhost', port=oauth2_port))
657
+ self.thHttp.start()
658
658
  time.sleep(1)
659
659
 
660
660
  # OAuth2認証のリクエストを送信
@@ -734,9 +734,9 @@ class Edge(object):
734
734
  except Exception as e:
735
735
  raise HTTPException(status_code=500, detail=f'Failed to get token. {e}')
736
736
 
737
- if not hasattr(self, 'thUvicorn') or not self.thUvicorn.is_alive():
738
- self.thUvicorn = web.ThreadedUvicorn(self.logger, Config(app=fastapi, host='localhost', port=saml_port), {})
739
- self.thUvicorn.start()
737
+ if not hasattr(self, 'thHttp') or not self.thHttp.is_alive():
738
+ self.thHttp = web.ThreadedASGI(config=Config(app=fastapi, host='localhost', port=saml_port))
739
+ self.thHttp.start()
740
740
  time.sleep(1)
741
741
 
742
742
  # SAML認証のリクエストを送信
@@ -185,8 +185,9 @@ class VisionInstall(cmdbox_vision_start.VisionStart):
185
185
  _msg = f"Failed to download SAM2 model: {responce.status_code} {responce.reason}. {mv['url']}"
186
186
  logger.error(_msg, exc_info=True)
187
187
  return dict(warn=_msg)
188
- with open(model_file, mode='wb') as f:
188
+ def _wm(f):
189
189
  f.write(responce.content)
190
+ common.save_file(model_file, _wm, mode='wb')
190
191
  #===============================================================
191
192
  # SAM2のpythonライブラリのインストール
192
193
  whl_url = f'git+https://github.com/facebookresearch/sam2.git'