mirror of
https://github.com/ProtoThis/python-synology.git
synced 2025-07-28 06:39:49 +00:00
Migrate to Python 3.6+ (#70)
* Migrate to Python 3.6+ Drop support of Python < 3.6 - remove six + future deps + usage - update deps - remove encoding - remove (object) * Fix pylint - pip3 super() style - remove simplejson dep + usage * Black format * lint setup * Travix CI py version * Use f string * Basic Typing * Revert setup version bump
This commit is contained in:
@ -3,8 +3,8 @@ dist: xenial
|
||||
|
||||
language: python
|
||||
python:
|
||||
- 2.7
|
||||
- 3.4
|
||||
- 3.6
|
||||
- 3.7
|
||||
- 3.8
|
||||
cache:
|
||||
pip: true
|
||||
@ -17,7 +17,7 @@ install:
|
||||
- python setup.py sdist
|
||||
before_script:
|
||||
- pylint synology_dsm tests
|
||||
- ./scripts/check_format.sh
|
||||
- black --check --fast .
|
||||
script:
|
||||
- py.test
|
||||
|
||||
|
@ -1,5 +1,3 @@
|
||||
requests>=2.20.0
|
||||
urllib3>=1.24.3,<1.25
|
||||
six>=1.14.0
|
||||
future>=0.18.2
|
||||
simplejson>=3.16.0
|
||||
requests>=2.24.0
|
||||
# Constrain urllib3 to ensure we deal with CVE-2019-11236 & CVE-2019-11324
|
||||
urllib3>=1.24.3
|
||||
|
@ -1,3 +1,4 @@
|
||||
pytest
|
||||
pylint>=1.9.5,<=2.4.4
|
||||
pylint>=2.6.0
|
||||
pylint-strict-informational==0.1
|
||||
black==20.8b1
|
||||
|
@ -1,16 +0,0 @@
|
||||
./scripts/common.sh
|
||||
|
||||
if ! hash python3; then
|
||||
echo "python3 is not installed"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
ver=$(python3 -V 2>&1 | sed 's/.* \([0-9]\).\([0-9]\).*/\1\2/')
|
||||
if [ "$ver" -lt "36" ]; then
|
||||
echo "This script requires python 3.6 or greater"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
pip install black==19.10b0
|
||||
|
||||
black --check --fast .
|
14
setup.py
14
setup.py
@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Synology DSM setup."""
|
||||
|
||||
# NOTE(ProtoThis) Guidelines for Major.Minor.Micro
|
||||
# - Major means an API contract change
|
||||
@ -7,7 +7,6 @@
|
||||
# - Micro means change of any kind (unless significant enough for a minor/major).
|
||||
|
||||
from setuptools import setup, find_packages
|
||||
from codecs import open
|
||||
|
||||
REPO_URL = "https://github.com/ProtoThis/python-synology"
|
||||
VERSION = "0.9.0"
|
||||
@ -25,23 +24,24 @@ setup(
|
||||
download_url=REPO_URL + "/tarball/" + VERSION,
|
||||
description="Python API for communication with Synology DSM",
|
||||
long_description=long_description,
|
||||
author="FG van Zeelst (ProtoThis)",
|
||||
author="Quentin POLLET (Quentame) & FG van Zeelst (ProtoThis)",
|
||||
packages=find_packages(include=["synology_dsm*"]),
|
||||
install_requires=required,
|
||||
python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*",
|
||||
python_requires=">=3.6",
|
||||
license="MIT",
|
||||
classifiers=[
|
||||
"Development Status :: 5 - Production/Stable",
|
||||
"Intended Audience :: Developers",
|
||||
"License :: OSI Approved :: MIT License",
|
||||
"Operating System :: OS Independent",
|
||||
"Programming Language :: Python",
|
||||
"Programming Language :: Python :: 2.7",
|
||||
"Programming Language :: Python :: 3 :: Only",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.4",
|
||||
"Programming Language :: Python :: 3.5",
|
||||
"Programming Language :: Python :: 3.6",
|
||||
"Programming Language :: Python :: 3.7",
|
||||
"Programming Language :: Python :: 3.8",
|
||||
"Programming Language :: Python :: 3.9",
|
||||
"Topic :: Software Development :: Libraries",
|
||||
],
|
||||
keywords=["synology-dsm", "synology"],
|
||||
)
|
||||
|
@ -1,8 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""DSM Security data."""
|
||||
|
||||
|
||||
class SynoCoreSecurity(object):
|
||||
class SynoCoreSecurity:
|
||||
"""Class containing Security data."""
|
||||
|
||||
API_KEY = "SYNO.Core.SecurityScan.Status"
|
||||
|
@ -1,9 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Shared Folders data."""
|
||||
from synology_dsm.helpers import SynoFormatHelper
|
||||
|
||||
|
||||
class SynoCoreShare(object):
|
||||
class SynoCoreShare:
|
||||
"""Class containing Share data."""
|
||||
|
||||
API_KEY = "SYNO.Core.Share"
|
||||
|
@ -1,9 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""DSM Utilization data."""
|
||||
from synology_dsm.helpers import SynoFormatHelper
|
||||
|
||||
|
||||
class SynoCoreUtilization(object):
|
||||
class SynoCoreUtilization:
|
||||
"""Class containing Utilization data."""
|
||||
|
||||
API_KEY = "SYNO.Core.System.Utilization"
|
||||
|
@ -2,7 +2,7 @@
|
||||
from .task import SynoDownloadTask
|
||||
|
||||
|
||||
class SynoDownloadStation(object):
|
||||
class SynoDownloadStation:
|
||||
"""An implementation of a Synology DownloadStation."""
|
||||
|
||||
API_KEY = "SYNO.DownloadStation.*"
|
||||
|
@ -1,7 +1,7 @@
|
||||
"""DownloadStation task."""
|
||||
|
||||
|
||||
class SynoDownloadTask(object):
|
||||
class SynoDownloadTask:
|
||||
"""An representation of a Synology DownloadStation task."""
|
||||
|
||||
def __init__(self, data):
|
||||
|
@ -1,8 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""DSM Information data."""
|
||||
|
||||
|
||||
class SynoDSMInformation(object):
|
||||
class SynoDSMInformation:
|
||||
"""Class containing Information data."""
|
||||
|
||||
API_KEY = "SYNO.DSM.Info"
|
||||
|
@ -1,8 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""DSM Network data."""
|
||||
|
||||
|
||||
class SynoDSMNetwork(object):
|
||||
class SynoDSMNetwork:
|
||||
"""Class containing Network data."""
|
||||
|
||||
API_KEY = "SYNO.DSM.Network"
|
||||
|
@ -1,11 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""DSM Storage data."""
|
||||
from __future__ import division
|
||||
|
||||
from synology_dsm.helpers import SynoFormatHelper
|
||||
|
||||
|
||||
class SynoStorage(object):
|
||||
class SynoStorage:
|
||||
"""Class containing Storage data."""
|
||||
|
||||
API_KEY = "SYNO.Storage.CGI.Storage"
|
||||
|
@ -5,7 +5,7 @@ from .camera import SynoCamera
|
||||
from .const import MOTION_DETECTION_BY_SURVEILLANCE, MOTION_DETECTION_DISABLED
|
||||
|
||||
|
||||
class SynoSurveillanceStation(object):
|
||||
class SynoSurveillanceStation:
|
||||
"""An implementation of a Synology SurveillanceStation."""
|
||||
|
||||
API_KEY = "SYNO.SurveillanceStation.*"
|
||||
@ -37,12 +37,12 @@ class SynoSurveillanceStation(object):
|
||||
)["data"]
|
||||
)
|
||||
|
||||
live_view_data = self._dsm.get(
|
||||
live_view_datas = self._dsm.get(
|
||||
self.CAMERA_API_KEY,
|
||||
"GetLiveViewPath",
|
||||
{"idList": ",".join(str(k) for k in self._cameras_by_id)},
|
||||
)["data"]
|
||||
for live_view_data in live_view_data:
|
||||
for live_view_data in live_view_datas:
|
||||
self._cameras_by_id[live_view_data["id"]].live_view.update(live_view_data)
|
||||
|
||||
# Global
|
||||
|
@ -2,7 +2,7 @@
|
||||
from .const import RECORDING_STATUS, MOTION_DETECTION_DISABLED
|
||||
|
||||
|
||||
class SynoCamera(object):
|
||||
class SynoCamera:
|
||||
"""An representation of a Synology SurveillanceStation camera."""
|
||||
|
||||
def __init__(self, data, live_view_data=None):
|
||||
@ -62,7 +62,7 @@ class SynoCamera(object):
|
||||
return self._data["recStatus"] in RECORDING_STATUS
|
||||
|
||||
|
||||
class SynoCameraLiveView(object):
|
||||
class SynoCameraLiveView:
|
||||
"""An representation of a Synology SurveillanceStation camera live view."""
|
||||
|
||||
def __init__(self, data):
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Library constants."""
|
||||
|
||||
# APIs
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Library exceptions."""
|
||||
from .const import API_AUTH, ERROR_AUTH, ERROR_COMMON, ERROR_DOWNLOAD_SEARCH, ERROR_DOWNLOAD_TASK, ERROR_FILE, ERROR_SURVEILLANCE, ERROR_VIRTUALIZATION
|
||||
|
||||
@ -24,7 +23,7 @@ class SynologyDSMException(Exception):
|
||||
reason = "Unknown"
|
||||
|
||||
error_message={"api": api, "code": code, "reason": reason, "details": details}
|
||||
super(SynologyDSMException, self).__init__(error_message)
|
||||
super().__init__(error_message)
|
||||
|
||||
# Request
|
||||
class SynologyDSMRequestException(SynologyDSMException):
|
||||
@ -34,57 +33,56 @@ class SynologyDSMRequestException(SynologyDSMException):
|
||||
ex_reason = exception.args[0]
|
||||
if hasattr(exception.args[0], "reason"):
|
||||
ex_reason = exception.args[0].reason
|
||||
message = "%s = %s" % (ex_class, ex_reason)
|
||||
super(SynologyDSMRequestException, self).__init__(None, -1, message)
|
||||
super().__init__(None, -1, f"{ex_class} = {ex_reason}")
|
||||
|
||||
# API
|
||||
class SynologyDSMAPINotExistsException(SynologyDSMException):
|
||||
"""API not exists exception."""
|
||||
def __init__(self, api):
|
||||
super(SynologyDSMAPINotExistsException, self).__init__(api, -2, "API %s does not exists" % api)
|
||||
super().__init__(api, -2, f"API {api} does not exists")
|
||||
|
||||
class SynologyDSMAPIErrorException(SynologyDSMException):
|
||||
"""API returns an error exception."""
|
||||
def __init__(self, api, code, details):
|
||||
super(SynologyDSMAPIErrorException, self).__init__(api, code, details)
|
||||
super().__init__(api, code, details)
|
||||
|
||||
# Login
|
||||
class SynologyDSMLoginFailedException(SynologyDSMException):
|
||||
"""Failed to login exception."""
|
||||
def __init__(self, code, details=None):
|
||||
super(SynologyDSMLoginFailedException, self).__init__(API_AUTH, code, details)
|
||||
super().__init__(API_AUTH, code, details)
|
||||
|
||||
|
||||
class SynologyDSMLoginInvalidException(SynologyDSMLoginFailedException):
|
||||
"""Invalid password & not admin account exception."""
|
||||
def __init__(self, username):
|
||||
message = "Invalid password or not admin account: %s" % username
|
||||
super(SynologyDSMLoginInvalidException, self).__init__(400, message)
|
||||
message = f"Invalid password or not admin account: {username}"
|
||||
super().__init__(400, message)
|
||||
|
||||
|
||||
class SynologyDSMLoginDisabledAccountException(SynologyDSMLoginFailedException):
|
||||
"""Guest & disabled account exception."""
|
||||
def __init__(self, username):
|
||||
message = "Guest or disabled account: %s" % username
|
||||
super(SynologyDSMLoginDisabledAccountException, self).__init__(401, message)
|
||||
message = f"Guest or disabled account: {username}"
|
||||
super().__init__(401, message)
|
||||
|
||||
|
||||
class SynologyDSMLoginPermissionDeniedException(SynologyDSMLoginFailedException):
|
||||
"""No access to login exception."""
|
||||
def __init__(self, username):
|
||||
message = "Permission denied for account: %s" % username
|
||||
super(SynologyDSMLoginPermissionDeniedException, self).__init__(402, message)
|
||||
message = f"Permission denied for account: {username}"
|
||||
super().__init__(402, message)
|
||||
|
||||
|
||||
class SynologyDSMLogin2SARequiredException(SynologyDSMLoginFailedException):
|
||||
"""2SA required to login exception."""
|
||||
def __init__(self, username):
|
||||
message = "Two-step authentication required for account: %s" % username
|
||||
super(SynologyDSMLogin2SARequiredException, self).__init__(403, message)
|
||||
message = f"Two-step authentication required for account: {username}"
|
||||
super().__init__(403, message)
|
||||
|
||||
|
||||
class SynologyDSMLogin2SAFailedException(SynologyDSMLoginFailedException):
|
||||
"""2SA code failed exception."""
|
||||
def __init__(self):
|
||||
message = "Two-step authentication failed, retry with a new pass code"
|
||||
super(SynologyDSMLogin2SAFailedException, self).__init__(404, message)
|
||||
super().__init__(404, message)
|
||||
|
@ -1,8 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Helpers."""
|
||||
|
||||
|
||||
class SynoFormatHelper(object):
|
||||
class SynoFormatHelper:
|
||||
"""Class containing various formatting functions."""
|
||||
|
||||
@staticmethod
|
||||
|
@ -1,11 +1,11 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Class to interact with Synology DSM."""
|
||||
from json import JSONDecodeError
|
||||
from urllib.parse import quote
|
||||
import socket
|
||||
|
||||
import urllib3
|
||||
import six
|
||||
from requests import Session
|
||||
from requests.exceptions import RequestException
|
||||
from simplejson.errors import JSONDecodeError
|
||||
|
||||
from .exceptions import (
|
||||
SynologyDSMAPIErrorException,
|
||||
@ -29,13 +29,8 @@ from .api.storage.storage import SynoStorage
|
||||
from .api.surveillance_station import SynoSurveillanceStation
|
||||
from .const import API_AUTH, API_INFO
|
||||
|
||||
if six.PY2:
|
||||
from future.moves.urllib.parse import quote
|
||||
else:
|
||||
from urllib.parse import quote # pylint: disable=import-error,no-name-in-module
|
||||
|
||||
|
||||
class SynologyDSM(object):
|
||||
class SynologyDSM:
|
||||
"""Class containing the main Synology DSM functions."""
|
||||
|
||||
DSM_5_WEIRD_URL_API = [
|
||||
@ -44,14 +39,14 @@ class SynologyDSM(object):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
dsm_ip,
|
||||
dsm_port,
|
||||
username,
|
||||
password,
|
||||
use_https=False,
|
||||
timeout=None,
|
||||
device_token=None,
|
||||
debugmode=False,
|
||||
dsm_ip: str,
|
||||
dsm_port: int,
|
||||
username: str,
|
||||
password: str,
|
||||
use_https: bool = False,
|
||||
timeout: int = None,
|
||||
device_token: str = None,
|
||||
debugmode: bool = False,
|
||||
):
|
||||
self.username = username
|
||||
self._password = password
|
||||
@ -86,16 +81,16 @@ class SynologyDSM(object):
|
||||
# disable SSL warnings due to the auto-genenerated cert
|
||||
urllib3.disable_warnings()
|
||||
|
||||
self._base_url = "https://%s:%s" % (dsm_ip, dsm_port)
|
||||
self._base_url = f"https://{dsm_ip}:{dsm_port}"
|
||||
else:
|
||||
self._base_url = "http://%s:%s" % (dsm_ip, dsm_port)
|
||||
self._base_url = f"http://{dsm_ip}:{dsm_port}"
|
||||
|
||||
def _debuglog(self, message):
|
||||
def _debuglog(self, message: str):
|
||||
"""Outputs message if debug mode is enabled."""
|
||||
if self._debugmode:
|
||||
print("DEBUG: " + message)
|
||||
|
||||
def _is_weird_api_url(self, api):
|
||||
def _is_weird_api_url(self, api: str) -> bool:
|
||||
"""Returns True if the API URL is not common (nas_base_url/webapi/path?params) [Only handles DSM 5 for now]."""
|
||||
return (
|
||||
api in self.DSM_5_WEIRD_URL_API
|
||||
@ -104,15 +99,12 @@ class SynologyDSM(object):
|
||||
and int(self._information.version) < 7321 # < DSM 6
|
||||
)
|
||||
|
||||
def _build_url(self, api):
|
||||
def _build_url(self, api: str) -> str:
|
||||
if self._is_weird_api_url(api):
|
||||
if api == SynoStorage.API_KEY:
|
||||
return (
|
||||
"%s/webman/modules/StorageManager/storagehandler.cgi?"
|
||||
% self._base_url
|
||||
)
|
||||
return f"{self._base_url}/webman/modules/StorageManager/storagehandler.cgi?"
|
||||
|
||||
return "%s/webapi/%s?" % (self._base_url, self.apis[api]["path"])
|
||||
return f"{self._base_url}/webapi/{self.apis[api]['path']}?"
|
||||
|
||||
def discover_apis(self):
|
||||
"""Retreives available API infos from the NAS."""
|
||||
@ -125,7 +117,7 @@ class SynologyDSM(object):
|
||||
"""Gets available API infos from the NAS."""
|
||||
return self._apis
|
||||
|
||||
def login(self, otp_code=None):
|
||||
def login(self, otp_code: str = None):
|
||||
"""Create a logged session."""
|
||||
# First reset the session
|
||||
self._debuglog("Creating new session")
|
||||
@ -180,20 +172,26 @@ class SynologyDSM(object):
|
||||
return True
|
||||
|
||||
@property
|
||||
def device_token(self):
|
||||
def device_token(self) -> str:
|
||||
"""Gets the device token to remember the 2SA access was granted on this device."""
|
||||
return self._device_token
|
||||
|
||||
def get(self, api, method, params=None, **kwargs):
|
||||
def get(self, api: str, method: str, params: dict = None, **kwargs):
|
||||
"""Handles API GET request."""
|
||||
return self._request("GET", api, method, params, **kwargs)
|
||||
|
||||
def post(self, api, method, params=None, **kwargs):
|
||||
def post(self, api: str, method: str, params: dict = None, **kwargs):
|
||||
"""Handles API POST request."""
|
||||
return self._request("POST", api, method, params, **kwargs)
|
||||
|
||||
def _request(
|
||||
self, request_method, api, method, params=None, retry_once=True, **kwargs
|
||||
self,
|
||||
request_method: str,
|
||||
api: str,
|
||||
method: str,
|
||||
params: dict = None,
|
||||
retry_once: bool = True,
|
||||
**kwargs
|
||||
):
|
||||
"""Handles API request."""
|
||||
# Discover existing APIs
|
||||
@ -252,17 +250,13 @@ class SynologyDSM(object):
|
||||
|
||||
return response
|
||||
|
||||
def _execute_request(self, method, url, params, **kwargs):
|
||||
def _execute_request(self, method: str, url: str, params: dict, **kwargs):
|
||||
"""Function to execute and handle a request."""
|
||||
# Execute Request
|
||||
try:
|
||||
if method == "GET":
|
||||
if six.PY2:
|
||||
items = params.iteritems()
|
||||
else:
|
||||
items = params.items()
|
||||
encoded_params = "&".join(
|
||||
"%s=%s" % (key, quote(str(value))) for key, value in items
|
||||
f"{key}={quote(str(value))}" for key, value in params.items()
|
||||
)
|
||||
response = self._session.get(
|
||||
url, params=encoded_params, timeout=self._timeout, **kwargs
|
||||
@ -300,9 +294,9 @@ class SynologyDSM(object):
|
||||
raise RequestException(response)
|
||||
|
||||
except (RequestException, JSONDecodeError) as exp:
|
||||
raise SynologyDSMRequestException(exp)
|
||||
raise SynologyDSMRequestException(exp) from exp
|
||||
|
||||
def update(self, with_information=False, with_network=False):
|
||||
def update(self, with_information: bool = False, with_network: bool = False):
|
||||
"""Updates the various instanced modules."""
|
||||
if self._download:
|
||||
self._download.update()
|
||||
@ -328,7 +322,7 @@ class SynologyDSM(object):
|
||||
if self._surveillance:
|
||||
self._surveillance.update()
|
||||
|
||||
def reset(self, api):
|
||||
def reset(self, api: any) -> bool:
|
||||
"""Reset an API to avoid fetching in on update."""
|
||||
if isinstance(api, str):
|
||||
if api in ("information", SynoDSMInformation.API_KEY):
|
||||
@ -376,56 +370,56 @@ class SynologyDSM(object):
|
||||
return False
|
||||
|
||||
@property
|
||||
def download_station(self):
|
||||
def download_station(self) -> SynoDownloadStation:
|
||||
"""Gets NAS DownloadStation."""
|
||||
if not self._download:
|
||||
self._download = SynoDownloadStation(self)
|
||||
return self._download
|
||||
|
||||
@property
|
||||
def information(self):
|
||||
def information(self) -> SynoDSMInformation:
|
||||
"""Gets NAS informations."""
|
||||
if not self._information:
|
||||
self._information = SynoDSMInformation(self)
|
||||
return self._information
|
||||
|
||||
@property
|
||||
def network(self):
|
||||
def network(self) -> SynoDSMNetwork:
|
||||
"""Gets NAS network informations."""
|
||||
if not self._network:
|
||||
self._network = SynoDSMNetwork(self)
|
||||
return self._network
|
||||
|
||||
@property
|
||||
def security(self):
|
||||
def security(self) -> SynoCoreSecurity:
|
||||
"""Gets NAS security informations."""
|
||||
if not self._security:
|
||||
self._security = SynoCoreSecurity(self)
|
||||
return self._security
|
||||
|
||||
@property
|
||||
def utilisation(self):
|
||||
def utilisation(self) -> SynoCoreUtilization:
|
||||
"""Gets NAS utilisation informations."""
|
||||
if not self._utilisation:
|
||||
self._utilisation = SynoCoreUtilization(self)
|
||||
return self._utilisation
|
||||
|
||||
@property
|
||||
def storage(self):
|
||||
def storage(self) -> SynoStorage:
|
||||
"""Gets NAS storage informations."""
|
||||
if not self._storage:
|
||||
self._storage = SynoStorage(self)
|
||||
return self._storage
|
||||
|
||||
@property
|
||||
def share(self):
|
||||
def share(self) -> SynoCoreShare:
|
||||
"""Gets NAS shares information."""
|
||||
if not self._share:
|
||||
self._share = SynoCoreShare(self)
|
||||
return self._share
|
||||
|
||||
@property
|
||||
def surveillance_station(self):
|
||||
def surveillance_station(self) -> SynoSurveillanceStation:
|
||||
"""Gets NAS SurveillanceStation."""
|
||||
if not self._surveillance:
|
||||
self._surveillance = SynoSurveillanceStation(self)
|
||||
|
@ -1,8 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Library tests."""
|
||||
import six
|
||||
from json import JSONDecodeError
|
||||
from urllib.parse import urlencode
|
||||
|
||||
from requests.exceptions import ConnectionError as ConnError, RequestException, SSLError
|
||||
from simplejson.errors import JSONDecodeError
|
||||
|
||||
from synology_dsm import SynologyDSM
|
||||
from synology_dsm.exceptions import SynologyDSMRequestException
|
||||
@ -71,7 +71,9 @@ API_SWITCHER = {
|
||||
"DSM_INFORMATION": DSM_5_DSM_INFORMATION,
|
||||
"DSM_NETWORK": DSM_5_DSM_NETWORK,
|
||||
"CORE_UTILIZATION": DSM_5_CORE_UTILIZATION,
|
||||
"STORAGE_STORAGE": {"RAID": DSM_5_STORAGE_STORAGE_DS410J_RAID5_4DISKS_1VOL,},
|
||||
"STORAGE_STORAGE": {
|
||||
"RAID": DSM_5_STORAGE_STORAGE_DS410J_RAID5_4DISKS_1VOL,
|
||||
},
|
||||
},
|
||||
6: {
|
||||
"API_INFO": DSM_6_API_INFO,
|
||||
@ -93,11 +95,6 @@ API_SWITCHER = {
|
||||
}
|
||||
|
||||
|
||||
if six.PY2:
|
||||
from future.moves.urllib.parse import urlencode
|
||||
else:
|
||||
from urllib.parse import urlencode # pylint: disable=import-error,no-name-in-module
|
||||
|
||||
VALID_HOST = "nas.mywebsite.me"
|
||||
VALID_PORT = "443"
|
||||
VALID_SSL = True
|
||||
@ -161,7 +158,7 @@ class SynologyDSMMock(SynologyDSM):
|
||||
|
||||
if VALID_PORT not in url and "https" not in url:
|
||||
raise SynologyDSMRequestException(
|
||||
JSONDecodeError("Expecting value", "<html>document</html>", 0, None)
|
||||
JSONDecodeError("Expecting value", "<html>document</html>", 0)
|
||||
)
|
||||
|
||||
if VALID_PORT not in url:
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""DSM 5 SYNO.Core.System.Utilization data."""
|
||||
|
||||
DSM_5_CORE_UTILIZATION = {
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""DSM 5 SYNO.DSM.Info data."""
|
||||
|
||||
DSM_5_DSM_INFORMATION_DS410J = {
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""DSM 5 SYNO.DSM.Network data."""
|
||||
|
||||
DSM_5_DSM_NETWORK = {
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""DSM 5 SYNO.Storage.CGI.Storage data."""
|
||||
from tests.const import UNIQUE_KEY
|
||||
|
||||
@ -253,10 +252,18 @@ DSM_5_STORAGE_STORAGE_DS410J_RAID5_4DISKS_1VOL = {
|
||||
"vol_path": "/volume1",
|
||||
"vspace_can_do": {
|
||||
"drbd": {
|
||||
"resize": {"can_do": False, "errCode": 53504, "stopService": False,}
|
||||
"resize": {
|
||||
"can_do": False,
|
||||
"errCode": 53504,
|
||||
"stopService": False,
|
||||
}
|
||||
},
|
||||
"flashcache": {
|
||||
"apply": {"can_do": False, "errCode": 53504, "stopService": False,},
|
||||
"apply": {
|
||||
"can_do": False,
|
||||
"errCode": 53504,
|
||||
"stopService": False,
|
||||
},
|
||||
"remove": {
|
||||
"can_do": False,
|
||||
"errCode": 53504,
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""DSM 6 SYNO.Core.SecurityScan.Status data."""
|
||||
|
||||
DSM_6_CORE_SECURITY = {
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""DSM 6 SYNO.Core.Share data."""
|
||||
|
||||
DSM_6_CORE_SHARE = {
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""DSM 6 SYNO.Core.System.Utilization data."""
|
||||
|
||||
DSM_6_CORE_UTILIZATION_ERROR_1055 = {
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""DSM 6 SYNO.DownloadStation.Info data."""
|
||||
|
||||
DSM_6_DOWNLOAD_STATION_INFO_INFO = {
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""DSM 6 SYNO.DownloadStation.Statistic data."""
|
||||
|
||||
DSM_6_DOWNLOAD_STATION_STAT_INFO = {
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""DSM 6 SYNO.DownloadStation.Task data."""
|
||||
|
||||
DSM_6_DOWNLOAD_STATION_TASK_LIST = {
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""DSM 6 SYNO.DSM.Info data."""
|
||||
|
||||
DSM_6_DSM_INFORMATION_DS213_PLUS = {
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""DSM 6 SYNO.DSM.Network data."""
|
||||
|
||||
DSM_6_DSM_NETWORK = {
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""DSM 6 SYNO.Storage.CGI.Storage data."""
|
||||
from tests.const import UNIQUE_KEY
|
||||
|
||||
@ -1979,7 +1978,10 @@ DSM_6_STORAGE_STORAGE_DS918_PLUS_RAID5_3DISKS_1VOL = {
|
||||
"env": {
|
||||
"batchtask": {"max_task": 64, "remain_task": 64},
|
||||
"bay_number": "4",
|
||||
"data_scrubbing": {"sche_enabled": "0", "sche_status": "disabled",},
|
||||
"data_scrubbing": {
|
||||
"sche_enabled": "0",
|
||||
"sche_status": "disabled",
|
||||
},
|
||||
"ebox": [],
|
||||
"fs_acting": False,
|
||||
"isSyncSysPartition": False,
|
||||
@ -1993,8 +1995,15 @@ DSM_6_STORAGE_STORAGE_DS918_PLUS_RAID5_3DISKS_1VOL = {
|
||||
"ram_size": 4,
|
||||
"ram_size_required": 32,
|
||||
"showpooltab": False,
|
||||
"status": {"system_crashed": False, "system_need_repair": False,},
|
||||
"support": {"ebox": True, "raid_cross": True, "sysdef": True,},
|
||||
"status": {
|
||||
"system_crashed": False,
|
||||
"system_need_repair": False,
|
||||
},
|
||||
"support": {
|
||||
"ebox": True,
|
||||
"raid_cross": True,
|
||||
"sysdef": True,
|
||||
},
|
||||
"support_fit_fs_limit": True,
|
||||
"unique_key": UNIQUE_KEY,
|
||||
"volume_full_critical": 0.1,
|
||||
@ -2040,9 +2049,21 @@ DSM_6_STORAGE_STORAGE_DS918_PLUS_RAID5_3DISKS_1VOL = {
|
||||
{
|
||||
"designedDiskCount": 3,
|
||||
"devices": [
|
||||
{"id": "sdc", "slot": 2, "status": "normal",},
|
||||
{"id": "sdb", "slot": 1, "status": "normal",},
|
||||
{"id": "sda", "slot": 0, "status": "normal",},
|
||||
{
|
||||
"id": "sdc",
|
||||
"slot": 2,
|
||||
"status": "normal",
|
||||
},
|
||||
{
|
||||
"id": "sdb",
|
||||
"slot": 1,
|
||||
"status": "normal",
|
||||
},
|
||||
{
|
||||
"id": "sda",
|
||||
"slot": 0,
|
||||
"status": "normal",
|
||||
},
|
||||
],
|
||||
"hasParity": True,
|
||||
"minDevSize": "4000681164800",
|
||||
@ -2053,7 +2074,10 @@ DSM_6_STORAGE_STORAGE_DS918_PLUS_RAID5_3DISKS_1VOL = {
|
||||
}
|
||||
],
|
||||
"scrubbingStatus": "no_action",
|
||||
"size": {"total": "7991698522112", "used": "7991698522112",},
|
||||
"size": {
|
||||
"total": "7991698522112",
|
||||
"used": "7991698522112",
|
||||
},
|
||||
"space_path": "/dev/md2",
|
||||
"ssd_trim": {"support": "not support"},
|
||||
"status": "normal",
|
||||
@ -2068,9 +2092,21 @@ DSM_6_STORAGE_STORAGE_DS918_PLUS_RAID5_3DISKS_1VOL = {
|
||||
}
|
||||
},
|
||||
"flashcache": {
|
||||
"apply": {"can_do": True, "errCode": 0, "stopService": True,},
|
||||
"remove": {"can_do": True, "errCode": 0, "stopService": False,},
|
||||
"resize": {"can_do": True, "errCode": 0, "stopService": False,},
|
||||
"apply": {
|
||||
"can_do": True,
|
||||
"errCode": 0,
|
||||
"stopService": True,
|
||||
},
|
||||
"remove": {
|
||||
"can_do": True,
|
||||
"errCode": 0,
|
||||
"stopService": False,
|
||||
},
|
||||
"resize": {
|
||||
"can_do": True,
|
||||
"errCode": 0,
|
||||
"stopService": False,
|
||||
},
|
||||
},
|
||||
"snapshot": {
|
||||
"resize": {
|
||||
@ -2142,9 +2178,21 @@ DSM_6_STORAGE_STORAGE_DS918_PLUS_RAID5_3DISKS_1VOL = {
|
||||
}
|
||||
},
|
||||
"flashcache": {
|
||||
"apply": {"can_do": True, "errCode": 0, "stopService": True,},
|
||||
"remove": {"can_do": True, "errCode": 0, "stopService": False,},
|
||||
"resize": {"can_do": True, "errCode": 0, "stopService": False,},
|
||||
"apply": {
|
||||
"can_do": True,
|
||||
"errCode": 0,
|
||||
"stopService": True,
|
||||
},
|
||||
"remove": {
|
||||
"can_do": True,
|
||||
"errCode": 0,
|
||||
"stopService": False,
|
||||
},
|
||||
"resize": {
|
||||
"can_do": True,
|
||||
"errCode": 0,
|
||||
"stopService": False,
|
||||
},
|
||||
},
|
||||
"snapshot": {
|
||||
"resize": {
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""DSM 6 SYNO.SurveillanceStation.Camera data."""
|
||||
|
||||
DSM_6_SURVEILLANCE_STATION_CAMERA_LIST = {
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""DSM 6 SYNO.API.SurveillanceStation.HomeMode data."""
|
||||
|
||||
DSM_6_SURVEILLANCE_STATION_HOME_MODE_GET_INFO = {
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Test constants."""
|
||||
|
||||
# API test data are localized in
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Synology DSM tests."""
|
||||
from unittest import TestCase
|
||||
import pytest
|
||||
|
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Synology DSM tests."""
|
||||
from unittest import TestCase
|
||||
|
||||
|
Reference in New Issue
Block a user