diff --git a/cuda_core/cuda/core/_module.pyx b/cuda_core/cuda/core/_module.pyx index 95e149065bf..60e4af3db52 100644 --- a/cuda_core/cuda/core/_module.pyx +++ b/cuda_core/cuda/core/_module.pyx @@ -802,8 +802,16 @@ cdef class ObjectCode: try: name = self._sym_map[name] except KeyError: - if isinstance(name, str): - name = name.encode() + pass + # Encode after the lookup, not only on the miss path. symbol_mapping is + # annotated and documented `dict[str, str]`, but a str mapped value used + # to reach `` unencoded and raise + # "TypeError: expected bytes, str found". Program.compile stores the + # lowered names as bytes (nvrtcGetLoweredName), so only the documented + # hand-built form was affected -- i.e. the mapping worked only when it + # did nothing. + if isinstance(name, str): + name = name.encode() cdef KernelHandle h_kernel = create_kernel_handle(self._h_library, name) if not h_kernel: diff --git a/cuda_core/docs/source/release/1.2.0-notes.rst b/cuda_core/docs/source/release/1.2.0-notes.rst index 120d2c2a253..fc028da9334 100644 --- a/cuda_core/docs/source/release/1.2.0-notes.rst +++ b/cuda_core/docs/source/release/1.2.0-notes.rst @@ -73,6 +73,13 @@ Fixes and enhancements Windows, both ``ctypes.CFUNCTYPE`` and ``ctypes.WINFUNCTYPE`` are accepted. (`#2439 `__) +- :meth:`ObjectCode.get_kernel` now accepts a ``symbol_mapping`` whose values + are ``str``, as :meth:`ObjectCode.from_cubin` and its siblings document + (``dict[str, str]``). The mapped name was only encoded on the *miss* path, so + a hand-built mapping raised ``TypeError: expected bytes, str found`` for + exactly the names it was supposed to translate. Mappings produced by + :meth:`Program.compile` are unaffected -- their values are already ``bytes``. + Deprecation Notices ------------------- diff --git a/cuda_core/tests/test_module.py b/cuda_core/tests/test_module.py index 25cf0e24de4..cb30447823e 100644 --- a/cuda_core/tests/test_module.py +++ b/cuda_core/tests/test_module.py @@ -369,6 +369,27 @@ def test_object_code_load_cubin(get_saxpy_kernel_cubin): mod.get_kernel("saxpy") # force loading +@pytest.mark.agent_authored(model="claude-opus-5") +def test_object_code_symbol_mapping_accepts_str_values(get_saxpy_kernel_cubin): + """``symbol_mapping`` is annotated and documented ``dict[str, str]``. + + ``Program.compile`` stores the lowered names as ``bytes`` (they come from + ``nvrtcGetLoweredName``), so every existing test round-trips + ``mod.symbol_mapping`` unchanged and the documented ``str`` form is never + exercised. On a mapping *hit* the value went straight to ```` + without being encoded, so a hand-built ``dict[str, str]`` raised + ``TypeError: expected bytes, str found`` -- the mapping worked only for + names it did not map. + """ + _, mod = get_saxpy_kernel_cubin + cubin = mod.code + str_sym_map = {k: v.decode() if isinstance(v, bytes) else v for k, v in mod.symbol_mapping.items()} + assert all(isinstance(v, str) for v in str_sym_map.values()) + + obj = ObjectCode.from_cubin(cubin, symbol_mapping=str_sym_map) + obj.get_kernel("saxpy") # force loading through the mapped name + + def test_object_code_load_cubin_from_file(get_saxpy_kernel_cubin, tmp_path, convert_path): _, mod = get_saxpy_kernel_cubin cubin = mod.code