mirror of
https://github.com/home-assistant/core.git
synced 2025-07-17 10:17:09 +00:00
EventBus can now report overview of events that have listeners.
This commit is contained in:
parent
63a1dfc64f
commit
a60f6754aa
@ -124,9 +124,16 @@ class EventBus(object):
|
|||||||
""" Class that allows code to listen for- and fire events. """
|
""" Class that allows code to listen for- and fire events. """
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.listeners = defaultdict(list)
|
self._listeners = defaultdict(list)
|
||||||
self.logger = logging.getLogger(__name__)
|
self.logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def listeners(self):
|
||||||
|
""" List of events that is being listened for. """
|
||||||
|
return { key: len(self._listeners[key])
|
||||||
|
for key in self._listeners.keys()
|
||||||
|
if len(self._listeners[key]) > 0 }
|
||||||
|
|
||||||
def fire(self, event_type, event_data=None):
|
def fire(self, event_type, event_data=None):
|
||||||
""" Fire an event. """
|
""" Fire an event. """
|
||||||
|
|
||||||
@ -142,8 +149,8 @@ class EventBus(object):
|
|||||||
|
|
||||||
# We do not use itertools.chain() because some listeners might
|
# We do not use itertools.chain() because some listeners might
|
||||||
# choose to remove themselves as a listener while being executed
|
# choose to remove themselves as a listener while being executed
|
||||||
for listener in self.listeners[ALL_EVENTS] + \
|
for listener in self._listeners[ALL_EVENTS] + \
|
||||||
self.listeners[event.event_type]:
|
self._listeners[event.event_type]:
|
||||||
try:
|
try:
|
||||||
listener(event)
|
listener(event)
|
||||||
|
|
||||||
@ -159,7 +166,7 @@ class EventBus(object):
|
|||||||
To listen to all events specify the constant ``ALL_EVENTS``
|
To listen to all events specify the constant ``ALL_EVENTS``
|
||||||
as event_type.
|
as event_type.
|
||||||
"""
|
"""
|
||||||
self.listeners[event_type].append(listener)
|
self._listeners[event_type].append(listener)
|
||||||
|
|
||||||
def listen_once(self, event_type, listener):
|
def listen_once(self, event_type, listener):
|
||||||
""" Listen once for event of a specific type.
|
""" Listen once for event of a specific type.
|
||||||
@ -181,10 +188,10 @@ class EventBus(object):
|
|||||||
def remove_listener(self, event_type, listener):
|
def remove_listener(self, event_type, listener):
|
||||||
""" Removes a listener of a specific event_type. """
|
""" Removes a listener of a specific event_type. """
|
||||||
try:
|
try:
|
||||||
self.listeners[event_type].remove(listener)
|
self._listeners[event_type].remove(listener)
|
||||||
|
|
||||||
if len(self.listeners[event_type]) == 0:
|
if len(self._listeners[event_type]) == 0:
|
||||||
del self.listeners[event_type]
|
del self._listeners[event_type]
|
||||||
|
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
|
@ -144,6 +144,7 @@ class RequestHandler(BaseHTTPRequestHandler):
|
|||||||
'_handle_post_states_category'),
|
'_handle_post_states_category'),
|
||||||
|
|
||||||
# /events
|
# /events
|
||||||
|
('GET', '/events', '_handle_get_events'),
|
||||||
('POST', re.compile(r'/events/(?P<event_type>\w+)'),
|
('POST', re.compile(r'/events/(?P<event_type>\w+)'),
|
||||||
'_handle_post_events_event_type')
|
'_handle_post_events_event_type')
|
||||||
]
|
]
|
||||||
@ -300,11 +301,8 @@ class RequestHandler(BaseHTTPRequestHandler):
|
|||||||
# Describe event bus:
|
# Describe event bus:
|
||||||
write(("<table><tr><th>Event</th><th>Listeners</th></tr>"))
|
write(("<table><tr><th>Event</th><th>Listeners</th></tr>"))
|
||||||
|
|
||||||
for category in sorted(self.server.eventbus.listeners,
|
for event_type, count in sorted(self.server.eventbus.listeners.items()):
|
||||||
key=lambda key: key.lower()):
|
write("<tr><td>{}</td><td>{}</td></tr>".format(event_type, count))
|
||||||
write("<tr><td>{}</td><td>{}</td></tr>".
|
|
||||||
format(category,
|
|
||||||
len(self.server.eventbus.listeners[category])))
|
|
||||||
|
|
||||||
# Form to allow firing events
|
# Form to allow firing events
|
||||||
write("</table>")
|
write("</table>")
|
||||||
@ -368,6 +366,10 @@ class RequestHandler(BaseHTTPRequestHandler):
|
|||||||
self._message("Invalid JSON for attributes",
|
self._message("Invalid JSON for attributes",
|
||||||
HTTP_UNPROCESSABLE_ENTITY)
|
HTTP_UNPROCESSABLE_ENTITY)
|
||||||
|
|
||||||
|
def _handle_get_events(self, path_match, data):
|
||||||
|
""" Handles getting overview of event listeners. """
|
||||||
|
self._write_json({'listeners': self.server.eventbus.listeners})
|
||||||
|
|
||||||
def _handle_post_events_event_type(self, path_match, data):
|
def _handle_post_events_event_type(self, path_match, data):
|
||||||
""" Handles firing of an event. """
|
""" Handles firing of an event. """
|
||||||
event_type = path_match.group('event_type')
|
event_type = path_match.group('event_type')
|
||||||
|
@ -55,6 +55,35 @@ class EventBus(ha.EventBus):
|
|||||||
|
|
||||||
self.logger = logging.getLogger(__name__)
|
self.logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def listeners(self):
|
||||||
|
""" List of events that is being listened for. """
|
||||||
|
try:
|
||||||
|
req = self._call_api(METHOD_GET, hah.URL_API_EVENTS)
|
||||||
|
|
||||||
|
if req.status_code == 200:
|
||||||
|
data = req.json()
|
||||||
|
|
||||||
|
return data['listeners']
|
||||||
|
|
||||||
|
else:
|
||||||
|
raise ha.HomeAssistantException(
|
||||||
|
"Got unexpected result (3): {}.".format(req.text))
|
||||||
|
|
||||||
|
except requests.exceptions.ConnectionError:
|
||||||
|
self.logger.exception("EventBus:Error connecting to server")
|
||||||
|
raise ha.HomeAssistantException("Error connecting to server")
|
||||||
|
|
||||||
|
except ValueError: # If req.json() can't parse the json
|
||||||
|
self.logger.exception("EventBus:Got unexpected result")
|
||||||
|
raise ha.HomeAssistantException(
|
||||||
|
"Got unexpected result: {}".format(req.text))
|
||||||
|
|
||||||
|
except KeyError: # If not all expected keys are in the returned JSON
|
||||||
|
self.logger.exception("EventBus:Got unexpected result (2)")
|
||||||
|
raise ha.HomeAssistantException(
|
||||||
|
"Got unexpected result (2): {}".format(req.text))
|
||||||
|
|
||||||
def fire(self, event_type, event_data=None):
|
def fire(self, event_type, event_data=None):
|
||||||
""" Fire an event. """
|
""" Fire an event. """
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@ def ensure_homeassistant_started():
|
|||||||
core = {'eventbus': ha.EventBus()}
|
core = {'eventbus': ha.EventBus()}
|
||||||
core['statemachine'] = ha.StateMachine(core['eventbus'])
|
core['statemachine'] = ha.StateMachine(core['eventbus'])
|
||||||
|
|
||||||
|
core['eventbus'].listen('test_event', len)
|
||||||
core['statemachine'].set_state('test','a_state')
|
core['statemachine'].set_state('test','a_state')
|
||||||
|
|
||||||
hah.HTTPInterface(core['eventbus'], core['statemachine'],
|
hah.HTTPInterface(core['eventbus'], core['statemachine'],
|
||||||
@ -83,14 +84,14 @@ class TestHTTPInterface(unittest.TestCase):
|
|||||||
def test_api_password(self):
|
def test_api_password(self):
|
||||||
""" Test if we get access denied if we omit or provide
|
""" Test if we get access denied if we omit or provide
|
||||||
a wrong api password. """
|
a wrong api password. """
|
||||||
req = requests.post(
|
req = requests.get(
|
||||||
_url(hah.URL_API_STATES_CATEGORY.format("test")))
|
_url(hah.URL_API_STATES_CATEGORY.format("test")))
|
||||||
|
|
||||||
self.assertEqual(req.status_code, 401)
|
self.assertEqual(req.status_code, 401)
|
||||||
|
|
||||||
req = requests.post(
|
req = requests.get(
|
||||||
_url(hah.URL_API_STATES_CATEGORY.format("test")),
|
_url(hah.URL_API_STATES_CATEGORY.format("test")),
|
||||||
data={"api_password":"not the password"})
|
params={"api_password":"not the password"})
|
||||||
|
|
||||||
self.assertEqual(req.status_code, 401)
|
self.assertEqual(req.status_code, 401)
|
||||||
|
|
||||||
@ -125,7 +126,7 @@ class TestHTTPInterface(unittest.TestCase):
|
|||||||
""" Test if the debug interface allows us to get a state. """
|
""" Test if the debug interface allows us to get a state. """
|
||||||
req = requests.get(
|
req = requests.get(
|
||||||
_url(hah.URL_API_STATES_CATEGORY.format("does_not_exist")),
|
_url(hah.URL_API_STATES_CATEGORY.format("does_not_exist")),
|
||||||
data={"api_password":API_PASSWORD})
|
params={"api_password":API_PASSWORD})
|
||||||
|
|
||||||
self.assertEqual(req.status_code, 422)
|
self.assertEqual(req.status_code, 422)
|
||||||
|
|
||||||
@ -227,6 +228,15 @@ class TestHTTPInterface(unittest.TestCase):
|
|||||||
self.assertEqual(req.status_code, 422)
|
self.assertEqual(req.status_code, 422)
|
||||||
self.assertEqual(len(test_value), 0)
|
self.assertEqual(len(test_value), 0)
|
||||||
|
|
||||||
|
def test_api_get_event_listeners(self):
|
||||||
|
""" Test if we can get the list of events being listened for. """
|
||||||
|
req = requests.get(_url(hah.URL_API_EVENTS),
|
||||||
|
params={"api_password":API_PASSWORD})
|
||||||
|
|
||||||
|
data = req.json()
|
||||||
|
|
||||||
|
self.assertEqual(data['listeners'], self.eventbus.listeners)
|
||||||
|
|
||||||
class TestRemote(unittest.TestCase):
|
class TestRemote(unittest.TestCase):
|
||||||
""" Test the homeassistant.remote module. """
|
""" Test the homeassistant.remote module. """
|
||||||
|
|
||||||
@ -273,6 +283,9 @@ class TestRemote(unittest.TestCase):
|
|||||||
self.assertEqual(state['state'], "set_remotely")
|
self.assertEqual(state['state'], "set_remotely")
|
||||||
self.assertEqual(state['attributes']['test'], 1)
|
self.assertEqual(state['attributes']['test'], 1)
|
||||||
|
|
||||||
|
def test_remote_eb_listening_for_same(self):
|
||||||
|
""" Test if remote EB correctly reports listener overview. """
|
||||||
|
self.assertEqual(self.eventbus.listeners, self.remote_eb.listeners)
|
||||||
|
|
||||||
# pylint: disable=invalid-name
|
# pylint: disable=invalid-name
|
||||||
def test_remote_eb_fire_event_with_no_data(self):
|
def test_remote_eb_fire_event_with_no_data(self):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user