Skip to content

Commit 4fccd7e

Browse files
authored
Update to NetworkX 3.2 (#77)
* Update to NetworkX 3.2 * Use mamba instead for faster environment creation * Drop Python 3.8
1 parent 3caced2 commit 4fccd7e

File tree

8 files changed

+181
-32
lines changed

8 files changed

+181
-32
lines changed

.github/workflows/test.yml

+22-4
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,34 @@ jobs:
2121
uses: actions/checkout@v3
2222
with:
2323
fetch-depth: 0
24-
- name: Conda
24+
- name: Setup mamba
2525
uses: conda-incubator/setup-miniconda@v2
26+
id: setup_mamba
27+
continue-on-error: true
28+
with:
29+
miniforge-variant: Mambaforge
30+
miniforge-version: latest
31+
use-mamba: true
32+
python-version: ${{ matrix.python-version }}
33+
channels: conda-forge,${{ contains(matrix.python-version, 'pypy') && 'defaults' || 'nodefaults' }}
34+
channel-priority: ${{ contains(matrix.python-version, 'pypy') && 'flexible' || 'strict' }}
35+
activate-environment: graphblas
36+
auto-activate-base: false
37+
- name: Setup conda
38+
uses: conda-incubator/setup-miniconda@v2
39+
id: setup_conda
40+
if: steps.setup_mamba.outcome == 'failure'
41+
continue-on-error: false
2642
with:
2743
auto-update-conda: true
2844
python-version: ${{ matrix.python-version }}
29-
channels: conda-forge
30-
activate-environment: testing
45+
channels: conda-forge,${{ contains(matrix.python-version, 'pypy') && 'defaults' || 'nodefaults' }}
46+
channel-priority: ${{ contains(matrix.python-version, 'pypy') && 'flexible' || 'strict' }}
47+
activate-environment: graphblas
48+
auto-activate-base: false
3149
- name: Install dependencies
3250
run: |
33-
conda install -c conda-forge python-graphblas scipy pandas pytest-cov pytest-randomly pytest-mpl
51+
$(command -v mamba || command -v conda) install python-graphblas scipy pandas pytest-cov pytest-randomly pytest-mpl
3452
# matplotlib lxml pygraphviz pydot sympy # Extra networkx deps we don't need yet
3553
pip install git+https://github.com/networkx/networkx.git@main --no-deps
3654
pip install -e . --no-deps

.pre-commit-config.yaml

+20-18
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,23 @@
55
# To update: `pre-commit autoupdate`
66
# - &flake8_dependencies below needs updated manually
77
ci:
8-
# See: https://pre-commit.ci/#configuration
9-
autofix_prs: false
10-
autoupdate_schedule: quarterly
11-
skip: [no-commit-to-branch]
8+
# See: https://pre-commit.ci/#configuration
9+
autofix_prs: false
10+
autoupdate_schedule: quarterly
11+
autoupdate_commit_msg: "chore: update pre-commit hooks"
12+
autofix_commit_msg: "style: pre-commit fixes"
13+
skip: [no-commit-to-branch]
1214
fail_fast: true
1315
default_language_version:
1416
python: python3
1517
repos:
1618
- repo: https://github.com/pre-commit/pre-commit-hooks
17-
rev: v4.4.0
19+
rev: v4.5.0
1820
hooks:
1921
- id: check-added-large-files
2022
- id: check-case-conflict
2123
- id: check-merge-conflict
22-
- id: check-symlinks
24+
# - id: check-symlinks
2325
- id: check-ast
2426
- id: check-toml
2527
- id: check-yaml
@@ -37,7 +39,7 @@ repos:
3739
name: Validate pyproject.toml
3840
# I don't yet trust ruff to do what autoflake does
3941
- repo: https://github.com/PyCQA/autoflake
40-
rev: v2.2.0
42+
rev: v2.2.1
4143
hooks:
4244
- id: autoflake
4345
args: [--in-place]
@@ -46,22 +48,22 @@ repos:
4648
hooks:
4749
- id: isort
4850
- repo: https://github.com/asottile/pyupgrade
49-
rev: v3.10.1
51+
rev: v3.15.0
5052
hooks:
5153
- id: pyupgrade
52-
args: [--py38-plus]
54+
args: [--py39-plus]
5355
- repo: https://github.com/MarcoGorelli/auto-walrus
5456
rev: v0.2.2
5557
hooks:
5658
- id: auto-walrus
5759
args: [--line-length, "100"]
5860
- repo: https://github.com/psf/black
59-
rev: 23.7.0
61+
rev: 23.9.1
6062
hooks:
6163
- id: black
6264
# - id: black-jupyter
63-
- repo: https://github.com/charliermarsh/ruff-pre-commit
64-
rev: v0.0.285
65+
- repo: https://github.com/astral-sh/ruff-pre-commit
66+
rev: v0.0.292
6567
hooks:
6668
- id: ruff
6769
args: [--fix-only, --show-fixes]
@@ -72,22 +74,22 @@ repos:
7274
additional_dependencies: &flake8_dependencies
7375
# These versions need updated manually
7476
- flake8==6.1.0
75-
- flake8-bugbear==23.7.10
76-
- flake8-simplify==0.20.0
77+
- flake8-bugbear==23.9.16
78+
- flake8-simplify==0.21.0
7779
- repo: https://github.com/asottile/yesqa
7880
rev: v1.5.0
7981
hooks:
8082
- id: yesqa
8183
additional_dependencies: *flake8_dependencies
8284
- repo: https://github.com/codespell-project/codespell
83-
rev: v2.2.5
85+
rev: v2.2.6
8486
hooks:
8587
- id: codespell
8688
types_or: [python, rst, markdown]
8789
additional_dependencies: [tomli]
8890
files: ^(graphblas_algorithms|docs)/
89-
- repo: https://github.com/charliermarsh/ruff-pre-commit
90-
rev: v0.0.285
91+
- repo: https://github.com/astral-sh/ruff-pre-commit
92+
rev: v0.0.292
9193
hooks:
9294
- id: ruff
9395
# `pyroma` may help keep our package standards up to date if best practices change.
@@ -98,6 +100,6 @@ repos:
98100
- id: pyroma
99101
args: [-n, "10", .]
100102
- repo: https://github.com/pre-commit/pre-commit-hooks
101-
rev: v4.4.0
103+
rev: v4.5.0
102104
hooks:
103105
- id: no-commit-to-branch # no commit directly to main

_nx_graphblas/__init__.py

+107
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
def get_info():
2+
return {
3+
"backend_name": "graphblas",
4+
"project": "graphblas-algorithms",
5+
"package": "graphblas_algorithms",
6+
"url": "https://github.com/python-graphblas/graphblas-algorithms",
7+
"short_summary": "Fast, OpenMP-enabled backend using GraphBLAS",
8+
# "description": "TODO",
9+
"functions": {
10+
"adjacency_matrix": {},
11+
"all_pairs_bellman_ford_path_length": {
12+
"extra_parameters": {
13+
"chunksize": "Split the computation into chunks; "
14+
'may specify size as string or number of rows. Default "10 MiB"',
15+
},
16+
},
17+
"all_pairs_shortest_path_length": {
18+
"extra_parameters": {
19+
"chunksize": "Split the computation into chunks; "
20+
'may specify size as string or number of rows. Default "10 MiB"',
21+
},
22+
},
23+
"ancestors": {},
24+
"average_clustering": {},
25+
"bellman_ford_path": {},
26+
"bellman_ford_path_length": {},
27+
"bethe_hessian_matrix": {},
28+
"bfs_layers": {},
29+
"boundary_expansion": {},
30+
"clustering": {},
31+
"complement": {},
32+
"compose": {},
33+
"conductance": {},
34+
"cut_size": {},
35+
"degree_centrality": {},
36+
"descendants": {},
37+
"descendants_at_distance": {},
38+
"difference": {},
39+
"directed_modularity_matrix": {},
40+
"disjoint_union": {},
41+
"edge_boundary": {},
42+
"edge_expansion": {},
43+
"efficiency": {},
44+
"ego_graph": {},
45+
"eigenvector_centrality": {},
46+
"fast_could_be_isomorphic": {},
47+
"faster_could_be_isomorphic": {},
48+
"floyd_warshall": {},
49+
"floyd_warshall_numpy": {},
50+
"floyd_warshall_predecessor_and_distance": {},
51+
"full_join": {},
52+
"generalized_degree": {},
53+
"google_matrix": {},
54+
"has_path": {},
55+
"hits": {},
56+
"in_degree_centrality": {},
57+
"inter_community_edges": {},
58+
"intersection": {},
59+
"intra_community_edges": {},
60+
"is_connected": {},
61+
"is_dominating_set": {},
62+
"is_isolate": {},
63+
"is_k_regular": {},
64+
"isolates": {},
65+
"is_regular": {},
66+
"is_simple_path": {},
67+
"is_tournament": {},
68+
"is_triad": {},
69+
"is_weakly_connected": {},
70+
"katz_centrality": {},
71+
"k_truss": {},
72+
"laplacian_matrix": {},
73+
"lowest_common_ancestor": {},
74+
"mixing_expansion": {},
75+
"modularity_matrix": {},
76+
"mutual_weight": {},
77+
"negative_edge_cycle": {},
78+
"node_boundary": {},
79+
"node_connected_component": {},
80+
"node_expansion": {},
81+
"normalized_cut_size": {},
82+
"normalized_laplacian_matrix": {},
83+
"number_of_isolates": {},
84+
"out_degree_centrality": {},
85+
"overall_reciprocity": {},
86+
"pagerank": {},
87+
"reciprocity": {},
88+
"reverse": {},
89+
"score_sequence": {},
90+
"single_source_bellman_ford_path_length": {},
91+
"single_source_shortest_path_length": {},
92+
"single_target_shortest_path_length": {},
93+
"s_metric": {},
94+
"square_clustering": {
95+
"extra_parameters": {
96+
"chunksize": "Split the computation into chunks; "
97+
'may specify size as string or number of rows. Default "256 MiB"',
98+
},
99+
},
100+
"symmetric_difference": {},
101+
"tournament_matrix": {},
102+
"transitivity": {},
103+
"triangles": {},
104+
"union": {},
105+
"volume": {},
106+
},
107+
}

graphblas_algorithms/classes/digraph.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,7 @@ def __missing__(self, key):
442442

443443

444444
class DiGraph(Graph):
445+
__networkx_backend__ = "graphblas"
445446
__networkx_plugin__ = "graphblas"
446447

447448
# "-" properties ignore self-edges, "+" properties include self-edges
@@ -611,7 +612,7 @@ def to_undirected(self, reciprocal=False, as_view=False, *, name=None):
611612
return Graph(B, key_to_id=self._key_to_id)
612613

613614
def reverse(self, copy=True):
614-
# We could even re-use many of the cached values
615+
# We could even reuse many of the cached values
615616
A = self._A.T # This probably mostly works, but does not yet support assignment
616617
if copy:
617618
A = A.new()

graphblas_algorithms/classes/graph.py

+1
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,7 @@ def __missing__(self, key):
301301

302302

303303
class Graph:
304+
__networkx_backend__ = "graphblas"
304305
__networkx_plugin__ = "graphblas"
305306

306307
# "-" properties ignore self-edges, "+" properties include self-edges

graphblas_algorithms/nxapi/smetric.py

+14-5
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,22 @@
1+
import warnings
2+
13
from graphblas_algorithms import algorithms
24
from graphblas_algorithms.classes.digraph import to_graph
35

4-
from .exception import NetworkXError
5-
66
__all__ = ["s_metric"]
77

88

9-
def s_metric(G, normalized=True):
10-
if normalized:
11-
raise NetworkXError("Normalization not implemented")
9+
def s_metric(G, **kwargs):
10+
if kwargs:
11+
if "normalized" in kwargs:
12+
warnings.warn(
13+
"\n\nThe `normalized` keyword is deprecated and will be removed\n"
14+
"in the future. To silence this warning, remove `normalized`\n"
15+
"when calling `s_metric`.\n\nThe value of `normalized` is ignored.",
16+
DeprecationWarning,
17+
stacklevel=2,
18+
)
19+
else:
20+
raise TypeError(f"s_metric got an unexpected keyword argument '{kwargs.popitem()[0]}'")
1221
G = to_graph(G)
1322
return algorithms.s_metric(G)

graphblas_algorithms/tests/test_core.py

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ def test_packages():
2727
path = pathlib.Path(ga.__file__).parent
2828
pkgs = [f"graphblas_algorithms.{x}" for x in setuptools.find_packages(path)]
2929
pkgs.append("graphblas_algorithms")
30+
pkgs.append("_nx_graphblas")
3031
pkgs.sort()
3132
pyproject = path.parent / "pyproject.toml"
3233
if not pyproject.exists():

pyproject.toml

+14-4
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ name = "graphblas-algorithms"
1010
dynamic = ["version"]
1111
description = "Graph algorithms written in GraphBLAS and backend for NetworkX"
1212
readme = "README.md"
13-
requires-python = ">=3.8"
13+
requires-python = ">=3.9"
1414
license = {file = "LICENSE"}
1515
authors = [
1616
{name = "Erik Welch", email = "[email protected]"},
@@ -43,7 +43,6 @@ classifiers = [
4343
"Operating System :: Microsoft :: Windows",
4444
"Programming Language :: Python",
4545
"Programming Language :: Python :: 3",
46-
"Programming Language :: Python :: 3.8",
4746
"Programming Language :: Python :: 3.9",
4847
"Programming Language :: Python :: 3.10",
4948
"Programming Language :: Python :: 3.11",
@@ -65,6 +64,12 @@ dependencies = [
6564
[project.entry-points."networkx.plugins"]
6665
graphblas = "graphblas_algorithms.interface:Dispatcher"
6766

67+
[project.entry-points."networkx.backends"]
68+
graphblas = "graphblas_algorithms.interface:Dispatcher"
69+
70+
[project.entry-points."networkx.backend_info"]
71+
graphblas = "_nx_graphblas:get_info"
72+
6873
[project.urls]
6974
homepage = "https://github.com/python-graphblas/graphblas-algorithms"
7075
# documentation = "https://graphblas-algorithms.readthedocs.io"
@@ -90,6 +95,7 @@ all = [
9095
# $ find graphblas_algorithms/ -name __init__.py -print | sort | sed -e 's/\/__init__.py//g' -e 's/\//./g'
9196
# $ python -c 'import tomli ; [print(x) for x in sorted(tomli.load(open("pyproject.toml", "rb"))["tool"]["setuptools"]["packages"])]'
9297
packages = [
98+
"_nx_graphblas",
9399
"graphblas_algorithms",
94100
"graphblas_algorithms.algorithms",
95101
"graphblas_algorithms.algorithms.centrality",
@@ -127,7 +133,7 @@ dirty_template = "{tag}+{ccount}.g{sha}.dirty"
127133

128134
[tool.black]
129135
line-length = 100
130-
target-version = ["py38", "py39", "py310", "py311"]
136+
target-version = ["py39", "py310", "py311"]
131137

132138
[tool.isort]
133139
sections = ["FUTURE", "STDLIB", "THIRDPARTY", "FIRSTPARTY", "LOCALFOLDER"]
@@ -143,6 +149,7 @@ skip = [
143149
]
144150

145151
[tool.pytest.ini_options]
152+
minversion = "6.0"
146153
testpaths = "graphblas_algorithms"
147154
xfail_strict = false
148155
markers = [
@@ -169,7 +176,10 @@ exclude_lines = [
169176
[tool.ruff]
170177
# https://github.com/charliermarsh/ruff/
171178
line-length = 100
172-
target-version = "py38"
179+
target-version = "py39"
180+
unfixable = [
181+
"F841" # unused-variable (Note: can leave useless expression)
182+
]
173183
select = [
174184
"ALL",
175185
]

0 commit comments

Comments
 (0)