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
if isinstance(o, dict):
                remove_attributes(o, attributes)
            return o
        return recurse_object(obj, _remove)
    attributes = attributes if is_list_or_tuple(attributes) else [attributes]
    for attr in attributes:
        obj.pop(attr, None)
    return obj
def rename_attributes(
    obj: Dict, old_to_new_attributes: Dict[str, str], in_place: bool = False
) -> Dict:
    """Rename a set of attributes in the given dict object. Second parameter is a dict that maps old to
    new attribute names. Default is to return a copy, but can also pass in_place=True."""
    if not in_place:
        obj = dict(obj)
    for old_name, new_name in old_to_new_attributes.items():
        if old_name in obj:
            obj[new_name] = obj.pop(old_name)
    return obj
def is_list_or_tuple(obj) -> bool:
    return isinstance(obj, (list, tuple))
def ensure_list(obj: Any, wrap_none=False) -> List:
    """Wrap the given object in a list, or return the object itself if it already is a list."""
    if obj is None and not wrap_none:
        return obj
    return obj if isinstance(obj, list) else [obj]
def in_docker() -> bool:
    return config.in_docker()
def path_from_url(url: str) -> str: