diff --git a/impactlab_tools/utils/configdict.py b/impactlab_tools/utils/configdict.py
index cb9e5ec..135dfde 100644
--- a/impactlab_tools/utils/configdict.py
+++ b/impactlab_tools/utils/configdict.py
@@ -10,15 +10,19 @@ except ImportError:
     import collections as collections_abc
 
 
-def gather_configtree(d):
+def gather_configtree(d, parse_lists=False):
     """Chains nested-dicts into a connected tree of ConfigDict(s)
 
     Parameters
     ----------
-    d : dict
+    d : dict or MutableMapping
         Cast to :py:class:`ConfigDict`. Nested dicts within are also
         recursively cast and assigned parents, reflecting their nested
         structure.
+    parse_lists : bool, optional
+        If `d` or its children contain a list of dicts, do you want to convert
+        these listed dicts to ConfDicts and assign them parents. This is
+        slow. Note this only parses lists, strictly, not all Sequences.
 
     Returns
     -------
@@ -47,8 +51,17 @@ def gather_configtree(d):
     for k, v in out.data.items():
         # Replace nested maps with new ConfigDicts
         if isinstance(v, collections_abc.MutableMapping):
-            out.data[k] = gather_configtree(v)
+            out.data[k] = gather_configtree(v, parse_lists=parse_lists)
             out.data[k].parent = out
+
+        # If list has mappings, replace mappings with new ConfigDicts
+        if parse_lists and isinstance(v, list):
+            for idx, item in enumerate(v):
+                if isinstance(item, collections_abc.MutableMapping):
+                    cd = gather_configtree(item, parse_lists=parse_lists)
+                    cd.parent = out
+                    out.data[k][idx] = cd
+
     return out
 
 
@@ -138,7 +151,7 @@ class ConfigDict(UserDict, object):
         if isinstance(key, str):
             return key.lower().replace('_', '-')
 
-    def accessed_all_keys(self, search='local'):
+    def accessed_all_keys(self, search='local', parse_lists=False):
         """Were all the keys used in the config tree?
 
         Parameters
@@ -156,6 +169,11 @@ class ConfigDict(UserDict, object):
             ``"children"``
                 Recursively check keys in children, moving down the tree, after
                 checking local keys.
+        parse_lists : bool, optional
+            If True when `search` is "children", check if self or its children
+            contain a list and check the list for ConfDicts and whether they
+            used their keys. This is slow. Note this only parses lists,
+            strictly, not all Sequences.
 
         Returns
         -------
@@ -215,17 +233,33 @@ class ConfigDict(UserDict, object):
             # Recursively check parents keys, if any haven't been used,
             # immediately return False.
             if self.parent is not None:
-                parent_used = self.parent.accessed_all_keys(search=search)
+                parent_used = self.parent.accessed_all_keys(
+                    search=search,
+                    parse_lists=parse_lists,
+                )
                 if parent_used is False:
                     return False
+
         elif search == 'children':
             # Recursively check children keys, if any haven't been used,
             # immediately return False.
             for k, v in self.data.items():
-                # Assuming its faster to ask for forgiveness than to check
-                # with `isinstance()` or `hasattr()q...
+                if parse_lists and isinstance(v, list):
+                    for item in v:
+                        try:
+                            child_used = item.accessed_all_keys(
+                                search=search,
+                                parse_lists=parse_lists,
+                            )
+                            if child_used is False:
+                                return False
+                        except AttributeError:
+                            continue
+                    continue
+
                 try:
-                    child_used = v.accessed_all_keys(search=search)
+                    child_used = v.accessed_all_keys(search=search,
+                                                     parse_lists=parse_lists)
                     if child_used is False:
                         return False
                 except AttributeError:

`gather_configtree()` needs option to assign parents to nested lists of dicts
`gather_configtree()` will skip over any nested lists of dictionaries. @jrising suggested allowing `gather_configtree()` to convert these nested dicts to `ConfDicts` and assigning them parents, as we would do for any other nested dictionaries.

