mirror of
https://github.com/home-assistant/core.git
synced 2025-04-25 01:38:02 +00:00
Use httpx in generic camera (#46576)
* Use httpx in generic camera * Remove commented out code
This commit is contained in:
parent
c5b9ad83c2
commit
9917bb76fb
@ -2,10 +2,7 @@
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
import aiohttp
|
||||
import async_timeout
|
||||
import requests
|
||||
from requests.auth import HTTPDigestAuth
|
||||
import httpx
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.camera import (
|
||||
@ -25,7 +22,7 @@ from homeassistant.const import (
|
||||
)
|
||||
from homeassistant.exceptions import TemplateError
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
from homeassistant.helpers.httpx_client import get_async_client
|
||||
from homeassistant.helpers.reload import async_setup_reload_service
|
||||
|
||||
from . import DOMAIN, PLATFORMS
|
||||
@ -39,6 +36,7 @@ CONF_STREAM_SOURCE = "stream_source"
|
||||
CONF_FRAMERATE = "framerate"
|
||||
|
||||
DEFAULT_NAME = "Generic Camera"
|
||||
GET_IMAGE_TIMEOUT = 10
|
||||
|
||||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
||||
{
|
||||
@ -93,9 +91,9 @@ class GenericCamera(Camera):
|
||||
|
||||
if username and password:
|
||||
if self._authentication == HTTP_DIGEST_AUTHENTICATION:
|
||||
self._auth = HTTPDigestAuth(username, password)
|
||||
self._auth = httpx.DigestAuth(username, password)
|
||||
else:
|
||||
self._auth = aiohttp.BasicAuth(username, password=password)
|
||||
self._auth = httpx.BasicAuth(username, password=password)
|
||||
else:
|
||||
self._auth = None
|
||||
|
||||
@ -129,40 +127,19 @@ class GenericCamera(Camera):
|
||||
if url == self._last_url and self._limit_refetch:
|
||||
return self._last_image
|
||||
|
||||
# aiohttp don't support DigestAuth yet
|
||||
if self._authentication == HTTP_DIGEST_AUTHENTICATION:
|
||||
|
||||
def fetch():
|
||||
"""Read image from a URL."""
|
||||
try:
|
||||
response = requests.get(
|
||||
url, timeout=10, auth=self._auth, verify=self.verify_ssl
|
||||
)
|
||||
return response.content
|
||||
except requests.exceptions.RequestException as error:
|
||||
_LOGGER.error(
|
||||
"Error getting new camera image from %s: %s", self._name, error
|
||||
)
|
||||
return self._last_image
|
||||
|
||||
self._last_image = await self.hass.async_add_executor_job(fetch)
|
||||
# async
|
||||
else:
|
||||
try:
|
||||
websession = async_get_clientsession(
|
||||
self.hass, verify_ssl=self.verify_ssl
|
||||
)
|
||||
with async_timeout.timeout(10):
|
||||
response = await websession.get(url, auth=self._auth)
|
||||
self._last_image = await response.read()
|
||||
except asyncio.TimeoutError:
|
||||
_LOGGER.error("Timeout getting camera image from %s", self._name)
|
||||
return self._last_image
|
||||
except aiohttp.ClientError as err:
|
||||
_LOGGER.error(
|
||||
"Error getting new camera image from %s: %s", self._name, err
|
||||
)
|
||||
return self._last_image
|
||||
try:
|
||||
async_client = get_async_client(self.hass, verify_ssl=self.verify_ssl)
|
||||
response = await async_client.get(
|
||||
url, auth=self._auth, timeout=GET_IMAGE_TIMEOUT
|
||||
)
|
||||
response.raise_for_status()
|
||||
self._last_image = response.content
|
||||
except httpx.TimeoutException:
|
||||
_LOGGER.error("Timeout getting camera image from %s", self._name)
|
||||
return self._last_image
|
||||
except (httpx.RequestError, httpx.HTTPStatusError) as err:
|
||||
_LOGGER.error("Error getting new camera image from %s: %s", self._name, err)
|
||||
return self._last_image
|
||||
|
||||
self._last_url = url
|
||||
return self._last_image
|
||||
|
@ -3,6 +3,8 @@ import asyncio
|
||||
from os import path
|
||||
from unittest.mock import patch
|
||||
|
||||
import respx
|
||||
|
||||
from homeassistant import config as hass_config
|
||||
from homeassistant.components.generic import DOMAIN
|
||||
from homeassistant.components.websocket_api.const import TYPE_RESULT
|
||||
@ -14,9 +16,10 @@ from homeassistant.const import (
|
||||
from homeassistant.setup import async_setup_component
|
||||
|
||||
|
||||
async def test_fetching_url(aioclient_mock, hass, hass_client):
|
||||
@respx.mock
|
||||
async def test_fetching_url(hass, hass_client):
|
||||
"""Test that it fetches the given url."""
|
||||
aioclient_mock.get("http://example.com", text="hello world")
|
||||
respx.get("http://example.com").respond(text="hello world")
|
||||
|
||||
await async_setup_component(
|
||||
hass,
|
||||
@ -38,12 +41,12 @@ async def test_fetching_url(aioclient_mock, hass, hass_client):
|
||||
resp = await client.get("/api/camera_proxy/camera.config_test")
|
||||
|
||||
assert resp.status == 200
|
||||
assert aioclient_mock.call_count == 1
|
||||
assert respx.calls.call_count == 1
|
||||
body = await resp.text()
|
||||
assert body == "hello world"
|
||||
|
||||
resp = await client.get("/api/camera_proxy/camera.config_test")
|
||||
assert aioclient_mock.call_count == 2
|
||||
assert respx.calls.call_count == 2
|
||||
|
||||
|
||||
async def test_fetching_without_verify_ssl(aioclient_mock, hass, hass_client):
|
||||
@ -100,12 +103,13 @@ async def test_fetching_url_with_verify_ssl(aioclient_mock, hass, hass_client):
|
||||
assert resp.status == 200
|
||||
|
||||
|
||||
async def test_limit_refetch(aioclient_mock, hass, hass_client):
|
||||
@respx.mock
|
||||
async def test_limit_refetch(hass, hass_client):
|
||||
"""Test that it fetches the given url."""
|
||||
aioclient_mock.get("http://example.com/5a", text="hello world")
|
||||
aioclient_mock.get("http://example.com/10a", text="hello world")
|
||||
aioclient_mock.get("http://example.com/15a", text="hello planet")
|
||||
aioclient_mock.get("http://example.com/20a", status=HTTP_NOT_FOUND)
|
||||
respx.get("http://example.com/5a").respond(text="hello world")
|
||||
respx.get("http://example.com/10a").respond(text="hello world")
|
||||
respx.get("http://example.com/15a").respond(text="hello planet")
|
||||
respx.get("http://example.com/20a").respond(status_code=HTTP_NOT_FOUND)
|
||||
|
||||
await async_setup_component(
|
||||
hass,
|
||||
@ -129,19 +133,19 @@ async def test_limit_refetch(aioclient_mock, hass, hass_client):
|
||||
|
||||
with patch("async_timeout.timeout", side_effect=asyncio.TimeoutError()):
|
||||
resp = await client.get("/api/camera_proxy/camera.config_test")
|
||||
assert aioclient_mock.call_count == 0
|
||||
assert respx.calls.call_count == 0
|
||||
assert resp.status == HTTP_INTERNAL_SERVER_ERROR
|
||||
|
||||
hass.states.async_set("sensor.temp", "10")
|
||||
|
||||
resp = await client.get("/api/camera_proxy/camera.config_test")
|
||||
assert aioclient_mock.call_count == 1
|
||||
assert respx.calls.call_count == 1
|
||||
assert resp.status == 200
|
||||
body = await resp.text()
|
||||
assert body == "hello world"
|
||||
|
||||
resp = await client.get("/api/camera_proxy/camera.config_test")
|
||||
assert aioclient_mock.call_count == 1
|
||||
assert respx.calls.call_count == 1
|
||||
assert resp.status == 200
|
||||
body = await resp.text()
|
||||
assert body == "hello world"
|
||||
@ -150,7 +154,7 @@ async def test_limit_refetch(aioclient_mock, hass, hass_client):
|
||||
|
||||
# Url change = fetch new image
|
||||
resp = await client.get("/api/camera_proxy/camera.config_test")
|
||||
assert aioclient_mock.call_count == 2
|
||||
assert respx.calls.call_count == 2
|
||||
assert resp.status == 200
|
||||
body = await resp.text()
|
||||
assert body == "hello planet"
|
||||
@ -158,7 +162,7 @@ async def test_limit_refetch(aioclient_mock, hass, hass_client):
|
||||
# Cause a template render error
|
||||
hass.states.async_remove("sensor.temp")
|
||||
resp = await client.get("/api/camera_proxy/camera.config_test")
|
||||
assert aioclient_mock.call_count == 2
|
||||
assert respx.calls.call_count == 2
|
||||
assert resp.status == 200
|
||||
body = await resp.text()
|
||||
assert body == "hello planet"
|
||||
@ -285,11 +289,12 @@ async def test_no_stream_source(aioclient_mock, hass, hass_client, hass_ws_clien
|
||||
}
|
||||
|
||||
|
||||
async def test_camera_content_type(aioclient_mock, hass, hass_client):
|
||||
@respx.mock
|
||||
async def test_camera_content_type(hass, hass_client):
|
||||
"""Test generic camera with custom content_type."""
|
||||
svg_image = "<some image>"
|
||||
urlsvg = "https://upload.wikimedia.org/wikipedia/commons/0/02/SVG_logo.svg"
|
||||
aioclient_mock.get(urlsvg, text=svg_image)
|
||||
respx.get(urlsvg).respond(text=svg_image)
|
||||
|
||||
cam_config_svg = {
|
||||
"name": "config_test_svg",
|
||||
@ -309,23 +314,24 @@ async def test_camera_content_type(aioclient_mock, hass, hass_client):
|
||||
client = await hass_client()
|
||||
|
||||
resp_1 = await client.get("/api/camera_proxy/camera.config_test_svg")
|
||||
assert aioclient_mock.call_count == 1
|
||||
assert respx.calls.call_count == 1
|
||||
assert resp_1.status == 200
|
||||
assert resp_1.content_type == "image/svg+xml"
|
||||
body = await resp_1.text()
|
||||
assert body == svg_image
|
||||
|
||||
resp_2 = await client.get("/api/camera_proxy/camera.config_test_jpg")
|
||||
assert aioclient_mock.call_count == 2
|
||||
assert respx.calls.call_count == 2
|
||||
assert resp_2.status == 200
|
||||
assert resp_2.content_type == "image/jpeg"
|
||||
body = await resp_2.text()
|
||||
assert body == svg_image
|
||||
|
||||
|
||||
async def test_reloading(aioclient_mock, hass, hass_client):
|
||||
@respx.mock
|
||||
async def test_reloading(hass, hass_client):
|
||||
"""Test we can cleanly reload."""
|
||||
aioclient_mock.get("http://example.com", text="hello world")
|
||||
respx.get("http://example.com").respond(text="hello world")
|
||||
|
||||
await async_setup_component(
|
||||
hass,
|
||||
@ -347,7 +353,7 @@ async def test_reloading(aioclient_mock, hass, hass_client):
|
||||
resp = await client.get("/api/camera_proxy/camera.config_test")
|
||||
|
||||
assert resp.status == 200
|
||||
assert aioclient_mock.call_count == 1
|
||||
assert respx.calls.call_count == 1
|
||||
body = await resp.text()
|
||||
assert body == "hello world"
|
||||
|
||||
@ -374,7 +380,7 @@ async def test_reloading(aioclient_mock, hass, hass_client):
|
||||
resp = await client.get("/api/camera_proxy/camera.reload")
|
||||
|
||||
assert resp.status == 200
|
||||
assert aioclient_mock.call_count == 2
|
||||
assert respx.calls.call_count == 2
|
||||
body = await resp.text()
|
||||
assert body == "hello world"
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user