Repository: radiasoft/pykern

Issue:
pknested_get accept iterable; pkuncheck_nested_get accept default

Discussion:

Patch:
diff --git a/pykern/pkcollections.py b/pykern/pkcollections.py
index 04f04cd..e195a63 100644
--- a/pykern/pkcollections.py
+++ b/pykern/pkcollections.py
@@ -158,21 +158,23 @@ class PKDict(dict):
                 raise _type_err(k, s, t)
         return self
 
-    def pknested_get(self, dotted_key):
-        """Split key on dots and return nested get calls
+    def pknested_get(self, qualifiers):
+        """Split key on dots or iterable and return nested get calls
 
-        If an element is a list or tuple,
+        If `qualifiers` is a str, will split on dots. Otherwise, will be iterated.
+
+        If an element is a list or tuple, tries to index as int.
 
         Throws KeyError if the dictionary key doesn't exist.
 
         Args:
-            dotted_key (str): what
+            qualifiers (str or iterable):
 
         Returns:
             object: value of element
         """
         d = self
-        for k in dotted_key.split("."):
+        for k in qualifiers.split(".") if isinstance(qualifiers, str) else qualifiers:
             try:
                 d = d[k]
             except TypeError:
@@ -214,21 +216,25 @@ class PKDict(dict):
                 self[k] = v() if callable(v) else v
         return self
 
-    def pkunchecked_nested_get(self, dotted_key):
-        """Split key on dots and return nested get calls
+    def pkunchecked_nested_get(self, qualifiers, default=None):
+        """Split key on dots or iterable and return nested get calls
+
+        If `qualifiers` is a str, will split on dots. Otherwise, will be iterated.
+
+        If the element does not exist or is not indexable, fails silently and returns `default`.
 
-        If the element does not exist or is not indexable, fails silently with None.
+        Throws KeyError if the dictionary key doesn't exist.
 
         Args:
-            dotted_key (str): what
+            qualifiers (str or iterable):
 
         Returns:
-            object: value of element or None
+            object: value of element
         """
         try:
-            return self.pknested_get(dotted_key)
+            return self.pknested_get(qualifiers)
         except (KeyError, IndexError, TypeError, ValueError):
-            return None
+            return default
 
     def pkupdate(self, *args, **kwargs):
         """Call `dict.update` and return ``self``."""


Test patch:
diff --git a/tests/pkcollections_test.py b/tests/pkcollections_test.py
index 7b25da4..1d800e6 100644
--- a/tests/pkcollections_test.py
+++ b/tests/pkcollections_test.py
@@ -130,13 +130,16 @@ def test_dict_pknested_get():
 
     n = PKDict(one=PKDict(two=1.2), simple=1)
     pkeq(1, n.pknested_get("simple"))
+    pkeq(1, n.pknested_get(["simple"]))
     pkeq(1.2, n.pknested_get("one.two"))
+    pkeq(1.2, n.pknested_get(("one", "two")))
     with pkexcept(TypeError):
         n.pknested_get("simple.not")
     pkeq(1, n.pkunchecked_nested_get("simple"))
     pkeq(1.2, n.pkunchecked_nested_get("one.two"))
     pkeq(None, n.pkunchecked_nested_get("one.two.three"))
     pkeq(None, n.pkunchecked_nested_get("simple.not"))
+    pkeq(36, n.pkunchecked_nested_get("simple.not", 36))
     n = PKDict(one=[10, PKDict(last="done"), 14])
     pkeq("done", n.pknested_get("one.1.last"))