Skip to content

Commit 5cd3512

Browse files
authored
Improve support for PythonKit, and update usage guide (#248)
* Add a Swift modulemap to the generated frameworks. * Updates usage information to reflect current package structure.
1 parent c82aa70 commit 5cd3512

File tree

3 files changed

+26
-21
lines changed

3 files changed

+26
-21
lines changed

Makefile

+6
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,9 @@ $$(PYTHON_INCLUDE-$(sdk))/pyconfig.h: $$(PYTHON_LIB-$(sdk))
466466
# Copy headers as-is from the first target in the $(sdk) SDK
467467
cp -r $$(PYTHON_INCLUDE-$$(firstword $$(SDK_TARGETS-$(sdk)))) $$(PYTHON_INCLUDE-$(sdk))
468468

469+
# Copy in the modulemap file
470+
cp -r patch/Python/module.modulemap $$(PYTHON_INCLUDE-$(sdk))
471+
469472
# Link the PYTHONHOME version of the headers
470473
mkdir -p $$(PYTHON_INSTALL-$(sdk))/include
471474
ln -si ../Python.framework/Headers $$(PYTHON_INSTALL-$(sdk))/include/python$(PYTHON_VER)
@@ -582,6 +585,9 @@ $$(PYTHON_XCFRAMEWORK-$(os))/Info.plist: \
582585
# Rewrite the framework to make it standalone
583586
patch/make-relocatable.sh $$(PYTHON_INSTALL_VERSION-macosx) 2>&1 > /dev/null
584587

588+
# Copy in the modulemap file
589+
cp -r patch/Python/module.modulemap $$(PYTHON_FRAMEWORK-macosx)/Headers
590+
585591
# Re-apply the signature on the binaries.
586592
codesign -s - --preserve-metadata=identifier,entitlements,flags,runtime -f $$(PYTHON_LIB-macosx) \
587593
2>&1 | tee $$(PYTHON_INSTALL-macosx)/python-$(os).codesign.log

USAGE.md

+15-21
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ what Briefcase is doing). The steps required are documented in the CPython usage
2020
guides:
2121

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

2525
For tvOS and watchOS, you should be able to broadly follow the instructions in
2626
the iOS guide.
@@ -29,7 +29,7 @@ the iOS guide.
2929

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

32-
### Embedded C API.
32+
### Embedded C API
3333

3434
You can use the [Python Embedded C
3535
API](https://docs.python.org/3/extending/embedding.html) to instantiate a Python
@@ -43,37 +43,31 @@ An alternate approach is to use
4343
[PythonKit](https://github.com/pvieito/PythonKit). PythonKit is a package that
4444
provides a Swift API to running Python code.
4545

46-
To use PythonKit in your project:
46+
To use PythonKit in your project, add the Python Apple Support package to your
47+
project as described above; then:
4748

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

51-
2. Create a file called `module.modulemap` inside
52-
`Python.xcframework/macos-arm64_x86_64/Headers/`, containing the following
53-
code:
54-
```
55-
module Python {
56-
umbrella header "Python.h"
57-
export *
58-
link "Python"
59-
}
60-
```
61-
62-
3. In your Swift code, initialize the Python runtime. This should generally be
52+
2. In your Swift code, initialize the Python runtime. This should generally be
6353
done as early as possible in the application's lifecycle, but definitely
64-
needs to be done before you invoke Python code:
54+
needs to be done before you invoke Python code. References to a specific
55+
Python version should reflect the version of Python you are using:
6556
```swift
6657
import Python
6758

68-
guard let stdLibPath = Bundle.main.path(forResource: "python-stdlib", ofType: nil) else { return }
69-
guard let libDynloadPath = Bundle.main.path(forResource: "python-stdlib/lib-dynload", ofType: nil) else { return }
70-
setenv("PYTHONHOME", stdLibPath, 1)
71-
setenv("PYTHONPATH", "\(stdLibPath):\(libDynloadPath)", 1)
59+
guard let pythonHome = Bundle.main.path(forResource: "python", ofType: nil) else { return }
60+
guard let pythonPath = Bundle.main.path(forResource: "python/lib/python3.13", ofType: nil) else { return }
61+
guard let libDynloadPath = Bundle.main.path(forResource: "python/lib/python3.13/lib-dynload", ofType: nil) else { return }
62+
let appPath = Bundle.main.path(forResource: "app", ofType: nil)
63+
64+
setenv("PYTHONHOME", pythonHome, 1)
65+
setenv("PYTHONPATH", [pythonPath, libDynloadPath, appPath].compactMap { $0 }.joined(separator: ":"), 1)
7266
Py_Initialize()
7367
// we now have a Python interpreter ready to be used
7468
```
7569

76-
5. Invoke Python code in your app. For example:
70+
3. Invoke Python code in your app. For example:
7771
```swift
7872
import PythonKit
7973

patch/Python/module.modulemap

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module Python {
2+
umbrella header "Python.h"
3+
export *
4+
link "Python"
5+
}

0 commit comments

Comments
 (0)