Skip to content

Update USAGE.md for iOS and macOS #249

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 20 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 97 additions & 45 deletions USAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,71 +20,123 @@ what Briefcase is doing). The steps required are documented in the CPython usage
guides:

* [macOS](https://docs.python.org/3/using/mac.html)
* [iOS](https://docs.python.org/3.14/using/ios.html)
* [iOS](https://docs.python.org/3/using/ios.html#adding-python-to-an-ios-project)

For tvOS and watchOS, you should be able to broadly follow the instructions in
the iOS guide.

## Accessing the Python runtime

There are 2 ways to access the Python runtime in your project code.
There are 3 ways to access the Python runtime in your project code.

### Embedded C API.
### Use C/Objective-C/C++ with Embedded C API

You can use the [Python Embedded C
API](https://docs.python.org/3/extending/embedding.html) to instantiate a Python
interpreter. This is the approach taken by Briefcase; you may find the bootstrap
mainline code generated by Briefcase a helpful guide to what is needed to start
an interpreter and run Python code.

### PythonKit
### Use Swift with Embedded C API
If you want to use Python framework in Swift, you should do some additional setups.

1. Edit all `Python.xcframework/*/Python.framework`
1. Make a `Modules/module.modulemap` file
```shell
cd Python.xcframework/macos-arm64_x86_64/Python.framework
mkdir Modules
touch Modules/module.modulemap
```
`macos-arm64_x86_64` in the cd command, should be changed to your target platform

2. Fill `Modules/module.modulemap` with the content:
```
framework module Python {
umbrella header "Python.h"
export *
link "Python"
}
```

3. Edit `Headers/cpython/pyatomic.h`, in the file:
- replace ``cpython/pyatomic_gcc.h`` with ``pyatomic_gcc.h``
- replace ``cpython/pyatomic_std.h`` with ``pyatomic_std.h``
- replace ``cpython/pyatomic_msc.h`` with ``pyatomic_msc.h``

2. Drag `Python.xcframework` into the root of the macOS/iOS project in Xcode Navigator
3. If you are making an iOS project, do the steps of 3, 6, 7, 8, 9 in the Python offical document [Adding Python to an iOS Project](https://docs.python.org/3/using/ios.html#adding-python-to-an-ios-project).
`iOS/Resources/dylib-Info-template.plist` for the step 3 is [here](https://github.com/python/cpython/blob/bee7bb3310b356e99e3a0f75f23efbc97f1b0a24/iOS/Resources/dylib-Info-template.plist))

5. In your Swift code, initialize the Python runtime. This should generally be
done as early as possible in the application's lifecycle, but definitely
needs to be done before you invoke Python code:

An alternate approach is to use
[PythonKit](https://github.com/pvieito/PythonKit). PythonKit is a package that
provides a Swift API to running Python code.
```swift
import Foundation
import Python

func setEnvs() {
#if os(macOS)
print("macOS do not need set envs")
#else
guard let pythonHome = Bundle.main.path(forResource: "python", ofType: nil) else { return }
setenv("PYTHONHOME", pythonHome, 1)

/*
The PYTHONPATH for the interpreter includes:
the python/lib/python3.X subfolder of your app’s bundle,
the python/lib/python3.X/lib-dynload subfolder of your app’s bundle, and
the app subfolder of your app’s bundle
*/
guard let pythonPath = Bundle.main.path(forResource: "python/lib/python3.13", ofType: nil) else { return }
guard let libDynLoad = Bundle.main.path(forResource: "python/lib/python3.13/lib-dynload", ofType: nil) else { return }
let appPath = Bundle.main.path(forResource: "app", ofType: nil)
setenv("PYTHONPATH", [pythonPath, libDynLoad, appPath].compactMap { $0 }.joined(separator: ":"), 1)
#endif
}

setEnvs()
Py_Initialize()
let version = String(cString: Py_GetVersion())
print(version)
// we now have a Python interpreter ready to be used
```

After init Python, you could use Embed C API in Swift directly.

To use PythonKit in your project:
To integrate 3rd party python code and dependencies, you will need to make sure
`PYTHONPATH` contains their paths; once this has been done, you can run
`Python.import("<lib name>")`. to import that module from inside swift.

1. Add PythonKit to your project using the Swift Package manager. See the
PythonKit documentation for details.

2. Create a file called `module.modulemap` inside
`Python.xcframework/macos-arm64_x86_64/Headers/`, containing the following
code:
```
module Python {
umbrella header "Python.h"
export *
link "Python"
}
```

3. In your Swift code, initialize the Python runtime. This should generally be
done as early as possible in the application's lifecycle, but definitely
needs to be done before you invoke Python code:
```swift
import Python
### Use Swift with `PythonKit`

guard let stdLibPath = Bundle.main.path(forResource: "python-stdlib", ofType: nil) else { return }
guard let libDynloadPath = Bundle.main.path(forResource: "python-stdlib/lib-dynload", ofType: nil) else { return }
setenv("PYTHONHOME", stdLibPath, 1)
setenv("PYTHONPATH", "\(stdLibPath):\(libDynloadPath)", 1)
Py_Initialize()
// we now have a Python interpreter ready to be used
```
Instead of using Embed C API, an alternate approach is to use
[PythonKit](https://github.com/pvieito/PythonKit).

5. Invoke Python code in your app. For example:
```swift
import PythonKit
PythonKit is a package that
provides Swift friendly API to running Python code.

let sys = Python.import("sys")
print("Python Version: \(sys.version_info.major).\(sys.version_info.minor)")
print("Python Encoding: \(sys.getdefaultencoding().upper())")
print("Python Path: \(sys.path)")
To use PythonKit in your project:

_ = Python.import("math") // verifies `lib-dynload` is found and signed successfully
```
1. Do all steps of "Use Swift with Embedded C API" above
2. Add PythonKit to your project using the Swift Package manager. See the
PythonKit documentation for details.

To integrate 3rd party python code and dependencies, you will need to make sure
`PYTHONPATH` contains their paths; once this has been done, you can run
`Python.import("<lib name>")`. to import that module from inside swift.
3. Invoke Python code in your app. For example:
```swift
import Foundation
import Python

// ... setEnv defines
setEnvs()
Py_Initialize()

import PythonKit
let sys = Python.import("sys")
print("Python Full Version: \(sys.version)")
print("Python Version: \(sys.version_info.major).\(sys.version_info.minor)")
print("Python Encoding: \(sys.getdefaultencoding().upper())")
print("Python Path: \(sys.path)")
_ = Python.import("math") // verifies `lib-dynload` is found and signed successfully
```