Bump python-synology to 0.7.0 (#34534)

This commit is contained in:
Quentame 2020-04-22 23:28:47 +02:00 committed by GitHub
parent 6631bbc6f5
commit a8cd7203df
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 62 additions and 71 deletions

View File

@ -9,7 +9,6 @@ import voluptuous as vol
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
from homeassistant.const import ( from homeassistant.const import (
CONF_API_VERSION,
CONF_DISKS, CONF_DISKS,
CONF_HOST, CONF_HOST,
CONF_PASSWORD, CONF_PASSWORD,
@ -22,14 +21,13 @@ from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.helpers.event import async_track_time_interval from homeassistant.helpers.event import async_track_time_interval
from homeassistant.helpers.typing import HomeAssistantType from homeassistant.helpers.typing import HomeAssistantType
from .const import CONF_VOLUMES, DEFAULT_DSM_VERSION, DEFAULT_SSL, DOMAIN from .const import CONF_VOLUMES, DEFAULT_SSL, DOMAIN
CONFIG_SCHEMA = vol.Schema( CONFIG_SCHEMA = vol.Schema(
{ {
vol.Required(CONF_HOST): cv.string, vol.Required(CONF_HOST): cv.string,
vol.Optional(CONF_PORT): cv.port, vol.Optional(CONF_PORT): cv.port,
vol.Optional(CONF_SSL, default=DEFAULT_SSL): cv.boolean, vol.Optional(CONF_SSL, default=DEFAULT_SSL): cv.boolean,
vol.Optional(CONF_API_VERSION, default=DEFAULT_DSM_VERSION): cv.positive_int,
vol.Required(CONF_USERNAME): cv.string, vol.Required(CONF_USERNAME): cv.string,
vol.Required(CONF_PASSWORD): cv.string, vol.Required(CONF_PASSWORD): cv.string,
vol.Optional(CONF_DISKS): cv.ensure_list, vol.Optional(CONF_DISKS): cv.ensure_list,
@ -70,12 +68,9 @@ async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry):
password = entry.data[CONF_PASSWORD] password = entry.data[CONF_PASSWORD]
unit = hass.config.units.temperature_unit unit = hass.config.units.temperature_unit
use_ssl = entry.data[CONF_SSL] use_ssl = entry.data[CONF_SSL]
api_version = entry.data.get(CONF_API_VERSION, DEFAULT_DSM_VERSION)
device_token = entry.data.get("device_token") device_token = entry.data.get("device_token")
api = SynoApi( api = SynoApi(hass, host, port, username, password, unit, use_ssl, device_token)
hass, host, port, username, password, unit, use_ssl, device_token, api_version
)
await api.async_setup() await api.async_setup()
@ -109,7 +104,6 @@ class SynoApi:
temp_unit: str, temp_unit: str,
use_ssl: bool, use_ssl: bool,
device_token: str, device_token: str,
api_version: int,
): ):
"""Initialize the API wrapper class.""" """Initialize the API wrapper class."""
self._hass = hass self._hass = hass
@ -119,7 +113,6 @@ class SynoApi:
self._password = password self._password = password
self._use_ssl = use_ssl self._use_ssl = use_ssl
self._device_token = device_token self._device_token = device_token
self._api_version = api_version
self.temp_unit = temp_unit self.temp_unit = temp_unit
self._dsm: SynologyDSM = None self._dsm: SynologyDSM = None
@ -143,7 +136,6 @@ class SynoApi:
self._password, self._password,
self._use_ssl, self._use_ssl,
device_token=self._device_token, device_token=self._device_token,
dsm_version=self._api_version,
) )
await self._hass.async_add_executor_job(self._fetch_device_configuration) await self._hass.async_add_executor_job(self._fetch_device_configuration)

View File

@ -4,16 +4,17 @@ from urllib.parse import urlparse
from synology_dsm import SynologyDSM from synology_dsm import SynologyDSM
from synology_dsm.exceptions import ( from synology_dsm.exceptions import (
SynologyDSMException,
SynologyDSMLogin2SAFailedException, SynologyDSMLogin2SAFailedException,
SynologyDSMLogin2SARequiredException, SynologyDSMLogin2SARequiredException,
SynologyDSMLoginInvalidException, SynologyDSMLoginInvalidException,
SynologyDSMRequestException,
) )
import voluptuous as vol import voluptuous as vol
from homeassistant import config_entries, exceptions from homeassistant import config_entries, exceptions
from homeassistant.components import ssdp from homeassistant.components import ssdp
from homeassistant.const import ( from homeassistant.const import (
CONF_API_VERSION,
CONF_DISKS, CONF_DISKS,
CONF_HOST, CONF_HOST,
CONF_NAME, CONF_NAME,
@ -23,13 +24,7 @@ from homeassistant.const import (
CONF_USERNAME, CONF_USERNAME,
) )
from .const import ( from .const import CONF_VOLUMES, DEFAULT_PORT, DEFAULT_PORT_SSL, DEFAULT_SSL
CONF_VOLUMES,
DEFAULT_DSM_VERSION,
DEFAULT_PORT,
DEFAULT_PORT_SSL,
DEFAULT_SSL,
)
from .const import DOMAIN # pylint: disable=unused-import from .const import DOMAIN # pylint: disable=unused-import
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -56,12 +51,6 @@ def _ordered_shared_schema(schema_input):
vol.Required(CONF_PASSWORD, default=schema_input.get(CONF_PASSWORD, "")): str, vol.Required(CONF_PASSWORD, default=schema_input.get(CONF_PASSWORD, "")): str,
vol.Optional(CONF_PORT, default=schema_input.get(CONF_PORT, "")): str, vol.Optional(CONF_PORT, default=schema_input.get(CONF_PORT, "")): str,
vol.Optional(CONF_SSL, default=schema_input.get(CONF_SSL, DEFAULT_SSL)): bool, vol.Optional(CONF_SSL, default=schema_input.get(CONF_SSL, DEFAULT_SSL)): bool,
vol.Optional(
CONF_API_VERSION,
default=schema_input.get(CONF_API_VERSION, DEFAULT_DSM_VERSION),
): vol.All(
vol.Coerce(int), vol.In([5, 6]), # DSM versions supported by the library
),
} }
@ -111,7 +100,6 @@ class SynologyDSMFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
username = user_input[CONF_USERNAME] username = user_input[CONF_USERNAME]
password = user_input[CONF_PASSWORD] password = user_input[CONF_PASSWORD]
use_ssl = user_input.get(CONF_SSL, DEFAULT_SSL) use_ssl = user_input.get(CONF_SSL, DEFAULT_SSL)
api_version = user_input.get(CONF_API_VERSION, DEFAULT_DSM_VERSION)
otp_code = user_input.get(CONF_OTP_CODE) otp_code = user_input.get(CONF_OTP_CODE)
if not port: if not port:
@ -120,9 +108,7 @@ class SynologyDSMFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
else: else:
port = DEFAULT_PORT port = DEFAULT_PORT
api = SynologyDSM( api = SynologyDSM(host, port, username, password, use_ssl)
host, port, username, password, use_ssl, dsm_version=api_version,
)
try: try:
serial = await self.hass.async_add_executor_job( serial = await self.hass.async_add_executor_job(
@ -134,8 +120,12 @@ class SynologyDSMFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
errors[CONF_OTP_CODE] = "otp_failed" errors[CONF_OTP_CODE] = "otp_failed"
user_input[CONF_OTP_CODE] = None user_input[CONF_OTP_CODE] = None
return await self.async_step_2sa(user_input, errors) return await self.async_step_2sa(user_input, errors)
except (SynologyDSMLoginInvalidException, InvalidAuth): except SynologyDSMLoginInvalidException:
errors[CONF_USERNAME] = "login" errors[CONF_USERNAME] = "login"
except SynologyDSMRequestException:
errors[CONF_HOST] = "connection"
except SynologyDSMException:
errors["base"] = "unknown"
except InvalidData: except InvalidData:
errors["base"] = "missing_data" errors["base"] = "missing_data"
@ -152,7 +142,6 @@ class SynologyDSMFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
CONF_SSL: use_ssl, CONF_SSL: use_ssl,
CONF_USERNAME: username, CONF_USERNAME: username,
CONF_PASSWORD: password, CONF_PASSWORD: password,
CONF_API_VERSION: api_version,
} }
if otp_code: if otp_code:
config_data["device_token"] = api.device_token config_data["device_token"] = api.device_token
@ -216,28 +205,21 @@ class SynologyDSMFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
def _login_and_fetch_syno_info(api, otp_code): def _login_and_fetch_syno_info(api, otp_code):
"""Login to the NAS and fetch basic data.""" """Login to the NAS and fetch basic data."""
if not api.login(otp_code):
raise InvalidAuth
# These do i/o # These do i/o
information = api.information api.login(otp_code)
utilisation = api.utilisation utilisation = api.utilisation
storage = api.storage storage = api.storage
if ( if (
information.serial is None api.information.serial is None
or utilisation.cpu_user_load is None or utilisation.cpu_user_load is None
or storage.disks_ids is None or storage.disks_ids is None
or storage.volumes_ids is None or storage.volumes_ids is None
): ):
raise InvalidData raise InvalidData
return information.serial return api.information.serial
class InvalidData(exceptions.HomeAssistantError): class InvalidData(exceptions.HomeAssistantError):
"""Error to indicate we get invalid data from the nas.""" """Error to indicate we get invalid data from the nas."""
class InvalidAuth(exceptions.HomeAssistantError):
"""Error to indicate there is invalid auth."""

View File

@ -12,7 +12,6 @@ CONF_VOLUMES = "volumes"
DEFAULT_SSL = True DEFAULT_SSL = True
DEFAULT_PORT = 5000 DEFAULT_PORT = 5000
DEFAULT_PORT_SSL = 5001 DEFAULT_PORT_SSL = 5001
DEFAULT_DSM_VERSION = 6
UTILISATION_SENSORS = { UTILISATION_SENSORS = {
"cpu_other_load": ["CPU Load (Other)", UNIT_PERCENTAGE, "mdi:chip"], "cpu_other_load": ["CPU Load (Other)", UNIT_PERCENTAGE, "mdi:chip"],

View File

@ -2,7 +2,7 @@
"domain": "synology_dsm", "domain": "synology_dsm",
"name": "Synology DSM", "name": "Synology DSM",
"documentation": "https://www.home-assistant.io/integrations/synology_dsm", "documentation": "https://www.home-assistant.io/integrations/synology_dsm",
"requirements": ["python-synology==0.6.0"], "requirements": ["python-synology==0.7.0"],
"codeowners": ["@ProtoThis", "@Quentame"], "codeowners": ["@ProtoThis", "@Quentame"],
"config_flow": true, "config_flow": true,
"ssdp": [ "ssdp": [

View File

@ -8,7 +8,6 @@
"host": "Host", "host": "Host",
"port": "Port (Optional)", "port": "Port (Optional)",
"ssl": "Use SSL/TLS to connect to your NAS", "ssl": "Use SSL/TLS to connect to your NAS",
"api_version": "DSM version",
"username": "Username", "username": "Username",
"password": "Password" "password": "Password"
} }
@ -24,7 +23,6 @@
"description": "Do you want to setup {name} ({host})?", "description": "Do you want to setup {name} ({host})?",
"data": { "data": {
"ssl": "Use SSL/TLS to connect to your NAS", "ssl": "Use SSL/TLS to connect to your NAS",
"api_version": "DSM version",
"username": "Username", "username": "Username",
"password": "Password", "password": "Password",
"port": "Port (Optional)" "port": "Port (Optional)"
@ -32,9 +30,11 @@
} }
}, },
"error": { "error": {
"connection": "Connection error: please check your host, password & ssl",
"login": "Login error: please check your username & password", "login": "Login error: please check your username & password",
"missing_data": "Missing data: please retry later or an other configuration", "missing_data": "Missing data: please retry later or an other configuration",
"otp_failed": "Two-step authentication failed, retry with a new pass code" "otp_failed": "Two-step authentication failed, retry with a new pass code",
"unknown": "Unknown error: please check logs to get more details"
}, },
"abort": { "already_configured": "Host already configured" } "abort": { "already_configured": "Host already configured" }
} }

