Mini Shell
# Default event queue for Simpleline application.
#
# This class is thread safe.
#
# Copyright (C) 2017 Red Hat, Inc.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions of
# the GNU General Public License v.2, or (at your option) any later version.
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY expressed or implied, including the implied warranties of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details. You should have received a copy of the
# GNU General Public License along with this program; if not, write to the
# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA. Any Red Hat trademarks that are incorporated in the
# source code or documentation are not subject to the GNU General Public
# License and may only be used or replicated with the express permission of
# Red Hat, Inc.
#
# Author(s): Jiri Konecny <jkonecny@redhat.com>
#
from queue import PriorityQueue
from threading import Lock
from simpleline.errors import SimplelineError
class EventQueueError(SimplelineError):
"""Main exception for `EventQueue` class.
Inherits from `simpleline.SimplelineError`.
"""
class EventQueue(object):
"""Class for managing signal queue.
Responsibilities of this class are:
* sorting by priority of signals
* managing sources for this event queue
* enqueuing signals
"""
def __init__(self):
self._queue = PriorityQueue()
self._contained_screens = set()
self._lock = Lock()
def empty(self):
"""Return true if Queue is empty.
:return: True if empty, False otherwise.
"""
return self._queue.empty()
def enqueue(self, signal):
"""Enqueue signal to this queue.
:param signal: Signal which should be enqueued to this queue.
:type signal: Signal class based on `simpleline.event_loop.signals.AbstractSignal`.
"""
self._queue.put(signal)
def enqueue_if_source_belongs(self, signal, source):
"""Enqueue signal to this queue if the signal source belongs to this queue.
Enqueue the `signal` only if the `source` belongs to this queue. See the `add_source()` method.
:param signal: Signal which should be enqueued to this queue.
:type signal: Signal class based on `simpleline.event_loop.signals.AbstractSignal`.
:param source: Source of this signal.
:type source: Anything.
:return: True if the source belongs to this queue and signal was queued, False otherwise.
:rtype: bool
"""
if self.contains_source(source):
self._queue.put(signal)
return True
else:
return False
def get(self):
"""Return enqueued signal with the highest priority.
This is FIFO implementation for the same priority.
If the queue is empty this method will wait for the input signal.
:return: Queued signal.
:rtype: Signal based on class `simpleline.event_loop.signals.AbstractSignal`.
"""
return self._queue.get()
def get_top_event_if_priority(self, priority):
"""Return top enqueued signal if priority is equal to `priority`. Otherwise `None`.
:param priority: Requested event priority.
:type priority: int
:return: Queued signal if it has requested priority. Otherwise `None`.
:rtype: Signal based on class `simpleline.event_loop.signals.AbstractSignal` or `None`.
"""
event = self._queue.get()
if event.priority == priority:
return event
else:
self._queue.put(event)
return None
def add_source(self, signal_source):
"""Add new source of signals to this queue.
This method is mandatory for `enqueue_if_source_belongs()` method.
The same source will be added only once.
:param signal_source: Source of future signals.
:type signal_source: Anything which will emit signals in future.
"""
# TODO: Remove when python3-astroid 1.5.3 will be in Fedora
# pylint: disable=not-context-manager
with self._lock:
self._contained_screens.add(signal_source)
def remove_source(self, signal_source):
"""Remove signal source from this queue.
:param signal_source: Source of future signals.
:type signal_source: Anything.
:raise: EventQueueError"""
try:
# TODO: Remove when python3-astroid 1.5.3 will be in Fedora
# pylint: disable=not-context-manager
with self._lock:
self._contained_screens.remove(signal_source)
except KeyError:
raise EventQueueError("Can't remove non-existing event source!")
def contains_source(self, signal_source):
"""Test if `signal_source` belongs to this queue.
:param signal_source: Source of signals.
:type signal_source: Anything.
:return: True if signal source belongs to this queue.
:rtype: bool
"""
# TODO: Remove when python3-astroid 1.5.3 will be in Fedora
# pylint: disable=not-context-manager
with self._lock:
return signal_source in self._contained_screens