# PyCUDA: Python bindings for Nvidia's CUDA driver API with RAII cleanup and automatic error checking

> PyCUDA wraps Nvidia's CUDA driver API for Python, adding RAII-style resource management and automatic translation of CUDA errors into Python exceptions. Its base layer is C++, and the higher-level abstractions for GPU arrays and kernel compilation sit on top without measurable Python overhead.

**inducer/pycuda** — CUDA integration for Python, plus shiny features

- Repository: https://github.com/inducer/pycuda
- Website: http://mathema.tician.de/software/pycuda
- Stars: 2,052 · Forks: 299
- Language: Python
- License: NOASSERTION
- Published: 2026-10-11 · Updated: 2026-10-11 · Language: en
- Canonical page: https://hysenlabs.com/projects/inducer-pycuda

## RAII and dependency tracking prevent CUDA context leaks in Python code

The first problem PyCUDA addresses is resource cleanup. CUDA contexts and GPU memory allocations have lifetimes that C programmers manage by hand, and a forgotten free call can corrupt state in ways that are hard to trace. PyCUDA ties cleanup to Python object lifetime through RAII, the C++ pattern where resource acquisition and release are bound to object construction and destruction.

PyCUDA also tracks dependencies between objects, so it will not detach from a context before all memory allocated in that context has been freed. Without this tracking, a program that destroys a context while device memory is still referenced would produce undefined behaviour. Making that class of bug impossible to express accidentally is the practical benefit, compared with requiring the programmer to sequence cleanup calls correctly.

## All CUDA errors surface as Python exceptions instead of integer return codes

CUDA's C API communicates failures through integer return codes. Every call returns a status value, and a caller that ignores it silently swallows the error. PyCUDA translates every CUDA error into a Python exception automatically, removing the need to check return codes after each call.

For Python code this changes the debugging workflow entirely. Exceptions propagate through the call stack and surface at the first unhandled frame, so a failed kernel launch or allocation becomes visible immediately rather than producing subtle wrong results downstream. Python's existing try/except and context manager patterns apply directly to GPU errors without any additional wrapper code.

This is what the README calls 'Automatic Error Checking': all CUDA errors are automatically translated into Python exceptions.

## pycuda.driver.SourceModule compiles CUDA C at runtime from a string

One of PyCUDA's two named convenience abstractions is `pycuda.driver.SourceModule`. It takes a string containing CUDA C source code, compiles it to a module at runtime, and exposes the resulting kernels as callable Python objects. A kernel can be constructed programmatically and compiled on the fly rather than requiring a separate offline compilation step.

The lower level of `pycuda.driver` also exposes context, device, stream, and memory management routines directly from the full CUDA driver API, making SourceModule a convenience layer on top of a complete binding rather than a limited high-level wrapper.

The examples directory contains demo_meta_template.py and demo_meta_codepy.py alongside demo_elementwise.py and demo_struct.py, which illustrate different ways to drive these runtime compilation facilities.

## pycuda.gpuarray.GPUArray exposes NumPy-style operations and supports the CUDA Array Interface

The second named abstraction is `pycuda.gpuarray.GPUArray`. It provides an array type that lives in GPU memory and supports NumPy-style operations, so common element-wise work can be expressed in Python without writing explicit CUDA kernel calls.

The examples directory includes `cai_cupy_arrays.py` and `cai_numba.py`, whose names indicate support for the CUDA Array Interface, a protocol for sharing GPU buffer ownership between libraries. The README's feature list does not name this explicitly, so this interoperability is visible only through the example files. It matters for projects that mix PyCUDA with CuPy or Numba: if a CuPy or Numba array already holds the data, PyCUDA can access that memory directly without copying through the CPU.

## Building PyCUDA requires nvcc in PATH, numpy 1.24 or newer, and the CUDA toolkit headers

PyCUDA's base layer is C++, so installation requires compiling extension modules against the CUDA toolkit. The pyproject.toml file names the Python build requirements:

```toml
[build-system]
requires = [
    "setuptools",
    "wheel",
    "numpy>=1.24",
]
```

At build time, setup.py searches for nvcc or nvcc.exe in the system PATH. When nvcc is found, the script derives the CUDA root automatically by going one directory above the nvcc binary. No additional path configuration is needed in that common case. When nvcc is absent from PATH, the script prints a warning and notes that CUDA_INC_DIR may need to be set for the build to succeed.

