Repository: chimpler/pyhocon

Issue:
ConfigFactory Parse File update after substitution incorrect
If I have a config called `test.conf`
```
test: {
  a: 1
  b: 2
}
test2: ${test}
test2.c: 3
```
I would expect
```
conf = ConfigFactory.parse_file("test.conf")
print(conf.get("test2"))
```
to print `{a:1, b:2, c:3}` but it just prints `{c:3}`. 

Discussion:
coveralls: 
[![Coverage Status](https://coveralls.io/builds/52759405/badge)](https://coveralls.io/builds/52759405)

Coverage decreased (-1.7%) to 94.413% when pulling **de87e8db9ddcc5a73b12ceef725a8e7391d9039b on USSX-Hares:bug/272-dict-substitution-fix** into **be660deb6d6a5a175d384792e208fd39986758ea on chimpler:master**.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/52759405/badge)](https://coveralls.io/builds/52759405)

Coverage decreased (-1.7%) to 94.413% when pulling **de87e8db9ddcc5a73b12ceef725a8e7391d9039b on USSX-Hares:bug/272-dict-substitution-fix** into **be660deb6d6a5a175d384792e208fd39986758ea on chimpler:master**.


Patch:
diff --git a/pyhocon/config_parser.py b/pyhocon/config_parser.py
index 6846589..52a06cb 100644
--- a/pyhocon/config_parser.py
+++ b/pyhocon/config_parser.py
@@ -125,6 +125,10 @@ def period(period_value, period_unit):
     return period_impl(**arguments)
 
 
+U_KEY_SEP = unicode('.')
+U_KEY_FMT = unicode('"{0}"')
+
+
 class ConfigFactory(object):
 
     @classmethod
@@ -868,6 +872,14 @@ class ConfigTreeParser(TokenConverter):
                         config_tree.put(key, value, False)
                     else:
                         existing_value = config_tree.get(key, None)
+                        parsed_key = ConfigTree.parse_key(key)
+                        key = parsed_key[0]
+                        if len(parsed_key) > 1:
+                            # Special case when the key contains path (i.e., `x.y = v`)
+                            new_value = ConfigTree()
+                            new_value.put(U_KEY_SEP.join(U_KEY_FMT.format(k) for k in parsed_key[1:]), value)
+                            value = new_value
+
                         if isinstance(value, ConfigTree) and not isinstance(existing_value, list):
                             # Only Tree has to be merged with tree
                             config_tree.put(key, value, True)
diff --git a/setup.py b/setup.py
index dad12e4..2d6b631 100755
--- a/setup.py
+++ b/setup.py
@@ -52,7 +52,10 @@ setup(
     packages=[
         'pyhocon',
     ],
-    install_requires=['pyparsing~=2.0'],
+    install_requires=[
+        'pyparsing~=2.0;python_version<"3.0"',
+        'pyparsing>=2,<4;python_version>="3.0"',
+    ],
     extras_require={
         'Duration': ['python-dateutil>=2.8.0']
     },


Test patch:
diff --git a/tests/test_config_parser.py b/tests/test_config_parser.py
index 13a130f..c4ce46a 100644
--- a/tests/test_config_parser.py
+++ b/tests/test_config_parser.py
@@ -19,7 +19,6 @@ try:
 except Exception:
     from datetime import timedelta as period
 
-
 class TestConfigParser(object):
     def test_parse_simple_value(self):
         config = ConfigFactory.parse_string(
@@ -606,6 +605,58 @@ class TestConfigParser(object):
             'cluster-size': 6
         }
 
+    def test_dict_substitutions2(self):
+        config = ConfigFactory.parse_string(
+            """
+                data-center-generic = { cluster-size = 6 }
+                data-center-east = ${data-center-generic}
+                data-center-east.name = "east"
+            """
+        )
+
+        assert config.get('data-center-east.cluster-size') == 6
+        assert config.get('data-center-east.name') == 'east'
+
+        config2 = ConfigFactory.parse_string(
+            """
+                data-center-generic = { cluster-size = 6 }
+                data-center-east.name = "east"
+                data-center-east = ${data-center-generic}
+            """
+        )
+
+        assert config2.get('data-center-east.cluster-size') == 6
+        assert config2.get('data-center-east.name') == 'east'
+
+        config3 = ConfigFactory.parse_string(
+            """
+                data-center-generic = { cluster-size = 6 }
+                data-center-east.name = "east"
+                data-center-east = ${data-center-generic}
+                data-center-east.cluster-size = 9
+                data-center-east.opts = "-Xmx4g"
+            """
+        )
+
+        assert config3.get('data-center-east.cluster-size') == 9
+        assert config3.get('data-center-east.name') == 'east'
+        assert config3.get('data-center-east.opts') == '-Xmx4g'
+
+        config4 = ConfigFactory.parse_string(
+            """
+                data-center-generic = { cluster-size = 6 }
+                data-center-east.name = "east"
+                data-center-east = ${data-center-generic}
+                data-center-east-prod = ${data-center-east}
+                data-center-east-prod.tmpDir=/tmp
+            """
+        )
+
+        assert config4.get('data-center-east.cluster-size') == 6
+        assert config4.get('data-center-east.name') == 'east'
+        assert config4.get('data-center-east-prod.cluster-size') == 6
+        assert config4.get('data-center-east-prod.tmpDir') == '/tmp'
+
     def test_dos_chars_with_unquoted_string_noeol(self):
         config = ConfigFactory.parse_string("foo = bar")
         assert config['foo'] == 'bar'