mirror of
https://github.com/python-kasa/python-kasa.git
synced 2025-08-04 01:34:12 +00:00
Simplify API documentation by using doctests (#73)
* Add doctests to SmartBulb * Add SmartDevice doctests, cleanup README.md * add doctests for smartplug and smartstrip * add discover doctests * Fix bulb mock * add smartdimmer doctests * add sphinx-generated docs, cleanup readme a bit * remove sphinx-click as it does not work with asyncclick * in preparation for rtd hooking, move doc deps to be separate from dev deps * pytestmark needs to be applied separately for each and every file, this fixes the tests * use pathlib for resolving relative paths * Skip discovery doctest on python3.7 The code is just fine, but some reason the mocking behaves differently between 3.7 and 3.8. The latter seems to accept a discrete object for asyncio.run where the former expects a coroutine..
This commit is contained in:
20
docs/Makefile
Normal file
20
docs/Makefile
Normal file
@@ -0,0 +1,20 @@
|
||||
# Minimal makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line, and also
|
||||
# from the environment for the first two.
|
||||
SPHINXOPTS ?=
|
||||
SPHINXBUILD ?= sphinx-build
|
||||
SOURCEDIR = source
|
||||
BUILDDIR = build
|
||||
|
||||
# Put it first so that "make" without argument is like "make help".
|
||||
help:
|
||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
|
||||
.PHONY: help Makefile
|
||||
|
||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||
%: Makefile
|
||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
35
docs/make.bat
Normal file
35
docs/make.bat
Normal file
@@ -0,0 +1,35 @@
|
||||
@ECHO OFF
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
REM Command file for Sphinx documentation
|
||||
|
||||
if "%SPHINXBUILD%" == "" (
|
||||
set SPHINXBUILD=sphinx-build
|
||||
)
|
||||
set SOURCEDIR=source
|
||||
set BUILDDIR=build
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
||||
%SPHINXBUILD% >NUL 2>NUL
|
||||
if errorlevel 9009 (
|
||||
echo.
|
||||
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
||||
echo.installed, then set the SPHINXBUILD environment variable to point
|
||||
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
||||
echo.may add the Sphinx directory to PATH.
|
||||
echo.
|
||||
echo.If you don't have Sphinx installed, grab it from
|
||||
echo.http://sphinx-doc.org/
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||
goto end
|
||||
|
||||
:help
|
||||
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||
|
||||
:end
|
||||
popd
|
65
docs/source/_static/copybutton.js
Normal file
65
docs/source/_static/copybutton.js
Normal file
@@ -0,0 +1,65 @@
|
||||
// Copyright 2014 PSF. Licensed under the PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
|
||||
// File originates from the cpython source found in Doc/tools/sphinxext/static/copybutton.js
|
||||
|
||||
$(document).ready(function() {
|
||||
/* Add a [>>>] button on the top-right corner of code samples to hide
|
||||
* the >>> and ... prompts and the output and thus make the code
|
||||
* copyable. */
|
||||
var div = $('.highlight-python .highlight,' +
|
||||
'.highlight-default .highlight,' +
|
||||
'.highlight-python3 .highlight')
|
||||
var pre = div.find('pre');
|
||||
|
||||
// get the styles from the current theme
|
||||
pre.parent().parent().css('position', 'relative');
|
||||
var hide_text = 'Hide the prompts and output';
|
||||
var show_text = 'Show the prompts and output';
|
||||
var border_width = pre.css('border-top-width');
|
||||
var border_style = pre.css('border-top-style');
|
||||
var border_color = pre.css('border-top-color');
|
||||
var button_styles = {
|
||||
'cursor':'pointer', 'position': 'absolute', 'top': '0', 'right': '0',
|
||||
'border-color': border_color, 'border-style': border_style,
|
||||
'border-width': border_width, 'color': border_color, 'text-size': '75%',
|
||||
'font-family': 'monospace', 'padding-left': '0.2em', 'padding-right': '0.2em',
|
||||
'border-radius': '0 3px 0 0'
|
||||
}
|
||||
|
||||
// create and add the button to all the code blocks that contain >>>
|
||||
div.each(function(index) {
|
||||
var jthis = $(this);
|
||||
if (jthis.find('.gp').length > 0) {
|
||||
var button = $('<span class="copybutton">>>></span>');
|
||||
button.css(button_styles)
|
||||
button.attr('title', hide_text);
|
||||
button.data('hidden', 'false');
|
||||
jthis.prepend(button);
|
||||
}
|
||||
// tracebacks (.gt) contain bare text elements that need to be
|
||||
// wrapped in a span to work with .nextUntil() (see later)
|
||||
jthis.find('pre:has(.gt)').contents().filter(function() {
|
||||
return ((this.nodeType == 3) && (this.data.trim().length > 0));
|
||||
}).wrap('<span>');
|
||||
});
|
||||
|
||||
// define the behavior of the button when it's clicked
|
||||
$('.copybutton').click(function(e){
|
||||
e.preventDefault();
|
||||
var button = $(this);
|
||||
if (button.data('hidden') === 'false') {
|
||||
// hide the code output
|
||||
button.parent().find('.go, .gp, .gt').hide();
|
||||
button.next('pre').find('.gt').nextUntil('.gp, .go').css('visibility', 'hidden');
|
||||
button.css('text-decoration', 'line-through');
|
||||
button.attr('title', show_text);
|
||||
button.data('hidden', 'true');
|
||||
} else {
|
||||
// show the code output
|
||||
button.parent().find('.go, .gp, .gt').show();
|
||||
button.next('pre').find('.gt').nextUntil('.gp, .go').css('visibility', 'visible');
|
||||
button.css('text-decoration', 'none');
|
||||
button.attr('title', hide_text);
|
||||
button.data('hidden', 'false');
|
||||
}
|
||||
});
|
||||
});
|
28
docs/source/cli.rst
Normal file
28
docs/source/cli.rst
Normal file
@@ -0,0 +1,28 @@
|
||||
Command-line usage
|
||||
==================
|
||||
|
||||
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 <address>`` 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. ``kasa emeter --help`` or ``kasa hsv --help``.
|
||||
|
||||
If no command is given, the ``state`` command will be executed to query the device state.
|
||||
|
||||
Provisioning
|
||||
~~~~~~~~~~~~
|
||||
|
||||
You can provision your device without any extra apps by using the ``kasa wifi`` command:
|
||||
|
||||
1. If the device is unprovisioned, connect to its open network
|
||||
2. Use ``kasa discover`` (or check the routes) to locate the IP address of the device (likely 192.168.0.1)
|
||||
3. Scan for available networks using ``kasa wifi scan``
|
||||
4. Join/change the network using ``kasa wifi join`` command, see ``--help`` for details.
|
||||
|
||||
``kasa --help``
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
.. program-output:: kasa --help
|
70
docs/source/conf.py
Normal file
70
docs/source/conf.py
Normal file
@@ -0,0 +1,70 @@
|
||||
# Configuration file for the Sphinx documentation builder.
|
||||
#
|
||||
# This file only contains a selection of the most common options. For a full
|
||||
# list see the documentation:
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html
|
||||
|
||||
# -- Path setup --------------------------------------------------------------
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#
|
||||
# import os
|
||||
# import sys
|
||||
# sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
|
||||
# -- Project information -----------------------------------------------------
|
||||
|
||||
project = "python-kasa"
|
||||
copyright = "2020, python-kasa developers"
|
||||
author = "python-kasa developers"
|
||||
|
||||
|
||||
# -- General configuration ---------------------------------------------------
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = [
|
||||
"sphinx.ext.autodoc",
|
||||
"sphinx.ext.coverage",
|
||||
"sphinx.ext.viewcode",
|
||||
"sphinxcontrib.programoutput",
|
||||
]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ["_templates"]
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
# This pattern also affects html_static_path and html_extra_path.
|
||||
exclude_patterns = [] # type: ignore
|
||||
|
||||
|
||||
# -- Options for HTML output -------------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
#
|
||||
html_theme = "sphinx_rtd_theme"
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ["_static"]
|
||||
|
||||
|
||||
def setup(app):
|
||||
# add copybutton to hide the >>> prompts, see https://github.com/readthedocs/sphinx_rtd_theme/issues/167
|
||||
app.add_js_file("copybutton.js")
|
||||
|
||||
# see https://github.com/readthedocs/recommonmark/issues/191#issuecomment-622369992
|
||||
from m2r import MdInclude
|
||||
|
||||
app.add_config_value("no_underscore_emphasis", False, "env")
|
||||
app.add_config_value("m2r_parse_relative_links", False, "env")
|
||||
app.add_config_value("m2r_anonymous_references", False, "env")
|
||||
app.add_config_value("m2r_disable_inline_math", False, "env")
|
||||
app.add_directive("mdinclude", MdInclude)
|
17
docs/source/discover.rst
Normal file
17
docs/source/discover.rst
Normal file
@@ -0,0 +1,17 @@
|
||||
Discovering devices
|
||||
===================
|
||||
|
||||
.. code-block::
|
||||
|
||||
import asyncio
|
||||
from kasa import Discover
|
||||
|
||||
devices = asyncio.run(Discover.discover())
|
||||
for addr, dev in devices.items():
|
||||
asyncio.run(dev.update())
|
||||
print(f"{addr} >> {dev}")
|
||||
|
||||
|
||||
.. autoclass:: kasa.Discover
|
||||
:members:
|
||||
:undoc-members:
|
17
docs/source/index.rst
Normal file
17
docs/source/index.rst
Normal file
@@ -0,0 +1,17 @@
|
||||
python-kasa documentation
|
||||
=========================
|
||||
|
||||
.. mdinclude:: ../../README.md
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
|
||||
Home <self>
|
||||
cli
|
||||
discover
|
||||
smartdevice
|
||||
smartbulb
|
||||
smartplug
|
||||
smartdimmer
|
||||
smartstrip
|
6
docs/source/smartbulb.rst
Normal file
6
docs/source/smartbulb.rst
Normal file
@@ -0,0 +1,6 @@
|
||||
Bulbs
|
||||
===========
|
||||
|
||||
.. autoclass:: kasa.SmartBulb
|
||||
:members:
|
||||
:undoc-members:
|
18
docs/source/smartdevice.rst
Normal file
18
docs/source/smartdevice.rst
Normal file
@@ -0,0 +1,18 @@
|
||||
Common API
|
||||
======================
|
||||
|
||||
The basic functionalities of all supported devices are accessible using the common :class:`SmartDevice` base class.
|
||||
|
||||
The property accesses use the data obtained before by awaiting :func:`update()`.
|
||||
The values are cached until the next update call. In practice this means that property accesses do no I/O and are dependent, while I/O producing methods need to be awaited.
|
||||
|
||||
Methods changing the state of the device do not invalidate the cache (i.e., there is no implicit `update()`).
|
||||
You can assume that the operation has succeeded if no exception is raised.
|
||||
These methods will return the device response, which can be useful for some use cases.
|
||||
|
||||
Errors are raised as :class:`SmartDeviceException` instances for the library user to handle.
|
||||
|
||||
|
||||
.. autoclass:: kasa.SmartDevice
|
||||
:members:
|
||||
:undoc-members:
|
6
docs/source/smartdimmer.rst
Normal file
6
docs/source/smartdimmer.rst
Normal file
@@ -0,0 +1,6 @@
|
||||
Dimmers
|
||||
=======
|
||||
|
||||
.. autoclass:: kasa.SmartDimmer
|
||||
:members:
|
||||
:undoc-members:
|
6
docs/source/smartplug.rst
Normal file
6
docs/source/smartplug.rst
Normal file
@@ -0,0 +1,6 @@
|
||||
Plugs
|
||||
=====
|
||||
|
||||
.. autoclass:: kasa.SmartPlug
|
||||
:members:
|
||||
:undoc-members:
|
6
docs/source/smartstrip.rst
Normal file
6
docs/source/smartstrip.rst
Normal file
@@ -0,0 +1,6 @@
|
||||
Smart strips
|
||||
============
|
||||
|
||||
.. autoclass:: kasa.SmartStrip
|
||||
:members:
|
||||
:undoc-members:
|
Reference in New Issue
Block a user