This file describes cuda_core, the high-level Pythonic CUDA subpackage in the
cuda-python monorepo.
- Role: provide higher-level CUDA abstractions (
Device,Stream,Program,Linker, memory resources, graphs) on top ofcuda.bindings. - API intent: keep interfaces Pythonic while preserving explicit CUDA behavior and error visibility.
- API stability:
cuda_coreis v1.0+; avoid breaking public APIs. Prefer compatibility/deprecation paths and document intentional public changes in docs and release notes. - Compatibility: changes should remain compatible with the supported CUDA major-version matrix.
- Main package:
cuda/core/contains most Cython modules (*.pyx,*.pxd) implementing runtime behaviors and public objects. - Subsystems:
- memory/resource stack:
cuda/core/_memory/ - system-level APIs:
cuda/core/system/ - compile/link path:
_program.pyx,_linker.pyx,_module.pyx - execution path:
_launcher.pyx,_launch_config.pyx,_stream.pyx
- memory/resource stack:
- C++ helpers: module-specific C++ implementations live under
cuda/core/_cpp/. - Build backend:
build_hooks.pyhandles Cython extension setup and build dependency wiring.
build_hooks.pydetermines CUDA major version fromCUDA_CORE_BUILD_MAJORor CUDA headers (CUDA_HOME/CUDA_PATH) and uses it for build decisions.- Source builds require CUDA headers available through
CUDA_HOMEorCUDA_PATH. cuda_coreexpectscuda.bindingsto be present and version-compatible.
- Primary tests:
pytest tests/ - Cython tests:
- build:
tests/cython/build_tests.sh(or platform equivalent) - run:
pytest tests/cython/
- build:
- Examples: validate affected examples in
examples/when changing user workflows or public APIs. - Orchestrated run: from repo root,
scripts/run_tests.sh core.
- Runtime env vars commonly relevant:
CUDA_PYTHON_CUDA_PER_THREAD_DEFAULT_STREAMCUDA_PYTHON_DISABLE_MAJOR_VERSION_WARNING
- Build env vars commonly relevant:
CUDA_HOME/CUDA_PATHCUDA_CORE_BUILD_MAJORCUDA_PYTHON_PARALLEL_LEVELCUDA_PYTHON_COVERAGE
- Keep user-facing behaviors coherent with docs and examples, especially around stream semantics, memory ownership, and compile/link flows.
- Reuse existing shared utilities in
cuda/core/_utils/before adding new helpers. - When changing Cython signatures or cimports, verify related
.pxdand call-site consistency. - Prefer explicit error propagation over silent fallback paths.
- If you change public behavior, update tests and docs under
docs/source/. - For new public APIs or broad feature work, sketch the API and behavior in an
issue/design discussion before opening a large implementation PR. Reviewers
often block major
cuda_corefeatures until API shape, compatibility impact, examples, and docs/release-note coverage are clear. - Feature availability checks should query CUDA driver/device capabilities instead of hard-coding broad platform skips. Prefer properties such as capability flags over assumptions like "Windows", "Linux", or "WSL".
- Preserve compatibility with the supported CUDA major-version matrix. Do not directly cimport newly generated binding symbols unless older supported CUDA-major builds are gated or have a wrapper/fallback path.
- Resource and context-manager code must preserve stream ordering, ownership,
and exception semantics.
close()/cleanup paths should use the stream that established the resource ordering, and__exit__should avoid masking a user's original exception where practical. - Tests should cover the behavior users exercise, not just private helpers. Avoid large module-stubbing tests for simple implementation choices; prefer focused regressions around the public API or the smallest stable internal boundary.
These are some API design guidelines we try to follow when adding new APIs to
cuda.core. These rules only apply to public APIs. Private implementation
details can violate these rules at any time.
Public APIs are defined as symbols defined in __all__ within modules or
subpackages that are not prefixed with _.
In code reviews, any violations of this section should be considered suggestions, not hard rules. Consistency with existing API design in this code base is also important.
The following things should not be exposed as part of the public API:
- Private symbols (prefixed with
_) - Symbols from a third-party module or the standard library
- Helper classes that can not be instantiated from Python
As a blanket rule, we follow the naming guidelines for capitalization in PEP 8.
Naming should be consistent. We should use the same English words for the same concepts throughout the public API. When abbreviations are used, they should be commonly understood, and they should also be used consistently across the public API.
For all attributes of a class:
- Properties and member variables should be nouns
- Methods should be verbs
- Methods that take no arguments, are idempotent and cheap (O(1) or trivial), and do not mutate observable state should be properties
Make sure conceptual pairs match, e.g. add/remove, get/set, create/delete, alloc/free.
Free functions should be verbs.
Enumerations from the underlying cuda_bindings should not be re-exposed.
Instead, a new StrEnum subclass should be used to define the values. Anywhere
a StrEnum is accepted as an argument, a str should also be acceptable. An
invalid value should raise an exception. When a function returns a str drawn
from a small number of values, return a StrEnum subclass instead.
Raising exceptions is preferred over a C-style return code that must be checked by the user.
Python or Cython type annotations should be included for all public APIs. Avoid
the use of Any unless absolutely necessary. The argument and return types as
defined in the docstrings should match the type annotations.
Python imports should generally be outside of an if typing.TYPE_CHECK: block, even if the imported object is only used in type annotations. Use if typing.TYPE_CHECK: only to avoid creating import cycles. (This guidance maximizes compatibility with the cross-reference mechanisms in Sphinx.)
APIs should exist for both manual resource management (such as close()) and
automatic resource management, using context managers or destructors where
appropriate. Context managers should be implemented with __enter__ and
__exit__, not contextlib.contextmanager. For destructors use __dealloc__
where possible, otherwise __del__.
The entirety of the public API should be documented in api.rst or one of the
subpages linked from it. Classes that are not directly instantiable but which
may be returned through the public API should be documented in api_private.rst
so that they are documented but don't appear in the main index.
Reviews should point out where existing public APIs are broken.