From fe7a207548d5a700c9f133e65d5d02a7a76a1bd9 Mon Sep 17 00:00:00 2001 From: Jonathan Penner Date: Thu, 3 Aug 2023 13:46:23 -0700 Subject: [PATCH 1/4] add GILState handling, allow Void-returning PyFunctions --- PythonKit/Python.swift | 134 +++++++++++++++++++++++++- PythonKit/PythonLibrary+Symbols.swift | 12 +++ 2 files changed, 141 insertions(+), 5 deletions(-) diff --git a/PythonKit/Python.swift b/PythonKit/Python.swift index 984aee0..483b7d7 100644 --- a/PythonKit/Python.swift +++ b/PythonKit/Python.swift @@ -19,6 +19,18 @@ // //===----------------------------------------------------------------------===// +struct GILState { + private var threadState: UnsafeMutableRawPointer? = nil + + mutating func ensure() { + threadState = PyGILState_Ensure() + } + + mutating func release() { + PyGILState_Release(threadState) + } +} + //===----------------------------------------------------------------------===// // `PyReference` definition //===----------------------------------------------------------------------===// @@ -55,7 +67,10 @@ final class PyReference { } deinit { + var lock = GILState() + lock.ensure() Py_DecRef(pointer) + lock.release() } var borrowedPyObject: PyObjectPointer { @@ -247,6 +262,9 @@ extension PythonError : CustomStringConvertible { // Reflect a Python error (which must be active) into a Swift error if one is // active. private func throwPythonErrorIfPresent() throws { + var lock = GILState() + lock.ensure() + defer { lock.release() } if PyErr_Occurred() == nil { return } var type: PyObjectPointer? @@ -295,6 +313,7 @@ public struct ThrowingPythonObject { withArguments args: [PythonConvertible] = []) throws -> PythonObject { try throwPythonErrorIfPresent() + let threadState = PyGILState_Ensure() // Positional arguments are passed as a tuple of objects. let argTuple = pyTuple(args.map { $0.pythonObject }) defer { Py_DecRef(argTuple) } @@ -305,6 +324,8 @@ public struct ThrowingPythonObject { // error, like `self` not being a Python callable. let selfObject = base.ownedPyObject defer { Py_DecRef(selfObject) } + + defer { PyGILState_Release(threadState) } guard let result = PyObject_CallObject(selfObject, argTuple) else { // If a Python exception was thrown, throw a corresponding Swift error. @@ -337,6 +358,9 @@ public struct ThrowingPythonObject { /// Implementation of `dynamicallyCall(withKeywordArguments)`. private func _dynamicallyCall(_ args: T) throws -> PythonObject where T.Element == (key: String, value: PythonConvertible) { + var lock = GILState() + lock.ensure() + defer { lock.release() } try throwPythonErrorIfPresent() // An array containing positional arguments. @@ -441,6 +465,9 @@ public struct CheckingPythonObject { public subscript(dynamicMember name: String) -> PythonObject? { get { + var lock = GILState() + lock.ensure() + defer { lock.release() } let selfObject = base.ownedPyObject defer { Py_DecRef(selfObject) } guard let result = PyObject_GetAttrString(selfObject, name) else { @@ -559,6 +586,10 @@ public extension PythonObject { defer { Py_DecRef(selfObject) } let valueObject = newValue.ownedPyObject defer { Py_DecRef(valueObject) } + + var lock = GILState() + lock.ensure() + defer { lock.release() } if PyObject_SetAttrString(selfObject, memberName, valueObject) == -1 { try! throwPythonErrorIfPresent() @@ -676,6 +707,9 @@ public struct PythonInterface { init() { Py_Initialize() // Initialize Python + let threadState = PyGILState_Ensure() + defer { PyGILState_Release(threadState) } + builtins = PythonObject(PyEval_GetBuiltins()) // Runtime Fixes: @@ -692,9 +726,14 @@ public struct PythonInterface { if sys.version_info.major == 3 and sys.platform == "darwin": sys.executable = os.path.join(sys.exec_prefix, "bin", "python3") """) + + } public func attemptImport(_ name: String) throws -> PythonObject { + let threadState = PyGILState_Ensure() + defer { PyGILState_Release(threadState) } + guard let module = PyImport_ImportModule(name) else { try throwPythonErrorIfPresent() throw PythonError.invalidModule(name) @@ -791,13 +830,19 @@ extension Bool : PythonConvertible, ConvertibleFromPython { guard isType(pythonObject, type: PyBool_Type) else { return nil } let pyObject = pythonObject.ownedPyObject - defer { Py_DecRef(pyObject) } + defer { + let threadState = PyGILState_Ensure() + Py_DecRef(pyObject) + PyGILState_Release(threadState) + } self = pyObject == _Py_TrueStruct } public var pythonObject: PythonObject { _ = Python // Ensure Python is initialized. + let threadState = PyGILState_Ensure() + defer { PyGILState_Release(threadState) } return PythonObject(consuming: PyBool_FromLong(self ? 1 : 0)) } } @@ -805,7 +850,11 @@ extension Bool : PythonConvertible, ConvertibleFromPython { extension String : PythonConvertible, ConvertibleFromPython { public init?(_ pythonObject: PythonObject) { let pyObject = pythonObject.ownedPyObject - defer { Py_DecRef(pyObject) } + defer { + let threadState = PyGILState_Ensure() + Py_DecRef(pyObject) + PyGILState_Release(threadState) + } guard let cString = PyString_AsString(pyObject) else { PyErr_Clear() @@ -816,6 +865,9 @@ extension String : PythonConvertible, ConvertibleFromPython { public var pythonObject: PythonObject { _ = Python // Ensure Python is initialized. + let threadState = PyGILState_Ensure() + defer { PyGILState_Release(threadState) } + let v = utf8CString.withUnsafeBufferPointer { // 1 is subtracted from the C string length to trim the trailing null // character (`\0`). @@ -831,8 +883,13 @@ fileprivate extension PythonObject { func converted( withError errorValue: T, by converter: (OwnedPyObjectPointer) -> T ) -> T? { + let threadState = PyGILState_Ensure() + let pyObject = ownedPyObject - defer { Py_DecRef(pyObject) } + defer { + Py_DecRef(pyObject) + PyGILState_Release(threadState) + } assert(PyErr_Occurred() == nil, "Python error occurred somewhere but wasn't handled") @@ -860,6 +917,8 @@ extension Int : PythonConvertible, ConvertibleFromPython { public var pythonObject: PythonObject { _ = Python // Ensure Python is initialized. + let threadState = PyGILState_Ensure() + defer { PyGILState_Release(threadState) } return PythonObject(consuming: PyInt_FromLong(self)) } } @@ -878,6 +937,8 @@ extension UInt : PythonConvertible, ConvertibleFromPython { public var pythonObject: PythonObject { _ = Python // Ensure Python is initialized. + let threadState = PyGILState_Ensure() + defer { PyGILState_Release(threadState) } return PythonObject(consuming: PyInt_FromSize_t(self)) } } @@ -895,6 +956,8 @@ extension Double : PythonConvertible, ConvertibleFromPython { public var pythonObject: PythonObject { _ = Python // Ensure Python is initialized. + let threadState = PyGILState_Ensure() + defer { PyGILState_Release(threadState) } return PythonObject(consuming: PyFloat_FromDouble(self)) } } @@ -1045,6 +1108,8 @@ where Wrapped : ConvertibleFromPython { extension Array : PythonConvertible where Element : PythonConvertible { public var pythonObject: PythonObject { _ = Python // Ensure Python is initialized. + let threadState = PyGILState_Ensure() + defer { PyGILState_Release(threadState) } let list = PyList_New(count)! for (index, element) in enumerated() { // `PyList_SetItem` steals the reference of the object stored. @@ -1070,6 +1135,9 @@ extension Dictionary : PythonConvertible where Key : PythonConvertible, Value : PythonConvertible { public var pythonObject: PythonObject { _ = Python // Ensure Python is initialized. + let threadState = PyGILState_Ensure() + defer { PyGILState_Release(threadState) } + let dict = PyDict_New()! for (key, value) in self { let k = key.ownedPyObject @@ -1185,6 +1253,9 @@ private typealias PythonUnaryOp = private func performBinaryOp( _ op: PythonBinaryOp, lhs: PythonObject, rhs: PythonObject) -> PythonObject { + + let threadState = PyGILState_Ensure() + defer { PyGILState_Release(threadState) } let result = op(lhs.borrowedPyObject, rhs.borrowedPyObject) // If binary operation fails (e.g. due to `TypeError`), throw an exception. try! throwPythonErrorIfPresent() @@ -1299,9 +1370,12 @@ extension PythonObject : Equatable, Comparable { private func compared(to other: PythonObject, byOp: Int32) -> Bool { let lhsObject = ownedPyObject let rhsObject = other.ownedPyObject + var lock = GILState() + lock.ensure() defer { Py_DecRef(lhsObject) Py_DecRef(rhsObject) + lock.release() } assert(PyErr_Occurred() == nil, "Python error occurred somewhere but wasn't handled") @@ -1343,9 +1417,12 @@ public extension PythonObject { private func compared(to other: PythonObject, byOp: Int32) -> PythonObject { let lhsObject = ownedPyObject let rhsObject = other.ownedPyObject + var lock = GILState() + lock.ensure() defer { Py_DecRef(lhsObject) Py_DecRef(rhsObject) + lock.release() } assert(PyErr_Occurred() == nil, "Python error occurred somewhere but wasn't handled") @@ -1480,6 +1557,8 @@ extension PythonObject : ExpressibleByArrayLiteral, ExpressibleByDictionaryLiter // existing key with the next one it encounters. public init(dictionaryLiteral elements: (PythonObject, PythonObject)...) { _ = Python // Ensure Python is initialized. + let threadState = PyGILState_Ensure() + defer { PyGILState_Release(threadState) } let dict = PyDict_New()! for (key, value) in elements { let k = key.ownedPyObject @@ -1512,7 +1591,12 @@ public struct PythonBytes : PythonConvertible, ConvertibleFromPython, Hashable { // We try to get the string/size pointers out. If it works, hooray, this is a bytes // otherwise it isn't. let pyObject = pythonObject.ownedPyObject - defer { Py_DecRef(pyObject) } + var lock = GILState() + lock.ensure() + defer { + Py_DecRef(pyObject) + lock.release() + } var length = 0 var buffer: UnsafeMutablePointer? = nil @@ -1576,7 +1660,13 @@ public struct PythonBytes : PythonConvertible, ConvertibleFromPython, Hashable { _ callback: (UnsafeRawBufferPointer) throws -> ReturnValue ) rethrows -> ReturnValue { let pyObject = self.pythonObject.ownedPyObject - defer { Py_DecRef(pyObject) } + + var lock = GILState() + lock.ensure() + defer { + Py_DecRef(pyObject) + lock.release() + } var length = 0 var buffer: UnsafeMutablePointer? = nil @@ -1674,6 +1764,14 @@ public struct PythonFunction { return try fn(argumentsAsTuple.map { $0 }) } } + + public init(_ fn: @escaping ([PythonObject]) throws -> Void) { + let f: ([PythonObject]) throws -> PythonConvertible = { + try fn($0) + return PyNone() + } + self.init(f) + } /// For cases where the Swift function should accept keyword arguments as `**kwargs` in Python. /// `**kwargs` must preserve order from Python 3.6 onward, similarly to @@ -1689,10 +1787,22 @@ public struct PythonFunction { return try fn(argumentsAsTuple.map { $0 }, kwargs) } } + + public init(_ fn: @escaping ([PythonObject], [(key: String, value: PythonObject)]) throws -> Void) { + let f: ([PythonObject], [(key: String, value: PythonObject)]) throws -> PythonConvertible = { + try fn($0, $1) + return PyNone() + } + self.init(f) + } } extension PythonFunction : PythonConvertible { public var pythonObject: PythonObject { + var lock = GILState() + lock.ensure() + defer { lock.release() } + // Ensure Python is initialized, and check for version match. let versionMajor = Python.versionInfo.major let versionMinor = Python.versionInfo.minor @@ -1701,6 +1811,8 @@ extension PythonFunction : PythonConvertible { } let destructor: @convention(c) (PyObjectPointer?) -> Void = { capsulePointer in + let threadState = PyGILState_Ensure() + defer { PyGILState_Release(threadState) } let funcPointer = PyCapsule_GetPointer(capsulePointer, nil) Unmanaged.fromOpaque(funcPointer).release() } @@ -1931,3 +2043,15 @@ extension PythonClass : PythonConvertible { typeObject } } + +public struct PyNone : PythonConvertible { + public var pythonObject: PythonObject { + var lock = GILState() + lock.ensure() + defer { lock.release() } + + let none = Py_BuildValue("")! + return PythonObject(none) + } + +} diff --git a/PythonKit/PythonLibrary+Symbols.swift b/PythonKit/PythonLibrary+Symbols.swift index c4db681..969f4ec 100644 --- a/PythonKit/PythonLibrary+Symbols.swift +++ b/PythonKit/PythonLibrary+Symbols.swift @@ -41,6 +41,12 @@ let Py_GE: Int32 = 5 let Py_Initialize: @convention(c) () -> Void = PythonLibrary.loadSymbol(name: "Py_Initialize") +let PyGILState_Ensure: @convention(c) () -> UnsafeMutableRawPointer? = + PythonLibrary.loadSymbol(name: "PyGILState_Ensure") + +let PyGILState_Release: @convention(c) (UnsafeMutableRawPointer?) -> Void = + PythonLibrary.loadSymbol(name: "PyGILState_Release") + let Py_IncRef: @convention(c) (PyObjectPointer?) -> Void = PythonLibrary.loadSymbol(name: "Py_IncRef") @@ -135,6 +141,12 @@ let PySlice_New: @convention(c) ( PyObjectPointer?) -> PyObjectPointer? = PythonLibrary.loadSymbol(name: "PySlice_New") +let Py_BuildValue: @convention(c) (UnsafeRawPointer) -> PyObjectPointer? = + PythonLibrary.loadSymbol(name: "Py_BuildValue") + +let PySequence_Check: @convention(c) (UnsafeRawPointer) -> Int = + PythonLibrary.loadSymbol(name: "PySequence_Check") + let PyTuple_New: @convention(c) (Int) -> PyObjectPointer? = PythonLibrary.loadSymbol(name: "PyTuple_New") From a8fe20a1e2c3ca178325978c6fc3501b9670c052 Mon Sep 17 00:00:00 2001 From: Jeff Date: Fri, 28 Mar 2025 10:42:55 -0700 Subject: [PATCH 2/4] windows: Fix insecure CRT warning about getenv. --- PythonKit/PythonLibrary.swift | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/PythonKit/PythonLibrary.swift b/PythonKit/PythonLibrary.swift index 6149478..b689b39 100644 --- a/PythonKit/PythonLibrary.swift +++ b/PythonKit/PythonLibrary.swift @@ -284,7 +284,17 @@ extension PythonLibrary { } var value: String? { +#if os(Windows) + var cString: UnsafeMutablePointer? = nil + var size: size_t = 0 + let result = _dupenv_s(&cString, &size, key) + defer { + if let cString { free(cString) } + } + guard result == 0, let cString else { return nil } +#else guard let cString = getenv(key) else { return nil } +#endif let value = String(cString: cString) guard !value.isEmpty else { return nil } return value From e58eabc5d3c6652f25a937954373186c9cb11d6e Mon Sep 17 00:00:00 2001 From: Jeff Date: Fri, 4 Apr 2025 14:38:07 -0700 Subject: [PATCH 3/4] Use dlerror() when dlopen() fails. --- PythonKit/PythonLibrary.swift | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/PythonKit/PythonLibrary.swift b/PythonKit/PythonLibrary.swift index 6149478..ab94a3f 100644 --- a/PythonKit/PythonLibrary.swift +++ b/PythonKit/PythonLibrary.swift @@ -205,6 +205,13 @@ extension PythonLibrary { // Must be RTLD_GLOBAL because subsequent .so files from the imported python // modules may depend on this .so file. let pythonLibraryHandle = dlopen(path, RTLD_LAZY | RTLD_GLOBAL) + if pythonLibraryHandle == nil { + self.log("Failed to load library at '\(path)'.") + if let errorCString = dlerror() { + let errorString = String(cString: errorCString) + self.log("Reason for failure: \(errorString)") + } + } #endif if pythonLibraryHandle != nil { From ae01fcc17bef93a321d47ae76509420034865ad2 Mon Sep 17 00:00:00 2001 From: Maxim-Lanskoy Date: Sun, 18 May 2025 01:17:28 +0300 Subject: [PATCH 4/4] Reversed @JonathanPenner3D fix. --- PythonKit/Python.swift | 141 ++------------------------ PythonKit/PythonLibrary+Symbols.swift | 12 --- 2 files changed, 10 insertions(+), 143 deletions(-) diff --git a/PythonKit/Python.swift b/PythonKit/Python.swift index 1b2d080..35d2fcb 100644 --- a/PythonKit/Python.swift +++ b/PythonKit/Python.swift @@ -19,18 +19,6 @@ // //===----------------------------------------------------------------------===// -struct GILState { - private var threadState: UnsafeMutableRawPointer? = nil - - mutating func ensure() { - threadState = PyGILState_Ensure() - } - - mutating func release() { - PyGILState_Release(threadState) - } -} - //===----------------------------------------------------------------------===// // `PyReference` definition //===----------------------------------------------------------------------===// @@ -67,10 +55,7 @@ final class PyReference { } deinit { - var lock = GILState() - lock.ensure() Py_DecRef(pointer) - lock.release() } var borrowedPyObject: PyObjectPointer { @@ -262,9 +247,6 @@ extension PythonError : CustomStringConvertible { // Reflect a Python error (which must be active) into a Swift error if one is // active. private func throwPythonErrorIfPresent() throws { - var lock = GILState() - lock.ensure() - defer { lock.release() } if PyErr_Occurred() == nil { return } var type: PyObjectPointer? @@ -312,7 +294,7 @@ public struct ThrowingPythonObject { public func dynamicallyCall( withArguments args: [PythonConvertible] = []) throws -> PythonObject { try throwPythonErrorIfPresent() - let threadState = PyGILState_Ensure() + // Positional arguments are passed as a tuple of objects. let argTuple = pyTuple(args.map { $0.pythonObject }) defer { Py_DecRef(argTuple) } @@ -323,8 +305,7 @@ public struct ThrowingPythonObject { // error, like `self` not being a Python callable. let selfObject = base.ownedPyObject defer { Py_DecRef(selfObject) } - defer { PyGILState_Release(threadState) } - + guard let result = PyObject_CallObject(selfObject, argTuple) else { // If a Python exception was thrown, throw a corresponding Swift error. try throwPythonErrorIfPresent() @@ -356,9 +337,6 @@ public struct ThrowingPythonObject { /// Implementation of `dynamicallyCall(withKeywordArguments)`. private func _dynamicallyCall(_ args: T) throws -> PythonObject where T.Element == (key: String, value: PythonConvertible) { - var lock = GILState() - lock.ensure() - defer { lock.release() } try throwPythonErrorIfPresent() // An array containing positional arguments. @@ -463,9 +441,6 @@ public struct CheckingPythonObject { public subscript(dynamicMember name: String) -> PythonObject? { get { - var lock = GILState() - lock.ensure() - defer { lock.release() } let selfObject = base.ownedPyObject defer { Py_DecRef(selfObject) } guard let result = PyObject_GetAttrString(selfObject, name) else { @@ -585,9 +560,6 @@ public extension PythonObject { let valueObject = newValue.ownedPyObject defer { Py_DecRef(valueObject) } - var lock = GILState() - lock.ensure() - defer { lock.release() } if PyObject_SetAttrString(selfObject, memberName, valueObject) == -1 { try! throwPythonErrorIfPresent() fatalError(""" @@ -704,9 +676,6 @@ public struct PythonInterface { init() { Py_Initialize() // Initialize Python - let threadState = PyGILState_Ensure() - defer { PyGILState_Release(threadState) } - builtins = PythonObject(PyEval_GetBuiltins()) // Runtime Fixes: @@ -724,14 +693,9 @@ public struct PythonInterface { executable_name = "python{}.{}".format(sys.version_info.major, sys.version_info.minor) sys.executable = os.path.join(sys.exec_prefix, "bin", executable_name) """) - - } public func attemptImport(_ name: String) throws -> PythonObject { - let threadState = PyGILState_Ensure() - defer { PyGILState_Release(threadState) } - guard let module = PyImport_ImportModule(name) else { try throwPythonErrorIfPresent() throw PythonError.invalidModule(name) @@ -828,19 +792,13 @@ extension Bool : PythonConvertible, ConvertibleFromPython { guard isType(pythonObject, type: PyBool_Type) else { return nil } let pyObject = pythonObject.ownedPyObject - defer { - let threadState = PyGILState_Ensure() - Py_DecRef(pyObject) - PyGILState_Release(threadState) - } - + defer { Py_DecRef(pyObject) } + self = pyObject == _Py_TrueStruct } public var pythonObject: PythonObject { _ = Python // Ensure Python is initialized. - let threadState = PyGILState_Ensure() - defer { PyGILState_Release(threadState) } return PythonObject(consuming: PyBool_FromLong(self ? 1 : 0)) } } @@ -848,12 +806,8 @@ extension Bool : PythonConvertible, ConvertibleFromPython { extension String : PythonConvertible, ConvertibleFromPython { public init?(_ pythonObject: PythonObject) { let pyObject = pythonObject.ownedPyObject - defer { - let threadState = PyGILState_Ensure() - Py_DecRef(pyObject) - PyGILState_Release(threadState) - } - + defer { Py_DecRef(pyObject) } + guard let cString = PyString_AsString(pyObject) else { PyErr_Clear() return nil @@ -863,9 +817,6 @@ extension String : PythonConvertible, ConvertibleFromPython { public var pythonObject: PythonObject { _ = Python // Ensure Python is initialized. - let threadState = PyGILState_Ensure() - defer { PyGILState_Release(threadState) } - let v = utf8CString.withUnsafeBufferPointer { // 1 is subtracted from the C string length to trim the trailing null // character (`\0`). @@ -881,14 +832,9 @@ fileprivate extension PythonObject { func converted( withError errorValue: T, by converter: (OwnedPyObjectPointer) -> T ) -> T? { - let threadState = PyGILState_Ensure() - let pyObject = ownedPyObject - defer { - Py_DecRef(pyObject) - PyGILState_Release(threadState) - } - + defer { Py_DecRef(pyObject) } + assert(PyErr_Occurred() == nil, "Python error occurred somewhere but wasn't handled") @@ -915,8 +861,6 @@ extension Int : PythonConvertible, ConvertibleFromPython { public var pythonObject: PythonObject { _ = Python // Ensure Python is initialized. - let threadState = PyGILState_Ensure() - defer { PyGILState_Release(threadState) } return PythonObject(consuming: PyInt_FromLong(self)) } } @@ -935,8 +879,6 @@ extension UInt : PythonConvertible, ConvertibleFromPython { public var pythonObject: PythonObject { _ = Python // Ensure Python is initialized. - let threadState = PyGILState_Ensure() - defer { PyGILState_Release(threadState) } return PythonObject(consuming: PyInt_FromSize_t(self)) } } @@ -954,8 +896,6 @@ extension Double : PythonConvertible, ConvertibleFromPython { public var pythonObject: PythonObject { _ = Python // Ensure Python is initialized. - let threadState = PyGILState_Ensure() - defer { PyGILState_Release(threadState) } return PythonObject(consuming: PyFloat_FromDouble(self)) } } @@ -1106,8 +1046,6 @@ where Wrapped : ConvertibleFromPython { extension Array : PythonConvertible where Element : PythonConvertible { public var pythonObject: PythonObject { _ = Python // Ensure Python is initialized. - let threadState = PyGILState_Ensure() - defer { PyGILState_Release(threadState) } let list = PyList_New(count)! for (index, element) in enumerated() { // `PyList_SetItem` steals the reference of the object stored. @@ -1133,9 +1071,6 @@ extension Dictionary : PythonConvertible where Key : PythonConvertible, Value : PythonConvertible { public var pythonObject: PythonObject { _ = Python // Ensure Python is initialized. - let threadState = PyGILState_Ensure() - defer { PyGILState_Release(threadState) } - let dict = PyDict_New()! for (key, value) in self { let k = key.ownedPyObject @@ -1251,9 +1186,6 @@ private typealias PythonUnaryOp = private func performBinaryOp( _ op: PythonBinaryOp, lhs: PythonObject, rhs: PythonObject) -> PythonObject { - - let threadState = PyGILState_Ensure() - defer { PyGILState_Release(threadState) } let result = op(lhs.borrowedPyObject, rhs.borrowedPyObject) // If binary operation fails (e.g. due to `TypeError`), throw an exception. try! throwPythonErrorIfPresent() @@ -1368,12 +1300,9 @@ extension PythonObject : Equatable, Comparable { private func compared(to other: PythonObject, byOp: Int32) -> Bool { let lhsObject = ownedPyObject let rhsObject = other.ownedPyObject - var lock = GILState() - lock.ensure() defer { Py_DecRef(lhsObject) Py_DecRef(rhsObject) - lock.release() } assert(PyErr_Occurred() == nil, "Python error occurred somewhere but wasn't handled") @@ -1415,12 +1344,9 @@ public extension PythonObject { private func compared(to other: PythonObject, byOp: Int32) -> PythonObject { let lhsObject = ownedPyObject let rhsObject = other.ownedPyObject - var lock = GILState() - lock.ensure() defer { Py_DecRef(lhsObject) Py_DecRef(rhsObject) - lock.release() } assert(PyErr_Occurred() == nil, "Python error occurred somewhere but wasn't handled") @@ -1555,8 +1481,6 @@ extension PythonObject : ExpressibleByArrayLiteral, ExpressibleByDictionaryLiter // existing key with the next one it encounters. public init(dictionaryLiteral elements: (PythonObject, PythonObject)...) { _ = Python // Ensure Python is initialized. - let threadState = PyGILState_Ensure() - defer { PyGILState_Release(threadState) } let dict = PyDict_New()! for (key, value) in elements { let k = key.ownedPyObject @@ -1589,12 +1513,7 @@ public struct PythonBytes : PythonConvertible, ConvertibleFromPython, Hashable { // We try to get the string/size pointers out. If it works, hooray, this is a bytes // otherwise it isn't. let pyObject = pythonObject.ownedPyObject - var lock = GILState() - lock.ensure() - defer { - Py_DecRef(pyObject) - lock.release() - } + defer { Py_DecRef(pyObject) } var length = 0 var buffer: UnsafeMutablePointer? = nil @@ -1658,13 +1577,7 @@ public struct PythonBytes : PythonConvertible, ConvertibleFromPython, Hashable { _ callback: (UnsafeRawBufferPointer) throws -> ReturnValue ) rethrows -> ReturnValue { let pyObject = self.pythonObject.ownedPyObject - - var lock = GILState() - lock.ensure() - defer { - Py_DecRef(pyObject) - lock.release() - } + defer { Py_DecRef(pyObject) } var length = 0 var buffer: UnsafeMutablePointer? = nil @@ -1763,14 +1676,6 @@ public struct PythonFunction { } } - public init(_ fn: @escaping ([PythonObject]) throws -> Void) { - let f: ([PythonObject]) throws -> PythonConvertible = { - try fn($0) - return PyNone() - } - self.init(f) - } - /// For cases where the Swift function should accept keyword arguments as `**kwargs` in Python. /// `**kwargs` must preserve order from Python 3.6 onward, similarly to /// Swift `KeyValuePairs` and unlike `Dictionary`. `KeyValuePairs` cannot be @@ -1785,22 +1690,10 @@ public struct PythonFunction { return try fn(argumentsAsTuple.map { $0 }, kwargs) } } - - public init(_ fn: @escaping ([PythonObject], [(key: String, value: PythonObject)]) throws -> Void) { - let f: ([PythonObject], [(key: String, value: PythonObject)]) throws -> PythonConvertible = { - try fn($0, $1) - return PyNone() - } - self.init(f) - } } extension PythonFunction : PythonConvertible { public var pythonObject: PythonObject { - var lock = GILState() - lock.ensure() - defer { lock.release() } - // Ensure Python is initialized, and check for version match. let versionMajor = Python.versionInfo.major let versionMinor = Python.versionInfo.minor @@ -1809,8 +1702,6 @@ extension PythonFunction : PythonConvertible { } let destructor: @convention(c) (PyObjectPointer?) -> Void = { capsulePointer in - let threadState = PyGILState_Ensure() - defer { PyGILState_Release(threadState) } let funcPointer = PyCapsule_GetPointer(capsulePointer, nil) Unmanaged.fromOpaque(funcPointer).release() } @@ -2041,15 +1932,3 @@ extension PythonClass : PythonConvertible { typeObject } } - -public struct PyNone : PythonConvertible { - public var pythonObject: PythonObject { - var lock = GILState() - lock.ensure() - defer { lock.release() } - - let none = Py_BuildValue("")! - return PythonObject(none) - } - -} diff --git a/PythonKit/PythonLibrary+Symbols.swift b/PythonKit/PythonLibrary+Symbols.swift index 969f4ec..c4db681 100644 --- a/PythonKit/PythonLibrary+Symbols.swift +++ b/PythonKit/PythonLibrary+Symbols.swift @@ -41,12 +41,6 @@ let Py_GE: Int32 = 5 let Py_Initialize: @convention(c) () -> Void = PythonLibrary.loadSymbol(name: "Py_Initialize") -let PyGILState_Ensure: @convention(c) () -> UnsafeMutableRawPointer? = - PythonLibrary.loadSymbol(name: "PyGILState_Ensure") - -let PyGILState_Release: @convention(c) (UnsafeMutableRawPointer?) -> Void = - PythonLibrary.loadSymbol(name: "PyGILState_Release") - let Py_IncRef: @convention(c) (PyObjectPointer?) -> Void = PythonLibrary.loadSymbol(name: "Py_IncRef") @@ -141,12 +135,6 @@ let PySlice_New: @convention(c) ( PyObjectPointer?) -> PyObjectPointer? = PythonLibrary.loadSymbol(name: "PySlice_New") -let Py_BuildValue: @convention(c) (UnsafeRawPointer) -> PyObjectPointer? = - PythonLibrary.loadSymbol(name: "Py_BuildValue") - -let PySequence_Check: @convention(c) (UnsafeRawPointer) -> Int = - PythonLibrary.loadSymbol(name: "PySequence_Check") - let PyTuple_New: @convention(c) (Int) -> PyObjectPointer? = PythonLibrary.loadSymbol(name: "PyTuple_New")