Skip to content

NativeQuilMetadata exposes no attribute getters in Python #593

Description

@ryanhill1

CompilationResult.native_quil_metadata is readable, but nothing on the object it returns is:

>>> from qcs_sdk.compiler.quilc import NativeQuilMetadata
>>> m = NativeQuilMetadata([9, 0, 1, 2], 3, 4, 1, 0.5, 0.99, 2, 1.5)
>>> [a for a in dir(m) if not a.startswith("_")]
[]
>>> m.final_rewiring
AttributeError: 'qcs_sdk.compiler.quilc.NativeQuilMetadata' object has no attribute 'final_rewiring'

Verified on qcs-sdk-python 0.26.3 (latest) and 0.26.1, and still the case on main: quilc.pyi declares only __eq__, __getnewargs__, __new__ and __repr__ for the class.

It looks like an omission

In crates/lib/src/compiler/quilc.rs#L302, NativeQuilMetadata is the only pyclass in the module that has pub fields and does not pass get_all:

pyclass get_all field visibility
CompilationResult, PauliTerm, and 5 others yes pub
CompilerOpts no pub(crate)
TargetDevice no private
NativeQuilMetadata no pub

So the two classes that legitimately hide their fields do so by keeping them non-public, while this one declares all eight fields pub and then exposes none of them.

Why it's worth fixing

final_rewiring is the only record of how quilc relabelled logical qubits onto physical ones. Anything expressed in physical qubits has to be interpreted against it — Quil-T especially, since DELAY 0 0.0005 and frame references address physical qubits, and reasoning about a compiled program without the mapping silently targets the wrong qubit rather than failing.

The only route today is __getnewargs__()[0]. It does return a typed list[int], so this isn't blocking, but it's the pickle protocol rather than an accessor: positional, undocumented, free to change, and it yields None instead of [] for an empty rewiring. __repr__ is the alternative, which means parsing Rust Debug output.

Suggested fix

 #[cfg_attr(
     feature = "python",
-    pyo3::pyclass(module = "qcs_sdk.compiler.quilc", eq)
+    pyo3::pyclass(module = "qcs_sdk.compiler.quilc", eq, get_all)
 )]
 pub struct NativeQuilMetadata {

Sibling classes also pass frozen; I've left it out here since it's a semantic change beyond adding getters, but it would match the module if you want it.

Happy to open a PR.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions