mirror of
https://github.com/home-assistant/core.git
synced 2025-04-23 00:37:53 +00:00
Upgrade aiohttp to 1.1.5 (#4213)
This commit is contained in:
parent
febe16d700
commit
95b439fbd5
@ -8,7 +8,7 @@ import os
|
||||
from aiohttp import web
|
||||
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.const import EVENT_HOMEASSISTANT_START, HTTP_NOT_FOUND
|
||||
from homeassistant.const import HTTP_NOT_FOUND
|
||||
from homeassistant.components import api, group
|
||||
from homeassistant.components.http import HomeAssistantView
|
||||
from .version import FINGERPRINTS
|
||||
@ -18,7 +18,6 @@ DEPENDENCIES = ['api']
|
||||
URL_PANEL_COMPONENT = '/frontend/panels/{}.html'
|
||||
URL_PANEL_COMPONENT_FP = '/frontend/panels/{}-{}.html'
|
||||
STATIC_PATH = os.path.join(os.path.dirname(__file__), 'www_static')
|
||||
PANELS = {}
|
||||
MANIFEST_JSON = {
|
||||
"background_color": "#FFFFFF",
|
||||
"description": "Open-source home automation platform running on Python 3.",
|
||||
@ -32,6 +31,16 @@ MANIFEST_JSON = {
|
||||
"theme_color": "#03A9F4"
|
||||
}
|
||||
|
||||
for size in (192, 384, 512, 1024):
|
||||
MANIFEST_JSON['icons'].append({
|
||||
"src": "/static/icons/favicon-{}x{}.png".format(size, size),
|
||||
"sizes": "{}x{}".format(size, size),
|
||||
"type": "image/png"
|
||||
})
|
||||
|
||||
DATA_PANELS = 'frontend_panels'
|
||||
DATA_INDEX_VIEW = 'frontend_index_view'
|
||||
|
||||
# To keep track we don't register a component twice (gives a warning)
|
||||
_REGISTERED_COMPONENTS = set()
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
@ -68,10 +77,14 @@ def register_panel(hass, component_name, path, md5=None, sidebar_title=None,
|
||||
|
||||
Warning: this API will probably change. Use at own risk.
|
||||
"""
|
||||
panels = hass.data.get(DATA_PANELS)
|
||||
if panels is None:
|
||||
panels = hass.data[DATA_PANELS] = {}
|
||||
|
||||
if url_path is None:
|
||||
url_path = component_name
|
||||
|
||||
if url_path in PANELS:
|
||||
if url_path in panels:
|
||||
_LOGGER.warning('Overwriting component %s', url_path)
|
||||
if not os.path.isfile(path):
|
||||
_LOGGER.error('Panel %s component does not exist: %s',
|
||||
@ -106,7 +119,15 @@ def register_panel(hass, component_name, path, md5=None, sidebar_title=None,
|
||||
fprinted_url = URL_PANEL_COMPONENT_FP.format(component_name, md5)
|
||||
data['url'] = fprinted_url
|
||||
|
||||
PANELS[url_path] = data
|
||||
panels[url_path] = data
|
||||
|
||||
# Register index view for this route if IndexView already loaded
|
||||
# Otherwise it will be done during setup.
|
||||
index_view = hass.data.get(DATA_INDEX_VIEW)
|
||||
|
||||
if index_view:
|
||||
hass.http.app.router.add_route('get', '/{}'.format(url_path),
|
||||
index_view.get)
|
||||
|
||||
|
||||
def add_manifest_json_key(key, val):
|
||||
@ -134,29 +155,24 @@ def setup(hass, config):
|
||||
if os.path.isdir(local):
|
||||
hass.http.register_static_path("/local", local)
|
||||
|
||||
index_view = hass.data[DATA_INDEX_VIEW] = IndexView(hass)
|
||||
hass.http.register_view(index_view)
|
||||
|
||||
# Components have registered panels before frontend got setup.
|
||||
# Now register their urls.
|
||||
if DATA_PANELS in hass.data:
|
||||
for url_path in hass.data[DATA_PANELS]:
|
||||
hass.http.app.router.add_route('get', '/{}'.format(url_path),
|
||||
index_view.get)
|
||||
else:
|
||||
hass.data[DATA_PANELS] = {}
|
||||
|
||||
register_built_in_panel(hass, 'map', 'Map', 'mdi:account-location')
|
||||
|
||||
for panel in ('dev-event', 'dev-info', 'dev-service', 'dev-state',
|
||||
'dev-template'):
|
||||
register_built_in_panel(hass, panel)
|
||||
|
||||
def register_frontend_index(event):
|
||||
"""Register the frontend index urls.
|
||||
|
||||
Done when Home Assistant is started so that all panels are known.
|
||||
"""
|
||||
hass.http.register_view(IndexView(
|
||||
hass, ['/{}'.format(name) for name in PANELS]))
|
||||
|
||||
hass.bus.listen_once(EVENT_HOMEASSISTANT_START, register_frontend_index)
|
||||
|
||||
for size in (192, 384, 512, 1024):
|
||||
MANIFEST_JSON['icons'].append({
|
||||
"src": "/static/icons/favicon-{}x{}.png".format(size, size),
|
||||
"sizes": "{}x{}".format(size, size),
|
||||
"type": "image/png"
|
||||
})
|
||||
|
||||
return True
|
||||
|
||||
|
||||
@ -174,7 +190,7 @@ class BootstrapView(HomeAssistantView):
|
||||
'states': self.hass.states.async_all(),
|
||||
'events': api.async_events_json(self.hass),
|
||||
'services': api.async_services_json(self.hass),
|
||||
'panels': PANELS,
|
||||
'panels': self.hass.data[DATA_PANELS],
|
||||
})
|
||||
|
||||
|
||||
@ -186,13 +202,12 @@ class IndexView(HomeAssistantView):
|
||||
requires_auth = False
|
||||
extra_urls = ['/states', '/states/{entity_id}']
|
||||
|
||||
def __init__(self, hass, extra_urls):
|
||||
def __init__(self, hass):
|
||||
"""Initialize the frontend view."""
|
||||
super().__init__(hass)
|
||||
|
||||
from jinja2 import FileSystemLoader, Environment
|
||||
|
||||
self.extra_urls = self.extra_urls + extra_urls
|
||||
self.templates = Environment(
|
||||
loader=FileSystemLoader(
|
||||
os.path.join(os.path.dirname(__file__), 'templates/')
|
||||
@ -223,7 +238,10 @@ class IndexView(HomeAssistantView):
|
||||
else:
|
||||
panel = request.path.split('/')[1]
|
||||
|
||||
panel_url = PANELS[panel]['url'] if panel != 'states' else ''
|
||||
if panel == 'states':
|
||||
panel_url = ''
|
||||
else:
|
||||
panel_url = self.hass.data[DATA_PANELS][panel]['url']
|
||||
|
||||
no_auth = 'true'
|
||||
if self.hass.config.api.api_password:
|
||||
@ -244,7 +262,7 @@ class IndexView(HomeAssistantView):
|
||||
resp = template.render(
|
||||
core_url=core_url, ui_url=ui_url, no_auth=no_auth,
|
||||
icons_url=icons_url, icons=FINGERPRINTS['mdi.html'],
|
||||
panel_url=panel_url, panels=PANELS)
|
||||
panel_url=panel_url, panels=self.hass.data[DATA_PANELS])
|
||||
|
||||
return web.Response(text=resp, content_type='text/html')
|
||||
|
||||
|
@ -20,7 +20,7 @@ from aiohttp import web, hdrs
|
||||
from aiohttp.file_sender import FileSender
|
||||
from aiohttp.web_exceptions import (
|
||||
HTTPUnauthorized, HTTPMovedPermanently, HTTPNotModified)
|
||||
from aiohttp.web_urldispatcher import StaticRoute
|
||||
from aiohttp.web_urldispatcher import StaticResource
|
||||
|
||||
from homeassistant.core import is_callback
|
||||
import homeassistant.remote as rem
|
||||
@ -33,7 +33,7 @@ import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.components import persistent_notification
|
||||
|
||||
DOMAIN = 'http'
|
||||
REQUIREMENTS = ('aiohttp_cors==0.4.0',)
|
||||
REQUIREMENTS = ('aiohttp_cors==0.5.0',)
|
||||
|
||||
CONF_API_PASSWORD = 'api_password'
|
||||
CONF_SERVER_HOST = 'server_host'
|
||||
@ -212,13 +212,8 @@ class GzipFileSender(FileSender):
|
||||
file_size = st.st_size
|
||||
|
||||
resp.content_length = file_size
|
||||
resp.set_tcp_cork(True)
|
||||
try:
|
||||
with filepath.open('rb') as f:
|
||||
yield from self._sendfile(request, resp, f, file_size)
|
||||
|
||||
finally:
|
||||
resp.set_tcp_nodelay(True)
|
||||
with filepath.open('rb') as f:
|
||||
yield from self._sendfile(request, resp, f, file_size)
|
||||
|
||||
return resp
|
||||
|
||||
@ -226,26 +221,32 @@ class GzipFileSender(FileSender):
|
||||
_GZIP_FILE_SENDER = GzipFileSender()
|
||||
|
||||
|
||||
class HAStaticRoute(StaticRoute):
|
||||
"""StaticRoute with support for fingerprinting."""
|
||||
@asyncio.coroutine
|
||||
def staticresource_enhancer(app, handler):
|
||||
"""Enhance StaticResourceHandler.
|
||||
|
||||
def __init__(self, prefix, path):
|
||||
"""Initialize a static route with gzip and cache busting support."""
|
||||
super().__init__(None, prefix, path)
|
||||
self._file_sender = _GZIP_FILE_SENDER
|
||||
Adds gzip encoding and fingerprinting matching.
|
||||
"""
|
||||
inst = getattr(handler, '__self__', None)
|
||||
if not isinstance(inst, StaticResource):
|
||||
return handler
|
||||
|
||||
def match(self, path):
|
||||
"""Match path to filename."""
|
||||
if not path.startswith(self._prefix):
|
||||
return None
|
||||
# pylint: disable=protected-access
|
||||
inst._file_sender = _GZIP_FILE_SENDER
|
||||
|
||||
@asyncio.coroutine
|
||||
def middleware_handler(request):
|
||||
"""Strip out fingerprints from resource names."""
|
||||
fingerprinted = _FINGERPRINT.match(request.match_info['filename'])
|
||||
|
||||
# Extra sauce to remove fingerprinted resource names
|
||||
filename = path[self._prefix_len:]
|
||||
fingerprinted = _FINGERPRINT.match(filename)
|
||||
if fingerprinted:
|
||||
filename = '{}.{}'.format(*fingerprinted.groups())
|
||||
request.match_info['filename'] = \
|
||||
'{}.{}'.format(*fingerprinted.groups())
|
||||
|
||||
return {'filename': filename}
|
||||
resp = yield from handler(request)
|
||||
return resp
|
||||
|
||||
return middleware_handler
|
||||
|
||||
|
||||
class HomeAssistantWSGI(object):
|
||||
@ -257,7 +258,8 @@ class HomeAssistantWSGI(object):
|
||||
"""Initialize the WSGI Home Assistant server."""
|
||||
import aiohttp_cors
|
||||
|
||||
self.app = web.Application(loop=hass.loop)
|
||||
self.app = web.Application(middlewares=[staticresource_enhancer],
|
||||
loop=hass.loop)
|
||||
self.hass = hass
|
||||
self.development = development
|
||||
self.api_password = api_password
|
||||
@ -318,11 +320,7 @@ class HomeAssistantWSGI(object):
|
||||
Specify optional cache length of asset in days.
|
||||
"""
|
||||
if os.path.isdir(path):
|
||||
assert url_root.startswith('/')
|
||||
if not url_root.endswith('/'):
|
||||
url_root += '/'
|
||||
route = HAStaticRoute(url_root, path)
|
||||
self.app.router.register_route(route)
|
||||
self.app.router.add_static(url_root, path)
|
||||
return
|
||||
|
||||
filepath = Path(path)
|
||||
|
@ -6,8 +6,8 @@ pip>=7.0.0
|
||||
jinja2>=2.8
|
||||
voluptuous==0.9.2
|
||||
typing>=3,<4
|
||||
aiohttp==1.0.5
|
||||
async_timeout==1.0.0
|
||||
aiohttp==1.1.5
|
||||
async_timeout==1.1.0
|
||||
|
||||
# homeassistant.components.nuimo_controller
|
||||
--only-binary=all git+https://github.com/getSenic/nuimo-linux-python#nuimo==1.0.0
|
||||
@ -31,7 +31,7 @@ SoCo==0.12
|
||||
TwitterAPI==2.4.2
|
||||
|
||||
# homeassistant.components.http
|
||||
aiohttp_cors==0.4.0
|
||||
aiohttp_cors==0.5.0
|
||||
|
||||
# homeassistant.components.apcupsd
|
||||
apcaccess==0.0.4
|
||||
|
@ -10,7 +10,7 @@ pytest>=2.9.2
|
||||
pytest-aiohttp>=0.1.3
|
||||
pytest-asyncio>=0.5.0
|
||||
pytest-cov>=2.3.1
|
||||
pytest-timeout>=1.0.0
|
||||
pytest-timeout>=1.2.0
|
||||
pytest-catchlog>=1.2.2
|
||||
requests_mock>=1.0
|
||||
mock-open>=1.3.1
|
||||
|
4
setup.py
4
setup.py
@ -21,8 +21,8 @@ REQUIRES = [
|
||||
'jinja2>=2.8',
|
||||
'voluptuous==0.9.2',
|
||||
'typing>=3,<4',
|
||||
'aiohttp==1.0.5',
|
||||
'async_timeout==1.0.0',
|
||||
'aiohttp==1.1.5',
|
||||
'async_timeout==1.1.0',
|
||||
]
|
||||
|
||||
setup(
|
||||
|
@ -245,13 +245,17 @@ class TestMediaPlayerWeb(unittest.TestCase):
|
||||
"""Setup things to be run when tests are started."""
|
||||
self.hass = get_test_home_assistant()
|
||||
|
||||
setup_component(self.hass, http.DOMAIN, {
|
||||
assert setup_component(self.hass, http.DOMAIN, {
|
||||
http.DOMAIN: {
|
||||
http.CONF_SERVER_PORT: SERVER_PORT,
|
||||
http.CONF_API_PASSWORD: API_PASSWORD,
|
||||
},
|
||||
})
|
||||
|
||||
assert setup_component(
|
||||
self.hass, mp.DOMAIN,
|
||||
{'media_player': {'platform': 'demo'}})
|
||||
|
||||
self.hass.start()
|
||||
|
||||
def tearDown(self):
|
||||
@ -287,10 +291,6 @@ class TestMediaPlayerWeb(unittest.TestCase):
|
||||
|
||||
self.hass._websession = MockWebsession()
|
||||
|
||||
self.hass.block_till_done()
|
||||
assert setup_component(
|
||||
self.hass, mp.DOMAIN,
|
||||
{'media_player': {'platform': 'demo'}})
|
||||
assert self.hass.states.is_state(entity_id, 'playing')
|
||||
state = self.hass.states.get(entity_id)
|
||||
req = requests.get(HTTP_BASE_URL +
|
||||
|
@ -34,6 +34,7 @@ class TestGoogle(unittest.TestCase):
|
||||
self.assertTrue(setup_component(self.hass, 'google', config))
|
||||
|
||||
def test_get_calendar_info(self):
|
||||
"""Test getting the calendar info."""
|
||||
calendar = {
|
||||
'id': 'qwertyuiopasdfghjklzxcvbnm@import.calendar.google.com',
|
||||
'etag': '"3584134138943410"',
|
||||
@ -61,21 +62,22 @@ class TestGoogle(unittest.TestCase):
|
||||
})
|
||||
|
||||
def test_found_calendar(self):
|
||||
calendar = {
|
||||
'id': 'qwertyuiopasdfghjklzxcvbnm@import.calendar.google.com',
|
||||
'etag': '"3584134138943410"',
|
||||
'timeZone': 'UTC',
|
||||
'accessRole': 'reader',
|
||||
'foregroundColor': '#000000',
|
||||
'selected': True,
|
||||
'kind': 'calendar#calendarListEntry',
|
||||
'backgroundColor': '#16a765',
|
||||
'description': 'Test Calendar',
|
||||
'summary': 'We are, we are, a... Test Calendar',
|
||||
'colorId': '8',
|
||||
'defaultReminders': [],
|
||||
'track': True
|
||||
}
|
||||
"""Test when a calendar is found."""
|
||||
# calendar = {
|
||||
# 'id': 'qwertyuiopasdfghjklzxcvbnm@import.calendar.google.com',
|
||||
# 'etag': '"3584134138943410"',
|
||||
# 'timeZone': 'UTC',
|
||||
# 'accessRole': 'reader',
|
||||
# 'foregroundColor': '#000000',
|
||||
# 'selected': True,
|
||||
# 'kind': 'calendar#calendarListEntry',
|
||||
# 'backgroundColor': '#16a765',
|
||||
# 'description': 'Test Calendar',
|
||||
# 'summary': 'We are, we are, a... Test Calendar',
|
||||
# 'colorId': '8',
|
||||
# 'defaultReminders': [],
|
||||
# 'track': True
|
||||
# }
|
||||
|
||||
# self.assertIsInstance(self.hass.data[google.DATA_INDEX], dict)
|
||||
# self.assertEquals(self.hass.data[google.DATA_INDEX], {})
|
||||
@ -84,8 +86,8 @@ class TestGoogle(unittest.TestCase):
|
||||
self.hass.config.path(google.TOKEN_FILE))
|
||||
self.assertTrue(google.setup_services(self.hass, True,
|
||||
calendar_service))
|
||||
self.hass.services.call('google', 'found_calendar', calendar,
|
||||
blocking=True)
|
||||
# self.hass.services.call('google', 'found_calendar', calendar,
|
||||
# blocking=True)
|
||||
|
||||
# TODO: Fix this
|
||||
# self.assertTrue(self.hass.data[google.DATA_INDEX]
|
||||
|
@ -14,12 +14,10 @@ class TestPanelIframe(unittest.TestCase):
|
||||
def setup_method(self, method):
|
||||
"""Setup things to be run when tests are started."""
|
||||
self.hass = get_test_home_assistant()
|
||||
frontend.PANELS = {}
|
||||
|
||||
def teardown_method(self, method):
|
||||
"""Stop everything that was started."""
|
||||
self.hass.stop()
|
||||
frontend.PANELS = {}
|
||||
|
||||
def test_wrong_config(self):
|
||||
"""Test setup with wrong configuration."""
|
||||
@ -55,9 +53,9 @@ class TestPanelIframe(unittest.TestCase):
|
||||
},
|
||||
})
|
||||
|
||||
# 5 dev tools + map are automatically loaded
|
||||
assert len(frontend.PANELS) == 8
|
||||
assert frontend.PANELS['router'] == {
|
||||
# 5 dev tools + map are automatically loaded + 2 iframe panels
|
||||
assert len(self.hass.data[frontend.DATA_PANELS]) == 8
|
||||
assert self.hass.data[frontend.DATA_PANELS]['router'] == {
|
||||
'component_name': 'iframe',
|
||||
'config': {'url': 'http://192.168.1.1'},
|
||||
'icon': 'mdi:network-wireless',
|
||||
@ -66,7 +64,7 @@ class TestPanelIframe(unittest.TestCase):
|
||||
'url_path': 'router'
|
||||
}
|
||||
|
||||
assert frontend.PANELS['weather'] == {
|
||||
assert self.hass.data[frontend.DATA_PANELS]['weather'] == {
|
||||
'component_name': 'iframe',
|
||||
'config': {'url': 'https://www.wunderground.com/us/ca/san-diego'},
|
||||
'icon': 'mdi:weather',
|
||||
|
Loading…
x
Reference in New Issue
Block a user