Fix a lot of flake8 linting errors (#85)

* Restore standard ignore list for flake8

In previous version we add some checks to ignore list.

* Fix all B950 flake8 errors (line too long)

Fix the code and add 2 per-file-ignore paterns for readability reasons.

* Fix F401 flake8 errors (import not used)

* Fix E302 flake8 errors

* Fix E266 flake8 errors

* Fix D107 flake8 errors

* Fix Dxxx Flake8 errors

* Add explanation on flake8 ignored rules

* Remove pyling inline ignore rules

pylint is no more used and replaced by flake8.

* Remove D102 flake8 errors.

* Apply suggestions from code review

Co-authored-by: Quentame <polletquentin74@me.com>

Co-authored-by: Quentame <polletquentin74@me.com>
This commit is contained in:
Oncleben31
2020-10-25 19:49:10 +01:00
committed by GitHub
parent 708e2b2342
commit 336731cbc2
20 changed files with 153 additions and 46 deletions

17
.flake8
View File

@ -1,12 +1,15 @@
[flake8]
select = B,B9,C,DAR,E,F,N,RST,S,W
# Some tests have been added to the ignore list to avoid reworking too much
# the code in this PR: D107, D403, B950, E266, C901, F401, E302.
# The error will be processed in a dedicated PR.
# targeted ignore list is:
select = B,B9,C,D,DAR,E,F,N,RST,S,W
# Some rules are ignore on top of the standard ones.
# C901 (complexity) will be processed in a dedicated PR
# DARxxx (documentation in docstrings) will be processed in a dedicated PR
# Final target is:
# ignore = E203,E501,RST201,RST203,RST301,W503
ignore = E203,E501,RST201,RST203,RST301,W503, D107, D403, B950, E266, C901, F401, E302
ignore = E203,E501,RST201,RST203,RST301,W503, C901, DAR101, DAR201
max-line-length = 80
max-complexity = 10
docstring-convention = google
per-file-ignores = tests/*:S101
per-file-ignores =
tests/*:S101
tests/**/const_*.py:B950
src/synology_dsm/const.py:B950

View File

@ -1,2 +1,4 @@
"""The python-synology library."""
from .synology_dsm import SynologyDSM
__all__ = ["SynologyDSM"]

View File

@ -7,6 +7,7 @@ class SynoCoreSecurity:
API_KEY = "SYNO.Core.SecurityScan.Status"
def __init__(self, dsm):
"""Constructor method."""
self._dsm = dsm
self._data = {}
@ -38,12 +39,18 @@ class SynoCoreSecurity:
@property
def progress(self):
"""Gets the scan progress (100 if finished)."""
"""Gets the scan progress.
Returns: 100 if finished
"""
return self._data.get("sysProgress")
@property
def status(self):
"""Gets the last scan status (safe, danger, info, outOfDate, risk, warning)."""
"""Gets the last scan status.
Possible values: safe, danger, info, outOfDate, risk, warning.
"""
return self._data.get("sysStatus")
@property

View File

@ -11,15 +11,17 @@ class SynoCoreShare:
# are returned plus any keys listed in the "additional" parameter.
# NOTE: The value of the additional key must be a string.
REQUEST_DATA = {
"additional": '["hidden","encryption","is_aclmode","unite_permission","is_support_acl",'
'"is_sync_share","is_force_readonly","force_readonly_reason","recyclebin",'
'"is_share_moving","is_cluster_share","is_exfat_share","is_cold_storage_share",'
'"support_snapshot","share_quota","enable_share_compress","enable_share_cow",'
'"include_cold_storage_share","is_cold_storage_share"]',
"additional": '["hidden","encryption","is_aclmode","unite_permission",'
'"is_support_acl","is_sync_share","is_force_readonly","force_readonly_reason",'
'"recyclebin","is_share_moving","is_cluster_share","is_exfat_share",'
'"is_cold_storage_share","support_snapshot","share_quota",'
'"enable_share_compress","enable_share_cow","include_cold_storage_share",'
'"is_cold_storage_share"]',
"shareType": "all",
}
def __init__(self, dsm):
"""Constructor method."""
self._dsm = dsm
self._data = {}

View File

@ -7,6 +7,7 @@ class SynoCoreSystem:
API_KEY = "SYNO.Core.System"
def __init__(self, dsm):
"""Constructor method."""
self._dsm = dsm
self._data = {}
@ -16,7 +17,9 @@ class SynoCoreSystem:
if raw_data:
self._data = raw_data["data"]
### get information
#
# get information
#
@property
def cpu_clock_speed(self):
"""Gets System CPU clock speed."""
@ -97,7 +100,9 @@ class SynoCoreSystem:
"""Gets System connected usb devices."""
return self._data.get("usb_dev", [])
### do system actions
#
# do system actions
#
def shutdown(self):
"""Shutdown NAS."""
res = self._dsm.get(

View File

@ -8,6 +8,7 @@ class SynoCoreUpgrade:
API_SERVER_KEY = API_KEY + ".Server"
def __init__(self, dsm):
"""Constructor method."""
self._dsm = dsm
self._data = {}

View File

@ -8,6 +8,7 @@ class SynoCoreUtilization:
API_KEY = "SYNO.Core.System.Utilization"
def __init__(self, dsm):
"""Constructor method."""
self._dsm = dsm
self._data = {}
@ -24,17 +25,17 @@ class SynoCoreUtilization:
@property
def cpu_other_load(self):
"""'Other' percentage of the total CPU load."""
"""Other percentage of the total CPU load."""
return self.cpu.get("other_load")
@property
def cpu_user_load(self):
"""'User' percentage of the total CPU load."""
"""User percentage of the total CPU load."""
return self.cpu.get("user_load")
@property
def cpu_system_load(self):
"""'System' percentage of the total CPU load."""
"""System percentage of the total CPU load."""
return self.cpu.get("system_load")
@property

View File

@ -39,7 +39,11 @@ class SynoDownloadTask:
@property
def status(self):
"""Return status of the task (waiting, downloading, paused, finishing, finished, hash_checking, seeding, filehosting_waiting, extracting, error)."""
"""Return status of the task.
Possible values: waiting, downloading, paused, finishing, finished,
hash_checking, seeding, filehosting_waiting, extracting, error
"""
return self._data["status"]
@property

View File

@ -7,6 +7,7 @@ class SynoDSMInformation:
API_KEY = "SYNO.DSM.Info"
def __init__(self, dsm):
"""Constructor methods."""
self._dsm = dsm
self._data = {}

View File

@ -7,6 +7,7 @@ class SynoDSMNetwork:
API_KEY = "SYNO.DSM.Network"
def __init__(self, dsm):
"""Constructor method."""
self._dsm = dsm
self._data = {}
@ -45,7 +46,7 @@ class SynoDSMNetwork:
@property
def macs(self):
"""MACs of the NAS."""
"""MACs of the NAS.""" # noqa: D403
macs = []
for interface in self.interfaces:
macs.append(interface["mac"])

View File

@ -8,6 +8,7 @@ class SynoStorage:
API_KEY = "SYNO.Storage.CGI.Storage"
def __init__(self, dsm):
"""Constructor method."""
self._dsm = dsm
self._data = {}

View File

@ -1,6 +1,4 @@
"""Synology SurveillanceStation API wrapper."""
import urllib
from .camera import SynoCamera
from .const import MOTION_DETECTION_BY_SURVEILLANCE
from .const import MOTION_DETECTION_DISABLED
@ -64,7 +62,12 @@ class SynoSurveillanceStation:
return self._cameras_by_id[camera_id]
def get_camera_live_view_path(self, camera_id, video_format=None):
"""Return camera live view path matching camera_id (video_format: mjpeg_http | multicast | mxpeg_http | rtsp_http | rtsp)."""
"""Return camera live view path matching camera_id.
Args:
camera_id: ID of the camera we want to get the live view path.
video_format: mjpeg_http | multicast | mxpeg_http | rtsp_http | rtsp.
"""
if video_format:
return getattr(self._cameras_by_id[camera_id].live_view, video_format)
return self._cameras_by_id[camera_id].live_view
@ -100,7 +103,12 @@ class SynoSurveillanceStation:
)
def download_snapshot(self, snapshot_id, snapshot_size):
"""Download snapshot image binary for a givent snapshot_id (snapshot_size: SNAPSHOT_SIZE_ICON | SNAPSHOT_SIZE_FULL)."""
"""Download snapshot image binary for a givent snapshot_id.
Args:
snapshot_id: ID of the snapshot we want to download.
snapshot_size: SNAPSHOT_SIZE_ICON | SNAPSHOT_SIZE_FULL.
"""
return self._dsm.get(
self.SNAPSHOT_API_KEY,
"LoadSnapshot",
@ -130,11 +138,11 @@ class SynoSurveillanceStation:
# Home mode
def get_home_mode_status(self):
"""Get the state of Home Mode"""
"""Get the state of Home Mode."""
return self._dsm.get(self.HOME_MODE_API_KEY, "GetInfo")["data"]["on"]
def set_home_mode(self, state):
"""Set the state of Home Mode (state: bool)"""
"""Set the state of Home Mode (state: bool)."""
return self._dsm.get(
self.HOME_MODE_API_KEY, "Switch", {"on": str(state).lower()}
)["success"]

View File

@ -13,6 +13,7 @@ class SynologyDSMException(Exception):
"""Generic Synology DSM exception."""
def __init__(self, api, code, details=None):
"""Constructor method."""
reason = ERROR_COMMON.get(code)
if api and not reason:
if api == API_AUTH:
@ -40,6 +41,7 @@ class SynologyDSMRequestException(SynologyDSMException):
"""Request exception."""
def __init__(self, exception):
"""Constructor method."""
ex_class = exception.__class__.__name__
ex_reason = exception.args[0]
if hasattr(exception.args[0], "reason"):
@ -52,6 +54,7 @@ class SynologyDSMAPINotExistsException(SynologyDSMException):
"""API not exists exception."""
def __init__(self, api):
"""Constructor method."""
super().__init__(api, -2, f"API {api} does not exists")
@ -59,6 +62,7 @@ class SynologyDSMAPIErrorException(SynologyDSMException):
"""API returns an error exception."""
def __init__(self, api, code, details):
"""Constructor method."""
super().__init__(api, code, details)
@ -67,6 +71,7 @@ class SynologyDSMLoginFailedException(SynologyDSMException):
"""Failed to login exception."""
def __init__(self, code, details=None):
"""Constructor method."""
super().__init__(API_AUTH, code, details)
@ -74,6 +79,7 @@ class SynologyDSMLoginInvalidException(SynologyDSMLoginFailedException):
"""Invalid password & not admin account exception."""
def __init__(self, username):
"""Constructor method."""
message = f"Invalid password or not admin account: {username}"
super().__init__(400, message)
@ -82,6 +88,7 @@ class SynologyDSMLoginDisabledAccountException(SynologyDSMLoginFailedException):
"""Guest & disabled account exception."""
def __init__(self, username):
"""Constructor method."""
message = f"Guest or disabled account: {username}"
super().__init__(401, message)
@ -90,6 +97,7 @@ class SynologyDSMLoginPermissionDeniedException(SynologyDSMLoginFailedException)
"""No access to login exception."""
def __init__(self, username):
"""Constructor method."""
message = f"Permission denied for account: {username}"
super().__init__(402, message)
@ -98,6 +106,7 @@ class SynologyDSMLogin2SARequiredException(SynologyDSMLoginFailedException):
"""2SA required to login exception."""
def __init__(self, username):
"""Constructor method."""
message = f"Two-step authentication required for account: {username}"
super().__init__(403, message)
@ -106,5 +115,6 @@ class SynologyDSMLogin2SAFailedException(SynologyDSMLoginFailedException):
"""2SA code failed exception."""
def __init__(self):
"""Constructor method."""
message = "Two-step authentication failed, retry with a new pass code"
super().__init__(404, message)

View File

@ -7,7 +7,7 @@ class SynoFormatHelper:
@staticmethod
def bytes_to_readable(num):
"""Converts bytes to a human readable format."""
if num < 512: # pylint: disable=no-else-return
if num < 512:
return "0 Kb"
elif num < 1024:
return "1 Kb"

View File

@ -49,6 +49,7 @@ class SynologyDSM:
device_token: str = None,
debugmode: bool = False,
):
"""Constructor method."""
self.username = username
self._password = password
self._timeout = timeout or 10
@ -82,7 +83,7 @@ class SynologyDSM:
# Build variables
if use_https:
if not verify_ssl:
# https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings
# https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings # noqa: B950
# disable SSL warnings due to the auto-genenerated cert
urllib3.disable_warnings()
@ -96,7 +97,11 @@ class SynologyDSM:
print("DEBUG: " + message)
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]."""
"""Returns True if the API URL is not common.
Common template is nas_base_url/webapi/path?params
Only handles DSM 5 for now.
"""
return (
api in self.DSM_5_WEIRD_URL_API
and self._information
@ -107,7 +112,10 @@ class SynologyDSM:
def _build_url(self, api: str) -> str:
if self._is_weird_api_url(api):
if api == SynoStorage.API_KEY:
return f"{self._base_url}/webman/modules/StorageManager/storagehandler.cgi?"
return (
f"{self._base_url}/webman/modules/StorageManager/"
f"storagehandler.cgi?"
)
return f"{self._base_url}/webapi/{self.apis[api]['path']}?"
@ -166,7 +174,8 @@ class SynologyDSM:
# Not available on API version < 3
self._syno_token = result["data"]["synotoken"]
if result["data"].get("did"):
# Not available on API version < 6 && device token is given once per device_name
# Not available on API version < 6 && device token is given once
# per device_name
self._device_token = result["data"]["did"]
self._debuglog("Authentication successful, token: " + str(self._session_id))
@ -184,7 +193,10 @@ class SynologyDSM:
@property
def device_token(self) -> str:
"""Gets the device token to remember the 2SA access was granted on this device."""
"""Gets the device token.
Used to remember the 2SA access was granted on this device.
"""
return self._device_token
def get(self, api: str, method: str, params: dict = None, **kwargs):
@ -250,7 +262,8 @@ class SynologyDSM:
if isinstance(response, dict) and response.get("error") and api != API_AUTH:
self._debuglog("Session error: " + str(response["error"]["code"]))
if response["error"]["code"] == 119 and retry_once:
# Session ID not valid, see https://github.com/aerialls/synology-srm/pull/3
# Session ID not valid
# see https://github.com/aerialls/synology-srm/pull/3
self._session_id = None
self._syno_token = None
self._device_token = None

View File

@ -93,7 +93,7 @@ API_SWITCHER = {
"RAID": DSM_6_STORAGE_STORAGE_DS918_PLUS_RAID5_3DISKS_1VOL,
"SHR1": DSM_6_STORAGE_STORAGE_DS213_PLUS_SHR1_2DISKS_2VOLS,
"SHR2": DSM_6_STORAGE_STORAGE_DS1819_PLUS_SHR2_8DISKS_1VOL,
"SHR2_EXPANSION": DSM_6_STORAGE_STORAGE_DS1515_PLUS_SHR2_10DISKS_1VOL_WITH_EXPANSION,
"SHR2_EXPANSION": DSM_6_STORAGE_STORAGE_DS1515_PLUS_SHR2_10DISKS_1VOL_WITH_EXPANSION, # noqa: B950
},
},
}
@ -128,6 +128,7 @@ class SynologyDSMMock(SynologyDSM):
device_token=None,
debugmode=False,
):
"""Constructor method."""
SynologyDSM.__init__(
self,
dsm_ip,
@ -153,14 +154,18 @@ class SynologyDSMMock(SynologyDSM):
if "no_internet" in url:
raise SynologyDSMRequestException(
ConnError(
"<urllib3.connection.VerifiedHTTPSConnection object at 0x106c1f250>: Failed to establish a new connection: [Errno 8] nodename nor servname provided, or not known"
"<urllib3.connection.VerifiedHTTPSConnection object at "
"0x106c1f250>: Failed to establish a new connection: "
"[Errno 8] nodename nor servname provided, or not known"
)
)
if VALID_HOST not in url:
raise SynologyDSMRequestException(
ConnError(
"<urllib3.connection.HTTPConnection object at 0x10d6f8090>: Failed to establish a new connection: [Errno 8] nodename nor servname provided, or not known"
"<urllib3.connection.HTTPConnection object at 0x10d6f8090>:"
" Failed to establish a new connection: [Errno 8] nodename "
"nor servname provided, or not known"
)
)

View File

@ -9,3 +9,14 @@ from .dsm.const_5_dsm_network import DSM_5_DSM_NETWORK
from .storage.const_5_storage_storage import (
DSM_5_STORAGE_STORAGE_DS410J_RAID5_4DISKS_1VOL,
)
__all__ = [
"DSM_5_AUTH_LOGIN",
"DSM_5_AUTH_LOGIN_2SA",
"DSM_5_AUTH_LOGIN_2SA_OTP",
"DSM_5_API_INFO",
"DSM_5_CORE_UTILIZATION",
"DSM_5_DSM_INFORMATION",
"DSM_5_DSM_NETWORK",
"DSM_5_STORAGE_STORAGE_DS410J_RAID5_4DISKS_1VOL",
]

View File

@ -58,3 +58,35 @@ from .surveillance_station.const_6_surveillance_station_home_mode import (
from .surveillance_station.const_6_surveillance_station_home_mode import (
DSM_6_SURVEILLANCE_STATION_HOME_MODE_SWITCH,
)
__all__ = [
"DSM_6_AUTH_LOGIN",
"DSM_6_AUTH_LOGIN_2SA",
"DSM_6_AUTH_LOGIN_2SA_OTP",
"DSM_6_API_INFO",
"DSM_6_CORE_SECURITY",
"DSM_6_CORE_SECURITY_UPDATE_OUTOFDATE",
"DSM_6_CORE_SHARE",
"DSM_6_CORE_SYSTEM_DS218_PLAY",
"DSM_6_CORE_SYSTEM_DS918_PLUS",
"DSM_6_CORE_UPGRADE",
"DSM_6_CORE_UTILIZATION",
"DSM_6_CORE_UTILIZATION_ERROR_1055",
"DSM_6_DOWNLOAD_STATION_INFO_CONFIG",
"DSM_6_DOWNLOAD_STATION_INFO_INFO",
"DSM_6_DOWNLOAD_STATION_STAT_INFO",
"DSM_6_DOWNLOAD_STATION_TASK_LIST",
"DSM_6_DSM_INFORMATION",
"DSM_6_DSM_NETWORK",
"DSM_6_STORAGE_STORAGE_DS1515_PLUS_SHR2_10DISKS_1VOL_WITH_EXPANSION",
"DSM_6_STORAGE_STORAGE_DS1819_PLUS_SHR2_8DISKS_1VOL",
"DSM_6_STORAGE_STORAGE_DS213_PLUS_SHR1_2DISKS_2VOLS",
"DSM_6_STORAGE_STORAGE_DS918_PLUS_RAID5_3DISKS_1VOL",
"DSM_6_API_INFO_SURVEILLANCE_STATION",
"DSM_6_SURVEILLANCE_STATION_CAMERA_EVENT_MD_PARAM_SAVE",
"DSM_6_SURVEILLANCE_STATION_CAMERA_EVENT_MOTION_ENUM",
"DSM_6_SURVEILLANCE_STATION_CAMERA_GET_LIVE_VIEW_PATH",
"DSM_6_SURVEILLANCE_STATION_CAMERA_LIST",
"DSM_6_SURVEILLANCE_STATION_HOME_MODE_GET_INFO",
"DSM_6_SURVEILLANCE_STATION_HOME_MODE_SWITCH",
]

View File

@ -28,8 +28,6 @@ from synology_dsm.exceptions import SynologyDSMLoginFailedException
from synology_dsm.exceptions import SynologyDSMLoginInvalidException
from synology_dsm.exceptions import SynologyDSMRequestException
# pylint: disable=no-self-use,protected-access
class TestSynologyDSM(TestCase):
"""SynologyDSM test cases."""
@ -37,6 +35,7 @@ class TestSynologyDSM(TestCase):
api = None
def setUp(self):
"""Context initialisation called for all tests."""
self.api = SynologyDSMMock(
VALID_HOST,
VALID_PORT,
@ -112,9 +111,9 @@ class TestSynologyDSM(TestCase):
assert not error_value["api"]
assert error_value["code"] == -1
assert error_value["reason"] == "Unknown"
assert (
error_value["details"]
== "SSLError = [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:1076)"
assert error_value["details"] == (
"SSLError = [SSL: WRONG_VERSION_NUMBER] "
"wrong version number (_ssl.c:1076)"
)
assert not api.apis.get(API_AUTH)
@ -380,9 +379,9 @@ class TestSynologyDSM(TestCase):
error_value = error.value.args[0]
assert error_value["api"] == "SYNO.FileStation.Upload"
assert error_value["code"] == 1805
assert (
error_value["reason"]
== "Cant overwrite or skip the existed file, if no overwrite parameter is given"
assert error_value["reason"] == (
"Cant overwrite or skip the existed file, if no overwrite"
" parameter is given"
)
assert not error_value["details"]

View File

@ -21,13 +21,14 @@ from synology_dsm.exceptions import SynologyDSMLogin2SARequiredException
from synology_dsm.exceptions import SynologyDSMLoginInvalidException
from synology_dsm.exceptions import SynologyDSMRequestException
# pylint: disable=no-self-use,protected-access,anomalous-backslash-in-string
class TestSynologyDSM(TestCase):
"""SynologyDSM test cases."""
api = None
def setUp(self):
"""Context initialisation called for all tests."""
self.api = SynologyDSMMock(
VALID_HOST,
VALID_PORT,