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
@@ -40,9 +40,9 @@ class WebGroupDel(feature.UnsupportEdgeFeature):
40
40
  dict(opt="group_id", type=Options.T_INT, default=None, required=True, multi=False, hide=False, choice=None,
41
41
  description_ja="グループIDを指定します。",
42
42
  description_en="Specify the group ID. Do not duplicate other groups."),
43
- dict(opt="signin_file", type=Options.T_FILE, default=f".{self.ver.__appid__}/user_list.yml", required=True, multi=False, hide=False, choice=None, fileio="in",
44
- description_ja="サインイン可能なユーザーとパスワードを記載したファイルを指定します。省略した時は認証を要求しません。",
45
- description_en="Specify a file containing users and passwords with which they can signin. If omitted, no authentication is required."),
43
+ dict(opt="signin_file", type=Options.T_FILE, default=None, required=True, multi=False, hide=False, choice=None, fileio="in",
44
+ description_ja=f"サインイン可能なユーザーとパスワードを記載したファイルを指定します。通常 '.{self.ver.__appid__}/user_list.yml' を指定します。",
45
+ description_en=f"Specify a file containing users and passwords with which they can signin.Typically, specify '.{self.ver.__appid__}/user_list.yml'."),
46
46
  dict(opt="stdout_log", type=Options.T_BOOL, default=True, required=False, multi=False, hide=True, choice=[True, False],
47
47
  description_ja="GUIモードでのみ使用可能です。コマンド実行時の標準出力をConsole logに出力します。",
48
48
  description_en="Available only in GUI mode. Outputs standard output during command execution to Console log."),
@@ -46,9 +46,9 @@ class WebGroupEdit(feature.UnsupportEdgeFeature):
46
46
  dict(opt="group_parent", type=Options.T_STR, default=None, required=False, multi=False, hide=False, choice=None,
47
47
  description_ja="親グループ名を指定します。",
48
48
  description_en="Specifies the parent group name."),
49
- dict(opt="signin_file", type=Options.T_FILE, default=f".{self.ver.__appid__}/user_list.yml", required=True, multi=False, hide=False, choice=None, fileio="in",
50
- description_ja="サインイン可能なユーザーとパスワードを記載したファイルを指定します。省略した時は認証を要求しません。",
51
- description_en="Specify a file containing users and passwords with which they can signin. If omitted, no authentication is required."),
49
+ dict(opt="signin_file", type=Options.T_FILE, default=None, required=True, multi=False, hide=False, choice=None, fileio="in",
50
+ description_ja=f"サインイン可能なユーザーとパスワードを記載したファイルを指定します。通常 '.{self.ver.__appid__}/user_list.yml' を指定します。",
51
+ description_en=f"Specify a file containing users and passwords with which they can signin.Typically, specify '.{self.ver.__appid__}/user_list.yml'."),
52
52
  dict(opt="stdout_log", type=Options.T_BOOL, default=True, required=False, multi=False, hide=True, choice=[True, False],
53
53
  description_ja="GUIモードでのみ使用可能です。コマンド実行時の標準出力をConsole logに出力します。",
54
54
  description_en="Available only in GUI mode. Outputs standard output during command execution to Console log."),
@@ -40,9 +40,9 @@ class WebGroupList(feature.UnsupportEdgeFeature):
40
40
  dict(opt="group_name", type=Options.T_STR, default=None, required=False, multi=False, hide=False, choice=None,
41
41
  description_ja="グループ名を指定して取得します。省略した時は全てのグループを取得します。",
42
42
  description_en="Retrieved by specifying a group name. If omitted, all groups are retrieved."),
43
- dict(opt="signin_file", type=Options.T_FILE, default=f".{self.ver.__appid__}/user_list.yml", required=True, multi=False, hide=False, choice=None, fileio="in",
44
- description_ja="サインイン可能なユーザーとパスワードを記載したファイルを指定します。省略した時は認証を要求しません。",
45
- description_en="Specify a file containing users and passwords with which they can signin. If omitted, no authentication is required."),
43
+ dict(opt="signin_file", type=Options.T_FILE, default=None, required=True, multi=False, hide=False, choice=None, fileio="in",
44
+ description_ja=f"サインイン可能なユーザーとパスワードを記載したファイルを指定します。通常 '.{self.ver.__appid__}/user_list.yml' を指定します。",
45
+ description_en=f"Specify a file containing users and passwords with which they can signin.Typically, specify '.{self.ver.__appid__}/user_list.yml'."),
46
46
  dict(opt="stdout_log", type=Options.T_BOOL, default=True, required=False, multi=False, hide=True, choice=[True, False],
47
47
  description_ja="GUIモードでのみ使用可能です。コマンド実行時の標準出力をConsole logに出力します。",
48
48
  description_en="Available only in GUI mode. Outputs standard output during command execution to Console log."),
