#!/usr/bin/env python

"""
Script to run Cython with a Python command line.

Executes Python code by compiling it in Cython and running the compiled code.
"""


import sys
import subprocess


def parse_args(args=None):
    import optparse  # tried argparse, but it doesn't stop at the first (interspersed) positional argument
    parser = optparse.OptionParser(description='Run a Python command line with Cython')
    parser.disable_interspersed_args()
    parser.add_option('-c', metavar='CODE', dest='command',
                      help='program passed in as string')
    parser.add_option('--python', metavar='PYTHON', dest='python', default=sys.executable,
                      help='Python interpreter to use')
    parser.add_option('-X', metavar='NAME=VALUE', dest='directives', action='append',
                      help='Compiler directives to set during compilation')
    parser.add_option('-V', '--version', action='store_true',
                      help='print the Python and Cython version numbers and exit')

    return parser.parse_args(args)


def run_python(python, command):
    subprocess.check_call([python, '-c', command])


def print_versions(python):
    """Print version numbers of Python and Cython.
    """
    command = (
        "import sys, Cython; "
        "print('Python {}'.format('.'.join(map(str, sys.version_info[:3])))); "
        "print('[Cython {}]'.format(Cython.__version__))"
    )
    run_python(python, command)


def run_cython_command(python, command, args=None):
    """Compile and run a Python command string.
    """
    command = (
        "import sys; "
        "from Cython.Build.Inline import cython_inline; "
        "sys.argv[1:] = {args!r}; "
        "(lambda: cython_inline({code!r}, quiet=True))()"
    ).format(code=command, args=list(args) if args else [])
    run_python(python, command)


def run_python_stdin(python, file_args=None, directives=None):
    """Compile and run a Python program from stdin.
    """
    import shutil
    import tempfile

    with tempfile.NamedTemporaryFile(suffix='.py') as f:
        shutil.copyfileobj(sys.stdin, f)
        f.flush()

        file_args = [f.name] + list(file_args or ())
        run_python_file(python, file_args, directives)


def run_python_file(python, file_args, directives=None):
    """Compile and run a Python program from a file.
    """
    args = []
    if directives:
        for directive in directives:
            args.extend(('-X', directive))
    args.extend(file_args)
    command = (
        "import Cython.Build.BuildExecutable as bex; "
        "bex.DEBUG = False; "
        "bex.build_and_run({args!r})"
    ).format(args=args)
    run_python(python, command)


def main():
    options, args = parse_args()
    python = options.python

    if options.version:
        print_versions(python)
        return

    if options.command:
        run_cython_command(python, options.command, args)

    if args:
        if args[0] == '-':
            run_python_stdin(python, args[1:], options.directives)
        else:
            run_python_file(python, args, options.directives)


if __name__ == '__main__':
    main()
