Skip to content

Commit f3cd4c5

Browse files
authored
Pre-release version 5 (#7)
1 parent 76a4825 commit f3cd4c5

File tree

12 files changed

+194
-33
lines changed

12 files changed

+194
-33
lines changed

.gitignore

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,3 +84,16 @@ output_*
8484
.benchmarks/
8585
ci.yml
8686
src/main.rs
87+
88+
# Ignore files in the tests/testdata/[graphina-graphs] directory
89+
tests/testdata/*.txt
90+
tests/testdata/*.csv
91+
tests/testdata/*.json
92+
tests/testdata/*.parquet
93+
tests/testdata/*.gitattributes
94+
tests/testdata/graphina-graphs/*.gitattributes
95+
tests/testdata/graphina-graphs/*.md
96+
tests/testdata/graphina-graphs/*.txt
97+
tests/testdata/graphina-graphs/*.csv
98+
tests/testdata/graphina-graphs/*.json
99+
tests/testdata/graphina-graphs/*.parquet

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "graphina"
3-
version = "0.2.1"
3+
version = "0.2.2-alpha"
44
description = "A graph data science library for Rust"
55
repository = "https://github.com/habedi/graphina"
66
license = "MIT OR Apache-2.0"

Makefile

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Variables
2-
PKG := github.com/habedi/graphina
3-
BINARY_NAME := $(or $(PROJ_BINARY), $(notdir $(PKG)))
2+
REPO := github.com/habedi/graphina
3+
BINARY_NAME := $(or $(PROJ_BINARY), $(notdir $(REPO)))
44
BINARY := target/release/$(BINARY_NAME)
55
PATH := /snap/bin:$(PATH)
66
DEBUG_GRAPHINA := 1
@@ -9,6 +9,8 @@ RUST_BACKTRACE := full
99
WHEEL_DIR := dist
1010
PYGRAPHINA_DIR := pygraphina
1111
TEST_DATA_DIR := tests/testdata
12+
SHELL := /bin/bash
13+
MSRV := 1.83
1214

1315
# Find the latest built Python wheel file
1416
WHEEL_FILE := $(shell ls $(PYGRAPHINA_DIR)/$(WHEEL_DIR)/pygraphina-*.whl 2>/dev/null | head -n 1)
@@ -17,7 +19,7 @@ WHEEL_FILE := $(shell ls $(PYGRAPHINA_DIR)/$(WHEEL_DIR)/pygraphina-*.whl 2>/dev/
1719
.DEFAULT_GOAL := help
1820

1921
.PHONY: help
20-
help: ## Show the list of available targets with their descriptions
22+
help: ## Show the help message for each target
2123
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \
2224
awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
2325

@@ -33,7 +35,8 @@ format: ## Format Rust files
3335
.PHONY: test
3436
test: format ## Run the tests
3537
@echo "Running tests..."
36-
@DEBUG_GRAPHINA=$(DEBUG_GRAPHINA) RUST_LOG=debug RUST_BACKTRACE=$(RUST_BACKTRACE) cargo test -- --nocapture
38+
@DEBUG_GRAPHINA=$(DEBUG_GRAPHINA) RUST_LOG=debug RUST_BACKTRACE=$(RUST_BACKTRACE) cargo test --all-targets \
39+
--workspace -- --nocapture
3740

3841
.PHONY: coverage
3942
coverage: format ## Generate test coverage report
@@ -98,23 +101,44 @@ doc: format ## Generate the documentation
98101
@cargo doc --no-deps --document-private-items
99102

100103
.PHONY: fix-lint
101-
fix_lint: ## Fix the linter warnings
104+
fix-lint: ## Fix the linter warnings
102105
@echo "Fixing linter warnings..."
103-
@cargo clippy --fix --allow-dirty --allow-staged
106+
@cargo clippy --fix --allow-dirty --all-targets --workspace --all-features -- -D warnings
104107

105108
.PHONY: nextest
106109
nextest: ## Run tests using nextest
107110
@echo "Running tests using nextest..."
108111
@DEBUG_GRAPHINA=$(DEBUG_GRAPHINA) RUST_BACKTRACE=$(RUST_BACKTRACE) cargo nextest run
109112

113+
.PHONY: testdata
114+
testdata: ## Download the datasets used in tests
115+
@echo "Downloading test data..."
116+
@$(SHELL) $(TEST_DATA_DIR)/download_datasets.sh $(TEST_DATA_DIR)
117+
118+
.PHONY: install-msrv
119+
install-msrv: ## Install the minimum supported Rust version (MSRV) for development
120+
@echo "Installing the minimum supported Rust version..."
121+
@rustup toolchain install $(MSRV)
122+
@rustup default $(MSRV)
123+
124+
.PHONY: run-examples
125+
run-examples: ## Run all the scripts in the examples directory one by one
126+
@echo "Running all example scripts..."
127+
@for example in examples/*.rs; do \
128+
example_name=$$(basename $$example .rs); \
129+
echo "Running example: $$example_name"; \
130+
cargo run --example $$example_name; \
131+
done
132+
110133
########################################################################################
111134
## Python targets
112135
########################################################################################
113136

114-
.PHONY: develop_py
115-
develop_py: ## Build and install PyGraphina in the current Python environment
137+
.PHONY: develop-py
138+
develop-py: ## Build and install PyGraphina in the current Python environment
116139
@echo "Building and installing PyGraphina..."
117-
@(cd $(PYGRAPHINA_DIR) && maturin develop)
140+
# Note: Maturin does not work when CONDA_PREFIX and VIRTUAL_ENV are both set
141+
@(cd $(PYGRAPHINA_DIR) && unset CONDA_PREFIX && maturin develop)
118142

119143
.PHONY: wheel
120144
wheel: ## Build the wheel file for PyGraphina
@@ -126,12 +150,13 @@ wheel-manylinux: ## Build the manylinux wheel file for PyGraphina (using Zig)
126150
@echo "Building the manylinux PyGraphina wheel..."
127151
@(cd $(PYGRAPHINA_DIR) && maturin build --release --out $(WHEEL_DIR) --auditwheel check --zig)
128152

129-
.PHONY: test_py
130-
test_py: develop_py ## Run Python tests
153+
.PHONY: test-py
154+
test-py: develop-py ## Run Python tests
131155
@echo "Running Python tests..."
132156
@poetry run pytest $(PYGRAPHINA_DIR)/tests
133157

134-
publish_py: wheel ## Publish the PyGraphina wheel to PyPI (requires PYPI_TOKEN to be set)
158+
.PHONY: publish-py
159+
publish-py: wheel-manylinux ## Publish the PyGraphina wheel to PyPI (requires PYPI_TOKEN to be set)
135160
@echo "Publishing PyGraphina to PyPI..."
136161
@if [ -z "$(WHEEL_FILE)" ]; then \
137162
echo "Error: No wheel file found. Please run 'make wheel' first."; \
@@ -140,7 +165,7 @@ publish_py: wheel ## Publish the PyGraphina wheel to PyPI (requires PYPI_TOKEN t
140165
@echo "Found wheel file: $(WHEEL_FILE)"
141166
@twine upload -u __token__ -p $(PYPI_TOKEN) $(WHEEL_FILE)
142167

143-
.PHONY: generate_ci
144-
generate_ci: ## Generate CI configuration files (GitHub Actions workflow)
168+
.PHONY: generate-ci
169+
generate-ci: ## Generate CI configuration files (GitHub Actions workflow)
145170
@echo "Generating CI configuration files..."
146171
@(cd $(PYGRAPHINA_DIR) && maturin generate-ci --zig --pytest --platform all -o ../.github/workflows/ci.yml github)

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
<img alt="Graphina the Dinosaur" src="logo.png" height="50%" width="50%">
44
</picture>
55
</div>
6+
<br>
67

78
## Graphina
89

@@ -14,7 +15,6 @@
1415
[![Docs.rs](https://img.shields.io/badge/docs.rs-graphina-66c2a5?style=flat&labelColor=282c34&logo=docs.rs)](https://docs.rs/graphina)
1516
[![Downloads](https://img.shields.io/crates/d/graphina?style=flat&labelColor=282c34&color=4caf50&logo=rust)](https://crates.io/crates/graphina)
1617
[![MSRV](https://img.shields.io/badge/MSRV-1.83.0-007ec6?label=msrv&style=flat&labelColor=282c34&logo=rust)](https://github.com/rust-lang/rust/releases/tag/1.83.0)
17-
[![Status: Alpha](https://img.shields.io/badge/status-alpha-ec407a.svg?style=flat&labelColor=282c34)](https://github.com/habedi/graphina)
1818
[![Docs](https://img.shields.io/badge/docs-latest-3776ab?style=flat&labelColor=282c34&logo=readthedocs)](docs)
1919
[![License](https://img.shields.io/badge/license-MIT%2FApache--2.0-007ec6?style=flat&labelColor=282c34&logo=open-source-initiative)](https://github.com/habedi/graphina)
2020

@@ -46,11 +46,11 @@ The extensions are independent of each other. However, they depend on the core l
4646

4747
#### Graphina Core
4848

49-
| Module | Feature/Algorithm | Status | Notes |
49+
| Module | Feature or Algorithm | Status | Notes |
5050
|------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------|---------------------------------------------------|
5151
| [**Types**](src/core/types.rs) | <ul><li>Directed and undirected graphs</li><li>Weighted and unweighted graphs</li></ul> | Tested | Graph types that Graphina supports |
5252
| [**Exceptions**](src/core/exceptions.rs) | <ul><li>List of exceptions</li></ul> | Tested | Custom error types for Graphina |
53-
| [**IO**](src/core/io.rs) | <ul><li>Edge list</li><li>Adjacency list</li></ul> | Tested | I/O routines for reading/writing graph data |
53+
| [**IO**](src/core/io.rs) | <ul><li>Edge list</li><li>Adjacency list</li></ul> | Tested | I/O routines for reading and writing graph data |
5454
| [**Generators**](src/core/generators.rs) | <ul><li>Erdős–Rényi graph</li><li>Watts–Strogatz graph</li><li>Barabási–Albert graph</li><li>Complete graph</li><li>Bipartite graph</li><li>Star graph</li><li>Cycle graph</li></ul> | Tested | Graph generators for random and structured graphs |
5555
| [**Paths**](src/core/paths.rs) | <ul><li>Dijkstra’s algorithm</li><li>Bellman–Ford algorithm</li><li>Floyd–Warshall algorithm</li><li>Johnson’s algorithm</li><li>A* search algorithm</li><li>Iterative deepening A*</li></ul> | Tested | Shortest paths algorithms |
5656
| [**MST**](src/core/mst.rs) | <ul><li>Prim’s algorithm</li><li>Kruskal’s algorithm</li><li>Borůvka’s algorithm</li></ul> | Tested | Minimum spanning tree algorithms |
@@ -79,7 +79,7 @@ Or add this to your `Cargo.toml`:
7979

8080
```toml
8181
[dependencies]
82-
graphina = "0.1"
82+
graphina = "0.2"
8383
```
8484

8585
*Graphina requires Rust 1.83 or later.*
@@ -115,7 +115,7 @@ fn main() {
115115
}
116116
```
117117

118-
See the [tests](tests/) directory for more usage examples.
118+
See the [examples](examples) and [tests](tests) directories for more usage examples.
119119

120120
### Contributing
121121

examples/core_io.rs

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
use graphina::core::io::{read_edge_list, write_adjacency_list, write_edge_list};
2+
use graphina::core::types::Graph;
3+
4+
// Use `make testdata` to download the test datasets if needed.
5+
6+
const TESTDATA_DIR: &str = "tests/testdata/graphina-graphs";
7+
8+
fn main() {
9+
// Parameters
10+
let path = format!("{}/dblp_citation_network.txt", TESTDATA_DIR);
11+
let mut graph = Graph::<i32, f32>::new();
12+
let sep = '\t';
13+
14+
// Read the edge list from the file
15+
let _ = read_edge_list_dataset(&path, &mut graph, sep);
16+
17+
// Write the adjacency list to a file
18+
let path_for_adjacency_list =
19+
format!("{}/dblp_citation_network_adjacency_list.txt", TESTDATA_DIR);
20+
let _ = write_adjacency_list_dataset(&path_for_adjacency_list, &graph, sep);
21+
22+
// Write the edge list to a file
23+
let path_for_edge_list = format!("{}/dblp_citation_network_edge_list.txt", TESTDATA_DIR);
24+
let _ = write_edge_list_dataset(&path_for_edge_list, &graph, sep);
25+
26+
// Have a look at the graph
27+
println!("==========================================================");
28+
let mut counter = 0;
29+
let limit = 5;
30+
for node in graph.nodes() {
31+
if counter > limit {
32+
break;
33+
}
34+
35+
println!("Node: {:?}", node);
36+
counter += 1;
37+
}
38+
39+
println!("==========================================================");
40+
41+
counter = 0;
42+
for edge in graph.edges() {
43+
if counter > limit {
44+
break;
45+
}
46+
47+
println!("Edge: {:?}", edge);
48+
counter += 1;
49+
}
50+
}
51+
52+
/// Read an edge list dataset from a text file and load it into a graph.
53+
fn read_edge_list_dataset(
54+
path: &str,
55+
graph: &mut Graph<i32, f32>,
56+
sep: char,
57+
) -> Result<(), Box<dyn std::error::Error>> {
58+
if let Err(e) = read_edge_list(path, graph, sep) {
59+
eprintln!("Error reading edges: {}", e);
60+
} else {
61+
println!(
62+
"Loaded graph from '{}' that has {} nodes and {} edges",
63+
path,
64+
graph.node_count(),
65+
graph.edge_count()
66+
);
67+
}
68+
Ok(())
69+
}
70+
71+
/// Writes the adjacency list of a graph to a text file
72+
fn write_adjacency_list_dataset(
73+
path: &str,
74+
graph: &Graph<i32, f32>,
75+
sep: char,
76+
) -> Result<(), Box<dyn std::error::Error>> {
77+
if let Err(e) = write_adjacency_list(path, graph, sep) {
78+
eprintln!("Error writing adjacency list: {}", e);
79+
} else {
80+
println!("Wrote adjacency list to '{}'", path);
81+
}
82+
Ok(())
83+
}
84+
85+
/// Write the edge list to a file
86+
fn write_edge_list_dataset(
87+
path: &str,
88+
graph: &Graph<i32, f32>,
89+
sep: char,
90+
) -> Result<(), Box<dyn std::error::Error>> {
91+
if let Err(e) = write_edge_list(path, graph, sep) {
92+
eprintln!("Error writing edge list: {}", e);
93+
} else {
94+
println!("Wrote edge list to '{}'", path);
95+
}
96+
Ok(())
97+
}

pygraphina/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "pygraphina"
3-
version = "0.1.1"
3+
version = "0.1.1-alpha"
44
edition = "2021"
55
publish = false
66

@@ -10,6 +10,6 @@ crate-type = ["cdylib"]
1010
doc = false
1111

1212
[dependencies]
13-
pyo3 = { version = "0.18", features = ["abi3-py39", "extension-module"] }
13+
pyo3 = { version = "0.24.0", features = ["abi3-py310", "extension-module", "auto-initialize"] }
1414
graphina = { path = ".." }
1515

pygraphina/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
## PyGraphina
22

33
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
4-
[![Python version](https://img.shields.io/badge/Python-%3E=3.9-blue)](https://github.com/habedi/graphina)
4+
[![Python version](https://img.shields.io/badge/Python-%3E=3.10-blue)](https://github.com/habedi/graphina)
55
[![PyPI version](https://badge.fury.io/py/pygraphina.svg)](https://badge.fury.io/py/pygraphina)
66
[![Pip downloads](https://img.shields.io/pypi/dm/pygraphina.svg)](https://pypi.org/project/pygraphina)
7+
[![Status: Alpha](https://img.shields.io/badge/status-alpha-ec407a.svg?style=flat)](https://github.com/habedi/graphina)
78

89
PyGraphina Python library allows users to use [Graphina](https://github.com/habedi/graphina) in Python.
910

pygraphina/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ description = "Python bindings for the Graphina library"
1212
authors = [{ name = "Hassan Abedi", email = "hassan.abedi.t@gmail.com" }]
1313
maintainers = [{ name = "Hassan Abedi", email = "hassan.abedi.t@gmail.com" }]
1414
keywords = ["graph-theory", "data-science", "graph-algorithms", "graph-analytics"]
15-
requires-python = ">=3.9"
15+
requires-python = ">=3.10"
1616
license = { text = "MIT" }
1717
readme = "README.md"
1818
dynamic = ['version']

pygraphina/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,8 @@ impl PyGraph {
171171

172172
/// The Python module declaration.
173173
#[pymodule]
174-
fn pygraphina(_py: Python, m: &PyModule) -> PyResult<()> {
174+
fn pygraphina(m: &Bound<'_, PyModule>) -> PyResult<()> {
175+
// Bound is from pyo3::prelude
175176
m.add_class::<PyGraph>()?;
176177
Ok(())
177178
}

pyproject.toml

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,21 @@ authors = ["Hassan Abedi <hassan.abedi.t@gmail.com>"]
66
maintainers = ["Hassan Abedi <hassan.abedi.t@gmail.com>"]
77

88
[tool.poetry.dependencies]
9-
python = "^3.9"
10-
maturin = { extras = ["zig"], version = "^1.8.2" }
9+
python = "^3.10"
10+
maturin = { extras = ["zig"], version = "^1.8.3" }
1111
poetry-dynamic-versioning = "^1.4.0"
12-
pytest = "^8.0.1"
12+
pytest = "^8.3.5"
1313
pytest-cov = "^6.0.0"
1414
pytest-mock = "^3.14.0"
1515
pytest-benchmark = "^5.1.0"
1616
mypy = "^1.11.1"
17-
ruff = "^0.9.3"
17+
ruff = "^0.11.0"
1818
twine = "^6.1.0"
19+
huggingface-hub = "^0.29.3"
20+
networkx = "^3.4.2"
1921

2022
[tool.mypy]
21-
python_version = "3.9"
23+
python_version = "3.10"
2224
ignore_missing_imports = true
2325
disallow_untyped_calls = true
2426
strict_optional = true
@@ -52,7 +54,7 @@ exclude = [
5254
line-length = 100
5355
indent-width = 4
5456
src = ["pygraphina"]
55-
target-version = "py39"
57+
target-version = "py310"
5658

5759
[tool.ruff.lint]
5860
select = ["ANN", "D", "E", "F", "I"]

0 commit comments

Comments
 (0)