Running Python

GraalVM provides an early-stage experimental implementation of Python 3.7. A primary goal is to support SciPy and its constituent libraries. At this point, the Python implementation is made available for experimentation and curious end-users.

Installing Python

Python can be installed to a GraalVM build with the gu command. See bin/gu --help for more information.

Running Python

Our implementation of Python targets Python 3.7 compatibility at the moment. While support for the Python language is still limited, you can run simple Python scripts or commands with the graalpython binary:

$ graalpython [options] [-c cmd | filename]

If no program file or command is given, you are dropped into a simple REPL.

GraalVM supports some of the same options as Python 3.7 and some additional options to control the underlying Python implementation and the GraalVM tools and execution engine. These can be viewed using the following command:

$ graalpython --help --help:tools --help:languages

Interoperability

GraalVM supports several other programming languages, including JavaScript, R, Ruby, and LLVM. GraalVM provides a Python API to interact with other languages available on the GraalVM. In fact, GraalVM uses this API internally to execute Python C extensions using the LLVM implementation in GraalVM.

To run the following script, pass the --jvm --polyglot options to graalpython binary. This makes other GraalVM languages available in scripts.

As a simple example, we can use the JavaScript regular expression engine to match Python strings:

import polyglot

re = polyglot.eval(string="RegExp()", language="js")

pattern = re.compile(".*(?:we have (?:a )?matching strings?(?:[!\\?] )?)(.*)")

if pattern.exec("This string does not match"):
    raise SystemError("that shouldn't happen")

md = pattern.exec("Look, we have matching strings! This string was matched by Graal.js")
if not md:
    raise SystemError("this should have matched")

print("Here is what we found: '%s'" % md[1])

If you put this code into a file polyglot_example.py, you can run it with:

$ graalpython --jvm --polyglot polyglot_example.py

This example matches Python strings using the JavaScript regular expression object and Python reads the captured group from the JavaScript result and prints: Here is what we found: 'This string was matched by Graal.js'.

As a more complex example, we can read a file using R, process the data in Python, and use R again to display the resulting data image, using both R and Python libraries in conjunction. To run it, first install the required R library:

$ R -e 'install.packages("https://www.rforge.net/src/contrib/jpeg_0.1-8.tar.gz", repos=NULL)'

This example also uses image_magix.py and works on a JPEG image input. (You can try with this image, for example). These files have to be in the same folder the script below is located in and executed from.

import polyglot
import sys
import time
sys.path.insert(0, ".")
from image_magix import Image

load_jpeg = polyglot.eval(string="""function(file.name) {
    library(jpeg)
    jimg <- readJPEG(file.name)
    jimg <- jimg*255
    jimg
}""", language="R")

raw_data = load_jpeg("python_demo_picture.jpg")

# the dimensions are R attributes; define function to access them
getDim = polyglot.eval(string="function(v, pos) dim(v)[[pos]]", language="R")

# Create object of Python class 'Image' with loaded JPEG data
image = Image(getDim(raw_data, 2), getDim(raw_data, 1), raw_data)

# Run Sobel filter
result = image.sobel()

draw = polyglot.eval(string="""function(processedImgObj) {
    require(grDevices)
    require(grid)
    mx <- matrix(processedImgObj$`@data`/255, nrow=processedImgObj$`@height`, ncol=processedImgObj$`@width`)
    grDevices:::awt()
    grid.raster(mx, height=unit(nrow(mx),"points"))
}""", language="R")

draw(result)
time.sleep(10)

See the Polyglot Reference and the Embedding documentation for more information about interoperability with other programming languages.

Tooling

Although GraalVM’s Python implementation is far from complete and cannot run the standard Python debugger pdb, the tools that GraalVM itself provides do work. To debug applications in the Chrome browser, for example, you can run a script like so:

$ graalpython --jvm --inspect [script-to-debug.py]
Debugger listening on port 9229.
To start debugging, open the following URL in Chrome:
    chrome-devtools://devtools/bundled/inspector.html?ws=127.0.0.1:9229/15615099-351e94d1e2db
Please note: This Python implementation is in the very early stages, and can run little more than basic benchmarks at this point.

The graalpython --jvm --help:tools command will give you more information about tools currently supported on Python.

Native Images and JVM Runtime

By default, GraalVM runs Python from an ahead-of-time compiled binary, yielding faster startup time and lower footprint. However, the ahead-of-time compiled binary only includes the Python and LLVM interpreters. To interoperate with other languages, we had to supply the --jvm argument above. This instructs the launcher to run on the JVM instead of from the native code – you will notice a longer startup time.

Python Compatibility

Is GraalVM compatible with the Python language?

GraalVM’s implementation of Python is in the early stages of development. A primary goal is to support SciPy and its constituent libraries, but we have a long way to go there. At this point, the Python implementation is made available for experimentation and curious end-users. GraalVM currently aims to be compatible with Python 3.7, but it is a long way from there, and it is very likely that any Python program that requires any imports at all will hit something unsupported.

Is there any progress in GraalVM and Python packages compatibility?

It is too early to claim that there are any Python packages that GraalVM is compatible with.

Python Command Options

Python is run using graalpython [option] ... (-c cmd | file) [arg] ... and supports some of the same options as the standard Python interpreter:

  • -c cmd: program passed in as string (terminates option list)
  • -h: print this help message and exit (also --help)
  • -i: inspect interactively after running script; forces a prompt even if stdin does not appear to be a terminal; also PYTHONINSPECT=x
  • -V: Print the Python version number and exit (also --version)
  • file: Program read from script file
  • arg ...: Arguments passed to program in sys.argv[1:]

Here are some GraalVM-specific options:

  • --python.PythonInspectFlag: This is equivalent to Python’s -i option (see above).
  • -CC: Run clang and then opt with the arguments required to build a GraalVM and Sulong compatible LLVM bitcode file.
  • -LD: Run llvm-link with the appropriate options to bind multiple LLVM bitcode files into one that can be used on GraalVM with Sulong.

The following options are mostly useful for developers of the language or to provide bug reports:

  • --python.CoreHome=<String>: The path to the core library of Python that is written in Python. This usually resides in a folder lib-graalpython in the GraalVM distribution.
  • --python.StdLibHome=<String>: The path to the standard library that Python will use. Usually this is in a under lib-python/3 in the GraalVM distribution, but any Python 3.7 standard library location may work.
  • --python.WithJavaStacktrace: Prints a Java-level stack trace besides the normal Python stack when errors occur.
  • --python.LazyInit: Load the core library after the Python context has been initialized. This only affects certain tools such as the Chrome debugger and lets these tools also see the code in the Python core library.
  • --python.SharedCore: This option is not fully implemented, yet. It will allow sharing parts of the core library across multiple Python contexts, which will improve startup time of subsequent contexts.

There are a few other debugging options used by the developers of GraalVM, but these change frequently and may not do anything at any given point in time, so any observed effects of them should not be relied upon.