1 | //===-- PythonDataObjects.h--------------------------------------*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | // |
10 | // !! FIXME FIXME FIXME !! |
11 | // |
12 | // Python APIs nearly all can return an exception. They do this |
13 | // by returning NULL, or -1, or some such value and setting |
14 | // the exception state with PyErr_Set*(). Exceptions must be |
15 | // handled before further python API functions are called. Failure |
16 | // to do so will result in asserts on debug builds of python. |
17 | // It will also sometimes, but not usually result in crashes of |
18 | // release builds. |
19 | // |
20 | // Nearly all the code in this header does not handle python exceptions |
21 | // correctly. It should all be converted to return Expected<> or |
22 | // Error types to capture the exception. |
23 | // |
24 | // Everything in this file except functions that return Error or |
25 | // Expected<> is considered deprecated and should not be |
26 | // used in new code. If you need to use it, fix it first. |
27 | // |
28 | // |
29 | // TODOs for this file |
30 | // |
31 | // * Make all methods safe for exceptions. |
32 | // |
33 | // * Eliminate method signatures that must translate exceptions into |
34 | // empty objects or NULLs. Almost everything here should return |
35 | // Expected<>. It should be acceptable for certain operations that |
36 | // can never fail to assert instead, such as the creation of |
37 | // PythonString from a string literal. |
38 | // |
39 | // * Eliminate Reset(), and make all non-default constructors private. |
40 | // Python objects should be created with Retain<> or Take<>, and they |
41 | // should be assigned with operator= |
42 | // |
43 | // * Eliminate default constructors, make python objects always |
44 | // nonnull, and use optionals where necessary. |
45 | // |
46 | |
47 | |
48 | #ifndef LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_PYTHONDATAOBJECTS_H |
49 | #define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_PYTHONDATAOBJECTS_H |
50 | |
51 | #include "lldb/Host/Config.h" |
52 | |
53 | #if LLDB_ENABLE_PYTHON |
54 | |
55 | // LLDB Python header must be included first |
56 | #include "lldb-python.h" |
57 | |
58 | #include "lldb/Host/File.h" |
59 | #include "lldb/Utility/StructuredData.h" |
60 | |
61 | #include "llvm/ADT/ArrayRef.h" |
62 | |
63 | namespace lldb_private { |
64 | namespace python { |
65 | |
66 | class PythonObject; |
67 | class PythonBytes; |
68 | class PythonString; |
69 | class PythonList; |
70 | class PythonDictionary; |
71 | class PythonInteger; |
72 | class PythonException; |
73 | |
74 | class GIL { |
75 | public: |
76 | GIL() { |
77 | m_state = PyGILState_Ensure(); |
78 | assert(!PyErr_Occurred()); |
79 | } |
80 | ~GIL() { PyGILState_Release(m_state); } |
81 | |
82 | protected: |
83 | PyGILState_STATE m_state; |
84 | }; |
85 | |
86 | enum class PyObjectType { |
87 | Unknown, |
88 | None, |
89 | Boolean, |
90 | Integer, |
91 | Dictionary, |
92 | List, |
93 | String, |
94 | Bytes, |
95 | ByteArray, |
96 | Module, |
97 | Callable, |
98 | Tuple, |
99 | File |
100 | }; |
101 | |
102 | enum class PyRefType { |
103 | Borrowed, // We are not given ownership of the incoming PyObject. |
104 | // We cannot safely hold it without calling Py_INCREF. |
105 | Owned // We have ownership of the incoming PyObject. We should |
106 | // not call Py_INCREF. |
107 | }; |
108 | |
109 | |
110 | // Take a reference that you already own, and turn it into |
111 | // a PythonObject. |
112 | // |
113 | // Most python API methods will return a +1 reference |
114 | // if they succeed or NULL if and only if |
115 | // they set an exception. Use this to collect such return |
116 | // values, after checking for NULL. |
117 | // |
118 | // If T is not just PythonObject, then obj must be already be |
119 | // checked to be of the correct type. |
120 | template <typename T> T Take(PyObject *obj) { |
121 | assert(obj); |
122 | assert(!PyErr_Occurred()); |
123 | T thing(PyRefType::Owned, obj); |
124 | assert(thing.IsValid()); |
125 | return thing; |
126 | } |
127 | |
128 | // Retain a reference you have borrowed, and turn it into |
129 | // a PythonObject. |
130 | // |
131 | // A minority of python APIs return a borrowed reference |
132 | // instead of a +1. They will also return NULL if and only |
133 | // if they set an exception. Use this to collect such return |
134 | // values, after checking for NULL. |
135 | // |
136 | // If T is not just PythonObject, then obj must be already be |
137 | // checked to be of the correct type. |
138 | template <typename T> T Retain(PyObject *obj) { |
139 | assert(obj); |
140 | assert(!PyErr_Occurred()); |
141 | T thing(PyRefType::Borrowed, obj); |
142 | assert(thing.IsValid()); |
143 | return thing; |
144 | } |
145 | |
146 | // This class can be used like a utility function to convert from |
147 | // a llvm-friendly Twine into a null-terminated const char *, |
148 | // which is the form python C APIs want their strings in. |
149 | // |
150 | // Example: |
151 | // const llvm::Twine &some_twine; |
152 | // PyFoo_Bar(x, y, z, NullTerminated(some_twine)); |
153 | // |
154 | // Why a class instead of a function? If the twine isn't already null |
155 | // terminated, it will need a temporary buffer to copy the string |
156 | // into. We need that buffer to stick around for the lifetime of the |
157 | // statement. |
158 | class NullTerminated { |
159 | const char *str; |
160 | llvm::SmallString<32> storage; |
161 | |
162 | public: |
163 | NullTerminated(const llvm::Twine &twine) { |
164 | llvm::StringRef ref = twine.toNullTerminatedStringRef(Out&: storage); |
165 | str = ref.begin(); |
166 | } |
167 | operator const char *() { return str; } |
168 | }; |
169 | |
170 | inline llvm::Error nullDeref() { |
171 | return llvm::createStringError(EC: llvm::inconvertibleErrorCode(), |
172 | Msg: "A NULL PyObject* was dereferenced" ); |
173 | } |
174 | |
175 | inline llvm::Error exception(const char *s = nullptr) { |
176 | return llvm::make_error<PythonException>(Args&: s); |
177 | } |
178 | |
179 | inline llvm::Error keyError() { |
180 | return llvm::createStringError(EC: llvm::inconvertibleErrorCode(), |
181 | Msg: "key not in dict" ); |
182 | } |
183 | |
184 | inline const char *py2_const_cast(const char *s) { return s; } |
185 | |
186 | enum class PyInitialValue { Invalid, Empty }; |
187 | |
188 | // DOC: https://docs.python.org/3/c-api/arg.html#building-values |
189 | template <typename T, typename Enable = void> struct PythonFormat; |
190 | |
191 | template <typename T, char F> struct PassthroughFormat { |
192 | static constexpr char format = F; |
193 | static constexpr T get(T t) { return t; } |
194 | }; |
195 | |
196 | template <> struct PythonFormat<char *> : PassthroughFormat<char *, 's'> {}; |
197 | template <> struct PythonFormat<const char *> : |
198 | PassthroughFormat<const char *, 's'> {}; |
199 | template <> struct PythonFormat<char> : PassthroughFormat<char, 'b'> {}; |
200 | template <> |
201 | struct PythonFormat<unsigned char> : PassthroughFormat<unsigned char, 'B'> {}; |
202 | template <> struct PythonFormat<short> : PassthroughFormat<short, 'h'> {}; |
203 | template <> |
204 | struct PythonFormat<unsigned short> : PassthroughFormat<unsigned short, 'H'> {}; |
205 | template <> struct PythonFormat<int> : PassthroughFormat<int, 'i'> {}; |
206 | template <> struct PythonFormat<bool> : PassthroughFormat<bool, 'p'> {}; |
207 | template <> |
208 | struct PythonFormat<unsigned int> : PassthroughFormat<unsigned int, 'I'> {}; |
209 | template <> struct PythonFormat<long> : PassthroughFormat<long, 'l'> {}; |
210 | template <> |
211 | struct PythonFormat<unsigned long> : PassthroughFormat<unsigned long, 'k'> {}; |
212 | template <> |
213 | struct PythonFormat<long long> : PassthroughFormat<long long, 'L'> {}; |
214 | template <> |
215 | struct PythonFormat<unsigned long long> |
216 | : PassthroughFormat<unsigned long long, 'K'> {}; |
217 | template <> |
218 | struct PythonFormat<PyObject *> : PassthroughFormat<PyObject *, 'O'> {}; |
219 | |
220 | template <typename T> |
221 | struct PythonFormat< |
222 | T, typename std::enable_if<std::is_base_of<PythonObject, T>::value>::type> { |
223 | static constexpr char format = 'O'; |
224 | static auto get(const T &value) { return value.get(); } |
225 | }; |
226 | |
227 | class PythonObject { |
228 | public: |
229 | PythonObject() = default; |
230 | |
231 | PythonObject(PyRefType type, PyObject *py_obj) { |
232 | m_py_obj = py_obj; |
233 | // If this is a borrowed reference, we need to convert it to |
234 | // an owned reference by incrementing it. If it is an owned |
235 | // reference (for example the caller allocated it with PyDict_New() |
236 | // then we must *not* increment it. |
237 | if (m_py_obj && Py_IsInitialized() && type == PyRefType::Borrowed) |
238 | Py_XINCREF(m_py_obj); |
239 | } |
240 | |
241 | PythonObject(const PythonObject &rhs) |
242 | : PythonObject(PyRefType::Borrowed, rhs.m_py_obj) {} |
243 | |
244 | PythonObject(PythonObject &&rhs) { |
245 | m_py_obj = rhs.m_py_obj; |
246 | rhs.m_py_obj = nullptr; |
247 | } |
248 | |
249 | ~PythonObject() { Reset(); } |
250 | |
251 | void Reset(); |
252 | |
253 | void Dump() const { |
254 | if (m_py_obj) |
255 | _PyObject_Dump(m_py_obj); |
256 | else |
257 | puts(s: "NULL" ); |
258 | } |
259 | |
260 | void Dump(Stream &strm) const; |
261 | |
262 | PyObject *get() const { return m_py_obj; } |
263 | |
264 | PyObject *release() { |
265 | PyObject *result = m_py_obj; |
266 | m_py_obj = nullptr; |
267 | return result; |
268 | } |
269 | |
270 | PythonObject &operator=(PythonObject other) { |
271 | Reset(); |
272 | m_py_obj = std::exchange(obj&: other.m_py_obj, new_val: nullptr); |
273 | return *this; |
274 | } |
275 | |
276 | PyObjectType GetObjectType() const; |
277 | |
278 | PythonString Repr() const; |
279 | |
280 | PythonString Str() const; |
281 | |
282 | static PythonObject ResolveNameWithDictionary(llvm::StringRef name, |
283 | const PythonDictionary &dict); |
284 | |
285 | template <typename T> |
286 | static T ResolveNameWithDictionary(llvm::StringRef name, |
287 | const PythonDictionary &dict) { |
288 | return ResolveNameWithDictionary(name, dict).AsType<T>(); |
289 | } |
290 | |
291 | PythonObject ResolveName(llvm::StringRef name) const; |
292 | |
293 | template <typename T> T ResolveName(llvm::StringRef name) const { |
294 | return ResolveName(name).AsType<T>(); |
295 | } |
296 | |
297 | bool HasAttribute(llvm::StringRef attribute) const; |
298 | |
299 | PythonObject GetAttributeValue(llvm::StringRef attribute) const; |
300 | |
301 | bool IsNone() const { return m_py_obj == Py_None; } |
302 | |
303 | bool IsValid() const { return m_py_obj != nullptr; } |
304 | |
305 | bool IsAllocated() const { return IsValid() && !IsNone(); } |
306 | |
307 | explicit operator bool() const { return IsValid() && !IsNone(); } |
308 | |
309 | template <typename T> T AsType() const { |
310 | if (!T::Check(m_py_obj)) |
311 | return T(); |
312 | return T(PyRefType::Borrowed, m_py_obj); |
313 | } |
314 | |
315 | StructuredData::ObjectSP CreateStructuredObject() const; |
316 | |
317 | template <typename... T> |
318 | llvm::Expected<PythonObject> CallMethod(const char *name, |
319 | const T &... t) const { |
320 | const char format[] = {'(', PythonFormat<T>::format..., ')', 0}; |
321 | PyObject *obj = |
322 | PyObject_CallMethod(m_py_obj, py2_const_cast(s: name), |
323 | py2_const_cast(format), PythonFormat<T>::get(t)...); |
324 | if (!obj) |
325 | return exception(); |
326 | return python::Take<PythonObject>(obj); |
327 | } |
328 | |
329 | template <typename... T> |
330 | llvm::Expected<PythonObject> Call(const T &... t) const { |
331 | const char format[] = {'(', PythonFormat<T>::format..., ')', 0}; |
332 | PyObject *obj = PyObject_CallFunction(m_py_obj, py2_const_cast(format), |
333 | PythonFormat<T>::get(t)...); |
334 | if (!obj) |
335 | return exception(); |
336 | return python::Take<PythonObject>(obj); |
337 | } |
338 | |
339 | llvm::Expected<PythonObject> GetAttribute(const llvm::Twine &name) const { |
340 | if (!m_py_obj) |
341 | return nullDeref(); |
342 | PyObject *obj = PyObject_GetAttrString(m_py_obj, NullTerminated(name)); |
343 | if (!obj) |
344 | return exception(); |
345 | return python::Take<PythonObject>(obj); |
346 | } |
347 | |
348 | llvm::Expected<PythonObject> GetType() const { |
349 | if (!m_py_obj) |
350 | return nullDeref(); |
351 | PyObject *obj = PyObject_Type(o: m_py_obj); |
352 | if (!obj) |
353 | return exception(); |
354 | return python::Take<PythonObject>(obj); |
355 | } |
356 | |
357 | llvm::Expected<bool> IsTrue() { |
358 | if (!m_py_obj) |
359 | return nullDeref(); |
360 | int r = PyObject_IsTrue(m_py_obj); |
361 | if (r < 0) |
362 | return exception(); |
363 | return !!r; |
364 | } |
365 | |
366 | llvm::Expected<long long> AsLongLong() const; |
367 | |
368 | llvm::Expected<unsigned long long> AsUnsignedLongLong() const; |
369 | |
370 | // wraps on overflow, instead of raising an error. |
371 | llvm::Expected<unsigned long long> AsModuloUnsignedLongLong() const; |
372 | |
373 | llvm::Expected<bool> IsInstance(const PythonObject &cls) { |
374 | if (!m_py_obj || !cls.IsValid()) |
375 | return nullDeref(); |
376 | int r = PyObject_IsInstance(object: m_py_obj, typeorclass: cls.get()); |
377 | if (r < 0) |
378 | return exception(); |
379 | return !!r; |
380 | } |
381 | |
382 | protected: |
383 | PyObject *m_py_obj = nullptr; |
384 | }; |
385 | |
386 | |
387 | // This is why C++ needs monads. |
388 | template <typename T> llvm::Expected<T> As(llvm::Expected<PythonObject> &&obj) { |
389 | if (!obj) |
390 | return obj.takeError(); |
391 | if (!T::Check(obj.get().get())) |
392 | return llvm::createStringError(EC: llvm::inconvertibleErrorCode(), |
393 | Msg: "type error" ); |
394 | return T(PyRefType::Borrowed, std::move(obj.get().get())); |
395 | } |
396 | |
397 | template <> llvm::Expected<bool> As<bool>(llvm::Expected<PythonObject> &&obj); |
398 | |
399 | template <> |
400 | llvm::Expected<long long> As<long long>(llvm::Expected<PythonObject> &&obj); |
401 | |
402 | template <> |
403 | llvm::Expected<unsigned long long> |
404 | As<unsigned long long>(llvm::Expected<PythonObject> &&obj); |
405 | |
406 | template <> |
407 | llvm::Expected<std::string> As<std::string>(llvm::Expected<PythonObject> &&obj); |
408 | |
409 | |
410 | template <class T> class TypedPythonObject : public PythonObject { |
411 | public: |
412 | TypedPythonObject(PyRefType type, PyObject *py_obj) { |
413 | if (!py_obj) |
414 | return; |
415 | if (T::Check(py_obj)) |
416 | PythonObject::operator=(other: PythonObject(type, py_obj)); |
417 | else if (type == PyRefType::Owned) |
418 | Py_DECREF(py_obj); |
419 | } |
420 | |
421 | TypedPythonObject() = default; |
422 | }; |
423 | |
424 | class PythonBytes : public TypedPythonObject<PythonBytes> { |
425 | public: |
426 | using TypedPythonObject::TypedPythonObject; |
427 | explicit PythonBytes(llvm::ArrayRef<uint8_t> bytes); |
428 | PythonBytes(const uint8_t *bytes, size_t length); |
429 | |
430 | static bool Check(PyObject *py_obj); |
431 | |
432 | llvm::ArrayRef<uint8_t> GetBytes() const; |
433 | |
434 | size_t GetSize() const; |
435 | |
436 | void SetBytes(llvm::ArrayRef<uint8_t> stringbytes); |
437 | |
438 | StructuredData::StringSP CreateStructuredString() const; |
439 | }; |
440 | |
441 | class PythonByteArray : public TypedPythonObject<PythonByteArray> { |
442 | public: |
443 | using TypedPythonObject::TypedPythonObject; |
444 | explicit PythonByteArray(llvm::ArrayRef<uint8_t> bytes); |
445 | PythonByteArray(const uint8_t *bytes, size_t length); |
446 | PythonByteArray(const PythonBytes &object); |
447 | |
448 | static bool Check(PyObject *py_obj); |
449 | |
450 | llvm::ArrayRef<uint8_t> GetBytes() const; |
451 | |
452 | size_t GetSize() const; |
453 | |
454 | void SetBytes(llvm::ArrayRef<uint8_t> stringbytes); |
455 | |
456 | StructuredData::StringSP CreateStructuredString() const; |
457 | }; |
458 | |
459 | class PythonString : public TypedPythonObject<PythonString> { |
460 | public: |
461 | using TypedPythonObject::TypedPythonObject; |
462 | static llvm::Expected<PythonString> FromUTF8(llvm::StringRef string); |
463 | |
464 | PythonString() : TypedPythonObject() {} // MSVC requires this for some reason |
465 | |
466 | explicit PythonString(llvm::StringRef string); // safe, null on error |
467 | |
468 | static bool Check(PyObject *py_obj); |
469 | |
470 | llvm::StringRef GetString() const; // safe, empty string on error |
471 | |
472 | llvm::Expected<llvm::StringRef> AsUTF8() const; |
473 | |
474 | size_t GetSize() const; |
475 | |
476 | void SetString(llvm::StringRef string); // safe, null on error |
477 | |
478 | StructuredData::StringSP CreateStructuredString() const; |
479 | }; |
480 | |
481 | class PythonInteger : public TypedPythonObject<PythonInteger> { |
482 | public: |
483 | using TypedPythonObject::TypedPythonObject; |
484 | |
485 | PythonInteger() : TypedPythonObject() {} // MSVC requires this for some reason |
486 | |
487 | explicit PythonInteger(int64_t value); |
488 | |
489 | static bool Check(PyObject *py_obj); |
490 | |
491 | void SetInteger(int64_t value); |
492 | |
493 | StructuredData::IntegerSP CreateStructuredInteger() const; |
494 | |
495 | StructuredData::UnsignedIntegerSP CreateStructuredUnsignedInteger() const; |
496 | |
497 | StructuredData::SignedIntegerSP CreateStructuredSignedInteger() const; |
498 | }; |
499 | |
500 | class PythonBoolean : public TypedPythonObject<PythonBoolean> { |
501 | public: |
502 | using TypedPythonObject::TypedPythonObject; |
503 | |
504 | explicit PythonBoolean(bool value); |
505 | |
506 | static bool Check(PyObject *py_obj); |
507 | |
508 | bool GetValue() const; |
509 | |
510 | void SetValue(bool value); |
511 | |
512 | StructuredData::BooleanSP CreateStructuredBoolean() const; |
513 | }; |
514 | |
515 | class PythonList : public TypedPythonObject<PythonList> { |
516 | public: |
517 | using TypedPythonObject::TypedPythonObject; |
518 | |
519 | PythonList() : TypedPythonObject() {} // MSVC requires this for some reason |
520 | |
521 | explicit PythonList(PyInitialValue value); |
522 | explicit PythonList(int list_size); |
523 | |
524 | static bool Check(PyObject *py_obj); |
525 | |
526 | uint32_t GetSize() const; |
527 | |
528 | PythonObject GetItemAtIndex(uint32_t index) const; |
529 | |
530 | void SetItemAtIndex(uint32_t index, const PythonObject &object); |
531 | |
532 | void AppendItem(const PythonObject &object); |
533 | |
534 | StructuredData::ArraySP CreateStructuredArray() const; |
535 | }; |
536 | |
537 | class PythonTuple : public TypedPythonObject<PythonTuple> { |
538 | public: |
539 | using TypedPythonObject::TypedPythonObject; |
540 | |
541 | explicit PythonTuple(PyInitialValue value); |
542 | explicit PythonTuple(int tuple_size); |
543 | PythonTuple(std::initializer_list<PythonObject> objects); |
544 | PythonTuple(std::initializer_list<PyObject *> objects); |
545 | |
546 | static bool Check(PyObject *py_obj); |
547 | |
548 | uint32_t GetSize() const; |
549 | |
550 | PythonObject GetItemAtIndex(uint32_t index) const; |
551 | |
552 | void SetItemAtIndex(uint32_t index, const PythonObject &object); |
553 | |
554 | StructuredData::ArraySP CreateStructuredArray() const; |
555 | }; |
556 | |
557 | class PythonDictionary : public TypedPythonObject<PythonDictionary> { |
558 | public: |
559 | using TypedPythonObject::TypedPythonObject; |
560 | |
561 | PythonDictionary() : TypedPythonObject() {} // MSVC requires this for some reason |
562 | |
563 | explicit PythonDictionary(PyInitialValue value); |
564 | |
565 | static bool Check(PyObject *py_obj); |
566 | |
567 | bool HasKey(const llvm::Twine &key) const; |
568 | |
569 | uint32_t GetSize() const; |
570 | |
571 | PythonList GetKeys() const; |
572 | |
573 | PythonObject GetItemForKey(const PythonObject &key) const; // DEPRECATED |
574 | void SetItemForKey(const PythonObject &key, |
575 | const PythonObject &value); // DEPRECATED |
576 | |
577 | llvm::Expected<PythonObject> GetItem(const PythonObject &key) const; |
578 | llvm::Expected<PythonObject> GetItem(const llvm::Twine &key) const; |
579 | llvm::Error SetItem(const PythonObject &key, const PythonObject &value) const; |
580 | llvm::Error SetItem(const llvm::Twine &key, const PythonObject &value) const; |
581 | |
582 | StructuredData::DictionarySP CreateStructuredDictionary() const; |
583 | }; |
584 | |
585 | class PythonModule : public TypedPythonObject<PythonModule> { |
586 | public: |
587 | using TypedPythonObject::TypedPythonObject; |
588 | |
589 | static bool Check(PyObject *py_obj); |
590 | |
591 | static PythonModule BuiltinsModule(); |
592 | |
593 | static PythonModule MainModule(); |
594 | |
595 | static PythonModule AddModule(llvm::StringRef module); |
596 | |
597 | // safe, returns invalid on error; |
598 | static PythonModule ImportModule(llvm::StringRef name) { |
599 | std::string s = std::string(name); |
600 | auto mod = Import(name: s.c_str()); |
601 | if (!mod) { |
602 | llvm::consumeError(Err: mod.takeError()); |
603 | return PythonModule(); |
604 | } |
605 | return std::move(mod.get()); |
606 | } |
607 | |
608 | static llvm::Expected<PythonModule> Import(const llvm::Twine &name); |
609 | |
610 | llvm::Expected<PythonObject> Get(const llvm::Twine &name); |
611 | |
612 | PythonDictionary GetDictionary() const; |
613 | }; |
614 | |
615 | class PythonCallable : public TypedPythonObject<PythonCallable> { |
616 | public: |
617 | using TypedPythonObject::TypedPythonObject; |
618 | |
619 | struct ArgInfo { |
620 | /* the largest number of positional arguments this callable |
621 | * can accept, or UNBOUNDED, ie UINT_MAX if it's a varargs |
622 | * function and can accept an arbitrary number */ |
623 | unsigned max_positional_args; |
624 | static constexpr unsigned UNBOUNDED = UINT_MAX; // FIXME c++17 inline |
625 | }; |
626 | |
627 | static bool Check(PyObject *py_obj); |
628 | |
629 | llvm::Expected<ArgInfo> GetArgInfo() const; |
630 | |
631 | PythonObject operator()(); |
632 | |
633 | PythonObject operator()(std::initializer_list<PyObject *> args); |
634 | |
635 | PythonObject operator()(std::initializer_list<PythonObject> args); |
636 | |
637 | template <typename Arg, typename... Args> |
638 | PythonObject operator()(const Arg &arg, Args... args) { |
639 | return operator()({arg, args...}); |
640 | } |
641 | }; |
642 | |
643 | class PythonFile : public TypedPythonObject<PythonFile> { |
644 | public: |
645 | using TypedPythonObject::TypedPythonObject; |
646 | |
647 | PythonFile() : TypedPythonObject() {} // MSVC requires this for some reason |
648 | |
649 | static bool Check(PyObject *py_obj); |
650 | |
651 | static llvm::Expected<PythonFile> FromFile(File &file, |
652 | const char *mode = nullptr); |
653 | |
654 | llvm::Expected<lldb::FileSP> ConvertToFile(bool borrowed = false); |
655 | llvm::Expected<lldb::FileSP> |
656 | ConvertToFileForcingUseOfScriptingIOMethods(bool borrowed = false); |
657 | }; |
658 | |
659 | class PythonException : public llvm::ErrorInfo<PythonException> { |
660 | private: |
661 | PyObject *m_exception_type, *m_exception, *m_traceback; |
662 | PyObject *m_repr_bytes; |
663 | |
664 | public: |
665 | static char ID; |
666 | const char *toCString() const; |
667 | PythonException(const char *caller = nullptr); |
668 | void Restore(); |
669 | ~PythonException() override; |
670 | void log(llvm::raw_ostream &OS) const override; |
671 | std::error_code convertToErrorCode() const override; |
672 | bool Matches(PyObject *exc) const; |
673 | std::string ReadBacktrace() const; |
674 | }; |
675 | |
676 | // This extracts the underlying T out of an Expected<T> and returns it. |
677 | // If the Expected is an Error instead of a T, that error will be converted |
678 | // into a python exception, and this will return a default-constructed T. |
679 | // |
680 | // This is appropriate for use right at the boundary of python calling into |
681 | // C++, such as in a SWIG typemap. In such a context you should simply |
682 | // check if the returned T is valid, and if it is, return a NULL back |
683 | // to python. This will result in the Error being raised as an exception |
684 | // from python code's point of view. |
685 | // |
686 | // For example: |
687 | // ``` |
688 | // Expected<Foo *> efoop = some_cpp_function(); |
689 | // Foo *foop = unwrapOrSetPythonException(efoop); |
690 | // if (!foop) |
691 | // return NULL; |
692 | // do_something(*foop); |
693 | // |
694 | // If the Error returned was itself created because a python exception was |
695 | // raised when C++ code called into python, then the original exception |
696 | // will be restored. Otherwise a simple string exception will be raised. |
697 | template <typename T> T unwrapOrSetPythonException(llvm::Expected<T> expected) { |
698 | if (expected) |
699 | return expected.get(); |
700 | llvm::handleAllErrors( |
701 | expected.takeError(), [](PythonException &E) { E.Restore(); }, |
702 | [](const llvm::ErrorInfoBase &E) { |
703 | PyErr_SetString(exception: PyExc_Exception, string: E.message().c_str()); |
704 | }); |
705 | return T(); |
706 | } |
707 | |
708 | // This is only here to help incrementally migrate old, exception-unsafe |
709 | // code. |
710 | template <typename T> T unwrapIgnoringErrors(llvm::Expected<T> expected) { |
711 | if (expected) |
712 | return std::move(expected.get()); |
713 | llvm::consumeError(Err: expected.takeError()); |
714 | return T(); |
715 | } |
716 | |
717 | llvm::Expected<PythonObject> runStringOneLine(const llvm::Twine &string, |
718 | const PythonDictionary &globals, |
719 | const PythonDictionary &locals); |
720 | |
721 | llvm::Expected<PythonObject> runStringMultiLine(const llvm::Twine &string, |
722 | const PythonDictionary &globals, |
723 | const PythonDictionary &locals); |
724 | |
725 | // Sometimes the best way to interact with a python interpreter is |
726 | // to run some python code. You construct a PythonScript with |
727 | // script string. The script assigns some function to `_function_` |
728 | // and you get a C++ callable object that calls the python function. |
729 | // |
730 | // Example: |
731 | // |
732 | // const char script[] = R"( |
733 | // def main(x, y): |
734 | // .... |
735 | // )"; |
736 | // |
737 | // Expected<PythonObject> cpp_foo_wrapper(PythonObject x, PythonObject y) { |
738 | // // no need to synchronize access to this global, we already have the GIL |
739 | // static PythonScript foo(script) |
740 | // return foo(x, y); |
741 | // } |
742 | class PythonScript { |
743 | const char *script; |
744 | PythonCallable function; |
745 | |
746 | llvm::Error Init(); |
747 | |
748 | public: |
749 | PythonScript(const char *script) : script(script), function() {} |
750 | |
751 | template <typename... Args> |
752 | llvm::Expected<PythonObject> operator()(Args &&... args) { |
753 | if (llvm::Error error = Init()) |
754 | return std::move(error); |
755 | return function.Call(std::forward<Args>(args)...); |
756 | } |
757 | }; |
758 | |
759 | class StructuredPythonObject : public StructuredData::Generic { |
760 | public: |
761 | StructuredPythonObject() : StructuredData::Generic() {} |
762 | |
763 | // Take ownership of the object we received. |
764 | StructuredPythonObject(PythonObject obj) |
765 | : StructuredData::Generic(obj.release()) {} |
766 | |
767 | ~StructuredPythonObject() override { |
768 | // Hand ownership back to a (temporary) PythonObject instance and let it |
769 | // take care of releasing it. |
770 | PythonObject(PyRefType::Owned, static_cast<PyObject *>(GetValue())); |
771 | } |
772 | |
773 | bool IsValid() const override { return GetValue() && GetValue() != Py_None; } |
774 | |
775 | void Serialize(llvm::json::OStream &s) const override; |
776 | |
777 | private: |
778 | StructuredPythonObject(const StructuredPythonObject &) = delete; |
779 | const StructuredPythonObject & |
780 | operator=(const StructuredPythonObject &) = delete; |
781 | }; |
782 | |
783 | } // namespace python |
784 | } // namespace lldb_private |
785 | |
786 | #endif |
787 | |
788 | #endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_PYTHONDATAOBJECTS_H |
789 | |