wohlgejm/accountable

View on GitHub
accountable/utils.py

Summary

Maintainability
B
4 hrs
Test Coverage
from __future__ import absolute_import
from __future__ import unicode_literals

try:
    from collections import MutableSequence, MutableMapping
except ImportError:
    from collections.abc import MutableSequence, MutableMapping
from collections import OrderedDict
import ast
from functools import reduce

from inflection import underscore


def reshape(schema, data):
    reshaped = [] if isinstance(schema, MutableSequence) else OrderedDict()

    def _reshape(schema, data, new_data):
        if isinstance(schema, MutableMapping):
            for idx, (key, value) in enumerate(schema.items()):
                try:
                    d = data[key]
                except KeyError:
                    continue
                new_data[key] = (
                    [] if isinstance(value, MutableSequence) else {}
                )
                if not value:
                    new_data[key] = data[key]
                else:
                    _reshape(value, d, new_data[key])
        elif isinstance(schema, MutableSequence):
            schema = schema[0]
            for idx, datum in enumerate(data):
                try:
                    new_data[idx]
                except IndexError:
                    new_data.append({})
                _reshape(schema, datum, new_data[idx])
        else:
            new_data[schema] = data[schema]
    _reshape(schema, data, reshaped)
    return reshaped


def nargs_to_dict(nargs):
    args = zip(nargs[0::2], nargs[1::2])
    d = reduce(rec_nargs_to_dict, args, {})
    return {'fields': d}


def rec_nargs_to_dict(accum, kv):
    k, v = kv
    keys = k.split('.')
    if len(keys) > 1:
        accum[keys[0]] = rec_nargs_to_dict({}, (keys[1], eval_value(v)))
    else:
        accum[keys[0]] = eval_value(v)
    return accum


def eval_value(value):
    try:
        return ast.literal_eval(value)
    except (SyntaxError, ValueError):
        return value


def flatten(d, parent_key='', sep='_'):
    items = []
    for k, v in d.items():
        new_key = (
            underscore(parent_key) +
            sep +
            underscore(k) if parent_key else underscore(k)
        )
        if isinstance(v, MutableMapping):
            items.extend(flatten(v, new_key, sep=sep).items())
        else:
            items.append((new_key, v))
    return OrderedDict(sorted(items))