From 62242b290d72ba1461d311fd561d9899a1e30c50 Mon Sep 17 00:00:00 2001 From: Thomas Lazarus Date: Sun, 9 Apr 2023 20:01:17 -0500 Subject: [PATCH 1/7] Updates Section class and adds test stub --- skops/card/_model_card.py | 32 +++++++++++++++++++++++++++++++- skops/card/tests/test_card.py | 5 +++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/skops/card/_model_card.py b/skops/card/_model_card.py index 1e54fc0e..e4450cc2 100644 --- a/skops/card/_model_card.py +++ b/skops/card/_model_card.py @@ -204,6 +204,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 @@ -239,9 +240,12 @@ def select(self, key: str) -> Section: section = section.subsections[section_name] return section - def format(self) -> str: + def _format(self) -> str: return self.content + def format(self) -> str: + return wrap_as_details(self._format(), folded=self.folded) + def __repr__(self) -> str: """Generates the ``repr`` of this section. @@ -250,6 +254,32 @@ def __repr__(self) -> str: """ return self.content + @property + def folded(self) -> bool: + """Return the folded state of this section. + + Returns + ------- + folded : bool + Whether this section is folded or not. + + """ + return self._folded + + @folded.setter + def folded(self, folded: bool) -> None: + """Set the folded state of this section. + + Parameters + ---------- + folded : bool + Whether to fold this section or not. + + """ + self._folded = folded + for section in self.subsections.values(): + section.folded = folded + @dataclass class PlotSection(Section): diff --git a/skops/card/tests/test_card.py b/skops/card/tests/test_card.py index 7a3dfb27..79466b1f 100644 --- a/skops/card/tests/test_card.py +++ b/skops/card/tests/test_card.py @@ -1887,3 +1887,8 @@ def test_toc_with_invisible_section(self, card): ] assert toc == "\n".join(exptected_toc) + + +# TODO: Add tests for the following classes +class TestFoldedSection: + pass From 81b3a5affde1099f495cd16758bc4d381ac14ea7 Mon Sep 17 00:00:00 2001 From: Thomas Lazarus Date: Tue, 2 May 2023 19:56:39 -0500 Subject: [PATCH 2/7] Removes getter and setter and added `set_folded` instead. Also adds the test to make sure subsections are getting folded and unfolded --- skops/card/_model_card.py | 24 +++++------------------- skops/card/tests/test_card.py | 26 ++++++++++++++++++++++++-- 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/skops/card/_model_card.py b/skops/card/_model_card.py index e4450cc2..3d247c44 100644 --- a/skops/card/_model_card.py +++ b/skops/card/_model_card.py @@ -244,7 +244,7 @@ def _format(self) -> str: return self.content def format(self) -> str: - return wrap_as_details(self._format(), folded=self.folded) + return wrap_as_details(self._format(), folded=self._folded) def __repr__(self) -> str: """Generates the ``repr`` of this section. @@ -254,31 +254,17 @@ def __repr__(self) -> str: """ return self.content - @property - def folded(self) -> bool: - """Return the folded state of this section. - - Returns - ------- - folded : bool - Whether this section is folded or not. - - """ - return self._folded - - @folded.setter - def folded(self, folded: bool) -> None: - """Set the folded state of this section. + def set_folded(self, folded: bool) -> None: + """Set the folded state of this section and children sections. Parameters ---------- folded : bool - Whether to fold this section or not. - + Whether this section should be folded or not. """ self._folded = folded for section in self.subsections.values(): - section.folded = folded + section.set_folded(folded) @dataclass diff --git a/skops/card/tests/test_card.py b/skops/card/tests/test_card.py index 79466b1f..0f8f873e 100644 --- a/skops/card/tests/test_card.py +++ b/skops/card/tests/test_card.py @@ -1889,6 +1889,28 @@ def test_toc_with_invisible_section(self, card): assert toc == "\n".join(exptected_toc) -# TODO: Add tests for the following classes class TestFoldedSection: - pass + def test_folded_section(self, model_card): + model_card.add(foo="Foo") + model_card.add(**{"foo/bar": "Foo/Bar"}) + model_card.add(**{"foo/baz": "Foo/Baz"}) + foo_baz = model_card.select("foo/baz") + foo_baz.set_folded(True) + foo = model_card.select("foo") + foo_bar = model_card.select("foo/bar") + + assert foo._folded is False + assert foo_bar._folded is False + assert foo_baz._folded is True + + model_card.select("foo").set_folded(True) + + assert foo._folded is True + assert foo_bar._folded is True + assert foo_baz._folded is True + + model_card.select("foo").set_folded(False) + + assert foo._folded is False + assert foo_bar._folded is False + assert foo_baz._folded is False From 5491b5383f357152d2c82daad744565f77c393f8 Mon Sep 17 00:00:00 2001 From: Thomas Lazarus Date: Tue, 16 May 2023 20:41:52 -0500 Subject: [PATCH 3/7] WIP Doesn't change child sections folded attribute --- skops/card/_model_card.py | 18 +++--------------- skops/card/tests/test_card.py | 33 ++++++++++++++++----------------- 2 files changed, 19 insertions(+), 32 deletions(-) diff --git a/skops/card/_model_card.py b/skops/card/_model_card.py index fd37309a..b3e0c51f 100644 --- a/skops/card/_model_card.py +++ b/skops/card/_model_card.py @@ -206,7 +206,7 @@ class Section: content: str subsections: dict[str, Section] = field(default_factory=dict) visible: bool = True - _folded: bool = False + folded: bool = False def select(self, key: str) -> Section: """Return a subsection or subsubsection of this section @@ -246,7 +246,7 @@ def _format(self) -> str: return self.content def format(self) -> str: - return wrap_as_details(self._format(), folded=self._folded) + return wrap_as_details(self._format(), folded=self.folded) def __repr__(self) -> str: """Generates the ``repr`` of this section. @@ -256,18 +256,6 @@ def __repr__(self) -> str: """ return self.content - def set_folded(self, folded: bool) -> None: - """Set the folded state of this section and children sections. - - Parameters - ---------- - folded : bool - Whether this section should be folded or not. - """ - self._folded = folded - for section in self.subsections.values(): - section.set_folded(folded) - @dataclass class PlotSection(Section): @@ -1352,7 +1340,7 @@ def _generate_content( yield section.format() - if section.subsections: + if section.subsections and not section.folded: yield from self._generate_content(section.subsections, depth=depth + 1) def _iterate_content( diff --git a/skops/card/tests/test_card.py b/skops/card/tests/test_card.py index c0a94558..53e4eacc 100644 --- a/skops/card/tests/test_card.py +++ b/skops/card/tests/test_card.py @@ -1921,25 +1921,24 @@ def test_toc_with_invisible_section(self, card): class TestFoldedSection: def test_folded_section(self, model_card): model_card.add(foo="Foo") - model_card.add(**{"foo/bar": "Foo/Bar"}) - model_card.add(**{"foo/baz": "Foo/Baz"}) - foo_baz = model_card.select("foo/baz") - foo_baz.set_folded(True) - foo = model_card.select("foo") - foo_bar = model_card.select("foo/bar") + model_card.add(**{"foo/bar": "Foo/Bar", "foo/baz": "Foo/Baz"}) + model_card.select("foo/baz").folded = True - assert foo._folded is False - assert foo_bar._folded is False - assert foo_baz._folded is True + output = model_card.render() + assert "Foo" in output + assert "Foo/Bar" in output + assert "Foo/Baz" not in output - model_card.select("foo").set_folded(True) + model_card.select("foo").folded = True - assert foo._folded is True - assert foo_bar._folded is True - assert foo_baz._folded is True + output = model_card.render() + assert "Foo" in output + assert "Foo/Bar" in output + assert "Foo/Baz" in output - model_card.select("foo").set_folded(False) + model_card.select("foo").folded = False - assert foo._folded is False - assert foo_bar._folded is False - assert foo_baz._folded is False + output = model_card.render() + assert "Foo" not in output + assert "Foo/Bar" not in output + assert "Foo/Baz" not in output From 15ad2fa4bb3e57a8d3269eade2244a08ae4edc2f Mon Sep 17 00:00:00 2001 From: Thomas Lazarus Date: Tue, 23 May 2023 20:06:41 -0500 Subject: [PATCH 4/7] Updates test to check if folded Checks by seeing if
is around the section title when folded --- skops/card/tests/test_card.py | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/skops/card/tests/test_card.py b/skops/card/tests/test_card.py index 14e15d55..be3d4be9 100644 --- a/skops/card/tests/test_card.py +++ b/skops/card/tests/test_card.py @@ -1919,31 +1919,41 @@ def test_toc_with_invisible_section(self, card): class TestFoldedSection: - def test_folded_section(self, model_card): + 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" in output - assert "Foo/Bar" in output - assert "Foo/Baz" not in output + 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" in output - assert "Foo/Bar" in output - assert "Foo/Baz" in output + 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" not in output - assert "Foo/Bar" not in output - assert "Foo/Baz" not in output + assert foo_details not in output + assert foo_bar_details not in output + assert foo_baz_details in output + - class TestCardSaveWithPlots: def test_copy_plots(self, destination_path, model_card): import matplotlib.pyplot as plt From 427dc53df89bfb4a6270e104563867c032790b34 Mon Sep 17 00:00:00 2001 From: Thomas Lazarus Date: Tue, 30 May 2023 12:14:30 -0500 Subject: [PATCH 5/7] Updates test and adds documentation --- docs/model_card.rst | 11 +++++++++++ skops/card/_model_card.py | 5 +---- skops/card/tests/test_card.py | 8 ++++++++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/docs/model_card.rst b/docs/model_card.rst index 0128a5e0..50eca0f9 100644 --- a/docs/model_card.rst +++ b/docs/model_card.rst @@ -113,6 +113,17 @@ 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 :meth:`.Section.folded` property: + +.. code-block:: python + + section = card.select("Model description/Figures") + section.folded = True + section.format() # This will now return the section in a folded state + + Saving and Loading Model Cards ------------------------------ diff --git a/skops/card/_model_card.py b/skops/card/_model_card.py index 60fdee98..12fc2057 100644 --- a/skops/card/_model_card.py +++ b/skops/card/_model_card.py @@ -243,11 +243,8 @@ def select(self, key: str) -> Section: section = section.subsections[section_name] return section - def _format(self) -> str: - return self.content - def format(self) -> str: - return wrap_as_details(self._format(), folded=self.folded) + return wrap_as_details(self.content, folded=self.folded) def __repr__(self) -> str: """Generates the ``repr`` of this section. diff --git a/skops/card/tests/test_card.py b/skops/card/tests/test_card.py index be3d4be9..def12589 100644 --- a/skops/card/tests/test_card.py +++ b/skops/card/tests/test_card.py @@ -1953,6 +1953,14 @@ def test_folded_section(self, destination_path, model_card): 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): From bc93a3dd96e21fb6c44bdc92d1f74091f6a0858e Mon Sep 17 00:00:00 2001 From: Thomas Lazarus Date: Tue, 30 May 2023 12:38:26 -0500 Subject: [PATCH 6/7] Fixes sphinx documentation --- docs/model_card.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/model_card.rst b/docs/model_card.rst index 50eca0f9..dfeb85eb 100644 --- a/docs/model_card.rst +++ b/docs/model_card.rst @@ -115,7 +115,7 @@ 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 :meth:`.Section.folded` property: +default. To fold a section, you can use the :attr:`.Section.folded` property: .. code-block:: python From d3a7b6d632073a77a338109006554739a3381baf Mon Sep 17 00:00:00 2001 From: Thomas Lazarus Date: Wed, 31 May 2023 11:17:23 -0500 Subject: [PATCH 7/7] Updated documentation --- docs/model_card.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/model_card.rst b/docs/model_card.rst index dfeb85eb..0afdb7d2 100644 --- a/docs/model_card.rst +++ b/docs/model_card.rst @@ -121,7 +121,9 @@ default. To fold a section, you can use the :attr:`.Section.folded` property: section = card.select("Model description/Figures") section.folded = True - section.format() # This will now return the section in a folded state + +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