this repo has no description
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com)
2// _warnings.c implementation
3
4#include <cstdarg>
5
6#include "cpython-data.h"
7#include "cpython-types.h"
8
9#include "api-handle.h"
10#include "modules.h"
11#include "runtime.h"
12#include "utils.h"
13
14namespace py {
15
16static int callWarn(PyObject* category, PyObject* message,
17 Py_ssize_t stack_level, PyObject* source) {
18 if (category == nullptr) {
19 category = PyExc_RuntimeWarning;
20 }
21 if (source == nullptr) {
22 source = Py_None;
23 }
24 // Pop the extra frame pushed for calling managed code below. We need to do
25 // that since we're calling warnings.warn that pushes an extra frame whereas
26 // CPython performs the same task natively.
27 if (stack_level < 0) stack_level = 0;
28 stack_level++;
29 Thread* thread = Thread::current();
30 HandleScope scope(thread);
31 Object category_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(category)));
32 DCHECK(message != nullptr, "message cannot be null");
33 Object message_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(message)));
34 Runtime* runtime = thread->runtime();
35 Int stack_level_obj(&scope, runtime->newInt(stack_level));
36 Object source_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(source)));
37 // Like CPython, bail out if we are finalizing the runtime
38 if (runtime->isFinalizing()) {
39 return 0;
40 }
41 if (ensureBuiltinModuleById(thread, ID(warnings)).isErrorException()) {
42 return -1;
43 }
44 if (thread
45 ->invokeFunction4(ID(warnings), ID(warn), message_obj, category_obj,
46 stack_level_obj, source_obj)
47 .isErrorException()) {
48 return -1;
49 }
50 return 0;
51}
52
53PY_EXPORT int PyErr_WarnEx(PyObject* category, const char* text,
54 Py_ssize_t stack_level) {
55 PyObject* message = PyUnicode_FromString(text);
56 if (message == nullptr) {
57 return -1;
58 }
59 int res = callWarn(category, message, stack_level, nullptr);
60 Py_DECREF(message);
61 return res;
62}
63
64static int warnFormat(PyObject* source, PyObject* category,
65 Py_ssize_t stack_level, const char* format,
66 va_list vargs) {
67 PyObject* message = PyUnicode_FromFormatV(format, vargs);
68 if (message == nullptr) {
69 return -1;
70 }
71 int res = callWarn(category, message, stack_level, source);
72 Py_DECREF(message);
73 return res;
74}
75
76PY_EXPORT int PyErr_ResourceWarning(PyObject* source, Py_ssize_t stack_level,
77 const char* format, ...) {
78 va_list vargs;
79 va_start(vargs, format);
80 int res =
81 warnFormat(source, PyExc_ResourceWarning, stack_level, format, vargs);
82 va_end(vargs);
83 return res;
84}
85
86PY_EXPORT int PyErr_WarnExplicit(PyObject* /* y */, const char* /* t */,
87 const char* /* r */, int /* o */,
88 const char* /* r */, PyObject* /* y */) {
89 UNIMPLEMENTED("PyErr_WarnExplicit");
90}
91
92PY_EXPORT int PyErr_WarnExplicitObject(PyObject* category, PyObject* message,
93 PyObject* filename, int lineno,
94 PyObject* module, PyObject* registry) {
95 // module can be None if a warning is emitted late during Python shutdown.
96 // In this case, the Python warnings module was probably unloaded, so filters
97 // are no longer available to choose as actions. It is safer to ignore the
98 // warning and do nothing.
99 if (module == Py_None) {
100 return 0;
101 }
102 if (category == nullptr) {
103 category = PyExc_RuntimeWarning;
104 }
105 if (module == nullptr) {
106 // Signal to Python implementation that the module should be derived from
107 // the filename.
108 module = Py_None;
109 }
110 Thread* thread = Thread::current();
111 HandleScope scope(thread);
112 DCHECK(category != nullptr, "category cannot be null");
113 Object category_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(category)));
114 DCHECK(message != nullptr, "message cannot be null");
115 Object message_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(message)));
116 DCHECK(filename != nullptr, "filename cannot be null");
117 Object filename_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(filename)));
118 Runtime* runtime = thread->runtime();
119 Int lineno_obj(&scope, runtime->newInt(lineno));
120 DCHECK(module != nullptr, "module cannot be null");
121 Object module_obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(module)));
122 Object registry_obj(&scope,
123 registry == nullptr
124 ? NoneType::object()
125 : ApiHandle::asObject(ApiHandle::fromPyObject(registry)));
126 // Like CPython, bail out if we are finalizing the runtime
127 if (runtime->isFinalizing()) {
128 return 0;
129 }
130 if (ensureBuiltinModuleById(thread, ID(warnings)).isErrorException()) {
131 return -1;
132 }
133 if (thread
134 ->invokeFunction6(ID(warnings), ID(warn_explicit), message_obj,
135 category_obj, filename_obj, lineno_obj, module_obj,
136 registry_obj)
137 .isError()) {
138 return -1;
139 }
140 return 0;
141}
142
143PY_EXPORT int PyErr_WarnFormat(PyObject* category, Py_ssize_t stack_level,
144 const char* format, ...) {
145 va_list vargs;
146 va_start(vargs, format);
147 int res = warnFormat(nullptr, category, stack_level, format, vargs);
148 va_end(vargs);
149 return res;
150}
151
152} // namespace py