Skip to content

Commit

Permalink
Avoid exporting incorrect PyInit_* symbols (#12891)
Browse files Browse the repository at this point in the history
Using the `#[pymodule]` derive macro in PyO3 0.21 always causes a
`PyInit_*` symbol with a matching name to be exported in the output
`cdylib`.  This is required for the top-level module, in order for
Python to import it---it needs to know which symbol in a shared library
file it should call---but submodules must be manually initialised, so do
not need it.  Including it is typically harmless (and something we've
been doing for a long time), but it is technically against the coding
rules for CPython extensions[^1].

Recent versions of `abi3audit` (0.0.11+) have tightened their symbol
checkers to better match the CPython guidelines, which causes our wheels
to be rejected by their audits.  This is, in theory, not a break of abi3
because CPython could never introduce an API-elvel `PyInit_*` function
themselves without causing problems, so there ought to be no problems
for our users, even with future Python versions. That said, we still
want to pass the audit, because the coding guidelines are useful.

This commit is not the cleanest way of doing things.  PyO3 0.22 includes
a `#[pymodule(submodule)]` option on the attribute macro, which lets us
use all the standard code generation while suppressing the unnecessary
`PyInit_*` symbol.  When we are ready to move to PyO3 0.22, we probably
want to revert this commit to switch to that form.

[^1]: https://docs.python.org/3/c-api/intro.html
  • Loading branch information
jakelishman authored Aug 3, 2024
1 parent 89069bb commit e447dc7
Show file tree
Hide file tree
Showing 21 changed files with 32 additions and 42 deletions.
1 change: 0 additions & 1 deletion crates/accelerate/src/convert_2q_block_matrix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ pub fn change_basis(matrix: ArrayView2<Complex64>) -> Array2<Complex64> {
trans_matrix
}

#[pymodule]
pub fn convert_2q_block_matrix(m: &Bound<PyModule>) -> PyResult<()> {
m.add_wrapped(wrap_pyfunction!(blocks_to_matrix))?;
Ok(())
Expand Down
1 change: 0 additions & 1 deletion crates/accelerate/src/dense_layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,6 @@ pub fn best_subset(
))
}

#[pymodule]
pub fn dense_layout(m: &Bound<PyModule>) -> PyResult<()> {
m.add_wrapped(wrap_pyfunction!(best_subset))?;
Ok(())
Expand Down
1 change: 0 additions & 1 deletion crates/accelerate/src/error_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,6 @@ impl ErrorMap {
}
}

