using llvm::cantFail;
using llvm::Error;
using llvm::Expected;
+using llvm::Twine;
template <> Expected<bool> python::As<bool>(Expected<PythonObject> &&obj) {
if (!obj)
PythonByteArray::PythonByteArray(const uint8_t *bytes, size_t length) {
const char *str = reinterpret_cast<const char *>(bytes);
- Reset(PyRefType::Owned, PyByteArray_FromStringAndSize(str, length));
+ *this = Take<PythonByteArray>(PyByteArray_FromStringAndSize(str, length));
}
bool PythonByteArray::Check(PyObject *py_obj) {
PythonList::PythonList(PyInitialValue value) {
if (value == PyInitialValue::Empty)
- Reset(PyRefType::Owned, PyList_New(0));
+ *this = Take<PythonList>(PyList_New(0));
}
PythonList::PythonList(int list_size) {
- Reset(PyRefType::Owned, PyList_New(list_size));
+ *this = Take<PythonList>(PyList_New(list_size));
}
bool PythonList::Check(PyObject *py_obj) {
PythonTuple::PythonTuple(PyInitialValue value) {
if (value == PyInitialValue::Empty)
- Reset(PyRefType::Owned, PyTuple_New(0));
+ *this = Take<PythonTuple>(PyTuple_New(0));
}
PythonTuple::PythonTuple(int tuple_size) {
- Reset(PyRefType::Owned, PyTuple_New(tuple_size));
+ *this = Take<PythonTuple>(PyTuple_New(tuple_size));
}
PythonTuple::PythonTuple(std::initializer_list<PythonObject> objects) {
PythonDictionary::PythonDictionary(PyInitialValue value) {
if (value == PyInitialValue::Empty)
- Reset(PyRefType::Owned, PyDict_New());
+ *this = Take<PythonDictionary>(PyDict_New());
}
bool PythonDictionary::Check(PyObject *py_obj) {
return Retain<PythonObject>(o);
}
-Expected<PythonObject> PythonDictionary::GetItem(const char *key) const {
+Expected<PythonObject> PythonDictionary::GetItem(const Twine &key) const {
if (!IsValid())
return nullDeref();
- PyObject *o = PyDict_GetItemString(m_py_obj, key);
+ PyObject *o = PyDict_GetItemString(m_py_obj, NullTerminated(key));
if (PyErr_Occurred())
return exception();
if (!o)
return Error::success();
}
-Error PythonDictionary::SetItem(const char *key,
+Error PythonDictionary::SetItem(const Twine &key,
const PythonObject &value) const {
if (!IsValid() || !value.IsValid())
return nullDeref();
- int r = PyDict_SetItemString(m_py_obj, key, value.get());
+ int r = PyDict_SetItemString(m_py_obj, NullTerminated(key), value.get());
if (r < 0)
return exception();
return Error::success();
return PythonModule(PyRefType::Borrowed, PyImport_AddModule(str.c_str()));
}
-Expected<PythonModule> PythonModule::Import(const char *name) {
- PyObject *mod = PyImport_ImportModule(name);
+Expected<PythonModule> PythonModule::Import(const Twine &name) {
+ PyObject *mod = PyImport_ImportModule(NullTerminated(name));
if (!mod)
return exception();
return Take<PythonModule>(mod);
}
-Expected<PythonObject> PythonModule::Get(const char *name) {
+Expected<PythonObject> PythonModule::Get(const Twine &name) {
if (!IsValid())
return nullDeref();
PyObject *dict = PyModule_GetDict(m_py_obj);
if (!dict)
return exception();
- PyObject *item = PyDict_GetItemString(dict, name);
+ PyObject *item = PyDict_GetItemString(dict, NullTerminated(name));
if (!item)
return exception();
return Retain<PythonObject>(item);
}
PythonDictionary PythonModule::GetDictionary() const {
- return PythonDictionary(PyRefType::Borrowed, PyModule_GetDict(m_py_obj));
+ if (!IsValid())
+ return PythonDictionary();
+ return Retain<PythonDictionary>(PyModule_GetDict(m_py_obj));
}
bool PythonCallable::Check(PyObject *py_obj) {
assert(m_py_obj);
GIL takeGIL;
Close();
+ // we need to ensure the python object is released while we still
+ // hold the GIL
m_py_obj.Reset();
}
return std::move(thing);
}
+// This class can be used like a utility function to convert from
+// a llvm-friendly Twine into a null-terminated const char *,
+// which is the form python C APIs want their strings in.
+//
+// Example:
+// const llvm::Twine &some_twine;
+// PyFoo_Bar(x, y, z, NullTerminated(some_twine));
+//
+// Why a class instead of a function? If the twine isn't already null
+// terminated, it will need a temporary buffer to copy the string
+// into. We need that buffer to stick around for the lifetime of the
+// statement.
+class NullTerminated {
+ const char *str;
+ llvm::SmallString<32> storage;
+
+public:
+ NullTerminated(const llvm::Twine &twine) {
+ llvm::StringRef ref = twine.toNullTerminatedStringRef(storage);
+ str = ref.begin();
+ }
+ operator const char *() { return str; }
+};
+
} // namespace python
enum class PyInitialValue { Invalid, Empty };
return python::Take<PythonObject>(obj);
}
- llvm::Expected<PythonObject> GetAttribute(const char *name) const {
+ llvm::Expected<PythonObject> GetAttribute(const llvm::Twine &name) const {
+ using namespace python;
if (!m_py_obj)
return nullDeref();
- PyObject *obj = PyObject_GetAttrString(m_py_obj, name);
+ PyObject *obj = PyObject_GetAttrString(m_py_obj, NullTerminated(name));
if (!obj)
return exception();
return python::Take<PythonObject>(obj);
// This can be eliminated once we drop python 2 support.
static void Convert(PyRefType &type, PyObject *&py_obj) {}
- using PythonObject::Reset;
+ void Reset() { PythonObject::Reset(); }
- void Reset(PyRefType type, PyObject *py_obj) {
- Reset();
+ void Reset(PyRefType type, PyObject *py_obj) = delete;
+
+ TypedPythonObject(PyRefType type, PyObject *py_obj) {
if (!py_obj)
return;
T::Convert(type, py_obj);
Py_DECREF(py_obj);
}
- TypedPythonObject(PyRefType type, PyObject *py_obj) { Reset(type, py_obj); }
-
TypedPythonObject() {}
};
const PythonObject &value); // DEPRECATED
llvm::Expected<PythonObject> GetItem(const PythonObject &key) const;
- llvm::Expected<PythonObject> GetItem(const char *key) const;
+ llvm::Expected<PythonObject> GetItem(const llvm::Twine &key) const;
llvm::Error SetItem(const PythonObject &key, const PythonObject &value) const;
- llvm::Error SetItem(const char *key, const PythonObject &value) const;
+ llvm::Error SetItem(const llvm::Twine &key, const PythonObject &value) const;
StructuredData::DictionarySP CreateStructuredDictionary() const;
};
return std::move(mod.get());
}
- static llvm::Expected<PythonModule> Import(const char *name);
+ static llvm::Expected<PythonModule> Import(const llvm::Twine &name);
- llvm::Expected<PythonObject> Get(const char *name);
+ llvm::Expected<PythonObject> Get(const llvm::Twine &name);
PythonDictionary GetDictionary() const;
};
return T();
}
+namespace python {
+// This is only here to help incrementally migrate old, exception-unsafe
+// code.
+template <typename T> T unwrapIgnoringErrors(llvm::Expected<T> expected) {
+ if (expected)
+ return std::move(expected.get());
+ llvm::consumeError(expected.takeError());
+ return T();
+}
+} // namespace python
+
} // namespace lldb_private
#endif
using namespace lldb;
using namespace lldb_private;
+using namespace lldb_private::python;
// Defined in the SWIG source file
#if PY_MAJOR_VERSION >= 3
if (!main_dict.IsValid())
return m_session_dict;
- PythonObject item = main_dict.GetItemForKey(PythonString(m_dictionary_name));
- m_session_dict.Reset(PyRefType::Borrowed, item.get());
+ m_session_dict = unwrapIgnoringErrors(
+ As<PythonDictionary>(main_dict.GetItem(m_dictionary_name)));
return m_session_dict;
}
PythonDictionary &ScriptInterpreterPythonImpl::GetSysModuleDictionary() {
if (m_sys_module_dict.IsValid())
return m_sys_module_dict;
-
- PythonObject sys_module(PyRefType::Borrowed, PyImport_AddModule("sys"));
- if (sys_module.IsValid())
- m_sys_module_dict.Reset(PyRefType::Borrowed,
- PyModule_GetDict(sys_module.get()));
+ PythonModule sys_module = unwrapIgnoringErrors(PythonModule::Import("sys"));
+ m_sys_module_dict = sys_module.GetDictionary();
return m_sys_module_dict;
}
PythonDictionary locals = GetSessionDictionary();
if (!locals.IsValid()) {
- locals.Reset(
- PyRefType::Owned,
- PyObject_GetAttrString(globals.get(), m_dictionary_name.c_str()));
+ locals = unwrapIgnoringErrors(
+ As<PythonDictionary>(globals.GetAttribute(m_dictionary_name)));
}
if (!locals.IsValid())
PythonDictionary locals = GetSessionDictionary();
if (!locals.IsValid())
- locals.Reset(
- PyRefType::Owned,
- PyObject_GetAttrString(globals.get(), m_dictionary_name.c_str()));
+ locals = unwrapIgnoringErrors(
+ As<PythonDictionary>(globals.GetAttribute(m_dictionary_name)));
if (!locals.IsValid())
locals = globals;
void SetUp() override {
PythonTestSuite::SetUp();
- PythonString sys_module("sys");
- m_sys_module.Reset(PyRefType::Owned, PyImport_Import(sys_module.get()));
+ m_sys_module = unwrapIgnoringErrors(PythonModule::Import("sys"));
m_main_module = PythonModule::MainModule();
m_builtins_module = PythonModule::BuiltinsModule();
}
PythonDictionary dict(PyInitialValue::Empty);
PyObject *new_dict = PyDict_New();
- dict.Reset(PyRefType::Owned, new_dict);
+ dict = Take<PythonDictionary>(new_dict);
EXPECT_EQ(new_dict, dict.get());
- dict.Reset(PyRefType::Owned, nullptr);
- EXPECT_EQ(nullptr, dict.get());
-
- dict.Reset(PyRefType::Owned, PyDict_New());
+ dict = Take<PythonDictionary>(PyDict_New());
EXPECT_NE(nullptr, dict.get());
dict.Reset();
EXPECT_EQ(nullptr, dict.get());