matlab-proxy 0.18.2__py3-none-any.whl → 0.19.0__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 (33) hide show
  1. matlab_proxy/app.py +54 -43
  2. matlab_proxy/app_state.py +370 -155
  3. matlab_proxy/constants.py +3 -0
  4. matlab_proxy/gui/asset-manifest.json +6 -6
  5. matlab_proxy/gui/index.html +1 -1
  6. matlab_proxy/gui/static/css/{main.47712126.css → main.da9c4eb8.css} +2 -2
  7. matlab_proxy/gui/static/css/main.da9c4eb8.css.map +1 -0
  8. matlab_proxy/gui/static/js/{main.5b5ca2f2.js → main.e07799e7.js} +3 -3
  9. matlab_proxy/gui/static/js/main.e07799e7.js.map +1 -0
  10. matlab_proxy/matlab/startup.m +0 -20
  11. matlab_proxy/settings.py +16 -1
  12. matlab_proxy/util/__init__.py +101 -1
  13. matlab_proxy/util/event_loop.py +28 -10
  14. matlab_proxy/util/mwi/embedded_connector/__init__.py +1 -1
  15. matlab_proxy/util/mwi/embedded_connector/helpers.py +9 -0
  16. matlab_proxy/util/mwi/embedded_connector/request.py +51 -21
  17. matlab_proxy/util/mwi/environment_variables.py +5 -0
  18. matlab_proxy/util/mwi/exceptions.py +16 -1
  19. matlab_proxy/util/mwi/validators.py +33 -0
  20. {matlab_proxy-0.18.2.dist-info → matlab_proxy-0.19.0.dist-info}/METADATA +1 -1
  21. {matlab_proxy-0.18.2.dist-info → matlab_proxy-0.19.0.dist-info}/RECORD +31 -31
  22. tests/unit/test_app.py +45 -22
  23. tests/unit/test_app_state.py +404 -111
  24. tests/unit/test_constants.py +1 -0
  25. tests/unit/util/mwi/test_validators.py +30 -1
  26. tests/unit/util/test_util.py +83 -0
  27. matlab_proxy/gui/static/css/main.47712126.css.map +0 -1
  28. matlab_proxy/gui/static/js/main.5b5ca2f2.js.map +0 -1
  29. /matlab_proxy/gui/static/js/{main.5b5ca2f2.js.LICENSE.txt → main.e07799e7.js.LICENSE.txt} +0 -0
  30. {matlab_proxy-0.18.2.dist-info → matlab_proxy-0.19.0.dist-info}/LICENSE.md +0 -0
  31. {matlab_proxy-0.18.2.dist-info → matlab_proxy-0.19.0.dist-info}/WHEEL +0 -0
  32. {matlab_proxy-0.18.2.dist-info → matlab_proxy-0.19.0.dist-info}/entry_points.txt +0 -0
  33. {matlab_proxy-0.18.2.dist-info → matlab_proxy-0.19.0.dist-info}/top_level.txt +0 -0
matlab_proxy/app.py CHANGED
@@ -94,9 +94,7 @@ def marshal_error(error):
94
94
  return {"message": error.__str__, "logs": "", "type": error.__class__.__name__}
95
95
 
96
96
 
97
- async def create_status_response(
98
- app, loadUrl=None, client_id=None, is_active_client=None
99
- ):
97
+ def create_status_response(app, loadUrl=None, client_id=None, is_active_client=None):
100
98
  """Send a generic status response about the state of server, MATLAB, MATLAB Licensing and the client session status.
101
99
 
102
100
  Args:
@@ -111,7 +109,8 @@ async def create_status_response(
111
109
  state = app["state"]
112
110
  status = {
113
111
  "matlab": {
114
- "status": await state.get_matlab_state(),
112
+ "status": state.get_matlab_state(),
113
+ "busyStatus": state.matlab_busy_state,
115
114
  "version": state.settings["matlab_version"],
116
115
  },
117
116
  "licensing": marshal_licensing_info(state.licensing),
@@ -139,14 +138,31 @@ async def clear_client_id(req):
139
138
  Returns:
140
139
  Response: an empty response in JSON format
141
140
  """
142
- # Sleep for one second prior to clearing the client id to ensure that any remaining get_status responses are fully processed first.
143
- await asyncio.sleep(1)
144
141
  state = req.app["state"]
