Skip to content

feature: hooks for injecting hidden code (could be extended for other uses) #73

Open
@benjamincburns

Description

@benjamincburns

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_* and error_* 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 object
  • pre_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?)

Metadata

Metadata

Assignees

Labels

featureNew feature or request

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions