-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Description
Environment
- Qiskit version: 2.2
- Python version: 2.2.0 (QPY 16)
- Operating system: Any (Linux/macOS/Windows)
What is happening?
In QPY version 16 (Qiskit ≥ 2.2.0), qpy.dump() introduces a circuit offset table that requires seeking back to fill offsets after writing the circuit data. This causes an OSError: Negative seek in write mode when the output stream is a gzip.GzipFile opened in write mode, because gzip only supports forward seeks.
This is probably caused by #14953 .
How can we reproduce the issue?
import gzip
from qiskit import QuantumCircuit, qpy
qc = QuantumCircuit(2)
qc.h(0); qc.h(1)
with gzip.open("circuit.qpy.gz", "wb") as f:
qpy.dump(qc, f)
Error:
OSError: Negative seek in write mode
The qpy.dump()
checks only file_obj.seekable()
to decide whether to use the “fast path” that performs in-place offset table writing. However, gzip.GzipFile
reports seekable() == True
yet does not support backward seeks, triggering the exception.
What should happen?
qpy.dump()
should successfully write QPY v16 data to any binary writable file-like object, including compressed streams like gzip.GzipFile
, without requiring random-access seeking.
Specifically:
-
The function should automatically detect when a stream cannot perform backward seeks (e.g., gzip write mode) and transparently fall back to a buffered approach.
-
Users should be able to do:
import gzip from qiskit import QuantumCircuit, qpy qc = QuantumCircuit(2) qc.h(0) qc.h(1) with gzip.open("circuit.qpy.gz", "wb") as f: qpy.dump(qc, f)
…and expect it to complete without error and produce a valid
.qpy.gz
file readable by:with gzip.open("circuit.qpy.gz", "rb") as f: qpy.load(f)
In short, QPY serialization should be stream-agnostic, working seamlessly with both seekable files (e.g., disk files) and non-seekable or partially seekable streams (e.g., gzip, sockets, pipes).
Any suggestions?
I added a small runtime probe to detect if the stream truly supports backward seeks. If not, fall back to the buffered write path (BytesIO) used for non-seekable streams.