import matplotlib
if not hasattr(matplotlib.RcParams, "_get"):
    matplotlib.RcParams._get = dict.get

Gated Directives#

This package is an extension for Sphinx that creates a start directive and an end directive for every registered class-based directive.

What does it do?#

This extension performs the following steps:

  1. It scans the Sphinx environment for all registered class-based directives.

  2. For each directive found, it automatically registers two new directives:

    • A start directive that marks the beginning of a block.

    • An end directive that marks the end of a block.

  3. On build time, it processes these start and end directives to ensure that content between them is handled correctly.

For example, if you have a directive called warning, this extension will create (with default settings) two new directives: warning-start and warning-end. The code:

:::{warning}
This is a warning message.

So, be careful!
:::

can now be replaced with the code

:::{warning-start}
This is a warning message.
:::

So, be careful!

:::{warning-end}
:::

In short:

  • This extension splits the original directive into a start and end directive.

  • The start directive has the same options as the original directive.

  • Anything inside the start directive is processed as usual.

  • Anything between the start and end directives is processed as usual, and then added to the output of the start directive.

  • The end directive is mandatory to close the directive.

  • Anything inside the end directive is ignored.

This allows two things:

  1. More granular control over where the directive starts and ends, which can be useful in complex documents. This is similar to how HTML tags and LaTeX environments work.

  2. The ability to nest directives more easily, as the start and end markers can be placed independently. A major benefit of this is that it allows for nesting of code-cells.

Caution

Some directives parse the content inside the directive. If that content is moved between the start and end directives, it may not be parsed as expected, as it will be parsed separately.

Installation#

To use this extension, follow these steps:

Step 1: Install the Package

Install the module sphinx-gated-directives package using pip:

pip install sphinx-gated-directives

Step 2: Add to requirements.txt

Make sure that the package is included in your project’s requirements.txt to track the dependency:

sphinx-gated-directives

Step 3: Enable in _config.yml

In your _config.yml file, add the extension to the list of Sphinx extra extensions (important: underscore, not dash this time):

sphinx: 
    extra_extensions:
        .
        .
        .
        - sphinx_gated_directives
        .
        .
        .

or similarly in your conf.py file.

Configuration#

This extension can be configured via the _config.yml file in your JupyterBook project (or similarly in conf.py for standard Sphinx projects).

The default configuration options are as follows:

sphinx:
  config:
    sphinx_gated_directives:
      suffix_start: start    # Suffix for the start directive
      suffix_end: end        # Suffix for the end directive
      suffix_separator: '-'     # Separator between the original directive name and the suffix
      override_existing: false  # Whether to override existing gated directives with the same name

Per key the meanings are:

  • suffix_start: The suffix to append to the original directive name for the start directive.

    • Default is start.

    • Must be a non-empty string containing only a-z.

  • suffix_end: The suffix to append to the original directive name for the end directive.

    • Default is end.

    • Must be a non-empty string containing only a-z.

  • suffix_separator: The separator to use between the original directive name and the suffix.

    • Default is -.

    • Must be a single character, no space, no underscore, no colon, or empty string.

  • override_existing: Whether to override existing gated directives with the same name.

    • Default is false.

    • Must be a boolean value (true or false), a single string or a list of strings.

    • If false, none existing gated directives will be overridden.

    • If true, all existing gated directives will be overridden.

    • If a string or a list of strings, only the existing gated directives with names in the list/string will be overridden.

Warning

Setting override_existing to anything other than false may lead to unexpected behavior if those directives are already in use.

Use with caution.

Examples#

Simple example#

We start with the example from the introduction:

Original syntax
:::{warning}
This is a warning message.

So, be careful!
:::
Gated syntax
:::{warning-start}
This is a warning message.

:::

So, be careful!

:::{warning-end}
:::
Original result

Warning

This is a warning message.

So, be careful!

Gated result

Warning

This is a warning message.

So, be careful!

Although the syntax is more verbose, the result is identical.

A benefit of the gated syntax is that the end of a directive can more easily be identified.

Nested code#

Gated directives allow the use of nesting of code cells inside other directives. Code cells must always be at the top level of Jupyter Notebooks (.ipynb) and Text-based Notebooks (.md).

Syntax

:::{prf:algorithm-start}
:label: alg:nested-code

To achieve a nice result, execute the following code:
:::

```{code-cell} ipython3
start = 1
end = 10
for i in range(start, end):
    print(i)
```

:::{prf:algorithm-end}
:::

Result

Algorithm 1

To achieve a nice result, execute the following code:

start = 1
end = 10
for i in range(start, end):
    print(i)
1
2
3
4
5
6
7
8
9

Another benefit of the gated syntax is that any content, such as admonitions and code cells can be nested inside, for example, a figure directive:

:::{figure-start} images/nothing.svg
:name: figure-label
:alt: Nothing
:align: left
:width: 100%

This is a figure that contains some code and an admonition.
:::

```{code-cell} ipython3
a = "This is some"
b = "Python code"
c = "that should be inside the figure,"
d = "above the caption."
print(f"{a} {b} {c} {d}")
```

```{prf:axiom} Occam's Razor
:label: axiom-occam

Entities must not be multiplied beyond necessity.
```

:::{figure-end}
:::
Nothing
a = "This is some"
b = "Python code"
c = "that should be inside the figure,"
d = "above the caption."
print(f"{a} {b} {c} {d}")
This is some Python code that should be inside the figure, above the caption.

Axiom 1 (Occam’s Razor)

Entities must not be multiplied beyond necessity.

Fig. 126 This is a figure that contains some code and an admonition.#

Contribute#

This tool’s repository is stored on GitHub. If you’d like to contribute, you can create a fork and open a pull request on the GitHub repository.