Repository: sosw/sosw

Issue:
Easy access from config
Implement a built-in helper in ``app.py`` to read from config using path.
E.g.
`` val = self._c('path.to.param')``

Instead of:
``val = self.config['path']['to']['param']``

And handle missing parts anywhere along the path.

Discussion:

Patch:
diff --git a/sosw/app.py b/sosw/app.py
index cec8a91..497b011 100644
--- a/sosw/app.py
+++ b/sosw/app.py
@@ -276,6 +276,17 @@ class Processor:
         return self.aws_region
 
 
+    def _c(self, path: str):
+        """
+        Shortcut to access values from the Processor config.
+
+        E.g. ``val = self._c('path.to.param')``
+
+        Is similar to: ``val = self.config.get('path', {}).get('to', {}).get('param', None)``
+        """
+        return recursive_matches_extract(self.config, path)
+
+
     @benchmark
     def get_ddbc(self, prefix: str) -> DynamoDbClient:
         """
diff --git a/sosw/components/helpers.py b/sosw/components/helpers.py
index 01a85b7..804894c 100644
--- a/sosw/components/helpers.py
+++ b/sosw/components/helpers.py
@@ -864,7 +864,8 @@ def recursive_insert(d: dict, path: str, value, separator: str = '.') -> dict:
     """
 
     if not isinstance(path, str) or not path:
-        raise ValueError(f"Path is invalid. Should be a non-empty string separated with '{separator}', but received: {path}")
+        raise ValueError(f"Path is invalid. Should be a non-empty string separated with '{separator}', "
+                         f"but received: {path}")
 
     result = deepcopy(d) if d is not None else {}
 


Test patch:
diff --git a/sosw/test/unit/test_app.py b/sosw/test/unit/test_app.py
index dc768ca..270bb01 100644
--- a/sosw/test/unit/test_app.py
+++ b/sosw/test/unit/test_app.py
@@ -262,3 +262,10 @@ class app_UnitTestCase(unittest.TestCase):
             processor.get_ddbc(prefix)
 
             self.assertEqual(str(context.exception), "get_ddbc() method supports only prefixes: ['example']")
+
+    def test_c(self):
+        p = Processor(custom_config={'a': {'b': {'c': 42}}})
+
+        self.assertEqual(p._c('a.b.c'), 42)
+        self.assertEqual(p._c('a.b.z'), None)
+        self.assertEqual(p._c('z'), None)