@@ -78,9 +78,9 @@ class WebStart(feature.UnsupportEdgeFeature, agent_base.AgentBase):
78
78
  dict(opt="ssl_ca_certs", type=Options.T_FILE, default=None, required=False, multi=False, hide=True, choice=None, fileio="in",
79
79
  description_ja="SSLサーバーCA証明書ファイルを指定します。",
80
80
  description_en="Specify the SSL server CA certificate file."),
81
- dict(opt="signin_file", type=Options.T_FILE, default=None, required=False, multi=False, hide=True, choice=None, fileio="in",
82
- description_ja="サインイン可能なユーザーとパスワードを記載したファイルを指定します。省略した時は認証を要求しません。",
83
- description_en="Specify a file containing users and passwords with which they can signin. If omitted, no authentication is required."),
81
+ dict(opt="signin_file", type=Options.T_FILE, default=None, required=False, multi=False, hide=False, choice=None, fileio="in",
82
+ description_ja=f"サインイン可能なユーザーとパスワードを記載したファイルを指定します。通常 '.{self.ver.__appid__}/user_list.yml' を指定します。",
83
+ description_en=f"Specify a file containing users and passwords with which they can signin.Typically, specify '.{self.ver.__appid__}/user_list.yml'."),
84
84
  dict(opt="session_domain", type=Options.T_STR, default=None, required=False, multi=False, hide=True, choice=None,
85
85
  description_ja="サインインしたユーザーのセッションが有効なドメインを指定します。",
86
86
  description_en="Specify the domain for which the signed-in user's session is valid."),
@@ -93,12 +93,12 @@ class WebStart(feature.UnsupportEdgeFeature, agent_base.AgentBase):
93
93
  dict(opt="session_timeout", type=Options.T_INT, default="900", required=False, multi=False, hide=True, choice=None,
94
94
  description_ja="サインインしたユーザーのセッションタイムアウトの時間を秒で指定します。",
95
95
  description_en="Specify the session timeout in seconds for signed-in users."),
96
- dict(opt="guvicorn_workers", type=Options.T_INT, default=multiprocessing.cpu_count()*2, required=False, multi=False, hide=True, choice=None,
97
- description_ja="guvicornワーカー数を指定します。Linux環境でのみ有効です。-1又は未指定の場合はCPU数の2倍を使用します。",
98
- description_en="Specifies the number of guvicorn workers, valid only in Linux environment. If -1 or unspecified, twice the number of CPUs is used."),
99
- dict(opt="guvicorn_timeout", type=Options.T_INT, default=30, required=False, multi=False, hide=True, choice=None,
100
- description_ja="guvicornワーカーのタイムアウトの時間を秒で指定します。",
101
- description_en="Specify the timeout duration of the guvicorn worker in seconds."),
96
+ dict(opt="gunicorn_workers", type=Options.T_INT, default=multiprocessing.cpu_count()*2, required=False, multi=False, hide=True, choice=None,
97
+ description_ja="gunicornワーカー数を指定します。Linux環境でのみ有効です。-1又は未指定の場合はCPU数の2倍を使用します。",
98
+ description_en="Specifies the number of gunicorn workers, valid only in Linux environment. If -1 or unspecified, twice the number of CPUs is used."),
99
+ dict(opt="gunicorn_timeout", type=Options.T_INT, default=30, required=False, multi=False, hide=True, choice=None,
100
+ description_ja="gunicornワーカーのタイムアウトの時間を秒で指定します。",
101
+ description_en="Specify the timeout duration of the gunicorn worker in seconds."),
102
102
  dict(opt="client_only", type=Options.T_BOOL, default=False, required=False, multi=False, hide=True, choice=[True, False],
103
103
  description_ja="サーバーへの接続を行わないようにします。",
104
104
  description_en="Do not make connections to the server."),
@@ -232,5 +232,5 @@ class WebStart(feature.UnsupportEdgeFeature, agent_base.AgentBase):
232
232
  ssl_cert=args.ssl_cert, ssl_key=args.ssl_key, ssl_keypass=args.ssl_keypass, ssl_ca_certs=args.ssl_ca_certs,
233
233
  session_domain=args.session_domain, session_path=args.session_path,
234
234
  session_secure=args.session_secure, session_timeout=args.session_timeout,
235
- outputs_key=args.outputs_key, guvicorn_workers=args.guvicorn_workers, guvicorn_timeout=args.guvicorn_timeout,
235
+ outputs_key=args.outputs_key, gunicorn_workers=args.gunicorn_workers, gunicorn_timeout=args.gunicorn_timeout,
236
236
  agent_runner=agent_runner, mcp=mcp,)
