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
Metadata
Release files for qhub-commons 1.2.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| qhub_commons-1.2.2.tar.gz | 37.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| qhub_commons-1.2.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 75.3 kB
Release files / qhub_commons-1.2.2.tar.gz
| Download URL | qhub_commons-1.2.2.tar.gz |
|---|---|
| Size | 37.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d296b7da2b9b5b2c178bca6c4fa58c1bb32822d5b4e158d9bbd45df3d1a6d271
|
|
BLAKE2b-256 checksum How to use checksums |
2fd5942d8fa1b1a3b229ca31191263d643fbcbfc17300d9576f4e07025190f27
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is 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}
|
Release files / qhub_commons-1.2.2-py3-none-any.whl
| Download URL | qhub_commons-1.2.2-py3-none-any.whl |
|---|---|
| Size | 38.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b5a78baa6a278fc051f349e9358710e219b9252c82eadf5af57f55418d927bae
|
|
BLAKE2b-256 checksum How to use checksums |
a2f4b7fefe48bf09320d5479a097a3bead98271c241b48f607cd7a0a25dd0c8e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is 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}
|