cubevis 1.0.14__py3-none-any.whl → 1.0.21__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.
@@ -53,6 +53,7 @@ from cubevis.bokeh.models import TipButton, Tip, EvTextInput, BokehAppContext
53
53
 
54
54
  from cubevis.utils import resource_manager, reset_resource_manager, is_interactive_jupyter, find_pkg, load_pkg
55
55
  from cubevis.utils import ContextMgrChain as CMC
56
+ from cubevis.utils import MutualExclusionManager
56
57
 
57
58
  # pylint: disable=no-name-in-module
58
59
  from casatasks.private.imagerhelpers.imager_return_dict import ImagingDict
@@ -61,7 +62,7 @@ from casatasks.private.imagerhelpers.input_parameters import ImagerParameters
61
62
  # pylint: enable=no-name-in-module
62
63
 
63
64
  from cubevis.utils import find_ws_address, convert_masks
64
- from cubevis.toolbox import CubeMask, AppContext
65
+ from cubevis.toolbox import CubeMask
65
66
  from cubevis.bokeh.utils import svg_icon
66
67
  from cubevis.bokeh.sources import DataPipe
67
68
  from cubevis.utils import DocEnum
@@ -74,6 +75,25 @@ USE_MULTIPLE_GCLEAN_HACK=False
74
75
  class InteractiveCleanUI:
75
76
  '''InteractiveCleanUI(...) implements interactive clean using Bokeh
76
77
  '''
78
+
79
+ exclusion_mgr = MutualExclusionManager(
80
+ name="interactive clean",
81
+ valid_modes={
82
+ "tab": "❌ Cannot use iclean task display:\n\n" \
83
+ "Reason: bokeh.plotting.show() or iclean show method has already been\n" \
84
+ " used for display of this class. Mixing display methods within\n" \
85
+ " a single notebook corrupts Bokeh display within the notebook\n",
86
+ "cell-bokeh-show": "❌ Cannot use bokeh.plotting.show() display method:\n\n" \
87
+ "Reason: iclean show or task method has already been used for display\n" \
88
+ " of this class. Mixing display methods within a single notebook\n" \
89
+ " corrupts Bokeh display within the notebook\n",
90
+ "cell-custom-show": "❌ Cannot use iclean show method:\n\n" \
91
+ "Reason: bokeh.plotting.show() or task has already been used for display\n" \
92
+ " of this class. Mixing display methods within a single notebook\n" \
93
+ " corrupts Bokeh display within the notebook\n",
94
+ }
95
+ )
96
+
77
97
  def __stop( self, _=None ):
78
98
  self.__result_future.set_result(self.__retrieve_result( ))
79
99
 
@@ -164,11 +184,6 @@ class InteractiveCleanUI:
164
184
  ### the image display.
165
185
  ###
166
186
  self._conv_spect_plot_width = 450
167
- ###
168
- ### Create application context (which includes a temporary directory).
169
- ### This sets the title of the plot.
170
- ###
171
- self._app_state = AppContext( 'Interactive Clean' )
172
187
 
173
188
  ###
174
189
  ### Whether or not the Interactive Clean session is running remotely
@@ -302,11 +317,13 @@ class InteractiveCleanUI:
302
317
  init_script=CustomJS( args=dict( initial_convergence_state=self._init_values["convergence_state"],
303
318
  clean_ctrl=self._control['iteration'],
304
319
  name=imid ),
305
- code='''document._casa_convergence_data = initial_convergence_state
306
- clean_ctrl.continue.disable_add_sub = this.disable_add_sub.values
307
- clean_ctrl.finish.disable_add_sub = this.disable_add_sub.values
308
- clean_ctrl.stop.disable_add_sub = this.disable_add_sub.values
309
- this.disable_add_sub.values.message = "cannot modify mask during cleaning"''' )
320
+ ### save appstate as _appstate in image source for future access
321
+ code='''cb_obj.appstate.convergence_data = initial_convergence_state
322
+ cb_obj.origin._appstate = cb_obj.appstate
323
+ clean_ctrl.continue.disable_add_sub = cb_obj.origin.disable_add_sub.values
324
+ clean_ctrl.finish.disable_add_sub = cb_obj.origin.disable_add_sub.values
325
+ clean_ctrl.stop.disable_add_sub = cb_obj.origin.disable_add_sub.values
326
+ cb_obj.origin.disable_add_sub.values.message = "cannot modify mask during cleaning"''' )
310
327
  if idx == 0 else None )
