lawrence_danna created this revision. lawrence_danna added reviewers: JDevlieghere, jasonmolenda, labath. Herald added a project: LLDB.
This makes SBFile::GetFile public and adds a SWIG typemap to convert the result back into a python native file. If the underlying File itself came from a python file, it is returned identically. Otherwise a new python file object is created using the file descriptor. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D68737 Files: lldb/include/lldb/API/SBFile.h lldb/include/lldb/Host/File.h lldb/packages/Python/lldbsuite/test/python_api/file_handle/TestFileHandle.py lldb/scripts/Python/python-typemaps.swig lldb/scripts/interface/SBFile.i lldb/source/API/SBFile.cpp lldb/source/Host/common/File.cpp lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h
Index: lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h =================================================================== --- lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h +++ lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h @@ -658,7 +658,6 @@ class PythonFile : public PythonObject { public: PythonFile(); - PythonFile(File &file, const char *mode); PythonFile(PyRefType type, PyObject *o); ~PythonFile() override; @@ -668,7 +667,19 @@ using PythonObject::Reset; void Reset(PyRefType type, PyObject *py_obj) override; - void Reset(File &file, const char *mode); + + static llvm::Expected<PythonFile> FromFile(File &file, + const char *mode = nullptr); + + PythonFile(File &file, const char *mode = nullptr) { + auto f = FromFile(file, mode); + if (f) + *this = std::move(f.get()); + else { + Reset(); + llvm::consumeError(f.takeError()); + } + } lldb::FileUP GetUnderlyingFile() const; Index: lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp =================================================================== --- lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp +++ lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp @@ -1012,8 +1012,6 @@ PythonFile::PythonFile() : PythonObject() {} -PythonFile::PythonFile(File &file, const char *mode) { Reset(file, mode); } - PythonFile::PythonFile(PyRefType type, PyObject *o) { Reset(type, o); } PythonFile::~PythonFile() {} @@ -1063,24 +1061,36 @@ PythonObject::Reset(PyRefType::Borrowed, result.get()); } -void PythonFile::Reset(File &file, const char *mode) { - if (!file.IsValid()) { - Reset(); - return; - } +Expected<PythonFile> PythonFile::FromFile(File &file, const char *mode) { + if (!file.IsValid()) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "invalid file"); + + PyObject *file_obj = (PyObject *)file.GetPythonObject(); + if (file_obj) + return Retain<PythonFile>(file_obj); + + if (!mode) + mode = file.GetOpenMode(); + if (!mode) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "can't determine open mode for file"); - char *cmode = const_cast<char *>(mode); #if PY_MAJOR_VERSION >= 3 - Reset(PyRefType::Owned, PyFile_FromFd(file.GetDescriptor(), nullptr, cmode, - -1, nullptr, "ignore", nullptr, 0)); + file_obj = PyFile_FromFd(file.GetDescriptor(), nullptr, mode, -1, nullptr, + "ignore", nullptr, 0); #else // Read through the Python source, doesn't seem to modify these strings - Reset(PyRefType::Owned, - PyFile_FromFile(file.GetStream(), const_cast<char *>(""), cmode, - nullptr)); + char *cmode = const_cast<char *>(mode); + file_obj = + PyFile_FromFile(file.GetStream(), const_cast<char *>(""), cmode, nullptr); #endif -} + if (!file_obj) + return exception(); + + return Take<PythonFile>(file_obj); +} FileUP PythonFile::GetUnderlyingFile() const { if (!IsValid()) @@ -1233,6 +1243,8 @@ return base_error; }; + void *GetPythonObject() const override { return m_py_obj.get(); } + protected: PythonFile m_py_obj; bool m_borrowed; @@ -1316,6 +1328,15 @@ return Status(); } + uint32_t GetOptions() const override { + GIL takeGIL; + auto options = GetOptionsForPyObject(m_py_obj); + if (!options) { + llvm::consumeError(options.takeError()); + return 0; + } + return options.get(); + } }; } // namespace Index: lldb/source/Host/common/File.cpp =================================================================== --- lldb/source/Host/common/File.cpp +++ lldb/source/Host/common/File.cpp @@ -38,7 +38,7 @@ using namespace lldb; using namespace lldb_private; -static const char *GetStreamOpenModeFromOptions(uint32_t options) { +const char *File::GetStreamOpenModeFromOptions(uint32_t options) { if (options & File::eOpenOptionAppend) { if (options & File::eOpenOptionRead) { if (options & File::eOpenOptionCanCreateNewOnly) @@ -215,6 +215,10 @@ return result; } +void *File::GetPythonObject() const { return nullptr; } + +uint32_t File::GetOptions() const { return 0; } + uint32_t File::GetPermissions(Status &error) const { int fd = GetDescriptor(); if (!DescriptorIsValid(fd)) { @@ -230,6 +234,8 @@ return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); } +uint32_t NativeFile::GetOptions() const { return m_options; } + int NativeFile::GetDescriptor() const { if (DescriptorIsValid()) return m_descriptor; Index: lldb/source/API/SBFile.cpp =================================================================== --- lldb/source/API/SBFile.cpp +++ lldb/source/API/SBFile.cpp @@ -103,6 +103,11 @@ return LLDB_RECORD_RESULT(!IsValid()); } +FileSP SBFile::GetFile() const { + LLDB_RECORD_METHOD_CONST_NO_ARGS(FileSP, SBFile, GetFile); + return m_opaque_sp; +} + namespace lldb_private { namespace repro { @@ -112,6 +117,7 @@ LLDB_REGISTER_METHOD_CONST(bool, SBFile, IsValid, ()); LLDB_REGISTER_METHOD_CONST(bool, SBFile, operator bool,()); LLDB_REGISTER_METHOD_CONST(bool, SBFile, operator!,()); + LLDB_REGISTER_METHOD_CONST(FileSP, SBFile, GetFile, ()); LLDB_REGISTER_METHOD(lldb::SBError, SBFile, Close, ()); } } // namespace repro Index: lldb/scripts/interface/SBFile.i =================================================================== --- lldb/scripts/interface/SBFile.i +++ lldb/scripts/interface/SBFile.i @@ -77,6 +77,9 @@ operator bool() const; SBError Close(); + + %feature("docstring", "convert this SBFile into a python io.IOBase file object"); + FileSP GetFile(); }; } // namespace lldb Index: lldb/scripts/Python/python-typemaps.swig =================================================================== --- lldb/scripts/Python/python-typemaps.swig +++ lldb/scripts/Python/python-typemaps.swig @@ -434,6 +434,22 @@ } } +%typemap(out) lldb::FileSP { + using namespace lldb_private; + $result = nullptr; + lldb::FileSP &sp = $1; + if (sp) { + PythonFile pyfile = unwrapOrSetPythonException(PythonFile::FromFile(*sp)); + if (!pyfile.IsValid()) + return nullptr; + $result = pyfile.release(); + } + if (!$result) + { + $result = Py_None; + Py_INCREF(Py_None); + } +} // FIXME both of these paths wind up calling fdopen() with no provision for ever calling // fclose() on the result. SB interfaces that use FILE* should be deprecated for scripting Index: lldb/packages/Python/lldbsuite/test/python_api/file_handle/TestFileHandle.py =================================================================== --- lldb/packages/Python/lldbsuite/test/python_api/file_handle/TestFileHandle.py +++ lldb/packages/Python/lldbsuite/test/python_api/file_handle/TestFileHandle.py @@ -773,7 +773,6 @@ @add_test_categories(['pyapi']) - @expectedFailure # FIXME implement SBFile::GetFile @skipIf(py_version=['<', (3,)]) def test_identity(self): Index: lldb/include/lldb/Host/File.h =================================================================== --- lldb/include/lldb/Host/File.h +++ lldb/include/lldb/Host/File.h @@ -53,6 +53,7 @@ static mode_t ConvertOpenOptionsForPOSIXOpen(uint32_t open_options); static uint32_t GetOptionsFromMode(llvm::StringRef mode); static bool DescriptorIsValid(int descriptor) { return descriptor >= 0; }; + static const char *GetStreamOpenModeFromOptions(uint32_t options); File() : IOObject(eFDTypeFile), m_is_interactive(eLazyBoolCalculate), @@ -308,6 +309,28 @@ /// format string \a format. virtual size_t PrintfVarArg(const char *format, va_list args); + /// If this file is a wrapper for a python file object, return it. + /// + /// \return + /// The PyObject* that this File wraps, or NULL. + virtual void *GetPythonObject() const; + + /// Return the OpenOptions for this file. + /// + /// Some options like eOpenOptionDontFollowSymlinks only make + /// sense when a file is being opened (or not at all) + /// and may not be preserved for this method. But any valid + /// File should return either or both of eOpenOptionRead and + /// eOpenOptionWrite here. + /// + /// \return + /// OpenOptions flags for this file, or 0 if unknown. + virtual uint32_t GetOptions() const; + + const char *GetOpenMode() const { + return GetStreamOpenModeFromOptions(GetOptions()); + } + /// Get the permissions for a this file. /// /// \return @@ -390,6 +413,7 @@ Status Flush() override; Status Sync() override; size_t PrintfVarArg(const char *format, va_list args) override; + uint32_t GetOptions() const override; protected: bool DescriptorIsValid() const { Index: lldb/include/lldb/API/SBFile.h =================================================================== --- lldb/include/lldb/API/SBFile.h +++ lldb/include/lldb/API/SBFile.h @@ -34,6 +34,8 @@ operator bool() const; bool operator!() const; + FileSP GetFile() const; + private: FileSP m_opaque_sp; };
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits