Skip to content

Commit

Permalink
Merge pull request #1328 from astrofrog/update-echo-5
Browse files Browse the repository at this point in the history
Update echo and fix failures due to restoring settings all in one go
  • Loading branch information
astrofrog authored Jul 5, 2017
2 parents 9151839 + 1ccf6f7 commit 3ea9531
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 9 deletions.
62 changes: 59 additions & 3 deletions glue/external/echo/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,11 +174,40 @@ class HasCallbackProperties(object):
def __init__(self):
from .list import ListCallbackProperty
self._global_callbacks = CallbackContainer()
self._ignored_properties = set()
self._delayed_properties = {}
self._delay_global_calls = {}
self._callback_wrappers = {}
for prop_name, prop in self.iter_callback_properties():
if isinstance(prop, ListCallbackProperty):
prop.add_callback(self, self._notify_global_lists)

def _ignore_global_callbacks(self, properties):
# This is to allow ignore_callbacks to work for global callbacks
self._ignored_properties.update(properties)

def _unignore_global_callbacks(self, properties):
# Once this is called, we simply remove properties from _ignored_properties
# and don't call the callbacks. This is used by ignore_callback
self._ignored_properties -= set(properties)

def _delay_global_callbacks(self, properties):
# This is to allow delay_callback to still have an effect in delaying
# global callbacks. We set _delayed_properties to a dictionary of the
# values at the point at which the callbacks are delayed.
self._delayed_properties.update(properties)

def _process_delayed_global_callbacks(self, properties):
# Once this is called, the global callbacks are called once each with
# a dictionary of the current values of properties that have been
# resumed.
kwargs = {}
for prop, new_value in properties.items():
old_value = self._delayed_properties.pop(prop)
if old_value != new_value:
kwargs[prop] = new_value
self._notify_global(**kwargs)

def _notify_global_lists(self, *args):
from .list import ListCallbackProperty
properties = {}
Expand All @@ -191,8 +220,12 @@ def _notify_global_lists(self, *args):
self._notify_global(**properties)

def _notify_global(self, **kwargs):
for callback in self._global_callbacks:
callback(**kwargs)
for prop in set(self._delayed_properties) | set(self._ignored_properties):
if prop in kwargs:
kwargs.pop(prop)
if len(kwargs) > 0:
for callback in self._global_callbacks:
callback(**kwargs)

def __setattr__(self, attribute, value):
super(HasCallbackProperties, self).__setattr__(attribute, value)
Expand Down Expand Up @@ -414,6 +447,8 @@ def __init__(self, instance, *props):

def __enter__(self):

delay_props = {}

for prop in self.props:

p = getattr(type(self.instance), prop)
Expand All @@ -423,13 +458,21 @@ def __enter__(self):
if (self.instance, prop) not in self.delay_count:
self.delay_count[self.instance, prop] = 1
self.old_values[self.instance, prop] = p.__get__(self.instance)
delay_props[prop] = p.__get__(self.instance)
else:
self.delay_count[self.instance, prop] += 1

p.disable(self.instance)

if isinstance(self.instance, HasCallbackProperties):
self.instance._delay_global_callbacks(delay_props)

def __exit__(self, *args):

resume_props = {}

notifications = []

for prop in self.props:

p = getattr(type(self.instance), prop)
Expand All @@ -444,7 +487,14 @@ def __exit__(self, *args):
p.enable(self.instance)
new = p.__get__(self.instance)
if old != new:
p.notify(self.instance, old, new)
notifications.append((p, (self.instance, old, new)))
resume_props[prop] = new

if isinstance(self.instance, HasCallbackProperties):
self.instance._process_delayed_global_callbacks(resume_props)

for p, args in notifications:
p.notify(*args)


@contextmanager
Expand Down Expand Up @@ -481,13 +531,19 @@ def ignore_callback(instance, *props):
raise TypeError("%s is not a CallbackProperty" % prop)
p.disable(instance)

if isinstance(instance, HasCallbackProperties):
instance._ignore_global_callbacks(props)

yield

for prop in props:
p = getattr(type(instance), prop)
assert isinstance(p, CallbackProperty)
p.enable(instance)

if isinstance(instance, HasCallbackProperties):
instance._unignore_global_callbacks(props)


class keep_in_sync(object):

Expand Down
4 changes: 3 additions & 1 deletion glue/viewers/histogram/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ def __init__(self, **kwargs):
def _update_priority(self, name):
if name == 'layers':
return 2
elif name.endswith(('_min', '_max', '_bin', '_log')):
elif name.endswith('_log'):
return 0.5
elif name.endswith(('_min', '_max', '_bin')):
return 0
else:
return 1
Expand Down
8 changes: 4 additions & 4 deletions glue/viewers/matplotlib/qt/data_viewer.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from glue.viewers.common.qt.data_viewer import DataViewer
from glue.viewers.matplotlib.qt.widget import MplWidget
from glue.viewers.common.viz_client import init_mpl, update_appearance_from_settings
from glue.external.echo import add_callback
from glue.external.echo import add_callback, delay_callback
from glue.utils import nonpartial, defer_draw
from glue.utils.decorators import avoid_circular
from glue.viewers.matplotlib.qt.toolbar import MatplotlibViewerToolbar
Expand Down Expand Up @@ -98,9 +98,9 @@ def update_y_log(self):

@avoid_circular
def limits_from_mpl(self):
# TODO: delay callbacks here
self.state.x_min, self.state.x_max = self.axes.get_xlim()
self.state.y_min, self.state.y_max = self.axes.get_ylim()
with delay_callback(self.state, 'x_min', 'x_max', 'y_min', 'y_max'):
self.state.x_min, self.state.x_max = self.axes.get_xlim()
self.state.y_min, self.state.y_max = self.axes.get_ylim()

@avoid_circular
def limits_to_mpl(self):
Expand Down
4 changes: 3 additions & 1 deletion glue/viewers/scatter/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ def __init__(self, **kwargs):
def _update_priority(self, name):
if name == 'layers':
return 2
elif name.endswith(('_min', '_max', '_log')):
elif name.endswith('_log'):
return 0.5
elif name.endswith(('_min', '_max')):
return 0
else:
return 1
Expand Down

0 comments on commit 3ea9531

Please sign in to comment.