KAP Tool#

To upload a Python package compatible with Linux to Kappa-Automate, you need to obtain the Linux-compatible distribution files for the package. We have developed the KAP Tool to simplify this procedure.

Follow these steps:

  • Copy the code below into a Python file named kap.py:

import os
import sys
import tempfile
import shutil
import subprocess
import argparse
import textwrap
import zipfile

from pathlib import Path

parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter)
subparsers = parser.add_subparsers(title='available commands')

pack_parser = subparsers.add_parser('pack', help="Create a KAPPA-Automate package based on requirements file")
pack_parser.add_argument('requirements', type=str, help='Create a KAPPA-Automate user task package from the given requirements file')

install_parser = subparsers.add_parser('install', help="Create a KAPPA-Automate package based on requirements file and install it on KAPPA-Automate")
install_parser.add_argument('requirements', type=str, help='Create a KAPPA-Automate user task package from the given requirements file')

parser.epilog = textwrap.dedent(f"{pack_parser.format_usage()}{install_parser.format_usage()}")

args = parser.parse_args(args=None if sys.argv[1:] else ['--help'])

with tempfile.TemporaryDirectory() as temp_dir:
    print("Downloading:")
    shutil.rmtree(temp_dir)
    download_dir = Path(temp_dir) / "downloaded_packages"
    os.makedirs(download_dir)

    # Try different approaches in order of preference
    download_commands = [
        # First try: exact platform with binary only
        [sys.executable, "-m", "pip", "download", f"--dest={download_dir}", "--platform=manylinux_2_17_x86_64.manylinux2014_x86_64", "--only-binary=:all:", "-r", args.requirements],
        # Second try: broader platform tag
        [sys.executable, "-m", "pip", "download", f"--dest={download_dir}", "--platform=manylinux_2_17_x86_64", "--prefer-binary", "-r", args.requirements],
        # Third try: no platform restriction, binary preferred
        [sys.executable, "-m", "pip", "download", f"--dest={download_dir}", "--prefer-binary", "-r", args.requirements],
        # Final try: allow everything
        [sys.executable, "-m", "pip", "download", f"--dest={download_dir}", "-r", args.requirements]
    ]

    success = False
    for i, cmd in enumerate(download_commands):
        try:
            print(f"Attempt {i+1}: {' '.join(cmd[4:])}")  # Show the relevant flags
            result = subprocess.run(cmd, capture_output=True, text=True)

            if result.returncode == 0:
                print("Download successful!")
                if result.stdout.strip():
                    print(result.stdout)
                success = True
                break
            else:
                print(f"Attempt {i+1} failed: {result.stderr.strip()}")

        except Exception as e:
            print(f"Attempt {i+1} encountered error: {e}")

    if not success:
        print("All download attempts failed!")
        exit(1)

    print("Unpacking:")

    ka_package_dir = Path(temp_dir) / "ka_package"
    os.makedirs(ka_package_dir)

    for whl_file in os.listdir(download_dir):
        with zipfile.ZipFile(Path(download_dir) / whl_file) as f:
            f.extractall(ka_package_dir)
        print(f"{whl_file} -> {ka_package_dir}")

    print("Re-packing:")

    requirements_path = Path(args.requirements)
    ka_package_file = requirements_path.parent / (requirements_path.stem + ".zip")
    with zipfile.ZipFile(ka_package_file, "w", zipfile.ZIP_DEFLATED) as zf:
        src_path = Path(ka_package_dir).expanduser().resolve(strict=True)
        for file in src_path.rglob('*'):
            zf.write(file, file.relative_to(src_path))
            print(f"{file} -> {ka_package_file}")

    print("Uploading:")
  • Create a “requirements.txt” file listing all packages you want to use.

  • From a terminal in the directory containing kap.py, run: python -m kap pack requirements.txt

This will generate a zip file containing all the specified packages.

Example: If you only need numpy 2.0.0, add numpy==2.0.0 to your requirements.txt file and run the command above.