311
328
 
312
329
  ###
@@ -678,7 +695,7 @@ class InteractiveCleanUI:
678
695
  ctrl={ 'converge': self._clean['converge'] },
679
696
  stopdescmap=ImagingDict.get_summaryminor_stopdesc( ) ),
680
697
  code=self._js['update-converge'] +
681
- '''update_convergence_single( img_state, document._casa_convergence_data.convergence[imid] )''' ) )
698
+ '''update_convergence_single( img_state, cb_obj._appstate.convergence_data.convergence[imid] )''' ) )
682
699
 
683
700
  ###
684
701
  ### collect toolbars for syncing selection
@@ -810,7 +827,8 @@ class InteractiveCleanUI:
810
827
  logbutton=self._log_button,
811
828
  stopdescmap=ImagingDict.get_summaryminor_stopdesc( )
812
829
  ),
813
- code=self._js['update-converge'] + self._js['clean-refresh'] + self._js['clean-disable'] +
830
+ code="const appstate = Bokeh.find.appState(cb_obj.origin);" +
831
+ self._js['update-converge'] + self._js['clean-refresh'] + self._js['clean-disable'] +
814
832
  self._js['clean-enable'] + self._js['clean-status-update'] +
815
833
  self._js['iter-gui-update'] + self._js['clean-wait'] +
