Bring your own wheels

Some functions need Python packages that are not baked into the runtime image. If a package is private or internal, or simply not part of the image, you can build a wheel for it yourself, upload it with your function, and install it from your entrypoint at run time.

This guide shows the full loop:

  1. See what the runtime image already ships, so you don’t bring something you don’t need.

  2. Check your requirements against that set.

  3. Upload your wheels.

  4. Install them from your entrypoint and import them.

1. Discover what the image already ships

dependencies_versions() is read-only discovery of the dependencies baked into the runtime image. Anything listed here is already available to your function — you do not need to bring it yourself.

[ ]:
from qiskit_serverless import IBMServerlessClient

client = IBMServerlessClient()
client.dependencies_versions()

2. Check your requirements

dependency_report() diffs a list of requirements against what the image ships. Each requirement is reported as:

  • baked — already in the image; don’t bring it.

  • bring — not in the image; upload a wheel.

  • clash — the image ships a different version than you asked for.

This is a client-side diff; it uploads nothing.

[ ]:
report = client.dependency_report(["numpy>=2", "mypkg", "jax<0.5"])
print(report)

3. Build and upload your wheels

Build a wheel for each package you need to bring (for example with python -m build --wheel, or pip wheel). Because installation happens offline with --no-deps (see below), each wheel must contain everything it needs that is not already baked into the image.

Then upload the wheels for a function with add_wheels(). It accepts paths or globs and only accepts .whl files.

[ ]:
from qiskit_serverless import QiskitFunction

function = QiskitFunction(
    title="my-function",
    entrypoint="function_with_wheels.py",
    working_dir="./source_files/",
)

client.add_wheels(function, ["dist/mypkg-1.0-*.whl"])

4. Install the wheels from your entrypoint

Call install_uploaded_wheels() at the top of your entrypoint, before importing the uploaded packages. It installs every uploaded wheel offline and makes it importable for the rest of the run.

from qiskit_serverless import install_uploaded_wheels, save_result

install_uploaded_wheels()

import mypkg  # now importable

save_result({"mypkg_version": mypkg.__version__})

Under the hood this runs pip install --no-index --no-deps --find-links /function_user_data/wheels --target /tmp/site and prepends the target to sys.path. add_wheels() uploads into that wheels directory, and the helper reads from it. --no-index keeps the install fully offline; --no-deps is required, because otherwise the offline install would try to satisfy packages already baked into the image (numpy, qiskit, …) from your wheelhouse and fail.

Notes and trade-offs

  • Wheels are installed on every execution, which adds start-up time.

  • Because you build the wheels, anything needing compilation or lacking a prebuilt wheel is up to you.

  • This is intended for private or internal packages. If a package would be broadly useful, consider requesting that it be added to the runtime image instead.

[ ]:
function = client.upload(function)
job = function.run()
print(job.result())