You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[BUG]: Tab completion with DeviceMemoryResource is broken #2053
ifisinstance(getattr(type(thisobject), word, None), property):
matches.append(match) # skip getattr(obj, word)continueif (value:=getattr(thisobject, word, None)) isnotNone:
...
However, Cython cdef class properties generate getset_descriptor objects, not Python property objects. The isinstance(..., property) guard does not fire for them. When getattr(obj, word, None) is called, it only catches AttributeError — any other exception propagates uncaught, crashing attr_matches() entirely and producing zero completions.
This was flagged as a concern before the naming audit landed — see #1945 (comment):
[methods] are side-effect free with getattr/hasattr (properties are not)
The offending commit (8b55a6c) converted get_allocation_handle() from a method to a @property. As a method, getattr(mr, 'get_allocation_handle') returned the bound method object (no side effects). As a property, getattr(mr, 'allocation_handle') invokes the getter, which raises RuntimeError for non-IPC resources — and crashes the completer.
Note
This is a known upstream CPython issue: python/cpython#112821 ("Reconsider BPO 44752 changes in rlcompleter since exceptions in descriptors cause auto completion to fail"). Filed Dec 2023, still open.
Impact audit
I audited every Cython @property in cuda/core/ that can raise a non-AttributeError exception. Only Cython cdef class properties (getset_descriptor) are affected — pure Python property descriptors are handled correctly by the rlcompleter guard.
Tab completion is effectively broken for all classes listed below. The triggering conditions are not edge cases — they are the default or common states for these objects (non-IPC is the default for memory resources and events; NVML queries fail on many GPU models; contexts get closed during normal lifecycle).
IPC-related properties (non-IPC is the default — affects most users):
Class
Property
Exception
Condition
DeviceMemoryResource
allocation_handle
RuntimeError
non-IPC MR (the default)
PinnedMemoryResource
allocation_handle
RuntimeError
non-IPC MR (the default)
Event
ipc_descriptor
RuntimeError
non-IPC event (the default)
Buffer
ipc_descriptor
RuntimeError
buffer from non-IPC MR
NVML-backed properties (raises on GPUs that don't support the query):
Class
Property
Exception
Condition
system.Device
attributes
NotSupportedError
GPU doesn't support NVML query
system.Device
is_auto_boosted_clocks_enabled
NotSupportedError
GPU doesn't support feature
system.Device
is_c2c_enabled
NotSupportedError
GPU doesn't support C2C
system.Device
numa_node_id
NotSupportedError
GPU doesn't expose NUMA node
Other properties:
Class
Property
Exception
Condition
Context
resources
RuntimeError
closed context
DeviceResources
workqueue
RuntimeError
hardware-dependent
GraphBuilder
is_building
NotImplementedError
unknown capture status
system.Device
current_clock_event_reasons
ValueError
unknown clock event bit
system.Device
supported_clock_event_reasons
ValueError
unknown clock event bit
Not affected (abstract base, never instantiated directly): MemoryResource.{is_device_accessible, is_host_accessible, device_id} — TypeError, but only hit on bare MemoryResource instances.
Not affected (pure Python class, rlcompleter guard works): LegacyPinnedMemoryResource.device_id — RuntimeError, but isinstance(desc, property) is True, so rlcompleter skips it.
cuda-python workaround — raise AttributeError instead: getattr(obj, name, None) catches AttributeError, so changing raise RuntimeError(...) to raise AttributeError(...) in the affected property getters is a minimal one-line-per-property fix. Downside: semantically misleading (the attribute exists, it's just unusable in the current state), and CPython appends a "Did you mean: ...?" suggestion that can be confusing.
cuda-python workaround — return None instead of raising:
Properties like allocation_handle and ipc_descriptor could return None when the feature is not enabled. Callers already need to check is_ipc_enabled first.
cuda-python workaround — revert to methods:
Keep get_allocation_handle() / get_ipc_descriptor() as methods. Methods are never evaluated by getattr() during tab completion.
cuda-python workaround — catch NVML errors in system.Device:
Wrap NVML-backed properties in try/except and return a sentinel (e.g., None or a "not supported" marker) instead of letting NotSupportedError propagate.
Upstream CPython fix (python/cpython#112821): Extend the rlcompleter guard to handle getset_descriptor (or restore the old try/except Exception around getattr). This would fix all Cython extension types, not just cuda.core.
This is a non-starter. Even if we got the bugfix in, it would be ~5 years until we could rely on it.
cuda-python workaround — raise AttributeError instead:
getattr(obj, name, None) catches AttributeError, so changing raise RuntimeError(...) to raise AttributeError(...) in the affected property getters is a minimal one-line-per-property fix. Downside: semantically misleading (the attribute exists, it's just unusable in the current state), and CPython appends a "Did you mean: ...?" suggestion that can be confusing.
This would change the semantics of the property, and the "Did you mean" would be incredibly misleading to users. They didn't misspell -- they used a feature that semantically should raise some sort of runtime error. It should be fine for us to design that way.
cuda-python workaround — return None instead of raising:
Properties like allocation_handle and ipc_descriptor could return None when the feature is not enabled. Callers already need to check is_ipc_enabled first.
This places the burden of error checking on our users. It's deeply un-Pythonic to require error code checks. We are even trying to move away from that in cuda_bindings.
cuda-python workaround — revert to methods:
Keep get_allocation_handle() / get_ipc_descriptor() as methods. Methods are never evaluated by getattr() during tab completion.
This is probably the most reasonable thing to do on this list. If we went this way, we should add some sort of a test harness that makes sure we stick to the convention that "any property that can raise an exception must be a getter instead", because we will forget. It seems frustrating to design an API around the limitations of tab completion, though, so I'm still not a huge fan.
cuda-python workaround — catch NVML errors in system.Device:
Wrap NVML-backed properties in try/except and return a sentinel (e.g., None or a "not supported" marker) instead of letting NotSupportedError propagate.
Activity
leofang commentedon May 8, 2026
Tab completion for
cuda.core.system.Deviceis broken too.leofang commentedon May 8, 2026
Root cause analysis
In CPython 3.12+,
rlcompleter.Completer.attr_matches()has a guard to skip evaluating Python properties (introduced by python/cpython#88915 / python/cpython#27401, for bpo-44752):However, Cython
cdef classproperties generategetset_descriptorobjects, not Pythonpropertyobjects. Theisinstance(..., property)guard does not fire for them. Whengetattr(obj, word, None)is called, it only catchesAttributeError— any other exception propagates uncaught, crashingattr_matches()entirely and producing zero completions.This was flagged as a concern before the naming audit landed — see #1945 (comment):
The offending commit (8b55a6c) converted
get_allocation_handle()from a method to a@property. As a method,getattr(mr, 'get_allocation_handle')returned the bound method object (no side effects). As a property,getattr(mr, 'allocation_handle')invokes the getter, which raisesRuntimeErrorfor non-IPC resources — and crashes the completer.Note
This is a known upstream CPython issue: python/cpython#112821 ("Reconsider BPO 44752 changes in rlcompleter since exceptions in descriptors cause auto completion to fail"). Filed Dec 2023, still open.
Impact audit
I audited every Cython
@propertyincuda/core/that can raise a non-AttributeErrorexception. Only Cythoncdef classproperties (getset_descriptor) are affected — pure Pythonpropertydescriptors are handled correctly by the rlcompleter guard.Tab completion is effectively broken for all classes listed below. The triggering conditions are not edge cases — they are the default or common states for these objects (non-IPC is the default for memory resources and events; NVML queries fail on many GPU models; contexts get closed during normal lifecycle).
IPC-related properties (non-IPC is the default — affects most users):
DeviceMemoryResourceallocation_handleRuntimeErrorPinnedMemoryResourceallocation_handleRuntimeErrorEventipc_descriptorRuntimeErrorBufferipc_descriptorRuntimeErrorNVML-backed properties (raises on GPUs that don't support the query):
system.DeviceattributesNotSupportedErrorsystem.Deviceis_auto_boosted_clocks_enabledNotSupportedErrorsystem.Deviceis_c2c_enabledNotSupportedErrorsystem.Devicenuma_node_idNotSupportedErrorOther properties:
ContextresourcesRuntimeErrorDeviceResourcesworkqueueRuntimeErrorGraphBuilderis_buildingNotImplementedErrorsystem.Devicecurrent_clock_event_reasonsValueErrorsystem.Devicesupported_clock_event_reasonsValueErrorNot affected (abstract base, never instantiated directly):
MemoryResource.{is_device_accessible, is_host_accessible, device_id}—TypeError, but only hit on bareMemoryResourceinstances.Not affected (pure Python class, rlcompleter guard works):
LegacyPinnedMemoryResource.device_id—RuntimeError, butisinstance(desc, property)isTrue, so rlcompleter skips it.Possible solutions
Upstream CPython fix (Reconsider gh-88915 changes rlcompleter since exceptions in descriptors cause auto completion to fail python/cpython#112821): Extend the rlcompleter guard to handle
getset_descriptor(or restore the oldtry/except Exceptionaroundgetattr). This would fix all Cython extension types, not just cuda.core.cuda-python workaround — raise
AttributeErrorinstead:getattr(obj, name, None)catchesAttributeError, so changingraise RuntimeError(...)toraise AttributeError(...)in the affected property getters is a minimal one-line-per-property fix. Downside: semantically misleading (the attribute exists, it's just unusable in the current state), and CPython appends a "Did you mean: ...?" suggestion that can be confusing.cuda-python workaround — return
Noneinstead of raising:Properties like
allocation_handleandipc_descriptorcould returnNonewhen the feature is not enabled. Callers already need to checkis_ipc_enabledfirst.cuda-python workaround — revert to methods:
Keep
get_allocation_handle()/get_ipc_descriptor()as methods. Methods are never evaluated bygetattr()during tab completion.cuda-python workaround — catch NVML errors in
system.Device:Wrap NVML-backed properties in
try/exceptand return a sentinel (e.g.,Noneor a "not supported" marker) instead of lettingNotSupportedErrorpropagate.-- Leo's bot
mdboom commentedon May 8, 2026
Confirming that tab completion is /not/ broken in IPython:
It is also /not/ broken in Jupyter:
EDIT: And everything is available in this list if you scroll down, just not visible in the screenshot.
So it seems confined to vanilla Python REPL tab completion specifically (which one could argue is the least important).
mdboom commentedon May 8, 2026
Confirmed this affects Python 3.10 -> 3.14, so it's not just the "new" REPL introduced in 3.13.
mdboom commentedon May 8, 2026
My assessment of the agent's suggestions:
This is a non-starter. Even if we got the bugfix in, it would be ~5 years until we could rely on it.
This would change the semantics of the property, and the "Did you mean" would be incredibly misleading to users. They didn't misspell -- they used a feature that semantically should raise some sort of runtime error. It should be fine for us to design that way.
This places the burden of error checking on our users. It's deeply un-Pythonic to require error code checks. We are even trying to move away from that in
cuda_bindings.This is probably the most reasonable thing to do on this list. If we went this way, we should add some sort of a test harness that makes sure we stick to the convention that "any property that can raise an exception must be a getter instead", because we will forget. It seems frustrating to design an API around the limitations of tab completion, though, so I'm still not a huge fan.
This is basically the same as #3 above.