Skip to content

Commit 0ea1c92

Browse files
authored
Preparing for 1.2.2 and updating versions (#46)
* Update build.yml * Update pyproject.toml Expanding our supported python trove identifiers to include python 3.13 * Update Cargo.toml Updating pyo3 from 0.15 to 0.23 * Update pyproject.toml Moving 3.6 and 3.7 to EOL (since not only they, but even 3.8 are EOL. pyo3 currently does not support abi3-py36, and I'm betting 3.7 is going to follow suit sometime soon.) * Update Cargo.toml abi3-py36 changing to abi3-py38 * Updated a bunch of versions. Pyo3 changed fairly substantially in signature specification for python. Also updated my first name everywhere. * Updating versions, running clippy, yanking the logging nonsense that was never used and never should be used (there have to be better ways than that nonsense), and about to have clippy fix my convention of always using a return statement because I hate implicit returns but that's a me thing not a world thing * More clippy fixes * More clippy suggestions. It's like I never ran this before. * Adding ipython and networkx as dev deps. `cd packages/pyo3 && uv sync && uv run ipython` get you to a reasonable repl for manual testing. I cannot believe I did not do proper python testing here. Maybe I did it in graspologic? * Running cargo fmt * Misspelled repetition, which I have also repetitively done in this commit message alone * Committing some minor changes before I rebase on dev. I forgot the dev/main branching scheme. * Updating the pyproject.toml to be correct as per the current pypa specification. I really hope this doesn't break older versions. * Fixing the changes clippy made to some of the commonmark documentation in the function. Too much was being treated as a quoted paragraph.
1 parent 10ef0a1 commit 0ea1c92

33 files changed

+550
-517
lines changed

.github/workflows/build.yml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ jobs:
1212
runs-on: "ubuntu-latest"
1313
steps:
1414
- uses: actions/checkout@v4
15-
- name: Set up Python 3.8
15+
- name: Set up Python 3.12
1616
uses: actions/setup-python@v5
1717
with:
18-
python-version: 3.8
18+
python-version: 3.12
1919
- name: Materialize build number
2020
run: |
2121
pip install -U pip
@@ -38,10 +38,10 @@ jobs:
3838
os: ["ubuntu-latest", "windows-latest", "macos-latest"]
3939
steps:
4040
- uses: actions/checkout@v4
41-
- name: Set up Python 3.9
41+
- name: Set up Python 3.12
4242
uses: actions/setup-python@v5
4343
with:
44-
python-version: 3.9
44+
python-version: 3.12
4545
- uses: actions/download-artifact@v4
4646
with:
4747
name: cargo-toml
@@ -106,10 +106,10 @@ jobs:
106106
if: github.ref=='refs/heads/main' || github.ref=='refs/heads/dev'
107107
steps:
108108
- uses: actions/checkout@v4
109-
- name: Set up Python 3.8
109+
- name: Set up Python 3.12
110110
uses: actions/setup-python@v2
111111
with:
112-
python-version: 3.8
112+
python-version: 3.12
113113
- uses: actions/download-artifact@v4
114114
with:
115115
name: dist-ubuntu-latest

.rustfmt.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
1-
fn_args_layout = "vertical"
2-
empty_item_single_line = false
1+
fn_params_layout = "vertical"
32

clippy.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
too-many-arguments-threshold=20 # for what it is worth, clippy is absolutely right and pythonic-ness is absolutely wrong
2+
enum-variant-name-threshold=10 # it doesn't like the repetition in "Error" in my export-to-python error types
File renamed without changes.

packages/cli/Cargo.toml

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,13 @@
11
[package]
22
name = "cli"
3-
version = "0.1.0"
4-
authors = ["Dwayne Pryce <dwpryce@microsoft.com>"]
3+
version = "0.1.1"
4+
authors = ["Dax Pryce <daxpryce@microsoft.com>"]
55
edition = "2018"
66
license = "MIT"
77
description = "CLI Runner for the topologic associated crates (network_partitions and eventually network_automatic_layouts)"
88

99
[dependencies]
10-
clap = "2.34"
10+
clap = "4.5"
1111
rand = "0.8"
1212
rand_xorshift = "0.3"
1313
network_partitions={path = "../network_partitions"}
14-
15-
[features]
16-
logging = ["network_partitions/logging"]

packages/cli/src/args.rs

Lines changed: 23 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -33,27 +33,30 @@ pub struct CliArgs {
3333
pub skip_first_line: bool,
3434
}
3535

36-
impl TryFrom<ArgMatches<'_>> for CliArgs {
36+
impl TryFrom<ArgMatches> for CliArgs {
3737
type Error = ParseCliError;
3838

39-
fn try_from(matches: ArgMatches<'_>) -> Result<Self, Self::Error> {
40-
let source_edges = matches
41-
.value_of(SOURCE_EDGES)
39+
fn try_from(matches: ArgMatches) -> Result<Self, Self::Error> {
40+
let source_edges: &str = matches
41+
.get_one(SOURCE_EDGES)
42+
.cloned()
4243
.ok_or(ParseCliError::RequiredValueError)?;
43-
let output = matches
44-
.value_of(OUTPUT)
44+
let output: &str = matches
45+
.get_one(OUTPUT)
46+
.cloned()
4547
.ok_or(ParseCliError::RequiredValueError)?;
46-
let separator = matches
47-
.value_of(SEPARATOR)
48+
let separator: &str = matches
49+
.get_one(SEPARATOR)
50+
.cloned()
4851
.ok_or(ParseCliError::RequiredValueError)?;
49-
let source_index: usize = matches.value_of(SOURCE_INDEX).as_a()?;
50-
let target_index: usize = matches.value_of(TARGET_INDEX).as_a()?;
51-
let weight_index: Option<usize> = matches.value_of(WEIGHT_INDEX).as_a()?;
52-
let seed: Option<usize> = matches.value_of(SEED).as_a()?;
53-
let iterations: usize = matches.value_of(ITERATIONS).as_a()?;
54-
let resolution: f64 = matches.value_of(RESOLUTION).as_a()?;
55-
let randomness: f64 = matches.value_of(RANDOMNESS).as_a()?;
56-
let quality_option: Option<&str> = matches.value_of(QUALITY);
52+
let source_index: usize = *matches.get_one(SOURCE_INDEX).unwrap();
53+
let target_index: usize = *matches.get_one(TARGET_INDEX).unwrap();
54+
let weight_index: Option<usize> = matches.get_one(WEIGHT_INDEX).copied();
55+
let seed: Option<usize> = matches.get_one(SEED).cloned();
56+
let iterations: usize = *matches.get_one(ITERATIONS).unwrap();
57+
let resolution: f64 = *matches.get_one(RESOLUTION).unwrap();
58+
let randomness: f64 = *matches.get_one(RANDOMNESS).unwrap();
59+
let quality_option: Option<&str> = matches.get_one(QUALITY).cloned();
5760
let use_modularity: bool = match quality_option {
5861
Some(quality_value) => {
5962
if quality_value == "cpm" {
@@ -66,7 +69,7 @@ impl TryFrom<ArgMatches<'_>> for CliArgs {
6669
}
6770
None => Err(ParseCliError::RequiredValueError),
6871
}?;
69-
let skip_first_line: bool = matches.is_present(HAS_HEADER);
72+
let skip_first_line: bool = matches.contains_id(HAS_HEADER);
7073
let cli_args: CliArgs = CliArgs {
7174
source_edges: source_edges.into(),
7275
output_path: output.into(),
@@ -81,7 +84,7 @@ impl TryFrom<ArgMatches<'_>> for CliArgs {
8184
use_modularity,
8285
skip_first_line,
8386
};
84-
return Ok(cli_args);
87+
Ok(cli_args)
8588
}
8689
}
8790

@@ -94,43 +97,12 @@ pub enum ParseCliError {
9497

9598
impl From<ParseFloatError> for ParseCliError {
9699
fn from(_: ParseFloatError) -> Self {
97-
return ParseCliError::NotANumber;
100+
ParseCliError::NotANumber
98101
}
99102
}
100103

101104
impl From<ParseIntError> for ParseCliError {
102105
fn from(_: ParseIntError) -> Self {
103-
return ParseCliError::NotANumber;
104-
}
105-
}
106-
107-
trait As<T> {
108-
fn as_a(&self) -> Result<T, ParseCliError>;
109-
}
110-
111-
impl As<f64> for Option<&str> {
112-
fn as_a(&self) -> Result<f64, ParseCliError> {
113-
self.map(|cli_arg| cli_arg.parse::<f64>().unwrap())
114-
.ok_or(ParseCliError::RequiredValueError)
115-
}
116-
}
117-
118-
impl As<usize> for Option<&str> {
119-
fn as_a(&self) -> Result<usize, ParseCliError> {
120-
self.map(|cli_arg| cli_arg.parse::<usize>().unwrap())
121-
.ok_or(ParseCliError::RequiredValueError)
122-
}
123-
}
124-
125-
impl As<Option<usize>> for Option<&str> {
126-
fn as_a(&self) -> Result<Option<usize>, ParseCliError> {
127-
let result = match self {
128-
Some(cli_arg) => {
129-
let parse_result = cli_arg.parse::<usize>();
130-
Ok(parse_result.map(|value| Some(value))?)
131-
}
132-
None => Ok(None),
133-
};
134-
return result;
106+
ParseCliError::NotANumber
135107
}
136108
}

packages/cli/src/leiden.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,9 @@ pub fn leiden(
7575
let mut output_file: File =
7676
File::create(output_path).expect("Unable to open output file for writing");
7777
for item in &clustering {
78-
write!(
78+
writeln!(
7979
output_file,
80-
"{},{}\n",
80+
"{},{}",
8181
labeled_network.label_for(item.node_id),
8282
item.cluster
8383
)

packages/cli/src/main.rs

Lines changed: 28 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
// Copyright (c) Microsoft Corporation.
22
// Licensed under the MIT license.
33

4-
#![feature(in_band_lifetimes)]
5-
use clap::{App, Arg};
4+
use clap::{Arg, ArgAction, Command};
65
use std::convert::TryFrom;
76

87
mod args;
@@ -11,83 +10,82 @@ mod leiden;
1110
use crate::args::*;
1211

1312
fn main() {
14-
let matches = App::new("leiden_cli")
13+
let matches = Command::new("leiden_cli")
1514
.version("0.1.0")
1615
.author("Dwayne Pryce <[email protected]>")
1716
.about("Runs leiden over a provided edge list and outputs the results")
1817
.arg(
19-
Arg::with_name(SOURCE_EDGES)
18+
Arg::new(SOURCE_EDGES)
2019
.help("The edge list that defines the graph's connections")
2120
.required(true)
2221
.index(1),
2322
)
2423
.arg(
25-
Arg::with_name(OUTPUT)
24+
Arg::new(OUTPUT)
2625
.help("The output for the communities detected")
2726
.required(true)
2827
.index(2),
2928
)
3029
.arg(
31-
Arg::with_name(SEPARATOR)
32-
.short("s")
30+
Arg::new(SEPARATOR)
31+
.short('s')
3332
.help("The character to split the edge list on")
34-
.takes_value(true)
33+
.action(ArgAction::Set)
3534
.default_value("\t"),
3635
)
3736
.arg(
38-
Arg::with_name(SOURCE_INDEX)
39-
.takes_value(true)
37+
Arg::new(SOURCE_INDEX)
38+
.action(ArgAction::Set)
4039
.help("0-based index of source column from edge file")
4140
.default_value("0"),
4241
)
4342
.arg(
44-
Arg::with_name(TARGET_INDEX)
45-
.takes_value(true)
43+
Arg::new(TARGET_INDEX)
44+
.action(ArgAction::Set)
4645
.help("0-based index of target column from edge file")
4746
.default_value("1"),
4847
)
4948
.arg(
50-
Arg::with_name(WEIGHT_INDEX)
51-
.takes_value(true)
49+
Arg::new(WEIGHT_INDEX)
50+
.action(ArgAction::Set)
5251
.help("0-based index of weight column from edge file")
5352
)
5453
.arg(
55-
Arg::with_name(SEED)
56-
.takes_value(true)
54+
Arg::new(SEED)
55+
.action(ArgAction::Set)
5756
.help("A seed value to start the PRNG")
5857
.long("seed"),
5958
)
6059
.arg(
61-
Arg::with_name(ITERATIONS)
62-
.takes_value(true)
60+
Arg::new(ITERATIONS)
61+
.action(ArgAction::Set)
6362
.help("Leiden is an inherently recursive algorithm, however it may find itself (due to randomness) at a localized maximum. Setting iterations to a number larger than 1 may allow you to jump out of a local maximum and continue until a better optimum partitioning is found (note that any n > 1 will mean that leiden will be run again for a minimum of n-1 more times, though it may be run for many more than that")
64-
.short("i")
63+
.short('i')
6564
.default_value("1"),
6665
)
6766
.arg(
68-
Arg::with_name(RESOLUTION)
69-
.takes_value(true)
67+
Arg::new(RESOLUTION)
68+
.action(ArgAction::Set)
7069
.help("")
71-
.short("r")
70+
.short('r')
7271
.default_value("1.0")
7372
)
7473
.arg(
75-
Arg::with_name(RANDOMNESS)
76-
.takes_value(true)
74+
Arg::new(RANDOMNESS)
75+
.action(ArgAction::Set)
7776
.help("")
7877
.default_value("1E-2"),
7978
)
8079
.arg(
81-
Arg::with_name(QUALITY)
82-
.takes_value(true)
80+
Arg::new(QUALITY)
81+
.action(ArgAction::Set)
8382
.help("Quality function to use")
84-
.short("q")
85-
.possible_value("modularity")
86-
.possible_value("cpm")
83+
.short('q')
84+
.value_parser(["modularity", "cpm"])
8785
.default_value("modularity"),
8886
)
8987
.arg(
90-
Arg::with_name(HAS_HEADER)
88+
Arg::new(HAS_HEADER)
9189
.help("Flag must be added if the source file contains a header line")
9290
.long("has_header")
9391
)
Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,14 @@
11
[package]
22
name = "network_partitions"
33
version = "0.1.0"
4-
authors = ["Dwayne Pryce <dwpryce@microsoft.com>"]
4+
authors = ["Dax Pryce <daxpryce@microsoft.com>"]
55
edition = "2018"
66
license = "MIT"
77
description = "Leiden community detection as per https://arxiv.org/abs/1810.08473"
88

99
[dependencies]
1010
rand = "0.8"
11-
chrono = { version = "0.4", optional = true }
1211

1312
[dev-dependencies]
1413
rand_xorshift = "0.3"
1514

16-
[features]
17-
logging = ["chrono"]
18-
debug = []

0 commit comments

Comments
 (0)