5

I'm trying to use some Python Code in my Swift project with PythonKit. In order to do that, I've downloaded the new Xcode 11 to add PythonKit as Swift Package. After adding PythonKit with Swift Package, I have these project dependencies right here.

Project Dependencies

I want to use my Python code at the start of my app, so I put the call for Python code in my App Delegate, in the application function.

import UIKit
import PythonKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?


    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        let sys = Python.import("sys")
        print("Python Version: \(sys.version)")
        sys.path.append("/Users/me/Documents/MyProject/MyPackage/my_python_main_file")
        let pythonAPI = Python.import("my_python_main_file")
        pythonAPI.main_function.call()

        return true
    }

After running my project, I get the following error :

Fatal error: Python library not found. Set the PYTHON_LIBRARY environment variable with the path to a Python library.

I tried to follow the different steps with Breakpoints to know where the code actually crashes. So here is the different stages the PythonKit goes through :

It goes inside PythonLibrary init() and produces the error :

guard let pythonLibraryHandle = PythonLibrary.loadPythonLibrary() else {
      fatalError("""
        Python library not found. Set the \(Environment.library.key) \
        environment variable with the path to a Python library.
        """)
    }

After investigation, it is because of the call of dlopen inside of loadPythonLibrary function

static func loadPythonLibrary(at path: String) -> UnsafeMutableRawPointer? {
    log("Trying to load library at '\(path)'...")
    #if canImport(Darwin) || canImport(Glibc)
    // 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)
    #elseif os(Windows)
    let pythonLibraryHandle = UnsafeMutableRawPointer(LoadLibraryA(path))
    #endif

    if pythonLibraryHandle != nil {
      log("Library at '\(path)' was sucessfully loaded.")
    }
    return pythonLibraryHandle
  }

This functions returns nil, which is due to dlopen function returning nil.

However, I checked the path given as parameter to loadPythonLibrary(at : path) and it appeared to be correct (in Terminal I tried to do cd to the following path and it worked) :

/usr/local/Frameworks/Python.framework/Versions/2.7/Python

I am using Python 2.7 in my code.

Do you know why dlopen would return nil in my case ?

marc-medley
  • 8,931
  • 5
  • 60
  • 66
Anissa
  • 51
  • 3

1 Answers1

2

You can do it now using my fork of PythonKit at https://github.com/kewlbear/PythonKit. This package depends on my other package https://github.com/kewlbear/Python-iOS. Ultimately Python will be embedded in the app. Currently Python 3.8 is used.

cahn
  • 1,350
  • 1
  • 12
  • 24