Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: update to support NetworkX 3.3 (dev), and other maintenance #91

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,4 @@ jobs:
- uses: actions/setup-python@v5
with:
python-version: "3.10"
- uses: pre-commit/[email protected].0
- uses: pre-commit/[email protected].1
27 changes: 14 additions & 13 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ default_language_version:
python: python3
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
rev: v4.6.0
hooks:
- id: check-added-large-files
- id: check-case-conflict
Expand All @@ -33,13 +33,13 @@ repos:
- id: name-tests-test
args: ["--pytest-test-first"]
- repo: https://github.com/abravalheri/validate-pyproject
rev: v0.15
rev: v0.18
hooks:
- id: validate-pyproject
name: Validate pyproject.toml
# I don't yet trust ruff to do what autoflake does
- repo: https://github.com/PyCQA/autoflake
rev: v2.2.1
rev: v2.3.1
hooks:
- id: autoflake
args: [--in-place]
Expand All @@ -48,48 +48,49 @@ repos:
hooks:
- id: isort
- repo: https://github.com/asottile/pyupgrade
rev: v3.15.0
rev: v3.16.0
hooks:
- id: pyupgrade
args: [--py310-plus]
- repo: https://github.com/MarcoGorelli/auto-walrus
rev: v0.2.2
rev: 0.3.4
hooks:
- id: auto-walrus
additional_dependencies: [tomli]
args: [--line-length, "100"]
- repo: https://github.com/psf/black
rev: 23.12.1
rev: 24.4.2
hooks:
- id: black
# - id: black-jupyter
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.1.9
rev: v0.5.0
hooks:
- id: ruff
args: [--fix-only, --show-fixes]
- repo: https://github.com/PyCQA/flake8
rev: 6.1.0
rev: 7.1.0
hooks:
- id: flake8
additional_dependencies: &flake8_dependencies
# These versions need updated manually
- flake8==6.1.0
- flake8-bugbear==23.12.2
- flake8==7.1.0
- flake8-bugbear==24.2.6
- flake8-simplify==0.21.0
- repo: https://github.com/asottile/yesqa
rev: v1.5.0
hooks:
- id: yesqa
additional_dependencies: *flake8_dependencies
- repo: https://github.com/codespell-project/codespell
rev: v2.2.6
rev: v2.3.0
hooks:
- id: codespell
types_or: [python, rst, markdown]
additional_dependencies: [tomli]
files: ^(graphblas_algorithms|docs)/
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.1.9
rev: v0.5.0
hooks:
- id: ruff
# `pyroma` may help keep our package standards up to date if best practices change.
Expand All @@ -100,6 +101,6 @@ repos:
- id: pyroma
args: [-n, "10", .]
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
rev: v4.6.0
hooks:
- id: no-commit-to-branch # no commit directly to main
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/graphblas-algorithms)](https://pypi.python.org/pypi/graphblas-algorithms/)
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/python-graphblas/graphblas-algorithms/blob/main/LICENSE)
<br>
[![Tests](https://github.com/python-graphblas/graphblas-algorithms/workflows/Tests/badge.svg?branch=main)](https://github.com/python-graphblas/graphblas-algorithms/actions)
[![Tests](https://github.com/python-graphblas/graphblas-algorithms/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/python-graphblas/graphblas-algorithms/actions)
[![Coverage](https://codecov.io/gh/python-graphblas/graphblas-algorithms/branch/main/graph/badge.svg)](https://codecov.io/gh/python-graphblas/graphblas-algorithms)
[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.7329185.svg)](https://doi.org/10.5281/zenodo.7329185)
[![Discord](https://img.shields.io/badge/Chat-Discord-blue)](https://discord.com/invite/vur45CbwMz)
Expand Down Expand Up @@ -91,7 +91,7 @@ T5 = nx.k_truss(G2, 5)
```

`G2` is not a `nx.Graph`, but it does have an attribute
`__networkx_plugin__ = "graphblas"`. This tells NetworkX to
`__networkx_backend__ = "graphblas"`. This tells NetworkX to
dispatch the k_truss call to graphblas-algorithms. This link
connection exists because graphblas-algorithms registers
itself as a "networkx.plugin" entry point.
Expand Down
2 changes: 1 addition & 1 deletion graphblas_algorithms/algorithms/_bfs.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""BFS routines used by other algorithms"""
"""BFS routines used by other algorithms."""

import numpy as np
from graphblas import Matrix, Vector, binary, indexunary, replace, semiring, unary
Expand Down
2 changes: 1 addition & 1 deletion graphblas_algorithms/algorithms/_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def normalize(x, how):


def is_converged(xprev, x, tol):
"""Check convergence, L1 norm: err = sum(abs(xprev - x)); err < N * tol
"""Check convergence, L1 norm: ``err = sum(abs(xprev - x)); err < N * tol``.

This modifies `xprev`.
"""
Expand Down
3 changes: 2 additions & 1 deletion graphblas_algorithms/algorithms/shortest_paths/weighted.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,13 +116,14 @@ def bellman_ford_path_length(G, source, target):


def bellman_ford_path_lengths(G, nodes=None, *, expand_output=False):
"""Extra parameter: expand_output
"""Extra parameter: expand_output.

Parameters
----------
expand_output : bool, default False
When False, the returned Matrix has one row per node in nodes.
When True, the returned Matrix has the same shape as the input Matrix.

"""
# Same algorithms as in `single_source_bellman_ford_path_length`, but with
# `Cur` as a Matrix with each row corresponding to a source node.
Expand Down
4 changes: 2 additions & 2 deletions graphblas_algorithms/classes/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ def matrix_to_vectornodemap(self, A):


def matrix_to_dicts(self, A, *, use_row_index=False, use_column_index=False, values_are_keys=False):
"""Convert a Matrix to a dict of dicts of the form ``{row: {col: val}}``
"""Convert a Matrix to a dict of dicts of the form ``{row: {col: val}}``.

Use ``use_row_index=True`` to return the row index as keys in the dict,
and likewise for `use_column_index=True``.
Expand Down Expand Up @@ -256,7 +256,7 @@ def _cacheit(self, key, func, *args, **kwargs):


def renumber_key_to_id(self, indices):
"""Create `key_to_id` for e.g. a subgraph with node ids from `indices`"""
"""Create `key_to_id` for e.g. a subgraph with node ids from `indices`."""
id_to_key = self.id_to_key
return {id_to_key[index]: i for i, index in enumerate(indices)}
# Alternative (about the same performance)
Expand Down
24 changes: 12 additions & 12 deletions graphblas_algorithms/classes/digraph.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@


def get_AT(G, mask=None):
"""A.T"""
"""``A.T``."""
A = G._A
cache = G._cache
if "AT" not in cache:
Expand All @@ -31,7 +31,7 @@ def get_AT(G, mask=None):


def get_Up(G, mask=None):
"""select.triu(A)"""
"""``select.triu(A)``."""
A = G._A
cache = G._cache
if "U+" not in cache:
Expand All @@ -50,7 +50,7 @@ def get_Up(G, mask=None):


def get_Lp(G, mask=None):
"""select.tril(A)"""
"""``select.tril(A)``."""
A = G._A
cache = G._cache
if "L+" not in cache:
Expand All @@ -69,7 +69,7 @@ def get_Lp(G, mask=None):


def get_Um(G, mask=None):
"""select.triu(A, 1)"""
"""``select.triu(A, 1)``."""
A = G._A
cache = G._cache
if "U-" not in cache:
Expand All @@ -93,7 +93,7 @@ def get_Um(G, mask=None):


def get_Lm(G, mask=None):
"""select.tril(A, -1)"""
"""``select.tril(A, -1)``."""
A = G._A
cache = G._cache
if "L-" not in cache:
Expand All @@ -117,7 +117,7 @@ def get_Lm(G, mask=None):


def get_recip_degreesp(G, mask=None):
"""pair(A & A.T).reduce_rowwise()"""
"""``pair(A & A.T).reduce_rowwise()``."""
A = G._A
cache = G._cache
AT = cache.get("AT", A.T)
Expand Down Expand Up @@ -159,7 +159,7 @@ def get_recip_degreesp(G, mask=None):


def get_recip_degreesm(G, mask=None):
"""C = select.offdiag(A) ; pair(C & C.T).reduce_rowwise()"""
"""``C = select.offdiag(A) ; pair(C & C.T).reduce_rowwise()``."""
A = G._A
cache = G._cache
if "AT" in cache:
Expand Down Expand Up @@ -236,7 +236,7 @@ def get_recip_degreesm(G, mask=None):


def get_total_degreesp(G, mask=None):
"""A.reduce_rowwise(agg.count) + A.reduce_columnwise(agg.count)"""
"""``A.reduce_rowwise(agg.count) + A.reduce_columnwise(agg.count)``."""
cache = G._cache
if mask is not None:
if "total_degrees+" in cache:
Expand Down Expand Up @@ -266,7 +266,7 @@ def get_total_degreesp(G, mask=None):


def get_total_degreesm(G, mask=None):
"""C = select.offdiag(A) ; C.reduce_rowwise(agg.count) + C.reduce_columnwise(agg.count)"""
"""``C = select.offdiag(A) ; C.reduce_rowwise(agg.count) + C.reduce_columnwise(agg.count)``."""
cache = G._cache
if mask is not None:
if "total_degrees-" in cache:
Expand Down Expand Up @@ -296,7 +296,7 @@ def get_total_degreesm(G, mask=None):


def get_total_recipp(G, mask=None):
"""pair(A & A.T).reduce_scalar()"""
"""``pair(A & A.T).reduce_scalar()``."""
A = G._A
cache = G._cache
if "total_recip+" not in cache:
Expand All @@ -315,7 +315,7 @@ def get_total_recipp(G, mask=None):


def get_total_recipm(G, mask=None):
"""C = select.offdiag(A) ; pair(C & C.T).reduce_scalar()"""
"""``C = select.offdiag(A) ; pair(C & C.T).reduce_scalar()``."""
cache = G._cache
if "total_recip-" not in cache:
if "total_recip+" in cache and cache.get("has_self_edges") is False:
Expand All @@ -330,7 +330,7 @@ def get_total_recipm(G, mask=None):


def has_self_edges(G, mask=None):
"""A.diag().nvals > 0"""
"""``A.diag().nvals > 0``."""
A = G._A
cache = G._cache
if "has_self_edges" not in cache:
Expand Down
18 changes: 9 additions & 9 deletions graphblas_algorithms/classes/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,19 @@


def get_A(G, mask=None):
"""A"""
"""``A``."""
return G._A


def get_AT(G, mask=None):
"""A.T"""
"""``A.T``."""
A = G._A
G._cache["AT"] = A
return A


def get_offdiag(G, mask=None):
"""select.offdiag(A)"""
"""``select.offdiag(A)``."""
A = G._A
cache = G._cache
if "offdiag" not in cache:
Expand All @@ -38,7 +38,7 @@ def get_offdiag(G, mask=None):


def get_Up(G, mask=None):
"""select.triu(A)"""
"""``select.triu(A)``."""
A = G._A
cache = G._cache
if "U+" not in cache:
Expand All @@ -54,7 +54,7 @@ def get_Up(G, mask=None):


def get_Lp(G, mask=None):
"""select.tril(A)"""
"""``select.tril(A)``."""
A = G._A
cache = G._cache
if "L+" not in cache:
Expand All @@ -70,7 +70,7 @@ def get_Lp(G, mask=None):


def get_Um(G, mask=None):
"""select.triu(A, 1)"""
"""``select.triu(A, 1)``."""
A = G._A
cache = G._cache
if "U-" not in cache:
Expand All @@ -91,7 +91,7 @@ def get_Um(G, mask=None):


def get_Lm(G, mask=None):
"""select.tril(A, -1)"""
"""``select.tril(A, -1)``."""
A = G._A
cache = G._cache
if "L-" not in cache:
Expand All @@ -112,7 +112,7 @@ def get_Lm(G, mask=None):


def get_diag(G, mask=None):
"""A.diag()"""
"""``A.diag()``."""
A = G._A
cache = G._cache
if "diag" not in cache:
Expand Down Expand Up @@ -193,7 +193,7 @@ def has_negative_edgesm(G, mask=None):


def has_self_edges(G, mask=None):
"""A.diag().nvals > 0"""
"""``A.diag().nvals > 0``."""
A = G._A
cache = G._cache
if "has_self_edges" not in cache:
Expand Down
2 changes: 1 addition & 1 deletion graphblas_algorithms/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

@pytest.fixture(scope="session", autouse=True)
def ic():
"""Make `ic` available everywhere during testing for easier debugging"""
"""Make `ic` available everywhere during testing for easier debugging."""
try:
import icecream
except ImportError:
Expand Down
4 changes: 2 additions & 2 deletions graphblas_algorithms/nxapi/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ def normalize_chunksize(chunksize, itemsize=1, N=None):


def partition(chunksize, L, *, evenly=True):
"""Partition a list into chunks"""
"""Partition a list into chunks."""
N = len(L)
if N == 0:
return
Expand All @@ -109,7 +109,7 @@ def partition(chunksize, L, *, evenly=True):


def split_evenly(k, L):
"""Split a list into approximately-equal parts"""
"""Split a list into approximately-equal parts."""
N = len(L)
if N == 0:
return
Expand Down
3 changes: 2 additions & 1 deletion graphblas_algorithms/tests/test_match_nx.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
For now, though, let's try to match and stay up-to-date with NetworkX!

"""

import sys
from collections import namedtuple
from pathlib import Path
Expand Down Expand Up @@ -49,7 +50,7 @@ def isdispatched(func):


def dispatchname(func):
"""The dispatched name of the dispatchable NetworkX function"""
"""The dispatched name of the dispatchable NetworkX function."""
# Haha, there should be a better way to get this
if not isdispatched(func):
raise ValueError(f"Function is not dispatched in NetworkX: {func.__name__}")
Expand Down
Loading
Loading