from typing import Mapping
from typing import Any
import re


def to_camelcase(variables: Mapping[str, Any]) -> Mapping[str, Any]:
    """
    Transform typical python underscore-style variables
    into camelCased variables that graphQL expects.
    NOTE: Converts nested dictionaries recursively so all keys are camelCased.
    """
    def convert(string):
        # thanks to https://stackoverflow.com/a/47253475/1327062
        return re.sub('_([a-zA-Z0-9])', lambda m: m.group(1).upper(), string)

    converted_dict = {}
    for key, value in variables.items():
        if isinstance(value, dict):
            value = to_camelcase(value)
        key = convert(key)
        converted_dict[key] = value
    return converted_dict