pcython 3.08 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
#!/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):
15 16 17 18 19 20 21 22 23 24 25
    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')
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87

    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():
88 89
    options, args = parse_args()
    python = options.python
90

91
    if options.version:
92 93 94
        print_versions(python)
        return

95 96
    if options.command:
        run_cython_command(python, options.command, args)
97

98 99 100
    if args:
        if args[0] == '-':
            run_python_stdin(python, args[1:], options.directives)
101
        else:
102
            run_python_file(python, args, options.directives)
103 104 105 106


if __name__ == '__main__':
    main()