Skip to content

Commit

Permalink
Merge pull request #518 from avcopan/dev
Browse files Browse the repository at this point in the history
Moves MechDriver-specific dict functions to point of use
  • Loading branch information
avcopan authored Jul 6, 2024
2 parents f70c8a5 + cfffd3c commit 9ac8b0e
Show file tree
Hide file tree
Showing 3 changed files with 7 additions and 153 deletions.
83 changes: 2 additions & 81 deletions automol/tests/test_dict.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,22 +58,10 @@
}


def test__update():
""" test automol.dict_.right_update
test automol.dict_.merge_sequence
def test__merge_sequence():
""" test automol.dict_.merge_sequence
"""

# Combine dct functions
ref_dct1 = {
'ich': 'InChI=1S/N2/c1-2',
'charge': 0,
'mult': 1
}

dct1 = dict_.right_update(DCT1, DCT2)

assert dct1 == ref_dct1

ref_dct2 = {
'ich': 'InChI=1S/N2/c1-2',
'charge': 0,
Expand Down Expand Up @@ -116,73 +104,6 @@ def test__read():
assert val4 == 'fill'


def test__separate_and_merge():
""" test_separate_subdct
"""

# Separate dictionaries
ref_subdct1 = {
'key1': {
'subkey1': 'subval1-1',
'subkey2': 'subval1-2'
},
'key2': {
'subkey1': 'subval2-1',
'subkey2': 'subval2-2'
}
}
ref_subdct2 = {
'subkey1': 'subvalg1',
'subkey3': 'subvalg3'
}

subdct1, subdct2 = dict_.separate_subdct(GDCT3, key='global')
assert ref_subdct1 == subdct1
assert ref_subdct2 == subdct2

subdct1, subdct2 = dict_.separate_subdct(GDCT3, key='key3')
assert GDCT3 == subdct1
assert not subdct2

# Merge subdictionaries
ref_mergedct1 = {
'key1': {
'subkey1': 'subval1-1',
'subkey3': 'subvalg3',
'subkey2': 'subval1-2'
},
'key2': {
'subkey1': 'subval2-1',
'subkey3': 'subvalg3',
'subkey2': 'subval2-2'
},
'global': {
'subkey1': 'subvalg1',
'subkey3': 'subvalg3'
}
}
ref_mergedct2 = {
'key1': {
'subkey1': 'subval1-1',
'subkey3': 'subvalg3',
'subkey2': 'subval1-2',
},
'key2': {
'subkey1': 'subval2-1',
'subkey3': 'subvalg3',
'subkey2': 'subval2-2',
}
}

mergedct1 = dict_.merge_subdct(GDCT3, key='global', keep_subdct=True)
mergedct2 = dict_.merge_subdct(GDCT3, key='global', keep_subdct=False)
mergedct3 = dict_.merge_subdct(GDCT4, key='global', keep_subdct=False)

assert ref_mergedct1 == mergedct1
assert ref_mergedct2 == mergedct2
assert GDCT4 == mergedct3


def test__sort():
""" test dict_.keys_sorted_by_value
"""
Expand Down
6 changes: 1 addition & 5 deletions automol/util/dict_/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,12 @@
from automol.util.dict_._dict_ import invert
from automol.util.dict_._dict_ import empty_if_none
from automol.util.dict_._dict_ import compose
from automol.util.dict_._dict_ import right_update
from automol.util.dict_._dict_ import by_key
from automol.util.dict_._dict_ import by_value
from automol.util.dict_._dict_ import values_by_key
from automol.util.dict_._dict_ import value_by_unordered_key
from automol.util.dict_._dict_ import values_in_multilevel_dct
from automol.util.dict_._dict_ import value_in_floatkey_dct
from automol.util.dict_._dict_ import separate_subdct
from automol.util.dict_._dict_ import merge_subdct
from automol.util.dict_._dict_ import keys_by_value
from automol.util.dict_._dict_ import transform_keys
from automol.util.dict_._dict_ import transform_values
Expand All @@ -31,11 +28,10 @@
__all__ = [
# functions
'invert',
'empty_if_none', 'compose', 'right_update', 'by_key', 'by_value',
'empty_if_none', 'compose', 'by_key', 'by_value',
'values_by_key', 'value_by_unordered_key',
'values_in_multilevel_dct', 'value_in_floatkey_dct',
'keys_by_value', 'transform_keys', 'transform_values',
'separate_subdct', 'merge_subdct',
'transform_items_to_values',
'keys_sorted_by_value',
'values_sorted_by_key',
Expand Down
71 changes: 4 additions & 67 deletions automol/util/dict_/_dict_.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
""" Helper functions for working with Python dictionaries
"""

import itertools
from copy import deepcopy
from typing import Any
Expand Down Expand Up @@ -42,33 +43,6 @@ def compose(dct1, dct2):
return {k2: dct1[v2] for k2, v2 in dct2.items()}


def right_update(dct1, dct2):
"""Updates the entries of `dct1` with those of `dct2`.
:param dct1: dictionary1 that will be updated
:type dct1: dict
:param dct2: dictionary2 whose entries will override dct1
:type dct2: dict
:rtype: dict
"""

dct = {}
dct1 = empty_if_none(dct1)
dct2 = empty_if_none(dct2)
dct.update(dct1)
dct.update(dct2)

# if both dictionaries have a nested dictionary, keep
# any non-overlapping nested key-value pairs and
# the dct2 key-values for overlapping keys.
for key, value in dct1.items():
if isinstance(value, dict) and key in dct2:
for subkey, subval in value.items():
if subkey not in dct2[key]:
dct[key][subkey] = subval
return dct


def by_key(dct, keys, fill=True, fill_val=None):
"""dictionary on a set of keys, filling missing entries
Expand Down Expand Up @@ -133,45 +107,6 @@ def values_in_multilevel_dct(dct, key1, key2, fill_val=None):
return val


