Generates and sends a query to DuckDuckGo API.

    Args:
        query_string: Query to be passed to DuckDuckGo API.
        secure: Use secure SSL/TLS connection. Default - False.
            Syntactic sugar is secure_query function which is passed the same
            parameters.
        container: Indicates how dict-like objects are serialized. There are
           two possible options: namedtuple and dict. If 'namedtuple' is passed
           the objects will be serialized to namedtuple instance of certain
           class. If 'dict' is passed the objects won't be deserialized.
           Default value: 'namedtuple'.
        verbose: Don't raise any exception if error occurs.
            Default value: False.
        user_agent: User-Agent header of HTTP requests to DuckDuckGo API.
            Default value: 'duckduckpy 0.2'
        no_redirect: Skip HTTP redirects (for !bang commands).
            Default value: False.
        no_html: Remove HTML from text, e.g. bold and italics.
            Default value: False.
        skip_disambig: Skip disambiguation (D) Type. Default value: False.

    Raises:
        DuckDuckDeserializeError: JSON serialization failed.
        DuckDuckConnectionError: Something went wrong with client operation.
        DuckDuckArgumentError: Passed argument is wrong.

    Returns:
        Container depends on container parameter. Each field in the response is
        converted to the so-called snake case.

    Usage:
        >>> import duckduckpy
        >>># Namedtuple is used as a container:
        >>> response = duckduckpy.query('Python')
        >>> response
        Response(redirect=u'', definition=u'', image_width=0, ...}
        >>> type(response)
        <class 'duckduckpy.api.Response'>
        >>> response.related_topics[0]
        Result(first_url=u'https://duckduckgo.com/Python', text=...)
        >>> type(response.related_topics[0])
        <class 'duckduckpy.api.Result'>

        >>># Dict is used as a container:
        >>> response = duckduckpy.query('Python', container='dict')
        >>> type(response)
        <type 'dict'>
        >>> response
        {u'abstract': u'', u'results': [], u'image_is_logo': 0, ...}
        >>> type(response['related_topics'][0])
        <type 'dict'>
        >>> response['related_topics'][0]
        {u'first_url': u'https://duckduckgo.com/Python', u'text': ...}

def query(query_string, secure=False, container='namedtuple', verbose=False,
          user_agent=api.USER_AGENT, no_redirect=False, no_html=False,
          skip_disambig=False):
    """
    Generates and sends a query to DuckDuckGo API.

    Args:
        query_string: Query to be passed to DuckDuckGo API.
        secure: Use secure SSL/TLS connection. Default - False.
            Syntactic sugar is secure_query function which is passed the same
            parameters.
        container: Indicates how dict-like objects are serialized. There are
           two possible options: namedtuple and dict. If 'namedtuple' is passed
           the objects will be serialized to namedtuple instance of certain
           class. If 'dict' is passed the objects won't be deserialized.
           Default value: 'namedtuple'.
        verbose: Don't raise any exception if error occurs.
            Default value: False.
        user_agent: User-Agent header of HTTP requests to DuckDuckGo API.
            Default value: 'duckduckpy 0.2'
        no_redirect: Skip HTTP redirects (for !bang commands).
            Default value: False.
        no_html: Remove HTML from text, e.g. bold and italics.
            Default value: False.
        skip_disambig: Skip disambiguation (D) Type. Default value: False.

    Raises:
        DuckDuckDeserializeError: JSON serialization failed.
        DuckDuckConnectionError: Something went wrong with client operation.
        DuckDuckArgumentError: Passed argument is wrong.

    Returns:
        Container depends on container parameter. Each field in the response is
        converted to the so-called snake case.

    Usage:
        >>> import duckduckpy
        >>># Namedtuple is used as a container:
        >>> response = duckduckpy.query('Python')
        >>> response
        Response(redirect=u'', definition=u'', image_width=0, ...}
        >>> type(response)
        <class 'duckduckpy.api.Response'>
        >>> response.related_topics[0]
        Result(first_url=u'https://duckduckgo.com/Python', text=...)
        >>> type(response.related_topics[0])
        <class 'duckduckpy.api.Result'>

        >>># Dict is used as a container:
        >>> response = duckduckpy.query('Python', container='dict')
        >>> type(response)
        <type 'dict'>
        >>> response
        {u'abstract': u'', u'results': [], u'image_is_logo': 0, ...}
        >>> type(response['related_topics'][0])
        <type 'dict'>
        >>> response['related_topics'][0]
        {u'first_url': u'https://duckduckgo.com/Python', u'text': ...}
    """
    if container not in Hook.containers:
        raise exc.DuckDuckArgumentError(
            "Argument 'container' must be one of the values: "
            "{0}".format(', '.join(Hook.containers)))

    headers = {"User-Agent": user_agent}
    url = url_assembler(
        query_string,
        no_redirect=no_redirect,
        no_html=no_html,
        skip_disambig=skip_disambig)

    if secure:
        conn = http_client.HTTPSConnection(api.SERVER_HOST)
    else:
        conn = http_client.HTTPConnection(api.SERVER_HOST)

    try:
        conn.request("GET", url, "", headers)
        resp = conn.getresponse()
        data = decoder(resp.read())
    except socket.gaierror as e:
        raise exc.DuckDuckConnectionError(e.strerror)
    finally:
        conn.close()

    hook = Hook(container, verbose=verbose)
    try:
        obj = json.loads(data, object_hook=hook)
    except ValueError:
        raise exc.DuckDuckDeserializeError(
            "Unable to deserialize response to an object")

    return obj