Repository: fabiocaccamo/python-benedict

Issue:
`from_ini()` returns a `str` instead of a `dict`
**Python version**
Python 3.11.0

**Package version**
python-benedict==0.30.0

**Current behavior (bug description)**
```python
from benedict import benedict

original = benedict({
    'section1': {'key1': 'value1'},
    'sectionA': {'keyA': 'valueA', 'keyB': 'valueB', 'keyC': {'subkeyC': 'subvalueC'}},
})

readback = benedict.from_ini(original.to_ini())


print('original vs readback')

path = 'sectionA.keyC'

print(original.get(path), type(original.get(path)))
print('-- vs --')
print(readback.get(path), type(readback.get(path)))
````
**output**
```cmd
original vs readback
{'subkeyC': 'subvalueC'} <class 'benedict.dicts.benedict'>
-- vs --
{'subkeyC': 'subvalueC'} <class 'str'>
```
**Expected behavior**
value type of the _keyC_ is a dict not a string

Discussion:

Patch:
diff --git a/benedict/serializers/ini.py b/benedict/serializers/ini.py
index 2903c9c..5b7fc41 100644
--- a/benedict/serializers/ini.py
+++ b/benedict/serializers/ini.py
@@ -1,8 +1,10 @@
 from configparser import DEFAULTSECT as default_section
 from configparser import RawConfigParser
 from io import StringIO
+from json.decoder import JSONDecodeError
 
 from benedict.serializers.abstract import AbstractSerializer
+from benedict.serializers.json import JSONSerializer
 from benedict.utils import type_util
 
 
@@ -17,6 +19,7 @@ class INISerializer(AbstractSerializer):
                 "ini",
             ],
         )
+        self._json = JSONSerializer()
 
     @staticmethod
     def _get_parser(options):
@@ -49,9 +52,14 @@ class INISerializer(AbstractSerializer):
         for section in parser.sections():
             data[section] = {}
             for option, _ in parser.items(section):
-                data[section][option] = self._get_section_option_value(
-                    parser, section, option
-                )
+                value = self._get_section_option_value(parser, section, option)
+                if type_util.is_string(value):
+                    try:
+                        value_decoded = self._json.decode(value)
+                        value = value_decoded
+                    except JSONDecodeError:
+                        pass
+                data[section][option] = value
         return data
 
     def encode(self, d, **kwargs):
@@ -63,7 +71,10 @@ class INISerializer(AbstractSerializer):
             section = key
             parser.add_section(section)
             for option_key, option_value in value.items():
-                parser.set(section, option_key, f"{option_value}")
+                if type_util.is_collection(option_value):
+                    parser.set(section, option_key, self._json.encode(option_value))
+                else:
+                    parser.set(section, option_key, option_value)
         str_data = StringIO()
         parser.write(str_data)
         return str_data.getvalue()


Test patch:
diff --git a/tests/github/test_issue_0284.py b/tests/github/test_issue_0284.py
new file mode 100644
index 0000000..15de7b6
--- /dev/null
+++ b/tests/github/test_issue_0284.py
@@ -0,0 +1,36 @@
+import unittest
+
+from benedict import benedict
+
+
+class github_issue_0284_test_case(unittest.TestCase):
+    """
+    This class describes a github issue 0284 test case.
+    https://github.com/fabiocaccamo/python-benedict/issues/284
+
+    To run this specific test:
+    - Run python -m unittest tests.github.test_issue_0284
+    """
+
+    def test_from_ini_returns_str_instead_of_dict(self):
+        original = benedict(
+            {
+                "section1": {
+                    "key1": "value1",
+                },
+                "sectionA": {
+                    "keyA": "valueA",
+                    "keyB": "valueB",
+                    "keyC": {
+                        "subkeyC": "subvalueC",
+                    },
+                },
+            }
+        )
+        readback = benedict.from_ini(original.to_ini())
+        keypath = "sectionA.keyC"
+        # print("original vs readback")
+        # print(original.get(keypath), type(original.get(keypath)))
+        # print("-- vs --")
+        # print(readback.get(keypath), type(readback.get(keypath)))
+        self.assertEqual(original.get(keypath), readback.get(keypath))