Skip to main content

localqpu

A local emulator of the IBM Quantum Platform API, built for testing. Like a payment provider's "test mode", it lets you test code that calls a quantum cloud without queues, without cost, and with any failure you want to simulate.

localqpu does not verify that quantum results are correct. It verifies the code around the quantum API call: submission, waiting, retries, result parsing, and error handling.

Install and run

pip install localqpu      # https://pypi.org/project/localqpu/
localqpu start            # http://127.0.0.1:8787

Docker

Multi-arch images (amd64, arm64) are published to GHCR for every release from v0.2.0 on:

docker run -p 127.0.0.1:8787:8787 ghcr.io/ictechgy/localqpu:latest

The image runs as an unprivileged user and has a HEALTHCHECK on /_localqpu/health, so it works as a CI service container — handy when the code under test is not Python:

# GitHub Actions
services:
  localqpu:
    image: ghcr.io/ictechgy/localqpu:latest
    ports: ["8787:8787"]

Connect existing Qiskit code

import localqpu

service = localqpu.connect(port=8787)  # use this instead of QiskitRuntimeService(...)
backend = service.least_busy()

⚠️ Always use localqpu.connect(). In qiskit-ibm-runtime the runtime authentication endpoint is hard-coded to iam.cloud.ibm.com and can only be changed through the IAM_URL environment variable. If you configure the client by hand and miss it, the client sends your key to the real IBM Cloud. connect() sets IAM_URL and routes both HTTP and HTTPS through localqpu, so any leaking HTTPS request is blocked. Blocked attempts are counted in blocked_connect_requests on GET /_localqpu/health.

Note that connect() changes process-wide environment variables: it sets IAM_URL and appends localqpu.test to NO_PROXY/no_proxy (so that HTTP_PROXY settings cannot redirect localqpu traffic to a corporate proxy). Run tests that talk to the real IBM Cloud in a separate process.

AWS Braket (experimental)

Install the extra (Python 3.11+, because the Braket packages require it) and point the Amazon Braket SDK at localqpu:

pip install 'localqpu[braket]'
import localqpu
from braket.aws import AwsDevice
from braket.circuits import Circuit

session = localqpu.connect_braket(port=8787)
device = AwsDevice("arn:aws:braket:::device/quantum-simulator/amazon/sv1", aws_session=session)
counts = device.run(Circuit().h(0).cnot(0, 1), shots=100).result().measurement_counts
  • Emulates the SV1 simulator only, for gate-model OpenQASM tasks: create/get/cancel quantum tasks, get/search devices, and the S3 results.json download. Tasks share the job manager with IBM jobs, so failure scenarios (next_jobs, failures, queue) apply to them too.
  • ⚠️ connect_braket() changes process-wide environment variables: it points AWS_ENDPOINT_URL (and the S3/Braket/STS-specific variants) at localqpu. The Braket SDK copies sessions internally and the copies lose explicitly passed clients — without this, result downloads went to the real AWS S3. With it, any AWS call the SDK makes lands on localqpu (unknown ones fail with 501) instead of leaking.
  • Qubits are limited by --max-sim-qubits (all declared qubits count, since entanglement is not analysed for Braket programs). There is no stub mode and no seed control for Braket tasks.

Use with pytest

The fixtures are registered automatically once the package is installed.

def test_retry_on_failure(localqpu_service, localqpu_control):
    localqpu_control.set_scenario({"next_jobs": [{"outcome": "failed", "reason": "calibrating"}]})
    ...
Fixture Description
localqpu_server A server on a free port for the whole test session
localqpu_control Change scenarios, inspect jobs, reset state. Reset before and after each test
localqpu_service A connected QiskitRuntimeService

Failure scenarios

Use localqpu start --scenario scenario.json or localqpu_control.set_scenario({...}).

