Skip to content

Commit afafee6

Browse files
Merge pull request #76 from adamtheturtle/admonition-pure-children
2 parents 133c2aa + 8692821 commit afafee6

File tree

3 files changed

+144
-10
lines changed

3 files changed

+144
-10
lines changed

sample/index.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,22 @@ This is **bold** and *italic* and ``inline code``.
1515

1616
This is a warning that demonstrates the warning admonition support.
1717

18+
.. code-block:: python
19+
20+
"""Python code nested in an admonition."""
21+
22+
23+
def hello_world() -> int:
24+
"""Return the answer."""
25+
return 42
26+
27+
28+
hello_world()
29+
30+
.. warning::
31+
32+
This is a warning that demonstrates the warning admonition support.
33+
1834
.. tip::
1935

2036
This is a helpful tip that demonstrates the tip admonition support.

src/sphinx_notion/__init__.py

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -249,12 +249,39 @@ def _create_admonition_callout(
249249
emoji: str,
250250
color: Color,
251251
) -> list[NotionObject[Any]]:
252+
"""Create a Notion Callout block for admonition nodes.
253+
254+
The first child (typically a paragraph) becomes the callout text,
255+
and any remaining children become nested blocks within the callout.
252256
"""
253-
Create a Notion Callout block for admonition nodes.
254-
"""
255-
rich_text = _create_rich_text_from_children(node=node)
256257
block = UnoCallout(text="", icon=Emoji(emoji=emoji), color=color)
257-
block.rich_text = rich_text
258+
259+
# Use the first child as the callout text
260+
first_child = node.children[0]
261+
if isinstance(first_child, nodes.paragraph):
262+
rich_text = _create_rich_text_from_children(node=first_child)
263+
block.rich_text = rich_text
264+
# Process remaining children as nested blocks
265+
children_to_process = node.children[1:]
266+
else:
267+
# If first child is not a paragraph, use empty text
268+
block.rich_text = Text.from_plain_text(text="")
269+
# Process all children as nested blocks (including the first)
270+
children_to_process = node.children
271+
272+
# Process children as nested blocks
273+
for child in children_to_process:
274+
for child_block in list(
275+
_process_node_to_blocks(
276+
child,
277+
section_level=1,
278+
)
279+
):
280+
# Add nested blocks as children to the callout
281+
# Remove pyright ignore once we have
282+
# https://github.com/ultimate-notion/ultimate-notion/issues/94.
283+
block.obj_ref.value.children.append(child_block.obj_ref) # pyright: ignore[reportUnknownMemberType]
284+
258285
return [block]
259286

260287

tests/test_integration.py

Lines changed: 97 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -731,8 +731,7 @@ def test_admonition_single_line(
731731
rst_content = f"""
732732
Regular paragraph.
733733
734-
.. {admonition_type}::
735-
{message}
734+
.. {admonition_type}:: {message}
736735
737736
Another paragraph.
738737
"""
@@ -773,19 +772,69 @@ def test_admonition_multiline(
773772
) -> None:
774773
"""Test that admonitions with multiple paragraphs work.
775774
776-
For now, we ignore children and just combine all text content.
775+
The first paragraph becomes the callout text, and subsequent
776+
paragraphs become nested blocks within the callout.
777777
"""
778778
rst_content = f"""
779779
.. {admonition_type}::
780780
This is the first paragraph of the {admonition_type}.
781781
782-
This is the second paragraph that should be combined.
782+
This is the second paragraph that should be nested.
783783
"""
784-
# Create the callout with expected rich text structure
785784
callout = UnoCallout(text="", icon=Emoji(emoji=emoji), color=color)
786785
callout.rich_text = text(
787786
text=f"This is the first paragraph of the {admonition_type}."
788-
) + text(text="This is the second paragraph that should be combined.")
787+
)
788+
789+
nested_paragraph = UnoParagraph(
790+
text="This is the second paragraph that should be nested."
791+
)
792+
793+
callout.obj_ref.value.children.append(nested_paragraph.obj_ref) # pyright: ignore[reportUnknownMemberType]
794+
795+
expected_objects: list[NotionObject[Any]] = [
796+
callout,
797+
]
798+
_assert_rst_converts_to_notion_objects(
799+
rst_content=rst_content,
800+
expected_objects=expected_objects,
801+
make_app=make_app,
802+
tmp_path=tmp_path,
803+
)
804+
805+
806+
def test_admonition_with_code_block(
807+
make_app: Callable[..., SphinxTestApp],
808+
tmp_path: Path,
809+
) -> None:
810+
"""
811+
Test that admonitions can contain code blocks as nested children.
812+
"""
813+
rst_content = """
814+
.. note::
815+
This note contains a code example.
816+
817+
.. code-block:: python
818+
819+
def hello():
820+
print("Hello, world!")
821+
822+
The code above demonstrates a simple function.
823+
"""
824+
825+
callout = UnoCallout(text="", icon=Emoji(emoji="📝"), color=Color.BLUE)
826+
callout.rich_text = text(text="This note contains a code example.")
827+
828+
nested_code_block = _create_code_block_without_annotations(
829+
content='def hello():\n print("Hello, world!")',
830+
language=CodeLang.PYTHON,
831+
)
832+
nested_paragraph = UnoParagraph(
833+
text="The code above demonstrates a simple function."
834+
)
835+
836+
callout.obj_ref.value.children.append(nested_code_block.obj_ref) # pyright: ignore[reportUnknownMemberType]
837+
callout.obj_ref.value.children.append(nested_paragraph.obj_ref) # pyright: ignore[reportUnknownMemberType]
789838

790839
expected_objects: list[NotionObject[Any]] = [
791840
callout,
@@ -798,6 +847,48 @@ def test_admonition_multiline(
798847
)
799848

800849

850+
def test_admonition_with_code_block_first(
851+
make_app: Callable[..., SphinxTestApp],
852+
tmp_path: Path,
853+
) -> None:
854+
"""Test admonition with code block as first child (not paragraph).
855+
856+
This tests the else clause when first child is not a paragraph.
857+
"""
858+
rst_content = """
859+
.. note::
860+
861+
.. code-block:: python
862+
863+
def hello():
864+
print("Hello, world!")
865+
866+
This paragraph comes after the code block.
867+
"""
868+
869+
callout = UnoCallout(text="", icon=Emoji(emoji="📝"), color=Color.BLUE)
870+
callout.rich_text = text(text="")
871+
872+
nested_code_block = _create_code_block_without_annotations(
873+
content='def hello():\n print("Hello, world!")',
874+
language=CodeLang.PYTHON,
875+
)
876+
nested_paragraph = UnoParagraph(
877+
text="This paragraph comes after the code block."
878+
)
879+
880+
callout.obj_ref.value.children.append(nested_code_block.obj_ref) # pyright: ignore[reportUnknownMemberType]
881+
callout.obj_ref.value.children.append(nested_paragraph.obj_ref) # pyright: ignore[reportUnknownMemberType]
882+
883+
expected_objects: list[NotionObject[Any]] = [callout]
884+
_assert_rst_converts_to_notion_objects(
885+
rst_content=rst_content,
886+
expected_objects=expected_objects,
887+
make_app=make_app,
888+
tmp_path=tmp_path,
889+
)
890+
891+
801892
def test_nested_bullet_list(
802893
make_app: Callable[..., SphinxTestApp],
803894
tmp_path: Path,

0 commit comments

Comments
 (0)