Skip to content

Commit b546c77

Browse files
committed
feat(cfn-lang-ext): add jmespath-aware property get/set helpers
1 parent 9006343 commit b546c77

2 files changed

Lines changed: 45 additions & 0 deletions

File tree

samcli/lib/package/language_extensions_packaging.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,14 @@
88

99
import copy
1010
import itertools
11+
import jmespath
1112
import logging
1213
import re
1314
from collections import Counter
1415
from typing import Any, Dict, List, Optional, Tuple
1516

1617
import click
18+
from botocore.utils import set_value_from_jmespath
1719

1820
from samcli.lib.cfn_language_extensions.models import (
1921
PACKAGEABLE_RESOURCE_ARTIFACT_PROPERTIES,
@@ -118,6 +120,22 @@ def generate_and_apply_artifact_mappings(
118120
return _apply_artifact_mappings_to_template(template, mappings, dynamic_properties, property_to_mapping)
119121

120122

123+
def _get_prop_value(props: Dict[str, Any], prop_name: str) -> Optional[Any]:
124+
"""Read a property by jmespath path. Supports flat keys ("CodeUri") and
125+
dotted paths ("Command.ScriptLocation"). Returns None if missing.
126+
"""
127+
if not isinstance(props, dict):
128+
return None
129+
return jmespath.search(prop_name, props)
130+
131+
132+
def _set_prop_value(props: Dict[str, Any], prop_name: str, value: Any) -> None:
133+
"""Write a property by jmespath path. Creates intermediate dicts as needed.
134+
Supports flat keys and dotted paths.
135+
"""
136+
set_value_from_jmespath(props, prop_name, value)
137+
138+
121139
# ---------------------------------------------------------------------------
122140
# Merge helpers
123141
# ---------------------------------------------------------------------------

tests/unit/commands/package/test_package_context.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -975,6 +975,33 @@ def test_apply_artifact_mappings_to_template_integration(self):
975975
code_uri = body["${Name}Service"]["Properties"]["CodeUri"]
976976
self.assertEqual(code_uri, {"Fn::FindInMap": ["SAMCodeUriServices", {"Ref": "Name"}, "CodeUri"]})
977977

978+
def test_get_prop_value_flat_key(self):
979+
from samcli.lib.package.language_extensions_packaging import _get_prop_value
980+
self.assertEqual(_get_prop_value({"CodeUri": "s3://b/k"}, "CodeUri"), "s3://b/k")
981+
982+
def test_get_prop_value_dotted_key(self):
983+
from samcli.lib.package.language_extensions_packaging import _get_prop_value
984+
props = {"Command": {"ScriptLocation": "s3://b/k.py"}}
985+
self.assertEqual(_get_prop_value(props, "Command.ScriptLocation"), "s3://b/k.py")
986+
987+
def test_get_prop_value_missing_returns_none(self):
988+
from samcli.lib.package.language_extensions_packaging import _get_prop_value
989+
self.assertIsNone(_get_prop_value({"CodeUri": "x"}, "Command.ScriptLocation"))
990+
991+
def test_set_prop_value_flat_key(self):
992+
from samcli.lib.package.language_extensions_packaging import _set_prop_value
993+
props = {"CodeUri": "./src"}
994+
_set_prop_value(props, "CodeUri", "s3://b/k")
995+
self.assertEqual(props["CodeUri"], "s3://b/k")
996+
997+
def test_set_prop_value_dotted_key_creates_intermediate(self):
998+
from samcli.lib.package.language_extensions_packaging import _set_prop_value
999+
props = {"Command": {"Name": "glueetl"}}
1000+
_set_prop_value(props, "Command.ScriptLocation", "s3://b/k.py")
1001+
self.assertEqual(props["Command"]["ScriptLocation"], "s3://b/k.py")
1002+
# Existing keys preserved
1003+
self.assertEqual(props["Command"]["Name"], "glueetl")
1004+
9781005

9791006
class TestPackageContextMappingsIntegration(TestCase):
9801007
"""Test cases for the complete Mappings transformation integration in _export()"""

0 commit comments

Comments
 (0)