diff --git a/CHANGELOG.md b/CHANGELOG.md index 488c8e7..842c69f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- Changed `style` parameter on `indented_text()` and `RemediationReporter.to_text()` from `str` to `Literal["without_comments", "merged", "with_comments"]` via new `TextStyle` type alias (#189). - Renamed `load_hconfig_v2_options` to `load_driver_rules` (#221). - Renamed `load_hconfig_v2_tags` to `load_tag_rules` (#221). - Renamed `tags_add()`/`tags_remove()` to `add_tags()`/`remove_tags()` (#216). diff --git a/hier_config/__init__.py b/hier_config/__init__.py index c56ec3e..ec8d8e1 100644 --- a/hier_config/__init__.py +++ b/hier_config/__init__.py @@ -13,7 +13,7 @@ IncompatibleDriverError, InvalidConfigError, ) -from .models import ChangeDetail, MatchRule, Platform, ReportSummary, TagRule +from .models import ChangeDetail, MatchRule, Platform, ReportSummary, TagRule, TextStyle from .reporting import RemediationReporter from .root import HConfig from .workflows import WorkflowRemediation @@ -32,6 +32,7 @@ "RemediationReporter", "ReportSummary", "TagRule", + "TextStyle", "WorkflowRemediation", "get_hconfig", "get_hconfig_driver", diff --git a/hier_config/child.py b/hier_config/child.py index fada308..513bd6a 100644 --- a/hier_config/child.py +++ b/hier_config/child.py @@ -6,7 +6,7 @@ from typing import TYPE_CHECKING, Any from .base import HConfigBase -from .models import Instance, MatchRule, SetLikeOfStr +from .models import Instance, MatchRule, SetLikeOfStr, TextStyle if TYPE_CHECKING: from collections.abc import Iterable, Iterator @@ -180,7 +180,7 @@ def path(self) -> Iterator[str]: def indented_text( self, - style: str = "without_comments", + style: TextStyle = "without_comments", tag: str | None = None, ) -> str: """Return an indented text line i.e. indentation_level + text ! comments.""" diff --git a/hier_config/models.py b/hier_config/models.py index c69f08a..cb5da59 100644 --- a/hier_config/models.py +++ b/hier_config/models.py @@ -1,8 +1,11 @@ from enum import Enum, auto +from typing import Literal from pydantic import BaseModel as PydanticBaseModel from pydantic import ConfigDict, NonNegativeInt, PositiveInt +TextStyle = Literal["without_comments", "merged", "with_comments"] + class BaseModel(PydanticBaseModel): """Pydantic.BaseModel with a safe config applied.""" diff --git a/hier_config/reporting.py b/hier_config/reporting.py index 8b55b51..b9949a0 100644 --- a/hier_config/reporting.py +++ b/hier_config/reporting.py @@ -14,7 +14,7 @@ from typing import Any from hier_config.child import HConfigChild -from hier_config.models import ChangeDetail, ReportSummary, TagRule +from hier_config.models import ChangeDetail, ReportSummary, TagRule, TextStyle from hier_config.root import HConfig @@ -637,7 +637,7 @@ def to_text( self, file_path: str | Path, *, - style: str = "merged", + style: TextStyle = "merged", include_tags: Iterable[str] = (), exclude_tags: Iterable[str] = (), ) -> None: diff --git a/tests/unit/test_child.py b/tests/unit/test_child.py index 711f9ae..cbc314c 100644 --- a/tests/unit/test_child.py +++ b/tests/unit/test_child.py @@ -1255,3 +1255,29 @@ def test_child_dict_key_lookup_with_order_weight() -> None: lookup: dict[HConfigChild, str] = {child1: "found"} # child2 is equal to child1, so it must find the same dict entry assert lookup[child2] == "found" + + +def test_indented_text_style_literal_values() -> None: + """Test that indented_text accepts each valid TextStyle literal value.""" + platform = Platform.CISCO_IOS + config = get_hconfig(platform) + child = config.add_child("interface GigabitEthernet0/0") + child.comments.add("a comment") + + # without_comments: should NOT include the comment + result_without = child.indented_text(style="without_comments") + assert "interface GigabitEthernet0/0" in result_without + assert "!" not in result_without + + # with_comments: should include the comment + result_with = child.indented_text(style="with_comments") + assert "interface GigabitEthernet0/0" in result_with + assert "!a comment" in result_with + + # merged: should include instance count info + instance = Instance( + id=1, comments=frozenset(["inst comment"]), tags=frozenset(["tag1"]) + ) + child.instances.append(instance) + result_merged = child.indented_text(style="merged") + assert "1 instance" in result_merged