Skip to content

Documentation#685

Draft
uzlonewolf wants to merge 30 commits into
jasonacox:masterfrom
uzlonewolf:documentation
Draft

Documentation#685
uzlonewolf wants to merge 30 commits into
jasonacox:masterfrom
uzlonewolf:documentation

Conversation

@uzlonewolf
Copy link
Copy Markdown
Collaborator

One thing that's always annoyed me about TinyTuya is the lack of documentation. One day I'd be using the good documentation for something like pySerial and the next I'd be digging through TinyTuya source code files 🤣 So, I got the Sphinx code-to-documentation generator set up along with Read The Docs for web display. It's still very, very rough as I spent the last 2 days fighting with Sphinx to get it to link everything correctly, but the TinyTuya function definitions imported surprisingly well as-is without me needing to rewrite anything.

PoC: https://tinytuya-lw.readthedocs.io/

It's still really rough, but it's a start. I think the next thing I'm going to work on is adding type hinting to all the functions (which is going to require Python 3.5+).

@jasonacox
Copy link
Copy Markdown
Owner

Ooooo! Love this! I see only conflict is version. Are you updating that?

@uzlonewolf
Copy link
Copy Markdown
Collaborator Author

Yeah, I had bumped the version which in hindsight wasn't needed as there aren't really any code changes, only comment changes. I also reworked how it sets the version string while I was in there to match what was wanted in #588 but I'll probably pull it out and save that for a different PR. Or you can do it the next time the version needs to be bumped.

I noticed this merge conflict yesterday but didn't fix it as I ran into a different issue that needs some discussion before moving forward:

Sphinx gets confused and cannot generate links when a class has the same name as the module (filename) it is in. Initially I had solved this by moving Cloud and BulbDevice et al to new files with different names, however I later realized this will break imports if someone is doing i.e. import tinytuya.Cloud (though from tinytuya import Cloud still works). If it weren't for the Cloud module I'm not sure how much this would matter as import tinytuya.Device has never worked.

I just discovered a different workaround that would allow leaving all the files as they are now at the expense of linking functions as project.module.class.function, i.e. Cloud's setregion() becomes tinytuya.Cloud.Cloud.setregion(). I'm still digging to see if there's anything else I can do.

@jasonacox
Copy link
Copy Markdown
Owner

I also reworked how it sets the version string while I was in there to match what was wanted in #588 but I'll probably pull it out and save that for a different PR. Or you can do it the next time the version needs to be bumped.

Thanks yes, I agree. It breaks my automation (which I just need to fix).

Sphinx gets confused and cannot generate links when a class has the same name as the module (filename) it is in.

To be honest, that sounds like a weakness (bug?) in Sphinx that needs to be addressed there, not by rewriting our structure.

I'll start walking through the commits. Let me know when you think this is ready.


for clib in ('pyca/cryptography', 'PyCryptodomex', 'PyCrypto', 'pyaes'):
Crypto = Crypto_modes = AES = CRYPTOLIB = None
CRYPTOLIB = _AES = _Crypto = _Crypto_modes = None
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense

@uzlonewolf
Copy link
Copy Markdown
Collaborator Author

To be honest, that sounds like a weakness (bug?) in Sphinx that needs to be addressed there, not by rewriting our structure.

I agree. Unfortunately they can't/won't fix it. I found one issue where someone (I have no idea if they are involved with the project or are just some rando) was basically bragging about how "over 100 people have opened issues due to this problem and all those people are wrong!" I'm still working on it though and have been digging through the Sphinx source code looking for a way to monkey-patch around it or something. Fixing it for the *Device classes was rather easy, it's the constants/direct attributes which are kicking my butt.

@uzlonewolf
Copy link
Copy Markdown
Collaborator Author

It's a kludge, but it appears to work. Fortunately it only messes with Sphinx so even if it breaks it's not a big deal.

@jasonacox jasonacox added the documentation Improvements or additions to documentation label Mar 3, 2026
@jasonacox jasonacox requested a review from Copilot March 5, 2026 05:35
@jasonacox
Copy link
Copy Markdown
Owner

Thanks @uzlonewolf - I'll run the Copilot peer review. Let me know if you think this ready to go otherwise.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces an initial Sphinx + ReadTheDocs documentation setup for TinyTuya and updates existing modules with docstrings/metadata to improve autodoc output.

Changes:

  • Add Sphinx project scaffolding, custom templates, and ReadTheDocs build configuration.
  • Improve/normalize docstrings across core modules for autodoc/autosummary.
  • Minor refactors to support documentation generation (e.g., centralizing UDPKEY, exporting crypto symbols).

Reviewed changes

Copilot reviewed 41 out of 43 changed files in this pull request and generated 14 comments.

