warnings.h 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. /*
  2. pybind11/warnings.h: Python warnings wrappers.
  3. Copyright (c) 2024 Jan Iwaszkiewicz <jiwaszkiewicz6@gmail.com>
  4. All rights reserved. Use of this source code is governed by a
  5. BSD-style license that can be found in the LICENSE file.
  6. */
  7. #pragma once
  8. #include "pybind11.h"
  9. #include "detail/common.h"
  10. PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
  11. PYBIND11_NAMESPACE_BEGIN(detail)
  12. inline bool PyWarning_Check(PyObject *obj) {
  13. int result = PyObject_IsSubclass(obj, PyExc_Warning);
  14. if (result == 1) {
  15. return true;
  16. }
  17. if (result == -1) {
  18. raise_from(PyExc_SystemError,
  19. "pybind11::detail::PyWarning_Check(): PyObject_IsSubclass() call failed.");
  20. throw error_already_set();
  21. }
  22. return false;
  23. }
  24. PYBIND11_NAMESPACE_END(detail)
  25. PYBIND11_NAMESPACE_BEGIN(warnings)
  26. inline object
  27. new_warning_type(handle scope, const char *name, handle base = PyExc_RuntimeWarning) {
  28. if (!detail::PyWarning_Check(base.ptr())) {
  29. pybind11_fail("pybind11::warnings::new_warning_type(): cannot create custom warning, base "
  30. "must be a subclass of "
  31. "PyExc_Warning!");
  32. }
  33. if (hasattr(scope, name)) {
  34. pybind11_fail("pybind11::warnings::new_warning_type(): an attribute with name \""
  35. + std::string(name) + "\" exists already.");
  36. }
  37. std::string full_name = scope.attr("__name__").cast<std::string>() + std::string(".") + name;
  38. handle h(PyErr_NewException(full_name.c_str(), base.ptr(), nullptr));
  39. if (!h) {
  40. raise_from(PyExc_SystemError,
  41. "pybind11::warnings::new_warning_type(): PyErr_NewException() call failed.");
  42. throw error_already_set();
  43. }
  44. auto obj = reinterpret_steal<object>(h);
  45. scope.attr(name) = obj;
  46. return obj;
  47. }
  48. // Similar to Python `warnings.warn()`
  49. inline void
  50. warn(const char *message, handle category = PyExc_RuntimeWarning, int stack_level = 2) {
  51. if (!detail::PyWarning_Check(category.ptr())) {
  52. pybind11_fail(
  53. "pybind11::warnings::warn(): cannot raise warning, category must be a subclass of "
  54. "PyExc_Warning!");
  55. }
  56. if (PyErr_WarnEx(category.ptr(), message, stack_level) == -1) {
  57. throw error_already_set();
  58. }
  59. }
  60. PYBIND11_NAMESPACE_END(warnings)
  61. PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)