816
834
  '''function invalid_niter( s ) {
@@ -859,11 +877,11 @@ class InteractiveCleanUI:
859
877
  // { action: 'stop',
860
878
  // value: { } },
861
879
  // update_gui )
862
- document._casa_window_closed = true
880
+ appstate.window_closed = true
863
881
  /*** this will close the tab >>>>---------+ ***/
864
882
  /*** | ***/
865
- /*** vvvvv----------------------------+ ***/
866
- document._cube_done( Object.entries(images_state).reduce((acc,[k,v]) => ({ ...acc, [k]: v.src.masks( ) }),{ } ) )
883
+ /*** vvvvvvvvv-----------------------+ ***/
884
+ appstate.cube_done( Object.entries(images_state).reduce((acc,[k,v]) => ({ ...acc, [k]: v.src.masks( ) }),{ } ) )
867
885
  }
868
886
  } else if ( state.mode === 'continuous' &&
869
887
  cb_obj.origin.name === 'stop' &&
@@ -942,13 +960,13 @@ class InteractiveCleanUI:
942
960
  self._control['iteration']['stop'], self._control['iteration']['continue'], self._control['iteration']['finish'], sizing_mode="scale_width" ),
943
961
  row( image_tabs, height_policy='max', width_policy='max' ),
944
962
  height_policy='max', width_policy='max' ),
945
- app_state={
946
- 'name': 'interactive clean',
947
- 'initialized': True
948
- } )
963
+ app_state={ ### while the state dictionary itself
964
+ 'name': 'interactive clean', ### is used, these particular element
965
+ 'initialized': True ### are not currently used for anything
966
+ }, title='Interactive Clean' )
949
967
 
950
968
  ###
951
- ### Keep track of which image is currently active in document._casa_image_name (which is
969
+ ### Keep track of which image is currently active in appstate.image_name (which is
952
970
  ### initialized in self._js['initialize']). Also, update the current control sub-tab
953
971
  ### when the field main-tab is changed. An attempt to manage this all within the
954
972
  ### control sub-tabs using a reference to self._image_control_tab_groups from
@@ -956,13 +974,17 @@ class InteractiveCleanUI:
956
974
  ###
957
975
  ### bokeh.core.serialization.SerializationError: circular reference
958
976
  ###
977
+ ### This set of tabs is the primary, outer tabs where each tab contains the complete
978
+ ### set of image controls
979
+ ###
959
980
  image_tabs.js_on_change( 'active', CustomJS( args=dict( names=[ t[0] for t in self._clean_targets.items( ) ],
960
981
  itergroups=self._image_control_tab_groups ),
961
- code='''if ( ! hasprop(document,'_casa_last_control_tab') ) {
962
- document._casa_last_control_tab = 0
982
+ code='''const appstate = Bokeh.find.appState(cb_obj)
983
+ if ( ! hasprop(appstate,'last_control_tab') ) {
984
+ appstate.last_control_tab = 0
963
985
  }
964
- document._casa_image_name = names[cb_obj.active]
965
- itergroups[document._casa_image_name].active = document._casa_last_control_tab''' ) )
986
+ appstate.image_name = names[cb_obj.active]
987
+ itergroups[appstate.image_name].active = appstate.last_control_tab''' ) )
966
988
 
967
989
  # Change display type depending on runtime environment
968
990
  #if self._is_notebook:
@@ -1017,8 +1039,11 @@ class InteractiveCleanUI:
1017
1039
  self._image_control_tab_groups = { }
1018
1040
 
1019
1041
  self._image_control_tab_groups[imid] = result
1042
+
1043
+ ### This set of tabs is the secondary, inner tabs for different controls for an individual image
1020
1044
  result.js_on_change( 'active', CustomJS( args=dict( ),
1021
- code='''document._casa_last_control_tab = cb_obj.active''' ) )
1045
+ code='''const appstate = Bokeh.find.appState(cb_obj)
1046
+ appstate.last_control_tab = cb_obj.active''' ) )
1022
1047
  return result
1023
1048
 
1024
1049
  def _create_image_panel( self, imagetuple ):
@@ -1285,20 +1310,22 @@ class InteractiveCleanUI:
1285
1310
 
1286
1311
  def _initialize_javascript( self ):
1287
1312
  self._js = { ### initialize state
1288
- ### --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
1289
- ### -- document is used storing state --
1290
- ### --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
1291
- 'initialize': '''if ( ! document._casa_initialized ) {
1313
+ ### --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
1314
+ ### -- "logbutton" is a random GUI model which can be used to locate the --
1315
+ ### -- appstate that is used storing state --
1316
+ ### --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
1317
+ 'initialize': '''const appstate = Bokeh.find.appState(logbutton)
1318
+ if ( ! appstate.ic_initialized ) {
1292
1319
  console.log(`casalib version: ${casalib.version}`)
1293
- document._casa_image_name = initial_image
1294
- document._casa_initialized = true
1295
- document._casa_window_closed = false
1320
+ appstate.image_name = initial_image
1321
+ appstate.ic_initialized = true
1322
+ appstate.window_closed = false
1296
1323
  window.addEventListener( 'beforeunload',
1297
1324
  function (e) {
1298
1325
  // if the window is already closed this message is never
1299
1326
  // delivered (unless interactive clean is called again then
1300
1327
  // the event shows up in the newly created control pipe)
1301
- if ( document._casa_window_closed == false ) {
1328
+ if ( appstate.window_closed == false ) {
1302
1329
  ctrl_pipe.send( ids['stop'],
1303
1330
  { action: 'stop', value: { } },
1304
1331
  undefined ) } } )
@@ -1374,13 +1401,13 @@ class InteractiveCleanUI:
1374
1401
 
1375
1402
  function update_convergence( recurse=false ) {
1376
1403
  let convdata
1377
- if ( hasprop(document,'_casa_convergence_data') ) {
1378
- convdata = document._casa_convergence_data
1404
+ if ( hasprop(appstate,'convergence_data') ) {
1405
+ convdata = appstate.convergence_data
1379
1406
  } else {
1380
1407
  if ( ! recurse ) {
1381
1408
  ctrl.converge.pipe.send( ctrl.converge.id, { action: 'retrieve' },
1382
1409
  (msg) => { if ( hasprop( msg.result, 'convergence' ) ) {
1383
- document._casa_convergence_data = { convergence: msg.result.convergence,
1410
+ appstate.convergence_data = { convergence: msg.result.convergence,
1384
1411
  cyclethreshold: msg.result.cyclethreshold }
1385
1412
  update_convergence(true)
1386
1413
  } } )
@@ -1415,8 +1442,8 @@ class InteractiveCleanUI:
1415
1442
  }
1416
1443
 
1417
1444
  if ( hasprop(clean_msg,'convergence') && clean_msg.convergence != null ) {
1418
- document._casa_convergence_data = { convergence: clean_msg.convergence,
1419
- cyclethreshold: clean_msg.cyclethreshold }
1445
+ appstate.convergence_data = { convergence: clean_msg.convergence,
1446
+ cyclethreshold: clean_msg.cyclethreshold }
1420
1447
  }
1421
1448
  }
1422
1449
 
@@ -1498,19 +1525,19 @@ class InteractiveCleanUI:
1498
1525
  'Stopping criteria encountered',
1499
1526
  'Unrecognized stop code' ]
1500
1527
  if ( typeof status === 'number' ) {
1501
- images_state[document._casa_image_name]['status'].text =
1528
+ images_state[appstate.image_name]['status'].text =
1502
1529
  '<p>' +
1503
1530
  stopstr[ status < 0 || status >= stopstr.length ?
1504
1531
  stopstr.length - 1 : status ] +
1505
1532
  '</p>'
1506
1533
  } else {
1507
- images_state[document._casa_image_name]['status'].text = `<p>${status}</p>`
1534
+ images_state[appstate.image_name]['status'].text = `<p>${status}</p>`
1508
1535
  }
1509
1536
  }''',
1510
1537
 
1511
1538
  'iter-gui-update': '''function get_update_dictionary( ) {
1512
- //const amste = images_state[document._casa_image_name]['automask']
1513
- //const clste = images_state[document._casa_image_name]['iteration']
1539
+ //const amste = images_state[appstate.image_name]['automask']
1540
+ //const clste = images_state[appstate.image_name]['iteration']
1514
1541
  // Assumption is that there is ONE set of iteration and automask updates
1515
1542
  // for ALL imaging fields...
1516
1543
  const amobj = Object.entries(images_state)[0][1].automask
@@ -1529,7 +1556,7 @@ class InteractiveCleanUI:
1529
1556
 
1530
1557
  const masks = Object.entries(images_state).reduce( (acc,[k,v]) => { acc[k] = v.src.masks( ); return acc }, { } )
1531
1558
  const breadcrumbs = Object.entries(images_state).reduce( (acc,[k,v]) => { acc[k] = v.src.breadcrumbs( ); return acc }, { } )
1532
- return { iteration, automask, masks, breadcrumbs, current_image: document._casa_image_name }
1559
+ return { iteration, automask, masks, breadcrumbs, current_image: appstate.image_name }
1533
1560
  }
1534
1561
  function update_log( log_lines ) {
1535
1562
  let b = logbutton
@@ -52,6 +52,7 @@ from cubevis.bokeh.models import TipButton, Tip, EvTextInput, BokehAppContext
52
52
 
53
53
  from cubevis.utils import resource_manager, reset_resource_manager, is_interactive_jupyter, find_pkg, load_pkg
54
54
  from cubevis.utils import ContextMgrChain as CMC
55
+ from cubevis.utils import MutualExclusionManager
55
56
 
56
57
  # pylint: disable=no-name-in-module
57
58
  from casatasks.private.imagerhelpers.imager_return_dict import ImagingDict
@@ -60,7 +61,7 @@ from casatasks.private.imagerhelpers.input_parameters import ImagerParameters
60
61
  # pylint: enable=no-name-in-module
61
62
 
62
63
  from cubevis.utils import find_ws_address, convert_masks
63
- from cubevis.toolbox import CubeMask, AppContext
64
+ from cubevis.toolbox import CubeMask
64
65
  from cubevis.bokeh.utils import svg_icon
65
66
  from cubevis.bokeh.sources import DataPipe
66
67
  from cubevis.utils import DocEnum
@@ -73,6 +74,25 @@ USE_MULTIPLE_GCLEAN_HACK=False
73
74
  class InteractiveCleanUI:
74
75
  '''InteractiveCleanUI(...) implements interactive clean using Bokeh
75
76
  '''
77
+
78
+ exclusion_mgr = MutualExclusionManager(
79
+ name="interactive clean",
80
+ valid_modes={
81
+ "tab": "❌ Cannot use iclean task display:\n\n" \
82
+ "Reason: bokeh.plotting.show() or iclean show method has already been\n" \
83
+ " used for display of this class. Mixing display methods within\n" \
84
+ " a single notebook corrupts Bokeh display within the notebook\n",
85
+ "cell-bokeh-show": "❌ Cannot use bokeh.plotting.show() display method:\n\n" \
86
+ "Reason: iclean show or task method has already been used for display\n" \
87
+ " of this class. Mixing display methods within a single notebook\n" \
88
+ " corrupts Bokeh display within the notebook\n",
89
+ "cell-custom-show": "❌ Cannot use iclean show method:\n\n" \
90
+ "Reason: bokeh.plotting.show() or task has already been used for display\n" \
91
+ " of this class. Mixing display methods within a single notebook\n" \
92
+ " corrupts Bokeh display within the notebook\n",
93
+ }
94
+ )
95
+
76
96
  def __stop( self, _=None ):
77
97
  self.__result_future.set_result(self.__retrieve_result( ))
78
98
 
@@ -163,11 +183,6 @@ class InteractiveCleanUI:
163
183
  ### the image display.
164
184
  ###
165
185
  self._conv_spect_plot_width = 450
166
- ###
167
- ### Create application context (which includes a temporary directory).
168
- ### This sets the title of the plot.
169
- ###
170
- self._app_state = AppContext( 'Interactive Clean' )
171
186
 
172
187
  ###
173
188
  ### Whether or not the Interactive Clean session is running remotely
@@ -301,11 +316,13 @@ class InteractiveCleanUI:
301
316
  init_script=CustomJS( args=dict( initial_convergence_state=self._init_values["convergence_state"],
302
317
  clean_ctrl=self._control['iteration'],
303
318
  name=imid ),
304
- code='''document._casa_convergence_data = initial_convergence_state
305
- clean_ctrl.continue.disable_add_sub = this.disable_add_sub.values
306
- clean_ctrl.finish.disable_add_sub = this.disable_add_sub.values
307
- clean_ctrl.stop.disable_add_sub = this.disable_add_sub.values
308
- this.disable_add_sub.values.message = "cannot modify mask during cleaning"''' )
319
+ ### save appstate as _appstate in image source for future access
320
+ code='''cb_obj.appstate.convergence_data = initial_convergence_state
321
+ cb_obj.origin._appstate = cb_obj.appstate
322
+ clean_ctrl.continue.disable_add_sub = cb_obj.origin.disable_add_sub.values
323
+ clean_ctrl.finish.disable_add_sub = cb_obj.origin.disable_add_sub.values
324
+ clean_ctrl.stop.disable_add_sub = cb_obj.origin.disable_add_sub.values
325
+ cb_obj.origin.disable_add_sub.values.message = "cannot modify mask during cleaning"''' )
309
326
  if idx == 0 else None )
310
327
 
311
328
  ###
@@ -677,7 +694,7 @@ class InteractiveCleanUI:
677
694
  ctrl={ 'converge': self._clean['converge'] },
678
695
  stopdescmap=ImagingDict.get_summaryminor_stopdesc( ) ),
679
696
  code=self._js['update-converge'] +
680
- '''update_convergence_single( img_state, document._casa_convergence_data.convergence[imid] )''' ) )
697
+ '''update_convergence_single( img_state, cb_obj._appstate.convergence_data.convergence[imid] )''' ) )
681
698
 
682
699
  ###
683
700
  ### collect toolbars for syncing selection
@@ -809,7 +826,8 @@ class InteractiveCleanUI:
809
826
  logbutton=self._log_button,
810
827
  stopdescmap=ImagingDict.get_summaryminor_stopdesc( )
811
828
  ),
812
- code=self._js['update-converge'] + self._js['clean-refresh'] + self._js['clean-disable'] +
829
+ code="const appstate = Bokeh.find.appState(cb_obj.origin);" +
830
+ self._js['update-converge'] + self._js['clean-refresh'] + self._js['clean-disable'] +
813
831
  self._js['clean-enable'] + self._js['clean-status-update'] +
814
832
  self._js['iter-gui-update'] + self._js['clean-wait'] +
815
833
  '''function invalid_niter( s ) {
@@ -858,11 +876,11 @@ class InteractiveCleanUI:
858
876
  // { action: 'stop',
859
877
  // value: { } },
860
878
  // update_gui )
861
- document._casa_window_closed = true
879
+ appstate.window_closed = true
862
880
  /*** this will close the tab >>>>---------+ ***/
863
881
  /*** | ***/
864
- /*** vvvvv----------------------------+ ***/
865
- document._cube_done( Object.entries(images_state).reduce((acc,[k,v]) => ({ ...acc, [k]: v.src.masks( ) }),{ } ) )
882
+ /*** vvvvvvvvv-----------------------+ ***/
883
+ appstate.cube_done( Object.entries(images_state).reduce((acc,[k,v]) => ({ ...acc, [k]: v.src.masks( ) }),{ } ) )
866
884
  }
867
885
  } else if ( state.mode === 'continuous' &&
868
886
  cb_obj.origin.name === 'stop' &&
@@ -941,13 +959,13 @@ class InteractiveCleanUI:
941
959
  self._control['iteration']['stop'], self._control['iteration']['continue'], self._control['iteration']['finish'], sizing_mode="scale_width" ),