Show a summary per file
File Description
tinytuya/core/udp_helper.py Uses shared UDPKEY constant for UDP decrypt/HMAC.
tinytuya/core/message_helper.py Adds richer docstrings for packing/unpacking protocol messages.
tinytuya/core/error_helper.py Adds module/docs scaffolding around error codes and JSON error helper.
tinytuya/core/document.py Adds documentation metadata for Sphinx generation.
tinytuya/core/crypto_helper.py Exposes documented crypto globals and renames internal imports for clarity.
tinytuya/core/core.py Adds package metadata and docstrings to utility functions.
tinytuya/core/const.py Documents constants and adds UDPKEY constant.
tinytuya/core/command_types.py Adds Sphinx-style inline docs for command constants.
tinytuya/core/init.py Adjusts imports and exposes document module for Sphinx context.
tinytuya/core/XenonDevice.py Adds class docstring and docstring tweaks aimed at Sphinx output.
tinytuya/core/Device.py Adds module-level name override aimed at Sphinx output.
tinytuya/init.py Simplifies top-level docstring and exports additional metadata.
tinytuya/OutletDevice.py Removes large header comment block (docs now come from Sphinx).
tinytuya/CoverDevice.py Removes large header comment block (docs now come from Sphinx).
tinytuya/Cloud.py Adds a class docstring placeholder for Cloud.
tinytuya/BulbDevice.py Adds __init__ docstring and docstring concatenation for Sphinx.
setup.py Changes crypto dependency detection to avoid pkg_resources usage.
docs/sphinx/tt_gen_local_api.rst Adds autosummary entrypoint for local API docs.
docs/sphinx/start/*.rst Adds “Getting Started” placeholder pages.
docs/sphinx/start.rst Adds getting-started toctree.
docs/sphinx/index.rst Adds Sphinx root index and toctree.
docs/sphinx/contrib.rst Adds placeholder contrib page.
docs/sphinx/conf.py Adds Sphinx configuration + custom directives/monkeypatches for nicer output.
docs/sphinx/cloud_api.rst Adds autosummary entrypoint for Cloud API docs.
docs/sphinx/_templates/*.rst Adds custom autosummary/autodoc templates for module/class layout.
docs/sphinx/_static/.gitkeep Keeps static dir in git.
docs/rtd-requirements.txt Adds RTD requirements for Sphinx/theme.
docs/make.bat Adds Windows Sphinx build helper.
docs/Makefile Adds Unix Sphinx build helper.
.readthedocs.yaml Configures RTD build (Python version, deps install, fail on warnings).
.gitignore Ignores Sphinx generated output directory.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread setup.py
Comment thread docs/sphinx/tt_gen_local_api.rst Outdated
@@ -0,0 +1,13 @@
:orphan:
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file appears to start with a UTF-8 BOM/zero-width character (an invisible character before :orphan:). That can cause odd rendering/diffs; consider removing the BOM so the first character is :.

Suggested change
:orphan:
:orphan:

Copilot uses AI. Check for mistakes.
Comment thread docs/sphinx/cloud_api.rst Outdated
@@ -0,0 +1,12 @@
TinyTuya Cloud API
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file appears to start with a UTF-8 BOM/zero-width character (an invisible character before TinyTuya Cloud API). That can cause odd rendering/diffs; consider removing the BOM.

Suggested change
TinyTuya Cloud API
TinyTuya Cloud API

Copilot uses AI. Check for mistakes.
Comment thread tinytuya/BulbDevice.py Outdated
kwargs['version'] = None
super(BulbDevice, self).__init__(*args, **kwargs)

# Monkey-patch the docstring so Sphinx gets a contatenation of parent+ours
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment typo: "contatenation" → "concatenation".

Suggested change
# Monkey-patch the docstring so Sphinx gets a contatenation of parent+ours
# Monkey-patch the docstring so Sphinx gets a concatenation of parent+ours

Copilot uses AI. Check for mistakes.
Comment on lines +3 to +5
"""
Error messages and formattring
"""
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Module docstring has a typo: "formattring" should be "formatting".

Copilot uses AI. Check for mistakes.
@@ -0,0 +1,14 @@
TinyTuya Local API
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This template appears to start with a UTF-8 BOM/zero-width character (an invisible character before TinyTuya Local API). That can leak into generated pages; consider removing the BOM from the template file.

Suggested change
TinyTuya Local API
TinyTuya Local API

Copilot uses AI. Check for mistakes.
Comment thread tinytuya/Cloud.py Outdated

class Cloud(object):
"""
placeholder
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Cloud class docstring is currently just "placeholder", which will surface prominently in the generated docs. Consider removing it (so the existing, detailed __init__ docstring is used) or replacing it with a short summary of what Cloud represents.

Suggested change
placeholder
Interface to the Tuya Cloud IoT Platform for managing and controlling devices via cloud APIs.

Copilot uses AI. Check for mistakes.
Comment on lines +21 to 24
# Fix the name so it's not tinytuya.core.XenonDevice
__name__ = 'tinytuya.XenonDevice'

log = logging.getLogger(__name__)
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

__name__ is a special module attribute; overriding it at runtime can confuse logging, introspection, stack traces, and tooling (and it doesn't change the class' fully-qualified name in a safe way). For documentation purposes, prefer setting XenonDevice.__module__ = "tinytuya" (or configuring Sphinx autodoc/currentmodule) instead of mutating the module __name__.

Copilot uses AI. Check for mistakes.
Comment on lines +239 to 241
node_id (str, optional): alias for cid
parent (XenonDevice, optional): gateway device this device is a child of)

Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Docstring has an unmatched trailing parenthesis in the parent argument description ("child of)"). This will render oddly in generated docs; please remove the extra ).

Copilot uses AI. Check for mistakes.
Comment thread tinytuya/core/Device.py
Comment on lines +10 to 13
# Fix the name so it's not tinytuya.core.Device
__name__ = 'tinytuya.Device'

log = logging.getLogger(__name__)
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

__name__ is a special module attribute; overriding it can confuse logging and introspection and may have unintended side effects at import time. For documentation purposes, prefer setting Device.__module__ or adjusting Sphinx autodoc configuration rather than mutating the module __name__.

Copilot uses AI. Check for mistakes.
@jasonacox
Copy link
Copy Markdown
Owner

Some noise here (reviews), but some signal we should act on. I can help with these.

@uzlonewolf
Copy link
Copy Markdown
Collaborator Author

I'm working through them and am hoping to get it wrapped up in the morning. Most of those warnings are easy fixes, it's finishing the documenting everywhere else which is taking a while 😆

@uzlonewolf
Copy link
Copy Markdown
Collaborator Author

While working on the Cloud documentation I ended up rewriting the Region stuff. Known region codes are now in API_REGIONS (descriptive names) and API_REGION_HOSTS (hostnames) and setregion() will now raise a key error if an unknown region code is passed to it.

@jasonacox
Copy link
Copy Markdown
Owner

@jasonacox-sam Tests are failing here. See if you can figure out why.

@jasonacox-sam
Copy link
Copy Markdown
Collaborator

jasonacox-sam commented Apr 11, 2026

@uzlonewolf — traced the CI failure. Quick update on my earlier comment:

The Pylint error is:

tinytuya/core/udp_helper.py:27: E0602: Undefined variable 'UDPKEY_AP'

This is happening because your PR branch (666d545a) is based on an older version of master from March, where udp_helper.py imported UDPKEY from const.py but referenced UDPKEY_AP without importing it.

Good news: master has since refactored udp_helper.py — it no longer imports from const.py at all and uses an inline md5() call instead. The UDPKEY_AP reference is gone. Master's Pylint is fully green.

The fix: rebase this PR branch onto current master. The conflict should resolve the Pylint error automatically since the udp_helper.py changes on master supersede the old version your branch is targeting.

No separate fix PR needed from our side.

@uzlonewolf
Copy link
Copy Markdown
Collaborator Author

uzlonewolf commented Apr 11, 2026

No, I already fixed it, it's just that this is nowhere near ready to merge even with that failure fixed so I didn't bother pushing it.

This turned out to be like 100x more effort than I was expecting and I ended up spending the time I had intended to use on documenting the code on making Sphinx do what I wanted. I haven't had time the last few weeks to finish it and was hoping to get it done this weekend, however I suddenly had a work project dropped on me Friday afternoon that's needed for Monday, so...

@uzlonewolf uzlonewolf marked this pull request as draft April 11, 2026 18:43
@jasonacox
Copy link
Copy Markdown
Owner

No worries and no rush @uzlonewolf - Thanks for the update.

@uzlonewolf
Copy link
Copy Markdown
Collaborator Author

uzlonewolf commented Apr 11, 2026

On a (similar? unrelated?) note, this is like the umpteenth time I've made a stupid mistake like this when committing, so I ended up adding a git hook to .git/hooks/pre-commit that calls pylint on every commit, so hopefully this will be the last time it happens ^_^

My .git/hooks/pre-commit:

#!/bin/bash

echo "Running pylint..."
pylint --recursive y --reports y -E tinytuya || {
    echo "pylint failed, aborting commit!"
    exit 2
}

echo "done."
exit $?

Sadly you can't commit anything in .git/ or I'd submit a PR for it :(

@jasonacox
Copy link
Copy Markdown
Owner

On a (similar? unrelated?) note, this is like the umpteenth time I've made a stupid mistake like this when committing, so I ended up adding a git hook to .git/hooks/pre-commit that calls pylint on every commit, so hopefully this will be the last time it happens ^_^

My .git/hooks/pre-commit:

#!/bin/bash

echo "Running pylint..."
pylint --recursive y --reports y -E tinytuya || {
    echo "pylint failed, aborting commit!"
    exit 2
}

echo "done."
exit $?

Sadly you can't commit anything in .git/ or I'd submit a PR for it :(

Oh! That's good. Adding myself. :)

@jasonacox-sam Make sure you add this to your local clone too!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants