Skip to content

Commit

Permalink
Update ConfitYamlLoader to preserve quotes around values and handle t…
Browse files Browse the repository at this point in the history
…hem correctly during parsing.
  • Loading branch information
LucasDedieu committed Dec 17, 2024
1 parent 3ab4e4d commit 5a536a3
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 14 deletions.
3 changes: 2 additions & 1 deletion confit/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,10 +141,11 @@ def from_cfg_str(cls, s: str, resolve: bool = False, registry: Any = None) -> An
@classmethod
def from_yaml_str(cls, s: str, resolve: bool = False, registry: Any = None) -> Any:
import yaml

class ConfitYamlLoader(yaml.SafeLoader):
def construct_object(self, x, deep=False):
if isinstance(x, yaml.ScalarNode):
if x.style == '"' or x.style == "'":
return loads(x.style+x.value+x.style)
return loads(x.value)
return super().construct_object(x, deep)

Expand Down
19 changes: 7 additions & 12 deletions confit/utils/xjson.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,24 +260,19 @@ def __init__(self, value: str):

def loads(s: str):
"""
Load an extended JSON string into a python object.
Handles references and tuples, and detects malformed objects.
Load an extended JSON string into a Python object.
Handles references, tuples, and detects malformed objects.
"""
try:
return XJsonTransformer(s).transform(_json_parser.parse(s))
except Exception:
# Detect malformed strings with unmatched quotes
if (s.startswith("'") and not s.endswith("'")) or (
s.startswith('"') and not s.endswith('"')
):
raise MalformedValueError(s)

# Detect suspicious malformed patterns
if any(char in s for char in ",{}[]") and not s.startswith(("'", '"')):
# Fail if we suspect that it is a malformed object
# (e.g. has ', ", {, }, [, ] in it)
if set(s) & set(",'\"{}[]$"):
raise MalformedValueError(s)

return s


def dumps(o: Any):
"""
Expand Down
20 changes: 19 additions & 1 deletion tests/test_config_instance.py
Original file line number Diff line number Diff line change
Expand Up @@ -694,5 +694,23 @@ def test_very_long_yaml_config():
""".format(
"x" * 4200
)
)
).resolve(registry=registry)
assert config == {"a": "x" * 4200}


def test_escaped_string():
config = Config.from_yaml_str("""
test:
a: "1"
section:
num: 1
escaped_num: "1"
real_ref: ${test.a}
escaped_broken_ref: "${test.a"
escaped_ref: "${test.a}"
""").resolve(registry=registry)
assert config["section"]["num"] == 1
assert config["section"]["escaped_num"] == "1"
assert config["section"]["real_ref"] == "1"
assert config["section"]["escaped_broken_ref"] == "${test.a"
assert config["section"]["escaped_ref"] == "${test.a}"

0 comments on commit 5a536a3

Please sign in to comment.