#[pymodule]
pub fn error_map(m: &Bound<PyModule>) -> PyResult<()> {
m.add_class::<ErrorMap>()?;
Ok(())
Expand Down
1 change: 0 additions & 1 deletion crates/accelerate/src/euler_one_qubit_decomposer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -883,7 +883,6 @@ pub fn params_zxz(unitary: PyReadonlyArray2<Complex64>) -> [f64; 4] {
params_zxz_inner(mat)
}

#[pymodule]
pub fn euler_one_qubit_decomposer(m: &Bound<PyModule>) -> PyResult<()> {
m.add_wrapped(wrap_pyfunction!(params_zyz))?;
m.add_wrapped(wrap_pyfunction!(params_xyx))?;
Expand Down
1 change: 0 additions & 1 deletion crates/accelerate/src/isometry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,6 @@ fn b(k: usize, s: usize) -> usize {
k - (a(k, s) * 2_usize.pow(s as u32))
}

#[pymodule]
pub fn isometry(m: &Bound<PyModule>) -> PyResult<()> {
m.add_wrapped(wrap_pyfunction!(diag_is_identity_up_to_global_phase))?;
m.add_wrapped(wrap_pyfunction!(find_squs_for_disentangling))?;
Expand Down
1 change: 0 additions & 1 deletion crates/accelerate/src/nlayout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,6 @@ impl NLayout {
}
}

#[pymodule]
pub fn nlayout(m: &Bound<PyModule>) -> PyResult<()> {
m.add_class::<NLayout>()?;
Ok(())
Expand Down
1 change: 0 additions & 1 deletion crates/accelerate/src/optimize_1q_gates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@ pub fn compose_u3_rust(
out_angles
}

#[pymodule]
pub fn optimize_1q_gates(m: &Bound<PyModule>) -> PyResult<()> {
m.add_wrapped(wrap_pyfunction!(compose_u3_rust))?;
Ok(())
Expand Down
1 change: 0 additions & 1 deletion crates/accelerate/src/pauli_exp_val.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,6 @@ pub fn density_expval_pauli_with_x(
}
}

#[pymodule]
pub fn pauli_expval(m: &Bound<PyModule>) -> PyResult<()> {
m.add_wrapped(wrap_pyfunction!(expval_pauli_no_x))?;
m.add_wrapped(wrap_pyfunction!(expval_pauli_with_x))?;
Expand Down
1 change: 0 additions & 1 deletion crates/accelerate/src/results/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ pub mod marginalization;
use pyo3::prelude::*;
use pyo3::wrap_pyfunction;

#[pymodule]
pub fn results(m: &Bound<PyModule>) -> PyResult<()> {
m.add_wrapped(wrap_pyfunction!(marginalization::marginal_counts))?;
m.add_wrapped(wrap_pyfunction!(marginalization::marginal_distribution))?;
Expand Down
1 change: 0 additions & 1 deletion crates/accelerate/src/sabre/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,6 @@ impl BlockResult {
}
}

#[pymodule]
pub fn sabre(m: &Bound<PyModule>) -> PyResult<()> {
m.add_wrapped(wrap_pyfunction!(route::sabre_routing))?;
m.add_wrapped(wrap_pyfunction!(layout::sabre_layout_and_routing))?;
Expand Down
1 change: 0 additions & 1 deletion crates/accelerate/src/sampled_exp_val.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ pub fn sampled_expval_complex(
Ok(out.re)
}

#[pymodule]
pub fn sampled_exp_val(m: &Bound<PyModule>) -> PyResult<()> {
m.add_wrapped(wrap_pyfunction!(sampled_expval_float))?;
m.add_wrapped(wrap_pyfunction!(sampled_expval_complex))?;
Expand Down
1 change: 0 additions & 1 deletion crates/accelerate/src/sparse_pauli_op.rs
Original file line number Diff line number Diff line change
Expand Up @@ -816,7 +816,6 @@ impl_to_matrix_sparse!(
u64
);

#[pymodule]
pub fn sparse_pauli_op(m: &Bound<PyModule>) -> PyResult<()> {
m.add_wrapped(wrap_pyfunction!(unordered_unique))?;
m.add_wrapped(wrap_pyfunction!(decompose_dense))?;
Expand Down
1 change: 0 additions & 1 deletion crates/accelerate/src/stochastic_swap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,6 @@ pub fn swap_trials(
Ok((best_edges, best_layout, best_depth))
}

#[pymodule]
pub fn stochastic_swap(m: &Bound<PyModule>) -> PyResult<()> {
m.add_wrapped(wrap_pyfunction!(swap_trials))?;
m.add_class::<EdgeCollection>()?;
Expand Down
1 change: 0 additions & 1 deletion crates/accelerate/src/two_qubit_decompose.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2042,7 +2042,6 @@ impl TwoQubitBasisDecomposer {
}
}

#[pymodule]
pub fn two_qubit_decompose(m: &Bound<PyModule>) -> PyResult<()> {
m.add_wrapped(wrap_pyfunction!(_num_basis_gates))?;
m.add_class::<TwoQubitGateSequence>()?;
Expand Down
1 change: 0 additions & 1 deletion crates/accelerate/src/uc_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,6 @@ pub fn dec_ucg_help(
)
}

#[pymodule]
pub fn uc_gate(m: &Bound<PyModule>) -> PyResult<()> {
m.add_wrapped(wrap_pyfunction!(dec_ucg_help))?;
Ok(())
Expand Down
1 change: 0 additions & 1 deletion crates/accelerate/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ pub fn eigenvalues(py: Python, unitary: PyReadonlyArray2<Complex<f64>>) -> PyObj
.into()
}

#[pymodule]
pub fn utils(m: &Bound<PyModule>) -> PyResult<()> {
m.add_wrapped(wrap_pyfunction!(eigenvalues))?;
Ok(())
Expand Down
1 change: 0 additions & 1 deletion crates/accelerate/src/vf2_layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,6 @@ pub fn score_layout(
Ok(1. - fidelity)
}

#[pymodule]
pub fn vf2_layout(m: &Bound<PyModule>) -> PyResult<()> {
m.add_wrapped(wrap_pyfunction!(score_layout))?;
m.add_class::<EdgeList>()?;
Expand Down
3 changes: 1 addition & 2 deletions crates/circuit/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ pub enum SliceOrInt<'a> {
Slice(Bound<'a, PySlice>),
}

#[pymodule]
pub fn circuit(m: Bound<PyModule>) -> PyResult<()> {
pub fn circuit(m: &Bound<PyModule>) -> PyResult<()> {
m.add_class::<circuit_data::CircuitData>()?;
m.add_class::<circuit_instruction::CircuitInstruction>()?;
Ok(())
Expand Down
52 changes: 31 additions & 21 deletions crates/pyext/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
// that they have been altered from the originals.

use pyo3::prelude::*;
use pyo3::wrap_pymodule;

use qiskit_accelerate::{
convert_2q_block_matrix::convert_2q_block_matrix, dense_layout::dense_layout,
Expand All @@ -23,27 +22,38 @@ use qiskit_accelerate::{
vf2_layout::vf2_layout,
};

#[inline(always)]
#[doc(hidden)]
fn add_submodule<F>(m: &Bound<PyModule>, constructor: F, name: &str) -> PyResult<()>
where
F: FnOnce(&Bound<PyModule>) -> PyResult<()>,
{
let new_mod = PyModule::new_bound(m.py(), name)?;
constructor(&new_mod)?;
m.add_submodule(&new_mod)
}

#[pymodule]
fn _accelerate(m: &Bound<PyModule>) -> PyResult<()> {
m.add_wrapped(wrap_pymodule!(qiskit_circuit::circuit))?;
m.add_wrapped(wrap_pymodule!(qiskit_qasm2::qasm2))?;
m.add_wrapped(wrap_pymodule!(qiskit_qasm3::qasm3))?;
m.add_wrapped(wrap_pymodule!(convert_2q_block_matrix))?;
m.add_wrapped(wrap_pymodule!(dense_layout))?;
m.add_wrapped(wrap_pymodule!(error_map))?;
m.add_wrapped(wrap_pymodule!(euler_one_qubit_decomposer))?;
m.add_wrapped(wrap_pymodule!(isometry))?;
m.add_wrapped(wrap_pymodule!(nlayout))?;
m.add_wrapped(wrap_pymodule!(optimize_1q_gates))?;
m.add_wrapped(wrap_pymodule!(pauli_expval))?;
m.add_wrapped(wrap_pymodule!(results))?;
m.add_wrapped(wrap_pymodule!(sabre))?;
m.add_wrapped(wrap_pymodule!(sampled_exp_val))?;
m.add_wrapped(wrap_pymodule!(sparse_pauli_op))?;
m.add_wrapped(wrap_pymodule!(stochastic_swap))?;
m.add_wrapped(wrap_pymodule!(two_qubit_decompose))?;
m.add_wrapped(wrap_pymodule!(uc_gate))?;
m.add_wrapped(wrap_pymodule!(utils))?;
m.add_wrapped(wrap_pymodule!(vf2_layout))?;
add_submodule(m, qiskit_circuit::circuit, "circuit")?;
add_submodule(m, qiskit_qasm2::qasm2, "qasm2")?;
add_submodule(m, qiskit_qasm3::qasm3, "qasm3")?;
add_submodule(m, convert_2q_block_matrix, "convert_2q_block_matrix")?;
add_submodule(m, dense_layout, "dense_layout")?;
add_submodule(m, error_map, "error_map")?;
add_submodule(m, euler_one_qubit_decomposer, "euler_one_qubit_decomposer")?;
add_submodule(m, isometry, "isometry")?;
add_submodule(m, nlayout, "nlayout")?;
add_submodule(m, optimize_1q_gates, "optimize_1q_gates")?;
add_submodule(m, pauli_expval, "pauli_expval")?;
add_submodule(m, results, "results")?;
add_submodule(m, sabre, "sabre")?;
add_submodule(m, sampled_exp_val, "sampled_exp_val")?;
add_submodule(m, sparse_pauli_op, "sparse_pauli_op")?;
add_submodule(m, stochastic_swap, "stochastic_swap")?;
add_submodule(m, two_qubit_decompose, "two_qubit_decompose")?;
add_submodule(m, uc_gate, "uc_gate")?;
add_submodule(m, utils, "utils")?;
add_submodule(m, vf2_layout, "vf2_layout")?;
Ok(())
}
1 change: 0 additions & 1 deletion crates/qasm2/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,6 @@ fn bytecode_from_file(
/// An interface to the Rust components of the parser stack, and the types it uses to represent the
/// output. The principal entry points for Python are :func:`bytecode_from_string` and
/// :func:`bytecode_from_file`, which produce iterables of :class:`Bytecode` objects.
#[pymodule]
pub fn qasm2(module: &Bound<PyModule>) -> PyResult<()> {
module.add_class::<bytecode::OpCode>()?;
module.add_class::<bytecode::UnaryOpCode>()?;
Expand Down
1 change: 0 additions & 1 deletion crates/qasm3/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,6 @@ pub fn load(

/// Internal module supplying the OpenQASM 3 import capabilities. The entries in it should largely
/// be re-exposed directly to public Python space.
#[pymodule]
pub fn qasm3(module: &Bound<PyModule>) -> PyResult<()> {
module.add_function(wrap_pyfunction!(loads, module)?)?;
module.add_function(wrap_pyfunction!(load, module)?)?;
Expand Down

0 comments on commit e447dc7

Please sign in to comment.