View File

@ -4,9 +4,11 @@
"already_configured": "Host already configured" "already_configured": "Host already configured"
}, },
"error": { "error": {
"connection": "Connection error: please check your host, password & ssl",
"login": "Login error: please check your username & password", "login": "Login error: please check your username & password",
"missing_data": "Missing data: please retry later or an other configuration", "missing_data": "Missing data: please retry later or an other configuration",
"otp_failed": "Two-step authentication failed, retry with a new pass code" "otp_failed": "Two-step authentication failed, retry with a new pass code",
"unknown": "Unknown error: please check logs to get more details"
}, },
"flow_title": "Synology DSM {name} ({host})", "flow_title": "Synology DSM {name} ({host})",
"step": { "step": {
@ -18,7 +20,6 @@
}, },
"link": { "link": {
"data": { "data": {
"api_version": "DSM version",
"password": "Password", "password": "Password",
"port": "Port (Optional)", "port": "Port (Optional)",
"ssl": "Use SSL/TLS to connect to your NAS", "ssl": "Use SSL/TLS to connect to your NAS",
@ -29,7 +30,6 @@
}, },
"user": { "user": {
"data": { "data": {
"api_version": "DSM version",
"host": "Host", "host": "Host",
"password": "Password", "password": "Password",
"port": "Port (Optional)", "port": "Port (Optional)",

View File

@ -1680,7 +1680,7 @@ python-sochain-api==0.0.2
python-songpal==0.11.2 python-songpal==0.11.2
# homeassistant.components.synology_dsm # homeassistant.components.synology_dsm
python-synology==0.6.0 python-synology==0.7.0
# homeassistant.components.tado # homeassistant.components.tado
python-tado==0.8.1 python-tado==0.8.1

View File

@ -650,7 +650,7 @@ python-miio==0.5.0.1
python-nest==4.1.0 python-nest==4.1.0
# homeassistant.components.synology_dsm # homeassistant.components.synology_dsm
python-synology==0.6.0 python-synology==0.7.0
# homeassistant.components.tado # homeassistant.components.tado
python-tado==0.8.1 python-tado==0.8.1

View File

@ -4,8 +4,11 @@ from unittest.mock import MagicMock, Mock, patch
import pytest import pytest
from synology_dsm.exceptions import ( from synology_dsm.exceptions import (
SynologyDSMException,
SynologyDSMLogin2SAFailedException, SynologyDSMLogin2SAFailedException,
SynologyDSMLogin2SARequiredException, SynologyDSMLogin2SARequiredException,
SynologyDSMLoginInvalidException,
SynologyDSMRequestException,
) )
from homeassistant import data_entry_flow, setup from homeassistant import data_entry_flow, setup
@ -13,7 +16,6 @@ from homeassistant.components import ssdp
from homeassistant.components.synology_dsm.config_flow import CONF_OTP_CODE from homeassistant.components.synology_dsm.config_flow import CONF_OTP_CODE
from homeassistant.components.synology_dsm.const import ( from homeassistant.components.synology_dsm.const import (
CONF_VOLUMES, CONF_VOLUMES,
DEFAULT_DSM_VERSION,
DEFAULT_PORT, DEFAULT_PORT,
DEFAULT_PORT_SSL, DEFAULT_PORT_SSL,
DEFAULT_SSL, DEFAULT_SSL,
@ -21,7 +23,6 @@ from homeassistant.components.synology_dsm.const import (
) )
from homeassistant.config_entries import SOURCE_IMPORT, SOURCE_SSDP, SOURCE_USER from homeassistant.config_entries import SOURCE_IMPORT, SOURCE_SSDP, SOURCE_USER
from homeassistant.const import ( from homeassistant.const import (
CONF_API_VERSION,
CONF_DISKS, CONF_DISKS,
CONF_HOST, CONF_HOST,
CONF_PASSWORD, CONF_PASSWORD,
@ -76,16 +77,6 @@ def mock_controller_service_2sa():
yield service_mock yield service_mock
@pytest.fixture(name="service_login_failed")
def mock_controller_service_login_failed():
"""Mock a failed login."""
with patch(
"homeassistant.components.synology_dsm.config_flow.SynologyDSM"
) as service_mock:
service_mock.return_value.login = Mock(return_value=False)
yield service_mock
@pytest.fixture(name="service_failed") @pytest.fixture(name="service_failed")
def mock_controller_service_failed(): def mock_controller_service_failed():
"""Mock a failed service.""" """Mock a failed service."""
@ -117,7 +108,6 @@ async def test_user(hass: HomeAssistantType, service: MagicMock):
CONF_SSL: SSL, CONF_SSL: SSL,
CONF_USERNAME: USERNAME, CONF_USERNAME: USERNAME,
CONF_PASSWORD: PASSWORD, CONF_PASSWORD: PASSWORD,
CONF_API_VERSION: 5,
}, },
) )
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
@ -128,7 +118,6 @@ async def test_user(hass: HomeAssistantType, service: MagicMock):
assert result["data"][CONF_SSL] == SSL assert result["data"][CONF_SSL] == SSL
assert result["data"][CONF_USERNAME] == USERNAME assert result["data"][CONF_USERNAME] == USERNAME
assert result["data"][CONF_PASSWORD] == PASSWORD assert result["data"][CONF_PASSWORD] == PASSWORD
assert result["data"][CONF_API_VERSION] == 5
assert result["data"].get("device_token") is None assert result["data"].get("device_token") is None
assert result["data"].get(CONF_DISKS) is None assert result["data"].get(CONF_DISKS) is None
assert result["data"].get(CONF_VOLUMES) is None assert result["data"].get(CONF_VOLUMES) is None
@ -153,7 +142,6 @@ async def test_user(hass: HomeAssistantType, service: MagicMock):
assert not result["data"][CONF_SSL] assert not result["data"][CONF_SSL]
assert result["data"][CONF_USERNAME] == USERNAME assert result["data"][CONF_USERNAME] == USERNAME
assert result["data"][CONF_PASSWORD] == PASSWORD assert result["data"][CONF_PASSWORD] == PASSWORD
assert result["data"][CONF_API_VERSION] == DEFAULT_DSM_VERSION
assert result["data"].get("device_token") is None assert result["data"].get("device_token") is None
assert result["data"].get(CONF_DISKS) is None assert result["data"].get(CONF_DISKS) is None
assert result["data"].get(CONF_VOLUMES) is None assert result["data"].get(CONF_VOLUMES) is None
@ -216,7 +204,6 @@ async def test_import(hass: HomeAssistantType, service: MagicMock):
assert result["data"][CONF_SSL] == DEFAULT_SSL assert result["data"][CONF_SSL] == DEFAULT_SSL
assert result["data"][CONF_USERNAME] == USERNAME assert result["data"][CONF_USERNAME] == USERNAME
assert result["data"][CONF_PASSWORD] == PASSWORD assert result["data"][CONF_PASSWORD] == PASSWORD
assert result["data"][CONF_API_VERSION] == DEFAULT_DSM_VERSION
assert result["data"].get("device_token") is None assert result["data"].get("device_token") is None
assert result["data"].get(CONF_DISKS) is None assert result["data"].get(CONF_DISKS) is None
assert result["data"].get(CONF_VOLUMES) is None assert result["data"].get(CONF_VOLUMES) is None
@ -232,7 +219,6 @@ async def test_import(hass: HomeAssistantType, service: MagicMock):
CONF_SSL: SSL, CONF_SSL: SSL,
CONF_USERNAME: USERNAME, CONF_USERNAME: USERNAME,
CONF_PASSWORD: PASSWORD, CONF_PASSWORD: PASSWORD,
CONF_API_VERSION: 5,
CONF_DISKS: ["sda", "sdb", "sdc"], CONF_DISKS: ["sda", "sdb", "sdc"],
CONF_VOLUMES: ["volume_1"], CONF_VOLUMES: ["volume_1"],
}, },
@ -245,7 +231,6 @@ async def test_import(hass: HomeAssistantType, service: MagicMock):
assert result["data"][CONF_SSL] == SSL assert result["data"][CONF_SSL] == SSL
assert result["data"][CONF_USERNAME] == USERNAME assert result["data"][CONF_USERNAME] == USERNAME
assert result["data"][CONF_PASSWORD] == PASSWORD assert result["data"][CONF_PASSWORD] == PASSWORD
assert result["data"][CONF_API_VERSION] == 5
assert result["data"].get("device_token") is None assert result["data"].get("device_token") is None
assert result["data"][CONF_DISKS] == ["sda", "sdb", "sdc"] assert result["data"][CONF_DISKS] == ["sda", "sdb", "sdc"]
assert result["data"][CONF_VOLUMES] == ["volume_1"] assert result["data"][CONF_VOLUMES] == ["volume_1"]
@ -278,8 +263,12 @@ async def test_abort_if_already_setup(hass: HomeAssistantType, service: MagicMoc
assert result["reason"] == "already_configured" assert result["reason"] == "already_configured"
async def test_login_failed(hass: HomeAssistantType, service_login_failed: MagicMock): async def test_login_failed(hass: HomeAssistantType, service: MagicMock):
"""Test when we have errors during connection.""" """Test when we have errors during login."""
service.return_value.login = Mock(
side_effect=(SynologyDSMLoginInvalidException(USERNAME))
)
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
DOMAIN, DOMAIN,
context={"source": SOURCE_USER}, context={"source": SOURCE_USER},
@ -289,6 +278,36 @@ async def test_login_failed(hass: HomeAssistantType, service_login_failed: Magic
assert result["errors"] == {CONF_USERNAME: "login"} assert result["errors"] == {CONF_USERNAME: "login"}
async def test_connection_failed(hass: HomeAssistantType, service: MagicMock):
"""Test when we have errors during connection."""
service.return_value.login = Mock(
side_effect=SynologyDSMRequestException(IOError("arg"))
)
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_USER},
data={CONF_HOST: HOST, CONF_USERNAME: USERNAME, CONF_PASSWORD: PASSWORD},
)
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["errors"] == {CONF_HOST: "connection"}
async def test_unknown_failed(hass: HomeAssistantType, service: MagicMock):
"""Test when we have an unknown error."""
service.return_value.login = Mock(side_effect=SynologyDSMException)
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_USER},
data={CONF_HOST: HOST, CONF_USERNAME: USERNAME, CONF_PASSWORD: PASSWORD},
)
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["errors"] == {"base": "unknown"}
async def test_missing_data_after_login( async def test_missing_data_after_login(
hass: HomeAssistantType, service_failed: MagicMock hass: HomeAssistantType, service_failed: MagicMock
): ):
@ -329,7 +348,6 @@ async def test_form_ssdp(hass: HomeAssistantType, service: MagicMock):
assert result["data"][CONF_SSL] == DEFAULT_SSL assert result["data"][CONF_SSL] == DEFAULT_SSL
assert result["data"][CONF_USERNAME] == USERNAME assert result["data"][CONF_USERNAME] == USERNAME
assert result["data"][CONF_PASSWORD] == PASSWORD assert result["data"][CONF_PASSWORD] == PASSWORD
assert result["data"][CONF_API_VERSION] == DEFAULT_DSM_VERSION
assert result["data"].get("device_token") is None assert result["data"].get("device_token") is None
assert result["data"].get(CONF_DISKS) is None assert result["data"].get(CONF_DISKS) is None
assert result["data"].get(CONF_VOLUMES) is None assert result["data"].get(CONF_VOLUMES) is None