Skip to content

Commit

Permalink
Test missing OpType definitions against pytket
Browse files Browse the repository at this point in the history
  • Loading branch information
aborgna-q committed Apr 5, 2024
1 parent 93e813b commit 9175fbc
Show file tree
Hide file tree
Showing 8 changed files with 148 additions and 6 deletions.
41 changes: 41 additions & 0 deletions .github/workflows/missing-ops.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Detect missing operation definitions

on:
push:
branches:
- main
pull_request:
branches:
- main
workflow_dispatch: {}
schedule:
# 04:00 daily
- cron: '0 4 * * *'

env:
CARGO_TERM_COLOR: always
SCCACHE_GHA_ENABLED: "true"
RUSTC_WRAPPER: "sccache"

jobs:
missing-optypes:
name: Check for missing op type definitions
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: mozilla-actions/sccache-action@v0.0.4
- name: Install stable toolchain
uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy
- name: Install poetry
run: pipx install poetry
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
cache: "poetry"
- name: Update the project dependencies
run: poetry -C tests update
- name: Run the missing op types test
run: poetry -C tests run -- cargo test --test integration -- --ignored missing_optypes
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
/target
Cargo.lock
tests/poetry.lock
25 changes: 20 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,27 @@ categories = ["compilers"]
name = "tket_json_rs"

[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
uuid = { version = "1.4", features = ["serde"] }
pyo3 = { version = "0.21.1", optional = true }
pythonize = { version = "0.21.1", optional = true }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
uuid = { workspace = true, features = ["serde"] }
pyo3 = { workspace = true, optional = true }
pythonize = { workspace = true, optional = true }
strum = { workspace = true, features = ["derive"] }

[dev-dependencies]
pyo3 = { workspace = true }

[features]
pyo3 = ["dep:pyo3", "dep:pythonize"]

[[test]]
name = "integration"
path = "tests/lib.rs"

[workspace.dependencies]
pyo3 = "0.21.1"
pythonize = "0.21.1"
serde = "1.0"
serde_json = "1.0"
strum = "0.26.2"
uuid = "1.4"
15 changes: 15 additions & 0 deletions justfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# List the available commands
help:
@just --list --justfile {{justfile()}}

# Run all the rust tests
test:
cargo test --all-features

# Auto-fix all clippy warnings
fix:
cargo clippy --all-targets --all-features --workspace --fix --allow-staged

# Check for missing optypes
check-optypes:
poetry -C tests run -- cargo test --test integration -- --ignored missing_optypes
3 changes: 2 additions & 1 deletion src/optype.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ use pyo3::prelude::*;
#[cfg(feature = "pyo3")]
use pyo3::{exceptions::PyNotImplementedError, pyclass::CompareOp};
use serde::{Deserialize, Serialize};
use strum::EnumString;

/// Operation types in a quantum circuit.
#[cfg_attr(feature = "pyo3", pyclass(name = "RsOpType"))]
#[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Eq, Hash)]
#[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Eq, Hash, EnumString)]
#[non_exhaustive]
pub enum OpType {
/// Quantum input node of the circuit
Expand Down
3 changes: 3 additions & 0 deletions tests/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
//! Integration tests.
pub mod missing_optypes;
48 changes: 48 additions & 0 deletions tests/missing_optypes.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//! Integration test to detect missing optypes in the optype module.
//!
//! Requires the `pyo3` feature to be enabled.
use std::str::FromStr;

use pyo3::prelude::*;
use pyo3::types::PyDict;
use tket_json_rs::OpType;

#[test]
#[ignore = "Requires a python environment with `pytket` installed."]
fn missing_optypes() -> PyResult<()> {
println!("Checking missing optypes");

pyo3::prepare_freethreaded_python();
Python::with_gil(|py| {
let Ok(pytket) = PyModule::import_bound(py, "pytket") else {
panic!("Failed to import `pytket`. Make sure the python library is installed.");
};
let py_enum = pytket.getattr("OpType")?;
let py_members = py_enum.getattr("__members__")?;
let py_members = py_members.downcast::<PyDict>()?;

let missing: Vec<String> = py_members
.into_iter()
.filter_map(|(name, _class)| {
let name = name.extract::<String>().unwrap();
match OpType::from_str(&name) {
Err(_) => Some(name),
Ok(_) => None,
}
})
.collect();

if !missing.is_empty() {
let msg = "\nMissing optypes in `tket_json_rs`:\n".to_string();
let msg = missing
.into_iter()
.fold(msg, |msg, s| msg + " - " + &s + "\n");
let msg =
msg + "Please add them to the `OpType` enum in `tket_json_rs/src/optype.rs`.\n";
panic!("{msg}");
}

Ok(())
})
}
18 changes: 18 additions & 0 deletions tests/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[tool.poetry]
description = "tket-json-rs integration tests."
name = "tket-json-rs-tests"
version = "0.0.0"
authors = ["TKET development team <tket-support@cambridgequantum.com>"]
package-mode = false

[tool.poetry.group.main.dependencies]
python = "^3.10"
# Always use the latest pytket version
pytket = "*"

[tool.poetry.group.dev.dependencies]
pytest = "^8.1.1"

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

0 comments on commit 9175fbc

Please sign in to comment.