diff --git a/craft_application/models/base.py b/craft_application/models/base.py index 06bf17cb..6e7cce1e 100644 --- a/craft_application/models/base.py +++ b/craft_application/models/base.py @@ -16,7 +16,7 @@ """Base pydantic model for *craft applications.""" from __future__ import annotations -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING, Any, Type, cast import pydantic import yaml @@ -34,6 +34,17 @@ def _alias_generator(s: str) -> str: return s.replace("_", "-") +# pyright: reportUnknownMemberType=false +# Type of "represent_scalar" is "(tag: str, value: Unknown, style: str | None = None) +# -> +# ScalarNode" (reportUnknownMemberType) +def _repr_str(dumper: yaml.Dumper, data: str) -> yaml.ScalarNode: + """Multi-line string representer for the YAML dumper.""" + if "\n" in data: + return dumper.represent_scalar("tag:yaml.org,2002:str", data, style="|") + return dumper.represent_scalar("tag:yaml.org,2002:str", data) + + class CraftBaseConfig(pydantic.BaseConfig): # pylint: disable=too-few-public-methods """Pydantic model configuration.""" @@ -83,4 +94,7 @@ def from_yaml_file(cls, path: pathlib.Path) -> Self: def to_yaml_file(self, path: pathlib.Path) -> None: """Write this model to a YAML file.""" with path.open("wt") as file: + yaml.add_representer( + str, _repr_str, Dumper=cast(Type[yaml.Dumper], yaml.SafeDumper) + ) yaml.safe_dump(self.marshal(), file) diff --git a/tests/unit/models/project_models/full_project.yaml b/tests/unit/models/project_models/full_project.yaml index 3c389ba9..c7417487 100644 --- a/tests/unit/models/project_models/full_project.yaml +++ b/tests/unit/models/project_models/full_project.yaml @@ -1,6 +1,8 @@ base: core24 contact: author@project.org -description: A fully-defined craft-application project. (description) +description: | + A fully-defined craft-application project. + With more than one line. issues: https://github.com/canonical/craft-application/issues license: LGPLv3 name: full-project diff --git a/tests/unit/models/test_project.py b/tests/unit/models/test_project.py index 2175749a..d8155094 100644 --- a/tests/unit/models/test_project.py +++ b/tests/unit/models/test_project.py @@ -15,6 +15,7 @@ # along with this program. If not, see . """Tests for BaseProject""" import pathlib +from textwrap import dedent from typing import Optional import pytest @@ -44,14 +45,19 @@ issues="https://github.com/canonical/craft-application/issues", source_code="https://github.com/canonical/craft-application", # pyright: ignore[reportGeneralTypeIssues] summary="A fully-defined craft-application project.", # pyright: ignore[reportGeneralTypeIssues] - description="A fully-defined craft-application project. (description)", + description="A fully-defined craft-application project.\nWith more than one line.\n", license="LGPLv3", parts=PARTS_DICT, ) FULL_PROJECT_DICT = { "base": "core24", "contact": "author@project.org", - "description": "A fully-defined craft-application project. (description)", + "description": dedent( + """\ + A fully-defined craft-application project. + With more than one line. + """ + ), "issues": "https://github.com/canonical/craft-application/issues", "license": "LGPLv3", "name": "full-project",