summaryrefslogtreecommitdiffstats
path: root/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h
diff options
context:
space:
mode:
authorLawrence D'Anna <lawrence_danna@apple.com>2019-10-22 02:32:37 +0000
committerLawrence D'Anna <lawrence_danna@apple.com>2019-10-22 02:32:37 +0000
commit04edd1893c2d0f35880fd5f81e78dc23979df0b9 (patch)
tree3cf81a16415feb717f0c566e804a8ddbdb87db06 /lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h
parentb94ac8a2632968d3961d528faa75d68a517b3bc4 (diff)
downloadbcm5719-llvm-04edd1893c2d0f35880fd5f81e78dc23979df0b9.tar.gz
bcm5719-llvm-04edd1893c2d0f35880fd5f81e78dc23979df0b9.zip
remove multi-argument form of PythonObject::Reset()
Summary: With this patch, only the no-argument form of `Reset()` remains in PythonDataObjects. It also deletes PythonExceptionState in favor of PythonException, because the only call-site of PythonExceptionState was also using Reset, so I cleaned up both while I was there. Reviewers: JDevlieghere, clayborg, labath, jingham Reviewed By: labath Subscribers: mgorny, lldb-commits Tags: #lldb Differential Revision: https://reviews.llvm.org/D69214 llvm-svn: 375475
Diffstat (limited to 'lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h')
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h115
1 files changed, 73 insertions, 42 deletions
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h
index 634d6e89601..373d3212697 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h
@@ -59,6 +59,7 @@
#include "llvm/ADT/ArrayRef.h"
namespace lldb_private {
+namespace python {
class PythonObject;
class PythonBytes;
@@ -113,7 +114,6 @@ enum class PyRefType {
// not call Py_INCREF.
};
-namespace python {
// Take a reference that you already own, and turn it into
// a PythonObject.
@@ -175,7 +175,19 @@ public:
operator const char *() { return str; }
};
-} // namespace python
+inline llvm::Error nullDeref() {
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "A NULL PyObject* was dereferenced");
+}
+
+inline llvm::Error exception(const char *s = nullptr) {
+ return llvm::make_error<PythonException>(s);
+}
+
+inline llvm::Error keyError() {
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "key not in dict");
+}
enum class PyInitialValue { Invalid, Empty };
@@ -191,6 +203,11 @@ template <> struct PythonFormat<long long> {
static auto get(long long value) { return value; }
};
+template <> struct PythonFormat<PyObject *> {
+ static constexpr char format = 'O';
+ static auto get(PyObject *value) { return value; }
+};
+
template <typename T>
struct PythonFormat<
T, typename std::enable_if<std::is_base_of<PythonObject, T>::value>::type> {
@@ -202,8 +219,14 @@ class PythonObject {
public:
PythonObject() : m_py_obj(nullptr) {}
- PythonObject(PyRefType type, PyObject *py_obj) : m_py_obj(nullptr) {
- Reset(type, py_obj);
+ PythonObject(PyRefType type, PyObject *py_obj) {
+ m_py_obj = py_obj;
+ // If this is a borrowed reference, we need to convert it to
+ // an owned reference by incrementing it. If it is an owned
+ // reference (for example the caller allocated it with PyDict_New()
+ // then we must *not* increment it.
+ if (m_py_obj && Py_IsInitialized() && type == PyRefType::Borrowed)
+ Py_XINCREF(m_py_obj);
}
PythonObject(const PythonObject &rhs)
@@ -222,23 +245,6 @@ public:
m_py_obj = nullptr;
}
- void Reset(PyRefType type, PyObject *py_obj) {
- if (py_obj == m_py_obj)
- return;
-
- if (Py_IsInitialized())
- Py_XDECREF(m_py_obj);
-
- m_py_obj = py_obj;
-
- // If this is a borrowed reference, we need to convert it to
- // an owned reference by incrementing it. If it is an owned
- // reference (for example the caller allocated it with PyDict_New()
- // then we must *not* increment it.
- if (m_py_obj && Py_IsInitialized() && type == PyRefType::Borrowed)
- Py_XINCREF(m_py_obj);
- }
-
void Dump() const {
if (m_py_obj)
_PyObject_Dump(m_py_obj);
@@ -304,17 +310,6 @@ public:
StructuredData::ObjectSP CreateStructuredObject() const;
protected:
- static llvm::Error nullDeref() {
- return llvm::createStringError(llvm::inconvertibleErrorCode(),
- "A NULL PyObject* was dereferenced");
- }
- static llvm::Error exception(const char *s = nullptr) {
- return llvm::make_error<PythonException>(s);
- }
- static llvm::Error keyError() {
- return llvm::createStringError(llvm::inconvertibleErrorCode(),
- "key not in dict");
- }
#if PY_MAJOR_VERSION < 3
// The python 2 API declares some arguments as char* that should
@@ -348,7 +343,6 @@ public:
}
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, NullTerminated(name));
@@ -389,7 +383,6 @@ protected:
PyObject *m_py_obj;
};
-namespace python {
// This is why C++ needs monads.
template <typename T> llvm::Expected<T> As(llvm::Expected<PythonObject> &&obj) {
@@ -409,7 +402,6 @@ llvm::Expected<long long> As<long long>(llvm::Expected<PythonObject> &&obj);
template <>
llvm::Expected<std::string> As<std::string>(llvm::Expected<PythonObject> &&obj);
-} // namespace python
template <class T> class TypedPythonObject : public PythonObject {
public:
@@ -417,16 +409,12 @@ public:
// This can be eliminated once we drop python 2 support.
static void Convert(PyRefType &type, PyObject *&py_obj) {}
- void Reset() { PythonObject::Reset(); }
-
- void Reset(PyRefType type, PyObject *py_obj) = delete;
-
TypedPythonObject(PyRefType type, PyObject *py_obj) {
if (!py_obj)
return;
T::Convert(type, py_obj);
if (T::Check(py_obj))
- PythonObject::Reset(type, py_obj);
+ PythonObject::operator=(PythonObject(type, py_obj));
else if (type == PyRefType::Owned)
Py_DECREF(py_obj);
}
@@ -698,6 +686,8 @@ public:
~PythonException();
void log(llvm::raw_ostream &OS) const override;
std::error_code convertToErrorCode() const override;
+ bool Matches(PyObject *exc) const;
+ std::string ReadBacktrace() const;
};
// This extracts the underlying T out of an Expected<T> and returns it.
@@ -732,7 +722,6 @@ template <typename T> T unwrapOrSetPythonException(llvm::Expected<T> expected) {
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) {
@@ -741,8 +730,50 @@ template <typename T> T unwrapIgnoringErrors(llvm::Expected<T> expected) {
llvm::consumeError(expected.takeError());
return T();
}
-} // namespace python
+llvm::Expected<PythonObject> runStringOneLine(const llvm::Twine &string,
+ const PythonDictionary &globals,
+ const PythonDictionary &locals);
+
+llvm::Expected<PythonObject> runStringMultiLine(const llvm::Twine &string,
+ const PythonDictionary &globals,
+ const PythonDictionary &locals);
+
+// Sometimes the best way to interact with a python interpreter is
+// to run some python code. You construct a PythonScript with
+// script string. The script assigns some function to `_function_`
+// and you get a C++ callable object that calls the python function.
+//
+// Example:
+//
+// const char script[] = R"(
+// def main(x, y):
+// ....
+// )";
+//
+// Expected<PythonObject> cpp_foo_wrapper(PythonObject x, PythonObject y) {
+// // no need to synchronize access to this global, we already have the GIL
+// static PythonScript foo(script)
+// return foo(x, y);
+// }
+class PythonScript {
+ const char *script;
+ PythonCallable function;
+
+ llvm::Error Init();
+
+public:
+ PythonScript(const char *script) : script(script), function() {}
+
+ template <typename... Args>
+ llvm::Expected<PythonObject> operator()(Args &&... args) {
+ if (llvm::Error error = Init())
+ return std::move(error);
+ return function.Call(std::forward<Args>(args)...);
+ }
+};
+
+} // namespace python
} // namespace lldb_private
#endif
OpenPOWER on IntegriCloud