Skip to content

Conversation

@ntoll
Copy link
Member

@ntoll ntoll commented Nov 28, 2025

Description

This PR has several aims:

  • Comprehensive, simple and accurate idiomatic docstrings in the Python code for the pyscript namespace. These will be integrated automatically into the "API" section of the PyScript docs.
  • Refactoring of the pyscript namespace as general housekeeping, simplification and removal of unnecessary / unused code.
  • Addition of a much more comprehensive upytest based test suite where possible.

Already I've notice code that would never work in MicroPython (where dict ordering was implied in the code - but MicroPython's dicts don't guarantee order). More comprehensive and complete tests found this pretty quickly.

Changes

For each module in the pyscript namespace: docs, refactoring and tests have been accomplished (adjusted as work is completed):

  • __init__.py
  • display.py
  • events.py
  • fetch.py
  • ffi.py
  • flatted.py
  • fs.py
  • magic_js.py (an "internal" module renamed to context.py)
  • media.py
  • storage.py
  • util.py
  • web.py
  • websocket.py
  • workers.py

Checklist

  • I have checked make build works locally.
  • I have created / updated documentation for this change (if applicable).

@ntoll ntoll requested a review from WebReflection November 28, 2025 09:49
@ntoll
Copy link
Member Author

ntoll commented Dec 4, 2025

This PR is ready for review. My apologies for the size, but this relates to the nature of the changes taking place (lots of docs).

So, some guidance for reviewers.

My approach

As outlined at the start I had three aims:

  1. Comprehensive, simple and accurate idiomatic docstrings in the Python code for the pyscript namespace.
  2. Refactoring of the pyscript namespace as general housekeeping, simplification and removal of unnecessary / unused code.
  3. Addition of a much more comprehensive upytest based test suite where possible.

The outcome

Given these aims, for each of the sub-modules in the pyscript namespace I have completed the following tasks:

  • Apart from exceptions in pyscript.web highlighted below, everything behaves the same as before.
  • All modules, classes and functions have Markdown flavoured docstrings. Where relevant (e.g. public aspects of the API) they include example usage. All arguments are explained. Where necessary I've tried to reference reliable yet readable web-standards related docs (MDN).
  • While retaining the same functionality, I have renamed internal classes, functions and variables to human-meaningful names, as far as possible. This is to make the code more readable (the code will also actually be in our docs, so needs to be easy to understand!) and therefore easier to maintain and reason about. I hope we can agree that this is a good thing ™️.
  • When appropriate I've simplified the code or tried to make it more Pythonic (e.g. favouring idiomatic Python ways of working over underlying JS implementation details).
  • The simplification has generally made the code smaller too.
  • I've added many many more tests to exercise edge cases and ensure all the main features of a module are properly checked.

While the size of the code base has increased by a huge amount (just look at all those docs!) the mini-fied version delivered to the user (pyscript.js) is smaller, at 1k less than it was before. 🎉

Finally, there will be a complementary PR/branch in the docs repository for auto-generating our API docs from this source code. I'll reference it here once this work is ready to be reviewed. 👍

Softly breaking adjustments

Our biggest module is (by far) pyscript.web. I have made significant changes to the source to save us hundreds of lines of code. As part of this refinement, and while the API is basically the same, I have had to make the following "softly breaking" adjustments to the module (i.e. functionally it's the same, but with some implementation changes):

  • An element's classes are just a Python set that automatically adjusts the underlying _dom_element.
  • An element's styles are just a Python dict that automatically adjusts the underlying _dom_element.
  • Explicitly use update_all with ElementCollections (simpler and greater flexibility). You used to be able to do implicit changes via: my_collection.innerHTML = "foo" and so on. On several occasions this felt risky (folks thought they were mutating an element, not an element collection and they were getting strange results). As Zen of Python says, explicit is better than implicit. Now you just: my_collection.update_all(innerHTML="foo") which also makes it more obvious what's going on.
  • Extract a child element by id with my_container["#an-id"]. This will return a single element or None. This has been a much requested refinement of the module via our community on discord (here's a recent example). It applies to all things that may contain elements (other Elements with children, ElementCollections and the page object). You can still search and match a collection of results via the .find("css-selector") function in the usual way.

That's it!

Clearly some of this is opinionated, but I hope my way of working reveals why I've made the choices I have. Once this lands our API docs will be VASTLY improved, and we'll have a single source of truth for such technical documentation (i.e. it's a part of the context of the source code, as it should be). Finally, we've set an obvious and consistent precedent for code standards (small and simple with human-comprehensible names that will be minified), documentation (Markdown with examples) and tests (comprehensive, intentional and browser based).

@ntoll
Copy link
Member Author

ntoll commented Dec 4, 2025

Related PR in the docs repostory: pyscript/docs#201

@ntoll
Copy link
Member Author

ntoll commented Dec 4, 2025

Now that I've got the docs automatically building via pyscript/docs#201 I need to revisit all the Markdown to adjust it so it renders properly in the context of the docs.

ntoll added 2 commits December 8, 2025 17:16
…rated documentation (where triple quoted strings are used to document module attributes).
@ntoll
Copy link
Member Author

ntoll commented Dec 8, 2025

Markdown now renders nicely over in pyscript/docs#201.

Side effect: I now know far too much about the mkdocstrings plugin. 🤦

@WebReflection
Copy link
Contributor

@ntoll there are two main points to address but everything else looks good to me. I want this to land before the other because it looks like the one in docs just copies over these files so it'd be pointless to approve that one, even if the the automatic code generation looks fine, although it will need a rebase after changes happen in here and this gets merged, then eventually I can approve the other one too.

@ntoll
Copy link
Member Author

ntoll commented Dec 11, 2025

OK... @WebReflection I've addressed your couple of points. If you're happy, I'm happy. 🚀

Copy link
Contributor

@WebReflection WebReflection left a comment

Choose a reason for hiding this comment

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

thanks 🙏

@ntoll ntoll merged commit a02ff69 into main Dec 11, 2025
2 checks passed
@ntoll ntoll deleted the api-docstring-refactor branch December 11, 2025 17:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants