When generating API stubs with the scaffold utility using, e.g., `python -m localstack.aws.scaffold sns`,
the scaffold creates method names from operation names, which are ugly when acronyms (subsequent uppercase characters that belong together).

Example:
`CreateSMSSandboxPhoneNumber` -> `create_s_m_s_sandbox_phone_number`

it would be nicer to have `create_sms_sandbox_phone_number`

This is a limitation of this method: https://github.com/localstack/localstack/blob/1888e66b85d7e6a8ee457bc7a732984fcf7aa830/localstack/utils/common.py#L978-L979
"""Recursively apply `func` to `obj` (may be a list, dict, or other object)."""
    obj = func(obj, path=path)
    if isinstance(obj, list):
        for i in range(len(obj)):
            tmp_path = "%s[%s]" % (path or ".", i)
            obj[i] = recurse_object(obj[i], func, tmp_path)
    elif isinstance(obj, dict):
        for k, v in obj.items():
            tmp_path = "%s%s" % ((path + ".") if path else "", k)
            obj[k] = recurse_object(v, func, tmp_path)
    return obj
def keys_to_lower(obj: JsonComplexType, skip_children_of: List[str] = None) -> JsonComplexType:
    """Recursively changes all dict keys to first character lowercase. Skip children
    of any elements whose names are contained in skip_children_of (e.g., ['Tags'])"""
    skip_children_of = ensure_list(skip_children_of or [])
    def fix_keys(o, path="", **kwargs):
        if any(re.match(r"(^|.*\.)%s($|[.\[].*)" % k, path) for k in skip_children_of):
            return o
        if isinstance(o, dict):
            for k, v in dict(o).items():
                o.pop(k)
                o[first_char_to_lower(k)] = v
        return o
    result = recurse_object(obj, fix_keys)
    return result
def camel_to_snake_case(string: str) -> str:
    return re.sub(r"(?<!^)(?=[A-Z])", "_", string).replace("__", "_").lower()
def snake_to_camel_case(string: str, capitalize_first: bool = True) -> str: