diff --git a/.agents/skills b/.agents/skills new file mode 120000 index 0000000..f0c855e --- /dev/null +++ b/.agents/skills @@ -0,0 +1 @@ +../Agents/Skills \ No newline at end of file diff --git a/.claude/skills b/.claude/skills new file mode 120000 index 0000000..f0c855e --- /dev/null +++ b/.claude/skills @@ -0,0 +1 @@ +../Agents/Skills \ No newline at end of file diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index e265347..a05389d 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -1,11 +1,19 @@ name: Continuous Integration on: - - push - - pull_request + push: + branches: + - main + pull_request: + branches: + - main jobs: continuous-integration: + if: > + (github.event_name != 'pull_request' || github.event.pull_request.draft == false) && + !contains(github.event.head_commit.message || '', '[SKIP-CI]') && + !contains(github.event.pull_request.title || '', '[SKIP-CI]') strategy: matrix: os: @@ -13,13 +21,19 @@ jobs: - macos-latest runs-on: ${{ matrix.os }} steps: + - name: Show Swift Version + run: swift --version - uses: actions/checkout@v1 - - uses: actions/setup-python@v5 + - uses: actions/setup-python@v6 with: - python-version: '3.x' + python-version: '3.13' + - name: Configure PythonKit + shell: bash + run: | + python_library="$(find -L "$pythonLocation" \( -name 'libpython3.13*.dylib' -o -name 'libpython3.13*.so' \) -print -quit)" + test -n "$python_library" + echo "PYTHON_LIBRARY=$python_library" >> "$GITHUB_ENV" - name: Test - run: swift test --enable-test-discovery - if: runner.os != 'Windows' + run: swift test env: - PYTHON_VERSION: 3 PYTHON_LOADER_LOGGING: TRUE diff --git a/.open_source b/.open_source new file mode 100644 index 0000000..e69de29 diff --git a/.public_project b/.public_project new file mode 100644 index 0000000..e69de29 diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..2538ff9 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,16 @@ +# Agents + +This is an open-source Swift package with a public API. + +## Project Notes + +- Read `README.md` for project-specific architecture, targets, and conventions. +- Keep project-specific guidance in `README.md` or source-local documentation, not in `AGENTS.md`. + +## Public Repository + +**IMPORTANT**: This is a public repository. Do not add internal or confidential information, including private project names, internal consumers, local paths, credentials, or content from private repositories or conversations. Use public, self-contained examples and dependencies. + +## Public API + +Modify this repository with extra care. Preserve its public APIs, behavior, supported platforms, toolchain requirements, and stable URLs. Do not introduce breaking changes without a detailed compatibility review and explicit authorization. Review source, tests, documentation, generated files, agent instructions, and commit or pull-request text for information disclosure before publishing. diff --git a/Agents/Instructions/.gitkeep b/Agents/Instructions/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Agents/Skills/.gitkeep b/Agents/Skills/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/CLAUDE.md b/CLAUDE.md new file mode 120000 index 0000000..47dc3e3 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +AGENTS.md \ No newline at end of file diff --git a/Package.swift b/Package.swift index c1ea0aa..2f5b7f0 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.1 +// swift-tools-version:6.0 import PackageDescription @@ -17,7 +17,10 @@ let package = Package( ), .testTarget( name: "PythonKitTests", - dependencies: ["PythonKit"] + dependencies: [ + "PythonKit", + ] ), - ] + ], + swiftLanguageModes: [.v5] ) diff --git a/PythonKit/PythonLibrary.swift b/PythonKit/PythonLibrary.swift index 6149478..ab94a3f 100644 --- a/PythonKit/PythonLibrary.swift +++ b/PythonKit/PythonLibrary.swift @@ -205,6 +205,13 @@ extension PythonLibrary { // 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) + if pythonLibraryHandle == nil { + self.log("Failed to load library at '\(path)'.") + if let errorCString = dlerror() { + let errorString = String(cString: errorCString) + self.log("Reason for failure: \(errorString)") + } + } #endif if pythonLibraryHandle != nil { diff --git a/README.md b/README.md index 83feb56..8174faa 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ +# PythonKit -# PythonKit [![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fpvieito%2FPythonKit%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/pvieito/PythonKit) [![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fpvieito%2FPythonKit%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/pvieito/PythonKit) @@ -17,7 +17,7 @@ print(f"Python Version: {sys.version}") print(f"Python Encoding: {sys.getdefaultencoding().upper()}") ``` -Can be implemented in Swift through PythonKit with the following code: +The same code can be implemented in Swift through PythonKit: ```swift import PythonKit @@ -34,14 +34,14 @@ print("Python Encoding: \(sys.getdefaultencoding().upper())") Add the following dependency to your `Package.swift` manifest: ```swift -.package(url: "https://github.com/pvieito/PythonKit.git", branch: "master"), +.package(url: "https://github.com/pvieito/PythonKit.git", from: "1.0.0"), ``` ## Environment Variables -As the Python library are loaded at runtime by **PythonKit**, it will try to find the most modern Python version available in the system. You can force a given version with the `PYTHON_VERSION` environment variable or an specific Python library path or name with `PYTHON_LIBRARY`. +As Python libraries are loaded at runtime by **PythonKit**, it will try to find the most modern Python version available in the system. You can force a given version with the `PYTHON_VERSION` environment variable or a specific Python library path or name with `PYTHON_LIBRARY`. -``` +```console $ PYTHON_VERSION=3 swift run [*] Python 3.5 $ PYTHON_VERSION=2.7 swift run @@ -54,7 +54,7 @@ $ PYTHON_LIBRARY=/usr/lib/x86_64-linux-gnu/libpython2.7.so swift run If **PythonKit** cannot find and load the Python library you can set the `PYTHON_LOADER_LOGGING` environment variable to know from which locations **PythonKit** is trying to load the library: -``` +```console $ PYTHON_LOADER_LOGGING=TRUE PYTHON_VERSION=3.8 swift run Loading symbol 'Py_Initialize' from the Python library... Trying to load library at 'Python.framework/Versions/3.8/Python'... @@ -64,8 +64,7 @@ Fatal error: Python library not found. Set the PYTHON_LIBRARY environment variab ## Troubleshooting -- If your are targeting the Mac platform with the [Hardened Runtime](https://developer.apple.com/documentation/security/hardened_runtime) enabled make sure you are properly signing and embedding the Python framework you are trying to load with **PythonKit**. The Hardened Runtime [Library Validation mechanism](https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_cs_disable-library-validation) prevents a process from loading libraries that are not signed by Apple or the same developer as the main process. - +- If you are targeting the Mac platform with the [Hardened Runtime](https://developer.apple.com/documentation/security/hardened_runtime) enabled, make sure you are properly signing and embedding the Python framework you are trying to load with **PythonKit**. The Hardened Runtime [Library Validation mechanism](https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_cs_disable-library-validation) prevents a process from loading libraries that are not signed by Apple or the same developer as the main process. ## Notes