From da31e1f2bbdb5fdd658cae24b93144463c33ce81 Mon Sep 17 00:00:00 2001 From: Agustin Borgna Date: Wed, 13 Sep 2023 15:44:27 +0100 Subject: [PATCH 1/4] Add a custom python error for `ValidationError` --- src/hugr/validate.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/hugr/validate.rs b/src/hugr/validate.rs index 9db0a4f7b..ebb9a715b 100644 --- a/src/hugr/validate.rs +++ b/src/hugr/validate.rs @@ -10,7 +10,7 @@ use portgraph::{LinkView, PortView}; use thiserror::Error; #[cfg(feature = "pyo3")] -use pyo3::prelude::*; +use pyo3::{create_exception, exceptions::PyException, prelude::*}; use crate::extension::SignatureError; use crate::extension::{ @@ -636,11 +636,18 @@ pub enum ValidationError { SignatureError { node: Node, cause: SignatureError }, } +#[cfg(feature = "pyo3")] +create_exception!( + pyrs, + PyValidationError, + PyException, + "Errors that can occur while validating a Hugr" +); + #[cfg(feature = "pyo3")] impl From for PyErr { fn from(err: ValidationError) -> Self { - // We may want to define more specific python-level errors at some point. - PyErr::new::(err.to_string()) + PyValidationError::new_err(err.to_string()) } } From ab36aa9e805d5f8c22e274ba5f3b58437fa2ca24 Mon Sep 17 00:00:00 2001 From: Agustin Borgna Date: Wed, 13 Sep 2023 16:06:00 +0100 Subject: [PATCH 2/4] feat: Define some pyo3 errors, wrap EdgeKind --- src/builder.rs | 13 ++++++++++--- src/hugr.rs | 13 ++++++++++--- src/hugr/serialize.rs | 12 ++++++++++-- src/types.rs | 12 +++++++++++- src/types/type_row.rs | 5 ++++- 5 files changed, 45 insertions(+), 10 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 0f85bd1ac..00280dd90 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -3,7 +3,7 @@ use thiserror::Error; #[cfg(feature = "pyo3")] -use pyo3::prelude::*; +use pyo3::{create_exception, exceptions::PyException, prelude::*}; use crate::hugr::{HugrError, Node, ValidationError, Wire}; use crate::ops::handle::{BasicBlockID, CfgID, ConditionalID, DfgID, FuncID, TailLoopID}; @@ -78,11 +78,18 @@ pub enum BuildError { CircuitError(#[from] circuit::CircuitBuildError), } +#[cfg(feature = "pyo3")] +create_exception!( + pyrs, + PyBuildError, + PyException, + "Errors that can occur while building a Hugr" +); + #[cfg(feature = "pyo3")] impl From for PyErr { fn from(err: BuildError) -> Self { - // We may want to define more specific python-level errors at some point. - PyErr::new::(err.to_string()) + PyBuildError::new_err(err.to_string()) } } diff --git a/src/hugr.rs b/src/hugr.rs index 648383562..5214a1b9e 100644 --- a/src/hugr.rs +++ b/src/hugr.rs @@ -23,7 +23,7 @@ use portgraph::{Hierarchy, NodeIndex, PortMut, UnmanagedDenseMap}; use thiserror::Error; #[cfg(feature = "pyo3")] -use pyo3::prelude::*; +use pyo3::{create_exception, exceptions::PyException, prelude::*}; pub use self::views::HugrView; use crate::extension::{ @@ -463,11 +463,18 @@ pub enum HugrError { InvalidNode(Node), } +#[cfg(feature = "pyo3")] +create_exception!( + pyrs, + PyHugrError, + PyException, + "Errors that can occur while manipulating a Hugr" +); + #[cfg(feature = "pyo3")] impl From for PyErr { fn from(err: HugrError) -> Self { - // We may want to define more specific python-level errors at some point. - PyErr::new::(err.to_string()) + PyHugrError::new_err(err.to_string()) } } diff --git a/src/hugr/serialize.rs b/src/hugr/serialize.rs index c75afa2af..02dbaeb97 100644 --- a/src/hugr/serialize.rs +++ b/src/hugr/serialize.rs @@ -6,7 +6,7 @@ use std::collections::HashMap; use thiserror::Error; #[cfg(feature = "pyo3")] -use pyo3::prelude::*; +use pyo3::{create_exception, exceptions::PyException, prelude::*}; use crate::extension::ExtensionSet; use crate::hugr::{Hugr, NodeType}; @@ -89,10 +89,18 @@ pub enum HUGRSerializationError { FirstNodeNotRoot(Node), } +#[cfg(feature = "pyo3")] +create_exception!( + pyrs, + PyHUGRSerializationError, + PyException, + "Errors that can occur while serializing a Hugr" +); + #[cfg(feature = "pyo3")] impl From for PyErr { fn from(err: HUGRSerializationError) -> Self { - PyErr::new::(err.to_string()) + PyHUGRSerializationError::new_err(err.to_string()) } } diff --git a/src/types.rs b/src/types.rs index 21688d936..2d927cd55 100644 --- a/src/types.rs +++ b/src/types.rs @@ -13,6 +13,7 @@ pub use custom::CustomType; pub use signature::{FunctionType, Signature, SignatureDescription}; pub use type_row::TypeRow; +use derive_more::{From, Into}; use itertools::FoldWhile::{Continue, Done}; use itertools::Itertools; use serde::{Deserialize, Serialize}; @@ -24,8 +25,10 @@ use std::fmt::Debug; use self::primitive::PrimType; +#[cfg(feature = "pyo3")] +use pyo3::prelude::*; + /// The kinds of edges in a HUGR, excluding Hierarchy. -//#[cfg_attr(feature = "pyo3", pyclass)] # TODO: Manually derive pyclass with non-unit variants #[derive(Clone, PartialEq, Eq, Debug, serde::Serialize, serde::Deserialize)] #[non_exhaustive] pub enum EdgeKind { @@ -46,6 +49,12 @@ impl EdgeKind { } } +/// Python representation for [`EdgeKind`], the kinds of edges in a HUGR. +#[cfg_attr(feature = "pyo3", pyclass)] +#[repr(transparent)] +#[derive(Clone, PartialEq, Eq, Debug, From, Into)] +pub struct PyEdgeKind(EdgeKind); + #[derive( Copy, Default, Clone, PartialEq, Eq, Hash, Debug, derive_more::Display, Serialize, Deserialize, )] @@ -167,6 +176,7 @@ impl TypeEnum { )] #[display(fmt = "{}", "_0")] #[serde(into = "serialize::SerSimpleType", from = "serialize::SerSimpleType")] +#[cfg_attr(feature = "pyo3", pyclass)] /// A HUGR type - the valid types of [EdgeKind::Value] and [EdgeKind::Static] edges. /// Such an edge is valid if the ports on either end agree on the [Type]. /// Types have an optional [TypeBound] which places limits on the valid diff --git a/src/types/type_row.rs b/src/types/type_row.rs index 055a5ac6d..bedb6750c 100644 --- a/src/types/type_row.rs +++ b/src/types/type_row.rs @@ -11,9 +11,12 @@ use super::Type; use crate::utils::display_list; use delegate::delegate; +#[cfg(feature = "pyo3")] +use pyo3::prelude::*; + /// List of types, used for function signatures. #[derive(Clone, PartialEq, Eq, Debug, serde::Serialize, serde::Deserialize)] -//#[cfg_attr(feature = "pyo3", pyclass)] +#[cfg_attr(feature = "pyo3", pyclass)] #[non_exhaustive] #[serde(transparent)] pub struct TypeRow { From 660fef6e001d159e4ba4b917fa41869e7ca98599 Mon Sep 17 00:00:00 2001 From: Agustin Borgna Date: Wed, 13 Sep 2023 16:17:49 +0100 Subject: [PATCH 3/4] Pyerror for InvalidReplacement --- src/hugr/views/sibling_subgraph.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/hugr/views/sibling_subgraph.rs b/src/hugr/views/sibling_subgraph.rs index a48ca2978..7bfc69997 100644 --- a/src/hugr/views/sibling_subgraph.rs +++ b/src/hugr/views/sibling_subgraph.rs @@ -26,6 +26,9 @@ use crate::{ use super::HugrView; +#[cfg(feature = "pyo3")] +use pyo3::{create_exception, exceptions::PyException, prelude::*}; + /// A non-empty convex subgraph of a HUGR sibling graph. /// /// A HUGR region in which all nodes share the same parent. Unlike @@ -536,6 +539,21 @@ pub enum InvalidReplacement { NonConvexSubgraph, } +#[cfg(feature = "pyo3")] +create_exception!( + pyrs, + PyInvalidReplacementError, + PyException, + "Errors that can occur while constructing a SimpleReplacement" +); + +#[cfg(feature = "pyo3")] +impl From for PyErr { + fn from(err: InvalidReplacement) -> Self { + PyInvalidReplacementError::new_err(err.to_string()) + } +} + /// Errors that can occur while constructing a [`SiblingSubgraph`]. #[derive(Debug, Clone, PartialEq, Eq, Error)] pub enum InvalidSubgraph { From c48882e997f3b69214ebe5b7690107f93ba7bb1d Mon Sep 17 00:00:00 2001 From: Agustin Borgna Date: Wed, 13 Sep 2023 17:07:45 +0100 Subject: [PATCH 4/4] Do explicit imports instead of `pyo3::prelude::*` --- src/builder.rs | 2 +- src/hugr.rs | 2 +- src/hugr/serialize.rs | 2 +- src/hugr/validate.rs | 2 +- src/hugr/views/sibling_subgraph.rs | 2 +- src/std_extensions/rotation.rs | 2 +- src/types.rs | 2 +- src/types/signature.rs | 2 +- src/types/type_row.rs | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 00280dd90..c8c0cdc55 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -3,7 +3,7 @@ use thiserror::Error; #[cfg(feature = "pyo3")] -use pyo3::{create_exception, exceptions::PyException, prelude::*}; +use pyo3::{create_exception, exceptions::PyException, PyErr}; use crate::hugr::{HugrError, Node, ValidationError, Wire}; use crate::ops::handle::{BasicBlockID, CfgID, ConditionalID, DfgID, FuncID, TailLoopID}; diff --git a/src/hugr.rs b/src/hugr.rs index 5214a1b9e..831f16298 100644 --- a/src/hugr.rs +++ b/src/hugr.rs @@ -23,7 +23,7 @@ use portgraph::{Hierarchy, NodeIndex, PortMut, UnmanagedDenseMap}; use thiserror::Error; #[cfg(feature = "pyo3")] -use pyo3::{create_exception, exceptions::PyException, prelude::*}; +use pyo3::{create_exception, exceptions::PyException, pyclass, PyErr}; pub use self::views::HugrView; use crate::extension::{ diff --git a/src/hugr/serialize.rs b/src/hugr/serialize.rs index 02dbaeb97..53bff8cc6 100644 --- a/src/hugr/serialize.rs +++ b/src/hugr/serialize.rs @@ -6,7 +6,7 @@ use std::collections::HashMap; use thiserror::Error; #[cfg(feature = "pyo3")] -use pyo3::{create_exception, exceptions::PyException, prelude::*}; +use pyo3::{create_exception, exceptions::PyException, PyErr}; use crate::extension::ExtensionSet; use crate::hugr::{Hugr, NodeType}; diff --git a/src/hugr/validate.rs b/src/hugr/validate.rs index ebb9a715b..281fb80c9 100644 --- a/src/hugr/validate.rs +++ b/src/hugr/validate.rs @@ -10,7 +10,7 @@ use portgraph::{LinkView, PortView}; use thiserror::Error; #[cfg(feature = "pyo3")] -use pyo3::{create_exception, exceptions::PyException, prelude::*}; +use pyo3::{create_exception, exceptions::PyException, PyErr}; use crate::extension::SignatureError; use crate::extension::{ diff --git a/src/hugr/views/sibling_subgraph.rs b/src/hugr/views/sibling_subgraph.rs index 7bfc69997..6d9e6e67d 100644 --- a/src/hugr/views/sibling_subgraph.rs +++ b/src/hugr/views/sibling_subgraph.rs @@ -27,7 +27,7 @@ use crate::{ use super::HugrView; #[cfg(feature = "pyo3")] -use pyo3::{create_exception, exceptions::PyException, prelude::*}; +use pyo3::{create_exception, exceptions::PyException, PyErr}; /// A non-empty convex subgraph of a HUGR sibling graph. /// diff --git a/src/std_extensions/rotation.rs b/src/std_extensions/rotation.rs index 15e1da725..35b2102b9 100644 --- a/src/std_extensions/rotation.rs +++ b/src/std_extensions/rotation.rs @@ -8,7 +8,7 @@ use num_rational::Rational64; use smol_str::SmolStr; #[cfg(feature = "pyo3")] -use pyo3::prelude::*; +use pyo3::{pyclass, FromPyObject}; use crate::extension::ExtensionId; use crate::types::type_param::TypeArg; diff --git a/src/types.rs b/src/types.rs index 2d927cd55..86a44a777 100644 --- a/src/types.rs +++ b/src/types.rs @@ -26,7 +26,7 @@ use std::fmt::Debug; use self::primitive::PrimType; #[cfg(feature = "pyo3")] -use pyo3::prelude::*; +use pyo3::pyclass; /// The kinds of edges in a HUGR, excluding Hierarchy. #[derive(Clone, PartialEq, Eq, Debug, serde::Serialize, serde::Deserialize)] diff --git a/src/types/signature.rs b/src/types/signature.rs index 0e83f4037..076ba8815 100644 --- a/src/types/signature.rs +++ b/src/types/signature.rs @@ -1,7 +1,7 @@ //! Abstract and concrete Signature types. #[cfg(feature = "pyo3")] -use pyo3::prelude::*; +use pyo3::{pyclass, pymethods}; use std::ops::Index; diff --git a/src/types/type_row.rs b/src/types/type_row.rs index bedb6750c..b3b69bafe 100644 --- a/src/types/type_row.rs +++ b/src/types/type_row.rs @@ -12,7 +12,7 @@ use crate::utils::display_list; use delegate::delegate; #[cfg(feature = "pyo3")] -use pyo3::prelude::*; +use pyo3::pyclass; /// List of types, used for function signatures. #[derive(Clone, PartialEq, Eq, Debug, serde::Serialize, serde::Deserialize)]