Repository: yt-project/yt

Issue:
YtConfig __getitem__ is slightly broken
### Bug report

If one attempts to display the main (and currently only) section of the configuration from an interactive session it should be doable like this
```python
from yt.config import ytcfg
print(ytcfg["yt"])
```
Though currently this fails with

```
KeyError: 'Cannot get key y'
```
Because the underlying code was only ever tested with double keys, the string`"yt"` is treated as an iterable.
It's probably an easy fix but I'd rather just report it for now.
ping @cphyc in case you're interested in looking this up


Discussion:

Resolving patch:
diff --git a/yt/config.py b/yt/config.py
--- a/yt/config.py
+++ b/yt/config.py
@@ -5,7 +5,7 @@
 from more_itertools import always_iterable
 
 from yt._maintenance.deprecation import issue_deprecation_warning
-from yt.utilities.configuration_tree import ConfigNode
+from yt.utilities.configuration_tree import ConfigLeaf, ConfigNode
 
 ytcfg_defaults = {}
 
@@ -99,13 +99,13 @@ def __init__(self, defaults=None):
             defaults = {}
         self.config_root = ConfigNode(None)
 
-    def get(self, section, *keys, callback=None, **kwargs):
-        if callback is None:
-
-            def callback(leaf):
-                return leaf.value
-
-        return self.config_root.get_leaf(section, *keys, callback=callback)
+    def get(self, section, *keys, callback=None):
+        node_or_leaf = self.config_root.get(section, *keys)
+        if isinstance(node_or_leaf, ConfigLeaf):
+            if callback is not None:
+                return callback(node_or_leaf)
+            return node_or_leaf.value
+        return node_or_leaf
 
     def get_most_specific(self, section, *keys, **kwargs):
         use_fallback = "fallback" in kwargs
@@ -148,14 +148,6 @@ def set(self, *args, metadata=None):
             [section] + list(keys), value, extra_data=metadata
         )
 
-    def __setitem__(self, args, value):
-        section, *keys = args
-        self.set(section, *keys, value, metadata=None)
-
-    def __getitem__(self, key):
-        section, *keys = key
-        return self.get(section, *keys)
-
     def remove(self, *args):
         self.config_root.pop_leaf(args)
 
@@ -190,6 +182,22 @@ def get_global_config_file():
     def get_local_config_file():
         return os.path.join(os.path.abspath(os.curdir), "yt.toml")
 
+    def __setitem__(self, args, value):
+        section, *keys = always_iterable(args)
+        self.set(section, *keys, value, metadata=None)
+
+    def __getitem__(self, key):
+        section, *keys = always_iterable(key)
+        return self.get(section, *keys)
+
+    def __contains__(self, item):
+        return item in self.config_root
+
+    # Add support for IPython rich display
+    # see https://ipython.readthedocs.io/en/stable/config/integrating.html
+    def _repr_json_(self):
+        return self.config_root._repr_json_()
+
 
 _global_config_file = YTConfig.get_global_config_file()
 _local_config_file = YTConfig.get_local_config_file()
diff --git a/yt/utilities/configuration_tree.py b/yt/utilities/configuration_tree.py
--- a/yt/utilities/configuration_tree.py
+++ b/yt/utilities/configuration_tree.py
@@ -105,9 +105,6 @@ def serialize(self):
             retval[key] = child.serialize()
         return retval
 
-    def __repr__(self):
-        return f"<Node {self.key}>"
-
     @staticmethod
     def from_dict(other, parent=None, **kwa):
         me = ConfigNode(None, parent=parent)
@@ -137,6 +134,17 @@ def as_dict(self, callback=lambda child: child.value):
         data, _ = self._as_dict_with_count(callback)
         return data
 
+    def __repr__(self):
+        return f"<Node {self.key}>"
+
+    def __contains__(self, item):
+        return item in self.children
+
+    # Add support for IPython rich display
+    # see https://ipython.readthedocs.io/en/stable/config/integrating.html
+    def _repr_json_(self):
+        return self.as_dict()
+
 
 class ConfigLeaf:
     def __init__(self, key, parent: ConfigNode, value, extra_data=None):


Test patch: