def execute_after_millis(millis, func): def register_timer(): assert is_in_main_thread(), \ 'We can only create QTimers in the main thread '\ '(or at least delete them in the same thread).' with _timers_lock: existing_timer = _timers_alive.get(func) if existing_timer is not None: timer = existing_timer.timer if timer is not None: try: timer.stop() timer.start(millis) except Exception: pass return # Restart it! timer = QTimer() timer_alive = _TimerAlive(func, timer) _timers_alive[func] = timer_alive timer.setSingleShot(True) timer.timeout.connect(timer_alive) timer.start(millis) if not is_in_main_thread(): from pyvmmonitor_qt.qt_event_loop import execute_on_next_event_loop execute_on_next_event_loop(register_timer) else: register_timer()
def assert_condition_within_timeout(condition, timeout=2.): ''' :param callable condition: A callable which may return a bool or a string (if True or an empty string, the condition is considered matched). :param float timeout: Timeout in seconds ''' assert is_in_main_thread() initial = time.time() while True: c = condition() if isinstance(c, bool): if c: return elif isinstance(c, (compat.bytes, compat.unicode)): if not c: return else: raise AssertionError('Expecting bool or string as the return.') if time.time() - initial > timeout: raise AssertionError( u'Could not reach condition before timeout: %s (condition return: %s)' % (timeout, c)) # from pyvmmonitor_qt.qt_event_loop import process_events # process_events() from pyvmmonitor_qt.qt_event_loop import process_queue process_queue() time.sleep(1 / 50.)
def set_selection(self, obj_ids, clear_selection=True): from pyvmmonitor_qt.qt.QtCore import QModelIndex from pyvmmonitor_qt.qt.QtCore import QItemSelection from pyvmmonitor_qt.qt.QtCore import QItemSelectionModel assert thread_utils.is_in_main_thread() selection_model = self.tree.selectionModel() selection = None for obj_id in obj_ids: item = self._fast.get(obj_id) if item is not None: index = item._items[0].index() if index is not None: index = self._sort_model.mapFromSource(index) if selection is None: selection = QItemSelection(index, index) else: selection.select(index, index) if selection: if not clear_selection: selection_model.select( selection, QItemSelectionModel.Select | QItemSelectionModel.Rows) else: selection_model.select( selection, QItemSelectionModel.ClearAndSelect | QItemSelectionModel.Current | QItemSelectionModel.Rows) else: if clear_selection: selection_model.select(QModelIndex(), QItemSelectionModel.Clear)
def execute_after_millis(millis, func): def register_timer(): assert is_in_main_thread(), \ 'We can only create QTimers in the main thread '\ '(or at least delete them in the same thread).' with _timers_lock: existing_timer = _timers_alive.get(func) if existing_timer is not None: timer = existing_timer.timer if timer is not None: try: timer.stop() timer.start(millis) except Exception: pass return # Restart it! timer = QTimer() timer_alive = _TimerAlive(func, timer) _timers_alive[func] = timer_alive timer.setSingleShot(True) timer.timeout.connect(timer_alive) timer.start(millis) if not is_in_main_thread(): from pyvmmonitor_qt.qt_event_loop import execute_on_next_event_loop execute_on_next_event_loop(register_timer) else: register_timer()
def set_selection(self, obj_ids, clear_selection=True): from pyvmmonitor_qt.qt.QtCore import QModelIndex from pyvmmonitor_qt.qt.QtCore import QItemSelection from pyvmmonitor_qt.qt.QtCore import QItemSelectionModel assert thread_utils.is_in_main_thread() selection_model = self.tree.selectionModel() selection = None for obj_id in obj_ids: item = self._fast.get(obj_id) if item is not None: index = item._items[0].index() if index is not None: index = self._sort_model.mapFromSource(index) if selection is None: selection = QItemSelection(index, index) else: selection.select(index, index) if selection: if not clear_selection: selection_model.select( selection, QItemSelectionModel.Select | QItemSelectionModel.Rows) else: selection_model.select( selection, QItemSelectionModel.ClearAndSelect | QItemSelectionModel.Current | QItemSelectionModel.Rows) else: if clear_selection: selection_model.select(QModelIndex(), QItemSelectionModel.Clear)
def assert_condition_within_timeout(condition, timeout=2.): ''' :param callable condition: A callable which may return a bool or a string (if True or an empty string, the condition is considered matched). :param float timeout: Timeout in seconds ''' assert is_in_main_thread() initial = time.time() while True: c = condition() if isinstance(c, bool): if c: return elif isinstance(c, (compat.bytes, compat.unicode)): if not c: return else: raise AssertionError('Expecting bool or string as the return.') if time.time() - initial > timeout: raise AssertionError( u'Could not reach condition before timeout: %s (condition return: %s)' % (timeout, c)) # from pyvmmonitor_qt.qt_event_loop import process_events # process_events() from pyvmmonitor_qt.qt_event_loop import process_queue process_queue() time.sleep(1 / 50.)
def __init__(self): assert is_in_main_thread() QObject.__init__(self) self._collector = GarbageCollector() timer = self.timer = QTimer() timer.timeout.connect(self.check) timer.start(self.INTERVAL)
def __call__(self, *args, **kwargs): # @DontTrace ''' Calls every registered function with the given args and kwargs. ''' callbacks = self._callbacks if not callbacks: return # Note: There's a copy of this code in the _calculate_to_call method below. It's a copy # because we don't want to had a function call overhead here. to_call = [] for key, info in compat.items(callbacks): # iterate in a copy func_obj = info[0] if func_obj is not None: # Ok, we have a self. func_obj = func_obj() if func_obj is None: # self is dead del callbacks[key] else: func_func = info[1] if func_func is None: to_call.append(func_obj) else: if compat.PY2: to_call.append( new.instancemethod(func_func, func_obj, info[2])) else: to_call.append(new.MethodType(func_func, func_obj)) else: func_func = info[1] # No self: either classmethod or just callable to_call.append(func_func) # let's keep the 'if' outside of the iteration... if not is_in_main_thread(): for func in to_call: if not getattr(func, '__call_out_of_main_thread__', False): raise AssertionError( 'Call: %s out of the main thread (and it is not marked as @not_main_thread_callback)!' % (func, )) for func in to_call: try: func(*args, **kwargs) except Exception: # Show it but don't propagate. sys.excepthook(*sys.exc_info())
def __setitem__(self, obj_id, obj): assert thread_utils.is_in_main_thread() assert obj_id not in self._fast try: i = obj_id.rindex('.') except ValueError: parent_node = self._root else: parent_node = self._fast[obj_id[:i]] self._add_child_node(parent_node, obj_id, obj) return obj
def add_child(self, root_id, prefix, obj): assert thread_utils.is_in_main_thread() if root_id: parent_node = self._fast[root_id] prefix = '%s.%s' % (root_id, prefix) else: parent_node = self._root obj_id = '%s%03d' % (prefix, parent_node.next_id(prefix)) while obj_id in self._fast: obj_id = '%s%03d' % (prefix, parent_node.next_id(prefix)) self._add_child_node(parent_node, obj_id, obj) return obj
def get_selection(self): ''' :return list(unicode): Returns a list with the selected items. ''' assert thread_utils.is_in_main_thread() new_selection = [] selected_indexes = self.tree.selectedIndexes() if selected_indexes: nodes = set() for i in selected_indexes: node = i.data(_NODE_ROLE) if node not in nodes: nodes.add(node) if node is not None: obj_id = node.obj_id new_selection.append(obj_id) return new_selection
def get_selection(self): ''' :return list(unicode): Returns a list with the selected items. ''' assert thread_utils.is_in_main_thread() new_selection = [] selected_indexes = self.tree.selectedIndexes() if selected_indexes: nodes = set() for i in selected_indexes: node = i.data(_NODE_ROLE) if node not in nodes: nodes.add(node) if node is not None: obj_id = node.obj_id new_selection.append(obj_id) return new_selection
def set_selection(self, source, selection): if isinstance(selection, basestring): selection = (selection,) # Note: besides removing the duplicates, will also convert the type to a tuple. selection = remove_duplicates(selection, ret_type=tuple) assert isinstance(selection, tuple) assert is_in_main_thread(), 'Can only change selection in main thread.' if selection == self._selection: if not self.reselect_on_same_selection: return False self._selection = selection self._source = source self._do_selection(source, selection) return True
def process_events(collect=False, handle_future_events=False): from pyvmmonitor_core.thread_utils import is_in_main_thread from pyvmmonitor_qt.qt.QtCore import QTimer from .qt_app import obtain_qapp assert is_in_main_thread() if not collect: obtain_qapp().processEvents() else: app = obtain_qapp() timer = QTimer() timer.setSingleShot(True) timer.timeout.connect(app.exit) timer.start(0) app.exec_() if handle_future_events: process_queue(handle_future_events=True)
def process_events(collect=False, handle_future_events=False): from pyvmmonitor_core.thread_utils import is_in_main_thread from pyvmmonitor_qt.qt.QtCore import QTimer from .qt_app import obtain_qapp assert is_in_main_thread() if not collect: obtain_qapp().processEvents() else: app = obtain_qapp() timer = QTimer() timer.setSingleShot(True) timer.timeout.connect(app.exit) timer.start(0) app.exec_() if handle_future_events: process_queue(handle_future_events=True)
def add_node(self, parent_node, obj_id, node, index=-1): ''' Adds a node to the tree below the passed parent. :param TreeNode|unicode|NoneType parent_node: If None is passed, it'll be added to the root, otherwise, it'll be added to the passed node (which can be passed directly or through its id). :param unicode obj_id: The id for this node. :param object|TreeNode node: Either the instanced TreeNode to be added or the data for which a TreeNode should be created. :param int index: The index at which the child node should be added. ''' if isinstance(parent_node, compat.unicode): parent_node = self._fast[parent_node] if not isinstance(node, TreeNode): node = TreeNode(node) assert thread_utils.is_in_main_thread() assert obj_id not in self._fast if parent_node is None: items = node._attach_to_tree(self, obj_id) if index == -1: self._model.appendRow(items) else: assert index >= 0 self._model.insertRow(index, items) self._root_items.add(node) else: items = node._attach_to_tree(self, obj_id) parent_node._append_row(node, index=index) node._parent = parent_node self._fast[obj_id] = node return node
def add_node(self, parent_node, obj_id, node, index=-1): ''' Adds a node to the tree below the passed parent. :param TreeNode|unicode|NoneType parent_node: If None is passed, it'll be added to the root, otherwise, it'll be added to the passed node (which can be passed directly or through its id). :param unicode obj_id: The id for this node. :param object|TreeNode node: Either the instanced TreeNode to be added or the data for which a TreeNode should be created. :param int index: The index at which the child node should be added. ''' if isinstance(parent_node, compat.unicode): parent_node = self._fast[parent_node] if not isinstance(node, TreeNode): node = TreeNode(node) assert thread_utils.is_in_main_thread() assert obj_id not in self._fast, '%s already in %s' % (obj_id, self) if parent_node is None: items = node._attach_to_tree(self, obj_id) if index == -1: self._model.appendRow(items) else: assert index >= 0 self._model.insertRow(index, items) self._root_items.add(node) else: items = node._attach_to_tree(self, obj_id) parent_node._append_row(node, index=index) node._parent = parent_node self._fast[obj_id] = node return node
def _assert_condition_within_timeout(condition, timeout=2.): assert is_in_main_thread() initial = time.time() while True: c = condition() if isinstance(c, bool): if c: return elif isinstance(c, (compat.bytes, compat.unicode)): if not c: return else: raise AssertionError('Expecting bool or string as the return.') if time.time() - initial > timeout: raise AssertionError( u'Could not reach condition before timeout: %s (condition return: %s)' % (timeout, c)) # process_events() time.sleep(1 / 60.)
def register_timer(): assert is_in_main_thread(), \ 'We can only create QTimers in the main thread '\ '(or at least delete them in the same thread).' with _timers_lock: existing_timer = _timers_alive.get(func) if existing_timer is not None: timer = existing_timer.timer if timer is not None: try: timer.stop() timer.start(millis) except Exception: pass return # Restart it! timer = QTimer() timer_alive = _TimerAlive(func, timer) _timers_alive[func] = timer_alive timer.setSingleShot(True) timer.timeout.connect(timer_alive) timer.start(millis)
def register_timer(): assert is_in_main_thread(), \ 'We can only create QTimers in the main thread '\ '(or at least delete them in the same thread).' with _timers_lock: existing_timer = _timers_alive.get(func) if existing_timer is not None: timer = existing_timer.timer if timer is not None: try: timer.stop() timer.start(millis) except Exception: pass return # Restart it! timer = QTimer() timer_alive = _TimerAlive(func, timer) _timers_alive[func] = timer_alive timer.setSingleShot(True) timer.timeout.connect(timer_alive) timer.start(millis)
def itertree(self, node=None, recursive=True, class_=None): ''' Iters children of the node sorted in tree order. :note: Usually to get all classes it'd be better to use iter_instances and to iterate all iteritems() (if the order is not important). Yields obj_id and the obj ''' assert thread_utils.is_in_main_thread() if node is None: node = self._root if recursive: if not class_: return self._iter_recursive_no_class(node) else: return self._iter_recursive_class(node, class_) else: if class_: return self._iter_no_recursive_class(node, class_) else: return self._iter_no_recursive_no_class(node)
def check(self): assert is_in_main_thread() DEBUG = False # Uncomment for debug if DEBUG: flags = ( gc.DEBUG_COLLECTABLE | gc.DEBUG_UNCOLLECTABLE | gc.DEBUG_SAVEALL # i.e.: put in gc.garbage! ) try: flags |= gc.DEBUG_INSTANCES # @UndefinedVariable except AttributeError: pass try: flags |= gc.DEBUG_OBJECTS # @UndefinedVariable except AttributeError: pass try: flags |= gc.DEBUG_LEAK except AttributeError: pass try: flags |= gc.DEBUG_STATS except AttributeError: pass else: flags = 0 gc.set_debug(flags) l0, l1, l2 = gc.get_count() if l0 > self.threshold[0]: num = gc.collect(0) if DEBUG: print('collecting gen 0, found:', num, 'unreachable') if l1 > self.threshold[1]: num = gc.collect(1) if DEBUG: print('collecting gen 1, found:', num, 'unreachable') if l2 > self.threshold[2]: num = gc.collect(2) if DEBUG: print('collecting gen 2, found:', num, 'unreachable') # uncomment for debug if DEBUG: garbage = gc.garbage if garbage: for obj in garbage: print('Error: cycle in: %s (%r) %s' % (obj, repr(obj), type(obj))) del gc.garbage[:] gc.set_debug(0)
def show_message( message, detailed_message='', title='Error', parent=None, icon=None): ''' :param icon: QMessageBox.NoIcon QMessageBox.Question QMessageBox.Information QMessageBox.Warning QMessageBox.Critical ''' from pyvmmonitor_qt.qt.QtWidgets import QMessageBox if icon is None: icon = QMessageBox.Critical if isinstance(icon, compat.bytes): icon = icon.decode('utf-8', 'replace') if isinstance(icon, compat.unicode): icon = icon.lower() if icon == 'error': icon = QMessageBox.Critical elif icon in ('warning', 'warn'): icon = QMessageBox.Warning elif icon in ('information', 'info'): icon = QMessageBox.Information elif icon == 'question': icon = QMessageBox.Question else: logger.warn('Invalid icon: %s' % (icon,)) icon = QMessageBox.NoIcon if not is_in_main_thread(): # Important: if we're not in the main thread, we have to schedule to run it later # (in the UI thread). def func(): show_message(message, detailed_message, title, parent, icon) from pyvmmonitor_qt.qt_event_loop import execute_on_next_event_loop execute_on_next_event_loop(func) return if parent is None: parent = get_main_window() from pyvmmonitor_qt.qt_app import obtain_qapp get_icon = obtain_qapp().style().standardIcon from pyvmmonitor_qt.qt.QtWidgets import QStyle if icon == QMessageBox.Information: icon = get_icon(QStyle.SP_MessageBoxInformation) elif icon == QMessageBox.Critical: icon = get_icon(QStyle.SP_MessageBoxCritical) elif icon == QMessageBox.Warning: icon = get_icon(QStyle.SP_MessageBoxWarning) elif icon == QMessageBox.Question: icon = get_icon(QStyle.SP_MessageBoxQuestion) else: from pyvmmonitor_qt.qt.QtGui import QIcon icon = QIcon() return __show_dialog_and_exec(parent, title, message, detailed_message, icon)
def show_message( message, detailed_message='', title='Error', parent=None, icon=None): ''' :param icon: QMessageBox.NoIcon QMessageBox.Question QMessageBox.Information QMessageBox.Warning QMessageBox.Critical ''' from pyvmmonitor_qt.qt.QtWidgets import QMessageBox if icon is None: icon = QMessageBox.Critical if isinstance(icon, compat.bytes): icon = icon.decode('utf-8', 'replace') if isinstance(icon, compat.unicode): icon = icon.lower() if icon == 'error': icon = QMessageBox.Critical elif icon in ('warning', 'warn'): icon = QMessageBox.Warning elif icon in ('information', 'info'): icon = QMessageBox.Information elif icon == 'question': icon = QMessageBox.Question else: logger.warn('Invalid icon: %s' % (icon,)) icon = QMessageBox.NoIcon if not is_in_main_thread(): # Important: if we're not in the main thread, we have to schedule to run it later # (in the UI thread). def func(): show_message(message, detailed_message, title, parent, icon) from pyvmmonitor_qt.qt_event_loop import execute_on_next_event_loop execute_on_next_event_loop(func) return if parent is None: parent = get_main_window() from pyvmmonitor_qt.qt_app import obtain_qapp get_icon = obtain_qapp().style().standardIcon from pyvmmonitor_qt.qt.QtWidgets import QStyle if icon == QMessageBox.Information: icon = get_icon(QStyle.SP_MessageBoxInformation) elif icon == QMessageBox.Critical: icon = get_icon(QStyle.SP_MessageBoxCritical) elif icon == QMessageBox.Warning: icon = get_icon(QStyle.SP_MessageBoxWarning) elif icon == QMessageBox.Question: icon = get_icon(QStyle.SP_MessageBoxQuestion) else: from pyvmmonitor_qt.qt.QtGui import QIcon icon = QIcon() return __show_dialog_and_exec(parent, title, message, detailed_message, icon)