Repository: executablebooks/MyST-Parser (python)

Issue:
For v3.0.1: If the last directive option has an empty value then it is omitted
### What version of `myst-parser` are you using?

3.0.0

### What version dependencies are you using?

sphinx=7.3.7
docutils=0.20.1


### What operating system are you using?

Linux

### Describe the Bug

The glob patterns defined in a toctree directive do not work with `3.0.0` anymore.

### Expected Behavior

_No response_

### To Reproduce

````markdown
```{toctree}
---
maxdepth: 2
caption: Contents
glob:
---
path*/index
pages/**
*/index
```
````

Pull request:
🐛 FIX empty value for final directive option
fixes #923 

Patch:
diff --git a/myst_parser/parsers/directives.py b/myst_parser/parsers/directives.py
index 5a2a7f4..d6a000c 100644
--- a/myst_parser/parsers/directives.py
+++ b/myst_parser/parsers/directives.py
@@ -49,8 +49,7 @@ from docutils.parsers.rst.states import MarkupError
 
 from myst_parser.warnings_ import MystWarnings
 
-from .options import TokenizeError
-from .options import to_items as options_to_items
+from .options import TokenizeError, options_to_items
 
 
 @dataclass
diff --git a/myst_parser/parsers/options.py b/myst_parser/parsers/options.py
index cf4d353..366d455 100644
--- a/myst_parser/parsers/options.py
+++ b/myst_parser/parsers/options.py
@@ -168,7 +168,7 @@ class State:
     has_comments: bool = False
 
 
-def to_items(
+def options_to_items(
     text: str, line_offset: int = 0, column_offset: int = 0
 ) -> tuple[list[tuple[str, str]], State]:
     """Parse a directive option block into (key, value) tuples.
@@ -211,6 +211,8 @@ def _to_tokens(
                     raise TokenizeError("expected key before value", token.start)
                 yield key_token, token
                 key_token = None
+        if key_token is not None:
+            yield key_token, None
     except TokenizeError as exc:
         if line_offset or column_offset:
             raise exc.clone(line_offset, column_offset) from exc


Test patch:
diff --git a/tests/test_renderers/fixtures/directive_parsing.txt b/tests/test_renderers/fixtures/directive_parsing.txt
index 663d09e..3b8cc86 100644
--- a/tests/test_renderers/fixtures/directive_parsing.txt
+++ b/tests/test_renderers/fixtures/directive_parsing.txt
@@ -257,3 +257,47 @@ error: missing argument
 .
 error: 1 argument(s) required, 0 supplied
 .
+
+option_flags_std
+.
+```{code-block}
+:linenos:
+:lineno-start: 2
+:force:
+
+body
+```
+.
+arguments: []
+body:
+- body
+content_offset: 4
+options:
+  force: null
+  lineno-start: 2
+  linenos: null
+warnings: []
+.
+
+option_flags_delimited
+.
+```{code-block}
+---
+linenos:
+lineno-start: 2
+force:
+---
+
+body
+```
+.
+arguments: []
+body:
+- body
+content_offset: 6
+options:
+  force: null
+  lineno-start: 2
+  linenos: null
+warnings: []
+.
diff --git a/tests/test_renderers/fixtures/option_parsing.yaml b/tests/test_renderers/fixtures/option_parsing.yaml
index 14fe0a5..772aa7f 100644
--- a/tests/test_renderers/fixtures/option_parsing.yaml
+++ b/tests/test_renderers/fixtures/option_parsing.yaml
@@ -182,3 +182,22 @@ folded values:
       ],
       "comments": false
     }
+
+empty_final_value:
+  content: |-
+    key1: val1
+    key2:
+  expected: |-
+    {
+      "dict": [
+        [
+          "key1",
+          "val1"
+        ],
+        [
+          "key2",
+          ""
+        ]
+      ],
+      "comments": false
+    }
diff --git a/tests/test_renderers/test_parse_directives.py b/tests/test_renderers/test_parse_directives.py
index e6b2c2b..3813cc9 100644
--- a/tests/test_renderers/test_parse_directives.py
+++ b/tests/test_renderers/test_parse_directives.py
@@ -6,10 +6,10 @@ import yaml
 from docutils.parsers.rst.directives.admonitions import Admonition, Note
 from docutils.parsers.rst.directives.body import Rubric
 from markdown_it import MarkdownIt
+from sphinx.directives.code import CodeBlock
 
 from myst_parser.parsers.directives import MarkupError, parse_directive_text
-from myst_parser.parsers.options import TokenizeError
-from myst_parser.parsers.options import to_items as options_to_items
+from myst_parser.parsers.options import TokenizeError, options_to_items
 
 FIXTURE_PATH = Path(__file__).parent.joinpath("fixtures")
 
@@ -50,6 +50,8 @@ def test_parsing(file_params):
         klass = Note
     elif name == "{admonition}":
         klass = Admonition
+    elif name == "{code-block}":
+        klass = CodeBlock
     else:
         raise AssertionError(f"Unknown directive: {name}")
     try: