def determine_how_to_read_input(input_obj):
    """ given some kind of input object, return a function that knows how to
    read chunks of that input object.
    
    each reader function should return a chunk and raise a DoneReadingForever
    exception, or return None, when there's no more data to read

    NOTE: the function returned does not need to care much about the requested
    buffering type (eg, unbuffered vs newline-buffered).  the StreamBufferer
    will take care of that.  these functions just need to return a
    reasonably-sized chunk of data. """

    get_chunk = None

    if isinstance(input_obj, Queue):
        log_msg = "queue"
        get_chunk = get_queue_chunk_reader(input_obj)

    elif callable(input_obj):
        log_msg = "callable"
        get_chunk = get_callable_chunk_reader(input_obj)

    # also handles stringio
    elif hasattr(input_obj, "read"):
        log_msg = "file descriptor"
        get_chunk = get_file_chunk_reader(input_obj)

    elif isinstance(input_obj, basestring):
        log_msg = "string"
        get_chunk = get_iter_string_reader(input_obj)

    elif isinstance(input_obj, bytes):
        log_msg = "bytes"
        get_chunk = get_iter_string_reader(input_obj)

    elif isinstance(input_obj, GeneratorType):
        log_msg = "generator"
        get_chunk = get_iter_chunk_reader(iter(input_obj))

    else:
        try:
            it = iter(input_obj)
        except TypeError:
            raise Exception("unknown input object")
        else:
            log_msg = "general iterable"
            get_chunk = get_iter_chunk_reader(it)

    return get_chunk, log_msg
given some kind of input object, return a function that knows how to
    read chunks of that input object.
    
    each reader function should return a chunk and raise a DoneReadingForever
    exception, or return None, when there's no more data to read

    NOTE: the function returned does not need to care much about the requested
    buffering type (eg, unbuffered vs newline-buffered).  the StreamBufferer
    will take care of that.  these functions just need to return a
    reasonably-sized chunk of data.