| 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 | S: "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 | S: "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 | S: "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 | |