Skip to content

Commit 10788fa

Browse files
authored
Drop Python 3.9, add 3.12; update pre-commit (#84)
* Drop Python 3.9, add 3.12; update pre-commit * Use latest networkx release, not dev version * Add .codecov.yml
1 parent 43c1731 commit 10788fa

File tree

11 files changed

+67
-45
lines changed

11 files changed

+67
-45
lines changed

Diff for: .codecov.yml

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
coverage:
2+
status:
3+
project:
4+
default:
5+
informational: true
6+
patch:
7+
default:
8+
informational: true
9+
changes: false
10+
comment:
11+
layout: "header, diff"
12+
behavior: default
13+
github_checks:
14+
annotations: false

Diff for: .github/workflows/publish_pypi.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020
- name: Set up Python
2121
uses: actions/setup-python@v4
2222
with:
23-
python-version: "3.9"
23+
python-version: "3.10"
2424
- name: Install build dependencies
2525
run: |
2626
python -m pip install --upgrade pip

Diff for: .github/workflows/test.yml

+4-3
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515
fail-fast: true
1616
matrix:
1717
os: ["ubuntu-latest", "macos-latest", "windows-latest"]
18-
python-version: ["3.9", "3.10", "3.11"]
18+
python-version: ["3.10", "3.11", "3.12"]
1919
steps:
2020
- name: Checkout
2121
uses: actions/checkout@v4
@@ -49,9 +49,10 @@ jobs:
4949
- name: Install dependencies
5050
run: |
5151
$(command -v mamba || command -v conda) install python-suitesparse-graphblas scipy pandas donfig pyyaml numpy python-graphblas \
52-
pytest-cov pytest-randomly pytest-mpl
52+
pytest-cov pytest-randomly pytest-mpl networkx
5353
# matplotlib lxml pygraphviz pydot sympy # Extra networkx deps we don't need yet
54-
pip install git+https://github.com/networkx/networkx.git@main --no-deps
54+
# Sometimes we prefer to use the latest release of NetworkX or the latest development from github
55+
# pip install git+https://github.com/networkx/networkx.git@main --no-deps
5556
pip install -e . --no-deps
5657
- name: PyTest
5758
run: |

Diff for: .pre-commit-config.yaml

+6-6
Original file line numberDiff line numberDiff line change
@@ -44,26 +44,26 @@ repos:
4444
- id: autoflake
4545
args: [--in-place]
4646
- repo: https://github.com/pycqa/isort
47-
rev: 5.12.0
47+
rev: 5.13.1
4848
hooks:
4949
- id: isort
5050
- repo: https://github.com/asottile/pyupgrade
5151
rev: v3.15.0
5252
hooks:
5353
- id: pyupgrade
54-
args: [--py39-plus]
54+
args: [--py310-plus]
5555
- repo: https://github.com/MarcoGorelli/auto-walrus
5656
rev: v0.2.2
5757
hooks:
5858
- id: auto-walrus
5959
args: [--line-length, "100"]
6060
- repo: https://github.com/psf/black
61-
rev: 23.10.0
61+
rev: 23.12.0
6262
hooks:
6363
- id: black
6464
# - id: black-jupyter
6565
- repo: https://github.com/astral-sh/ruff-pre-commit
66-
rev: v0.1.0
66+
rev: v0.1.7
6767
hooks:
6868
- id: ruff
6969
args: [--fix-only, --show-fixes]
@@ -74,7 +74,7 @@ repos:
7474
additional_dependencies: &flake8_dependencies
7575
# These versions need updated manually
7676
- flake8==6.1.0
77-
- flake8-bugbear==23.9.16
77+
- flake8-bugbear==23.12.2
7878
- flake8-simplify==0.21.0
7979
- repo: https://github.com/asottile/yesqa
8080
rev: v1.5.0
@@ -89,7 +89,7 @@ repos:
8989
additional_dependencies: [tomli]
9090
files: ^(graphblas_algorithms|docs)/
9191
- repo: https://github.com/astral-sh/ruff-pre-commit
92-
rev: v0.1.0
92+
rev: v0.1.7
9393
hooks:
9494
- id: ruff
9595
# `pyroma` may help keep our package standards up to date if best practices change.

Diff for: graphblas_algorithms/algorithms/operators/binary.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ def intersection(G, H, *, name="intersection"):
6767
ids = H.list_to_ids(keys)
6868
B = H._A[ids, ids].new(dtypes.unify(A.dtype, H._A.dtype), mask=A.S, name=name)
6969
B << unary.one(B)
70-
return type(G)(B, key_to_id=dict(zip(keys, range(len(keys)))))
70+
return type(G)(B, key_to_id=dict(zip(keys, range(len(keys)), strict=True)))
7171

7272

7373
def difference(G, H, *, name="difference"):
@@ -142,7 +142,7 @@ def compose(G, H, *, name="compose"):
142142
C[A.nrows :, A.ncols :] = B[ids, ids]
143143
# Now make new `key_to_id`
144144
ids += A.nrows
145-
key_to_id = dict(zip(newkeys, ids.tolist()))
145+
key_to_id = dict(zip(newkeys, ids.tolist(), strict=True))
146146
key_to_id.update(G._key_to_id)
147147
return type(G)(C, key_to_id=key_to_id)
148148

Diff for: graphblas_algorithms/algorithms/shortest_paths/weighted.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ def bellman_ford_path_lengths(G, nodes=None, *, expand_output=False):
199199

200200
def _reconstruct_path_from_parents(G, parents, src, dst):
201201
indices, values = parents.to_coo(sort=False)
202-
d = dict(zip(indices.tolist(), values.tolist()))
202+
d = dict(zip(indices.tolist(), values.tolist(), strict=True))
203203
if dst not in d:
204204
return []
205205
cur = dst

Diff for: graphblas_algorithms/classes/_utils.py

+13-10
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ def dict_to_vector(self, d, *, size=None, dtype=None, name=None):
6161
if size is None:
6262
size = len(self)
6363
key_to_id = self._key_to_id
64-
indices, values = zip(*((key_to_id[key], val) for key, val in d.items()))
64+
indices, values = zip(*((key_to_id[key], val) for key, val in d.items()), strict=True)
6565
return Vector.from_coo(indices, values, size=size, dtype=dtype, name=name)
6666

6767

@@ -116,7 +116,7 @@ def vector_to_dict(self, v, *, mask=None, fill_value=None):
116116
elif fill_value is not None and v.nvals < v.size:
117117
v(mask=~v.S) << fill_value
118118
id_to_key = self.id_to_key
119-
return {id_to_key[index]: value for index, value in zip(*v.to_coo(sort=False))}
119+
return {id_to_key[index]: value for index, value in zip(*v.to_coo(sort=False), strict=True)}
120120

121121

122122
def vector_to_list(self, v, *, values_are_keys=False):
@@ -198,26 +198,29 @@ def matrix_to_dicts(self, A, *, use_row_index=False, use_column_index=False, val
198198
id_to_key = self.id_to_key
199199
if values_are_keys:
200200
values = [id_to_key[val] for val in values]
201-
it = zip(rows, np.lib.stride_tricks.sliding_window_view(indptr, 2).tolist())
201+
it = zip(rows, np.lib.stride_tricks.sliding_window_view(indptr, 2).tolist(), strict=True)
202202
if use_row_index and use_column_index:
203203
return {
204-
row: dict(zip(col_indices[start:stop], values[start:stop])) for row, (start, stop) in it
204+
row: dict(zip(col_indices[start:stop], values[start:stop], strict=True))
205+
for row, (start, stop) in it
205206
}
206207
if use_row_index:
207208
return {
208209
row: {
209-
id_to_key[col]: val for col, val in zip(col_indices[start:stop], values[start:stop])
210+
id_to_key[col]: val
211+
for col, val in zip(col_indices[start:stop], values[start:stop], strict=True)
210212
}
211213
for row, (start, stop) in it
212214
}
213215
if use_column_index:
214216
return {
215-
id_to_key[row]: dict(zip(col_indices[start:stop], values[start:stop]))
217+
id_to_key[row]: dict(zip(col_indices[start:stop], values[start:stop], strict=True))
216218
for row, (start, stop) in it
217219
}
218220
return {
219221
id_to_key[row]: {
220-
id_to_key[col]: val for col, val in zip(col_indices[start:stop], values[start:stop])
222+
id_to_key[col]: val
223+
for col, val in zip(col_indices[start:stop], values[start:stop], strict=True)
221224
}
222225
for row, (start, stop) in it
223226
}
@@ -239,9 +242,9 @@ def to_networkx(self, edge_attribute="weight"):
239242
rows = (id_to_key[row] for row in rows.tolist())
240243
cols = (id_to_key[col] for col in cols.tolist())
241244
if edge_attribute is None:
242-
G.add_edges_from(zip(rows, cols))
245+
G.add_edges_from(zip(rows, cols, strict=True))
243246
else:
244-
G.add_weighted_edges_from(zip(rows, cols, vals), weight=edge_attribute)
247+
G.add_weighted_edges_from(zip(rows, cols, vals, strict=True), weight=edge_attribute)
245248
# What else should we copy over?
246249
return G
247250

@@ -258,4 +261,4 @@ def renumber_key_to_id(self, indices):
258261
return {id_to_key[index]: i for i, index in enumerate(indices)}
259262
# Alternative (about the same performance)
260263
# keys = self.list_to_keys(indices)
261-
# return dict(zip(keys, range(len(indices))))
264+
# return dict(zip(keys, range(len(indices)), strict=True))

Diff for: graphblas_algorithms/interface.py

+16-16
Original file line numberDiff line numberDiff line change
@@ -281,31 +281,31 @@ def key(testpath):
281281
return (testname, frozenset({filename}))
282282

283283
# Reasons to skip tests
284-
multi_attributed = "unable to handle multi-attributed graphs"
284+
# multi_attributed = "unable to handle multi-attributed graphs"
285285
multidigraph = "unable to handle MultiDiGraph"
286286
multigraph = "unable to handle MultiGraph"
287287

288288
# Which tests to skip
289289
skip = {
290-
key("test_mst.py:TestBoruvka.test_attributes"): multi_attributed,
291-
key("test_mst.py:TestBoruvka.test_weight_attribute"): multi_attributed,
290+
# key("test_mst.py:TestBoruvka.test_attributes"): multi_attributed,
291+
# key("test_mst.py:TestBoruvka.test_weight_attribute"): multi_attributed,
292292
key("test_dense.py:TestFloyd.test_zero_weight"): multidigraph,
293293
key("test_dense_numpy.py:test_zero_weight"): multidigraph,
294294
key("test_weighted.py:TestBellmanFordAndGoldbergRadzik.test_multigraph"): multigraph,
295-
key("test_binary.py:test_compose_multigraph"): multigraph,
296-
key("test_binary.py:test_difference_multigraph_attributes"): multigraph,
297-
key("test_binary.py:test_disjoint_union_multigraph"): multigraph,
298-
key("test_binary.py:test_full_join_multigraph"): multigraph,
299-
key("test_binary.py:test_intersection_multigraph_attributes"): multigraph,
300-
key(
301-
"test_binary.py:test_intersection_multigraph_attributes_node_set_different"
302-
): multigraph,
303-
key("test_binary.py:test_symmetric_difference_multigraph"): multigraph,
304-
key("test_binary.py:test_union_attributes"): multi_attributed,
295+
# key("test_binary.py:test_compose_multigraph"): multigraph,
296+
# key("test_binary.py:test_difference_multigraph_attributes"): multigraph,
297+
# key("test_binary.py:test_disjoint_union_multigraph"): multigraph,
298+
# key("test_binary.py:test_full_join_multigraph"): multigraph,
299+
# key("test_binary.py:test_intersection_multigraph_attributes"): multigraph,
300+
# key(
301+
# "test_binary.py:test_intersection_multigraph_attributes_node_set_different"
302+
# ): multigraph,
303+
# key("test_binary.py:test_symmetric_difference_multigraph"): multigraph,
304+
# key("test_binary.py:test_union_attributes"): multi_attributed,
305305
# TODO: move failing assertion from `test_union_and_compose`
306-
key("test_binary.py:test_union_and_compose"): multi_attributed,
307-
key("test_binary.py:test_union_multigraph"): multigraph,
308-
key("test_vf2pp.py:test_custom_multigraph4_different_labels"): multigraph,
306+
# key("test_binary.py:test_union_and_compose"): multi_attributed,
307+
# key("test_binary.py:test_union_multigraph"): multigraph,
308+
# key("test_vf2pp.py:test_custom_multigraph4_different_labels"): multigraph,
309309
}
310310
for item in items:
311311
kset = set(item.keywords)

Diff for: graphblas_algorithms/nxapi/boundary.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,19 @@ def edge_boundary(G, nbunch1, nbunch2=None, data=False, keys=False, default=None
2929
(id_to_key[col] for col in cols),
3030
# Unsure about this; data argument may mean *all* edge attributes
3131
({weight: val} for val in vals),
32+
strict=True,
3233
)
3334
else:
3435
it = zip(
3536
(id_to_key[row] for row in rows),
3637
(id_to_key[col] for col in cols),
38+
strict=True,
3739
)
3840
if is_multigraph:
3941
# Edge weights indicate number of times to repeat edges
40-
it = itertools.chain.from_iterable(itertools.starmap(itertools.repeat, zip(it, vals)))
42+
it = itertools.chain.from_iterable(
43+
itertools.starmap(itertools.repeat, zip(it, vals, strict=True))
44+
)
4145
return it
4246

4347

Diff for: pyproject.toml

+4-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.9"
13+
requires-python = ">=3.10"
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.9",
4746
"Programming Language :: Python :: 3.10",
4847
"Programming Language :: Python :: 3.11",
4948
"Programming Language :: Python :: 3.12",
@@ -134,7 +133,7 @@ dirty_template = "{tag}+{ccount}.g{sha}.dirty"
134133

135134
[tool.black]
136135
line-length = 100
137-
target-version = ["py39", "py310", "py311", "py312"]
136+
target-version = ["py310", "py311", "py312"]
138137

139138
[tool.isort]
140139
sections = ["FUTURE", "STDLIB", "THIRDPARTY", "FIRSTPARTY", "LOCALFOLDER"]
@@ -177,7 +176,7 @@ exclude_lines = [
177176
[tool.ruff]
178177
# https://github.com/charliermarsh/ruff/
179178
line-length = 100
180-
target-version = "py39"
179+
target-version = "py310"
181180
unfixable = [
182181
"F841" # unused-variable (Note: can leave useless expression)
183182
]
@@ -205,6 +204,7 @@ ignore = [
205204
# "SIM401", # Use dict.get ... instead of if-else-block (Note: if-else better for coverage and sometimes clearer)
206205
# "TRY004", # Prefer `TypeError` exception for invalid type (Note: good advice, but not worth the nuisance)
207206
# "TRY200", # Use `raise from` to specify exception cause (Note: sometimes okay to raise original exception)
207+
"UP038", # Use `X | Y` in `isinstance` call instead of `(X, Y)` (Note: using `|` seems to be slower)
208208

209209
# Intentionally ignored
210210
"COM812", # Trailing comma missing

Diff for: scripts/scipy_impl.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ def pagerank(
5050
err = np.absolute(x - xlast).sum()
5151
if err < N * tol:
5252
return x
53-
# return dict(zip(nodelist, map(float, x)))
53+
# return dict(zip(nodelist, map(float, x), strict=True))
5454
raise nx.PowerIterationFailedConvergence(max_iter)
5555

5656

0 commit comments

Comments
 (0)