@@ -55,9 +55,9 @@ class WebUserAdd(feature.UnsupportEdgeFeature):
55
55
  dict(opt="user_group", type=Options.T_STR, default=None, required=True, multi=True, hide=False, choice=None,
56
56
  description_ja="ユーザーが所属するグループを指定します。",
57
57
  description_en="Specifies the groups to which the user belongs."),
58
- dict(opt="signin_file", type=Options.T_FILE, default=f".{self.ver.__appid__}/user_list.yml", required=True, multi=False, hide=False, choice=None, fileio="in",
59
- description_ja="サインイン可能なユーザーとパスワードを記載したファイルを指定します。省略した時は認証を要求しません。",
60
- description_en="Specify a file containing users and passwords with which they can signin. If omitted, no authentication is required."),
58
+ dict(opt="signin_file", type=Options.T_FILE, default=None, required=True, multi=False, hide=False, choice=None, fileio="in",
59
+ description_ja=f"サインイン可能なユーザーとパスワードを記載したファイルを指定します。通常 '.{self.ver.__appid__}/user_list.yml' を指定します。",
60
+ description_en=f"Specify a file containing users and passwords with which they can signin.Typically, specify '.{self.ver.__appid__}/user_list.yml'."),
61
61
  dict(opt="stdout_log", type=Options.T_BOOL, default=True, required=False, multi=False, hide=True, choice=[True, False],
62
62
  description_ja="GUIモードでのみ使用可能です。コマンド実行時の標準出力をConsole logに出力します。",
63
63
  description_en="Available only in GUI mode. Outputs standard output during command execution to Console log."),
@@ -40,9 +40,9 @@ class WebUserDel(feature.UnsupportEdgeFeature):
40
40
  dict(opt="user_id", type=Options.T_INT, default=None, required=True, multi=False, hide=False, choice=None,
41
41
  description_ja="ユーザーIDを指定します。",
42
42
  description_en="Specify the user ID."),
43
- dict(opt="signin_file", type=Options.T_FILE, default=f".{self.ver.__appid__}/user_list.yml", required=True, multi=False, hide=False, choice=None, fileio="in",
44
- description_ja="サインイン可能なユーザーとパスワードを記載したファイルを指定します。省略した時は認証を要求しません。",
45
- description_en="Specify a file containing users and passwords with which they can signin. If omitted, no authentication is required."),
43
+ dict(opt="signin_file", type=Options.T_FILE, default=None, required=True, multi=False, hide=False, choice=None, fileio="in",
44
+ description_ja=f"サインイン可能なユーザーとパスワードを記載したファイルを指定します。通常 '.{self.ver.__appid__}/user_list.yml' を指定します。",
45
+ description_en=f"Specify a file containing users and passwords with which they can signin.Typically, specify '.{self.ver.__appid__}/user_list.yml'."),
46
46
  dict(opt="stdout_log", type=Options.T_BOOL, default=True, required=False, multi=False, hide=True, choice=[True, False],
47
47
  description_ja="GUIモードでのみ使用可能です。コマンド実行時の標準出力をConsole logに出力します。",
48
48
  description_en="Available only in GUI mode. Outputs standard output during command execution to Console log."),
@@ -55,9 +55,9 @@ class WebUserEdit(feature.UnsupportEdgeFeature):
55
55
  dict(opt="user_group", type=Options.T_STR, default=None, required=True, multi=True, hide=False, choice=None,
56
56
  description_ja="ユーザーが所属するグループを指定します。",
57
57
  description_en="Specifies the groups to which the user belongs."),
58
- dict(opt="signin_file", type=Options.T_FILE, default=f".{self.ver.__appid__}/user_list.yml", required=True, multi=False, hide=False, choice=None, fileio="in",
59
- description_ja="サインイン可能なユーザーとパスワードを記載したファイルを指定します。省略した時は認証を要求しません。",
60
- description_en="Specify a file containing users and passwords with which they can signin. If omitted, no authentication is required."),
58
+ dict(opt="signin_file", type=Options.T_FILE, default=None, required=True, multi=False, hide=False, choice=None, fileio="in",
59
+ description_ja=f"サインイン可能なユーザーとパスワードを記載したファイルを指定します。通常 '.{self.ver.__appid__}/user_list.yml' を指定します。",
60
+ description_en=f"Specify a file containing users and passwords with which they can signin.Typically, specify '.{self.ver.__appid__}/user_list.yml'."),
61
61
  dict(opt="stdout_log", type=Options.T_BOOL, default=True, required=False, multi=False, hide=True, choice=[True, False],
62
62
  description_ja="GUIモードでのみ使用可能です。コマンド実行時の標準出力をConsole logに出力します。",
63
63
  description_en="Available only in GUI mode. Outputs standard output during command execution to Console log."),