On Windows, setup.py substitutes lib/x64 for the default lib64 library path. On macOS, it searches under `/Developer/NVIDIA/CUDA-*` for an existing installation, and README_SETUP.txt at the repository root covers the complete build procedure including environment variables and platform-specific notes.

## The full CUDA driver API is exposed, including OpenGL interoperability

PyCUDA's README names 'Completeness' as a design goal: the full power of CUDA's driver API is available when the high-level abstractions are not enough. Code for interoperability with OpenGL is also included.

OpenGL interoperability allows a GPU buffer computed by CUDA to be passed directly to OpenGL for rendering, without copying back to CPU memory first. For real-time simulation or visualisation pipelines, that zero-copy path eliminates a frame-time-dominating round trip.

PyOpenCL, described in the README as a sister project for like-minded computing, provides the same Python-wrapping pattern for OpenCL devices. PyOpenCL runs on Nvidia, AMD and Intel GPUs among other hardware, unlike PyCUDA which is exclusively bound to the Nvidia CUDA driver API.

## PyCUDA only runs on Nvidia hardware, and the C++ base layer makes per-call overhead negligible

PyCUDA binds to the CUDA driver API, an Nvidia proprietary interface. There is no path to run PyCUDA code on AMD, Intel or Apple GPUs. For projects where vendor portability is a requirement, PyOpenCL provides equivalent functionality across OpenCL-capable devices, though it cannot expose Nvidia-specific capabilities such as Tensor Core operations.

On the performance side, PyCUDA's base layer is written in C++ and the README characterises the convenience features as virtually free in terms of speed. The Python-level overhead per CUDA call is thin because the bindings call directly into the C++ layer. For workloads that launch a few large kernels, per-call overhead is irrelevant. For workloads that issue many small operations in a loop, the lightweight binding matters more.

Version v2026.1 was published on 2026-01-15, and v2025.1.3 followed on 2026-02-18.

## Conclusion

PyCUDA suits Python projects that need the full CUDA driver API with RAII-style resource cleanup to prevent context leaks. Avoid it when vendor-neutral GPU code is a requirement, because the CUDA API is Nvidia-only; PyOpenCL covers the same programming model for OpenCL devices. Before building, confirm nvcc is in PATH, since the setup script derives the CUDA root automatically from its location and CUDA_INC_DIR is only needed when nvcc is absent. The last push was on 2026-09-12, and the licence is a custom one that GitHub cannot classify; the LICENSE file at the repository root holds the full text.

## FAQ

### What is PyCUDA?

PyCUDA gives Python code access to Nvidia's CUDA parallel computation API. It adds RAII-style resource cleanup, automatic conversion of CUDA errors into Python exceptions, and two named abstractions: pycuda.driver.SourceModule for runtime kernel compilation and pycuda.gpuarray.GPUArray for NumPy-style GPU arrays.

### How do I install PyCUDA?

Building PyCUDA requires nvcc in PATH and numpy 1.24 or newer. The setup script searches for nvcc at build time and derives the CUDA root from its location automatically. The README_SETUP.txt file at the repository root covers the full build procedure.

### What is the difference between PyCUDA and PyOpenCL?

PyCUDA wraps Nvidia's CUDA driver API and runs only on Nvidia GPUs. PyOpenCL, described in the README as a sister project, provides the same Python-friendly wrapping pattern for OpenCL devices, which run on Nvidia, AMD and Intel GPUs among others.

### Does PyCUDA work on non-Nvidia GPUs?

No. PyCUDA binds to the CUDA driver API, which is Nvidia-only. PyOpenCL is the alternative named in the README for OpenCL-capable hardware.

### Can PyCUDA exchange GPU buffers with CuPy or Numba?

The examples directory includes cai_cupy_arrays.py and cai_numba.py, whose names indicate support for the CUDA Array Interface for sharing GPU buffer ownership between libraries. The README does not name this explicitly.

## Sources

- [inducer/pycuda on GitHub](https://github.com/inducer/pycuda)
- [Issues](https://github.com/inducer/pycuda/issues)
- [Project website](http://mathema.tician.de/software/pycuda)
- [README](https://github.com/inducer/pycuda/blob/main/README.md)
- [Releases](https://github.com/inducer/pycuda/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/inducer-pycuda