145
142
  state.active_client = None
143
+ logger.debug("Client Id was cleaned!!!")
146
144
  # This response is of no relevance to the front-end as the client has already exited
147
145
  return web.json_response({})
148
146
 
149
147
 
148
+ def reset_timer_decorator(endpoint):
149
+ """This decorator resets the IDLE timer if MWI_IDLE_TIMEOUT environment variable is supplied.
150
+
151
+ Args:
152
+ endpoint (callable): An asynchronous function which is a request handler.
153
+ """
154
+
155
+ async def reset_timer(req):
156
+ state = req.app["state"]
157
+
158
+ if state.is_idle_timeout_enabled:
159
+ await state.reset_timer()
160
+
161
+ return await endpoint(req)
162
+
163
+ return reset_timer
164
+
165
+
150
166
  @token_auth.authenticate_access_decorator
151
167
  async def get_auth_token(req):
152
168
  """API endpoint to return the auth token
@@ -192,15 +208,19 @@ async def get_env_config(req):
192
208
 
193
209
  config["matlab"] = {
194
210
  "version": state.settings["matlab_version"],
195
- "supported_versions": constants.SUPPORTED_MATLAB_VERSIONS,
211
+ "supportedVersions": constants.SUPPORTED_MATLAB_VERSIONS,
196
212
  }
197
213
 
214
+ # Send timeout duration for the idle timer as part of the response
215
+ config["idleTimeoutDuration"] = state.settings["mwi_idle_timeout"]
216
+
198
217
  return web.json_response(config)
199
218
 
200
219
 
201
220
  # @token_auth.authenticate_access_decorator
202
221
  # Explicitly disabling authentication for this end-point,
203
222
  # because the front end requires this endpoint to be available at all times.
223
+ @reset_timer_decorator
204
224
  async def get_status(req):
205
225
  """API Endpoint to get the generic status of the server, MATLAB and MATLAB Licensing.
206
226
 
@@ -220,7 +240,7 @@ async def get_status(req):
220
240
  is_desktop, client_id, transfer_session
221
241
  )
222
242
 
