"""Useful functions."""
import io
import mimetypes
[docs]def execute(url, *args, headers=None, **kwargs):
    """Sends a GraphQL request without the user haveing to make a dedicated
    :py:class:`.Client` object.
    :param str url: the URL to send to.
    :param str message: The query to make.
    :param str method: By default, POST requests are sent, but this can be\
    overriden here.
    :param dict headers: Any additional HTTP headers.
    :param dict variables: Any GraphQL variables can be passed here.
    :rtype: ``dict``"""
    from .client import Client
    client = Client(url)
    if headers: client.headers.update(headers)
    return client.execute(*args, **kwargs) 
[docs]def get_files_from_variables(variables):
    """Takes a variables objects and looks to see if any of the values are file
    objects which need to be sent separately.
    :param dict variables: the variables to inspect, or ``None``.
    :returns: ``(variables, files)``"""
    if not variables: return variables, None
    files, new_variables = {}, {}
    for k, v in variables.items():
        if isinstance(v, io.IOBase):
            files[k] = v
            new_variables[k] = None
        elif isinstance(v, list) and len(v) and isinstance(v[0], io.IOBase):
            files[k] = v
            new_variables[k] = [None] * len(v)
        else:
            new_variables[k] = v
    return new_variables, files 
[docs]def files_to_map(files):
    """Takes a files dict and creates the map dict needed by the GraphQL file
    upload spec.
    
    :param dict files: the files dict.
    :rtype: ``dict``"""
    map = {}
    for k, v in files.items():
        is_list = isinstance(v, list)
        l = v if is_list else [v]
        for i in range(len(l)):
            map[str(len(map))] = [f"variables.{k}.{i}" if is_list else f"variables.{k}"]
    return map 
[docs]def pack_files(files):
    """Takes a files dict and packs them into a HTTP sendable form.
    
    :param dict files: the files dict.
    :rtype: ``dict``"""
    packed_files = {}
    for file in files.values():
        l = file if isinstance(file, list) else [file]
        for f in l:
            packed_files[str(len(packed_files))] = (
                f.name, f.read(), mimetypes.MimeTypes().guess_type(f.name)[0]
            )
    return packed_files 
[docs]def create_response_error_message(response):
    """Works out what to say about a response that isn't JSON.
    :param response: The HTTP response object.
    :rtype: ``str``"""
    content_type = response.headers["Content-type"]
    try:
        content = response.content.decode()
    except: content = None
    message = f"Server did not return JSON, it returned {content_type}"
    if content and len(content) < 256:
        message += ":\n" + content
    return message