From 3ef5086ffbf02cfe6d90db909234f855d97f65e0 Mon Sep 17 00:00:00 2001 From: Teemu R Date: Wed, 18 Dec 2019 09:11:18 +0100 Subject: [PATCH] mass rename to (python-)kasa (#1) --- .pre-commit-config.yaml | 1 - Dockerfile | 4 +-- README.md | 28 +++++++++---------- azure-pipelines.yml | 2 +- {pyHS100 => kasa}/__init__.py | 17 ++++------- {pyHS100 => kasa}/cli.py | 12 ++++---- {pyHS100 => kasa}/discover.py | 10 +++---- {pyHS100 => kasa}/protocol.py | 0 {pyHS100 => kasa}/smartbulb.py | 4 +-- {pyHS100 => kasa}/smartdevice.py | 2 +- {pyHS100 => kasa}/smartplug.py | 4 +-- {pyHS100 => kasa}/smartstrip.py | 6 ++-- {pyHS100 => kasa}/tests/__init__.py | 0 {pyHS100 => kasa}/tests/conftest.py | 2 +- .../tests/fixtures/HS100(US)_1.0.json | 0 .../tests/fixtures/HS105(US)_1.0.json | 0 .../tests/fixtures/HS110(EU)_1.0_real.json | 0 .../tests/fixtures/HS110(EU)_2.0.json | 0 .../tests/fixtures/HS110(US)_1.0.json | 0 .../tests/fixtures/HS200(US)_1.0.json | 0 .../tests/fixtures/HS220(US)_1.0.json | 0 .../tests/fixtures/HS220(US)_1.0_real.json | 0 .../tests/fixtures/HS300(US)_1.0.json | 0 .../tests/fixtures/KL120(US)_1.0_real.json | 0 .../tests/fixtures/LB100(US)_1.0.json | 0 .../tests/fixtures/LB120(US)_1.0.json | 0 .../tests/fixtures/LB130(US)_1.0.json | 0 {pyHS100 => kasa}/tests/newfakes.py | 0 {pyHS100 => kasa}/tests/test_fixtures.py | 2 +- {pyHS100 => kasa}/tests/test_protocol.py | 0 {pyHS100 => kasa}/version.py | 0 setup.py | 18 ++++++------ tox.ini | 20 ++++++------- 33 files changed, 63 insertions(+), 69 deletions(-) rename {pyHS100 => kasa}/__init__.py (65%) rename {pyHS100 => kasa}/cli.py (98%) rename {pyHS100 => kasa}/discover.py (95%) rename {pyHS100 => kasa}/protocol.py (100%) rename {pyHS100 => kasa}/smartbulb.py (99%) rename {pyHS100 => kasa}/smartdevice.py (99%) rename {pyHS100 => kasa}/smartplug.py (98%) rename {pyHS100 => kasa}/smartstrip.py (97%) rename {pyHS100 => kasa}/tests/__init__.py (100%) rename {pyHS100 => kasa}/tests/conftest.py (98%) rename {pyHS100 => kasa}/tests/fixtures/HS100(US)_1.0.json (100%) rename {pyHS100 => kasa}/tests/fixtures/HS105(US)_1.0.json (100%) rename {pyHS100 => kasa}/tests/fixtures/HS110(EU)_1.0_real.json (100%) rename {pyHS100 => kasa}/tests/fixtures/HS110(EU)_2.0.json (100%) rename {pyHS100 => kasa}/tests/fixtures/HS110(US)_1.0.json (100%) rename {pyHS100 => kasa}/tests/fixtures/HS200(US)_1.0.json (100%) rename {pyHS100 => kasa}/tests/fixtures/HS220(US)_1.0.json (100%) rename {pyHS100 => kasa}/tests/fixtures/HS220(US)_1.0_real.json (100%) rename {pyHS100 => kasa}/tests/fixtures/HS300(US)_1.0.json (100%) rename {pyHS100 => kasa}/tests/fixtures/KL120(US)_1.0_real.json (100%) rename {pyHS100 => kasa}/tests/fixtures/LB100(US)_1.0.json (100%) rename {pyHS100 => kasa}/tests/fixtures/LB120(US)_1.0.json (100%) rename {pyHS100 => kasa}/tests/fixtures/LB130(US)_1.0.json (100%) rename {pyHS100 => kasa}/tests/newfakes.py (100%) rename {pyHS100 => kasa}/tests/test_fixtures.py (99%) rename {pyHS100 => kasa}/tests/test_protocol.py (100%) rename {pyHS100 => kasa}/version.py (100%) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index bbdf8a9f..0606516f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -19,7 +19,6 @@ repos: rev: stable hooks: - id: black - language_version: python3.7 - repo: https://github.com/pre-commit/pre-commit-hooks rev: v2.3.0 diff --git a/Dockerfile b/Dockerfile index 38e680f5..f6b70e2b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -20,8 +20,8 @@ RUN apk update && \ ################################################### # Create somewhere to put the files # ################################################### -RUN mkdir -p /opt/pyHS100 -WORKDIR /opt/pyHS100 +RUN mkdir -p /opt/python-kasa +WORKDIR /opt/python-kasa ################################################### # Requirements file first to help cache # diff --git a/README.md b/README.md index d409d023..516e4670 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ -# pyHS100 +# python-kasa -[![PyPI version](https://badge.fury.io/py/pyHS100.svg)](https://badge.fury.io/py/pyHS100) +[![PyPI version](https://badge.fury.io/py/python-kasa.svg)](https://badge.fury.io/py/python-kasa) [![Build Status](https://dev.azure.com/python-tplink-kasa/python-kasa/_apis/build/status/python-tplink-kasa.python-kasa?branchName=master)](https://dev.azure.com/python-tplink-kasa/python-kasa/_build/latest?definitionId=1&branchName=master) -[![Coverage Status](https://coveralls.io/repos/github/GadgetReactor/pyHS100/badge.svg?branch=master)](https://coveralls.io/github/GadgetReactor/pyHS100?branch=master) +[![Coverage Status](https://coveralls.io/repos/github/python-kasa/python-kasa/badge.svg?branch=master)](https://coveralls.io/github/python-kasa/python-kasa?branch=master) [![Reviewed by Hound](https://img.shields.io/badge/Reviewed_by-Hound-8E64B0.svg)](https://houndci.com) Python Library to control TPLink smart plugs/switches and smart bulbs. @@ -32,25 +32,25 @@ Python Library to control TPLink smart plugs/switches and smart bulbs. # Usage -The package is shipped with a console tool named pyhs100, please refer to ```pyhs100 --help``` for detailed usage. -The device to which the commands are sent is chosen by `PYHS100_HOST` environment variable or passing `--host
` as an option. +The package is shipped with a console tool named kasa, please refer to ```kasa --help``` for detailed usage. +The device to which the commands are sent is chosen by `KASA_HOST` environment variable or passing `--host
` as an option. To see what is being sent to and received from the device, specify option `--debug`. To avoid discovering the devices when executing commands its type can be passed by specifying either `--plug` or `--bulb`, if no type is given its type will be discovered automatically with a small delay. Some commands (such as reading energy meter values and setting color of bulbs) additional parameters are required, -which you can find by adding `--help` after the command, e.g. `pyhs100 emeter --help` or `pyhs100 hsv --help`. +which you can find by adding `--help` after the command, e.g. `kasa emeter --help` or `kasa hsv --help`. If no command is given, the `state` command will be executed to query the device state. ## Discovering devices -The devices can be discovered either by using `pyhs100 discover` or by calling `pyhs100` without any parameters. +The devices can be discovered either by using `kasa discover` or by calling `kasa` without any parameters. In both cases supported devices are discovered from the same broadcast domain, and their current state will be queried and printed out. ``` -$ pyhs100 +$ kasa No --bulb nor --plug given, discovering.. Discovering devices for 3 seconds == My Smart Plug - HS110(EU) == @@ -83,7 +83,7 @@ Possible options include `--year` and `--month` for retrieving historical state, and reseting the counters is done with `--erase`. ``` -$ pyhs100 emeter +$ kasa emeter == Emeter == Current state: {'total': 133.105, 'power': 108.223577, 'current': 0.54463, 'voltage': 225.296283} ``` @@ -97,9 +97,9 @@ At the moment only switching the state of the LED is implemented. `led` command can be used to control whether the LED light on front of the plug is on or off. ``` -$ pyhs100 --plug led +$ kasa --plug led LED state: False -$ pyhs100 --plug led 1 +$ kasa --plug led 1 Turning led to True ``` @@ -122,7 +122,7 @@ which returns a dictionary keyed with the IP address whose value hold a ready-to Example: ```python -from pyHS100 import Discover +from kasa import Discover for dev in Discover.discover().values(): print(dev) @@ -138,7 +138,7 @@ $ python3 example.py If you want to avoid unnecessary communication with the device please use `get_sysinfo` and handle parsing of information by yourself.* ```python -from pyHS100 import SmartPlug, SmartBulb +from kasa import SmartPlug, SmartBulb from pprint import pformat as pf plug = SmartPlug("192.168.XXX.XXX") @@ -231,5 +231,5 @@ The following assumes you have a working installation of Docker. Set up the environment and run the tests on demand. ```shell -docker build . -t pyhs100 && docker run -v $(PWD)/pyHS100/tests:/opt/pyHS100/pyHS100/tests pyhs100 pytest +docker build . -t kasa && docker run -v $(PWD)/kasa/tests:/opt/python-kasa/kasa/tests kasa pytest ``` diff --git a/azure-pipelines.yml b/azure-pipelines.yml index e0630373..b9e3636c 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -71,5 +71,5 @@ steps: displayName: 'Order of imports (isort)' - script: | - pytest --cov pyHS100 --cov-report html + pytest --cov kasa --cov-report html displayName: 'Tests' diff --git a/pyHS100/__init__.py b/kasa/__init__.py similarity index 65% rename from pyHS100/__init__.py rename to kasa/__init__.py index a64b360d..460d522a 100755 --- a/pyHS100/__init__.py +++ b/kasa/__init__.py @@ -11,17 +11,12 @@ For device type specific actions `SmartBulb`, `SmartPlug`, or `SmartStrip` Module-specific errors are raised as `SmartDeviceException` and are expected to be handled by the user of the library. """ -from pyHS100.discover import Discover -from pyHS100.protocol import TPLinkSmartHomeProtocol -from pyHS100.smartbulb import SmartBulb -from pyHS100.smartdevice import ( - DeviceType, - EmeterStatus, - SmartDevice, - SmartDeviceException, -) -from pyHS100.smartplug import SmartPlug -from pyHS100.smartstrip import SmartStrip +from kasa.discover import Discover +from kasa.protocol import TPLinkSmartHomeProtocol +from kasa.smartbulb import SmartBulb +from kasa.smartdevice import DeviceType, EmeterStatus, SmartDevice, SmartDeviceException +from kasa.smartplug import SmartPlug +from kasa.smartstrip import SmartStrip __all__ = [ "Discover", diff --git a/pyHS100/cli.py b/kasa/cli.py similarity index 98% rename from pyHS100/cli.py rename to kasa/cli.py index fe395ffd..7f09c52a 100755 --- a/pyHS100/cli.py +++ b/kasa/cli.py @@ -1,4 +1,4 @@ -"""pyHS100 cli tool.""" +"""python-kasa cli tool.""" import asyncio import logging import sys @@ -6,9 +6,9 @@ from pprint import pformat as pf import click -from pyHS100 import Discover, SmartBulb, SmartDevice, SmartStrip +from kasa import Discover, SmartBulb, SmartDevice, SmartStrip -from pyHS100 import SmartPlug # noqa: E402; noqa: E402 +from kasa import SmartPlug # noqa: E402; noqa: E402 if sys.version_info < (3, 6): print("To use this script you need Python 3.6 or newer! got %s" % sys.version_info) @@ -21,7 +21,7 @@ pass_dev = click.make_pass_decorator(SmartDevice) @click.group(invoke_without_command=True) @click.option( "--ip", - envvar="PYHS100_IP", + envvar="KASA_IP", required=False, help="The IP address of the device to connect to. This option " "is deprecated and will be removed in the future; use --host " @@ -29,13 +29,13 @@ pass_dev = click.make_pass_decorator(SmartDevice) ) @click.option( "--host", - envvar="PYHS100_HOST", + envvar="KASA_HOST", required=False, help="The host name or IP address of the device to connect to.", ) @click.option( "--alias", - envvar="PYHS100_NAME", + envvar="KASA_NAME", required=False, help="The device name, or alias, of the device to connect to.", ) diff --git a/pyHS100/discover.py b/kasa/discover.py similarity index 95% rename from pyHS100/discover.py rename to kasa/discover.py index 867f7e60..562adfff 100755 --- a/pyHS100/discover.py +++ b/kasa/discover.py @@ -4,11 +4,11 @@ import logging import socket from typing import Dict, Optional, Type -from pyHS100.protocol import TPLinkSmartHomeProtocol -from pyHS100.smartbulb import SmartBulb -from pyHS100.smartdevice import SmartDevice, SmartDeviceException -from pyHS100.smartplug import SmartPlug -from pyHS100.smartstrip import SmartStrip +from kasa.protocol import TPLinkSmartHomeProtocol +from kasa.smartbulb import SmartBulb +from kasa.smartdevice import SmartDevice, SmartDeviceException +from kasa.smartplug import SmartPlug +from kasa.smartstrip import SmartStrip _LOGGER = logging.getLogger(__name__) diff --git a/pyHS100/protocol.py b/kasa/protocol.py similarity index 100% rename from pyHS100/protocol.py rename to kasa/protocol.py diff --git a/pyHS100/smartbulb.py b/kasa/smartbulb.py similarity index 99% rename from pyHS100/smartbulb.py rename to kasa/smartbulb.py index 8e8cb9af..469de772 100644 --- a/pyHS100/smartbulb.py +++ b/kasa/smartbulb.py @@ -2,8 +2,8 @@ import re from typing import Any, Dict, Optional, Tuple -from pyHS100.protocol import TPLinkSmartHomeProtocol -from pyHS100.smartdevice import ( +from kasa.protocol import TPLinkSmartHomeProtocol +from kasa.smartdevice import ( DeviceType, SmartDevice, SmartDeviceException, diff --git a/pyHS100/smartdevice.py b/kasa/smartdevice.py similarity index 99% rename from pyHS100/smartdevice.py rename to kasa/smartdevice.py index 45348590..d8f0fa47 100755 --- a/pyHS100/smartdevice.py +++ b/kasa/smartdevice.py @@ -20,7 +20,7 @@ from datetime import datetime, timedelta from enum import Enum from typing import Any, Dict, Optional -from pyHS100.protocol import TPLinkSmartHomeProtocol +from kasa.protocol import TPLinkSmartHomeProtocol _LOGGER = logging.getLogger(__name__) diff --git a/pyHS100/smartplug.py b/kasa/smartplug.py similarity index 98% rename from pyHS100/smartplug.py rename to kasa/smartplug.py index 2a50f47c..a9066a3f 100644 --- a/pyHS100/smartplug.py +++ b/kasa/smartplug.py @@ -3,8 +3,8 @@ import datetime import logging from typing import Any, Dict -from pyHS100.protocol import TPLinkSmartHomeProtocol -from pyHS100.smartdevice import ( +from kasa.protocol import TPLinkSmartHomeProtocol +from kasa.smartdevice import ( DeviceType, SmartDevice, SmartDeviceException, diff --git a/pyHS100/smartstrip.py b/kasa/smartstrip.py similarity index 97% rename from pyHS100/smartstrip.py rename to kasa/smartstrip.py index 2571c542..aedc9962 100755 --- a/pyHS100/smartstrip.py +++ b/kasa/smartstrip.py @@ -7,9 +7,9 @@ import logging from collections import defaultdict from typing import Any, DefaultDict, Dict, List -from pyHS100.protocol import TPLinkSmartHomeProtocol -from pyHS100.smartdevice import DeviceType, requires_update -from pyHS100.smartplug import SmartPlug +from kasa.protocol import TPLinkSmartHomeProtocol +from kasa.smartdevice import DeviceType, requires_update +from kasa.smartplug import SmartPlug _LOGGER = logging.getLogger(__name__) diff --git a/pyHS100/tests/__init__.py b/kasa/tests/__init__.py similarity index 100% rename from pyHS100/tests/__init__.py rename to kasa/tests/__init__.py diff --git a/pyHS100/tests/conftest.py b/kasa/tests/conftest.py similarity index 98% rename from pyHS100/tests/conftest.py rename to kasa/tests/conftest.py index c7efdb1d..bf0f139a 100644 --- a/pyHS100/tests/conftest.py +++ b/kasa/tests/conftest.py @@ -6,7 +6,7 @@ from os.path import basename import pytest -from pyHS100 import Discover, SmartBulb, SmartPlug, SmartStrip +from kasa import Discover, SmartBulb, SmartPlug, SmartStrip from .newfakes import FakeTransportProtocol diff --git a/pyHS100/tests/fixtures/HS100(US)_1.0.json b/kasa/tests/fixtures/HS100(US)_1.0.json similarity index 100% rename from pyHS100/tests/fixtures/HS100(US)_1.0.json rename to kasa/tests/fixtures/HS100(US)_1.0.json diff --git a/pyHS100/tests/fixtures/HS105(US)_1.0.json b/kasa/tests/fixtures/HS105(US)_1.0.json similarity index 100% rename from pyHS100/tests/fixtures/HS105(US)_1.0.json rename to kasa/tests/fixtures/HS105(US)_1.0.json diff --git a/pyHS100/tests/fixtures/HS110(EU)_1.0_real.json b/kasa/tests/fixtures/HS110(EU)_1.0_real.json similarity index 100% rename from pyHS100/tests/fixtures/HS110(EU)_1.0_real.json rename to kasa/tests/fixtures/HS110(EU)_1.0_real.json diff --git a/pyHS100/tests/fixtures/HS110(EU)_2.0.json b/kasa/tests/fixtures/HS110(EU)_2.0.json similarity index 100% rename from pyHS100/tests/fixtures/HS110(EU)_2.0.json rename to kasa/tests/fixtures/HS110(EU)_2.0.json diff --git a/pyHS100/tests/fixtures/HS110(US)_1.0.json b/kasa/tests/fixtures/HS110(US)_1.0.json similarity index 100% rename from pyHS100/tests/fixtures/HS110(US)_1.0.json rename to kasa/tests/fixtures/HS110(US)_1.0.json diff --git a/pyHS100/tests/fixtures/HS200(US)_1.0.json b/kasa/tests/fixtures/HS200(US)_1.0.json similarity index 100% rename from pyHS100/tests/fixtures/HS200(US)_1.0.json rename to kasa/tests/fixtures/HS200(US)_1.0.json diff --git a/pyHS100/tests/fixtures/HS220(US)_1.0.json b/kasa/tests/fixtures/HS220(US)_1.0.json similarity index 100% rename from pyHS100/tests/fixtures/HS220(US)_1.0.json rename to kasa/tests/fixtures/HS220(US)_1.0.json diff --git a/pyHS100/tests/fixtures/HS220(US)_1.0_real.json b/kasa/tests/fixtures/HS220(US)_1.0_real.json similarity index 100% rename from pyHS100/tests/fixtures/HS220(US)_1.0_real.json rename to kasa/tests/fixtures/HS220(US)_1.0_real.json diff --git a/pyHS100/tests/fixtures/HS300(US)_1.0.json b/kasa/tests/fixtures/HS300(US)_1.0.json similarity index 100% rename from pyHS100/tests/fixtures/HS300(US)_1.0.json rename to kasa/tests/fixtures/HS300(US)_1.0.json diff --git a/pyHS100/tests/fixtures/KL120(US)_1.0_real.json b/kasa/tests/fixtures/KL120(US)_1.0_real.json similarity index 100% rename from pyHS100/tests/fixtures/KL120(US)_1.0_real.json rename to kasa/tests/fixtures/KL120(US)_1.0_real.json diff --git a/pyHS100/tests/fixtures/LB100(US)_1.0.json b/kasa/tests/fixtures/LB100(US)_1.0.json similarity index 100% rename from pyHS100/tests/fixtures/LB100(US)_1.0.json rename to kasa/tests/fixtures/LB100(US)_1.0.json diff --git a/pyHS100/tests/fixtures/LB120(US)_1.0.json b/kasa/tests/fixtures/LB120(US)_1.0.json similarity index 100% rename from pyHS100/tests/fixtures/LB120(US)_1.0.json rename to kasa/tests/fixtures/LB120(US)_1.0.json diff --git a/pyHS100/tests/fixtures/LB130(US)_1.0.json b/kasa/tests/fixtures/LB130(US)_1.0.json similarity index 100% rename from pyHS100/tests/fixtures/LB130(US)_1.0.json rename to kasa/tests/fixtures/LB130(US)_1.0.json diff --git a/pyHS100/tests/newfakes.py b/kasa/tests/newfakes.py similarity index 100% rename from pyHS100/tests/newfakes.py rename to kasa/tests/newfakes.py diff --git a/pyHS100/tests/test_fixtures.py b/kasa/tests/test_fixtures.py similarity index 99% rename from pyHS100/tests/test_fixtures.py rename to kasa/tests/test_fixtures.py index ce7a03e5..a3a1a67e 100644 --- a/pyHS100/tests/test_fixtures.py +++ b/kasa/tests/test_fixtures.py @@ -4,7 +4,7 @@ from unittest.mock import patch import pytest -from pyHS100 import DeviceType, SmartDeviceException, SmartStrip +from kasa import DeviceType, SmartDeviceException, SmartStrip from .conftest import ( bulb, diff --git a/pyHS100/tests/test_protocol.py b/kasa/tests/test_protocol.py similarity index 100% rename from pyHS100/tests/test_protocol.py rename to kasa/tests/test_protocol.py diff --git a/pyHS100/version.py b/kasa/version.py similarity index 100% rename from pyHS100/version.py rename to kasa/version.py diff --git a/setup.py b/setup.py index 0f4fb94e..9fd45106 100644 --- a/setup.py +++ b/setup.py @@ -1,19 +1,19 @@ from setuptools import setup -with open("pyHS100/version.py") as f: +with open("kasa/version.py") as f: exec(f.read()) setup( - name="pyHS100", + name="python-kasa", version=__version__, # type: ignore # noqa: F821 - description="Python interface for TPLink KASA-enabled smart home devices", - url="https://github.com/GadgetReactor/pyHS100", - author="Sean Seah (GadgetReactor)", - author_email="sean@gadgetreactor.com", + description="Python API for TP-Link Kasa Smarthome products", + url="https://github.com/python-kasa/python-kasa", + author="", + author_email="", license="GPLv3", - packages=["pyHS100"], - install_requires=["click", "deprecation"], + packages=["kasa"], + install_requires=["click"], python_requires=">=3.6", - entry_points={"console_scripts": ["pyhs100=pyHS100.cli:cli"]}, + entry_points={"console_scripts": ["kasa=kasa.cli:cli"]}, zip_safe=False, ) diff --git a/tox.ini b/tox.ini index 2fe21c69..6d2e65f4 100644 --- a/tox.ini +++ b/tox.ini @@ -17,24 +17,24 @@ deps= deprecation flake8 commands= - py.test --cov --cov-config=tox.ini pyHS100 + py.test --cov --cov-config=tox.ini kasa [testenv:flake8] deps= flake8 flake8-docstrings -commands=flake8 pyHS100 +commands=flake8 kasa [testenv:typing] skip_install=true deps=mypy -commands=mypy --ignore-missing-imports pyHS100 +commands=mypy --ignore-missing-imports kasa [flake8] -exclude = .git,.tox,__pycache__,pyHS100/tests/newfakes.py,pyHS100/tests/test_fixtures.py +exclude = .git,.tox,__pycache__,kasa/tests/newfakes.py,kasa/tests/test_fixtures.py max-line-length = 88 per-file-ignores = - pyHS100/tests/*.py:D100,D101,D102,D103,D104 + kasa/tests/*.py:D100,D101,D102,D103,D104 setup.py:D100 ignore = D105, D107, E203, E501, W503 #ignore = E203, E266, E501, W503, F403, F401 @@ -47,11 +47,11 @@ skip_install = true commands = pre-commit run --all-files [coverage:run] -source = pyHS100 +source = kasa branch = True omit = - pyHS100/cli.py - pyHS100/tests/* + kasa/cli.py + kasa/tests/* [coverage:report] exclude_lines = @@ -65,5 +65,5 @@ include_trailing_comma=True force_grid_wrap=0 use_parentheses=True line_length=88 -known_first_party=pyHS100 -known_third_party=click,deprecation,pytest,setuptools,voluptuous +known_first_party=kasa +known_third_party=click,pytest,setuptools,voluptuous