-
Notifications
You must be signed in to change notification settings - Fork 115
Restore and improve @add_example() docstring-generating decorator
#1029
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
* Requires dev shinylive * Added `@add_example()` in places where it was missing * Requires `dynamic: true` in _quartodoc.yml. Where this is problematic, we've set `dynamic: false` * `@add_example()` now writes the primary app code in a static python chunk if `SHINY_ADD_EXAMPLES="true"` * `@add_example()` supports using non-standard file names so that multiple examples can be added to the same doc string
It was being used as a test to ensure multiple calls to `add_example()` work as expected
| - render.renderer.ValueFn | ||
| - render.renderer.AsyncValueFn | ||
| - name: render.renderer.Jsonifiable | ||
| dynamic: false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is it important that these are dynamic: false? For better performance, or correctness?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this case and the other one in this section, dynamic: true leads to cyclic reference errors in griffe
* Disable at function level with @no_example * Or use manual examples * Example check excludes implicitly exported functions and shiny.experimental * Also excludes shiny.express for now
Co-authored-by: Barret Schloerke <[email protected]>
Historically, pre-quartodoc, we used an
@add_example()decorator to explicitly add examples. When we moved to quartodoc, we switched to an automatic method for including examples and@add_example()has been effectively disabled since then.This PR restores the decorator and adapts it for use in quartodoc. The decorator approach gives us a few advantages over the automatic example approach. In particular it's now possible to add more than one example and to use non-standard file names for the example app.
Behavior after this PR
Use
@add_example()without arguments to automatically add an example fromapi-examples/{fn_name}/app.py, whereapi-examplescan be anywhere in the documented functions parent directories.shiny/api-examples/{func}/app.pyandshiny/api-examples/{func}/app-express.pyand alternativelyshiny/express/api-examples/{func}/app.py.Use the
app_fileargument of@add_example()to add an example from a file not namedapp.pyDecorators are applied bottom-up, but
@add_examples()applies the example in the order they appear in the code. In the following, the basic example appears first, followed by the complicated example.add_example()will add the other files in the example directory as supporting files, but it will not includeapp.pyor files that start withapp-.You can call
@add_example()more than once. They should be grouped together in a block (called sequentially) and multiple examples will be collected under a single "Examples" heading.We now require that all public functions have an example and
make quartodocwill throw if an included function doesn't have an example. You can use the@no_exampledecorator to tell quartodoc that the documented function intentionally doesn't include examples.render.plot.@add_example()or by manually including anExamplesheading. NOTE: Examples must be plural!shiny.express(temporarily) andshiny.experimental. We also don't require examples in external packages, e.g. fromhtmltools. I'll remove theshiny.expressexclusion when we start adding those examples.Changes in this PR
Setting this up required some large-ish changes to our quartodoc process.
We now set
dynamic: trueindocs/_quartodoc.ymland selectively mark functions to be visited statically with markup like@add_example()is a no-op unlessSHINY_ADD_EXAMPLESis"true". When exactly"true", we now write an Examples section into the docs that only includes the main app file as a static Python chunk.When both
SHINY_ADD_EXAMPLESandIN_QUARTODOCare"true", we wrap out the examples writer with a function that uses py-shinylive to create a shinylive quarto chunk. quartodoc may eventually set this envvar manually, for now we set both env vars inmake quartodoc.I've kept the no-op behavior of
@add_example(), but in my checking if we always allow@add_example()to run,import shinygoes from appox 0.09 seconds to 0.15. The utility is limited, however; in VSCode the function docs hover cards don't include the dynamically rendered portion of the docstrings.Other notes and tasks
docs/api/*.qmdfiles at the start of this PR and periodically updated them throughout to provide a way to see the changes in the final result. Before merging we need to stop tracking these intermediate files.make quartodocand the@no_exampledecorator.@no_exampledecorator to indicate that no example is required for the function.if not TYPE_CHECKING. This path is only executed when building quartdoc (i.e. whenIN_QUARTODOCis"true") but is run frequently in our CI tests, so the risk of this solution is low.