Skip to content

Managing Site Packages

Overview

This guide covers how to add Python packages to your PSProject using both uv commands and manual pyproject.toml editing. These packages will be included when you run psproject update site-packages to sync dependencies to your iOS/macOS Xcode project.

Using UV Commands

The uv package manager provides convenient commands to add dependencies to your project.

Add by Package Name

Add the latest version of a package:

uv add requests

This adds the package to [project.dependencies] in pyproject.toml:

[project]
dependencies = [
    "requests>=2.31.0",
]

Add by Specific Version

Add a package with a specific version constraint:

# Exact version
uv add "pillow==10.0.0"

# Minimum version
uv add "kivy>=2.3.1"

# Version range
uv add "numpy>=1.24.0,<2.0.0"

Results in:

[project]
dependencies = [
    "pillow==10.0.0",
    "kivy>=2.3.1",
    "numpy>=1.24.0,<2.0.0",
]

Add by Git Branch

Add a package directly from a Git branch:

# From main branch
uv add "git+https://github.com/kivy/kivy.git@main"

# From specific branch
uv add "git+https://github.com/username/package.git@feature-branch"

# With subdirectory
uv add "git+https://github.com/username/monorepo.git@main#subdirectory=packages/mypackage"

Results in:

[project]
dependencies = [
    "kivy @ git+https://github.com/kivy/kivy.git@main",
    "package @ git+https://github.com/username/package.git@feature-branch",
]

Add by Git Tag or Commit

Add a package from a specific tag or commit hash:

# By tag
uv add "git+https://github.com/username/package.git@v1.2.3"

# By commit hash
uv add "git+https://github.com/username/package.git@abc123def"

Add by URL

Add a package from a direct URL:

# From archive URL
uv add "https://github.com/username/package/archive/refs/tags/v1.0.0.tar.gz"

# From zip file
uv add "https://example.com/packages/mypackage-1.0.0.zip"

Results in:

[project]
dependencies = [
    "package @ https://github.com/username/package/archive/refs/tags/v1.0.0.tar.gz",
]

Add by Wheel URL

Add a pre-built wheel directly:

# From direct wheel URL
uv add "https://example.com/wheels/mypackage-1.0.0-py3-none-any.whl"

# Platform-specific wheel
uv add "https://example.com/wheels/numpy-1.24.0-cp313-cp313-macosx_11_0_arm64.whl"

Results in:

[project]
dependencies = [
    "mypackage @ https://example.com/wheels/mypackage-1.0.0-py3-none-any.whl",
]

Add Development Dependencies

Add packages only needed for development:

# Add to dev group
uv add --dev pytest
uv add --dev black
uv add --dev mypy

Results in:

[dependency-groups]
dev = [
    "pytest>=7.0.0",
    "black>=23.0.0",
    "mypy>=1.0.0",
]

Add Platform-Specific Dependencies

Add dependencies for specific platforms:

# Add to iOS group
uv add --group iphoneos pyobjus

# Add to Android group (if using buildozer)
uv add --group android pyjnius

Results in:

[dependency-groups]
iphoneos = [
    "pyobjus>=1.2.0",
]
android = [
    "pyjnius>=1.4.0",
]

Manual pyproject.toml Editing

You can also manually edit pyproject.toml to add or modify dependencies. This is useful for complex version constraints or when you need fine-grained control.

Basic Dependencies

Edit the [project.dependencies] section:

[project]
dependencies = [
    "kivy>=2.3.1",
    "pillow>=10.0.0",
    "requests>=2.31.0,<3.0.0",
    "python-dotenv==1.0.0",
]

Git Repository Dependencies

Specify Git repositories with various options:

[project]
dependencies = [
    # From branch
    "mypackage @ git+https://github.com/username/mypackage.git@main",

    # From tag
    "anotherpackage @ git+https://github.com/username/anotherpackage.git@v1.2.3",

    # From commit hash
    "thirdpackage @ git+https://github.com/username/thirdpackage.git@abc123def456",

    # With subdirectory
    "subpackage @ git+https://github.com/username/monorepo.git@main#subdirectory=packages/subpackage",

    # SSH URL (requires SSH keys)
    "privatepackage @ git+ssh://git@github.com/username/privatepackage.git@main",
]

Direct URL Dependencies

Specify packages from direct URLs:

[project]
dependencies = [
    # Archive URLs
    "package1 @ https://github.com/user/pkg/archive/refs/tags/v1.0.0.tar.gz",
    "package2 @ https://example.com/downloads/package2-2.1.0.zip",

    # Wheel URLs
    "package3 @ https://example.com/wheels/package3-1.0.0-py3-none-any.whl",

    # Platform-specific wheels
    "numpy @ https://files.pythonhosted.org/packages/.../numpy-1.24.0-cp313-cp313-macosx_11_0_arm64.whl",
]

Local Path Dependencies

Reference local packages during development:

[project]
dependencies = [
    # Relative path
    "mylocalpackage @ file:../mylocalpackage",

    # Absolute path
    "anotherlocal @ file:///Users/username/projects/anotherlocal",

    # Editable install (development mode)
    "mydevpackage @ file:../mydevpackage#egg=mydevpackage&editable=true",
]

Local paths are not portable

Local path dependencies won't work on other machines or in CI/CD. Use them only for local development and testing.

Dependency Groups

Organize dependencies by purpose:

[dependency-groups]
dev = [
    "pytest>=7.0.0",
    "pytest-cov>=4.0.0",
    "black>=23.0.0",
    "mypy>=1.0.0",
    "ruff>=0.1.0",
]

iphoneos = [
    "pyobjus>=1.2.0",
    "rubicon-objc>=0.4.0",
]

