Fix pydocstyle issues and enable in tox

This commit is contained in:
Pierre Ståhl
2020-09-22 12:30:16 +02:00
parent ec7652b193
commit a18c69f8eb
10 changed files with 59 additions and 39 deletions

View File

@@ -140,7 +140,7 @@ def get_entity_config(config_entry, dps_id):
class TuyaDevice: class TuyaDevice:
"""Cache wrapper for pytuya.TuyaInterface""" """Cache wrapper for pytuya.TuyaInterface."""
def __init__(self, interface, friendly_name): def __init__(self, interface, friendly_name):
"""Initialize the cache.""" """Initialize the cache."""
@@ -226,6 +226,7 @@ class LocalTuyaEntity(Entity):
@property @property
def device_info(self): def device_info(self):
"""Return device information for the device registry."""
return { return {
"identifiers": { "identifiers": {
# Serial numbers are unique identifiers within a specific domain # Serial numbers are unique identifiers within a specific domain

View File

@@ -103,7 +103,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
class LocaltuyaCover(LocalTuyaEntity, CoverEntity): class LocaltuyaCover(LocalTuyaEntity, CoverEntity):
"""Tuya cover devices.""" """Tuya cover device."""
def __init__( def __init__(
self, self,
@@ -112,6 +112,7 @@ class LocaltuyaCover(LocalTuyaEntity, CoverEntity):
switchid, switchid,
**kwargs, **kwargs,
): ):
"""Initialize a new LocaltuyaCover."""
#_LOGGER.info("running def __init__ of LocaltuyaCover(CoverEntity) with self=%s device=%s name=%s friendly_name=%s icon=%s switchid=%s open_cmd=%s close_cmd=%s stop_cmd=%s", self, device, name, friendly_name, icon, switchid, open_cmd, close_cmd, stop_cmd) #_LOGGER.info("running def __init__ of LocaltuyaCover(CoverEntity) with self=%s device=%s name=%s friendly_name=%s icon=%s switchid=%s open_cmd=%s close_cmd=%s stop_cmd=%s", self, device, name, friendly_name, icon, switchid, open_cmd, close_cmd, stop_cmd)
super().__init__(device, config_entry, switchid, **kwargs) super().__init__(device, config_entry, switchid, **kwargs)
self._state = None self._state = None
@@ -137,6 +138,7 @@ class LocaltuyaCover(LocalTuyaEntity, CoverEntity):
@property @property
def current_cover_position(self): def current_cover_position(self):
"""Return current cover position in percent."""
# self.update() # self.update()
# state = self._state # state = self._state
# _LOGGER.info("curr_pos() : %i", self._position) # _LOGGER.info("curr_pos() : %i", self._position)
@@ -145,6 +147,7 @@ class LocaltuyaCover(LocalTuyaEntity, CoverEntity):
@property @property
def is_opening(self): def is_opening(self):
"""Return if cover is opening."""
# self.update() # self.update()
state = self._state state = self._state
# print('is_opening() : state [{}]'.format(state)) # print('is_opening() : state [{}]'.format(state))
@@ -154,6 +157,7 @@ class LocaltuyaCover(LocalTuyaEntity, CoverEntity):
@property @property
def is_closing(self): def is_closing(self):
"""Return if cover is closing."""
# self.update() # self.update()
state = self._state state = self._state
# print('is_closing() : state [{}]'.format(state)) # print('is_closing() : state [{}]'.format(state))
@@ -177,7 +181,6 @@ class LocaltuyaCover(LocalTuyaEntity, CoverEntity):
def set_cover_position(self, **kwargs): def set_cover_position(self, **kwargs):
# _LOGGER.info("running set_cover_position from cover") # _LOGGER.info("running set_cover_position from cover")
"""Move the cover to a specific position.""" """Move the cover to a specific position."""
newpos = float(kwargs["position"]) newpos = float(kwargs["position"])
# _LOGGER.info("Set new pos: %f", newpos) # _LOGGER.info("Set new pos: %f", newpos)

View File

@@ -72,6 +72,7 @@ async def discover(timeout, loop):
def main(): def main():
"""Run discovery and print result."""
loop = asyncio.get_event_loop() loop = asyncio.get_event_loop()
res = loop.run_until_complete(discover(5, loop)) res = loop.run_until_complete(discover(5, loop))
print(res) print(res)

View File

@@ -1,7 +1,8 @@
# PyTuya Module # PyTuya Module
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
Python module to interface with Tuya WiFi smart devices Python module to interface with Tuya WiFi smart devices.
Mostly derived from Shenzhen Xenon ESP8266MOD WiFi smart devices Mostly derived from Shenzhen Xenon ESP8266MOD WiFi smart devices
E.g. https://wikidevi.com/wiki/Xenon_SM-PW701U E.g. https://wikidevi.com/wiki/Xenon_SM-PW701U
@@ -80,12 +81,16 @@ PROTOCOL_VERSION_BYTES_33 = b"3.3"
IS_PY2 = sys.version_info[0] == 2 IS_PY2 = sys.version_info[0] == 2
class AESCipher(object): class AESCipher:
"""Cipher module for Tuya communication."""
def __init__(self, key): def __init__(self, key):
"""Initialize a new AESCipher."""
self.bs = 16 self.bs = 16
self.key = key self.key = key
def encrypt(self, raw, use_base64=True): def encrypt(self, raw, use_base64=True):
"""Encrypt data to be sent to device."""
if Crypto: if Crypto:
raw = self._pad(raw) raw = self._pad(raw)
cipher = AES.new(self.key, mode=AES.MODE_ECB) cipher = AES.new(self.key, mode=AES.MODE_ECB)
@@ -104,6 +109,7 @@ class AESCipher(object):
return crypted_text return crypted_text
def decrypt(self, enc, use_base64=True): def decrypt(self, enc, use_base64=True):
"""Decrypt data from device."""
if use_base64: if use_base64:
enc = base64.b64decode(enc) enc = base64.b64decode(enc)
# print('enc (%d) %r' % (len(enc), enc)) # print('enc (%d) %r' % (len(enc), enc))
@@ -134,6 +140,7 @@ class AESCipher(object):
def bin2hex(x, pretty=False): def bin2hex(x, pretty=False):
"""Convert binary data to hex string."""
if pretty: if pretty:
space = " " space = " "
else: else:
@@ -146,6 +153,7 @@ def bin2hex(x, pretty=False):
def hex2bin(x): def hex2bin(x):
"""Convert hex string to binary."""
if IS_PY2: if IS_PY2:
return x.decode("hex") return x.decode("hex")
else: else:
@@ -171,12 +179,14 @@ payload_dict = {
} }
class TuyaInterface(object): class TuyaInterface:
"""Represent a Tuya device."""
def __init__( def __init__(
self, dev_id, address, local_key, protocol_version, connection_timeout=10 self, dev_id, address, local_key, protocol_version, connection_timeout=10
): ):
""" """
Represents a Tuya device. Initialize a new TuyaInterface.
Args: Args:
dev_id (str): The device id. dev_id (str): The device id.
@@ -186,7 +196,6 @@ class TuyaInterface(object):
Attributes: Attributes:
port (int): The port to connect to. port (int): The port to connect to.
""" """
self.id = dev_id self.id = dev_id
self.address = address self.address = address
self.local_key = local_key.encode("latin1") self.local_key = local_key.encode("latin1")
@@ -198,6 +207,7 @@ class TuyaInterface(object):
self.port = 6668 # default - do not expect caller to pass in self.port = 6668 # default - do not expect caller to pass in
def __repr__(self): def __repr__(self):
"""Return internal string representation of object."""
return "%r" % ((self.id, self.address),) # FIXME can do better than this return "%r" % ((self.id, self.address),) # FIXME can do better than this
def _send_receive(self, payload): def _send_receive(self, payload):
@@ -239,6 +249,7 @@ class TuyaInterface(object):
return data return data
def detect_available_dps(self): def detect_available_dps(self):
"""Return which datapoints are supported by the device."""
# type_0d devices need a sort of bruteforce querying in order to detect the list of available dps # type_0d devices need a sort of bruteforce querying in order to detect the list of available dps
# experience shows that the dps available are usually in the ranges [1-25] and [100-110] # experience shows that the dps available are usually in the ranges [1-25] and [100-110]
# need to split the bruteforcing in different steps due to request payload limitation (max. length = 255) # need to split the bruteforcing in different steps due to request payload limitation (max. length = 255)
@@ -288,6 +299,7 @@ class TuyaInterface(object):
return detected_dps return detected_dps
def add_dps_to_request(self, dps_index): def add_dps_to_request(self, dps_index):
"""Add a datapoint (DP) to be included in requests."""
if isinstance(dps_index, int): if isinstance(dps_index, int):
self.dps_to_request[str(dps_index)] = None self.dps_to_request[str(dps_index)] = None
else: else:
@@ -393,6 +405,7 @@ class TuyaInterface(object):
return buffer return buffer
def status(self): def status(self):
"""Return device status."""
log.debug("status() entry (dev_type is %s)", self.dev_type) log.debug("status() entry (dev_type is %s)", self.dev_type)
# open device, send request, then close connection # open device, send request, then close connection
payload = self.generate_payload("status") payload = self.generate_payload("status")

View File

@@ -152,6 +152,7 @@ class LocaltuyaSwitch(LocalTuyaEntity, SwitchEntity):
@property @property
def device_state_attributes(self): def device_state_attributes(self):
"""Return device state attributes."""
attrs = {} attrs = {}
if self._config.get(CONF_CURRENT, "-1") != "-1": if self._config.get(CONF_CURRENT, "-1") != "-1":
attrs[ATTR_CURRENT] = self.dps(self._config[CONF_CURRENT]) attrs[ATTR_CURRENT] = self.dps(self._config[CONF_CURRENT])

View File

@@ -1,2 +1,3 @@
black==20.8b1 black==20.8b1
mypy==0.782 mypy==0.782
pydocstyle==5.1.1

View File

@@ -30,7 +30,7 @@ commands =
#codespell -q 4 -L {[tox]cs_exclude_words} --skip="*.pyc,*.pyi,*~" custom_components #codespell -q 4 -L {[tox]cs_exclude_words} --skip="*.pyc,*.pyi,*~" custom_components
#flake8 cu #flake8 cu
black --fast --check . black --fast --check .
#pydocstyle -v custom_components pydocstyle -v custom_components
[testenv:typing] [testenv:typing]
whitelist_externals = whitelist_externals =