Skip to content

Commit

Permalink
internal format-style API to raise type errors easily
Browse files Browse the repository at this point in the history
  • Loading branch information
wjakob committed Jul 3, 2023
1 parent 8c75c97 commit 1d2aa6d
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 15 deletions.
5 changes: 2 additions & 3 deletions include/nanobind/nb_error.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,8 @@ class NB_EXPORT python_error : public std::exception {
using cast_error = std::bad_cast;

enum class exception_type {
stop_iteration, index_error, key_error, value_error,
type_error, buffer_error, import_error, attribute_error,
next_overload
runtime_error, stop_iteration, index_error, key_error, value_error,
type_error, buffer_error, import_error, attribute_error, next_overload
};

// Base interface used to expose common Python exceptions in C++
Expand Down
10 changes: 9 additions & 1 deletion include/nanobind/nb_lib.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,22 @@ struct NB_CORE cleanup_list {

// ========================================================================

/// Raise a std::runtime_error with the given message
/// Raise a runtime error with the given message
#if defined(__GNUC__)
__attribute__((noreturn, __format__ (__printf__, 1, 2)))
#else
[[noreturn]]
#endif
NB_CORE void raise(const char *fmt, ...);

/// Raise a type error with the given message
#if defined(__GNUC__)
__attribute__((noreturn, __format__ (__printf__, 1, 2)))
#else
[[noreturn]]
#endif
NB_CORE void raise_type_error(const char *fmt, ...);

/// Abort the process with a fatal error
#if defined(__GNUC__)
__attribute__((noreturn, __format__ (__printf__, 1, 2)))
Expand Down
46 changes: 35 additions & 11 deletions src/common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,30 +13,54 @@
NAMESPACE_BEGIN(NB_NAMESPACE)
NAMESPACE_BEGIN(detail)

NB_NOINLINE static builtin_exception
create_exception(exception_type type, const char *fmt, va_list args_) {
char buf[512];
va_list args;

va_copy(args, args_);
int size = vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);

if (size < (int) sizeof(buf)) {
return builtin_exception(type, buf);
} else {
scoped_pymalloc<char> temp(size + 1);

va_copy(args, args_);
vsnprintf(temp.get(), size + 1, fmt, args);
va_end(args);

return builtin_exception(type, temp.get());
}
}

#if defined(__GNUC__)
__attribute__((noreturn, __format__ (__printf__, 1, 2)))
#else
[[noreturn]]
#endif
void raise(const char *fmt, ...) {
char buf[512];
va_list args;

va_start(args, fmt);
int size = vsnprintf(buf, sizeof(buf), fmt, args);
builtin_exception err =
create_exception(exception_type::runtime_error, fmt, args);
va_end(args);
throw err;
}

if (size < (int) sizeof(buf))
throw std::runtime_error(buf);

scoped_pymalloc<char> temp(size + 1);

#if defined(__GNUC__)
__attribute__((noreturn, __format__ (__printf__, 1, 2)))
#else
[[noreturn]]
#endif
void raise_type_error(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
vsnprintf(temp.get(), size + 1, fmt, args);
builtin_exception err =
create_exception(exception_type::type_error, fmt, args);
va_end(args);

throw std::runtime_error(temp.get());
throw err;
}

/// Abort the process with a fatal error
Expand Down
1 change: 1 addition & 0 deletions src/nb_func.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ static bool set_builtin_exception_status(builtin_exception &e) {
PyObject *o;

switch (e.type()) {
case exception_type::runtime_error: o = PyExc_RuntimeError; break;
case exception_type::stop_iteration: o = PyExc_StopIteration; break;
case exception_type::index_error: o = PyExc_IndexError; break;
case exception_type::key_error: o = PyExc_KeyError; break;
Expand Down

0 comments on commit 1d2aa6d

Please sign in to comment.