Set of common utilities and classes to boost development of quantum computing applications using Kipu Quantum Hub.
Project description
qhub-commons
Set of common utilities and classes to boost development of quantum computing applications using Kipu Quantum Hub.
Overview
qhub-commons is a Python library that simplifies the development of quantum computing services on Kipu Quantum Hub.
It provides a runtime system that automatically handles input/output processing, parameter binding, and OpenAPI specification generation from your Python functions.
Key Features
- Zero-Configuration Runtime: Automatically discovers and executes your entrypoint functions
- Automatic Parameter Binding: Maps input files to function parameters using type hints
- Secret Management: Secure handling of sensitive values with automatic environment variable injection
- DataPool Integration: Direct access to mounted data pools for large file processing
- OpenAPI Generation: Automatically generates API specifications from function signatures
- Type Safety: Full support for Pydantic models and Python type hints
Usage Guide
1. Basic Service Function
The simplest way to use qhub-commons is to define a function with type hints:
from pydantic import BaseModel
class InputData(BaseModel):
values: list[float]
def run(data: InputData) -> float:
return sum(data.values)
The runtime will:
- Read input files from the configured directory
- Parse them according to your type hints
- Call your function with the correct parameters
- Write the result to the output directory
2. Working with Secrets
For sensitive values like API tokens, use the SecretValue type:
from typing import Optional
from qhub.commons.secret import SecretValue
def run(api_token: SecretValue, data: InputData, optional_key: Optional[SecretValue] = None) -> dict:
# Access the actual value (single-use only)
token = api_token.unwrap()
# IMPORTANT: unwrap() can only be called once
# Second call will raise ValueError: "Secret is locked and cannot be unwrapped"
# Secrets are automatically redacted in logs
print(api_token) # Output: [redacted]
# Handle optional secrets
if optional_key:
key = optional_key.unwrap()
return {"status": "processed"}
Environment Variable Mapping:
Secrets are automatically loaded from environment variables following these patterns:
api_token→SECRET_API_TOKENibmToken→SECRET_IBM_TOKEN(camelCase → UPPER_SNAKE_CASE)iqm_token→SECRET_IQM_TOKEN(snake_case → UPPER_SNAKE_CASE)
Required vs Optional Secrets:
- Required secrets (e.g.,
api_token: SecretValue): Must have corresponding environment variable or runtime will fail - Optional secrets (e.g.,
api_token: Optional[SecretValue]): Set toNoneif environment variable is missing
Security Features:
- Single-use unwrapping: Once
unwrap()is called, the secret is locked to prevent accidental reuse - Automatic redaction: String representation always shows
[redacted]to prevent logging exposure - JSON serialization: Secrets are serialized to
{"value": "..."}format but remain usable after serialization
Naming Guidelines:
Use generic parameter names to avoid exposing sensitive integration details in OpenAPI specifications:
✅ Good: api_key, auth_token, credentials, quantum_token
❌ Avoid: prod_ibm_quantum_api_key, aws_secret_key_region_us_east_1
3. DataPool Integration
For processing large files from mounted data pools:
from qhub.commons.datapool import DataPool
def run(data: InputData, training_data: DataPool) -> dict:
# List available files
files = training_data.list_files()
# Open and read files
with training_data.open("model.pkl", "rb") as f:
model = pickle.load(f)
return {"files_processed": len(files)}
DataPools are automatically mounted from /var/runtime/datapool/{parameter_name} when you declare a parameter with type DataPool.
4. Runtime Execution
Run your service using the main runtime:
from qhub.commons.runtime.main import main
if __name__ == "__main__":
exit(main())
Configure via environment variables:
ENTRYPOINT: Function to execute (default:user_code.src.program:run)INPUT_DIRECTORY: Input files location (default:/var/runtime/input)OUTPUT_DIRECTORY: Output files location (default:/var/runtime/output)
5. OpenAPI Specification Generation
Generate OpenAPI specs automatically from your function signatures:
from qhub.commons.openapi.generator import generate_openapi
generate_openapi(
entrypoint="my_module:my_function",
title="My Quantum Service",
version="1.0"
)
Or use the Docker command:
docker run -v "$(pwd)/user_code:/workspace" qhub-commons openapi
The generator will:
- Extract parameter schemas from type hints
- Handle Pydantic models, primitives, and complex types
- Generate request/response schemas
- Create a
$secretsobject for SecretValue parameters
Secret Parameters in OpenAPI:
SecretValue parameters are automatically exposed in a special $secrets object in the request body schema:
requestBody:
content:
application/json:
schema:
properties:
# Regular parameters
data:
type: object
# Secret parameters in $secrets object
$secrets:
type: object
description: Secret values to be injected as environment variables
properties:
api_token:
type: string
description: Secret value for parameter 'api_token'
additionalProperties: false
required: [data, $secrets]
The API gateway uses this schema to map the $secrets object properties to environment variables before executing your service.
6. Advanced Type Support
The parameter binding system supports rich type annotations:
from typing import Optional, Dict, List
from datetime import datetime
from uuid import UUID
def run(
data: InputData,
config: Optional[Dict[str, Any]] = None,
timestamps: List[datetime] = [],
job_id: UUID = None
) -> dict:
# All parameters are automatically parsed and validated
return {"processed": True}
Supported types:
- Primitives:
str,int,float,bool - Collections:
List[T],Dict[K, V],Set[T],Tuple[T, ...] - Optional:
Optional[T],Union[X, Y] - Pydantic Models: Full support for
BaseModelwith validation - Special Types:
datetime,date,time,UUID,Decimal,Path,Enum - Platform Types:
DataPool,SecretValue
7. Function Resolution
The entrypoint system uses string-based function references:
from qhub.commons.entrypoint import run_entrypoint
from qhub.commons.reflection import resolve_signature, resolve_function
# Get function signature
signature = resolve_signature("my_module.submodule:my_function")
# Execute with parameters
result = run_entrypoint(
"my_module.submodule:my_function",
{"param1": value1, "param2": value2}
)
Examples
Complete Service Example
from typing import Optional, Dict, Any
from pydantic import BaseModel, Field
from qhub.commons.secret import SecretValue
from qhub.commons.datapool import DataPool
class CircuitParams(BaseModel):
num_qubits: int = Field(ge=1, le=100)
depth: int = Field(ge=1)
shots: int = Field(default=1024)
def run(
circuit: CircuitParams,
backend_token: SecretValue,
training_data: Optional[DataPool] = None,
api_key: Optional[SecretValue] = None
) -> Dict[str, Any]:
"""
Execute quantum circuit with optional training data and API authentication.
Input files:
- circuit.json: Circuit parameters
Environment variables (required):
- SECRET_BACKEND_TOKEN: API token for quantum backend
Environment variables (optional):
- SECRET_API_KEY: Additional API key if needed
Data pools (optional):
- training_data: Mounted at /var/runtime/datapool/training_data
"""
# Use the token securely (single-use unwrap)
token = backend_token.unwrap()
# Handle optional secret
key = api_key.unwrap() if api_key else None
# Process training data if available
files_used = []
if training_data:
files_used = list(training_data.list_files().keys())
# Execute circuit (implementation omitted)
result = execute_circuit(circuit, token, api_key=key)
return {
"result": result,
"training_files": files_used,
"shots": circuit.shots,
"authenticated": key is not None
}
Development
Setup
This project uses a Git submodule. Clone with submodules included:
git clone --recurse-submodules <repo-url>
If you already cloned without submodules, initialize them afterwards:
git submodule update --init --recursive
To update the submodule to the latest commit on its tracked branch:
git submodule update --remote --recursive
Then set up the Python environment:
uv venv
source .venv/bin/activate
uv lock
uv sync
Update dependencies and lock files:
uv sync -U
Run tests
pytest
Export dependencies to requirements files
This is useful to keep the project independent of the
uvtool. Developers can install the dependencies usingpip install -r requirements.txtandpip install -r requirements-dev.txt. Further, they may use a different tool to manage virtual environments.
uv export --format requirements-txt --no-dev --no-emit-project > requirements.txt
uv export --format requirements-txt --only-dev --no-emit-project > requirements-dev.txt
Docker
Build the image:
docker build -t qhub-commons .
Run interactive shell:
docker run -it -v "$(pwd)/user_code:/workspace" qhub-commons
Generate OpenAPI description:
docker run -v "$(pwd)/user_code:/workspace" qhub-commons openapi
You can also use the pre-built image:
docker run -it -v "$(pwd)/user_code:/workspace" registry.gitlab.com/kipu-all/kipuproduct-platform/qhub-commons:latest
License
Apache-2.0 | Copyright 2026-now Kipu Quantum GmbH
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file qhub_commons-1.2.0.tar.gz.
File metadata
- Download URL: qhub_commons-1.2.0.tar.gz
- Upload date:
- Size: 36.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.10.12 {"installer":{"name":"uv","version":"0.10.12","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
933ee3711d80ae6d255d3dd25a0aee9bda12d2446bcbfbde1745f5bae519ea5a
|
|
| MD5 |
e7442abd39b57006137b9441f2a22973
|
|
| BLAKE2b-256 |
b570bc7d50185d30d128939dd7978f266a4db6cf0b2b474cdc5ce9d122da4b37
|
File details
Details for the file qhub_commons-1.2.0-py3-none-any.whl.
File metadata
- Download URL: qhub_commons-1.2.0-py3-none-any.whl
- Upload date:
- Size: 38.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.10.12 {"installer":{"name":"uv","version":"0.10.12","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9e663e2355189f9a5418ed880cc6f23c8a8a0acbf5dcf7fc696471ffbd46dfc0
|
|
| MD5 |
cf50dfe1e28884c00b5877f8ccff28eb
|
|
| BLAKE2b-256 |
52de166aabb7e33d0b297c7c90ee8b65446a727e0cf8f6e53890b9b22781bd1e
|