diff --git a/docs/model_card.rst b/docs/model_card.rst index 0128a5e0..0afdb7d2 100644 --- a/docs/model_card.rst +++ b/docs/model_card.rst @@ -113,6 +113,19 @@ using :meth:`.Card.select`, and you can delete sections using To see how you can use the API in ``skops`` to create a model card, please refer to :ref:`sphx_glr_auto_examples_plot_model_card.py`. +You can also fold sections after adding them to the model card. This is useful +if you have a lot of content in a section that you don't want to show by +default. To fold a section, you can use the :attr:`.Section.folded` property: + +.. code-block:: python + + section = card.select("Model description/Figures") + section.folded = True + +After setting :attr:`.Section.folded` to ``True``, the section will be collapsed by default +when the model card is rendered. + + Saving and Loading Model Cards ------------------------------ diff --git a/skops/card/_model_card.py b/skops/card/_model_card.py index 32ba9b8c..12fc2057 100644 --- a/skops/card/_model_card.py +++ b/skops/card/_model_card.py @@ -207,6 +207,7 @@ class Section: content: str subsections: dict[str, Section] = field(default_factory=dict) visible: bool = True + folded: bool = False def select(self, key: str) -> Section: """Return a subsection or subsubsection of this section @@ -243,7 +244,7 @@ def select(self, key: str) -> Section: return section def format(self) -> str: - return self.content + return wrap_as_details(self.content, folded=self.folded) def __repr__(self) -> str: """Generates the ``repr`` of this section. @@ -1343,7 +1344,7 @@ def _generate_content( if destination_path is not None and isinstance(section, PlotSection): shutil.copy(section.path, destination_path) - if section.subsections: + if section.subsections and not section.folded: yield from self._generate_content( section.subsections, depth=depth + 1, diff --git a/skops/card/tests/test_card.py b/skops/card/tests/test_card.py index 9e625852..def12589 100644 --- a/skops/card/tests/test_card.py +++ b/skops/card/tests/test_card.py @@ -1918,6 +1918,50 @@ def test_toc_with_invisible_section(self, card): assert toc == "\n".join(exptected_toc) +class TestFoldedSection: + def test_folded_section(self, destination_path, model_card): + model_card.add(foo="Foo") + model_card.add(**{"foo/bar": "Foo/Bar", "foo/baz": "Foo/Baz"}) + model_card.select("foo/baz").folded = True + + foo_details = ( + "
\n Click to expand \n\nFoo\n\n
\n" + ) + foo_bar_details = ( + "
\n Click to expand \n\nFoo/Bar\n\n
\n" + ) + foo_baz_details = ( + "
\n Click to expand \n\nFoo/Baz\n\n
\n" + ) + + output = model_card.render() + assert foo_details not in output + assert foo_bar_details not in output + assert foo_baz_details in output + + model_card.select("foo").folded = True + + output = model_card.render() + assert foo_details in output + assert foo_bar_details not in output + assert foo_baz_details not in output + + model_card.select("foo").folded = False + + output = model_card.render() + assert foo_details not in output + assert foo_bar_details not in output + assert foo_baz_details in output + + model_card.select("foo/bar").folded = True + model_card.select("foo/baz").folded = False + + output = model_card.render() + assert foo_details not in output + assert foo_bar_details in output + assert foo_baz_details not in output + + class TestCardSaveWithPlots: def test_copy_plots(self, destination_path, model_card): import matplotlib.pyplot as plt