@@ -40,9 +40,9 @@ class WebUserList(feature.UnsupportEdgeFeature):
40
40
  dict(opt="user_name", type=Options.T_STR, default=None, required=False, multi=False, hide=False, choice=None,
41
41
  description_ja="ユーザー名を指定して取得します。省略した時は全てのユーザーを取得します。",
42
42
  description_en="Retrieved by specifying a user name. If omitted, all users are retrieved."),
43
- dict(opt="signin_file", type=Options.T_FILE, default=f".{self.ver.__appid__}/user_list.yml", required=True, multi=False, hide=False, choice=None, fileio="in",
44
- description_ja="サインイン可能なユーザーとパスワードを記載したファイルを指定します。省略した時は認証を要求しません。",
45
- description_en="Specify a file containing users and passwords with which they can signin. If omitted, no authentication is required."),
43
+ dict(opt="signin_file", type=Options.T_FILE, default=None, required=True, multi=False, hide=False, choice=None, fileio="in",
44
+ description_ja=f"サインイン可能なユーザーとパスワードを記載したファイルを指定します。通常 '.{self.ver.__appid__}/user_list.yml' を指定します。",
45
+ description_en=f"Specify a file containing users and passwords with which they can signin.Typically, specify '.{self.ver.__appid__}/user_list.yml'."),
46
46
  dict(opt="stdout_log", type=Options.T_BOOL, default=True, required=False, multi=False, hide=True, choice=[True, False],
47
47
  description_ja="GUIモードでのみ使用可能です。コマンド実行時の標準出力をConsole logに出力します。",
48
48
  description_en="Available only in GUI mode. Outputs standard output during command execution to Console log."),
@@ -34,16 +34,14 @@ class ExecCmd(cmdbox_web_load_cmd.LoadCmd):
34
34
  raise HTTPException(status_code=401, detail=self.DEFAULT_401_MESSAGE)
35
35
  opt = None
36
36
  content_type = req.headers.get('content-type')
37
- def _marge_opt(opt, param):
38
- for k in opt.keys():
39
- if k in param: opt[k] = param[k]
37
+ def _marge_opt(opt:Dict[str, Any], param:Dict[str, Any]) -> Dict[str, Any]:
38
+ opt.update(param)
40
39
  return opt
40
+ opt_def = self.load_cmd(web, title)
41
41
  if content_type is None:
42
- opt = self.load_cmd(web, title)
43
- opt = _marge_opt(opt, req.query_params)
42
+ opt = _marge_opt(opt_def, req.query_params)
44
43
  elif content_type.startswith('multipart/form-data'):
45
- opt = self.load_cmd(web, title)
46
- opt = _marge_opt(opt, req.query_params)
44
+ opt = _marge_opt(opt_def, req.query_params)
47
45
  form = await req.form()
48
46
  #files = {key: value for key, value in form.multi_items() if isinstance(value, UploadFile)}
49
47
  for key, fv in form.multi_items():
@@ -52,13 +50,12 @@ class ExecCmd(cmdbox_web_load_cmd.LoadCmd):
52
50
  if key == 'input_file': opt['stdin'] = False
53
51
  elif content_type.startswith('application/json'):
54
52
  opt = await req.json()
53
+ opt = _marge_opt(opt_def, opt)
55
54
  elif content_type.startswith('application/octet-stream'):
56
- opt = self.load_cmd(web, title)
57
- opt = _marge_opt(opt, req.query_params)
55
+ opt = _marge_opt(opt_def, req.query_params)
58
56
  opt['_stdin_body'] = await req.body()
59
57
  else:
60
- opt = self.load_cmd(web, title)
61
- opt = _marge_opt(opt, req.query_params)
58
+ opt = _marge_opt(opt_def, req.query_params)
62
59
  if 'mode' not in opt or 'cmd' not in opt:
63
60
  raise HTTPException(status_code=404, detail='mode or cmd is not found.')
64
61
  opt['capture_stdout'] = nothread = True
@@ -147,9 +144,10 @@ class ExecCmd(cmdbox_web_load_cmd.LoadCmd):
147
144
  if 'port' in opt: opt['port'] = web.redis_port
148
145
  if 'password' in opt: opt['password'] = web.redis_password
149
146
  if 'svname' in opt: opt['svname'] = web.svname