{
  "seed": 42,
  "queue": { "delay_seconds": 0, "polls_before_running": 1 },
  "failures": { "rate": 0.0, "reason": "Simulated failure", "reason_code": 9999 },
  "next_jobs": [
    { "outcome": "failed", "reason": "QPU calibration in progress", "reason_code": 1517 },
    { "outcome": "cancelled" }
  ],
  "backends": { "ibm_brisbane": { "status": "offline", "queue_length": 120 } },
  "usage": { "limit_seconds": 600, "consumed_seconds": 600 },
  "auth": { "reject_tokens": false },
  "noise": false
}
Scenario What the client sees
next_jobs failure RuntimeJobFailureError (with the reason)
next_jobs cancellation RuntimeInvalidStateError
Failure or cancellation with reason_code: 1305 RuntimeJobMaxTimeoutError (the client treats 1305 as a max-time error and turns a cancelled job with this code into an error)
job.cancel() from your code CANCELLED; localqpu records reason_code: 9001
Backend offline Excluded from least_busy(); submitted jobs stay QUEUED until it is back online
Backend paused A "currently has a status of paused" warning, then normal processing
Usage limit reached A warning, then submission fails with IBMRuntimeError (403)
auth.reject_tokens InvalidAccountError when creating the service
noise: true Results include the chip's gate and readout errors (noise model built from the same calibration snapshot, e.g. ~6% 01/10 on a Bell pair on ibm_brisbane)

QiskitRuntimeService caches the backend list after the first least_busy()/backends() call, exactly as it does against IBM. After changing backend status in a scenario, create a new service (the localqpu_service fixture gives you a fresh one per test).

Control API

Method and path Purpose
GET /_localqpu/health Status, backends, blocked CONNECT count
GET/PUT /_localqpu/scenario Read or replace the scenario
POST /_localqpu/reset Reset jobs, scenario, and stats
GET /_localqpu/jobs Summary of submitted jobs

Supported primitives

Qiskit primitive Program Notes
SamplerV2 (legacy) sampler Exact, including mid-circuit measurements and if_test
executor_sampler.Sampler executor (schema v2.0) Exact
EstimatorV2 (legacy) estimator Exact expectation values when no precision is requested; with a precision, Aer adds Gaussian noise of that size
executor_estimator.Estimator executor (schema v2.0) Expectation values are computed by the client from sampled measurements

All of them also work inside Session(...) and Batch(...).

Simulation size

Circuits arrive laid out on the full chip (e.g. 127 qubits), but what makes simulation expensive is entanglement, not width. localqpu therefore limits the number of entangled qubits — qubits touched by multi-qubit gates — with --max-sim-qubits (default 24), and simulates exactly with Aer's matrix-product-state method, which is cheap for qubits that only get single-qubit gates or measurements. Above the limit you get a stub instead of an error: sampler and estimator return shape-correct random values (metadata["localqpu_stub"]), and executor runs an approximate simulation with a capped MPS bond dimension, so the result structure is exact but the values are not meaningful. Stub jobs are flagged with is_stub: true in GET /_localqpu/jobs and logged by the server.

Limitations

  • IBM Quantum Platform, plus AWS Braket SV1 as an experimental extra. Qiskit Functions are not supported yet.
  • Session and Batch are supported (create, status, close(), cancel(), from_id), but session timeouts (max_time, interactive timeout) are not emulated.
  • Noiseless by default; set "noise": true in the scenario to add the chip's noise model.
  • Jobs are kept in memory only and are lost when the server restarts.
  • A running simulation cannot be interrupted. POST /_localqpu/reset (used by the pytest fixtures between tests) discards its result and starts a fresh worker pool, so later jobs are not blocked, but the old computation keeps using CPU until it finishes.
  • Failure reasons use localqpu codes: 9000 for localqpu-side failures (invalid input, simulation limits) and 9001 for user cancellation.

Release files for localqpu 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for localqpu 0.2.0
File Size Uploaded
localqpu-0.2.0.tar.gz 236.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for localqpu 0.2.0
File Interpreter ABI Platform
localqpu-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 303.0 kB

Release files / localqpu-0.2.0.tar.gz

Download URL localqpu-0.2.0.tar.gz
Size 236.1 kB
Tags Source
SHA-256 checksum
How to use checksums
0059db194c1f439516e9b93b39fa4f9d1c27fb25df78aeba1cb75d11843421ff
BLAKE2b-256 checksum
How to use checksums
26afbf53c95330b28973cb67f42e0423438dda8c1af399c92addad58e3996e5c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 27, 2026.

Transparency log

Release files / localqpu-0.2.0-py3-none-any.whl

Download URL localqpu-0.2.0-py3-none-any.whl
Size 66.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
06e0aeae53528aebd7d49b04cf7ec5da0b62fc8d0adad3c322289203639887f2
BLAKE2b-256 checksum
How to use checksums
0f77cc6336b7e68a950dc265decf9f9276aae577384ff52f53ab417de1466e1a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 27, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page