PyOpenCL: OpenCL from Python with numpy arrays and error checking
OpenCL integration for Python, plus shiny features
At a glance
- What is it?
- PyOpenCL is a Python binding for OpenCL that turns every CL error into a Python exception, ties device object cleanup to Python lifetimes, and gives you numpy arrays that can be used directly as kernel arguments. It suits a numerical Python codebase that needs to run on GPUs, and the install path still depends on a working OpenCL implementation, which is where most of the friction lives.
- Who is it for?
- PyOpenCL suits a Python scientific codebase that needs to reach an OpenCL device without writing C++ extensions, and that wants numpy arrays passed straight to kernels with exceptions instead of error codes. It does not suit a team that wants a portable API over NVIDIA and AMD hardware, since OpenCL support varies by driver, and it does not suit someone without an OpenCL implementation, because the package is only a binding.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 2 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 25, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A binding built for exception handling and object lifetimes
PyOpenCL gives Python access to GPUs and other massively parallel compute devices, and it is deliberately built in the spirit of its sister project PyCUDA. The design goals are stated plainly. Object cleanup is tied to the lifetime of objects, an idiom called RAII in C++, which is meant to make it easier to write correct, leak free and crash free code. Every obscure get_info() query and all CL calls are reachable, so the full API is available. All CL errors are automatically translated into Python exceptions, which is the single biggest ergonomic difference from a raw C binding. And the base layer is written in C++, so those behaviours are described as virtually free rather than as a Python level emulation. The consequences for a user are practical. A kernel launch that fails raises an exception carrying the CL error code, and a buffer that goes out of scope is released, so you do not have to write explicit teardown paths for every device object. The package is MIT licensed and free for commercial, academic and private use, and the documentation states it was tested and works with Apple's, AMD's and Nvidia's CL implementations.
The repository is set up for that C++ core. The source lives in src/, the Python package in pyopencl/, the build is driven by scikit-build-core with nanobind doing the binding generation, and there is a CMakeLists.txt at the top level. A stubgen/ directory holds the type stub generation, and a .basedpyright/ directory configures the type checker, which the test extras pull in alongside pytest, ruff and mako.
The install needs an OpenCL implementation, not just the package
This is the practical trap. PyOpenCL is a binding, so on its own it has nothing to talk to. The README points at a four step install using Conda on Linux and macOS, and makes the point that the Conda route also installs a working OpenCL implementation, which removes the usual separate step. Binary wheels are published on the Python package index for Linux, macOS and Windows, and Conda Forge carries binary packages for the same three platforms, so the common case is a pip or conda install rather than a build. When you do build from source, the README lists what you need. A g++ or clang new enough to be compatible with nanobind, which specifically means full C++17 support, numpy, and an OpenCL implementation, with a howto link for getting one.
The optional extras are worth knowing about because they change how you test. The oclgrind extra pulls in oclgrind-binary-distribution, and the pocl extra pulls in pocl-binary-distribution. Having one of those installed means a test suite can run without a GPU present, which is the difference between a test suite that runs in continuous integration and one that only runs on the machine with the accelerator. The project also ships a test/ directory and a scripts/ directory, and the CI runs on both GitHub and GitLab, with the GitLab pipeline badge pointing at the gitlab.tiker.net mirror rather than GitHub.
Numpy arrays as kernel arguments, and the copy you should know about
The headline feature is that numpy arrays can be passed to kernels directly, and the examples directory shows the range of ways to do it. There is demo_array.py for the plain case, demo_array_svm.py for the shared virtual memory path, demo_elementwise.py and demo_elementwise_complex.py for elementwise kernels, demo-struct-reduce.py for reductions over structured data, and demo_meta_codepy.py and demo_meta_template.py for the meta programming layer where the kernel is generated in Python. There are also larger examples, n-body.py, pi-monte-carlo.py, mandelbrot, transpose.py, median-filter.py and a black-hole-accretion simulation, plus the interop examples gl_interop_demo.py and gl_particle_animation.py for sharing buffers with OpenGL, and ipython-demo.ipynb for working inside a notebook.
The copy semantics are the thing to understand before you write a kernel, because this is where the performance story actually lives. A numpy array lives in host memory, and a device buffer lives in device memory, so passing one to a kernel involves either a transfer or a mapping of host memory into the device address space. PyOpenCL gives you both routes, which is why demo_array.py and demo_array_svm.py sit side by side in the examples. The buffer protocol path is straightforward and portable, and the SVM path avoids a copy when the hardware supports it, at the cost of portability. The dump-performance.py and dump-properties.py examples exist to show what the device can actually do, and the repository topics name the algorithmic areas the library cares about, prefix sum, reduction and sorting, which are the primitives you write when you need a fast scan or a fast sum and cannot use a vendor primitive.
A 2026 release train and a version scheme tied to the calendar
The versioning here does not follow the usual semantic version convention, and that is worth knowing before you pin. The current version is 2026.1.4, and the release list shows 2026.1.2, 2026.1.3 and 2026.1.4 all published on 2026-08-25 within a few minutes of each other, which suggests a batch release rather than three separate changes. The pyproject.toml records the same 2026.1.4 string, and the year based scheme makes the release cadence legible at a glance, since a number that starts with 2026 is from this year. The metadata classifies the package as Production/Stable and requires Python 3.10 or newer and below 4. The runtime dependencies are a short list: numpy, platformdirs at 4.6 or newer because that version added support for the XDG variables on macOS, pytools at 2025.1.6 or newer, and typing_extensions at 4.6 or newer for the Buffer override. The project carries a CITATION.cff file and a Zenodo DOI badge, which is the convention for a package that gets cited in academic work, and the last push to main was on 2026-10-19, so the branch is moving even though the last tagged release is from August.
On licensing, the README states the MIT licence and the pyproject metadata records the same, while the repository listing shows a LICENSE file and GitHub classifying the licence as one it cannot categorise, so the LICENSE file in the repository is the place to read the authoritative terms if the difference matters to you.
Where PyOpenCL is the wrong tool
Four cases argue against it. The first is a project that needs portable GPU code. OpenCL support in drivers is uneven, and the README's own claim is that the library was tested and works with Apple's, AMD's and Nvidia's implementations, which is a statement about three vendors rather than about every device, and a machine with a consumer NVIDIA card may expose a vendor specific path instead. If your requirement is one code path that works everywhere, a library built on a single vendor runtime or on a higher level framework that hides the backend is a different bet. The second is a team that wants array programming rather than kernel writing. PyOpenCL is a binding to a low level API, so you write kernels and think about buffers, contexts and queues, and if your actual need is a few elementwise operations on large arrays, the higher level array libraries are a smaller commitment. The third is a CPU only deployment where you want the code to run anywhere without a GPU. That works, but only because of the pocl or oclgrind extras, and those are development aids rather than something to plan a production deployment around. The fourth is a project that cannot take a native dependency. The package needs a C++ compiler and a working OpenCL loader at install time when wheels are not available for the platform, and the nanobind and C++17 requirement sets a floor for the toolchain. None of this makes the library a poor fit for its audience, which is a scientific Python developer who needs direct device access with sane error handling and numpy interoperability.
Editorial conclusion
PyOpenCL suits a Python scientific codebase that needs to reach an OpenCL device without writing C++ extensions, and that wants numpy arrays passed straight to kernels with exceptions instead of error codes. It does not suit a team that wants a portable API over NVIDIA and AMD hardware, since OpenCL support varies by driver, and it does not suit someone without an OpenCL implementation, because the package is only a binding. Before you start, read the installation page and choose the Conda route on Linux or macOS since it also installs a working OpenCL implementation, and note that the newest release is v2026.1.4 from 2026-08-25 with the last push on 2026-10-19.
Frequently asked questions
How do I install PyOpenCL?
The README points at a four step Conda install for Linux and macOS, which also installs a working OpenCL implementation. Binary wheels are on the Python package index and binary packages are on Conda Forge for Linux, macOS and Windows, and building from source needs a C++17 capable compiler, numpy and an OpenCL implementation.
Does PyOpenCL raise exceptions when OpenCL calls fail?
Yes. All CL errors are automatically translated into Python exceptions, and object cleanup is tied to the lifetime of objects, so device resources are released rather than leaked.
Can I run PyOpenCL tests without a GPU?
The optional extras pull in alternative implementations, with oclgrind-binary-distribution and pocl-binary-distribution. Either gives you a way to run tests where no accelerator is present.
Which Python versions does PyOpenCL support?
The package metadata requires Python 3.10 or newer and below 4, and the current version is 2026.1.4 with a release train of 2026.1.2, 2026.1.3 and 2026.1.4 published on 2026-08-25.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/inducer-pyopencl)Was this useful?