Skip to content

Commit 1c52b21

Browse files
committed
Make runPython sync
1 parent 204b4f3 commit 1c52b21

File tree

3 files changed

+44
-49
lines changed

3 files changed

+44
-49
lines changed
Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import Foundation
22
import LangChain
3-
import PythonKit
43
import PythonHelper
4+
import PythonKit
55

66
func solveMathProblem(_ problem: String) async throws -> String {
77
#if DEBUG
@@ -16,16 +16,20 @@ func solveMathProblem(_ problem: String) async throws -> String {
1616
}
1717
}
1818

19-
return try await runPython {
20-
let langchain = try Python.attemptImportOnPythonThread("langchain")
21-
let LLMMathChain = langchain.LLMMathChain
22-
let llm = try LangChainChatModel.DynamicChatOpenAI(temperature: 0)
23-
let llmMath = LLMMathChain.from_llm(llm, verbose: verbose)
24-
let result = try llmMath.run.throwing.dynamicallyCall(withArguments: problem)
25-
let answer = String(result)
26-
if let answer { return answer }
19+
let task = Task {
20+
try runPython {
21+
let langchain = try Python.attemptImportOnPythonThread("langchain")
22+
let LLMMathChain = langchain.LLMMathChain
23+
let llm = try LangChainChatModel.DynamicChatOpenAI(temperature: 0)
24+
let llmMath = LLMMathChain.from_llm(llm, verbose: verbose)
25+
let result = try llmMath.run.throwing.dynamicallyCall(withArguments: problem)
26+
let answer = String(result)
27+
if let answer { return answer }
2728

28-
throw E()
29+
throw E()
30+
}
2931
}
32+
33+
return try await task.value
3034
}
3135

ExtensionService/InitializePython.swift

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import Foundation
22
import Python
3-
import PythonKit
43
import PythonHelper
4+
import PythonKit
55

66
func initializePython() {
77
guard let sitePackagePath = Bundle.main.path(forResource: "site-packages", ofType: nil),
@@ -14,24 +14,21 @@ func initializePython() {
1414

1515
setenv("PYTHONHOME", stdLibPath, 1)
1616
setenv("PYTHONPATH", "\(stdLibPath):\(libDynloadPath):\(sitePackagePath)", 1)
17-
17+
1818
// Initialize python
1919
Py_Initialize()
20-
20+
2121
// Immediately release the thread, so that we can ensure the GIL state later.
2222
// We may not recover the thread because all future tasks will be done in the Python Thread.
23-
let _ = PyEval_SaveThread()
24-
23+
_ = PyEval_SaveThread()
24+
2525
// Setup GIL state guard.
26-
PythonHelper.PyGILState_Guard = { closure in
27-
let gilState = PyGILState_Ensure()
28-
try closure()
29-
PyGILState_Release(gilState)
30-
}
26+
PythonHelper.gilStateEnsure = { PyGILState_Ensure() }
27+
PythonHelper.gilStateRelease = { gilState in PyGILState_Release(gilState as! PyGILState_STATE) }
3128

3229
Task {
3330
// All future task should run inside runPython.
34-
try await runPython {
31+
try runPython {
3532
let sys = Python.import("sys")
3633
print("Python Version: \(sys.version_info.major).\(sys.version_info.minor)")
3734
}
Lines changed: 22 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,36 @@
11
import Foundation
22
import PythonKit
33

4-
public var PyGILState_Guard: ((() throws -> Void) throws -> Void)! = nil
4+
public var gilStateEnsure: (() -> Any)!
5+
public var gilStateRelease: ((Any) -> Void)!
6+
func gilStateGuard<T>(_ closure: @escaping () throws -> T) throws -> T {
7+
let state = gilStateEnsure()
8+
do {
9+
let result = try closure()
10+
gilStateRelease(state)
11+
return result
12+
} catch {
13+
gilStateRelease(state)
14+
throw error
15+
}
16+
}
517

618
let pythonQueue = DispatchQueue(label: "Python Queue")
719

820
public func runPython<T>(
921
usePythonThread: Bool = false,
1022
_ closure: @escaping () throws -> T
11-
) async throws -> T {
12-
return try await withUnsafeThrowingContinuation { con in
13-
if usePythonThread {
14-
PythonThread.shared.runPython {
15-
do {
16-
try PyGILState_Guard {
17-
con.resume(returning: try closure())
18-
}
19-
} catch let error as PythonError {
20-
con.resume(throwing: ReadablePythonError(error))
21-
} catch {
22-
con.resume(throwing: error)
23-
}
24-
}
25-
} else {
26-
pythonQueue.async {
27-
do {
28-
try PyGILState_Guard {
29-
con.resume(returning: try closure())
30-
}
31-
} catch let error as PythonError {
32-
con.resume(throwing: ReadablePythonError(error))
33-
} catch {
34-
con.resume(throwing: error)
35-
}
23+
) throws -> T {
24+
if usePythonThread {
25+
return try PythonThread.shared.runPythonAndWait {
26+
return try gilStateGuard {
27+
try closure()
3628
}
3729
}
30+
} else {
31+
return try gilStateGuard {
32+
try closure()
33+
}
3834
}
3935
}
4036

@@ -66,5 +62,3 @@ public struct ReadablePythonError: Error, LocalizedError {
6662
}
6763
}
6864

69-
70-

0 commit comments

Comments
 (0)