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.

Files changed (28) hide show
  1. matlab_proxy/app_state.py +42 -47
  2. matlab_proxy/default_configuration.py +39 -4
  3. matlab_proxy/gui/asset-manifest.json +6 -6
  4. matlab_proxy/gui/index.html +1 -1
  5. matlab_proxy/gui/static/css/{main.6cd0caba.css → main.efa05ff9.css} +2 -2
  6. matlab_proxy/gui/static/css/{main.6cd0caba.css.map → main.efa05ff9.css.map} +1 -1
  7. matlab_proxy/gui/static/js/{main.77e6cbaf.js → main.ce0f5505.js} +3 -3
  8. matlab_proxy/gui/static/js/main.ce0f5505.js.map +1 -0
  9. matlab_proxy/settings.py +1 -1
  10. matlab_proxy/util/__init__.py +1 -1
  11. matlab_proxy/util/mwi/validators.py +17 -16
  12. {matlab_proxy-0.22.0.dist-info → matlab_proxy-0.23.3.dist-info}/METADATA +2 -2
  13. {matlab_proxy-0.22.0.dist-info → matlab_proxy-0.23.3.dist-info}/RECORD +27 -27
  14. {matlab_proxy-0.22.0.dist-info → matlab_proxy-0.23.3.dist-info}/WHEEL +1 -1
  15. matlab_proxy_manager/lib/api.py +90 -49
  16. matlab_proxy_manager/storage/server.py +2 -2
  17. matlab_proxy_manager/utils/helpers.py +38 -21
  18. matlab_proxy_manager/web/app.py +92 -49
  19. matlab_proxy_manager/web/monitor.py +1 -2
  20. matlab_proxy_manager/web/watcher.py +11 -0
  21. tests/unit/test_app.py +1 -0
  22. tests/unit/test_app_state.py +79 -4
  23. tests/unit/util/mwi/test_validators.py +4 -5
  24. matlab_proxy/gui/static/js/main.77e6cbaf.js.map +0 -1
  25. /matlab_proxy/gui/static/js/{main.77e6cbaf.js.LICENSE.txt → main.ce0f5505.js.LICENSE.txt} +0 -0
  26. {matlab_proxy-0.22.0.dist-info → matlab_proxy-0.23.3.dist-info}/LICENSE.md +0 -0
  27. {matlab_proxy-0.22.0.dist-info → matlab_proxy-0.23.3.dist-info}/entry_points.txt +0 -0
  28. {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.info(error_message)
106
+ logger.error(error_message)
107
107
  raise MatlabInstallError(error_message)
108
108
 
109
109
 
@@ -98,7 +98,7 @@ def prepare_site(app, runner):
98
98
  )
99
99
  break
100
100
  except:
101
- logger.info(f"Failed to launch the site on port {p}")
101
+ logger.error(f"Failed to launch the site on port {p}")
102
102
 
103
103
  return site
104
104
 
@@ -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
- available_configs = __get_configs()
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
- for key in default_config_keys:
194
- if not key in env_config:
195
- error_message = f"{key} missing in the provided {config} configuration"
196
- logger.error(error_message)
197
- raise FatalError(error_message)
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(f"Successfully validated provided {config} configuration")
201
+ logger.debug("Successfully validated provided %s configuration", config)
200
202
  return env_config
201
203
 