150
- if req.session is not None and 'signin' in req.session and req.session['signin'] is not None:
151
- if 'clmsg_id' in req.session['signin'] and req.session['signin']['clmsg_id'] is not None:
152
- opt['clmsg_id'] = req.session['signin']['clmsg_id']
147
+ if not 'clmsg_id' in opt: # optに含まれる場合は処理しない
148
+ if req.session is not None and 'signin' in req.session and req.session['signin'] is not None:
149
+ if 'clmsg_id' in req.session['signin'] and req.session['signin']['clmsg_id'] is not None:
150
+ opt['clmsg_id'] = req.session['signin']['clmsg_id']
153
151
  ap.sv = None
154
152
  ap.cl = None
155
153
  ap.web = None
cmdbox/app/filer.py CHANGED
@@ -206,13 +206,15 @@ class Filer(object):
206
206
  try:
207
207
  mime_type, encoding = mimetypes.guess_type(str(abspath))
208
208
  fname = abspath.name
209
- with open(abspath, "rb") as f:
209
+ def _r(f):
210
210
  fd = f.read()
211
211
  if mime_type is not None and mime_type != 'image/svg+xml' and mime_type.startswith('image') and img_thumbnail > 0:
212
212
  img = convert.imgbytes2thumbnail(fd, (img_thumbnail, img_thumbnail))
213
213
  fd = convert.img2byte(img, "jpeg")
214
214
  fname = f"{fname}.thumbnail.jpg"
215
215
  data = convert.bytes2b64str(fd)
216
+ return data
217
+ data = common.load_file(abspath, _r, mode='rb')
216
218
  return self.RESP_SUCCESS, dict(success=dict(name=fname, data=data, mime_type=mime_type))
217
219
  except Exception as e:
218
220
  self.logger.warning(f"Failed to download {abspath}. {e}")
@@ -252,8 +254,9 @@ class Filer(object):
252
254
  try:
253
255
  if mkdir:
254
256
  save_path.parent.mkdir(parents=True, exist_ok=True)
255
- with open(save_path, "wb") as f:
257
+ def _w(f):
256
258
  f.write(file_data)
259
+ common.save_file(Path(save_path), _w, mode='wb')
257
260
  return self.RESP_SUCCESS, dict(success=f"Uploaded {save_path}")
258
261
  except Exception as e:
259
262
  self.logger.warning(f"Failed to upload {save_path}. {e}")
cmdbox/app/mcp.py CHANGED
@@ -186,8 +186,9 @@ class Mcp:
186
186
  if args.llmmodel is None: raise ValueError("llmmodel is required.")
187
187
  if args.llmlocation is None: raise ValueError("llmlocation is required.")
188
188
  if args.llmsvaccountfile is not None:
189
- with open(args.llmsvaccountfile, "r", encoding="utf-8") as f:
190
- vertex_credentials = json.load(f)
189
+ def _r(f):
190
+ return json.load(f)
191
+ vertex_credentials = common.load_file(Path(args.llmsvaccountfile), _r, mode='r')
191
192
  elif args.llmprojectid is None: raise ValueError("llmprojectid is required.")
192
193
  agent = Agent(
193
194
  name=args.agent_name,
@@ -353,7 +354,7 @@ class Mcp:
353
354
  func_txt += f' signin_data = signin.Signin.load_signin_file(args.signin_file)\n'
354
355
  func_txt += f' req = scope["req"] if scope["req"] is not None else scope["websocket"]\n'
355
356
  func_txt += f' sign = signin.Signin._check_signin(req, scope["res"], signin_data, logger)\n'
356
- func_txt += f' if sign is not None:\n'
357
+ func_txt += f' if sign is not None or "signin" not in req.session or "groups" not in req.session["signin"]:\n'
357
358
  func_txt += f' logger.warning("Unable to execute command because authentication information cannot be obtained")\n'
358
359
  func_txt += f' return dict(warn="Unable to execute command because authentication information cannot be obtained")\n'
359
360
  func_txt += f' groups = req.session["signin"]["groups"]\n'
cmdbox/app/options.py CHANGED
@@ -267,6 +267,14 @@ class Options:
267
267
  short="d", type=Options.T_BOOL, default=False, required=False, multi=False, hide=True, choice=[True, False],
268
268
  description_ja="デバックモードで起動します。",
269
269
  description_en="Starts in debug mode.")
