Import Python Scripts To SwiftUI With PythonKit

Daily Coding Tip 034

This tutorial is somewhat based on Anupam Chugh’s PythonKit tutorial, which teaches you how to download a YouTube video and display it in a SwiftUI video player.

We’re going to be doing something much simpler.

Anyone familiar with the Python language, or even something like JavaScript, will know that strings are handled differently in these languages.

Although Swift allows you to add two strings together using the + addition operator, it does not allow you to multiply a string by a number. This is mostly because type safety (which those other languages lack) prevents Swift from allowing operations involving different types. You may have found that you can’t even multiply two numbers of different types without the compiler complaining that you must convert them to be the same type first.

This is a useful feature, because you want to know what you’ll be getting out of it. If you want to multiply a Float by a Double, what should the result be? A Double, as the name suggests, has double the number of bits that a Float has. Swift requires that you specifically request to halve the precision of your result by converting the Double to a Float, as this may be an unwanted outcome.

Python allows for the multiplication of strings, so we’re going to make use of it here. It’s obviously true that you could use operator overloading or even a simple function to add this functionality. But this is mainly about calling Python from within Swift code, which may be useful if you use Python for more complicated tasks. You’re going to need to import PythonKit. Create a new Xcode macOS project, choosing SwiftUI as the user interface.

PythonKit doesn’t work on iOS, so don’t even try making a multiplatform app!

Go to File > Swift Packages > Add Package Dependency and paste this:

https://github.com/pvieito/PythonKit

I imported the master branch, but it doesn’t really matter which option you choose for this tutorial. Now that you have PythonKit in your project, you should try importing the library into your code by writing import PythonKit.

If you can do that successfully, start by creating this extension of PythonKit’s PythonObject class.

This gives us an easy way to load a Python script from our bundle.

Create an empty file called MyPythonScript.py in the same folder as your SwiftUI code.

You’ll need to add this Python code to that new file:

def hello():
    return "Python says Hello World"
def multiplyString(string, number):
    return string * number

Since we know the name of this file, searching the main bundle for it will give us the full URL for its location. We actually only care about the folder it’s in, which is why we’re calling .deletingLastPathComponent() on it. That’s because we want to add this folder to Python so that any scripts in the folder can be accessed.

If the path has not been added before, we append it to sys.path, which is an array of type PythonObject. Then we can import the file, which should be successful because the guard let at the beginning would not let us continue if the file we want isn’t in that folder. You can use this static function directly, or I’ve provided a simple initialiser for PythonObject which calls it for you.

Finally our SwiftUI code displays the result of importing Python.

Replace the existing ContentView structure with this:

We create a PythonObject that stores the contents of our script file and we obtain the helloWorld string as a computed property. Since myPythonScript is initialised at the same scope as helloWorld, it isn’t possible to call the hello() function without it being a computed property. Another way you could do it is make myPythonScript a static constant, but then you’d have to call it using Self.myPthonScript in the multiplyString function.

The multiplyString function unsurprisingly calls the Python function, and both of them are requesting the result in string format by getting the description.

The SwiftUI merely displays the two strings on top of each other in a VStack.

Get more Daily Coding Tips in your inbox!