Description
Problem
In our docs for LangGraph we use tools like VCR and nock to cache and replay interactions between our code samples and the APIs with which our samples interact.
When we built our docs from Jupyter notebooks, we'd inject code for setting these up into the notebooks as non-rendered blocks. This allows us to have the setup/teardown defined centrally, and means less boilerplate in each notebook file.
markdown-exec
sessions are throwing us a curve-ball, however. We'd have to process each block in the doc, catalogue the sessions, and insert a pre/post amble block for each one.
Proposed solution
It would be nice if I could register callbacks to markdown-exec
that would be called at the start and end of each session, and perhaps also at the start and end of each block.
Configuration
The callbacks could be registered via the mkdocs.yml
config in the following way:
plugins:
- markdown-exec:
hooks:
python:
pre_session: # called before the first code block of a python session runs
- module.to.import:python_pre_session_callback_fn
post_session: # called after the last code block of a python session runs
- module.to.import:python_post_session_callback_fn
pre_block: # called before the execution of each python block
- module.to.import:python_pre_block_callback_fn
post_block: # called after each successful execution of each python block
- module.to.import:python_post_block_callback_fn
block_error: # called after each erroneous execution of each python block
- module.to.import:python_block_error_callback_fn
typescript:
pre_session: # called before the first code block of a typescript session runs
- module.to.import:typescript_pre_session_callback_fn
post_session: # called after the last code block of a typescript session runs
- module.to.import:typescript_post_session_callback_fn
pre_block: # called before the execution of each typescript block
- module.to.import:typescript_pre_block_callback_fn
post_block: # called after each successful execution of each typescript block
- module.to.import:typescript_post_block_callback_fn
block_error: # called after each erroneous execution of each typescript block
- module.to.import:typescript_block_error_callback_fn
Hook arguments
As for what arguments to pass, I think these functions should ideally get the full context available. So that would include
- all of the arguments passed to the formatter on the invocation that triggered the hook
- in addition, context about the filename & path of the document being rendered, if that's not already in the kwargs for the formatter calls
- in the case of
post_*
anderror_*
hooks, the result of the execution that triggered the call
You could also pass the code and output history, but our immediate use case doesn't require this.
Hook return values
To make this mechanism extensible, hook functions should return an object (or list of objects?) that instruct markdown-exec
to carry out some operation.
Example operations could include:
- Execute some setup/teardown code before/after the block/session, but don't include it or its output in the rendered output for the block
- This is the case that we have immediate need for
pre_block
only: Replace the code in the given block with the code returned in the objectpre_block
only: Skip execution of the block, and render the output as given (provides an extension point that would be useful for solving feature: only recompute dirty docs during editing #71, perhaps also Cache #4?)