diff --git a/src/hugr/validate.rs b/src/hugr/validate.rs
index f45b7c5fc..67016ac5f 100644
--- a/src/hugr/validate.rs
+++ b/src/hugr/validate.rs
@@ -101,7 +101,7 @@ impl<'a, 'b> ValidationContext<'a, 'b> {
     fn compute_dominator(&self, parent: Node) -> Dominators<Node> {
         let region: SiblingGraph = SiblingGraph::new(self.hugr, parent);
         let entry_node = self.hugr.children(parent).next().unwrap();
-        dominators::simple_fast(&region, entry_node)
+        dominators::simple_fast(&region.as_petgraph(), entry_node)
     }
 
     /// Check the constraints on a single node.
@@ -365,8 +365,11 @@ impl<'a, 'b> ValidationContext<'a, 'b> {
         };
 
         let region: SiblingGraph = SiblingGraph::new(self.hugr, parent);
-        let postorder = Topo::new(&region);
-        let nodes_visited = postorder.iter(&region).filter(|n| *n != parent).count();
+        let postorder = Topo::new(&region.as_petgraph());
+        let nodes_visited = postorder
+            .iter(&region.as_petgraph())
+            .filter(|n| *n != parent)
+            .count();
         let node_count = self.hugr.children(parent).count();
         if nodes_visited != node_count {
             return Err(ValidationError::NotADag {
diff --git a/src/hugr/views.rs b/src/hugr/views.rs
index 5b31ab4fe..f26bfb3e9 100644
--- a/src/hugr/views.rs
+++ b/src/hugr/views.rs
@@ -1,13 +1,14 @@
 //! Read-only access into HUGR graphs and subgraphs.
 
 pub mod descendants;
-mod petgraph;
+pub mod petgraph;
 pub mod sibling;
 pub mod sibling_subgraph;
 
 #[cfg(test)]
 mod tests;
 
+pub use self::petgraph::PetgraphWrapper;
 pub use descendants::DescendantsGraph;
 pub use sibling::SiblingGraph;
 pub use sibling_subgraph::SiblingSubgraph;
@@ -22,7 +23,6 @@ use crate::ops::handle::NodeHandle;
 use crate::ops::{FuncDecl, FuncDefn, OpName, OpTag, OpType, DFG};
 use crate::types::{EdgeKind, FunctionType};
 use crate::{Direction, Node, Port};
-use ::petgraph::visit as pv;
 
 /// A trait for inspecting HUGRs.
 /// For end users we intend this to be superseded by region-specific APIs.
@@ -181,6 +181,15 @@ pub trait HugrView: sealed::HugrInternals {
     /// type. Otherwise return None.
     fn get_function_type(&self) -> Option<&FunctionType>;
 
+    /// Return a wrapper over the view that can be used in petgraph algorithms.
+    #[inline]
+    fn as_petgraph(&self) -> PetgraphWrapper<'_, Self>
+    where
+        Self: Sized,
+    {
+        PetgraphWrapper { hugr: self }
+    }
+
     /// Return dot string showing underlying graph and hierarchy side by side.
     fn dot_string(&self) -> String {
         let hugr = self.base_hugr();
@@ -232,19 +241,7 @@ pub trait HugrView: sealed::HugrInternals {
 }
 
 /// A common trait for views of a HUGR hierarchical subgraph.
-pub trait HierarchyView<'a>:
-    HugrView
-    + pv::GraphBase<NodeId = Node>
-    + pv::GraphProp
-    + pv::NodeCount
-    + pv::NodeIndexable
-    + pv::EdgeCount
-    + pv::Visitable
-    + pv::GetAdjacencyMatrix
-    + pv::Visitable
-where
-    for<'g> &'g Self: pv::IntoNeighborsDirected + pv::IntoNodeIdentifiers,
-{
+pub trait HierarchyView<'a>: HugrView {
     /// The base from which the subgraph is derived.
     type Base;
 
diff --git a/src/hugr/views/descendants.rs b/src/hugr/views/descendants.rs
index cf0262be3..508517f40 100644
--- a/src/hugr/views/descendants.rs
+++ b/src/hugr/views/descendants.rs
@@ -21,8 +21,8 @@ type RegionGraph<'g> = portgraph::view::Region<'g, &'g MultiPortGraph>;
 /// its immediate children.  Prefer using [`SiblingGraph`] when possible,
 /// as it is more efficient.
 ///
-/// Implements the [`HierarchyView`] trait, as well as [`HugrView`] and petgraph's
-/// _visit_ traits, so can be  used interchangeably with [`SiblingGraph`].
+/// Implements the [`HierarchyView`] trait, as well as [`HugrView`], it can be
+/// used interchangeably with [`SiblingGraph`].
 ///
 /// [`SiblingGraph`]: super::SiblingGraph
 pub struct DescendantsGraph<'g, Root = Node, Base = Hugr>
diff --git a/src/hugr/views/petgraph.rs b/src/hugr/views/petgraph.rs
index 29de1506f..751b3ac4f 100644
--- a/src/hugr/views/petgraph.rs
+++ b/src/hugr/views/petgraph.rs
@@ -1,9 +1,6 @@
 //! Implementations of petgraph's traits for Hugr Region views.
 
-use super::{DescendantsGraph, SiblingGraph};
-use crate::hugr::views::sealed::HugrInternals;
 use crate::hugr::HugrView;
-use crate::ops::handle::NodeHandle;
 use crate::ops::OpType;
 use crate::types::EdgeKind;
 use crate::{Node, Port};
@@ -12,176 +9,159 @@ use context_iterators::{ContextIterator, IntoContextIterator, MapWithCtx};
 use petgraph::visit as pv;
 use portgraph::NodeIndex;
 
-macro_rules! impl_region_petgraph_traits {
-    ($hugr:ident) => {
-        impl<'a, Root, Base> pv::GraphBase for $hugr<'a, Root, Base>
-        where
-            Root: NodeHandle,
-            Base: HugrInternals + HugrView,
-        {
-            type NodeId = Node;
-            type EdgeId = ((Node, Port), (Node, Port));
-        }
+/// Wrapper for a HugrView that implements petgraph's traits.
+///
+/// It can be used to apply petgraph's algorithms to a Hugr.
+#[derive(Debug, Clone, Copy)]
+pub struct PetgraphWrapper<'a, T> {
+    pub(crate) hugr: &'a T,
+}
 
-        impl<'a, Root, Base> pv::GraphProp for $hugr<'a, Root, Base>
-        where
-            Root: NodeHandle,
-            Base: HugrInternals + HugrView,
-        {
-            type EdgeType = petgraph::Directed;
-        }
+impl<'a, T> pv::GraphBase for PetgraphWrapper<'a, T>
+where
+    T: HugrView,
+{
+    type NodeId = Node;
+    type EdgeId = ((Node, Port), (Node, Port));
+}
 
-        impl<'a, Root, Base> pv::NodeCount for $hugr<'a, Root, Base>
-        where
-            Root: NodeHandle,
-            Base: HugrInternals + HugrView,
-        {
-            fn node_count(&self) -> usize {
-                HugrView::node_count(self)
-            }
-        }
+impl<'a, T> pv::GraphProp for PetgraphWrapper<'a, T>
+where
+    T: HugrView,
+{
+    type EdgeType = petgraph::Directed;
+}
 
-        impl<'a, Root, Base> pv::NodeIndexable for $hugr<'a, Root, Base>
-        where
-            Root: NodeHandle,
-            Base: HugrInternals + HugrView,
-        {
-            fn node_bound(&self) -> usize {
-                HugrView::node_count(self)
-            }
+impl<'a, T> pv::NodeCount for PetgraphWrapper<'a, T>
+where
+    T: HugrView,
+{
+    fn node_count(&self) -> usize {
+        HugrView::node_count(self.hugr)
+    }
+}
 
-            fn to_index(&self, ix: Self::NodeId) -> usize {
-                ix.index.into()
-            }
+impl<'a, T> pv::NodeIndexable for PetgraphWrapper<'a, T>
+where
+    T: HugrView,
+{
+    fn node_bound(&self) -> usize {
+        HugrView::node_count(self.hugr)
+    }
 
-            fn from_index(&self, ix: usize) -> Self::NodeId {
-                NodeIndex::new(ix).into()
-            }
-        }
+    fn to_index(&self, ix: Self::NodeId) -> usize {
+        ix.index.into()
+    }
 
-        impl<'a, Root, Base> pv::EdgeCount for $hugr<'a, Root, Base>
-        where
-            Root: NodeHandle,
-            Base: HugrInternals + HugrView,
-        {
-            fn edge_count(&self) -> usize {
-                HugrView::edge_count(self)
-            }
-        }
+    fn from_index(&self, ix: usize) -> Self::NodeId {
+        NodeIndex::new(ix).into()
+    }
+}
 
-        impl<'a, Root, Base> pv::Data for $hugr<'a, Root, Base>
-        where
-            Root: NodeHandle,
-            Base: HugrInternals + HugrView,
-        {
-            type NodeWeight = OpType;
-            type EdgeWeight = EdgeKind;
-        }
+impl<'a, T> pv::EdgeCount for PetgraphWrapper<'a, T>
+where
+    T: HugrView,
+{
+    fn edge_count(&self) -> usize {
+        HugrView::edge_count(self.hugr)
+    }
+}
 
-        impl<'g, 'a, Root, Base> pv::IntoNodeIdentifiers for &'g $hugr<'a, Root, Base>
-        where
-            Root: NodeHandle,
-            Base: HugrInternals + HugrView,
-        {
-            type NodeIdentifiers = <$hugr<'a, Root, Base> as HugrView>::Nodes<'g>;
+impl<'a, T> pv::Data for PetgraphWrapper<'a, T>
+where
+    T: HugrView,
+{
+    type NodeWeight = OpType;
+    type EdgeWeight = EdgeKind;
+}
 
-            fn node_identifiers(self) -> Self::NodeIdentifiers {
-                self.nodes()
-            }
-        }
+impl<'g, 'a, T> pv::IntoNodeReferences for &'g PetgraphWrapper<'a, T>
+where
+    T: HugrView,
+{
+    type NodeRef = HugrNodeRef<'g>;
+    type NodeReferences = MapWithCtx<<T as HugrView>::Nodes<'g>, Self, HugrNodeRef<'g>>;
+
+    fn node_references(self) -> Self::NodeReferences {
+        self.hugr
+            .nodes()
+            .with_context(self)
+            .map_with_context(|n, &wrapper| HugrNodeRef::from_node(n, wrapper.hugr))
+    }
+}
 
-        impl<'g, 'a, Root, Base> pv::IntoNodeReferences for &'g $hugr<'a, Root, Base>
-        where
-            Root: NodeHandle,
-            'g: 'a,
-            Base: HugrInternals + HugrView,
-        {
-            type NodeRef = HugrNodeRef<'a>;
-            type NodeReferences =
-                MapWithCtx<<$hugr<'a, Root, Base> as HugrView>::Nodes<'a>, Self, HugrNodeRef<'a>>;
-
-            fn node_references(self) -> Self::NodeReferences {
-                self.nodes()
-                    .with_context(self)
-                    .map_with_context(|n, &hugr| HugrNodeRef::from_node(n, hugr))
-            }
-        }
+impl<'g, 'a, T> pv::IntoNodeIdentifiers for &'g PetgraphWrapper<'a, T>
+where
+    T: HugrView,
+{
+    type NodeIdentifiers = <T as HugrView>::Nodes<'g>;
 
-        impl<'g, 'a, Root, Base> pv::IntoNeighbors for &'g $hugr<'a, Root, Base>
-        where
-            Root: NodeHandle,
-            Base: HugrInternals + HugrView,
-        {
-            type Neighbors = <$hugr<'a, Root, Base> as HugrView>::Neighbours<'g>;
+    fn node_identifiers(self) -> Self::NodeIdentifiers {
+        self.hugr.nodes()
+    }
+}
 
-            fn neighbors(self, n: Self::NodeId) -> Self::Neighbors {
-                self.output_neighbours(n)
-            }
-        }
+impl<'g, 'a, T> pv::IntoNeighbors for &'g PetgraphWrapper<'a, T>
+where
+    T: HugrView,
+{
+    type Neighbors = <T as HugrView>::Neighbours<'g>;
 
-        impl<'g, 'a, Root, Base> pv::IntoNeighborsDirected for &'g $hugr<'a, Root, Base>
-        where
-            Root: NodeHandle,
-            Base: HugrInternals + HugrView,
-        {
-            type NeighborsDirected = <$hugr<'a, Root, Base> as HugrView>::Neighbours<'g>;
-
-            fn neighbors_directed(
-                self,
-                n: Self::NodeId,
-                d: petgraph::Direction,
-            ) -> Self::NeighborsDirected {
-                self.neighbours(n, d.into())
-            }
-        }
+    fn neighbors(self, n: Self::NodeId) -> Self::Neighbors {
+        self.hugr.output_neighbours(n)
+    }
+}
 
-        impl<'a, Root, Base> pv::Visitable for $hugr<'a, Root, Base>
-        where
-            Root: NodeHandle,
-            Base: HugrInternals + HugrView,
-        {
-            type Map = std::collections::HashSet<Self::NodeId>;
+impl<'g, 'a, T> pv::IntoNeighborsDirected for &'g PetgraphWrapper<'a, T>
+where
+    T: HugrView,
+{
+    type NeighborsDirected = <T as HugrView>::Neighbours<'g>;
+
+    fn neighbors_directed(
+        self,
+        n: Self::NodeId,
+        d: petgraph::Direction,
+    ) -> Self::NeighborsDirected {
+        self.hugr.neighbours(n, d.into())
+    }
+}
 
-            fn visit_map(&self) -> Self::Map {
-                std::collections::HashSet::new()
-            }
+impl<'a, T> pv::Visitable for PetgraphWrapper<'a, T>
+where
+    T: HugrView,
+{
+    type Map = std::collections::HashSet<Self::NodeId>;
 
-            fn reset_map(&self, map: &mut Self::Map) {
-                map.clear();
-            }
-        }
+    fn visit_map(&self) -> Self::Map {
+        std::collections::HashSet::new()
+    }
 
-        impl<'a, Root, Base> pv::GetAdjacencyMatrix for $hugr<'a, Root, Base>
-        where
-            Root: NodeHandle,
-            Base: HugrInternals + HugrView,
-        {
-            type AdjMatrix = std::collections::HashSet<(Self::NodeId, Self::NodeId)>;
-
-            fn adjacency_matrix(&self) -> Self::AdjMatrix {
-                let mut matrix = std::collections::HashSet::new();
-                for node in self.nodes() {
-                    for neighbour in self.output_neighbours(node) {
-                        matrix.insert((node, neighbour));
-                    }
-                }
-                matrix
-            }
+    fn reset_map(&self, map: &mut Self::Map) {
+        map.clear();
+    }
+}
 
-            fn is_adjacent(
-                &self,
-                matrix: &Self::AdjMatrix,
-                a: Self::NodeId,
-                b: Self::NodeId,
-            ) -> bool {
-                matrix.contains(&(a, b))
+impl<'a, T> pv::GetAdjacencyMatrix for PetgraphWrapper<'a, T>
+where
+    T: HugrView,
+{
+    type AdjMatrix = std::collections::HashSet<(Self::NodeId, Self::NodeId)>;
+
+    fn adjacency_matrix(&self) -> Self::AdjMatrix {
+        let mut matrix = std::collections::HashSet::new();
+        for node in self.hugr.nodes() {
+            for neighbour in self.hugr.output_neighbours(node) {
+                matrix.insert((node, neighbour));
             }
         }
-    };
-}
+        matrix
+    }
 
-impl_region_petgraph_traits!(SiblingGraph);
-impl_region_petgraph_traits!(DescendantsGraph);
+    fn is_adjacent(&self, matrix: &Self::AdjMatrix, a: Self::NodeId, b: Self::NodeId) -> bool {
+        matrix.contains(&(a, b))
+    }
+}
 
 /// Reference to a Hugr node and its associated OpType.
 #[derive(Debug, Clone, Copy)]
diff --git a/src/hugr/views/sibling.rs b/src/hugr/views/sibling.rs
index 84532831a..86bc142d3 100644
--- a/src/hugr/views/sibling.rs
+++ b/src/hugr/views/sibling.rs
@@ -21,8 +21,8 @@ type FlatRegionGraph<'g> = portgraph::view::FlatRegion<'g, &'g MultiPortGraph>;
 ///
 /// See [`DescendantsGraph`] for a view that includes all descendants of the root.
 ///
-/// Implements the [`HierarchyView`] trait, as well as [`HugrView`] and petgraph's
-/// _visit_ traits, so can be  used interchangeably with [`DescendantsGraph`].
+/// Implements the [`HierarchyView`] trait, as well as [`HugrView`], it can be
+/// used interchangeably with [`DescendantsGraph`].
 ///
 /// [`DescendantsGraph`]: super::DescendantsGraph
 pub struct SiblingGraph<'g, Root = Node, Base = Hugr>