From 18366684f4bf3455beb310032a97eabd871ff514 Mon Sep 17 00:00:00 2001 From: Benjamin Bossan Date: Thu, 16 Mar 2023 14:35:41 +0100 Subject: [PATCH] ENH: Default section for add_* methods Description The add_* methods for Card now have default sections (the one used in the skops template) and no longer set descriptions by default. None is no longer a valid argument for section. This is useful because it allows us to completely remove all the template checks in the diverse add_* methods. Before this change, every add_* method had to check the template and if it was a custom template, would raise an error when the section is not indicated. All methods have been homogenized in that they no longer add a description by default and put a placeholder there if empty. This means that after this PR is merged, the same code will sometimes produce a different looking model card. Comment For the Card class, this is a nice simplification of the code. The main change affects the unit tests. All tests that used to raise when using a custom template without a section argument no longer raise but use the default template. Furthermore, since some default descriptions have been removed, other tests had to be touched too. Apart from that, some minor cleanups in the tests. --- docs/changes.rst | 3 + skops/card/_model_card.py | 96 +++++---------- skops/card/_templates.py | 4 +- skops/card/tests/test_card.py | 214 +++++++++++++++++----------------- 4 files changed, 139 insertions(+), 178 deletions(-) diff --git a/docs/changes.rst b/docs/changes.rst index 2a6438a3..bf0d29ea 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -22,6 +22,9 @@ v0.6 `Benjamin Bossan`_. - Fix: skops persistence now also works with many functions from the :mod:`operator` module. :pr:`287` by `Benjamin Bossan`_. +- ``add_*`` methods on :class:`.Card` now have default section names (but + ``None`` is no longer valid) and no longer add descriptions by default. + :pr:`321` by `Benjamin Bossan`_. v0.5 ---- diff --git a/skops/card/_model_card.py b/skops/card/_model_card.py index 42931031..5ab5b25f 100644 --- a/skops/card/_model_card.py +++ b/skops/card/_model_card.py @@ -791,7 +791,7 @@ def _add_single(self, key: str, val: str | Section) -> Section: def add_model_plot( self, - section: str | None = None, + section: str = "Model description/Training Procedure/Model Plot", description: str | None = None, ) -> Self: """Add a model plot @@ -805,11 +805,10 @@ def add_model_plot( Parameters ---------- - section : str or None, default=None - The section that the model plot should be added to. If you're using - the default skops template, you can leave this parameter as - ``None``, otherwise you have to indicate the section. If the section - does not exist, it will be created for you. + section : str (default="Model description/Training Procedure/Model Plot") + The section that the model plot should be added to. By default, the + section is set to fit the skops model card template. If you're using + a different template, you may have to choose a different section name. description : str or None, default=None An optional description to be added before the model plot. If you're @@ -821,18 +820,8 @@ def add_model_plot( ------- self : object Card object. - """ - if section is None: - if self.template == Templates.skops.value: - section = "Model description/Training Procedure/Model Plot" - else: - msg = NEED_SECTION_ERR_MSG.format(action="add a model plot") - raise ValueError(msg) - - if description is None: - if self.template == Templates.skops.value: - description = "The model plot is below." + """ self._add_model_plot( self.get_model(), section_name=section, description=description ) @@ -864,17 +853,19 @@ def _add_model_plot( self._add_single(section_name, section) def add_hyperparams( - self, section: str | None = None, description: str | None = None + self, + section: str = "Model description/Training Procedure/Hyperparameters", + description: str | None = None, ) -> Self: """Add the model's hyperparameters as a table Parameters ---------- - section : str or None, default=None - The section that the hyperparamters should be added to. If you're - using the default skops template, you can leave this parameter as - ``None``, otherwise you have to indicate the section. If the section - does not exist, it will be created for you. + section : str (default="Model description/Training Procedure/Hyperparameters") + The section that the hyperparameters should be added to. By default, + the section is set to fit the skops model card template. If you're + using a different template, you may have to choose a different section + name. description : str or None, default=None An optional description to be added before the hyperparamters. If @@ -888,17 +879,6 @@ def add_hyperparams( Card object. """ - if section is None: - if self.template == Templates.skops.value: - section = "Model description/Training Procedure/Hyperparameters" - else: - msg = NEED_SECTION_ERR_MSG.format(action="add model hyperparameters") - raise ValueError(msg) - - if description is None: - if self.template == Templates.skops.value: - description = "The model is trained with below hyperparameters." - self._add_hyperparams( self.get_model(), section_name=section, description=description ) @@ -924,7 +904,7 @@ def _add_hyperparams( def add_get_started_code( self, - section: str | None = None, + section: str = "How to Get Started with the Model", description: str | None = None, file_name: str | None = None, model_format: Literal["pickle", "skops"] | None = None, @@ -936,11 +916,11 @@ def add_get_started_code( Parameters ---------- - section : str or None, default=None - The section that the code should be added to. If you're using the - default skops template, you can leave this parameter as ``None``, - otherwise you have to indicate the section. If the section does not - exist, it will be created for you. + section : str (default="How to Get Started with the Model") + The section that the code for loading the model should be added to. + By default, the section is set to fit the skops model card template. + If you're using a different template, you may have to choose a + different section name. description : str or None, default=None An optional description to be added before the code. If you're using @@ -984,17 +964,6 @@ def add_get_started_code( if (not file_name) or (not model_format): return self - if section is None: - if self.template == Templates.skops.value: - section = "How to Get Started with the Model" - else: - msg = NEED_SECTION_ERR_MSG.format(action="add get started code") - raise ValueError(msg) - - if description is None: - if self.template == Templates.skops.value: - description = "Use the code below to get started with the model." - self._add_get_started_code( section, file_name=file_name, @@ -1157,7 +1126,7 @@ def add_table( def add_metrics( self, - section: str | None = None, + section: str = "Model description/Evaluation Results", description: str | None = None, **kwargs: str | int | float, ) -> Self: @@ -1167,11 +1136,10 @@ def add_metrics( Parameters ---------- - section : str or None, default=None - The section that the metrics should be added to. If you're using the - default skops template, you can leave this parameter as ``None``, - otherwise you have to indicate the section. If the section does not - exist, it will be created for you. + section : str (default="Model description/Evaluation Results") + The section that metrics should be added to. By default, the section + is set to fit the skops model card template. If you're using a + different template, you may have to choose a different section name. description : str or None, default=None An optional description to be added before the metrics. If you're @@ -1186,20 +1154,8 @@ def add_metrics( ------- self : object Card object. - """ - if section is None: - if self.template == Templates.skops.value: - section = "Model description/Evaluation Results" - else: - msg = NEED_SECTION_ERR_MSG.format(action="add metrics") - raise ValueError(msg) - if description is None: - if self.template == Templates.skops.value: - description = ( - "You can find the details about evaluation process and " - "the evaluation results." - ) + """ self._metrics.update(kwargs) self._add_metrics(section, description=description, metrics=self._metrics) return self diff --git a/skops/card/_templates.py b/skops/card/_templates.py index d30a39a7..e343c427 100644 --- a/skops/card/_templates.py +++ b/skops/card/_templates.py @@ -35,9 +35,9 @@ class Templates(Enum): SKOPS_TEMPLATE = { "Model description": CONTENT_PLACEHOLDER, "Model description/Intended uses & limitations": CONTENT_PLACEHOLDER, - "Model description/Training Procedure": "", + "Model description/Training Procedure": CONTENT_PLACEHOLDER, "Model description/Training Procedure/Hyperparameters": CONTENT_PLACEHOLDER, - "Model description/Training Procedure/Model Plot": "The model plot is below.", + "Model description/Training Procedure/Model Plot": CONTENT_PLACEHOLDER, "Model description/Evaluation Results": CONTENT_PLACEHOLDER, "How to Get Started with the Model": CONTENT_PLACEHOLDER, "Model Card Authors": ( diff --git a/skops/card/tests/test_card.py b/skops/card/tests/test_card.py index 82043bba..7a3dfb27 100644 --- a/skops/card/tests/test_card.py +++ b/skops/card/tests/test_card.py @@ -18,6 +18,7 @@ from skops import hub_utils from skops.card import Card, metadata_from_config from skops.card._model_card import ( + CONTENT_PLACEHOLDER, SKOPS_TEMPLATE, PlotSection, Section, @@ -153,9 +154,9 @@ class TestAddModelPlot: def test_default(self, model_card): result = model_card.select( "Model description/Training Procedure/Model Plot" - ).content + ).format() # don't compare whole text, as it's quite long and non-deterministic - assert result.startswith("The model plot is below.\n\n