def separate_subdct(dct, key="global"):
"""Pulls out a sub-dictionary indexed by the given key and returns it
and the original dictioanry with the requested sub-dictionary removed
"""

# Grab the sub-dictonary and
sub_dct = dct.get(key, {})

# Build a new copy of the input dictionary with the sub-dict removed
dct2 = deepcopy(dct)
dct2.pop(key, None)

return dct2, sub_dct


def merge_subdct(dct, key="global", keep_subdct=False):
"""Obtain a sub-dictionary indexed by a given key and merge its contents
with all of the other sub-dictionaries in the main dictionary.
:param dct: dictionary containing several sub-dictionaries
:type dct: dict[str: dict]
:param key: key for the sub-dictionary to be merged
:type key: str, int, float, tuple
:param keep_subdct: keep/remove the sub-dictionary following the merge
:type keep_subdct: bool
"""

if list(dct.keys()) == [key]:
new_dct = {key: dct[key]}
else:
new_dct, sub_dct = separate_subdct(dct, key=key)
for new_key in new_dct:
new_dct[new_key] = right_update(sub_dct, new_dct[new_key])
if keep_subdct:
new_dct[key] = sub_dct

return new_dct


def keys_by_value(dct, func=lambda x: x):
"""return dictionary keys for specific values"""
return frozenset(key for key, val in dct.items() if func(val))
Expand Down Expand Up @@ -243,7 +178,7 @@ def merge_sequence(dcts):
return merged_dct


def sort_value_(dct, allow_missing: bool = True, missing_val: Any=None):
def sort_value_(dct, allow_missing: bool = True, missing_val: Any = None):
"""Generate a sort value function from a dictionary
:param dct: A dictionary
Expand All @@ -253,7 +188,9 @@ def sort_value_(dct, allow_missing: bool = True, missing_val: Any=None):
:param missing_val: Value to assign to missing values, defaults to None
:type missing_val: Any, optional
"""

def sort_value(key):
assert allow_missing or key in dct, "No key {key} in dictionary:\n{dict}"
return dct[key] if key in dct else missing_val

return sort_value

0 comments on commit 9ac8b0e

Please sign in to comment.