942
960
  row( image_tabs, height_policy='max', width_policy='max' ),
943
961
  height_policy='max', width_policy='max' ),
944
- app_state={
945
- 'name': 'interactive clean',
946
- 'initialized': True
947
- } )
962
+ app_state={ ### while the state dictionary itself
963
+ 'name': 'interactive clean', ### is used, these particular element
964
+ 'initialized': True ### are not currently used for anything
965
+ }, title='Interactive Clean' )
948
966
 
949
967
  ###
950
- ### Keep track of which image is currently active in document._casa_image_name (which is
968
+ ### Keep track of which image is currently active in appstate.image_name (which is
951
969
  ### initialized in self._js['initialize']). Also, update the current control sub-tab
952
970
  ### when the field main-tab is changed. An attempt to manage this all within the
953
971
  ### control sub-tabs using a reference to self._image_control_tab_groups from
@@ -955,13 +973,17 @@ class InteractiveCleanUI:
955
973
  ###
956
974
  ### bokeh.core.serialization.SerializationError: circular reference
957
975
  ###
976
+ ### This set of tabs is the primary, outer tabs where each tab contains the complete
977
+ ### set of image controls
978
+ ###
958
979
  image_tabs.js_on_change( 'active', CustomJS( args=dict( names=[ t[0] for t in self._clean_targets.items( ) ],
959
980
  itergroups=self._image_control_tab_groups ),
960
- code='''if ( ! hasprop(document,'_casa_last_control_tab') ) {
961
- document._casa_last_control_tab = 0
981
+ code='''const appstate = Bokeh.find.appState(cb_obj)
982
+ if ( ! hasprop(appstate,'last_control_tab') ) {
983
+ appstate.last_control_tab = 0
962
984
  }
963
- document._casa_image_name = names[cb_obj.active]
964
- itergroups[document._casa_image_name].active = document._casa_last_control_tab''' ) )
985
+ appstate.image_name = names[cb_obj.active]
986
+ itergroups[appstate.image_name].active = appstate.last_control_tab''' ) )
965
987
 