The key here is that using the `accessed_all_keys()` method with `search='parents'` or `search='children'` from the top or bottom of the tree should not be "blocked" by a list of ConfDicts. This was a cause for trouble in the `impact-calculations` package. Be sure to test against this use case.
diff --git a/tests/utils/test_configdict.py b/tests/utils/test_configdict.py
index 1d299f0..c26edb8 100644
--- a/tests/utils/test_configdict.py
+++ b/tests/utils/test_configdict.py
@@ -8,6 +8,18 @@ def simple_nested_tree():
     return {'a': 1, 'b': {'a': 2}, 'c': 3, 'd-4': 4, 'e_5': 5, 'F': 6}
 
 
+def test_gather_configtree_nested_lists():
+    """Test gather_configtree() "parse_lists" option"""
+    d = {'a': 1, 'c': [2, {'x': 'foo', 'y': {'z': 'bar'}}]}
+    conf = gather_configtree(d, parse_lists=True)
+    assert conf['c'][1]['y']['a'] == conf['a']
+
+    assert conf.accessed_all_keys(search='children', parse_lists=True) is False
+    conf['c'][1]['x']
+    conf['c'][1]['y']['z']
+    assert conf.accessed_all_keys(search='children', parse_lists=True) is True
+
+
 def test_configdict_climbs_tree(simple_nested_tree):
     conf = gather_configtree(simple_nested_tree)
     assert conf['b']['c'] == 3
@@ -105,24 +117,6 @@ def test_configdict_key_access_stack_nested(simple_nested_tree):
     assert top_keys == ['b', 'f']
 
 
-def test_configdict_accessed_all_keys_local(simple_nested_tree):
-    root_conf = gather_configtree(simple_nested_tree)
-    child_conf = root_conf['b']
-
-    root_conf['a']
-    root_conf['c']
-    root_conf['d-4']
-    root_conf['e-5']
-
-    assert root_conf.accessed_all_keys(search='local') is False
-
-    root_conf['f']
-
-    assert root_conf.accessed_all_keys(search='local') is True
-
-    assert child_conf.accessed_all_keys(search='local') is False
-
-
 def test_configdict_accessed_all_keys_local(simple_nested_tree):
     kwargs = {'search': 'local'}
     root_conf = gather_configtree(simple_nested_tree)

pip install -e .[test]
parse_log_pytest
requirements.txt
numpy>=1.7 pandas>=0.15 netCDF4>=1.1 xarray>=0.8 pytest pytest-cov pytest-runner coverage flake8
apt-get update apt-get install -y gcc
3.9
requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
alabaster==0.7.16
babel==2.17.0
cachetools==5.5.2
certifi==2025.1.31
cftime==1.6.4.post1
chardet==5.2.0
charset-normalizer==3.4.1
colorama==0.4.6
coverage==7.8.0
coveralls==4.0.1
distlib==0.3.9
docopt==0.6.2
docutils==0.21.2
exceptiongroup==1.2.2
filelock==3.18.0
flake8==7.2.0
idna==3.10
imagesize==1.4.1
-e git+https://github.com/ClimateImpactLab/impactlab-tools.git@a56fa03cfe65515c324bfebda79e7906e20ac87d#egg=impactlab_tools
importlib_metadata==8.6.1
iniconfig==2.1.0
Jinja2==3.1.6
MarkupSafe==3.0.2
mccabe==0.7.0
netCDF4==1.7.2
numpy==2.0.2
packaging==24.2
pandas==2.2.3
platformdirs==4.3.7
pluggy==1.5.0
pycodestyle==2.13.0
pyflakes==3.3.2
Pygments==2.19.1
pyproject-api==1.9.0
pytest==8.3.5
pytest-cov==6.0.0
pytest-runner==6.0.1
python-dateutil==2.9.0.post0
pytz==2025.2
requests==2.32.3
six==1.17.0
snowballstemmer==2.2.0
Sphinx==7.4.7
sphinx-rtd-theme==3.0.2
sphinxcontrib-applehelp==2.0.0
sphinxcontrib-devhelp==2.0.0
sphinxcontrib-htmlhelp==2.1.0
sphinxcontrib-jquery==4.1
sphinxcontrib-jsmath==1.0.1
sphinxcontrib-qthelp==2.0.0
sphinxcontrib-serializinghtml==2.0.0
tomli==2.2.1
tox==4.25.0
typing_extensions==4.13.0
tzdata==2025.2
urllib3==2.3.0
virtualenv==20.30.0
xarray==2024.7.0
zipp==3.21.0

