Repository: executablebooks/MyST-Parser (python)

Issue:
For v3.0.1: indented directive options no longer recognised
### What version of `myst-parser` are you using?

3.0.0

### What version dependencies are you using?

<details>

```Package                       Version
----------------------------- -----------
ablog                         0.11.8
accessible-pygments           0.0.4
alabaster                     0.7.16
attrs                         23.2.0
Babel                         2.14.0
bcrypt                        4.1.2
beautifulsoup4                4.12.3
bleach                        6.1.0
certifi                       2024.2.2
cffi                          1.16.0
charset-normalizer            3.3.2
colorama                      0.4.6
cryptography                  42.0.5
defusedxml                    0.7.1
docutils                      0.20.1
fancylog                      0.3.0
fastjsonschema                2.19.1
feedgen                       1.0.0
idna                          3.7
imagesize                     1.4.1
invoke                        2.2.0
Jinja2                        3.1.3
jsonschema                    4.21.1
jsonschema-specifications     2023.12.1
jupyter_client                8.6.1
jupyter_core                  5.7.2
jupyterlab_pygments           0.3.0
linkify-it-py                 2.0.3
lxml                          5.2.1
markdown-it-py                3.0.0
MarkupSafe                    2.1.5
mdit-py-plugins               0.4.0
mdurl                         0.1.2
mistune                       3.0.2
myst-parser                   2.0.0
nbclient                      0.10.0
nbconvert                     7.16.3
nbformat                      5.10.4
nbsphinx                      0.9.3
numpydoc                      1.7.0
packaging                     24.0
pandocfilters                 1.5.1
paramiko                      3.4.0
pip                           23.3.1
platformdirs                  4.2.1
pycparser                     2.22
pydata-sphinx-theme           0.15.2
Pygments                      2.17.2
PyNaCl                        1.5.0
python-dateutil               2.9.0.post0
pywin32                       306
PyYAML                        6.0.1
pyzmq                         26.0.2
referencing                   0.35.0
requests                      2.31.0
rich                          13.7.1
rpds-py                       0.18.0
setuptools                    68.2.2
setuptools-scm                8.0.4
simplejson                    3.19.2
six                           1.16.0
snowballstemmer               2.2.0
soupsieve                     2.5
Sphinx                        7.1.2
sphinx-argparse               0.4.0
sphinx-autodoc-typehints      2.0.1
sphinx_design                 0.5.0
sphinx-sitemap                2.5.1
sphinxcontrib-applehelp       1.0.8
sphinxcontrib-devhelp         1.0.6
sphinxcontrib-htmlhelp        2.0.5
sphinxcontrib-jsmath          1.0.1
sphinxcontrib-qthelp          1.0.7
sphinxcontrib-serializinghtml 1.1.10
tabulate                      0.9.0
tinycss2                      1.3.0
tomli                         2.0.1
tornado                       6.4
traitlets                     5.14.3
typing_extensions             4.11.0
uc-micro-py                   1.0.3
urllib3                       2.2.1
watchdog                      4.0.0
webencodings                  0.5.1
wheel                         0.41.2
```
</details>

### What operating system are you using?

Windows

### Describe the Bug

In version 2.0.0 I have the images with content (I use backticks in the real version but use `:::` here for formatting reasons), e.g.:

```
:::{image} /_static/blog_images/neuroblueprint/NeuroBlueprint_project_tree_dark.png
   :align: center
   :class: only-dark
   :width: 650px
:::
```

```
:::{image} /_static/blog_images/neuroblueprint/NeuroBlueprint_project_tree_light.png
   :align: center
   :class: only-light
   :width: 650px
:::
```

but the content is not respected (e.g. image size) and the warning reads:

```
16: WARNING: 'image': Has content, but none permitted [myst.directive_parse]
```

I checked the changelog and couldnt see anything immediately relevant so listed as bug, but maybe this is a new feature I am misunderstanding.



### Expected Behavior

Image formats with content as directed .

### To Reproduce

I believe building with any image content should show the error.

Pull request:
🐛 FIX: allow indented option block
fixes #922 

Patch:
diff --git a/myst_parser/parsers/directives.py b/myst_parser/parsers/directives.py
index d6a000c..22ff5a6 100644
--- a/myst_parser/parsers/directives.py
+++ b/myst_parser/parsers/directives.py
@@ -175,34 +175,34 @@ def _parse_directive_options(
 
     :returns: (content, options, validation_errors)
     """
-    yaml_block: None | str = None
+    options_block: None | str = None
     if content.startswith("---"):
         line = None if line is None else line + 1
         content = "\n".join(content.splitlines()[1:])
         match = re.search(r"^-{3,}", content, re.MULTILINE)
         if match:
-            yaml_block = content[: match.start()]
+            options_block = content[: match.start()]
             content = content[match.end() + 1 :]  # TODO advance line number
         else:
-            yaml_block = content
+            options_block = content
             content = ""
-        yaml_block = dedent(yaml_block)
-    elif content.startswith(":"):
+        options_block = dedent(options_block)
+    elif content.lstrip().startswith(":"):
         content_lines = content.splitlines()
         yaml_lines = []
         while content_lines:
-            if not content_lines[0].startswith(":"):
+            if not content_lines[0].lstrip().startswith(":"):
                 break
-            yaml_lines.append(content_lines.pop(0)[1:])
-        yaml_block = "\n".join(yaml_lines)
+            yaml_lines.append(content_lines.pop(0).lstrip()[1:])
+        options_block = "\n".join(yaml_lines)
         content = "\n".join(content_lines)
 
-    has_options_block = yaml_block is not None
+    has_options_block = options_block is not None
 
     if as_yaml:
         yaml_errors: list[ParseWarnings] = []
         try:
-            yaml_options = yaml.safe_load(yaml_block or "") or {}
+            yaml_options = yaml.safe_load(options_block or "") or {}
         except (yaml.parser.ParserError, yaml.scanner.ScannerError):
             yaml_options = {}
             yaml_errors.append(
@@ -226,9 +226,9 @@ def _parse_directive_options(
     validation_errors: list[ParseWarnings] = []
 
     options: dict[str, str] = {}
-    if yaml_block is not None:
+    if options_block is not None:
         try:
-            _options, state = options_to_items(yaml_block)
+            _options, state = options_to_items(options_block)
             options = dict(_options)
         except TokenizeError as err:
             return _DirectiveOptions(


Test patch:
diff --git a/tests/test_renderers/fixtures/directive_parsing.txt b/tests/test_renderers/fixtures/directive_parsing.txt
index 3b8cc86..d148094 100644
--- a/tests/test_renderers/fixtures/directive_parsing.txt
+++ b/tests/test_renderers/fixtures/directive_parsing.txt
@@ -258,6 +258,24 @@ error: missing argument
 error: 1 argument(s) required, 0 supplied
 .
 
+indented_options
+.
+```{note}
+  :class: name
+
+body
+```
+.
+arguments: []
+body:
+- body
+content_offset: 2
+options:
+  class:
+  - name
+warnings: []
+.
+
 option_flags_std
 .
 ```{code-block}