966
988
  # Change display type depending on runtime environment
967
989
  #if self._is_notebook:
@@ -1016,8 +1038,11 @@ class InteractiveCleanUI:
1016
1038
  self._image_control_tab_groups = { }
1017
1039
 
1018
1040
  self._image_control_tab_groups[imid] = result
1041
+
1042
+ ### This set of tabs is the secondary, inner tabs for different controls for an individual image
1019
1043
  result.js_on_change( 'active', CustomJS( args=dict( ),
1020
- code='''document._casa_last_control_tab = cb_obj.active''' ) )
1044
+ code='''const appstate = Bokeh.find.appState(cb_obj)
1045
+ appstate.last_control_tab = cb_obj.active''' ) )
1021
1046
  return result
1022
1047
 
1023
1048
  def _create_image_panel( self, imagetuple ):
@@ -1284,20 +1309,22 @@ class InteractiveCleanUI:
1284
1309
 
1285
1310
  def _initialize_javascript( self ):
1286
1311
  self._js = { ### initialize state
1287
- ### --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
1288
- ### -- document is used storing state --
1289
- ### --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
1290
- 'initialize': '''if ( ! document._casa_initialized ) {
1312
+ ### --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
1313
+ ### -- "logbutton" is a random GUI model which can be used to locate the --
1314
+ ### -- appstate that is used storing state --
1315
+ ### --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
1316
+ 'initialize': '''const appstate = Bokeh.find.appState(logbutton)
1317
+ if ( ! appstate.ic_initialized ) {
1291
1318
  console.log(`casalib version: ${casalib.version}`)
1292
- document._casa_image_name = initial_image
1293
- document._casa_initialized = true
1294
- document._casa_window_closed = false
1319
+ appstate.image_name = initial_image
1320
+ appstate.ic_initialized = true
1321
+ appstate.window_closed = false
1295
1322
  window.addEventListener( 'beforeunload',
1296
1323
  function (e) {
1297
1324
  // if the window is already closed this message is never
1298
1325
  // delivered (unless interactive clean is called again then
1299
1326
  // the event shows up in the newly created control pipe)
1300
- if ( document._casa_window_closed == false ) {
1327
+ if ( appstate.window_closed == false ) {
1301
1328
  ctrl_pipe.send( ids['stop'],
1302
1329
  { action: 'stop', value: { } },
1303
1330
  undefined ) } } )
@@ -1373,13 +1400,13 @@ class InteractiveCleanUI:
1373
1400
 
1374
1401
  function update_convergence( recurse=false ) {
1375
1402
  let convdata
1376
- if ( hasprop(document,'_casa_convergence_data') ) {
1377
- convdata = document._casa_convergence_data
1403
+ if ( hasprop(appstate,'convergence_data') ) {
1404
+ convdata = appstate.convergence_data
1378
1405
  } else {
1379
1406
  if ( ! recurse ) {
1380
1407
  ctrl.converge.pipe.send( ctrl.converge.id, { action: 'retrieve' },
1381
1408
  (msg) => { if ( hasprop( msg.result, 'convergence' ) ) {
1382
- document._casa_convergence_data = { convergence: msg.result.convergence,
1409
+ appstate.convergence_data = { convergence: msg.result.convergence,
1383
1410
  cyclethreshold: msg.result.cyclethreshold }
1384
1411
  update_convergence(true)
1385
1412
  } } )
@@ -1414,8 +1441,8 @@ class InteractiveCleanUI:
1414
1441
  }
1415
1442
 
1416
1443
  if ( hasprop(clean_msg,'convergence') && clean_msg.convergence != null ) {
1417
- document._casa_convergence_data = { convergence: clean_msg.convergence,
1418
- cyclethreshold: clean_msg.cyclethreshold }
1444
+ appstate.convergence_data = { convergence: clean_msg.convergence,
1445
+ cyclethreshold: clean_msg.cyclethreshold }
1419
1446
  }
1420
1447
  }
1421
1448
 
@@ -1497,19 +1524,19 @@ class InteractiveCleanUI:
1497
1524
  'Stopping criteria encountered',
1498
1525
  'Unrecognized stop code' ]
1499
1526
  if ( typeof status === 'number' ) {
1500
- images_state[document._casa_image_name]['status'].text =
1527
+ images_state[appstate.image_name]['status'].text =
1501
1528
  '<p>' +
1502
1529
  stopstr[ status < 0 || status >= stopstr.length ?
1503
1530
  stopstr.length - 1 : status ] +
1504
1531
  '</p>'
1505
1532
  } else {
1506
- images_state[document._casa_image_name]['status'].text = `<p>${status}</p>`
1533
+ images_state[appstate.image_name]['status'].text = `<p>${status}</p>`
1507
1534
  }
1508
1535
  }''',
1509
1536
 
1510
1537
  'iter-gui-update': '''function get_update_dictionary( ) {
1511
- //const amste = images_state[document._casa_image_name]['automask']
1512
- //const clste = images_state[document._casa_image_name]['iteration']
1538
+ //const amste = images_state[appstate.image_name]['automask']
1539
+ //const clste = images_state[appstate.image_name]['iteration']
1513
1540
  // Assumption is that there is ONE set of iteration and automask updates
1514
1541
  // for ALL imaging fields...
1515
1542
  const amobj = Object.entries(images_state)[0][1].automask
@@ -1528,7 +1555,7 @@ class InteractiveCleanUI:
1528
1555
 
1529
1556
  const masks = Object.entries(images_state).reduce( (acc,[k,v]) => { acc[k] = v.src.masks( ); return acc }, { } )
1530
1557
  const breadcrumbs = Object.entries(images_state).reduce( (acc,[k,v]) => { acc[k] = v.src.breadcrumbs( ); return acc }, { } )
1531
- return { iteration, automask, masks, breadcrumbs, current_image: document._casa_image_name }
1558
+ return { iteration, automask, masks, breadcrumbs, current_image: appstate.image_name }
1532
1559
  }
1533
1560
  function update_log( log_lines ) {
1534
1561
  let b = logbutton
cubevis/utils/__init__.py CHANGED
@@ -67,6 +67,7 @@ from ._static import static_vars, static_dir
67
67
  from ._tiles import TMSTiles
68
68
  from ._contextmgrchain import ContextMgrChain
69
69
  from ._import_protected_module import ImportProtectedModule
70
+ from ._mutual_exclusion import MutualExclusionManager
70
71
 
71
72
  @static_vars(mgr=None)
72
73
  def resource_manager( ):