Bump androidtv to 0.0.28 (#26906)

* Bump androidtv to 0.0.28

* Address reviewer comments

* Remove adb-shell from requirements_test_all.txt

* Use a one-liner to avoid a coverage failure
This commit is contained in:
Jeff Irion 2019-09-26 22:53:26 -07:00 committed by Martin Hjelmare
parent b04a70995e
commit 45c548ae47
6 changed files with 61 additions and 52 deletions

View File

@ -3,7 +3,8 @@
"name": "Androidtv", "name": "Androidtv",
"documentation": "https://www.home-assistant.io/components/androidtv", "documentation": "https://www.home-assistant.io/components/androidtv",
"requirements": [ "requirements": [
"androidtv==0.0.27" "adb-shell==0.0.2",
"androidtv==0.0.28"
], ],
"dependencies": [], "dependencies": [],
"codeowners": ["@JeffLIrion"] "codeowners": ["@JeffLIrion"]

View File

@ -3,6 +3,12 @@ import functools
import logging import logging
import voluptuous as vol import voluptuous as vol
from adb_shell.exceptions import (
InvalidChecksumError,
InvalidCommandError,
InvalidResponseError,
TcpTimeoutException,
)
from androidtv import setup, ha_state_detection_rules_validator from androidtv import setup, ha_state_detection_rules_validator
from androidtv.constants import APPS, KEYS from androidtv.constants import APPS, KEYS
@ -123,11 +129,15 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the Android TV / Fire TV platform.""" """Set up the Android TV / Fire TV platform."""
hass.data.setdefault(ANDROIDTV_DOMAIN, {}) hass.data.setdefault(ANDROIDTV_DOMAIN, {})
host = "{0}:{1}".format(config[CONF_HOST], config[CONF_PORT]) host = f"{config[CONF_HOST]}:{config[CONF_PORT]}"
if CONF_ADB_SERVER_IP not in config: if CONF_ADB_SERVER_IP not in config:
# Use "python-adb" (Python ADB implementation) # Use "adb_shell" (Python ADB implementation)
adb_log = "using Python ADB implementation " adb_log = "using Python ADB implementation " + (
f"with adbkey='{config[CONF_ADBKEY]}'"
if CONF_ADBKEY in config
else "without adbkey authentication"
)
if CONF_ADBKEY in config: if CONF_ADBKEY in config:
aftv = setup( aftv = setup(
host, host,
@ -135,7 +145,6 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
device_class=config[CONF_DEVICE_CLASS], device_class=config[CONF_DEVICE_CLASS],
state_detection_rules=config[CONF_STATE_DETECTION_RULES], state_detection_rules=config[CONF_STATE_DETECTION_RULES],
) )
adb_log += "with adbkey='{0}'".format(config[CONF_ADBKEY])
else: else:
aftv = setup( aftv = setup(
@ -143,7 +152,6 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
device_class=config[CONF_DEVICE_CLASS], device_class=config[CONF_DEVICE_CLASS],
state_detection_rules=config[CONF_STATE_DETECTION_RULES], state_detection_rules=config[CONF_STATE_DETECTION_RULES],
) )
adb_log += "without adbkey authentication"
else: else:
# Use "pure-python-adb" (communicate with ADB server) # Use "pure-python-adb" (communicate with ADB server)
aftv = setup( aftv = setup(
@ -153,9 +161,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
device_class=config[CONF_DEVICE_CLASS], device_class=config[CONF_DEVICE_CLASS],
state_detection_rules=config[CONF_STATE_DETECTION_RULES], state_detection_rules=config[CONF_STATE_DETECTION_RULES],
) )
adb_log = "using ADB server at {0}:{1}".format( adb_log = f"using ADB server at {config[CONF_ADB_SERVER_IP]}:{config[CONF_ADB_SERVER_PORT]}"
config[CONF_ADB_SERVER_IP], config[CONF_ADB_SERVER_PORT]
)
if not aftv.available: if not aftv.available:
# Determine the name that will be used for the device in the log # Determine the name that will be used for the device in the log
@ -251,6 +257,7 @@ def adb_decorator(override_available=False):
"establishing attempt in the next update. Error: %s", "establishing attempt in the next update. Error: %s",
err, err,
) )
self.aftv.adb.close()
self._available = False # pylint: disable=protected-access self._available = False # pylint: disable=protected-access
return None return None
@ -278,14 +285,7 @@ class ADBDevice(MediaPlayerDevice):
# ADB exceptions to catch # ADB exceptions to catch
if not self.aftv.adb_server_ip: if not self.aftv.adb_server_ip:
# Using "python-adb" (Python ADB implementation) # Using "adb_shell" (Python ADB implementation)
from adb.adb_protocol import (
InvalidChecksumError,
InvalidCommandError,
InvalidResponseError,
)
from adb.usb_exceptions import TcpTimeoutException
self.exceptions = ( self.exceptions = (
AttributeError, AttributeError,
BrokenPipeError, BrokenPipeError,

View File

@ -111,6 +111,9 @@ adafruit-blinka==1.2.1
# homeassistant.components.mcp23017 # homeassistant.components.mcp23017
adafruit-circuitpython-mcp230xx==1.1.2 adafruit-circuitpython-mcp230xx==1.1.2
# homeassistant.components.androidtv
adb-shell==0.0.2
# homeassistant.components.adguard # homeassistant.components.adguard
adguardhome==0.2.1 adguardhome==0.2.1
@ -197,7 +200,7 @@ ambiclimate==0.2.1
amcrest==1.5.3 amcrest==1.5.3
# homeassistant.components.androidtv # homeassistant.components.androidtv
androidtv==0.0.27 androidtv==0.0.28
# homeassistant.components.anel_pwrctrl # homeassistant.components.anel_pwrctrl
anel_pwrctrl-homeassistant==0.0.1.dev2 anel_pwrctrl-homeassistant==0.0.1.dev2

View File

@ -80,7 +80,7 @@ aiowwlln==2.0.2
ambiclimate==0.2.1 ambiclimate==0.2.1
# homeassistant.components.androidtv # homeassistant.components.androidtv
androidtv==0.0.27 androidtv==0.0.28
# homeassistant.components.apns # homeassistant.components.apns
apns2==0.3.0 apns2==0.3.0

View File

@ -4,34 +4,24 @@ from socket import error as socket_error
from unittest.mock import patch from unittest.mock import patch
class AdbCommandsFake: class AdbDeviceFake:
"""A fake of the `adb.adb_commands.AdbCommands` class.""" """A fake of the `adb_shell.adb_device.AdbDevice` class."""
def ConnectDevice(self, *args, **kwargs): # pylint: disable=invalid-name def __init__(self, *args, **kwargs):
"""Initialize a fake `adb_shell.adb_device.AdbDevice` instance."""
self.available = False
def close(self):
"""Close the socket connection."""
self.available = False
def connect(self, *args, **kwargs):
"""Try to connect to a device.""" """Try to connect to a device."""
raise NotImplementedError raise NotImplementedError
def Shell(self, cmd): # pylint: disable=invalid-name def shell(self, cmd):
"""Send an ADB shell command.""" """Send an ADB shell command."""
raise NotImplementedError return None
class AdbCommandsFakeSuccess(AdbCommandsFake):
"""A fake of the `adb.adb_commands.AdbCommands` class when the connection attempt succeeds."""
def ConnectDevice(self, *args, **kwargs): # pylint: disable=invalid-name
"""Successfully connect to a device."""
return self
class AdbCommandsFakeFail(AdbCommandsFake):
"""A fake of the `adb.adb_commands.AdbCommands` class when the connection attempt fails."""
def ConnectDevice(
self, *args, **kwargs
): # pylint: disable=invalid-name, no-self-use
"""Fail to connect to a device."""
raise socket_error
class ClientFakeSuccess: class ClientFakeSuccess:
@ -85,31 +75,39 @@ class DeviceFake:
def patch_connect(success): def patch_connect(success):
"""Mock the `adb.adb_commands.AdbCommands` and `adb_messenger.client.Client` classes.""" """Mock the `adb_shell.adb_device.AdbDevice` and `adb_messenger.client.Client` classes."""
def connect_success_python(self, *args, **kwargs):
"""Mock the `AdbDeviceFake.connect` method when it succeeds."""
self.available = True
def connect_fail_python(self, *args, **kwargs):
"""Mock the `AdbDeviceFake.connect` method when it fails."""
raise socket_error
if success: if success:
return { return {
"python": patch( "python": patch(
"androidtv.adb_manager.AdbCommands", AdbCommandsFakeSuccess f"{__name__}.AdbDeviceFake.connect", connect_success_python
), ),
"server": patch("androidtv.adb_manager.Client", ClientFakeSuccess), "server": patch("androidtv.adb_manager.Client", ClientFakeSuccess),
} }
return { return {
"python": patch("androidtv.adb_manager.AdbCommands", AdbCommandsFakeFail), "python": patch(f"{__name__}.AdbDeviceFake.connect", connect_fail_python),
"server": patch("androidtv.adb_manager.Client", ClientFakeFail), "server": patch("androidtv.adb_manager.Client", ClientFakeFail),
} }
def patch_shell(response=None, error=False): def patch_shell(response=None, error=False):
"""Mock the `AdbCommandsFake.Shell` and `DeviceFake.shell` methods.""" """Mock the `AdbDeviceFake.shell` and `DeviceFake.shell` methods."""
def shell_success(self, cmd): def shell_success(self, cmd):
"""Mock the `AdbCommandsFake.Shell` and `DeviceFake.shell` methods when they are successful.""" """Mock the `AdbDeviceFake.shell` and `DeviceFake.shell` methods when they are successful."""
self.shell_cmd = cmd self.shell_cmd = cmd
return response return response
def shell_fail_python(self, cmd): def shell_fail_python(self, cmd):
"""Mock the `AdbCommandsFake.Shell` method when it fails.""" """Mock the `AdbDeviceFake.shell` method when it fails."""
self.shell_cmd = cmd self.shell_cmd = cmd
raise AttributeError raise AttributeError
@ -120,10 +118,13 @@ def patch_shell(response=None, error=False):
if not error: if not error:
return { return {
"python": patch(f"{__name__}.AdbCommandsFake.Shell", shell_success), "python": patch(f"{__name__}.AdbDeviceFake.shell", shell_success),
"server": patch(f"{__name__}.DeviceFake.shell", shell_success), "server": patch(f"{__name__}.DeviceFake.shell", shell_success),
} }
return { return {
"python": patch(f"{__name__}.AdbCommandsFake.Shell", shell_fail_python), "python": patch(f"{__name__}.AdbDeviceFake.shell", shell_fail_python),
"server": patch(f"{__name__}.DeviceFake.shell", shell_fail_server), "server": patch(f"{__name__}.DeviceFake.shell", shell_fail_server),
} }
PATCH_ADB_DEVICE = patch("androidtv.adb_manager.AdbDevice", AdbDeviceFake)

View File

@ -79,7 +79,9 @@ async def _test_reconnect(hass, caplog, config):
else: else:
entity_id = "media_player.fire_tv" entity_id = "media_player.fire_tv"
with patchers.patch_connect(True)[patch_key], patchers.patch_shell("")[patch_key]: with patchers.PATCH_ADB_DEVICE, patchers.patch_connect(True)[
patch_key
], patchers.patch_shell("")[patch_key]:
assert await async_setup_component(hass, DOMAIN, config) assert await async_setup_component(hass, DOMAIN, config)
await hass.helpers.entity_component.async_update_entity(entity_id) await hass.helpers.entity_component.async_update_entity(entity_id)
state = hass.states.get(entity_id) state = hass.states.get(entity_id)
@ -151,7 +153,9 @@ async def _test_adb_shell_returns_none(hass, config):
else: else:
entity_id = "media_player.fire_tv" entity_id = "media_player.fire_tv"
with patchers.patch_connect(True)[patch_key], patchers.patch_shell("")[patch_key]: with patchers.PATCH_ADB_DEVICE, patchers.patch_connect(True)[
patch_key
], patchers.patch_shell("")[patch_key]:
assert await async_setup_component(hass, DOMAIN, config) assert await async_setup_component(hass, DOMAIN, config)
await hass.helpers.entity_component.async_update_entity(entity_id) await hass.helpers.entity_component.async_update_entity(entity_id)
state = hass.states.get(entity_id) state = hass.states.get(entity_id)