diff --git a/Cargo.lock b/Cargo.lock index c9c28c997..d51344a16 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -73,7 +73,7 @@ dependencies = [ "autocfg", "cfg-if", "crossbeam-utils", - "memoffset", + "memoffset 0.6.5", "scopeguard", ] @@ -197,6 +197,15 @@ dependencies = [ "autocfg", ] +[[package]] +name = "memoffset" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" +dependencies = [ + "autocfg", +] + [[package]] name = "ndarray" version = "0.15.6" @@ -262,17 +271,17 @@ dependencies = [ [[package]] name = "numpy" -version = "0.17.2" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a462c1af5ba1fddec1488c4646993a23ae7931f9e170ccba23e9c7c834277797" +checksum = "96b0fee4571867d318651c24f4a570c3f18408cf95f16ccb576b3ce85496a46e" dependencies = [ - "ahash 0.7.6", "libc", "ndarray", "num-complex", "num-integer", "num-traits", "pyo3", + "rustc-hash", ] [[package]] @@ -341,16 +350,16 @@ dependencies = [ [[package]] name = "pyo3" -version = "0.17.3" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "268be0c73583c183f2b14052337465768c07726936a260f480f0857cb95ba543" +checksum = "ccd4149c8c3975099622b4e1962dac27565cf5663b76452c3e2b66e0b6824277" dependencies = [ "cfg-if", "hashbrown 0.12.3", "indexmap", "indoc", "libc", - "memoffset", + "memoffset 0.8.0", "num-bigint", "num-complex", "parking_lot", @@ -362,9 +371,9 @@ dependencies = [ [[package]] name = "pyo3-build-config" -version = "0.17.3" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28fcd1e73f06ec85bf3280c48c67e731d8290ad3d730f8be9dc07946923005c8" +checksum = "9cd09fe469834db21ee60e0051030339e5d361293d8cb5ec02facf7fdcf52dbf" dependencies = [ "once_cell", "target-lexicon", @@ -372,9 +381,9 @@ dependencies = [ [[package]] name = "pyo3-ffi" -version = "0.17.3" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f6cb136e222e49115b3c51c32792886defbfb0adead26a688142b346a0b9ffc" +checksum = "0c427c9a96b9c5b12156dbc11f76b14f49e9aae8905ca783ea87c249044ef137" dependencies = [ "libc", "pyo3-build-config", @@ -382,9 +391,9 @@ dependencies = [ [[package]] name = "pyo3-macros" -version = "0.17.3" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94144a1266e236b1c932682136dc35a9dee8d3589728f68130c7c3861ef96b28" +checksum = "16b822bbba9d60630a44d2109bc410489bb2f439b33e3a14ddeb8a40b378a7c4" dependencies = [ "proc-macro2", "pyo3-macros-backend", @@ -394,9 +403,9 @@ dependencies = [ [[package]] name = "pyo3-macros-backend" -version = "0.17.3" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8df9be978a2d2f0cdebabb03206ed73b11314701a5bfe71b0d753b81997777f" +checksum = "84ae898104f7c99db06231160770f3e40dad6eb9021daddc0fedfa3e41dff10a" dependencies = [ "proc-macro2", "quote", @@ -497,6 +506,12 @@ dependencies = [ "bitflags", ] +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustworkx" version = "0.13.0" diff --git a/Cargo.toml b/Cargo.toml index 731d9498e..5f329eb17 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ crate-type = ["cdylib"] ahash = "0.8.0" petgraph = "0.6.2" fixedbitset = "0.4.2" -numpy = "0.17.2" +numpy = "0.18.0" rand = "0.8" rand_pcg = "0.3" rayon = "1.6" @@ -35,7 +35,7 @@ serde_json = "1.0" rustworkx-core = { path = "rustworkx-core", version = "=0.13.0" } [dependencies.pyo3] -version = "0.17.3" +version = "0.18.0" features = ["extension-module", "hashbrown", "num-bigint", "num-complex", "indexmap"] [dependencies.hashbrown] diff --git a/src/centrality.rs b/src/centrality.rs index 7393fbbd5..1168096ea 100644 --- a/src/centrality.rs +++ b/src/centrality.rs @@ -62,7 +62,14 @@ use rustworkx_core::centrality; /// :returns: a read-only dict-like object whose keys are the node indices and values are the /// betweenness score for each node. /// :rtype: CentralityMapping -#[pyfunction(normalized = "true", endpoints = "false", parallel_threshold = "50")] +#[pyfunction( + signature = ( + graph, + normalized=true, + endpoints=false, + parallel_threshold=50 + ) +)] #[pyo3(text_signature = "(graph, /, normalized=True, endpoints=False, parallel_threshold=50)")] pub fn graph_betweenness_centrality( graph: &graph::PyGraph, @@ -119,7 +126,14 @@ pub fn graph_betweenness_centrality( /// :returns: a read-only dict-like object whose keys are the node indices and values are the /// betweenness score for each node. /// :rtype: CentralityMapping -#[pyfunction(normalized = "true", endpoints = "false", parallel_threshold = "50")] +#[pyfunction( + signature = ( + graph, + normalized=true, + endpoints=false, + parallel_threshold=50 + ) +)] #[pyo3(text_signature = "(graph, /, normalized=True, endpoints=False, parallel_threshold=50)")] pub fn digraph_betweenness_centrality( graph: &digraph::PyDiGraph, @@ -172,7 +186,15 @@ pub fn digraph_betweenness_centrality( /// :returns: a read-only dict-like object whose keys are the node indices and values are the /// centrality score for that node. /// :rtype: CentralityMapping -#[pyfunction(default_weight = "1.0", max_iter = "100", tol = "1e-6")] +#[pyfunction( + signature = ( + graph, + weight_fn=None, + default_weight=1.0, + max_iter=100, + tol=1e-6 + ) +)] #[pyo3(text_signature = "(graph, /, weight_fn=None, default_weight=1.0, max_iter=100, tol=1e-6)")] pub fn graph_eigenvector_centrality( py: Python, @@ -251,7 +273,15 @@ pub fn graph_eigenvector_centrality( /// :returns: a read-only dict-like object whose keys are the node indices and values are the /// centrality score for that node. /// :rtype: CentralityMapping -#[pyfunction(default_weight = "1.0", max_iter = "100", tol = "1e-6")] +#[pyfunction( + signature = ( + graph, + weight_fn=None, + default_weight=1.0, + max_iter=100, + tol=1e-6 + ) +)] #[pyo3(text_signature = "(graph, /, weight_fn=None, default_weight=1.0, max_iter=100, tol=1e-6)")] pub fn digraph_eigenvector_centrality( py: Python, diff --git a/src/connectivity/mod.rs b/src/connectivity/mod.rs index 6c2349274..0ab9c945f 100644 --- a/src/connectivity/mod.rs +++ b/src/connectivity/mod.rs @@ -290,8 +290,11 @@ pub fn is_weakly_connected(graph: &digraph::PyDiGraph) -> PyResult { /// /// :return: The adjacency matrix for the input directed graph as a numpy array /// :rtype: numpy.ndarray -#[pyfunction(default_weight = "1.0", null_value = "0.0")] -#[pyo3(text_signature = "(graph, /, weight_fn=None, default_weight=1.0, null_value=0.0)")] +#[pyfunction] +#[pyo3( + signature=(graph, weight_fn=None, default_weight=1.0, null_value=0.0), + text_signature = "(graph, /, weight_fn=None, default_weight=1.0, null_value=0.0)" +)] pub fn digraph_adjacency_matrix( py: Python, graph: &digraph::PyDiGraph, @@ -341,8 +344,11 @@ pub fn digraph_adjacency_matrix( /// /// :return: The adjacency matrix for the input graph as a numpy array /// :rtype: numpy.ndarray -#[pyfunction(default_weight = "1.0", null_value = "0.0")] -#[pyo3(text_signature = "(graph, /, weight_fn=None, default_weight=1.0, null_value=0.0)")] +#[pyfunction] +#[pyo3( + signature=(graph, weight_fn=None, default_weight=1.0, null_value=0.0), + text_signature = "(graph, /, weight_fn=None, default_weight=1.0, null_value=0.0)" +)] pub fn graph_adjacency_matrix( py: Python, graph: &graph::PyGraph, diff --git a/src/dag_algo/mod.rs b/src/dag_algo/mod.rs index dbfcf4702..7a21d5b92 100644 --- a/src/dag_algo/mod.rs +++ b/src/dag_algo/mod.rs @@ -223,8 +223,11 @@ pub fn is_directed_acyclic_graph(graph: &digraph::PyDiGraph) -> bool { /// :rtype: list /// /// :raises InvalidNode: If a node index in ``first_layer`` is not in the graph -#[pyfunction(index_output = "false")] -#[pyo3(text_signature = "(dag, first_layer, /, index_output=False)")] +#[pyfunction] +#[pyo3( + signature=(dag, first_layer, index_output=false), + text_signature = "(dag, first_layer, /, index_output=False)" +)] pub fn layers( py: Python, dag: &digraph::PyDiGraph, diff --git a/src/digraph.rs b/src/digraph.rs index a48c62531..0fcddde12 100644 --- a/src/digraph.rs +++ b/src/digraph.rs @@ -10,7 +10,7 @@ // License for the specific language governing permissions and limitations // under the License. -#![allow(clippy::borrow_as_ptr)] +#![allow(clippy::borrow_as_ptr, clippy::redundant_closure)] use std::cmp; use std::cmp::Ordering; @@ -285,7 +285,7 @@ impl PyDiGraph { #[pymethods] impl PyDiGraph { #[new] - #[args(check_cycle = "false", multigraph = "true")] + #[pyo3(signature=(check_cycle=false, multigraph=true, attrs=None))] fn new(py: Python, check_cycle: bool, multigraph: bool, attrs: Option) -> Self { PyDiGraph { graph: StablePyGraph::::new(), @@ -322,7 +322,7 @@ impl PyDiGraph { fn __setstate__(&mut self, py: Python, state: PyObject) -> PyResult<()> { self.graph = StablePyGraph::::new(); - let dict_state = state.cast_as::(py)?; + let dict_state = state.downcast::(py)?; let nodes_dict = dict_state.get_item("nodes").unwrap().downcast::()?; let edges_list = dict_state.get_item("edges").unwrap().downcast::()?; @@ -908,7 +908,7 @@ impl PyDiGraph { /// would only retain edges if the input edge to ``node`` had the same /// data payload as the outgoing edge. #[pyo3(text_signature = "(self, node, /, use_outgoing=None, condition=None)")] - #[args(use_outgoing = "false")] + #[pyo3(signature=(node, use_outgoing=false, condition=None))] pub fn remove_node_retain_edges( &mut self, py: Python, @@ -1495,7 +1495,7 @@ impl PyDiGraph { /// :returns: A list of the edge indices incident to a node in the graph /// :rtype: EdgeIndices #[pyo3(text_signature = "(self, node, /, all_edges=False)")] - #[args(all_edges = "false")] + #[pyo3(signature=(node, all_edges=false))] pub fn incident_edges(&self, node: usize, all_edges: bool) -> EdgeIndices { let node_index = NodeIndex::new(node); if all_edges { @@ -1538,7 +1538,7 @@ impl PyDiGraph { /// ``(source, target, data)`` /// :rtype: EdgeIndexMap #[pyo3(text_signature = "(self, node, /, all_edges=False)")] - #[args(all_edges = "false")] + #[pyo3(signature=(node, all_edges=false))] pub fn incident_edge_index_map( &self, py: Python, @@ -1876,7 +1876,7 @@ impl PyDiGraph { /// mpl_draw(graph) /// #[staticmethod] - #[args(labels = "false")] + #[pyo3(signature=(path, comment=None, deliminator=None, labels=false))] #[pyo3(text_signature = "(path, /, comment=None, deliminator=None, labels=False)")] pub fn read_edge_list( py: Python, @@ -2051,8 +2051,7 @@ impl PyDiGraph { /// :returns: A new graph object generated from the adjacency matrix /// :rtype: PyDiGraph #[staticmethod] - #[args(null_value = "0.0")] - #[pyo3(text_signature = "(matrix, /, null_value=0.0)")] + #[pyo3(signature=(matrix, null_value=0.0), text_signature = "(matrix, /, null_value=0.0)")] pub fn from_adjacency_matrix<'p>( py: Python<'p>, matrix: PyReadonlyArray2<'p, f64>, @@ -2088,8 +2087,7 @@ impl PyDiGraph { /// :returns: A new graph object generated from the adjacency matrix /// :rtype: PyDiGraph #[staticmethod] - #[args(null_value = "Complex64::zero()")] - #[pyo3(text_signature = "(matrix, /, null_value=0.0+0.0j)")] + #[pyo3(signature=(matrix, null_value=Complex64::zero()), text_signature = "(matrix, /, null_value=0.0+0.0j)")] pub fn from_complex_adjacency_matrix<'p>( py: Python<'p>, matrix: PyReadonlyArray2<'p, Complex64>, @@ -2497,8 +2495,7 @@ impl PyDiGraph { /// the other. /// :rtype: PyGraph /// - #[args(preserve_attrs = "false")] - #[pyo3(text_signature = "(self, nodes, /, preserve_attrs=False)")] + #[pyo3(signature=(nodes, preserve_attrs=false),text_signature = "(self, nodes, /, preserve_attrs=False)")] pub fn subgraph(&self, py: Python, nodes: Vec, preserve_attrs: bool) -> PyDiGraph { let node_set: HashSet = nodes.iter().cloned().collect(); let mut node_map: HashMap = HashMap::with_capacity(nodes.len()); @@ -2637,8 +2634,7 @@ impl PyDiGraph { /// :returns: A new PyGraph object with an undirected edge for every /// directed edge in this graph /// :rtype: PyGraph - #[pyo3(text_signature = "(self, /, multigraph=True, weight_combo_fn=None)")] - #[args(multigraph = "true", weight_combo_fn = "None")] + #[pyo3(signature=(multigraph=true, weight_combo_fn=None), text_signature = "(self, /, multigraph=True, weight_combo_fn=None)")] pub fn to_undirected( &self, py: Python, diff --git a/src/generators.rs b/src/generators.rs index 18e378afb..6bb8085dd 100644 --- a/src/generators.rs +++ b/src/generators.rs @@ -59,8 +59,11 @@ where /// graph = rustworkx.generators.directed_cycle_graph(5) /// mpl_draw(graph) /// -#[pyfunction(bidirectional = "false", multigraph = "true")] -#[pyo3(text_signature = "(/, num_nodes=None, weights=None, bidirectional=False, multigraph=True)")] +#[pyfunction] +#[pyo3( + signature=(num_nodes=None, weights=None, bidirectional=false, multigraph=true), + text_signature = "(/, num_nodes=None, weights=None, bidirectional=False, multigraph=True)" +)] pub fn directed_cycle_graph( py: Python, num_nodes: Option, @@ -118,8 +121,11 @@ pub fn directed_cycle_graph( /// graph = rustworkx.generators.cycle_graph(5) /// mpl_draw(graph) /// -#[pyfunction(multigraph = true)] -#[pyo3(text_signature = "(/, num_nodes=None, weights=None, multigraph=True)")] +#[pyfunction] +#[pyo3( + signature=(num_nodes=None, weights=None, multigraph=true), + text_signature = "(/, num_nodes=None, weights=None, multigraph=True)" +)] pub fn cycle_graph( py: Python, num_nodes: Option, @@ -171,8 +177,11 @@ pub fn cycle_graph( /// graph = rustworkx.generators.directed_path_graph(10) /// mpl_draw(graph) /// -#[pyfunction(bidirectional = "false", multigraph = "true")] -#[pyo3(text_signature = "(/, num_nodes=None, weights=None, bidirectional=False, multigraph=True)")] +#[pyfunction] +#[pyo3( + signature=(num_nodes=None, weights=None, bidirectional=false, multigraph=true), + text_signature = "(/, num_nodes=None, weights=None, bidirectional=False, multigraph=True)" +)] pub fn directed_path_graph( py: Python, num_nodes: Option, @@ -230,8 +239,11 @@ pub fn directed_path_graph( /// graph = rustworkx.generators.path_graph(10) /// mpl_draw(graph) /// -#[pyfunction(multigraph = true)] -#[pyo3(text_signature = "(/, num_nodes=None, weights=None, multigraph=True)")] +#[pyfunction] +#[pyo3( + signature=(num_nodes=None, weights=None, multigraph=true), + text_signature = "(/, num_nodes=None, weights=None, multigraph=True)" +)] pub fn path_graph( py: Python, num_nodes: Option, @@ -294,8 +306,9 @@ pub fn path_graph( /// graph = rustworkx.generators.directed_star_graph(10, inward=True) /// mpl_draw(graph) /// -#[pyfunction(inward = "false", bidirectional = "false", multigraph = "true")] +#[pyfunction] #[pyo3( + signature=(num_nodes=None, weights=None, inward=false, bidirectional=false, multigraph=true), text_signature = "(/, num_nodes=None, weights=None, inward=False, bidirectional=False, multigraph=True)" )] pub fn directed_star_graph( @@ -358,8 +371,11 @@ pub fn directed_star_graph( /// graph = rustworkx.generators.star_graph(10) /// mpl_draw(graph) /// -#[pyfunction(multigraph = true)] -#[pyo3(text_signature = "(/, num_nodes=None, weights=None, multigraph=True)")] +#[pyfunction] +#[pyo3( + signature=(num_nodes=None, weights=None, multigraph=true), + text_signature = "(/, num_nodes=None, weights=None, multigraph=True)" +)] pub fn star_graph( py: Python, num_nodes: Option, @@ -409,8 +425,11 @@ pub fn star_graph( /// graph = rustworkx.generators.mesh_graph(4) /// mpl_draw(graph) /// -#[pyfunction(multigraph = true)] -#[pyo3(text_signature = "(/, num_nodes=None, weights=None, multigraph=True)")] +#[pyfunction] +#[pyo3( + signature=(num_nodes=None, weights=None, multigraph=true), + text_signature = "(/, num_nodes=None, weights=None, multigraph=True)" +)] pub fn mesh_graph( py: Python, num_nodes: Option, @@ -444,8 +463,11 @@ pub fn mesh_graph( /// graph = rustworkx.generators.directed_mesh_graph(4) /// mpl_draw(graph) /// -#[pyfunction(multigraph = "true")] -#[pyo3(text_signature = "(/, num_nodes=None, weights=None, multigraph=True)")] +#[pyfunction] +#[pyo3( + signature=(num_nodes=None, weights=None, multigraph=true), + text_signature = "(/, num_nodes=None, weights=None, multigraph=True)" +)] pub fn directed_mesh_graph( py: Python, num_nodes: Option, @@ -487,8 +509,11 @@ pub fn directed_mesh_graph( /// graph = rustworkx.generators.grid_graph(2, 3) /// mpl_draw(graph) /// -#[pyfunction(multigraph = true)] -#[pyo3(text_signature = "(/, rows=None, cols=None, weights=None, multigraph=True)")] +#[pyfunction] +#[pyo3( + signature=(rows=None, cols=None, weights=None, multigraph=true), + text_signature = "(/, rows=None, cols=None, weights=None, multigraph=True)" +)] pub fn grid_graph( py: Python, rows: Option, @@ -545,8 +570,9 @@ pub fn grid_graph( /// graph = rustworkx.generators.directed_grid_graph(2, 3) /// mpl_draw(graph) /// -#[pyfunction(bidirectional = "false", multigraph = "true")] +#[pyfunction] #[pyo3( + signature=(rows=None, cols=None, weights=None, bidirectional=false, multigraph=true), text_signature = "(/, rows=None, cols=None, weights=None, bidirectional=False, multigraph=True)" )] pub fn directed_grid_graph( @@ -612,8 +638,11 @@ const MAX_ORDER: u32 = 29; /// graph = rustworkx.generators.binomial_tree_graph(4) /// mpl_draw(graph) /// -#[pyfunction(multigraph = true)] -#[pyo3(text_signature = "(order, /, weights=None, multigraph=True)")] +#[pyfunction] +#[pyo3( + signature=(order, weights=None, multigraph=true), + text_signature = "(order, /, weights=None, multigraph=True)" +)] pub fn binomial_tree_graph( py: Python, order: u32, @@ -674,8 +703,11 @@ pub fn binomial_tree_graph( /// graph = rustworkx.generators.directed_binomial_tree_graph(4) /// mpl_draw(graph) /// -#[pyfunction(bidirectional = "false", multigraph = "true")] -#[pyo3(text_signature = "(order, /, weights=None, bidirectional=False, multigraph=True)")] +#[pyfunction] +#[pyo3( + signature=(order, weights=None, bidirectional=false, multigraph=true), + text_signature = "(order, /, weights=None, bidirectional=False, multigraph=True)" +)] pub fn directed_binomial_tree_graph( py: Python, order: u32, @@ -739,8 +771,11 @@ pub fn directed_binomial_tree_graph( /// graph = rustworkx.generators.full_rary_tree(5, 15) /// mpl_draw(graph) /// -#[pyfunction(multigraph = true)] -#[pyo3(text_signature = "(branching_factor, num_nodes, /, weights=None, multigraph=True)")] +#[pyfunction] +#[pyo3( + signature=(branching_factor, num_nodes, weights=None, multigraph=true), + text_signature = "(branching_factor, num_nodes, /, weights=None, multigraph=True)" +)] pub fn full_rary_tree( py: Python, branching_factor: usize, @@ -820,8 +855,11 @@ pub fn full_rary_tree( /// graphviz_draw(graph, lambda node: dict( /// color='black', fillcolor='lightblue', style='filled')) /// -#[pyfunction(multigraph = true)] -#[pyo3(text_signature = "(d, /, multigraph=True)")] +#[pyfunction] +#[pyo3( + signature=(d, multigraph=true), + text_signature = "(d, /, multigraph=True)" +)] pub fn heavy_square_graph(py: Python, d: usize, multigraph: bool) -> PyResult { let default_fn = || py.None(); let graph: StablePyGraph = @@ -883,8 +921,11 @@ pub fn heavy_square_graph(py: Python, d: usize, multigraph: bool) -> PyResult PyResult { let default_fn = || py.None(); let graph: StablePyGraph = @@ -1038,8 +1082,11 @@ pub fn heavy_hex_graph(py: Python, d: usize, multigraph: bool) -> PyResult, @@ -1395,8 +1454,11 @@ pub fn barbell_graph( /// graph = rustworkx.generators.empty_graph(5) /// mpl_draw(graph) /// -#[pyfunction(multigraph = true)] -#[pyo3(text_signature = "(/, n, multigraph=True)")] +#[pyfunction] +#[pyo3( + signature=(n, multigraph=true), + text_signature = "(/, n, multigraph=True)" +)] pub fn empty_graph(py: Python, n: usize, multigraph: bool) -> PyResult { let mut graph = StableUnGraph::::default(); for _ in 0..n { @@ -1425,8 +1487,11 @@ pub fn empty_graph(py: Python, n: usize, multigraph: bool) -> PyResult, @@ -1532,8 +1600,11 @@ pub fn complete_graph( /// graph = rustworkx.generators.directed_complete_graph(5) /// mpl_draw(graph) /// -#[pyfunction(multigraph = "true")] -#[pyo3(text_signature = "(/, num_nodes=None, weights=None, multigraph=True)")] +#[pyfunction] +#[pyo3( + signature=(num_nodes=None, weights=None, multigraph=true), + text_signature = "(/, num_nodes=None, weights=None, multigraph=True)" +)] pub fn directed_complete_graph( py: Python, num_nodes: Option, diff --git a/src/graph.rs b/src/graph.rs index dd4610698..c718ce930 100644 --- a/src/graph.rs +++ b/src/graph.rs @@ -10,7 +10,7 @@ // License for the specific language governing permissions and limitations // under the License. -#![allow(clippy::borrow_as_ptr)] +#![allow(clippy::borrow_as_ptr, clippy::redundant_closure)] use std::cmp; use std::collections::BTreeMap; @@ -181,7 +181,7 @@ impl PyGraph { #[pymethods] impl PyGraph { #[new] - #[args(multigraph = "true")] + #[pyo3(signature=(multigraph=true, attrs=None))] fn new(py: Python, multigraph: bool, attrs: Option) -> Self { PyGraph { graph: StablePyGraph::::default(), @@ -217,7 +217,7 @@ impl PyGraph { fn __setstate__(&mut self, py: Python, state: PyObject) -> PyResult<()> { self.graph = StablePyGraph::::default(); - let dict_state = state.cast_as::(py)?; + let dict_state = state.downcast::(py)?; let nodes_dict = dict_state.get_item("nodes").unwrap().downcast::()?; let edges_list = dict_state.get_item("edges").unwrap().downcast::()?; let nodes_removed_raw = dict_state @@ -1204,8 +1204,7 @@ impl PyGraph { /// mpl_draw(graph) /// #[staticmethod] - #[args(labels = "false")] - #[pyo3(text_signature = "(path, /, comment=None, deliminator=None, labels=False)")] + #[pyo3(signature=(path, comment=None, deliminator=None, labels=false), text_signature = "(path, /, comment=None, deliminator=None, labels=False)")] pub fn read_edge_list( py: Python, path: &str, @@ -1377,8 +1376,7 @@ impl PyGraph { /// :returns: A new graph object generated from the adjacency matrix /// :rtype: PyGraph #[staticmethod] - #[args(null_value = "0.0")] - #[pyo3(text_signature = "(matrix, /, null_value=0.0)")] + #[pyo3(signature=(matrix, null_value=0.0), text_signature = "(matrix, /, null_value=0.0)")] pub fn from_adjacency_matrix<'p>( py: Python<'p>, matrix: PyReadonlyArray2<'p, f64>, @@ -1413,9 +1411,9 @@ impl PyGraph { /// /// :returns: A new graph object generated from the adjacency matrix /// :rtype: PyGraph + /// #[staticmethod] - #[args(null_value = "Complex64::zero()")] - #[pyo3(text_signature = "(matrix, /, null_value=0.0+0.0j)")] + #[pyo3(signature=(matrix, null_value=Complex64::zero()), text_signature = "(matrix, /, null_value=0.0+0.0j)")] pub fn from_complex_adjacency_matrix<'p>( py: Python<'p>, matrix: PyReadonlyArray2<'p, Complex64>, @@ -1629,8 +1627,7 @@ impl PyGraph { /// the other. /// :rtype: PyGraph /// - #[args(preserve_attrs = "false")] - #[pyo3(text_signature = "(self, nodes, /, preserve_attrs=False)")] + #[pyo3(signature=(nodes, preserve_attrs=false), text_signature = "(self, nodes, /, preserve_attrs=False)")] pub fn subgraph(&self, py: Python, nodes: Vec, preserve_attrs: bool) -> PyGraph { let node_set: HashSet = nodes.iter().cloned().collect(); let mut node_map: HashMap = HashMap::with_capacity(nodes.len()); diff --git a/src/isomorphism/mod.rs b/src/isomorphism/mod.rs index 5dc8466db..6e48f1f10 100644 --- a/src/isomorphism/mod.rs +++ b/src/isomorphism/mod.rs @@ -57,8 +57,9 @@ use pyo3::Python; /// :returns: ``True`` if the 2 graphs are isomorphic ``False`` if they are /// not. /// :rtype: bool -#[pyfunction(id_order = "true")] +#[pyfunction] #[pyo3( + signature=(first, second, node_matcher=None, edge_matcher=None, id_order=true, call_limit=None), text_signature = "(first, second, /, node_matcher=None, edge_matcher=None, id_order=True, call_limit=None)" )] @@ -120,8 +121,9 @@ pub fn digraph_is_isomorphic( /// :returns: ``True`` if the 2 graphs are isomorphic ``False`` if they are /// not. /// :rtype: bool -#[pyfunction(id_order = "true")] +#[pyfunction] #[pyo3( + signature=(first, second, node_matcher=None, edge_matcher=None, id_order=true, call_limit=None), text_signature = "(first, second, /, node_matcher=None, edge_matcher=None, id_order=True, call_limit=None)" )] @@ -190,8 +192,9 @@ pub fn graph_is_isomorphic( /// :returns: ``True`` if there is a subgraph of `first` isomorphic to `second`, /// ``False`` if there is not. /// :rtype: bool -#[pyfunction(id_order = "false", induced = "true")] +#[pyfunction] #[pyo3( + signature=(first, second, node_matcher=None, edge_matcher=None, id_order=false, induced=true, call_limit=None), text_signature = "(first, second, /, node_matcher=None, edge_matcher=None, id_order=False, induced=True, call_limit=None)" )] @@ -261,8 +264,9 @@ pub fn digraph_is_subgraph_isomorphic( /// :returns: ``True`` if there is a subgraph of `first` isomorphic to `second`, /// ``False`` if there is not. /// :rtype: bool -#[pyfunction(id_order = "false", induced = "true")] +#[pyfunction] #[pyo3( + signature=(first, second, node_matcher=None, edge_matcher=None, id_order=false, induced=true, call_limit=None), text_signature = "(first, second, /, node_matcher=None, edge_matcher=None, id_order=False, induced=True, call_limit=None)" )] @@ -332,8 +336,9 @@ pub fn graph_is_subgraph_isomorphic( /// :returns: An iterator over dicitonaries of node indices from ``first`` to node /// indices in ``second`` representing the mapping found. /// :rtype: Iterable[NodeMap] -#[pyfunction(id_order = "true", subgraph = "false", induced = "true")] +#[pyfunction] #[pyo3( + signature=(first, second, node_matcher=None, edge_matcher=None, id_order=true, subgraph=false, induced=true, call_limit=None), text_signature = "(first, second, /, node_matcher=None, edge_matcher=None, id_order=True, subgraph=False, induced=True, call_limit=None)" )] @@ -409,8 +414,9 @@ pub fn digraph_vf2_mapping( /// :returns: An iterator over dicitonaries of node indices from ``first`` to node /// indices in ``second`` representing the mapping found. /// :rtype: Iterable[NodeMap] -#[pyfunction(id_order = "true", subgraph = "false", induced = "true")] +#[pyfunction] #[pyo3( + signature=(first, second, node_matcher=None, edge_matcher=None, id_order=true, subgraph=false, induced=true, call_limit=None), text_signature = "(first, second, /, node_matcher=None, edge_matcher=None, id_order=True, subgraph=False, induced=True, call_limit=None)" )] diff --git a/src/layout/mod.rs b/src/layout/mod.rs index ba6f66982..818103661 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -71,6 +71,7 @@ use crate::iterators::Pos2DMapping; /// :rtype: dict #[pyfunction] #[pyo3( + signature=(graph, pos=None, fixed=None, k=None, repulsive_exponent=2, adaptive_cooling=true, num_iter=50, tol=1e-6, weight_fn=None, default_weight=1., scale=1., center=None, seed=None), text_signature = "(graph, pos=None, fixed=None, k=None, repulsive_exponent=2, adaptive_cooling=True, num_iter=50, tol=1e-6, weight_fn=None, default_weight=1, scale=1, center=None, seed=None, /)" @@ -82,13 +83,13 @@ pub fn graph_spring_layout( pos: Option>, fixed: Option>, k: Option, - repulsive_exponent: Option, - adaptive_cooling: Option, - num_iter: Option, - tol: Option, + repulsive_exponent: i32, + adaptive_cooling: bool, + num_iter: usize, + tol: f64, weight_fn: Option, default_weight: f64, - scale: Option, + scale: f64, center: Option, seed: Option, ) -> PyResult { @@ -98,13 +99,13 @@ pub fn graph_spring_layout( pos, fixed, k, - repulsive_exponent, - adaptive_cooling, - num_iter, - tol, + Some(repulsive_exponent), + Some(adaptive_cooling), + Some(num_iter), + Some(tol), weight_fn, default_weight, - scale, + Some(scale), center, seed, ) @@ -154,6 +155,7 @@ pub fn graph_spring_layout( /// :rtype: dict #[pyfunction] #[pyo3( + signature=(graph, pos=None, fixed=None, k=None, repulsive_exponent=2, adaptive_cooling=true, num_iter=50, tol=1e-6, weight_fn=None, default_weight=1., scale=1., center=None, seed=None), text_signature = "(graph, pos=None, fixed=None, k=None, repulsive_exponent=2, adaptive_cooling=True, num_iter=50, tol=1e-6, weight_fn=None, default_weight=1, scale=1, center=None, seed=None, /)" @@ -165,13 +167,13 @@ pub fn digraph_spring_layout( pos: Option>, fixed: Option>, k: Option, - repulsive_exponent: Option, - adaptive_cooling: Option, - num_iter: Option, + repulsive_exponent: i32, + adaptive_cooling: bool, + num_iter: usize, tol: Option, weight_fn: Option, default_weight: f64, - scale: Option, + scale: f64, center: Option, seed: Option, ) -> PyResult { @@ -181,13 +183,13 @@ pub fn digraph_spring_layout( pos, fixed, k, - repulsive_exponent, - adaptive_cooling, - num_iter, + Some(repulsive_exponent), + Some(adaptive_cooling), + Some(num_iter), tol, weight_fn, default_weight, - scale, + Some(scale), center, seed, ) diff --git a/src/matching/mod.rs b/src/matching/mod.rs index f6738ac4c..fac47e973 100644 --- a/src/matching/mod.rs +++ b/src/matching/mod.rs @@ -64,12 +64,9 @@ use crate::weight_callable; /// .. [1] "Efficient Algorithms for Finding Maximum Matching in Graphs", /// Zvi Galil, ACM Computing Surveys, 1986. /// -#[pyfunction( - max_cardinality = "false", - default_weight = 1, - verify_optimum = "false" -)] +#[pyfunction] #[pyo3( + signature=(graph, max_cardinality=false, weight_fn=None, default_weight=1, verify_optimum=false), text_signature = "(graph, /, max_cardinality=False, weight_fn=None, default_weight=1, verify_optimum=False)" )] pub fn max_weight_matching( diff --git a/src/random_graph.rs b/src/random_graph.rs index dd97f33de..408544064 100644 --- a/src/random_graph.rs +++ b/src/random_graph.rs @@ -434,8 +434,11 @@ fn distance(x: &[f64], y: &[f64], p: f64) -> f64 { /// /// :return: A PyGraph object /// :rtype: PyGraph -#[pyfunction(dim = "2", p = "2.0")] -#[pyo3(text_signature = "(num_nodes, radius, /, dim=2, pos=None, p=2.0, seed=None)")] +#[pyfunction] +#[pyo3( + signature=(num_nodes, radius, dim=2, pos=None, p=2.0, seed=None), + text_signature = "(num_nodes, radius, /, dim=2, pos=None, p=2.0, seed=None)" +)] pub fn random_geometric_graph( py: Python, num_nodes: usize, diff --git a/src/shortest_path/mod.rs b/src/shortest_path/mod.rs index f03eeaa7d..229741da5 100644 --- a/src/shortest_path/mod.rs +++ b/src/shortest_path/mod.rs @@ -64,8 +64,11 @@ use crate::iterators::{ /// :rtype: dict /// :raises ValueError: when an edge weight with NaN or negative value /// is provided. -#[pyfunction(default_weight = "1.0", as_undirected = "false")] -#[pyo3(text_signature = "(graph, source, /, target=None weight_fn=None, default_weight=1.0)")] +#[pyfunction] +#[pyo3( + signature=(graph, source, target=None, weight_fn=None, default_weight=1.0), + text_signature = "(graph, source, /, target=None weight_fn=None, default_weight=1.0)" +)] pub fn graph_dijkstra_shortest_paths( py: Python, graph: &graph::PyGraph, @@ -127,8 +130,9 @@ pub fn graph_dijkstra_shortest_paths( /// :rtype: dict /// :raises ValueError: when an edge weight with NaN or negative value /// is provided. -#[pyfunction(default_weight = "1.0", as_undirected = "false")] +#[pyfunction] #[pyo3( + signature=(graph, source, target=None, weight_fn=None, default_weight=1.0, as_undirected=false), text_signature = "(graph, source, /, target=None weight_fn=None, default_weight=1.0, as_undirected=False)" )] pub fn digraph_dijkstra_shortest_paths( @@ -745,12 +749,9 @@ pub fn graph_k_shortest_path_lengths( /// } /// /// :rtype: AllPairsPathLengthMapping -#[pyfunction( - parallel_threshold = "300", - as_undirected = "false", - default_weight = "1.0" -)] +#[pyfunction] #[pyo3( + signature=(graph, weight_fn=None, as_undirected=false, default_weight=1.0, parallel_threshold=300), text_signature = "(graph, /, weight_fn=None, as_undirected=False, default_weight=1.0, parallel_threshold=300)" )] pub fn digraph_floyd_warshall( @@ -811,8 +812,11 @@ pub fn digraph_floyd_warshall( /// } /// /// :rtype: AllPairsPathLengthMapping -#[pyfunction(parallel_threshold = "300", default_weight = "1.0")] -#[pyo3(text_signature = "(graph, /, weight_fn=None, default_weight=1.0, parallel_threshold=300)")] +#[pyfunction] +#[pyo3( + signature=(graph, weight_fn=None, default_weight=1.0, parallel_threshold=300), + text_signature = "(graph, /, weight_fn=None, default_weight=1.0, parallel_threshold=300)" +)] pub fn graph_floyd_warshall( py: Python, graph: &graph::PyGraph, @@ -864,8 +868,11 @@ pub fn graph_floyd_warshall( /// path between two nodes then the corresponding matrix entry will be /// ``np.inf``. /// :rtype: numpy.ndarray -#[pyfunction(parallel_threshold = "300", default_weight = "1.0")] -#[pyo3(text_signature = "(graph, /, weight_fn=None, default_weight=1.0, parallel_threshold=300)")] +#[pyfunction] +#[pyo3( + signature=(graph, weight_fn=None, default_weight=1.0, parallel_threshold=300), + text_signature = "(graph, /, weight_fn=None, default_weight=1.0, parallel_threshold=300)" +)] pub fn graph_floyd_warshall_numpy( py: Python, graph: &graph::PyGraph, @@ -919,12 +926,9 @@ pub fn graph_floyd_warshall_numpy( /// path between two nodes then the corresponding matrix entry will be /// ``np.inf``. /// :rtype: numpy.ndarray -#[pyfunction( - parallel_threshold = "300", - as_undirected = "false", - default_weight = "1.0" -)] +#[pyfunction] #[pyo3( + signature=(graph, weight_fn=None, as_undirected=false, default_weight=1.0, parallel_threshold=300), text_signature = "(graph, /, weight_fn=None, as_undirected=False, default_weight=1.0, parallel_threshold=300)" )] pub fn digraph_floyd_warshall_numpy( @@ -1010,12 +1014,11 @@ pub fn graph_num_shortest_paths_unweighted( /// /// :returns: The distance matrix /// :rtype: numpy.ndarray -#[pyfunction( - parallel_threshold = "300", - as_undirected = "false", - null_value = "0.0" +#[pyfunction] +#[pyo3( + signature=(graph, parallel_threshold=300, as_undirected=false, null_value=0.0), + text_signature = "(graph, /, parallel_threshold=300, as_undirected=False, null_value=0.0)" )] -#[pyo3(text_signature = "(graph, /, parallel_threshold=300, as_undirected=False, null_value=0.0)")] pub fn digraph_distance_matrix( py: Python, graph: &digraph::PyDiGraph, @@ -1039,7 +1042,7 @@ pub fn digraph_distance_matrix( /// distance of 1. /// /// This function is also multithreaded and will run in parallel if the number -/// of nodes in the graph is above the value of ``paralllel_threshold`` (it +/// of nodes in the graph is above the value of ``parallel_threshold`` (it /// defaults to 300). If the function will be running in parallel the env var /// ``RAYON_NUM_THREADS`` can be used to adjust how many threads will be used. /// @@ -1053,8 +1056,11 @@ pub fn digraph_distance_matrix( /// /// :returns: The distance matrix /// :rtype: numpy.ndarray -#[pyfunction(parallel_threshold = "300", null_value = "0.0")] -#[pyo3(text_signature = "(graph, /, parallel_threshold=300, null_value=0.0)")] +#[pyfunction] +#[pyo3( + signature=(graph, parallel_threshold=300, null_value=0.0), + text_signature = "(graph, /, parallel_threshold=300, null_value=0.0)" +)] pub fn graph_distance_matrix( py: Python, graph: &graph::PyGraph, @@ -1106,12 +1112,9 @@ pub fn graph_distance_matrix( /// :returns: The average shortest path length. If no vertex pairs can be included /// in the calculation this will return NaN. /// :rtype: float -#[pyfunction( - parallel_threshold = "300", - as_undirected = "false", - disconnected = "false" -)] +#[pyfunction] #[pyo3( + signature=(graph, parallel_threshold=300, as_undirected=false, disconnected=false), text_signature = "(graph, /, parallel_threshold=300, as_undirected=False, disconnected=False)" )] pub fn digraph_unweighted_average_shortest_path_length( @@ -1173,8 +1176,11 @@ pub fn digraph_unweighted_average_shortest_path_length( /// :returns: The average shortest path length. If no vertex pairs can be included /// in the calculation this will return NaN. /// :rtype: float -#[pyfunction(parallel_threshold = "300", disconnected = "false")] -#[pyo3(text_signature = "(graph, /, parallel_threshold=300, disconnected=False)")] +#[pyfunction] +#[pyo3( + signature=(graph, parallel_threshold=300, disconnected=false), + text_signature = "(graph, /, parallel_threshold=300, disconnected=False)" +)] pub fn graph_unweighted_average_shortest_path_length( graph: &graph::PyGraph, parallel_threshold: usize, @@ -1380,8 +1386,11 @@ pub fn graph_bellman_ford_shortest_path_lengths( /// /// :raises: :class:`~rustworkx.NegativeCycle`: when there is a negative cycle and the shortest /// path is not defined. -#[pyfunction(default_weight = "1.0", as_undirected = "false")] -#[pyo3(text_signature = "(graph, source, /, target=None, weight_fn=None, default_weight=1.0)")] +#[pyfunction] +#[pyo3( + signature=(graph, source, target=None, weight_fn=None, default_weight=1.0), + text_signature = "(graph, source, /, target=None, weight_fn=None, default_weight=1.0)" +)] pub fn graph_bellman_ford_shortest_paths( py: Python, graph: &graph::PyGraph, @@ -1451,8 +1460,9 @@ pub fn graph_bellman_ford_shortest_paths( /// /// :raises: :class:`~rustworkx.NegativeCycle`: when there is a negative cycle and the shortest /// path is not defined. -#[pyfunction(default_weight = "1.0", as_undirected = "false")] +#[pyfunction] #[pyo3( + signature=(graph, source, target=None, weight_fn=None, default_weight=1.0, as_undirected=false), text_signature = "(graph, source, /, target=None, weight_fn=None, default_weight=1.0, as_undirected=False)" )] pub fn digraph_bellman_ford_shortest_paths( diff --git a/src/toposort.rs b/src/toposort.rs index 8c80f9da3..7dcb1932a 100644 --- a/src/toposort.rs +++ b/src/toposort.rs @@ -75,7 +75,7 @@ pub struct TopologicalSorter { #[pymethods] impl TopologicalSorter { #[new] - #[args(check_cycle = "true")] + #[pyo3(signature=(dag, check_cycle=true))] fn new(py: Python, dag: Py, check_cycle: bool) -> PyResult { { let dag = &dag.borrow(py); diff --git a/src/traversal/mod.rs b/src/traversal/mod.rs index 8f27cad86..f92b95bd9 100644 --- a/src/traversal/mod.rs +++ b/src/traversal/mod.rs @@ -28,6 +28,7 @@ use std::convert::TryFrom; use hashbrown::HashSet; +use pyo3::exceptions::PyTypeError; use pyo3::prelude::*; use pyo3::Python; @@ -284,14 +285,20 @@ pub fn descendants(graph: &digraph::PyDiGraph, node: usize) -> HashSet { /// graph are searched. /// :param visitor: A visitor object that is invoked at the event points inside the /// algorithm. This should be a subclass of :class:`~rustworkx.visit.BFSVisitor`. +/// This has a default value of ``None`` as a backwards compatibility artifact (to +/// preserve argument ordering from an earlier version) but it is a required argument +/// and will raise a ``TypeError`` if not specified. #[pyfunction] -#[pyo3(text_signature = "(graph, source, visitor)")] pub fn digraph_bfs_search( py: Python, graph: &digraph::PyDiGraph, source: Option>, - visitor: PyBfsVisitor, + visitor: Option, ) -> PyResult<()> { + if visitor.is_none() { + return Err(PyTypeError::new_err("Missing required argument visitor")); + } + let visitor = visitor.unwrap(); let starts: Vec<_> = match source { Some(nx) => nx.into_iter().map(NodeIndex::new).collect(), None => graph.graph.node_indices().collect(), @@ -370,14 +377,20 @@ pub fn digraph_bfs_search( /// graph are searched. /// :param visitor: A visitor object that is invoked at the event points inside the /// algorithm. This should be a subclass of :class:`~rustworkx.visit.BFSVisitor`. +/// This has a default value of ``None`` as a backwards compatibility artifact (to +/// preserve argument ordering from an earlier version) but it is a required argument +/// and will raise a ``TypeError`` if not specified. #[pyfunction] -#[pyo3(text_signature = "(graph, source, visitor)")] pub fn graph_bfs_search( py: Python, graph: &graph::PyGraph, source: Option>, - visitor: PyBfsVisitor, + visitor: Option, ) -> PyResult<()> { + if visitor.is_none() { + return Err(PyTypeError::new_err("Missing required argument visitor")); + } + let visitor = visitor.unwrap(); let starts: Vec<_> = match source { Some(nx) => nx.into_iter().map(NodeIndex::new).collect(), None => graph.graph.node_indices().collect(), @@ -454,14 +467,20 @@ pub fn graph_bfs_search( /// graph are searched. /// :param visitor: A visitor object that is invoked at the event points inside the /// algorithm. This should be a subclass of :class:`~rustworkx.visit.DFSVisitor`. +/// This has a default value of ``None`` as a backwards compatibility artifact (to +/// preserve argument ordering from an earlier version) but it is a required argument +/// and will raise a ``TypeError`` if not specified. #[pyfunction] -#[pyo3(text_signature = "(graph, source, visitor)")] pub fn digraph_dfs_search( py: Python, graph: &digraph::PyDiGraph, source: Option>, - visitor: PyDfsVisitor, + visitor: Option, ) -> PyResult<()> { + if visitor.is_none() { + return Err(PyTypeError::new_err("Missing required argument visitor")); + } + let visitor = visitor.unwrap(); let starts: Vec<_> = match source { Some(nx) => nx.into_iter().map(NodeIndex::new).collect(), None => graph.graph.node_indices().collect(), @@ -538,14 +557,20 @@ pub fn digraph_dfs_search( /// graph are searched. /// :param visitor: A visitor object that is invoked at the event points inside the /// algorithm. This should be a subclass of :class:`~rustworkx.visit.DFSVisitor`. +/// This has a default value of ``None`` as a backwards compatibility artifact (to +/// preserve argument ordering from an earlier version) but it is a required argument +/// and will raise a ``TypeError`` if not specified. #[pyfunction] -#[pyo3(text_signature = "(graph, source, visitor)")] pub fn graph_dfs_search( py: Python, graph: &graph::PyGraph, source: Option>, - visitor: PyDfsVisitor, + visitor: Option, ) -> PyResult<()> { + if visitor.is_none() { + return Err(PyTypeError::new_err("Missing required argument visitor")); + } + let visitor = visitor.unwrap(); let starts: Vec<_> = match source { Some(nx) => nx.into_iter().map(NodeIndex::new).collect(), None => graph.graph.node_indices().collect(), @@ -608,15 +633,21 @@ pub fn graph_dfs_search( /// a default value of cost ``1.0`` will be used for each edge. /// :param visitor: A visitor object that is invoked at the event points inside the /// algorithm. This should be a subclass of :class:`~rustworkx.visit.DijkstraVisitor`. +/// This has a default value of ``None`` as a backwards compatibility artifact (to +/// preserve argument ordering from an earlier version) but it is a required argument +/// and will raise a ``TypeError`` if not specified. #[pyfunction] -#[pyo3(text_signature = "(graph, source, weight_fn, visitor)")] pub fn digraph_dijkstra_search( py: Python, graph: &digraph::PyDiGraph, source: Option>, weight_fn: Option, - visitor: PyDijkstraVisitor, + visitor: Option, ) -> PyResult<()> { + if visitor.is_none() { + return Err(PyTypeError::new_err("Missing required argument visitor")); + } + let visitor = visitor.unwrap(); let starts: Vec<_> = match source { Some(nx) => nx.into_iter().map(NodeIndex::new).collect(), None => graph.graph.node_indices().collect(), @@ -683,15 +714,21 @@ pub fn digraph_dijkstra_search( /// a default value of cost ``1.0`` will be used for each edge. /// :param visitor: A visitor object that is invoked at the event points inside the /// algorithm. This should be a subclass of :class:`~rustworkx.visit.DijkstraVisitor`. +/// This has a default value of ``None`` as a backwards compatibility artifact (to +/// preserve argument ordering from an earlier version) but it is a required argument +/// and will raise a ``TypeError`` if not specified. #[pyfunction] -#[pyo3(text_signature = "(graph, source, weight_fn, visitor)")] pub fn graph_dijkstra_search( py: Python, graph: &graph::PyGraph, source: Option>, weight_fn: Option, - visitor: PyDijkstraVisitor, + visitor: Option, ) -> PyResult<()> { + if visitor.is_none() { + return Err(PyTypeError::new_err("Missing required argument visitor")); + } + let visitor = visitor.unwrap(); let starts: Vec<_> = match source { Some(nx) => nx.into_iter().map(NodeIndex::new).collect(), None => graph.graph.node_indices().collect(), diff --git a/src/tree.rs b/src/tree.rs index edcd3f95f..11e2ba5b6 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -49,8 +49,8 @@ use crate::iterators::WeightedEdgeList; /// :returns: The :math:`N - |c|` edges of the Minimum Spanning Tree (or Forest, if :math:`|c| > 1`) /// where :math:`N` is the number of nodes and :math:`|c|` is the number of connected components of the graph /// :rtype: WeightedEdgeList -#[pyfunction(weight_fn = "None", default_weight = "1.0")] -#[pyo3(text_signature = "(graph, weight_fn=None, default_weight=1.0)")] +#[pyfunction] +#[pyo3(signature=(graph, weight_fn=None, default_weight=1.0), text_signature = "(graph, weight_fn=None, default_weight=1.0)")] pub fn minimum_spanning_edges( py: Python, graph: &graph::PyGraph, @@ -115,8 +115,8 @@ pub fn minimum_spanning_edges( /// .. note:: /// /// The new graph will keep the same node indices, but edge indices might differ. -#[pyfunction(weight_fn = "None", default_weight = "1.0")] -#[pyo3(text_signature = "(graph, weight_fn=None, default_weight=1.0)")] +#[pyfunction] +#[pyo3(signature=(graph, weight_fn=None, default_weight=1.0), text_signature = "(graph, weight_fn=None, default_weight=1.0)")] pub fn minimum_spanning_tree( py: Python, graph: &graph::PyGraph, diff --git a/src/union.rs b/src/union.rs index c6d3e81a1..7861ac804 100644 --- a/src/union.rs +++ b/src/union.rs @@ -124,8 +124,8 @@ fn union( /// ``first``. It's worth noting the weight/data payload objects are /// passed by reference from ``first`` and ``second`` to this new object. /// :rtype: PyGraph -#[pyfunction(merge_nodes = false, merge_edges = false)] -#[pyo3(text_signature = "(first, second, /, merge_nodes=False, merge_edges=False)")] +#[pyfunction] +#[pyo3(signature=(first, second, merge_nodes=false, merge_edges=false), text_signature = "(first, second, /, merge_nodes=False, merge_edges=False)")] pub fn graph_union( py: Python, first: &graph::PyGraph, @@ -173,8 +173,8 @@ pub fn graph_union( /// ``first``. It's worth noting the weight/data payload objects are /// passed by reference from ``first`` and ``second`` to this new object. /// :rtype: PyDiGraph -#[pyfunction(merge_nodes = false, merge_edges = false)] -#[pyo3(text_signature = "(first, second, /, merge_nodes=False, merge_edges=False)")] +#[pyfunction] +#[pyo3(signature=(first, second, merge_nodes=false, merge_edges=false), text_signature = "(first, second, /, merge_nodes=False, merge_edges=False)")] pub fn digraph_union( py: Python, first: &digraph::PyDiGraph,