202
- else:
203
- error_message = f"{config} is not a valid config. Available configs are : {list(available_configs.keys())}"
204
- logger.error(error_message)
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.info(
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.22.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>=3.7.4
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=pt6s3Yy6NV6LB-GxT1Y4cOpeDaTFMm_ItN_qPstDTwE,71296
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=DxQaHzAivzstiPl_nDfxs8SOyP9oaK9v3RP4LtroJl4,843
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=63pyCUvT7WLBRUpUr3F4r4nL13pQ2Hn6-oZODAhuGLo,26722
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=YkEfNW24kpJZ_PoGlR8THdaAQvYutFAs_wEq1ZvCJXU,3516
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=NnOkBgjxfhXFum5bQF6xZ2SIfTJc7YccmLyqpYJIfVk,637
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.6cd0caba.css,sha256=Ks90yx_8kQC9UQXlkvh5ecz2vk2jEN2FKkMCLn0hTb8,269168
17
- matlab_proxy/gui/static/css/main.6cd0caba.css.map,sha256=-pczDWw0U0T9Yd7pVYDklDlsc6OJqxCYlGmS6qtAhqU,350517
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.77e6cbaf.js,sha256=gKag4fSgMd4NoDEIYWDmxAPqAUjdrPT3qCP0FCXf_AA,283174
20
- matlab_proxy/gui/static/js/main.77e6cbaf.js.LICENSE.txt,sha256=uJRPpXtA1Wzfw2dMAUGOPgwqYk2GvDcIafoGMMNLECQ,1539
21
- matlab_proxy/gui/static/js/main.77e6cbaf.js.map,sha256=QxEP96Qq3AEySDSK1PnVJdvvYVFjwYgRrDAWGJYscpw,911437
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=CoH6sfgrQ1phhO1FXeyQwTjtl7PPgeZOCGNrkyGv-5o,11711
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=br-22Gyef_vxVSSH2Qkb97Nfph9sfl7fyhQ8-LWkBP4,12600
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=IBAYvrTCA2TQ1pBzz8mkn1GQXUpIC1mUwaqVktvl4aE,10639
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=kQ4jtG2xqCa8c7zqDBFYxOhxMxwZwqTIITBxcJRDcvE,4848
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=8RlUe2WfhJ65YEVlhfU6ivpjpy4AAyA70vzmnJh0ypA,9267
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=Lu6sl3Mft98oL-Z1NwBdmmG1OvnwYEN31pU2bOdzFi0,16572
89
- matlab_proxy_manager/web/monitor.py,sha256=Gj0DxwX0c1PEAly5jWmuIGqNJYGDDjTkQIzbVXu4zCQ,1589
90
- matlab_proxy_manager/web/watcher.py,sha256=aNa_UDwvzaZrIdHyvWGX7dILH199uc6xVH4odrKU5-E,1817
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=15kSWsfIEQpGzr6QoDoFpV501SYA5XkszrwDp8pJi74,38442
104
- tests/unit/test_app_state.py,sha256=ZtM79HAe5W6pVVWV-NICjDJBlmuxJ4NnZn-urGGtH-E,33429
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=rzSmifQdPWZ5ZjecShBpC_RYL55_smCsG248h2JzUDU,11467
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.22.0.dist-info/LICENSE.md,sha256=oF0h3UdSF-rlUiMGYwi086ZHqelzz7yOOk9HFDv9ELo,2344
125
- matlab_proxy-0.22.0.dist-info/METADATA,sha256=oSpSLAsT_HNS-Gg6WiaM0EGv8Dg_g2-GfY6Lv8yPdNY,10190
126
- matlab_proxy-0.22.0.dist-info/WHEEL,sha256=eOLhNAGa2EW3wWl_TU484h7q1UNgy0JXjjoqKoxAAQc,92
127
- matlab_proxy-0.22.0.dist-info/entry_points.txt,sha256=ZAlCUsgKzGcAeQaMZOq31FrTB5tQ8Ypq8Op_8U600-A,305
128
- matlab_proxy-0.22.0.dist-info/top_level.txt,sha256=KF-347aoRGsfHTpiSqfIPUZ95bzK5-oMIu8S_TUcu-w,40
129
- matlab_proxy-0.22.0.dist-info/RECORD,,
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,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.44.0)
2
+ Generator: bdist_wheel (0.45.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -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, is_isolated_matlab: bool
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, is_isolated_matlab=is_isolated_matlab
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, is_isolated_matlab: bool, mpm_auth_token: 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
- is_isolated_matlab=is_isolated_matlab,
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
- - is_isolated_matlab (bool, optional): Whether to start an isolated MATLAB proxy instance.
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 `is_isolated_matlab` is True.
72
+ ValueError: If `caller_id` is "default" and `is_shared_matlab` is False.
73
73
  """
74
- caller_id: str = options.get("caller_id")
75
- ctx: str = options.get("ctx")
76
- is_isolated_matlab: bool = options.get("is_isolated_matlab", False)
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 is_isolated_matlab and caller_id == "default":
86
+ if not is_shared_matlab and caller_id == "default":
80
87
  raise ValueError(
81
- "Caller id cannot be default when isolated_matlab is set to true"
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 is_isolated_matlab else "default"
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, is_isolated_matlab)
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: ServerProcess | None = (
105
- await _start_subprocess_and_check_for_readiness(
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, isolated: bool, mpm_auth_token: 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
- process_id, url, mwi_base_url = await _start_subprocess(
140
- matlab_proxy_cmd, matlab_proxy_env, server_id
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="named" if isolated else "shared",
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("Could not start matlab proxy")
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, closer to starting the matlab proxy appx
203
- port: str = helpers.find_free_port()
204
- env.update(
205
- {
206
- "MWI_APP_PORT": port,
207
- "MWI_BASE_URL": mwi_base_url,
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
- # Using loopback address so that DNS resolution doesn't add latency in Windows
212
- url: str = f"http://127.0.0.1:{port}"
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
- if mwi_sys.is_posix():
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 %d", process.returncode)
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[int] = None
24
- parent_pid: Optional[int] = None
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 == requests.codes.OK
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: int) -> bool:
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
- parent_status = pid is not None and psutil.pid_exists(int(pid))
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(None)
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(None)
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
- def find_free_port() -> str:
220
+ @contextmanager
221
+ def find_free_port() -> Generator[Tuple[str, socket.socket], None, None]:
214
222
  """
215
- Find a free port on the system.
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, retrieves
218
- the port number, and then closes the socket.
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
- Returns:
221
- str: The free port number as a string.
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
- s.close()
227
- return port
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]: