Skip to content

Commit

Permalink
Inline Cython exception handler (rapidsai#13411)
Browse files Browse the repository at this point in the history
I originally placed the exception handler into a separate C++ header file that could be included by the Cython header because I figured that reading C++ inlined in Cython would be more confusing to devs. Unfortunately, the current approach complicates the build system due to the need to ensure that the directory containing the C++ header is always in the include path, which becomes problematic depending on where the files including the exception handler are (anywhere outside of `_lib` becomes problematic). Inlining is the simplest solution to this problem.

Authors:
  - Vyas Ramasubramani (https://github.com/vyasr)

Approvers:
  - Ashwin Srinath (https://github.com/shwina)
  - Bradley Dice (https://github.com/bdice)

URL: rapidsai#13411
  • Loading branch information
vyasr authored May 24, 2023
1 parent 9a0f87c commit 063a924
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 90 deletions.
5 changes: 0 additions & 5 deletions python/cudf/cudf/_lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,6 @@ rapids_cython_create_modules(
LINKED_LIBRARIES "${linked_libraries}" ASSOCIATED_TARGETS cudf
)

# All modules need to include the header containing the exception handler.
foreach(target IN LISTS RAPIDS_CYTHON_CREATED_TARGETS)
target_include_directories(${target} PRIVATE ${CMAKE_CURRENT_LIST_DIR})
endforeach()

target_link_libraries(strings_udf cudf_strings_udf)

# TODO: Finding NumPy currently requires finding Development due to a bug in CMake. This bug was
Expand Down
80 changes: 0 additions & 80 deletions python/cudf/cudf/_lib/exception_handler.hpp

This file was deleted.

66 changes: 65 additions & 1 deletion python/cudf/cudf/_lib/exception_handler.pxd
Original file line number Diff line number Diff line change
@@ -1,5 +1,69 @@
# Copyright (c) 2023, NVIDIA CORPORATION.


cdef extern from "exception_handler.hpp" namespace "cudf_python::exceptions":
# See
# https://github.com/cython/cython/blob/master/Cython/Utility/CppSupport.cpp
# for the original Cython exception handler.
cdef extern from *:
"""
#include <Python.h>
#include <cudf/utilities/error.hpp>
#include <ios>
#include <stdexcept>
namespace {
/**
* @brief Exception handler to map C++ exceptions to Python ones in Cython
*
* This exception handler extends the base exception handler provided by
* Cython. In addition to the exceptions that Cython itself supports, this
* file adds support for additional exceptions thrown by libcudf that need
* to be mapped to specific Python exceptions.
*
* Since this function interoperates with Python's exception state, it
* does not throw any C++ exceptions.
*/
void cudf_exception_handler()
{
// Catch a handful of different errors here and turn them into the
// equivalent Python errors.
try {
if (PyErr_Occurred())
; // let latest Python exn pass through and ignore the current one
throw;
} catch (const std::bad_alloc& exn) {
PyErr_SetString(PyExc_MemoryError, exn.what());
} catch (const std::bad_cast& exn) {
PyErr_SetString(PyExc_TypeError, exn.what());
} catch (const std::domain_error& exn) {
PyErr_SetString(PyExc_ValueError, exn.what());
} catch (const cudf::data_type_error& exn) {
// Catch subclass (data_type_error) before parent (invalid_argument)
PyErr_SetString(PyExc_TypeError, exn.what());
} catch (const std::invalid_argument& exn) {
PyErr_SetString(PyExc_ValueError, exn.what());
} catch (const std::ios_base::failure& exn) {
// Unfortunately, in standard C++ we have no way of distinguishing EOF
// from other errors here; be careful with the exception mask
PyErr_SetString(PyExc_IOError, exn.what());
} catch (const std::out_of_range& exn) {
// Change out_of_range to IndexError
PyErr_SetString(PyExc_IndexError, exn.what());
} catch (const std::overflow_error& exn) {
PyErr_SetString(PyExc_OverflowError, exn.what());
} catch (const std::range_error& exn) {
PyErr_SetString(PyExc_ArithmeticError, exn.what());
} catch (const std::underflow_error& exn) {
PyErr_SetString(PyExc_ArithmeticError, exn.what());
// The below is the default catch-all case.
} catch (const std::exception& exn) {
PyErr_SetString(PyExc_RuntimeError, exn.what());
} catch (...) {
PyErr_SetString(PyExc_RuntimeError, "Unknown exception");
}
}
} // anonymous namespace
"""
cdef void cudf_exception_handler()
2 changes: 1 addition & 1 deletion python/cudf_kafka/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ authors = [
license = { text = "Apache 2.0" }
requires-python = ">=3.9"
dependencies = [
"cudf==23.6.*",
"cudf==23.8.*",
] # This list was generated by `rapids-dependency-file-generator`. To make changes, edit ../../dependencies.yaml and run `rapids-dependency-file-generator`.

[project.optional-dependencies]
Expand Down
4 changes: 2 additions & 2 deletions python/custreamz/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ license = { text = "Apache 2.0" }
requires-python = ">=3.9"
dependencies = [
"confluent-kafka>=1.9.0,<1.10.0a0",
"cudf==23.6.*",
"cudf_kafka==23.6.*",
"cudf==23.8.*",
"cudf_kafka==23.8.*",
"streamz",
] # This list was generated by `rapids-dependency-file-generator`. To make changes, edit ../../dependencies.yaml and run `rapids-dependency-file-generator`.
classifiers = [
Expand Down
2 changes: 1 addition & 1 deletion python/dask_cudf/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ dynamic = ["entry-points"]

[project.optional-dependencies]
test = [
"dask-cuda==23.6.*",
"dask-cuda==23.8.*",
"numba>=0.57",
"pytest",
"pytest-cov",
Expand Down

0 comments on commit 063a924

Please sign in to comment.