Repository: j4c0bs/spectron

Issue:
Pass case_insensitive arg to MaxDict
MaxDict needs an optional arg to ignore parent key case.

Discussion:

Patch:
diff --git a/spectron/MaxDict.py b/spectron/MaxDict.py
index c3e8ff3..2398fa6 100644
--- a/spectron/MaxDict.py
+++ b/spectron/MaxDict.py
@@ -4,7 +4,7 @@ import logging
 
 from collections import defaultdict
 from itertools import chain
-from typing import AbstractSet, Dict, Generator, List, Optional, Tuple
+from typing import AbstractSet, Dict, Generator, List, Optional, Tuple, Union
 
 from . import data_types
 from .Field import Field, add_hist_dicts
@@ -90,7 +90,10 @@ class MaxDict:
             The output of MaxDict.asdict() will contain a.b.[array] and not a.b.c
     """
 
-    def __init__(self, str_numeric_override: bool = False):
+    def __init__(
+        self, case_insensitive: bool = False, str_numeric_override: bool = False
+    ):
+        self.case_insensitive = case_insensitive
         self.str_numeric_override = str_numeric_override
         self.hist = defaultdict(int)
         self.key_store = {}
@@ -116,7 +119,14 @@ class MaxDict:
 
         return md
 
-    def add(self, key: str, value):
+    def add(self, key: Union[str, Tuple[str]], value):
+
+        if self.case_insensitive:
+            if isinstance(key, str):
+                key = key.lower()
+            else:
+                key = tuple(map(str.lower, key))
+
         self.hist[key] += 1
         if key in self.key_store:
             self.key_store[key].add(value)
diff --git a/spectron/__init__.py b/spectron/__init__.py
index 4558e9d..0ffa0ee 100644
--- a/spectron/__init__.py
+++ b/spectron/__init__.py
@@ -1,5 +1,5 @@
 # -*- coding: utf-8 -*-
 
-__version__ = "0.4.7"
+__version__ = "0.4.8"
 
 from . import ddl  # noqa: F401
diff --git a/spectron/cli.py b/spectron/cli.py
index e741834..3d092b3 100644
--- a/spectron/cli.py
+++ b/spectron/cli.py
@@ -197,7 +197,9 @@ def parse_arguments():
     return args
 
 
-def load_dict_from_infiles(infiles: List[io.TextIOWrapper]) -> Dict:
+def load_dict_from_infiles(
+    infiles: List[io.TextIOWrapper], case_insensitive: bool
+) -> Dict:
     """Load JSON infile(s) as dict | max dict.
     If > 1 files or any input is a list of dicts, max dict is used as schema source.
     """
@@ -209,7 +211,7 @@ def load_dict_from_infiles(infiles: List[io.TextIOWrapper]) -> Dict:
         else:
             infiles[0].seek(0)
 
-    md = MaxDict()
+    md = MaxDict(case_insensitive=case_insensitive)
     for infile in infiles:
         d = json.loads(infile.read())
 
@@ -227,7 +229,7 @@ def create_spectrum_schema():
     """Create Spectrum schema from JSON."""
 
     args = parse_arguments()
-    d = load_dict_from_infiles(args.infile)
+    d = load_dict_from_infiles(args.infile, args.case_insensitive)
 
     kwargs = {k: v for (k, v) in args._get_kwargs()}
     statement = ddl.from_dict(d, **kwargs)


Test patch:
diff --git a/tests/test_MaxDict.py b/tests/test_MaxDict.py
index 212743f..a705489 100644
--- a/tests/test_MaxDict.py
+++ b/tests/test_MaxDict.py
@@ -59,3 +59,34 @@ def test__add_max_dicts():
     }
 
     assert mdx.asdict() == expected
+
+
+def test__max_dicts__case():
+    d1 = {
+        "a1": {"b1": 1, "B2": "test", "B3": "x"},
+        "a2": -100,
+        "a3": {"b3": [{"c3": False}]},
+        "a4": 1.234,
+    }
+    d2 = {
+        "a1": {"b1": 10 ** 10, "b2": "x", "b3": "test"},
+        "a2": 1,
+        "a3": {"b3": [{"c3": True}]},
+        "a4": 2.345,
+    }
+
+    md1 = MaxDict(case_insensitive=True)
+    md1.load_dict(d1)
+    md2 = MaxDict(case_insensitive=True)
+    md2.load_dict(d2)
+
+    mdx = md1 + md2
+
+    expected = {
+        "a1": {"b1": 10000000000, "b2": "test", "b3": "test"},
+        "a2": -100,
+        "a3": {"b3": [{"c3": True}]},
+        "a4": 2.345,
+    }
+
+    assert mdx.asdict() == expected