Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Some python errors and bindings #533

Merged
merged 4 commits into from
Sep 13, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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, prelude::*};

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, prelude::*};

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, prelude::*};

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, prelude::*};

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, prelude::*};

/// 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
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::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 {
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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why can't we just use EdgeKind for this?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because pyo3 doesn't like enums with non-unit variants. Wrapping it in a struct we hide the variants so it works alright (we'll need some python-level methods to access the internals later).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I saw the comment on the deleted line, but didn't really parse what it meant until now - thanks 🙂


#[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
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::prelude::*;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we always importing all of the pyo3 prelude when we seem to just be using 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