Skip to content

Fix from_dict() silently truncating dict keys that contain dots#349

Open
gaoflow wants to merge 1 commit into
chimpler:masterfrom
gaoflow:fix/from-dict-dotted-keys
Open

Fix from_dict() silently truncating dict keys that contain dots#349
gaoflow wants to merge 1 commit into
chimpler:masterfrom
gaoflow:fix/from-dict-dotted-keys

Conversation

@gaoflow

@gaoflow gaoflow commented Jun 25, 2026

Copy link
Copy Markdown

Problem

ConfigFactory.from_dict() calls ConfigTree.put(key, value) for each item in the input dictionary. put() passes the key through ConfigTree.parse_key(), which splits on HOCON path-separator characters — including . — treating them as a path rather than a literal key.

This means a Python dict key like "myThing_r0.1" is stored as a nested path myThing_r0 → 1, silently dropping everything after the last dot:

d = {"myStuff": {"myThing_r0.1": ["someVal"]}}
cfg = ConfigFactory.from_dict(d)
list(cfg["myStuff"].keys())  # ["myThing_r0"]  ← .1 silently dropped

Reported in issue #335.

Fix

Two minimal changes:

pyhocon/config_parser.pyfrom_dict() now calls res._put([key], …) instead of res.put(key, …). Passing the key as a single-element path list bypasses parse_key() entirely, so the Python dict key is stored verbatim.

pyhocon/config_tree.pyConfigTree.get() now first attempts an exact OrderedDict lookup before falling back to dotted-path traversal. This makes literal dotted keys stored by from_dict() accessible through the normal API (cfg["myThing_r0.1"], .items(), etc.) without breaking existing HOCON path traversal.

Testing

All 286 existing tests continue to pass. A new regression test (test_from_dict_preserves_dotted_keys) covers the reported scenario.

This pull request was prepared with the assistance of AI, under my direction and review.

ConfigTree.put() interprets dots in keys as HOCON path separators, so
from_dict({"a.b": v}) stored the value under the nested path a→b instead
of under the literal key "a.b", causing the dot-suffix to be silently dropped.

Two-part fix:
* config_parser.py: from_dict() now calls _put([key], …) with a
  single-element path, preserving the Python dict key verbatim.
* config_tree.py: ConfigTree.get() first attempts an exact (OrderedDict)
  lookup before falling back to dotted-path traversal, so literal dotted
  keys stored by from_dict() are accessible via the normal API.

All 286 existing tests still pass; a new regression test covers the case
reported in issue chimpler#335.

Fixes chimpler#335
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant