Skip to content

Commit

Permalink
feat: Some python errors and bindings (#533)
Browse files Browse the repository at this point in the history
Adds multiple custom python errors, and implements `Into<PyErr>` using
them.
Unfortunately, we have to name the `pyrs` python module name here due to
how pyo3 works.

Also, adds a python wrapper for `EdgeKind`. We don't export any python
methods yet, just the class definitions.
  • Loading branch information
aborgna-q committed Sep 13, 2023
1 parent b247378 commit 88c25b3
Show file tree
Hide file tree
Showing 9 changed files with 75 additions and 15 deletions.
13 changes: 10 additions & 3 deletions src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use thiserror::Error;

#[cfg(feature = "pyo3")]
use pyo3::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};
Expand Down Expand Up @@ -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<BuildError> for PyErr {
fn from(err: BuildError) -> Self {
// We may want to define more specific python-level errors at some point.
PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(err.to_string())
PyBuildError::new_err(err.to_string())
}
}

Expand Down
13 changes: 10 additions & 3 deletions src/hugr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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, pyclass, PyErr};

pub use self::views::HugrView;
use crate::extension::{
Expand Down Expand Up @@ -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<HugrError> for PyErr {
fn from(err: HugrError) -> Self {
// We may want to define more specific python-level errors at some point.
PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(err.to_string())
PyHugrError::new_err(err.to_string())
}
}

Expand Down
12 changes: 10 additions & 2 deletions src/hugr/serialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::collections::HashMap;
use thiserror::Error;

#[cfg(feature = "pyo3")]
use pyo3::prelude::*;
use pyo3::{create_exception, exceptions::PyException, PyErr};

use crate::extension::ExtensionSet;
use crate::hugr::{Hugr, NodeType};
Expand Down Expand Up @@ -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<HUGRSerializationError> for PyErr {
fn from(err: HUGRSerializationError) -> Self {
PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(err.to_string())
PyHUGRSerializationError::new_err(err.to_string())
}
}

Expand Down
13 changes: 10 additions & 3 deletions src/hugr/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use portgraph::{LinkView, PortView};
use thiserror::Error;

#[cfg(feature = "pyo3")]
use pyo3::prelude::*;
use pyo3::{create_exception, exceptions::PyException, PyErr};

use crate::extension::SignatureError;
use crate::extension::{
Expand Down Expand Up @@ -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<ValidationError> for PyErr {
fn from(err: ValidationError) -> Self {
// We may want to define more specific python-level errors at some point.
PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(err.to_string())
PyValidationError::new_err(err.to_string())
}
}

Expand Down
18 changes: 18 additions & 0 deletions src/hugr/views/sibling_subgraph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ use crate::{

use super::HugrView;

#[cfg(feature = "pyo3")]
use pyo3::{create_exception, exceptions::PyException, PyErr};

/// A non-empty convex subgraph of a HUGR sibling graph.
///
/// A HUGR region in which all nodes share the same parent. Unlike
Expand Down Expand Up @@ -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<InvalidReplacement> 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 {
Expand Down
2 changes: 1 addition & 1 deletion src/std_extensions/rotation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
12 changes: 11 additions & 1 deletion src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -24,8 +25,10 @@ use std::fmt::Debug;

use self::primitive::PrimType;

#[cfg(feature = "pyo3")]
use pyo3::pyclass;

/// 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 {
Expand All @@ -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,
)]
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/types/signature.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Abstract and concrete Signature types.

#[cfg(feature = "pyo3")]
use pyo3::prelude::*;
use pyo3::{pyclass, pymethods};

use std::ops::Index;

Expand Down
5 changes: 4 additions & 1 deletion src/types/type_row.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,12 @@ use super::Type;
use crate::utils::display_list;
use delegate::delegate;

#[cfg(feature = "pyo3")]
use pyo3::pyclass;

/// 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 {
Expand Down

0 comments on commit 88c25b3

Please sign in to comment.