223
- return await create_status_response(
243
+ return create_status_response(
224
244
  req.app, client_id=generated_client_id, is_active_client=is_active_client
225
245
  )
226
246
 
@@ -269,7 +289,7 @@ async def start_matlab(req):
269
289
  # Start MATLAB
270
290
  await state.start_matlab(restart_matlab=True)
271
291
 
272
- return await create_status_response(req.app)
292
+ return create_status_response(req.app)
273
293
 
274
294
 
275
295
  @token_auth.authenticate_access_decorator
@@ -286,7 +306,7 @@ async def stop_matlab(req):
286
306
 
287
307
  await state.stop_matlab()
288
308
 
289
- return await create_status_response(req.app)
309
+ return create_status_response(req.app)
290
310
 
291
311
 
292
312
  @token_auth.authenticate_access_decorator
@@ -337,7 +357,7 @@ async def set_licensing_info(req):
337
357
  # This is true for a user who has only one license associated with their account
338
358
  await __start_matlab_if_licensed(state)
339
359
 
340
- return await create_status_response(req.app)
360
+ return create_status_response(req.app)
341
361
 
342
362
 
343
363
  @token_auth.authenticate_access_decorator
@@ -361,7 +381,7 @@ async def update_entitlement(req):
361
381
  await state.update_user_selected_entitlement_info(entitlement_id)
362
382
  await __start_matlab_if_licensed(state)
363
383
 
364
- return await create_status_response(req.app)
384
+ return create_status_response(req.app)
365
385
 
366
386
 
367
387
  async def __start_matlab_if_licensed(state):
@@ -397,35 +417,36 @@ async def licensing_info_delete(req):
397
417
  # Persist config information
398
418
  state.persist_config_data()
399
419
 
400
- return await create_status_response(req.app)
420
+ return create_status_response(req.app)
401
421
 
402
422
 
403
423
  @token_auth.authenticate_access_decorator
404
- async def termination_integration_delete(req):
405
- """API Endpoint to terminate the Integration and shutdown the server.
424
+ async def shutdown_integration_delete(req):
425
+ """API Endpoint to shutdown the Integration
406
426
 
407
427
  Args:
408
428
  req (HTTPRequest): HTTPRequest Object
409
429
  """
410
- logger.debug("Terminating the integration...")
411
430
  state = req.app["state"]
412
431
 
432
+ logger.info(f"Going ahead with shutdown of {state.settings['integration_name']}...")
433
+
413
434
  # Send response manually because this has to happen before the application exits
414
- res = await create_status_response(req.app, "../")
435
+ res = create_status_response(req.app, "../")
415
436
  await res.prepare(req)
416
437
  await res.write_eof()
417
438
 
418
- logger.debug("Shutting down the server...")
419
- # End termination with 0 exit code to indicate intentional termination
439
+ # Gracefully shutdown the server
420
440
  await req.app.shutdown()
421
441
  await req.app.cleanup()
422
- """When testing with pytest, its not possible to catch sys.exit(0) using the construct
423
- 'with pytest.raises()', there by causing the test : test_termination_integration_delete()
424
- to fail. In order to avoid this, adding the below if condition to check to skip sys.exit(0) when testing
425
- """
426
- logger.debug("Exiting with return code 0")
427
- if not mwi_env.is_testing_mode_enabled():
428
- sys.exit(0)
442
+
443
+ loop = util.get_event_loop()
444
+ # Run the current batch of coroutines in the event loop and then exit.
445
+ # This completes the loop.run_forever() blocking call and subsequent code
446
+ # in main() resumes execution.
447
+ loop.stop()
448
+
449
+ return res
429
450
 
430
451
 
431
452
  # @token_auth.authenticate_access_decorator
@@ -562,7 +583,7 @@ async def matlab_view(req):
562
583
  async with aiohttp.ClientSession(
563
584
  trust_env=True,
564
585
  cookies=req.cookies,
565
- connector=aiohttp.TCPConnector(verify_ssl=False),
586
+ connector=aiohttp.TCPConnector(ssl=False),
566
587
  ) as client_session:
567
588
  try:
568
589
  async with client_session.ws_connect(
@@ -628,7 +649,7 @@ async def matlab_view(req):
628
649
  timeout = aiohttp.ClientTimeout(total=None)
629
650
  async with aiohttp.ClientSession(
630
651
  trust_env=True,
631
- connector=aiohttp.TCPConnector(verify_ssl=False),
652
+ connector=aiohttp.TCPConnector(ssl=False),
632
653
  timeout=timeout,
633
654
  ) as client_session:
634
655
  try:
@@ -754,7 +775,7 @@ async def matlab_starter(app):
754
775
  state = app["state"]
755
776
 
756
777
  try:
757
- if state.is_licensed() and await state.get_matlab_state() == "down":
778
+ if state.is_licensed() and state.get_matlab_state() == "down":
758
779
  await state.start_matlab()
759
780
  except asyncio.CancelledError:
760
781
  # Ensure MATLAB is terminated
@@ -785,19 +806,9 @@ async def cleanup_background_tasks(app):
785
806
 
786
807
  await state.stop_matlab(force_quit=True)
787
808
 
788
- # Stop any running async tasks
789
- logger = mwi.logger.get()
790
- tasks = state.tasks
791
- if state.task_detect_client_status:
792
- tasks["detect_client_status"] = state.task_detect_client_status
793
- for task_name, task in tasks.items():
794
- if not task.cancelled():
795
- logger.debug(f"Cancelling MWI task: {task_name} : {task} ")
796
- task.cancel()
797
- try:
798
- await task
799
- except asyncio.CancelledError:
800
- pass
809
+ # Cleanup server tasks
810
+ all_tasks = state.server_tasks
811
+ await util.cancel_tasks(all_tasks)
801
812
 
802
813
 
803
814
  def configure_and_start(app):
@@ -893,7 +904,7 @@ def create_app(config_name=matlab_proxy.get_default_config_name()):
893
904
  "DELETE", f"{base_url}/set_licensing_info", licensing_info_delete
894
905
  )
895
906
  app.router.add_route(
896
- "DELETE", f"{base_url}/terminate_integration", termination_integration_delete
907
+ "DELETE", f"{base_url}/shutdown_integration", shutdown_integration_delete
897
908
  )
898
909
  app.router.add_route("*", f"{base_url}/", root_redirect)
899
910
  app.router.add_route("*", f"{base_url}", root_redirect)