matlab-proxy 0.22.0__py3-none-any.whl → 0.23.3__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 matlab-proxy might be problematic. Click here for more details.
- matlab_proxy/app_state.py +42 -47
- matlab_proxy/default_configuration.py +39 -4
- matlab_proxy/gui/asset-manifest.json +6 -6
- matlab_proxy/gui/index.html +1 -1
- matlab_proxy/gui/static/css/{main.6cd0caba.css → main.efa05ff9.css} +2 -2
- matlab_proxy/gui/static/css/{main.6cd0caba.css.map → main.efa05ff9.css.map} +1 -1
- matlab_proxy/gui/static/js/{main.77e6cbaf.js → main.ce0f5505.js} +3 -3
- matlab_proxy/gui/static/js/main.ce0f5505.js.map +1 -0
- matlab_proxy/settings.py +1 -1
- matlab_proxy/util/__init__.py +1 -1
- matlab_proxy/util/mwi/validators.py +17 -16
- {matlab_proxy-0.22.0.dist-info → matlab_proxy-0.23.3.dist-info}/METADATA +2 -2
- {matlab_proxy-0.22.0.dist-info → matlab_proxy-0.23.3.dist-info}/RECORD +27 -27
- {matlab_proxy-0.22.0.dist-info → matlab_proxy-0.23.3.dist-info}/WHEEL +1 -1
- matlab_proxy_manager/lib/api.py +90 -49
- matlab_proxy_manager/storage/server.py +2 -2
- matlab_proxy_manager/utils/helpers.py +38 -21
- matlab_proxy_manager/web/app.py +92 -49
- matlab_proxy_manager/web/monitor.py +1 -2
- matlab_proxy_manager/web/watcher.py +11 -0
- tests/unit/test_app.py +1 -0
- tests/unit/test_app_state.py +79 -4
- tests/unit/util/mwi/test_validators.py +4 -5
- matlab_proxy/gui/static/js/main.77e6cbaf.js.map +0 -1
- /matlab_proxy/gui/static/js/{main.77e6cbaf.js.LICENSE.txt → main.ce0f5505.js.LICENSE.txt} +0 -0
- {matlab_proxy-0.22.0.dist-info → matlab_proxy-0.23.3.dist-info}/LICENSE.md +0 -0
- {matlab_proxy-0.22.0.dist-info → matlab_proxy-0.23.3.dist-info}/entry_points.txt +0 -0
- {matlab_proxy-0.22.0.dist-info → matlab_proxy-0.23.3.dist-info}/top_level.txt +0 -0
matlab_proxy/settings.py
CHANGED
|
@@ -103,7 +103,7 @@ def get_matlab_executable_and_root_path():
|
|
|
103
103
|
# Note, error messages are formatted as multi-line strings and the front end displays them as is.
|
|
104
104
|
error_message = "Unable to find MATLAB on the system PATH. Add MATLAB to the system PATH, and restart matlab-proxy."
|
|
105
105
|
|
|
106
|
-
logger.
|
|
106
|
+
logger.error(error_message)
|
|
107
107
|
raise MatlabInstallError(error_message)
|
|
108
108
|
|
|
109
109
|
|
matlab_proxy/util/__init__.py
CHANGED
|
@@ -179,30 +179,31 @@ def validate_env_config(config):
|
|
|
179
179
|
Returns:
|
|
180
180
|
Dict: Containing data specific to the environment in which MATLAB proxy is being used in.
|
|
181
181
|
"""
|
|
182
|
-
|
|
182
|
+
from matlab_proxy.default_configuration import get_required_config
|
|
183
|
+
|
|
184
|
+
available_configs: dict = __get_configs()
|
|
183
185
|
config = config.lower()
|
|
184
186
|
|
|
185
187
|
# Check if supplied config is present in the available configs
|
|
186
188
|
if config in available_configs:
|
|
187
|
-
# Check if all keys are present in the supplied config
|
|
188
|
-
default_config_keys = available_configs[
|
|
189
|
-
matlab_proxy.get_default_config_name()
|
|
190
|
-
].keys()
|
|
191
189
|
env_config = available_configs[config]
|
|
190
|
+
required_keys = get_required_config()
|
|
192
191
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
192
|
+
# Check if all required keys are present in the supplied config
|
|
193
|
+
valid = all(key in env_config for key in required_keys)
|
|
194
|
+
if not valid:
|
|
195
|
+
error_message = (
|
|
196
|
+
f"Required key/s missing in the provided {config} configuration"
|
|
197
|
+
)
|
|
198
|
+
logger.error(error_message)
|
|
199
|
+
raise FatalError(error_message)
|
|
198
200
|
|
|
199
|
-
logger.debug(
|
|
201
|
+
logger.debug("Successfully validated provided %s configuration", config)
|
|
200
202
|
return env_config
|
|
201
203
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
raise FatalError(error_message)
|
|
204
|
+
error_message = f"{config} is not a valid config. Available configs are : {list(available_configs.keys())}"
|
|
205
|
+
logger.error(error_message)
|
|
206
|
+
raise FatalError(error_message)
|
|
206
207
|
|
|
207
208
|
|
|
208
209
|
def __get_configs():
|
|
@@ -325,7 +326,7 @@ def validate_matlab_root_path(matlab_root: Path, is_custom_matlab_root: bool):
|
|
|
325
326
|
|
|
326
327
|
try:
|
|
327
328
|
__validate_if_paths_exist([matlab_root])
|
|
328
|
-
logger.
|
|
329
|
+
logger.debug(
|
|
329
330
|
f"MATLAB root path: {matlab_root} exists, continuing to verify its validity..."
|
|
330
331
|
)
|
|
331
332
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: matlab-proxy
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.23.3
|
|
4
4
|
Summary: Python® package enables you to launch MATLAB® and access it from a web browser.
|
|
5
5
|
Home-page: https://github.com/mathworks/matlab-proxy/
|
|
6
6
|
Author: The MathWorks, Inc.
|
|
@@ -17,7 +17,7 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
17
17
|
Classifier: Programming Language :: Python :: 3.11
|
|
18
18
|
Requires-Python: ~=3.8
|
|
19
19
|
Description-Content-Type: text/markdown
|
|
20
|
-
Requires-Dist: aiohttp
|
|
20
|
+
Requires-Dist: aiohttp<=3.10.5,>=3.7.4
|
|
21
21
|
Requires-Dist: aiohttp-session[secure]
|
|
22
22
|
Requires-Dist: importlib-metadata
|
|
23
23
|
Requires-Dist: importlib-resources
|
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
matlab_proxy/__init__.py,sha256=6cwi8buKCMtw9OeWaOYUHEoqwl5MyJ_s6GxgNuqPuNg,1673
|
|
2
2
|
matlab_proxy/app.py,sha256=7BsHSM3PxTjN6eN10HLj74Y1wtu-Gl92g1RLbaTGz9U,34698
|
|
3
|
-
matlab_proxy/app_state.py,sha256=
|
|
3
|
+
matlab_proxy/app_state.py,sha256=fGZjhY8ZupX54Q6gEbXjfrxR8svDBicnsO97vetjpo4,71015
|
|
4
4
|
matlab_proxy/constants.py,sha256=L9fhXdcGH7Eu56h0aB_TNm3d6aNFr2nP6-HyQJ96TAA,1175
|
|
5
|
-
matlab_proxy/default_configuration.py,sha256=
|
|
5
|
+
matlab_proxy/default_configuration.py,sha256=tBHaEq_bYsX2uC9pPA9mi_8M6o94ij-rxq8mbvcYpFc,1874
|
|
6
6
|
matlab_proxy/devel.py,sha256=nR6XPVBUEdQ-RZGtYvX1YHTp8gj9cuw5Hp8ahasMBc8,14310
|
|
7
|
-
matlab_proxy/settings.py,sha256=
|
|
7
|
+
matlab_proxy/settings.py,sha256=ni-9zNbWF3cy4v0X8vAwAiM5WcC8U_t3a-s7GXIkyBA,26723
|
|
8
8
|
matlab_proxy/gui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
|
-
matlab_proxy/gui/asset-manifest.json,sha256=
|
|
9
|
+
matlab_proxy/gui/asset-manifest.json,sha256=VW67P_Jg7RPTCNDkMCWmphyXKJvv-KE-DjFQvQxm8aM,3516
|
|
10
10
|
matlab_proxy/gui/favicon.ico,sha256=7w7Ki1uQP2Rgwc64dOV4-NrTu97I3WsZw8OvRSoY1A0,130876
|
|
11
|
-
matlab_proxy/gui/index.html,sha256=
|
|
11
|
+
matlab_proxy/gui/index.html,sha256=QFS6XN-j7nMc8qNT6m9nJzC73St0zo76PS2e__HS5BM,637
|
|
12
12
|
matlab_proxy/gui/manifest.json,sha256=NwDbrALM5auYyj2bbEf4aGwAUDqNl1FzMFQpPiG2Ty4,286
|
|
13
13
|
matlab_proxy/gui/robots.txt,sha256=kNJLw79pisHhc3OVAimMzKcq3x9WT6sF9IS4xI0crdI,67
|
|
14
14
|
matlab_proxy/gui/static/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
15
|
matlab_proxy/gui/static/css/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
16
|
-
matlab_proxy/gui/static/css/main.
|
|
17
|
-
matlab_proxy/gui/static/css/main.
|
|
16
|
+
matlab_proxy/gui/static/css/main.efa05ff9.css,sha256=dOvmpZ0-Xez2_dwxue5yb0el7o7btgZTzzbuQZ3hnSg,269167
|
|
17
|
+
matlab_proxy/gui/static/css/main.efa05ff9.css.map,sha256=y9dh-GxZmqmtSCOwW6szE68iuVhO7gEhm80yqvRX4oU,350512
|
|
18
18
|
matlab_proxy/gui/static/js/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
19
|
-
matlab_proxy/gui/static/js/main.
|
|
20
|
-
matlab_proxy/gui/static/js/main.
|
|
21
|
-
matlab_proxy/gui/static/js/main.
|
|
19
|
+
matlab_proxy/gui/static/js/main.ce0f5505.js,sha256=yK_ZQcKt2MrEb4BAcFeeWmSxD82N8dmhGhxrPxNBTeE,283625
|
|
20
|
+
matlab_proxy/gui/static/js/main.ce0f5505.js.LICENSE.txt,sha256=uJRPpXtA1Wzfw2dMAUGOPgwqYk2GvDcIafoGMMNLECQ,1539
|
|
21
|
+
matlab_proxy/gui/static/js/main.ce0f5505.js.map,sha256=drUlJe9d8w69Djdw-LIdrt7sRRjZl9Zw_PaZd-MlSdo,912523
|
|
22
22
|
matlab_proxy/gui/static/media/MATLAB-env-blur.4fc94edbc82d3184e5cb.png,sha256=QpmQTLDvBu2-b7ev83Rvpt0Q72R6wdQGkuJMPPpjv7M,220290
|
|
23
23
|
matlab_proxy/gui/static/media/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
24
24
|
matlab_proxy/gui/static/media/arrow.0c2968b90bd9a64c8c3f.svg,sha256=XtmvDWzGZnwCZm08TKBnqt5hc1wphJnNupG0Fx_faAY,327
|
|
@@ -54,7 +54,7 @@ matlab_proxy/gui/static/media/trigger-ok.7b9c238be42f685c4fa7.svg,sha256=mD-7N9c
|
|
|
54
54
|
matlab_proxy/icons/matlab.svg,sha256=xh5uYebQd8I-ISvenjU9A-PkClzW_lU9wvm3doXOFKM,13366
|
|
55
55
|
matlab_proxy/matlab/evaluateUserMatlabCode.m,sha256=R8w6nPdGtadR4UUFJaspcrGQL7cJwUItdrfc531w3bM,2420
|
|
56
56
|
matlab_proxy/matlab/startup.m,sha256=Rgb1Y3F2pFgByKAaXxWWcYOA2594D7V2HXuyuVmGYjs,653
|
|
57
|
-
matlab_proxy/util/__init__.py,sha256=
|
|
57
|
+
matlab_proxy/util/__init__.py,sha256=JkVIsTOae5giDK0cQ7jcxQSHa8zo1umdq-1C0grDZwk,11712
|
|
58
58
|
matlab_proxy/util/event_loop.py,sha256=sX_0tKlirCY5ImLxkss_XO4Ksj65u6JHtwMj25oGL94,1816
|
|
59
59
|
matlab_proxy/util/list_servers.py,sha256=M93coVZjyQCdIvCCxsNOU_XDWNjBSysOJ5tWXaTjP8Y,1369
|
|
60
60
|
matlab_proxy/util/mw.py,sha256=dLGSdfcTZiwKR1MMZA-39o-8na13IEPZOGBqcaHmKVI,11086
|
|
@@ -67,27 +67,27 @@ matlab_proxy/util/mwi/environment_variables.py,sha256=sOfmL8PjQONgkJdegdotLbsqHs
|
|
|
67
67
|
matlab_proxy/util/mwi/exceptions.py,sha256=3jklFU6br2_pSSsATCRDY3A5fTzk6ekJ4M69sunwxBk,5114
|
|
68
68
|
matlab_proxy/util/mwi/logger.py,sha256=EHHr6OWlXe6yVX0RPh57HSE7lz6MhWmwLQIpe_SlsC0,3803
|
|
69
69
|
matlab_proxy/util/mwi/token_auth.py,sha256=UbIWqo7qADaZdijFvorLYsZbxzaB8TycGP8nk305ru0,9997
|
|
70
|
-
matlab_proxy/util/mwi/validators.py,sha256=
|
|
70
|
+
matlab_proxy/util/mwi/validators.py,sha256=iXPR7b3jtnwx2i15YxKQgmOm2pt3ujJeMGYNxY0oGGw,12633
|
|
71
71
|
matlab_proxy/util/mwi/embedded_connector/__init__.py,sha256=Vfl2hNC7V1IwoK9_wrwfENs4BC8P-Mvvqh4BNGi2n48,119
|
|
72
72
|
matlab_proxy/util/mwi/embedded_connector/helpers.py,sha256=aOn-AvcDy6jBQJIffiv_agIa4UVldAIl3--QnDpXWDM,3656
|
|
73
73
|
matlab_proxy/util/mwi/embedded_connector/request.py,sha256=-IzTDjy3qViHfLJpK3OnFtEyV7dgwJKPQAfav9lqILc,4317
|
|
74
74
|
matlab_proxy_manager/__init__.py,sha256=CMqm2aSYUWo5sxV3vyqWudrQU31muouSqZRDesJNJSA,178
|
|
75
75
|
matlab_proxy_manager/lib/__init__.py,sha256=KfwQxxM5a1kMRtNbhz8tb7YfHp8e2d0tNLB55wYvDS8,37
|
|
76
|
-
matlab_proxy_manager/lib/api.py,sha256=
|
|
76
|
+
matlab_proxy_manager/lib/api.py,sha256=_ukL8ZeQg8E5s9uPeNjYAuCc_1BR08GSlom0VQclt84,12549
|
|
77
77
|
matlab_proxy_manager/storage/__init__.py,sha256=KfwQxxM5a1kMRtNbhz8tb7YfHp8e2d0tNLB55wYvDS8,37
|
|
78
78
|
matlab_proxy_manager/storage/file_repository.py,sha256=U4FAw0zFN9z7YNlaMsYZXWm5ccs3rp3bzZL-W2BNhxA,5187
|
|
79
79
|
matlab_proxy_manager/storage/interface.py,sha256=pnRRD0Ku3gzbruAOM3J3NI2Kk8do3-_yRw9Pag1IqnE,1883
|
|
80
|
-
matlab_proxy_manager/storage/server.py,sha256=
|
|
80
|
+
matlab_proxy_manager/storage/server.py,sha256=MjTw5-CRb3jF57wUXnVJmOyezM6peBOAyBfMfEqSzBc,4848
|
|
81
81
|
matlab_proxy_manager/utils/__init__.py,sha256=KfwQxxM5a1kMRtNbhz8tb7YfHp8e2d0tNLB55wYvDS8,37
|
|
82
82
|
matlab_proxy_manager/utils/auth.py,sha256=60vi16eQ7LWp3I4CNv2easTjObw50irEm518fiMA5YI,2526
|
|
83
83
|
matlab_proxy_manager/utils/constants.py,sha256=pyg-bkk6wWfmy60nvhroZDMZt__FcbZbuvU-b9m2Fkg,163
|
|
84
84
|
matlab_proxy_manager/utils/environment_variables.py,sha256=rbDeWnyJp77Yr6btK3eXKZQ5thwiwhOGZcvDetGPOH8,1436
|
|
85
|
-
matlab_proxy_manager/utils/helpers.py,sha256=
|
|
85
|
+
matlab_proxy_manager/utils/helpers.py,sha256=vgbWDTGmHpI_IMEy67UMfExxmbjMskhdEadCmbbvav8,9983
|
|
86
86
|
matlab_proxy_manager/utils/logger.py,sha256=GSRGD-yf518o-2b1BxEeJYuNiEz2eEqpl0Solqbwpb4,1869
|
|
87
87
|
matlab_proxy_manager/web/__init__.py,sha256=KfwQxxM5a1kMRtNbhz8tb7YfHp8e2d0tNLB55wYvDS8,37
|
|
88
|
-
matlab_proxy_manager/web/app.py,sha256=
|
|
89
|
-
matlab_proxy_manager/web/monitor.py,sha256=
|
|
90
|
-
matlab_proxy_manager/web/watcher.py,sha256=
|
|
88
|
+
matlab_proxy_manager/web/app.py,sha256=a_fCQS1rDGCuQ7iE1J2oaFrKSeBUyk_9lYeuyZo-MVc,18174
|
|
89
|
+
matlab_proxy_manager/web/monitor.py,sha256=PWkwV0kP3XHCxDRHpurPh74Zg-SgaIXnCnX2xZSW_R8,1541
|
|
90
|
+
matlab_proxy_manager/web/watcher.py,sha256=89JHjBAQtOrllstaJFxqrjHwckpRmu3qfUqeqPLmH2Q,2130
|
|
91
91
|
tests/integration/__init__.py,sha256=ttzJ8xKWGxOJZz56qOiWOn6sp5LGomkZMn_w4KJLRMU,42
|
|
92
92
|
tests/integration/integration_tests_with_license/__init__.py,sha256=vVYZCur-QhmIGCxUmn-WZjIywtDQidaLDmlmrRHRlgY,37
|
|
93
93
|
tests/integration/integration_tests_with_license/conftest.py,sha256=sCaIXB8d4vf05C7JWSVA7g5gnPjbpRq3dftuBpWyp1s,1599
|
|
@@ -100,8 +100,8 @@ tests/integration/utils/integration_tests_utils.py,sha256=IbJ9CedFHiz3k85FBY-8Gw
|
|
|
100
100
|
tests/integration/utils/licensing.py,sha256=rEBjvMXO8R3mL6KnePu2lojmOsjD4GXl9frf9N0Wacs,4842
|
|
101
101
|
tests/unit/__init__.py,sha256=KfwQxxM5a1kMRtNbhz8tb7YfHp8e2d0tNLB55wYvDS8,37
|
|
102
102
|
tests/unit/conftest.py,sha256=Hfxq3h8IZuLJkRMh5jdEFiq78CIAdKvm-6KryRDZ0FY,1918
|
|
103
|
-
tests/unit/test_app.py,sha256=
|
|
104
|
-
tests/unit/test_app_state.py,sha256=
|
|
103
|
+
tests/unit/test_app.py,sha256=pM8zVyXWLx8nP8RePusXH4admEBYKc5JC8eE2t8xIQE,38487
|
|
104
|
+
tests/unit/test_app_state.py,sha256=mq0qDWY3k2-_8job9g3BY52aT3ciNxji5_HVG1VhVBw,37112
|
|
105
105
|
tests/unit/test_constants.py,sha256=2nXxTmDP8utr8krsfZ4c_Bh4_mWPcDO5uI8MXeq4Usg,158
|
|
106
106
|
tests/unit/test_ddux.py,sha256=a2J2iM8j_nnfJVuMI38p5AjwrRdoMj3N88gFgS2I4hg,713
|
|
107
107
|
tests/unit/test_devel.py,sha256=A-1iVhSSwmywaW65QIRcUS2Fk7nJxceCcCm7CJtNdEc,7982
|
|
@@ -115,15 +115,15 @@ tests/unit/util/mwi/test_custom_http_headers.py,sha256=UfrhclS0j6WhShtg1ki2oF1kK
|
|
|
115
115
|
tests/unit/util/mwi/test_download.py,sha256=jYwPJFYGrPKqnkIJW42XYSe1fowmzChAkOx0k0xVldo,4779
|
|
116
116
|
tests/unit/util/mwi/test_logger.py,sha256=2VFoVlMLgsSWtDn0iVxHNArGBfN-IgWehuoaLvWlS6U,3151
|
|
117
117
|
tests/unit/util/mwi/test_token_auth.py,sha256=-eBsaQ5JC7pyd9PXt48Rqs4cWjg6I-eOkp_gFVEwYhk,10538
|
|
118
|
-
tests/unit/util/mwi/test_validators.py,sha256=
|
|
118
|
+
tests/unit/util/mwi/test_validators.py,sha256=lJy9rEXCULRrp9wxv9KXUjtlTFbchqTefxGLUg_n3S8,11452
|
|
119
119
|
tests/unit/util/mwi/embedded_connector/__init__.py,sha256=pl5jqyCHEwZEviiL8OC-SHulb1rBecstQCFF6qVjL9Y,37
|
|
120
120
|
tests/unit/util/mwi/embedded_connector/test_helpers.py,sha256=vYTWNUTuDeaygo16JGMTvWeI_CLOnvPkwNJmLndvJhE,890
|
|
121
121
|
tests/unit/util/mwi/embedded_connector/test_request.py,sha256=PR-jddnXDEiip-lD7A_QSvRwEkwo3eQ8owZlk-r9vnk,1867
|
|
122
122
|
tests/utils/__init__.py,sha256=ttzJ8xKWGxOJZz56qOiWOn6sp5LGomkZMn_w4KJLRMU,42
|
|
123
123
|
tests/utils/logging_util.py,sha256=VBy_NRvwau3C_CVTBjK5RMROrQimnJYHO2U0aKSZiRw,2234
|
|
124
|
-
matlab_proxy-0.
|
|
125
|
-
matlab_proxy-0.
|
|
126
|
-
matlab_proxy-0.
|
|
127
|
-
matlab_proxy-0.
|
|
128
|
-
matlab_proxy-0.
|
|
129
|
-
matlab_proxy-0.
|
|
124
|
+
matlab_proxy-0.23.3.dist-info/LICENSE.md,sha256=oF0h3UdSF-rlUiMGYwi086ZHqelzz7yOOk9HFDv9ELo,2344
|
|
125
|
+
matlab_proxy-0.23.3.dist-info/METADATA,sha256=l32qvymxSsGA0amtHFIGVvMQDMFMBs6758Qm2_YSq-A,10199
|
|
126
|
+
matlab_proxy-0.23.3.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
|
|
127
|
+
matlab_proxy-0.23.3.dist-info/entry_points.txt,sha256=ZAlCUsgKzGcAeQaMZOq31FrTB5tQ8Ypq8Op_8U600-A,305
|
|
128
|
+
matlab_proxy-0.23.3.dist-info/top_level.txt,sha256=KF-347aoRGsfHTpiSqfIPUZ95bzK5-oMIu8S_TUcu-w,40
|
|
129
|
+
matlab_proxy-0.23.3.dist-info/RECORD,,
|
matlab_proxy_manager/lib/api.py
CHANGED
|
@@ -3,7 +3,7 @@ import asyncio
|
|
|
3
3
|
import os
|
|
4
4
|
import secrets
|
|
5
5
|
import subprocess
|
|
6
|
-
from typing import Optional
|
|
6
|
+
from typing import List, Optional, Tuple
|
|
7
7
|
|
|
8
8
|
import matlab_proxy
|
|
9
9
|
import matlab_proxy.util.system as mwi_sys
|
|
@@ -20,7 +20,7 @@ log = logger.get(init=True)
|
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
async def start_matlab_proxy_for_kernel(
|
|
23
|
-
caller_id: str, parent_id: str,
|
|
23
|
+
caller_id: str, parent_id: str, is_shared_matlab: bool
|
|
24
24
|
):
|
|
25
25
|
"""
|
|
26
26
|
Starts a MATLAB proxy server specifically for MATLAB Kernel.
|
|
@@ -29,12 +29,12 @@ async def start_matlab_proxy_for_kernel(
|
|
|
29
29
|
set to None, for starting the MATLAB proxy server via proxy manager.
|
|
30
30
|
"""
|
|
31
31
|
return await _start_matlab_proxy(
|
|
32
|
-
caller_id=caller_id, ctx=parent_id,
|
|
32
|
+
caller_id=caller_id, ctx=parent_id, is_shared_matlab=is_shared_matlab
|
|
33
33
|
)
|
|
34
34
|
|
|
35
35
|
|
|
36
36
|
async def start_matlab_proxy_for_jsp(
|
|
37
|
-
parent_id: str,
|
|
37
|
+
parent_id: str, is_shared_matlab: bool, mpm_auth_token: str
|
|
38
38
|
):
|
|
39
39
|
"""
|
|
40
40
|
Starts a MATLAB proxy server specifically for Jupyter Server Proxy (JSP) - Open MATLAB launcher.
|
|
@@ -45,7 +45,7 @@ async def start_matlab_proxy_for_jsp(
|
|
|
45
45
|
return await _start_matlab_proxy(
|
|
46
46
|
caller_id="jsp",
|
|
47
47
|
ctx=parent_id,
|
|
48
|
-
|
|
48
|
+
is_shared_matlab=is_shared_matlab,
|
|
49
49
|
mpm_auth_token=mpm_auth_token,
|
|
50
50
|
)
|
|
51
51
|
|
|
@@ -60,7 +60,7 @@ async def _start_matlab_proxy(**options) -> Optional[dict]:
|
|
|
60
60
|
Args (keyword arguments):
|
|
61
61
|
- caller_id (str): The identifier for the caller (kernel id for kernels, "jsp" for JSP).
|
|
62
62
|
- ctx (str): The context in which the server is being started (parent pid).
|
|
63
|
-
-
|
|
63
|
+
- is_shared_matlab (bool, optional): Whether to start a shared MATLAB proxy instance.
|
|
64
64
|
Defaults to False.
|
|
65
65
|
- mpm_auth_token (str, optional): The MATLAB proxy manager token. If not provided,
|
|
66
66
|
a new token is generated. Defaults to None.
|
|
@@ -69,16 +69,23 @@ async def _start_matlab_proxy(**options) -> Optional[dict]:
|
|
|
69
69
|
ServerProcess: The process representing the MATLAB proxy server.
|
|
70
70
|
|
|
71
71
|
Raises:
|
|
72
|
-
ValueError: If `caller_id` is "default" and `
|
|
72
|
+
ValueError: If `caller_id` is "default" and `is_shared_matlab` is False.
|
|
73
73
|
"""
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
74
|
+
# Validate arguments
|
|
75
|
+
required_args: List[str] = ["caller_id", "ctx", "is_shared_matlab"]
|
|
76
|
+
missing_args: List[str] = [arg for arg in required_args if arg not in options]
|
|
77
|
+
|
|
78
|
+
if missing_args:
|
|
79
|
+
raise ValueError(f"Missing required arguments: {', '.join(missing_args)}")
|
|
80
|
+
|
|
81
|
+
caller_id: str = options["caller_id"]
|
|
82
|
+
ctx: str = options["ctx"]
|
|
83
|
+
is_shared_matlab: bool = options.get("is_shared_matlab", True)
|
|
77
84
|
mpm_auth_token: Optional[str] = options.get("mpm_auth_token", None)
|
|
78
85
|
|
|
79
|
-
if
|
|
86
|
+
if not is_shared_matlab and caller_id == "default":
|
|
80
87
|
raise ValueError(
|
|
81
|
-
"Caller id cannot be default when
|
|
88
|
+
"Caller id cannot be default when matlab proxy is not shareable"
|
|
82
89
|
)
|
|
83
90
|
|
|
84
91
|
mpm_auth_token = mpm_auth_token or secrets.token_hex(32)
|
|
@@ -86,9 +93,9 @@ async def _start_matlab_proxy(**options) -> Optional[dict]:
|
|
|
86
93
|
# Cleanup stale entries before starting new instance of matlab proxy server
|
|
87
94
|
helpers._are_orphaned_servers_deleted(ctx)
|
|
88
95
|
|
|
89
|
-
ident = caller_id if
|
|
96
|
+
ident = caller_id if not is_shared_matlab else "default"
|
|
90
97
|
key = f"{ctx}_{ident}"
|
|
91
|
-
log.debug("Starting matlab proxy using %s, %s, %s", ctx, ident,
|
|
98
|
+
log.debug("Starting matlab proxy using %s, %s, %s", ctx, ident, is_shared_matlab)
|
|
92
99
|
|
|
93
100
|
data_dir = helpers.create_and_get_proxy_manager_data_dir()
|
|
94
101
|
server_process = ServerProcess.find_existing_server(data_dir, key)
|
|
@@ -101,10 +108,8 @@ async def _start_matlab_proxy(**options) -> Optional[dict]:
|
|
|
101
108
|
|
|
102
109
|
# Create a new matlab proxy server
|
|
103
110
|
else:
|
|
104
|
-
server_process
|
|
105
|
-
|
|
106
|
-
ident, ctx, key, is_isolated_matlab, mpm_auth_token
|
|
107
|
-
)
|
|
111
|
+
server_process = await _start_subprocess_and_check_for_readiness(
|
|
112
|
+
ident, ctx, key, is_shared_matlab, mpm_auth_token
|
|
108
113
|
)
|
|
109
114
|
|
|
110
115
|
# Store the newly created server into filesystem
|
|
@@ -115,7 +120,7 @@ async def _start_matlab_proxy(**options) -> Optional[dict]:
|
|
|
115
120
|
|
|
116
121
|
|
|
117
122
|
async def _start_subprocess_and_check_for_readiness(
|
|
118
|
-
server_id: str, ctx: str, key: str,
|
|
123
|
+
server_id: str, ctx: str, key: str, is_shared_matlab: bool, mpm_auth_token: str
|
|
119
124
|
) -> Optional[ServerProcess]:
|
|
120
125
|
"""
|
|
121
126
|
Starts a MATLAB proxy server.
|
|
@@ -136,10 +141,12 @@ async def _start_subprocess_and_check_for_readiness(
|
|
|
136
141
|
matlab_proxy_cmd, matlab_proxy_env = _prepare_cmd_and_env_for_matlab_proxy()
|
|
137
142
|
|
|
138
143
|
# Start the matlab proxy process
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
144
|
+
result = await _start_subprocess(matlab_proxy_cmd, matlab_proxy_env, server_id)
|
|
145
|
+
if not result:
|
|
146
|
+
log.error("Could not start matlab proxy")
|
|
147
|
+
return None
|
|
142
148
|
|
|
149
|
+
process_id, url, mwi_base_url = result
|
|
143
150
|
server_process = None
|
|
144
151
|
|
|
145
152
|
# Check for the matlab proxy server readiness
|
|
@@ -151,14 +158,14 @@ async def _start_subprocess_and_check_for_readiness(
|
|
|
151
158
|
headers=helpers.convert_mwi_env_vars_to_header_format(
|
|
152
159
|
matlab_proxy_env, "MWI"
|
|
153
160
|
),
|
|
154
|
-
pid=process_id,
|
|
161
|
+
pid=str(process_id),
|
|
155
162
|
parent_pid=ctx,
|
|
156
163
|
id=key,
|
|
157
|
-
type="
|
|
164
|
+
type="shared" if is_shared_matlab else "named",
|
|
158
165
|
mpm_auth_token=mpm_auth_token,
|
|
159
166
|
)
|
|
160
167
|
else:
|
|
161
|
-
log.error("
|
|
168
|
+
log.error("matlab-proxy server never became ready")
|
|
162
169
|
|
|
163
170
|
return server_process
|
|
164
171
|
|
|
@@ -189,7 +196,7 @@ def _prepare_cmd_and_env_for_matlab_proxy():
|
|
|
189
196
|
return matlab_proxy_cmd, matlab_proxy_env
|
|
190
197
|
|
|
191
198
|
|
|
192
|
-
async def _start_subprocess(cmd, env, server_id) -> Optional[int]:
|
|
199
|
+
async def _start_subprocess(cmd, env, server_id) -> Optional[Tuple[int, str, str]]:
|
|
193
200
|
"""
|
|
194
201
|
Initializes and starts a subprocess using the specified command and provided environment.
|
|
195
202
|
|
|
@@ -199,33 +206,22 @@ async def _start_subprocess(cmd, env, server_id) -> Optional[int]:
|
|
|
199
206
|
process = None
|
|
200
207
|
mwi_base_url: str = f"{constants.MWI_BASE_URL_PREFIX}{server_id}"
|
|
201
208
|
|
|
202
|
-
# Get a free port
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
209
|
+
# Get a free port and corresponding bound socket
|
|
210
|
+
with helpers.find_free_port() as (port, _):
|
|
211
|
+
env.update(
|
|
212
|
+
{
|
|
213
|
+
"MWI_APP_PORT": port,
|
|
214
|
+
"MWI_BASE_URL": mwi_base_url,
|
|
215
|
+
}
|
|
216
|
+
)
|
|
210
217
|
|
|
211
|
-
|
|
212
|
-
|
|
218
|
+
# Using loopback address so that DNS resolution doesn't add latency in Windows
|
|
219
|
+
url: str = f"http://127.0.0.1:{port}"
|
|
213
220
|
|
|
214
|
-
|
|
215
|
-
process = await asyncio.create_subprocess_exec(
|
|
216
|
-
*cmd,
|
|
217
|
-
env=env,
|
|
218
|
-
)
|
|
219
|
-
log.debug("Started matlab proxy subprocess for posix")
|
|
220
|
-
else:
|
|
221
|
-
process = subprocess.Popen(
|
|
222
|
-
cmd,
|
|
223
|
-
env=env,
|
|
224
|
-
)
|
|
225
|
-
log.debug("Started matlab proxy subprocess for windows")
|
|
221
|
+
process = await _initialize_process_based_on_os_type(cmd, env)
|
|
226
222
|
|
|
227
223
|
if not process:
|
|
228
|
-
log.error("Matlab proxy process not created
|
|
224
|
+
log.error("Matlab proxy process not created due to some error")
|
|
229
225
|
return None
|
|
230
226
|
|
|
231
227
|
process_pid = process.pid
|
|
@@ -233,6 +229,51 @@ async def _start_subprocess(cmd, env, server_id) -> Optional[int]:
|
|
|
233
229
|
return process_pid, url, mwi_base_url
|
|
234
230
|
|
|
235
231
|
|
|
232
|
+
async def _initialize_process_based_on_os_type(cmd, env):
|
|
233
|
+
"""
|
|
234
|
+
Initializes and starts a subprocess based on the operating system.
|
|
235
|
+
|
|
236
|
+
This function attempts to create a subprocess using the provided command and
|
|
237
|
+
environment variables. It handles both POSIX and Windows systems differently.
|
|
238
|
+
|
|
239
|
+
Args:
|
|
240
|
+
cmd (List[str]): The command to execute in the subprocess.
|
|
241
|
+
env (Dict[str, str]): The environment variables for the subprocess.
|
|
242
|
+
|
|
243
|
+
Returns:
|
|
244
|
+
Union[Process, None, Popen[bytes]]: The created subprocess object if successful,
|
|
245
|
+
or None if an error occurs during subprocess creation.
|
|
246
|
+
|
|
247
|
+
Raises:
|
|
248
|
+
Exception: If there's an error creating the subprocess (caught and logged).
|
|
249
|
+
"""
|
|
250
|
+
if mwi_sys.is_posix():
|
|
251
|
+
log.debug("Starting matlab proxy subprocess for posix")
|
|
252
|
+
try:
|
|
253
|
+
return await asyncio.create_subprocess_exec(
|
|
254
|
+
*cmd,
|
|
255
|
+
env=env,
|
|
256
|
+
# kernel sporadically ends up cleaning the child matlab-proxy process during the
|
|
257
|
+
# restart workflow. This is a workaround to handle that race condition which leads
|
|
258
|
+
# to starting matlab-proxy in a new process group and is not counted for deletion.
|
|
259
|
+
# https://github.com/ipython/ipykernel/blob/main/ipykernel/kernelbase.py#L1283
|
|
260
|
+
start_new_session=True,
|
|
261
|
+
)
|
|
262
|
+
except Exception as e:
|
|
263
|
+
log.error("Failed to create posix subprocess: %s", e)
|
|
264
|
+
return None
|
|
265
|
+
else:
|
|
266
|
+
try:
|
|
267
|
+
log.debug("Starting matlab proxy subprocess for windows")
|
|
268
|
+
return subprocess.Popen(
|
|
269
|
+
cmd,
|
|
270
|
+
env=env,
|
|
271
|
+
)
|
|
272
|
+
except Exception as e:
|
|
273
|
+
log.error("Failed to create windows subprocess: %s", e)
|
|
274
|
+
return None
|
|
275
|
+
|
|
276
|
+
|
|
236
277
|
async def shutdown(parent_pid: str, caller_id: str, mpm_auth_token: str):
|
|
237
278
|
"""
|
|
238
279
|
Shutdown the MATLAB proxy server if the provided authentication token is valid.
|
|
@@ -20,8 +20,8 @@ class ServerProcess:
|
|
|
20
20
|
mwi_base_url: Optional[str] = None
|
|
21
21
|
headers: Optional[dict] = None
|
|
22
22
|
errors: Optional[list] = None
|
|
23
|
-
pid: Optional[
|
|
24
|
-
parent_pid: Optional[
|
|
23
|
+
pid: Optional[str] = None
|
|
24
|
+
parent_pid: Optional[str] = None
|
|
25
25
|
absolute_url: Optional[str] = field(default=None)
|
|
26
26
|
id: Optional[str] = None
|
|
27
27
|
type: Optional[str] = None
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
# Copyright 2024 The MathWorks, Inc.
|
|
2
|
+
import http
|
|
2
3
|
import os
|
|
3
4
|
import socket
|
|
4
5
|
import time
|
|
6
|
+
from contextlib import contextmanager
|
|
5
7
|
from pathlib import Path
|
|
6
|
-
from typing import Dict
|
|
8
|
+
from typing import Dict, Generator, Optional, Tuple
|
|
9
|
+
from urllib.parse import urlparse
|
|
7
10
|
|
|
8
11
|
import psutil
|
|
9
12
|
import requests
|
|
@@ -18,7 +21,7 @@ from matlab_proxy_manager.utils import logger
|
|
|
18
21
|
log = logger.get()
|
|
19
22
|
|
|
20
23
|
|
|
21
|
-
def is_server_ready(url: str, retries: int = 2, backoff_factor=None) -> bool:
|
|
24
|
+
def is_server_ready(url: Optional[str], retries: int = 2, backoff_factor=None) -> bool:
|
|
22
25
|
"""
|
|
23
26
|
Check if the server at the given URL is ready.
|
|
24
27
|
|
|
@@ -29,13 +32,19 @@ def is_server_ready(url: str, retries: int = 2, backoff_factor=None) -> bool:
|
|
|
29
32
|
bool: True if the server is ready, False otherwise.
|
|
30
33
|
"""
|
|
31
34
|
try:
|
|
35
|
+
# Validate URL
|
|
36
|
+
parsed_url = urlparse(url)
|
|
37
|
+
if not all([parsed_url.scheme, parsed_url.netloc]):
|
|
38
|
+
log.debug("Invalid URL provided: %s", url)
|
|
39
|
+
return False
|
|
40
|
+
|
|
32
41
|
matlab_proxy_index_page_identifier = "MWI_MATLAB_PROXY_IDENTIFIER"
|
|
33
42
|
resp = requests_retry_session(
|
|
34
43
|
retries=retries, backoff_factor=backoff_factor
|
|
35
44
|
).get(f"{url}", verify=False)
|
|
36
45
|
log.debug("Response status code from server readiness: %s", resp.status_code)
|
|
37
46
|
return (
|
|
38
|
-
resp.status_code ==
|
|
47
|
+
resp.status_code == http.HTTPStatus.OK
|
|
39
48
|
and matlab_proxy_index_page_identifier in resp.text
|
|
40
49
|
)
|
|
41
50
|
except Exception as e:
|
|
@@ -71,16 +80,14 @@ def requests_retry_session(
|
|
|
71
80
|
return session
|
|
72
81
|
|
|
73
82
|
|
|
74
|
-
def does_process_exist(pid:
|
|
83
|
+
def does_process_exist(pid: Optional[str]) -> bool:
|
|
75
84
|
"""
|
|
76
85
|
Checks if the parent process is alive.
|
|
77
86
|
|
|
78
87
|
Returns:
|
|
79
88
|
bool: True if the parent process is alive, False otherwise.
|
|
80
89
|
"""
|
|
81
|
-
|
|
82
|
-
log.debug("Parent liveness check returned: %s", parent_status)
|
|
83
|
-
return parent_status
|
|
90
|
+
return bool(pid and psutil.pid_exists(int(pid)))
|
|
84
91
|
|
|
85
92
|
|
|
86
93
|
def convert_mwi_env_vars_to_header_format(
|
|
@@ -124,11 +131,11 @@ async def delete_dangling_servers(app: web.Application) -> None:
|
|
|
124
131
|
Args:
|
|
125
132
|
app (web.Application): aiohttp web application
|
|
126
133
|
"""
|
|
127
|
-
is_delete_successful = _are_orphaned_servers_deleted(
|
|
134
|
+
is_delete_successful = _are_orphaned_servers_deleted()
|
|
128
135
|
log.debug("Deleted dangling matlab proxy servers: %s", is_delete_successful)
|
|
129
136
|
|
|
130
137
|
|
|
131
|
-
def _are_orphaned_servers_deleted(predicate: str) -> bool:
|
|
138
|
+
def _are_orphaned_servers_deleted(predicate: Optional[str] = "") -> bool:
|
|
132
139
|
"""
|
|
133
140
|
Get all the files under the proxy manager directory, check the status of the servers,
|
|
134
141
|
and delete orphaned servers and their corresponding files.
|
|
@@ -146,7 +153,7 @@ def _are_orphaned_servers_deleted(predicate: str) -> bool:
|
|
|
146
153
|
servers: dict = storage.get_all()
|
|
147
154
|
|
|
148
155
|
def _matches_predicate(filename: str) -> bool:
|
|
149
|
-
return filename.split("_")[0] == predicate
|
|
156
|
+
return filename.split("_")[0] == str(predicate)
|
|
150
157
|
|
|
151
158
|
# Checks only a subset of servers (that matches the parent_pid of the caller)
|
|
152
159
|
# to reduce the MATLAB proxy startup time
|
|
@@ -154,7 +161,7 @@ def _are_orphaned_servers_deleted(predicate: str) -> bool:
|
|
|
154
161
|
servers = {
|
|
155
162
|
filename: server
|
|
156
163
|
for filename, server in servers.items()
|
|
157
|
-
if _matches_predicate(filename)
|
|
164
|
+
if _matches_predicate(Path(filename).stem)
|
|
158
165
|
}
|
|
159
166
|
if not servers:
|
|
160
167
|
log.debug("Parent pid not matched, nothing to cleanup")
|
|
@@ -163,7 +170,7 @@ def _are_orphaned_servers_deleted(predicate: str) -> bool:
|
|
|
163
170
|
return _delete_server_and_file(storage, servers)
|
|
164
171
|
|
|
165
172
|
|
|
166
|
-
def _delete_server_and_file(storage, servers):
|
|
173
|
+
def _delete_server_and_file(storage, servers) -> bool:
|
|
167
174
|
is_server_deleted = False
|
|
168
175
|
for filename, server in servers.items():
|
|
169
176
|
if not server.is_server_alive():
|
|
@@ -201,7 +208,7 @@ def poll_for_server_deletion() -> None:
|
|
|
201
208
|
start_time = time.time()
|
|
202
209
|
|
|
203
210
|
while time.time() - start_time < timeout_in_seconds:
|
|
204
|
-
is_server_deleted = _are_orphaned_servers_deleted(
|
|
211
|
+
is_server_deleted = _are_orphaned_servers_deleted()
|
|
205
212
|
if is_server_deleted:
|
|
206
213
|
log.debug("Servers deleted, breaking out of loop")
|
|
207
214
|
break
|
|
@@ -210,21 +217,31 @@ def poll_for_server_deletion() -> None:
|
|
|
210
217
|
time.sleep(0.5)
|
|
211
218
|
|
|
212
219
|
|
|
213
|
-
|
|
220
|
+
@contextmanager
|
|
221
|
+
def find_free_port() -> Generator[Tuple[str, socket.socket], None, None]:
|
|
214
222
|
"""
|
|
215
|
-
|
|
223
|
+
Context manager for finding a free port on the system.
|
|
216
224
|
|
|
217
|
-
This function creates a socket, binds it to an available port,
|
|
218
|
-
the port number
|
|
225
|
+
This function creates a socket, binds it to an available port, and yields
|
|
226
|
+
the port number along with the socket object. The socket is automatically
|
|
227
|
+
closed when exiting the context.
|
|
219
228
|
|
|
220
|
-
|
|
221
|
-
str:
|
|
229
|
+
Yields:
|
|
230
|
+
Tuple[str, socket.socket]: A tuple containing:
|
|
231
|
+
- str: The free port number as a string.
|
|
232
|
+
- socket.socket: The socket object.
|
|
222
233
|
"""
|
|
223
234
|
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
224
235
|
s.bind(("", 0))
|
|
225
236
|
port = str(s.getsockname()[1])
|
|
226
|
-
|
|
227
|
-
|
|
237
|
+
try:
|
|
238
|
+
yield port, s
|
|
239
|
+
finally:
|
|
240
|
+
try:
|
|
241
|
+
s.close()
|
|
242
|
+
except OSError as ex:
|
|
243
|
+
# Socket already closed, log and ignore the exception
|
|
244
|
+
log.debug("Failed to close socket: %s", ex)
|
|
228
245
|
|
|
229
246
|
|
|
230
247
|
def pre_load_from_state_file(data_dir: str) -> Dict[str, str]:
|