* @brief Parse capabilities from a Python tuple of strings and intersect with hardware capabilities. * @param[in] caps_tuple Python tuple containing capability strings (e.g., ('serial', 'haswell')). * @param[out] result Output capability mask after intersection with hardware capabilities. * @return 0 on success, -1 on error (with Python exception set). */
| 276 | * @return 0 on success, -1 on error (with Python exception set). |
| 277 | */ |
| 278 | static int parse_and_intersect_capabilities(PyObject *caps_obj, sz_capability_t *result) { |
| 279 | // Handle `DeviceScope` objects |
| 280 | if (PyObject_IsInstance(caps_obj, (PyObject *)&DeviceScopeType)) { |
| 281 | DeviceScope *device_scope = (DeviceScope *)caps_obj; |
| 282 | |
| 283 | // Try to get GPU device |
| 284 | sz_size_t gpu_device; |
| 285 | char const *error_detail_gpu = NULL; |
| 286 | if (szs_device_scope_get_gpu_device(device_scope->handle, &gpu_device, &error_detail_gpu) == sz_success_k) { |
| 287 | if (default_hardware_capabilities & sz_caps_cuda_k) { |
| 288 | *result = sz_caps_cuda_k & default_hardware_capabilities; |
| 289 | return 0; |
| 290 | } |
| 291 | else { |
| 292 | PyErr_SetString(PyExc_RuntimeError, "GPU DeviceScope requested but CUDA not available"); |
| 293 | return -1; |
| 294 | } |
| 295 | } |
| 296 | |
| 297 | // Try to get CPU cores first |
| 298 | sz_size_t cpu_cores; |
| 299 | char const *error_detail_cpu = NULL; |
| 300 | if (szs_device_scope_get_cpu_cores(device_scope->handle, &cpu_cores, &error_detail_cpu) == sz_success_k) { |
| 301 | *result = sz_caps_cpus_k & default_hardware_capabilities; |
| 302 | return 0; |
| 303 | } |
| 304 | |
| 305 | // Default scope - use all available capabilities |
| 306 | *result = default_hardware_capabilities; |
| 307 | return 0; |
| 308 | } |
| 309 | |
| 310 | // Handle tuple of capability strings (original behavior) |
| 311 | if (!PyTuple_Check(caps_obj)) { |
| 312 | PyErr_SetString(PyExc_TypeError, "capabilities must be a tuple of strings or a DeviceScope object"); |
| 313 | return -1; |
| 314 | } |
| 315 | |
| 316 | sz_capability_t requested_caps = 0; |
| 317 | Py_ssize_t n = PyTuple_Size(caps_obj); |
| 318 | |
| 319 | for (Py_ssize_t i = 0; i < n; i++) { |
| 320 | PyObject *item = PyTuple_GET_ITEM(caps_obj, i); |
| 321 | if (!PyUnicode_Check(item)) { |
| 322 | PyErr_SetString(PyExc_TypeError, "capabilities must be a tuple of strings"); |
| 323 | return -1; |
| 324 | } |
| 325 | |
| 326 | char const *cap_str = PyUnicode_AsUTF8(item); |
| 327 | if (!cap_str) return -1; |
| 328 | |
| 329 | sz_capability_t flag = sz_capability_from_string_implementation_(cap_str); |
| 330 | if (flag == sz_caps_none_k) { |
| 331 | PyErr_Format(PyExc_ValueError, "Unknown capability: %s", cap_str); |
| 332 | return -1; |
| 333 | } |
| 334 | requested_caps |= flag; |
| 335 | } |
no outgoing calls
no test coverage detected
searching dependent graphs…