if True:
  from PySide import QtGui
  from PySide import QtCore
  import threading
  from collections import defaultdict

  # resizing a window too fast seems to allow for the window manager to drop some requests.
  # for experimentation, we resize a label within a fixed-size window.
  w = QtGui.QLabel()
  w.show()
  w.setGeometry(QtCore.QRect(100,100,400,400))

  propagators = {
      'width': lambda src, dest:
        dest.__self__.setGeometry(QtCore.QRect(dest.__self__.x(), dest.__self__.y(), src.value, dest.__self__.height())),
      'height': lambda src, dest:
        dest.__self__.setGeometry(QtCore.QRect(dest.__self__.x(), dest.__self__.y(), dest.__self__.width(), src.value))
  }

  def propagate(src, dest):
    propagators[dest.__name__](src, dest)

  def connect(src, dest):
    src.register('set', lambda _: propagate(src, dest))

  class Model:
    def __init__(self):
      self._lock = threading.Lock()
      self._eventTypeToCallbacks = defaultdict(dict) # key: string i.e. event type, value: {callback}
      self._eventTypeToCurrent = dict()
      self._nextId = 0
    def notify(self, eventType, info):
      with self._lock:
        self._eventTypeToCurrent[eventType] = info
        # avoid race conditions by caching the list of callbacks, that way if
        # one of the callbacks modifies the list of callbacks, it won't cause
        # issues. Also, it prevents deadlocks if one of the callbacks tries to
        # perform an operation which would try to acquire the lock.
        cachedCallbacks = [c for c in self._eventTypeToCallbacks[eventType].values()]
      for c in cachedCallbacks:
        c(info)
    def register(self, eventType, callback):
      with self._lock:
        callbackId = self._nextId
        self._nextId = self._nextId + 1
        self._eventTypeToCallbacks[eventType][callbackId] = callback
        cachedHasCurrent = False
        if eventType in self._eventTypeToCurrent:
          cachedCurrent = self._eventTypeToCurrent[eventType]
          cachedHasCurrent = True
      if cachedHasCurrent:
        callback(cachedCurrent)
      return callbackId
    def unregister(self, event, callbackId):
      with self._lock:
        del self._eventTypeToCallbacks[eventType][callbackId]

  class Connection:
    def __init__(self, src, dest):
      self.src = src
      self.dest = dest

  class ModelFragment(Model):
    def __init__(self, name, v):
      super(ModelFragment, self).__init__()
      self.name = name
      if isinstance(v, ModelFragment):
        self.value = v.value
      else:
        self.value = v
      self.notify('set', self.value)
    def setValue(self, v):
      self.value = v
      self.notify('set', self.value)
    def __rshift__(self, other):
      return Connection(self, other)

  class ModelPropertySet(Model):
    def _getter(self, p):
      def real_getter(self):
        return self._properties[p]
      return real_getter
    def _setter(self, p):
      def real_setter(self, v):
        if isinstance(v, Connection):
          connect(v.src, v.dest)
        else:
          self._properties[p].setValue(v)
      return real_setter
    def __init__(self, theClass, properties):
      super(ModelPropertySet, self).__init__()
      self._properties = {}
      for (p, v) in properties.items():
        self._properties[p] = ModelFragment(p, v)
        setattr(theClass, p, property(self._getter(p), self._setter(p)))

  class ModelNode(ModelPropertySet):
    def __init__(self):
      super(ModelNode, self).__init__(ModelNode, {
        'width': 200,
        'height': 200
      })
  
  m = ModelNode()

  l = QtGui.QLabel()
  l.setStyleSheet("QLabel { background-color : rgba(0,0,255,100%); color : black; }")
  l.setParent(w)
  l.show()
  l.setGeometry(QtCore.QRect(100,100,100,100))

  m.width >>= l.width
  m.height >>= l.height
  
  m.width = 50