name: impactlab-tools
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - pip=25.0=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - alabaster==0.7.16
      - babel==2.17.0
      - cachetools==5.5.2
      - certifi==2025.1.31
      - cftime==1.6.4.post1
      - chardet==5.2.0
      - charset-normalizer==3.4.1
      - colorama==0.4.6
      - coverage==7.8.0
      - coveralls==4.0.1
      - distlib==0.3.9
      - docopt==0.6.2
      - docutils==0.21.2
      - exceptiongroup==1.2.2
      - filelock==3.18.0
      - flake8==7.2.0
      - idna==3.10
      - imagesize==1.4.1
      - importlib-metadata==8.6.1
      - iniconfig==2.1.0
      - jinja2==3.1.6
      - markupsafe==3.0.2
      - mccabe==0.7.0
      - netcdf4==1.7.2
      - numpy==2.0.2
      - packaging==24.2
      - pandas==2.2.3
      - platformdirs==4.3.7
      - pluggy==1.5.0
      - pycodestyle==2.13.0
      - pyflakes==3.3.2
      - pygments==2.19.1
      - pyproject-api==1.9.0
      - pytest==8.3.5
      - pytest-cov==6.0.0
      - pytest-runner==6.0.1
      - python-dateutil==2.9.0.post0
      - pytz==2025.2
      - requests==2.32.3
      - six==1.17.0
      - snowballstemmer==2.2.0
      - sphinx==7.4.7
      - sphinx-rtd-theme==3.0.2
      - sphinxcontrib-applehelp==2.0.0
      - sphinxcontrib-devhelp==2.0.0
      - sphinxcontrib-htmlhelp==2.1.0
      - sphinxcontrib-jquery==4.1
      - sphinxcontrib-jsmath==1.0.1
      - sphinxcontrib-qthelp==2.0.0
      - sphinxcontrib-serializinghtml==2.0.0
      - tomli==2.2.1
      - tox==4.25.0
      - typing-extensions==4.13.0
      - tzdata==2025.2
      - urllib3==2.3.0
      - virtualenv==20.30.0
      - xarray==2024.7.0
      - zipp==3.21.0
prefix: /opt/conda/envs/impactlab-tools

tests/utils/test_configdict.py::test_gather_configtree_nested_lists
tests/utils/test_configdict.py::test_configdict_climbs_tree tests/utils/test_configdict.py::test_configdict_prefer_child tests/utils/test_configdict.py::test_configdict_selfreference tests/utils/test_configdict.py::test_configdict_caseinsensitive_keys tests/utils/test_configdict.py::test_configdict_normalize tests/utils/test_configdict.py::test_configdict_throws_keyerror tests/utils/test_configdict.py::test_configdict_merge tests/utils/test_configdict.py::test_configdict_merge_parentswap tests/utils/test_configdict.py::test_configdict_key_access_stack tests/utils/test_configdict.py::test_configdict_key_access_stack_nested tests/utils/test_configdict.py::test_configdict_accessed_all_keys_local tests/utils/test_configdict.py::test_configdict_accessed_all_keys_children tests/utils/test_configdict.py::test_configdict_accessed_all_keys_parents
impactlab_tools/utils/configdict.py
impactlab_tools/utils/configdict.py