from io import StringIO
import tabnanny
import tokenize


def get_parse_error(code):
    """
    Checks code for ambiguous tabs or other basic parsing issues.

    :param code: a string containing a file's worth of Python code
    :returns: a string containing a description of the first parse error encountered,
              or None if the code is ok
    """
    # note that this uses non-public elements from stdlib's tabnanny, because tabnanny
    # is (very frustratingly) written only to be used as a script, but using it that way
    # in this context requires writing temporarily files, running subprocesses, blah blah blah
    code_buffer = StringIO(code)
    try:
        tabnanny.process_tokens(tokenize.generate_tokens(code_buffer.readline))
    except tokenize.TokenError as err:
        return f"Could not parse code: {err}"
    except IndentationError as err:
        return f"Indentation error: {err}"
    except tabnanny.NannyNag as err:
        return f"Ambiguous tab at line {err.get_lineno()}; line is '{err.get_line()}'."
    return None