android = [
    "pyjnius>=1.4.0",
]

docs = [
    "mkdocs>=1.5.0",
    "mkdocs-material>=9.0.0",
]

Optional Dependencies

Define optional feature sets:

[project.optional-dependencies]
audio = [
    "pyaudio>=0.2.13",
    "sounddevice>=0.4.6",
]

video = [
    "opencv-python>=4.8.0",
    "ffmpeg-python>=0.2.0",
]

all = [
    "pyaudio>=0.2.13",
    "sounddevice>=0.4.6",
    "opencv-python>=4.8.0",
    "ffmpeg-python>=0.2.0",
]

Install optional dependencies:

# Install specific feature
uv sync --extra audio

# Install all optional dependencies
uv sync --extra all

Platform-Specific Markers

Use environment markers for platform-specific dependencies:

[project]
dependencies = [
    "pywin32>=305; platform_system == 'Windows'",
    "pyobjc-framework-Cocoa>=9.0; platform_system == 'Darwin'",
    "python-xlib>=0.33; platform_system == 'Linux'",
]

Common markers: - platform_system: 'Windows', 'Darwin', 'Linux' - sys_platform: 'win32', 'darwin', 'linux' - python_version: '3.13', '3.12', etc. - platform_machine: 'x86_64', 'arm64', etc.

Syncing Dependencies

After adding dependencies, sync them to your project:

Sync All Dependencies

uv sync

Sync with Development Dependencies

uv sync --all-groups

Sync with Specific Groups

uv sync --group iphoneos
uv sync --group dev --group iphoneos

Update Site Packages for iOS/macOS

After syncing, update your Xcode project:

psproject update site-packages

This copies the installed packages to your iOS/macOS project's site-packages directory.

Complete Example

Here's a complete pyproject.toml with various dependency types:

pyproject.toml
[project]
name = "MyKivyApp"
version = "1.0.0"
requires-python = ">=3.13"
dependencies = [
    # PyPI packages
    "kivy>=2.3.1",
    "kivymd>=1.1.1",
    "pillow>=10.0.0",
    "requests>=2.31.0,<3.0.0",

    # Git repository
    "custom-lib @ git+https://github.com/username/custom-lib.git@main",

    # Specific version from Git
    "experimental @ git+https://github.com/username/experimental.git@v0.5.0-beta",

    # Direct URL
    "special-package @ https://example.com/packages/special-package-1.2.0.tar.gz",

    # Wheel URL
    "optimized-lib @ https://example.com/wheels/optimized_lib-2.0.0-cp313-cp313-macosx_11_0_arm64.whl",

    # Platform-specific
    "pyobjus>=1.2.0; platform_system == 'Darwin'",
]

[project.optional-dependencies]
audio = ["pyaudio>=0.2.13"]
video = ["opencv-python>=4.8.0"]
all = ["pyaudio>=0.2.13", "opencv-python>=4.8.0"]

[dependency-groups]
dev = [
    "pytest>=7.0.0",
    "black>=23.0.0",
    "mypy>=1.0.0",
]

iphoneos = [
    "rubicon-objc>=0.4.0",
]

[build-system]
requires = ["uv_build>=0.9.2,<0.10.0"]
build-backend = "uv_build"

Workflow Example

Here's a typical workflow for adding and managing dependencies:

# 1. Initialize project
psproject init MyApp
cd MyApp

# 2. Add main dependencies
uv add kivy
uv add kivymd
uv add pillow

# 3. Add from Git repository
uv add "git+https://github.com/username/custom-widget.git@main"

# 4. Add development tools
uv add --dev pytest
uv add --dev black

# 5. Add iOS-specific dependency
uv add --group iphoneos pyobjus

# 6. Sync all dependencies
uv sync --all-groups

# 7. Create Xcode project
psproject create xcode

# 8. Update site-packages in Xcode project
psproject update site-packages

# 9. Build in Xcode
# Open project_dist/xcode/MyApp.xcodeproj and build

Best Practices

Version Pinning

For production apps, use specific version constraints to ensure reproducible builds:

dependencies = [
    "kivy==2.3.1",  # Exact version
    "requests>=2.31.0,<2.32.0",  # Range
]

Use UV Lock File

The uv.lock file ensures all developers use the same dependency versions. Commit it to version control:

git add uv.lock
git commit -m "Lock dependencies"

Separate Development Dependencies

Keep development tools separate from production dependencies:

uv add --dev pytest black mypy

Test After Adding Dependencies

Always test after adding new dependencies:

uv sync
psproject update site-packages
# Test in Xcode or on device

Wheel Compatibility

When using wheel URLs, ensure they match your target platform: - iOS: Use wheels built for the iOS platform (if available) - Check wheel tags: cp313 (Python 3.13), abi3 (stable ABI), macosx_11_0_arm64 (macOS ARM64)

Troubleshooting

Dependency Conflicts

If you encounter version conflicts:

# Show dependency tree
uv tree

# Update all dependencies to compatible versions
uv sync --upgrade

Missing Packages in Xcode

If packages don't appear in your iOS project:

# Force update site-packages
psproject update site-packages --force

# Check package installation
uv list

Git Authentication Issues

For private repositories:

# Use SSH instead of HTTPS
uv add "git+ssh://git@github.com/username/private-repo.git@main"

# Or use personal access token in URL
uv add "git+https://TOKEN@github.com/username/private-repo.git@main"

Wheel Not Found

If a wheel isn't available for your platform:

# Install from source
uv add --no-binary mypackage mypackage

# Or build wheel locally
uv build /path/to/package
uv add ./dist/mypackage-1.0.0-py3-none-any.whl

Additional Resources