Add precommit hooks & tox env to enforce code structure, add azure pipelines

Instead of leveraging hound & travis, add an option for azure pipelines,
which may replace the former in the future.

This also streamlines the contributing guidelines by:
* Adding pre-commit hooks to run isort, black, flake8, mypy
* Adding lint environment to allow checks to be run `tox -e lint`

This also contains a major cleanup to the SmartStrip handling which was due.
After seeing #184 I thought I should push this in as it is for comments before the codebase diverges too much.
This commit is contained in:
Teemu Rytilahti
2019-11-11 22:14:34 +01:00
parent 59424d2738
commit 8a131e1eeb
17 changed files with 354 additions and 549 deletions

View File

@@ -1,10 +1,13 @@
import pytest
import glob
import json
import os
from .newfakes import FakeTransportProtocol
from os.path import basename
from pyHS100 import SmartPlug, SmartBulb, SmartStrip, Discover
import pytest
from pyHS100 import Discover, SmartBulb, SmartPlug, SmartStrip
from .newfakes import FakeTransportProtocol
SUPPORTED_DEVICES = glob.glob(
os.path.dirname(os.path.abspath(__file__)) + "/fixtures/*.json"

View File

@@ -1,8 +1,10 @@
from ..protocol import TPLinkSmartHomeProtocol
from .. import SmartDeviceException
import logging
import re
from voluptuous import Schema, Range, All, Any, Coerce, Invalid, Optional, REMOVE_EXTRA
from voluptuous import REMOVE_EXTRA, All, Any, Coerce, Invalid, Optional, Range, Schema
from .. import SmartDeviceException
from ..protocol import TPLinkSmartHomeProtocol
_LOGGER = logging.getLogger(__name__)

View File

@@ -1,31 +1,31 @@
import datetime
from unittest.mock import patch
import pytest
from pyHS100 import DeviceType, SmartStripException, SmartDeviceException
from .newfakes import (
BULB_SCHEMA,
PLUG_SCHEMA,
FakeTransportProtocol,
CURRENT_CONSUMPTION_SCHEMA,
TZ_SCHEMA,
)
from pyHS100 import DeviceType, SmartDeviceException
from .conftest import (
turn_on,
handle_turn_on,
plug,
strip,
bulb,
color_bulb,
non_color_bulb,
dimmable,
handle_turn_on,
has_emeter,
no_emeter,
dimmable,
non_color_bulb,
non_dimmable,
variable_temp,
non_variable_temp,
plug,
strip,
turn_on,
variable_temp,
)
from .newfakes import (
BULB_SCHEMA,
CURRENT_CONSUMPTION_SCHEMA,
PLUG_SCHEMA,
TZ_SCHEMA,
FakeTransportProtocol,
)
@@ -436,67 +436,44 @@ def test_deprecated_hsv(dev, turn_on):
dev.hsv = (1, 1, 1)
@strip
def test_children_is_on(dev):
is_on = dev.get_is_on()
for i in range(dev.num_children):
assert is_on[i] == dev.get_is_on(index=i)
@strip
@turn_on
def test_children_change_state(dev, turn_on):
handle_turn_on(dev, turn_on)
for i in range(dev.num_children):
orig_state = dev.get_is_on(index=i)
for plug in dev.plugs:
orig_state = plug.is_on
if orig_state:
dev.turn_off(index=i)
assert not dev.get_is_on(index=i)
assert dev.get_is_off(index=i)
plug.turn_off()
assert not plug.is_on
assert plug.is_off
dev.turn_on(index=i)
assert dev.get_is_on(index=i)
assert not dev.get_is_off(index=i)
plug.turn_on()
assert plug.is_on
assert not plug.is_off
else:
dev.turn_on(index=i)
assert dev.get_is_on(index=i)
assert not dev.get_is_off(index=i)
dev.turn_off(index=i)
assert not dev.get_is_on(index=i)
assert dev.get_is_off(index=i)
@strip
def test_children_bounds(dev):
out_of_bounds = dev.num_children + 100
with pytest.raises(SmartDeviceException):
dev.turn_off(index=out_of_bounds)
with pytest.raises(SmartDeviceException):
dev.turn_on(index=out_of_bounds)
with pytest.raises(SmartDeviceException):
dev.get_is_on(index=out_of_bounds)
with pytest.raises(SmartDeviceException):
dev.get_alias(index=out_of_bounds)
with pytest.raises(SmartDeviceException):
dev.get_on_since(index=out_of_bounds)
plug.turn_on()
assert plug.is_on
assert not plug.is_off
plug.turn_off()
assert not plug.is_on
assert plug.is_off
@strip
def test_children_alias(dev):
original = dev.get_alias()
test_alias = "TEST1234"
for idx in range(dev.num_children):
dev.set_alias(alias=test_alias, index=idx)
assert dev.get_alias(index=idx) == test_alias
dev.set_alias(alias=original[idx], index=idx)
assert dev.get_alias(index=idx) == original[idx]
for plug in dev.plugs:
original = plug.get_alias()
plug.set_alias(alias=test_alias)
assert plug.get_alias() == test_alias
plug.set_alias(alias=original)
assert plug.get_alias() == original
@strip
def test_children_on_since(dev):
for idx in range(dev.num_children):
assert dev.get_on_since(index=idx)
for plug in dev.plugs:
assert plug.get_on_since()
@pytest.mark.skip("this test will wear out your relays")
@@ -548,78 +525,61 @@ def test_all_binary_states(dev):
def test_children_get_emeter_realtime(dev):
assert dev.has_emeter
# test with index
for plug_index in range(dev.num_children):
emeter = dev.get_emeter_realtime(index=plug_index)
for plug in dev.plugs:
emeter = plug.get_emeter_realtime()
CURRENT_CONSUMPTION_SCHEMA(emeter)
# test without index
for index, emeter in dev.get_emeter_realtime().items():
CURRENT_CONSUMPTION_SCHEMA(emeter)
# TODO test that sum matches the sum of individiaul plugs.
# out of bounds
with pytest.raises(SmartStripException):
dev.get_emeter_realtime(index=dev.num_children + 100)
# for index, emeter in dev.get_emeter_realtime().items():
# CURRENT_CONSUMPTION_SCHEMA(emeter)
@strip
def test_children_get_emeter_daily(dev):
assert dev.has_emeter
# test with index
for plug_index in range(dev.num_children):
emeter = dev.get_emeter_daily(year=1900, month=1, index=plug_index)
# test individual emeters
for plug in dev.plugs:
emeter = plug.get_emeter_daily(year=1900, month=1)
assert emeter == {}
emeter = dev.get_emeter_daily(index=plug_index)
emeter = plug.get_emeter_daily()
assert len(emeter) > 0
k, v = emeter.popitem()
assert isinstance(k, int)
assert isinstance(v, float)
# test without index
# test sum of emeters
all_emeter = dev.get_emeter_daily(year=1900, month=1)
for plug_index, emeter in all_emeter.items():
assert emeter == {}
emeter = dev.get_emeter_daily(index=plug_index)
k, v = emeter.popitem()
assert isinstance(k, int)
assert isinstance(v, float)
# out of bounds
with pytest.raises(SmartStripException):
dev.get_emeter_daily(year=1900, month=1, index=dev.num_children + 100)
k, v = all_emeter.popitem()
assert isinstance(k, int)
assert isinstance(v, float)
@strip
def test_children_get_emeter_monthly(dev):
assert dev.has_emeter
# test with index
for plug_index in range(dev.num_children):
emeter = dev.get_emeter_monthly(year=1900, index=plug_index)
# test individual emeters
for plug in dev.plugs:
emeter = plug.get_emeter_monthly(year=1900)
assert emeter == {}
emeter = dev.get_emeter_monthly()
emeter = plug.get_emeter_monthly()
assert len(emeter) > 0
k, v = emeter.popitem()
assert isinstance(k, int)
assert isinstance(v, float)
# test without index
# test sum of emeters
all_emeter = dev.get_emeter_monthly(year=1900)
for index, emeter in all_emeter.items():
assert emeter == {}
assert len(emeter) > 0
k, v = emeter.popitem()
assert isinstance(k, int)
assert isinstance(v, float)
# out of bounds
with pytest.raises(SmartStripException):
dev.get_emeter_monthly(year=1900, index=dev.num_children + 100)
k, v = all_emeter.popitem()
assert isinstance(k, int)
assert isinstance(v, float)
def test_cache(dev):
@@ -658,6 +618,6 @@ def test_cache_invalidates(dev):
def test_representation(dev):
import re
pattern = re.compile("<.* model .* at .* (.*), is_on: .* - dev specific: .*>")
assert pattern.match(str(dev))

View File

@@ -1,6 +1,7 @@
from unittest import TestCase
from ..protocol import TPLinkSmartHomeProtocol
import json
from unittest import TestCase
from ..protocol import TPLinkSmartHomeProtocol
class TestTPLinkSmartHomeProtocol(TestCase):