270
+ self._options["debug_attach"] = dict(
271
+ short="debug_attach", type=Options.T_BOOL, default=False, required=False, multi=False, hide=True, choice=[True, False],
272
+ description_ja="デバックプロセスへのアタッチを有効にするかどうかを指定します。",
273
+ description_en="Specify whether to enable attaching to the debug process.")
274
+ self._options["debug_attach_port"] = dict(
275
+ short="debug_attach_port", type=Options.T_INT, default=5678, required=False, multi=False, hide=True, choice=None,
276
+ description_ja="デバックプロセスにアタッチするポート番号を指定します。",
277
+ description_en="Specify the port number to attach to the debug process.")
270
278
  self._options["format"] = dict(
271
279
  short="f", type=Options.T_BOOL, default=None, required=False, multi=False, hide=True,
272
280
  description_ja="処理結果を見やすい形式で出力します。指定しない場合json形式で出力します。",
cmdbox/app/web.py CHANGED
@@ -719,7 +719,7 @@ class Web:
719
719
  def start(self, allow_host:str="0.0.0.0", listen_port:int=8081, ssl_listen_port:int=8443,
720
720
  ssl_cert:Path=None, ssl_key:Path=None, ssl_keypass:str=None, ssl_ca_certs:Path=None,
721
721
  session_domain:str=None, session_path:str='/', session_secure:bool=False, session_timeout:int=900, outputs_key:List[str]=[],
722
- guvicorn_workers:int=-1, guvicorn_timeout:int=30,
722
+ gunicorn_workers:int=-1, gunicorn_timeout:int=30,
723
723
  agent_runner=None, mcp=None,):
724
724
  """
725
725
  Webサーバを起動する
@@ -737,8 +737,8 @@ class Web:
737
737
  session_secure (bool, optional): セッションセキュア. Defaults to False.
738
738
  session_timeout (int, optional): セッションタイムアウト. Defaults to 900.
739
739
  outputs_key (list, optional): 出力キー. Defaults to [].
740
- guvicorn_workers (int, optional): Gunicornワーカー数. Defaults to -1.
741
- guvicorn_timeout (int, optional): Gunicornタイムアウト. Defaults to 30.
740
+ gunicorn_workers (int, optional): Gunicornワーカー数. Defaults to -1.
741
+ gunicorn_timeout (int, optional): Gunicornタイムアウト. Defaults to 30.
742
742
  agent_runner (Runner, optional): エージェントランナー. Defaults to None.
743
743
  mcp (MCP, optional): MCP. Defaults to None.
744
744
  """
@@ -754,8 +754,8 @@ class Web:
754
754
  self.session_path = session_path
755
755
  self.session_secure = session_secure
756
756
  self.session_timeout = session_timeout
757
- self.guvicorn_workers = guvicorn_workers
758
- self.guvicorn_timeout = guvicorn_timeout
757
+ self.gunicorn_workers = gunicorn_workers
758
+ self.gunicorn_timeout = gunicorn_timeout
759
759
  self.agent_runner = agent_runner
760
760
  self.mcp = mcp
761
761
  if self.logger.level == logging.DEBUG:
@@ -771,8 +771,8 @@ class Web:
771
771
  self.logger.debug(f"web start parameter: session_path={self.session_path}")
772
772
  self.logger.debug(f"web start parameter: session_secure={self.session_secure}")
773
773
  self.logger.debug(f"web start parameter: session_timeout={self.session_timeout}")
774
- self.logger.debug(f"web start parameter: guvicorn_worker={self.guvicorn_workers}")
775
- self.logger.debug(f"web start parameter: guvicorn_timeout={self.guvicorn_timeout}")
774
+ self.logger.debug(f"web start parameter: gunicorn_workers={self.gunicorn_workers}")
775
+ self.logger.debug(f"web start parameter: gunicorn_timeout={self.gunicorn_timeout}")
776
776
  self.logger.debug(f"web start parameter: agent_runner={self.agent_runner}")
777
777
  self.logger.debug(f"web start parameter: mcp={self.mcp}")
778
778
 
@@ -894,21 +894,22 @@ class Web:
894
894
  https_config = Config(app=app, host=self.allow_host, port=self.ssl_listen_port,
895
895
  ssl_certfile=self.ssl_cert, ssl_keyfile=self.ssl_key,
896
896
  ssl_keyfile_password=self.ssl_keypass, ssl_ca_certs=self.ssl_ca_certs)
897
- th_ssl = ThreadedUvicorn(self.logger, config=https_config,
898
- guvicorn_config=dict(workers=self.guvicorn_workers, timeout=self.guvicorn_timeout))
897
+ th_ssl = ThreadedASGI(app, self.logger, config=https_config,
898
+ gunicorn_config=dict(workers=self.gunicorn_workers, timeout=self.gunicorn_timeout))
899
899
  th_ssl.start()
900
900
  browser_port = self.ssl_listen_port
901
901
  else:
902
902
  http_config = Config(app=app, host=self.allow_host, port=self.listen_port)
903
- th = ThreadedUvicorn(self.logger, config=http_config,
904
- guvicorn_config=dict(workers=self.guvicorn_workers, timeout=self.guvicorn_timeout))
903
+ th = ThreadedASGI(app, self.logger, config=http_config,
904
+ gunicorn_config=dict(workers=self.gunicorn_workers, timeout=self.gunicorn_timeout))
905
905
  th.start()
906
906
  browser_port = self.listen_port
907
907
  try:
908
908
  if self.gui_mode:
909
909
  webbrowser.open(f'http://localhost:{browser_port}/gui')
910
- with open("web.pid", mode="w", encoding="utf-8") as f:
910
+ def _w(f):
911
911
  f.write(str(os.getpid()))
912
+ common.save_file("web.pid", _w)
912
913
  while self.is_running:
913
914
  gevent.sleep(1)
914
915
  if th is not None:
@@ -926,35 +927,42 @@ class Web:
926
927
  Webサーバを停止する
927
928
  """
928
929
  try:
929
- with open("web.pid", mode="r", encoding="utf-8") as f:
930
+ def _r(f):
930
931
  pid = f.read()
931
932
  if pid != "":
932
- os.kill(int(pid), signal.CTRL_C_EVENT)
933
+ if platform.system() == "Windows":
934
+ os.system(f"taskkill /F /PID {pid}")
935
+ else:
936
+ os.kill(int(pid), signal.CTRL_C_EVENT)
933
937
  self.logger.info(f"Stop web.")
934
938
  else:
935
939
  self.logger.warning(f"pid is empty.")
940
+ common.load_file("web.pid", _r)
936
941
  Path("web.pid").unlink(missing_ok=True)
937
942
  except:
938
943
  traceback.print_exc()
939
944
  finally:
940
945
  self.logger.info(f"Exit web.")
941
946
 
942
- class ThreadedUvicorn:
943
- def __init__(self, logger:logging.Logger, config:Config, guvicorn_config:Dict[str, Any]=None, force_uvicorn:bool=False):
947
+ class ThreadedASGI:
948
+ def __init__(self, app:FastAPI, logger:logging.Logger, config:Config, gunicorn_config:Dict[str, Any]=None, force_single:bool=False):
949
+ self.app = app
944
950
  self.logger = logger
945
- self.guvicorn_config = guvicorn_config
946
- self.force_uvicorn = True if platform.system() == "Windows" else force_uvicorn
951
+ self.config = config
952
+ self.gunicorn_config = gunicorn_config
953
+ # windows環境下ではシングルプロセスで動作させる
954
+ self.force_single = True if platform.system() == "Windows" else force_single
947
955
  # loggerの設定
948
956
  common.reset_logger("uvicorn")
949
957
  common.reset_logger("uvicorn.error")
950
958
  common.reset_logger("uvicorn.access")
951
959
  #common.reset_logger("gunicorn.error")
952
960
  #common.reset_logger("gunicorn.access")
953
- if self.force_uvicorn:
961
+ if self.force_single:
962
+ config.ws = "wsproto"
954
963
  self.server = uvicorn.Server(config)
955
964
  self.thread = RaiseThread(daemon=True, target=self.server.run)
956
965
  else:
957
-
958
966
  from gunicorn.app.wsgiapp import WSGIApplication
959
967
  class App(WSGIApplication):
960
968
  def __init__(self, app, options):
@@ -969,29 +977,28 @@ class ThreadedUvicorn:
969
977
  def load(self):
970
978
  return self.application
971
979
  opt = dict(bind=f"{config.host}:{config.port}",
972
- worker_class="uvicorn.workers.UvicornWorker",
980
+ worker_class="cmdbox.app.web.ASGIWorker",
973
981
  access_log_format='[%(t)s] %(p)s %(l)s %(h)s "%(r)s" %(s)s',
974
982
  loglevel=logging.getLevelName(self.logger.level),
975
983
  keyfile=config.ssl_keyfile, certfile=config.ssl_certfile,
976
984
  ca_certs=config.ssl_ca_certs, keyfile_password=config.ssl_keyfile_password,
977
985
  limit_request_line=8190, limit_request_fields=100, limit_request_field_size=8190)
978
986
 
979
- self.guvicorn_config = self.guvicorn_config or {}
980
- if 'workers' not in self.guvicorn_config:
981
- self.guvicorn_config['workers'] = None
982
- if self.guvicorn_config['workers'] is None or self.guvicorn_config['workers'] <= 0:
983
- self.guvicorn_config['workers'] = multiprocessing.cpu_count()*2
984
- if 'timeout' not in self.guvicorn_config:
985
- self.guvicorn_config['timeout'] = None
986
- if self.guvicorn_config['timeout'] is None or self.guvicorn_config['timeout'] <= 0:
987
- self.guvicorn_config['timeout'] = 30
987
+ self.gunicorn_config = self.gunicorn_config or {}
988
+ if 'workers' not in self.gunicorn_config:
989
+ self.gunicorn_config['workers'] = None
990
+ if self.gunicorn_config['workers'] is None or self.gunicorn_config['workers'] <= 0:
991
+ self.gunicorn_config['workers'] = multiprocessing.cpu_count()*2
992
+ if 'timeout' not in self.gunicorn_config:
993
+ self.gunicorn_config['timeout'] = None
994
+ if self.gunicorn_config['timeout'] is None or self.gunicorn_config['timeout'] <= 0:
995
+ self.gunicorn_config['timeout'] = 30
988
996
 
989
- opt = {**opt, **self.guvicorn_config}
990
- self.server = App(config.app, opt)
991
- #self.thread = RaiseThread(daemon=True, target=self.server.run)
997
+ opt = {**opt, **self.gunicorn_config}
998
+ self.server = App(app, opt)
992
999
 
993
1000
  def start(self):
994
- if self.force_uvicorn:
1001
+ if self.force_single:
995
1002
  asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
996
1003
  self.thread.start()
997
1004
  asyncio.run(self.wait_for_started())
@@ -1005,7 +1012,7 @@ class ThreadedUvicorn:
1005
1012
  await asyncio.sleep(0.1)
1006
1013
 
1007
1014
  def stop(self):
1008
- if self.force_uvicorn:
1015
+ if self.force_single:
1009
1016
  if self.thread.is_alive():
1010
1017
  self.server.should_exit = True
1011
1018
  self.thread.raise_exception()
@@ -1015,7 +1022,7 @@ class ThreadedUvicorn:
1015
1022
  self.server.started = False
1016
1023
 
1017
1024
  def is_alive(self):
1018
- if self.force_uvicorn:
1025
+ if self.force_single:
1019
1026
  return self.thread.is_alive()
1020
1027
  else:
1021
1028
  return self.server.started
@@ -1044,3 +1051,10 @@ class RaiseThread(threading.Thread):
1044
1051
  0
1045
1052
  )
1046
1053
  print('Failure in raising exception')
1054
+
1055
+ if platform.system() != "Windows":
1056
+ from uvicorn.workers import UvicornWorker
1057
+ class ASGIWorker(UvicornWorker):
1058
+ def __init__(self, *args: Any, **kwargs: Any) -> None:
1059
+ super().__init__(*args, **kwargs)
1060
+ self.config.ws = "wsproto"
@@ -0,0 +1,22 @@
1
+ Copyright P G Jones 2018.
2
+
3
+ Permission is hereby granted, free of charge, to any person
4
+ obtaining a copy of this software and associated documentation
5
+ files (the "Software"), to deal in the Software without
6
+ restriction, including without limitation the rights to use,
7
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the
9
+ Software is furnished to do so, subject to the following
10
+ conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
@@ -3,7 +3,7 @@ Except when otherwise stated (look for LICENSE files in directories or
3
3
  information at the beginning of each file) all software and
4
4
  documentation is licensed as follows:
5
5
 
6
- The MIT License
6
+ MIT No Attribution
7
7
 
8
8
  Permission is hereby granted, free of charge, to any person
9
9
  obtaining a copy of this software and associated documentation
@@ -11,10 +11,7 @@ documentation is licensed as follows:
11
11
  restriction, including without limitation the rights to use,
12
12
  copy, modify, merge, publish, distribute, sublicense, and/or
13
13
  sell copies of the Software, and to permit persons to whom the
14
- Software is furnished to do so, subject to the following conditions:
15
-
16
- The above copyright notice and this permission notice shall be included
17
- in all copies or substantial portions of the Software.
14
+ Software is furnished to do so.
18
15
 
19
16
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20
17
  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
@@ -1,4 +1,6 @@
1
- Copyright (c) 2022 Julian Berman
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015-2020 Cory Benfield and contributors
2
4
 
3
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
4
6
  of this software and associated documentation files (the "Software"), to deal
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2014 litl, LLC.
3
+ Copyright (c) 2014 Cory Benfield
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2013-2025 Sebastian Bank
3
+ Copyright (c) 2014 Cory Benfield
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -1,4 +1,4 @@
1
- Copyright (c) 2013 Julian Berman
1
+ Copyright (c) 2015 Cory Benfield
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  of this software and associated documentation files (the "Software"), to deal
@@ -16,4 +16,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
16
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
17
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
18
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
- THE SOFTWARE.
19
+ THE SOFTWARE.