Skip to content
Merged
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
8 changes: 6 additions & 2 deletions graphblas/ss/_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -259,9 +259,13 @@ class About(Mapping):
_modes = {
lib.GrB_NONBLOCKING: "nonblocking",
lib.GrB_BLOCKING: "blocking",
lib.GxB_NONBLOCKING_GPU: "nonblocking_gpu",
lib.GxB_BLOCKING_GPU: "blocking_gpu",
}
# GxB_NONBLOCKING_GPU and GxB_BLOCKING_GPU were modes of their own in SS:GraphBLAS <=10.5.1.
# In 10.5.2 they became aliases of GrB_NONBLOCKING and GrB_BLOCKING, which python-suitesparse-
# graphblas leaves out; `setdefault` keeps "nonblocking" and "blocking" if they are aliases.
if hasattr(lib, "GxB_NONBLOCKING_GPU"):
_modes.setdefault(lib.GxB_NONBLOCKING_GPU, "nonblocking_gpu")
_modes.setdefault(lib.GxB_BLOCKING_GPU, "blocking_gpu")
_mode_options = {
"mode": lib.GxB_MODE,
}
Expand Down
3 changes: 3 additions & 0 deletions graphblas/tests/test_matrix.py
Original file line number Diff line number Diff line change
Expand Up @@ -2084,6 +2084,9 @@ def test_ss_import_export(A, do_iso, methods):
assert A5.isequal(A)
assert A5.ss.is_iso is do_iso
d["bitmap"] = np.concatenate([d["bitmap"], d["bitmap"]], axis=0)
if not do_iso:
# Values for the whole bitmap; GraphBLAS reads them all
d["values"] = np.concatenate([d["values"], d["values"]], axis=0)
B5b = Matrix.ss.import_any(**d)
if in_method == "import":
# B5b == [A, A] (i.e, get 2d shape from bitmap first if possible)
Expand Down
2 changes: 2 additions & 0 deletions graphblas/tests/test_ss_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,8 @@ def test_about():
with pytest.raises(KeyError):
about["badkey"]
assert "SuiteSparse" in about["library_name"]
# SS:GraphBLAS 10.5.2 made the GPU modes aliases of these; neither may read as a GPU mode
assert about["mode"] == ("blocking" if gb._init_params["blocking"] else "nonblocking")
with pytest.raises(TypeError):
del about["library_name"] # pylint: disable=unsupported-delete-operation
assert "library_name" in repr(about)
Expand Down
1 change: 1 addition & 0 deletions scripts/check_versions.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
conda search 'flake8-bugbear[channel=conda-forge]>=26.9.9'
conda search 'flake8-simplify[channel=conda-forge]>=0.30.0'
conda search 'numpy[channel=conda-forge]>=2.5'
# ci_pick_versions.py caps an unpinned pandas below 3.1 for now (see its MAINT note).
conda search 'pandas[channel=conda-forge]>=3.0'
conda search 'scipy[channel=conda-forge]>=1.18'
conda search 'networkx[channel=conda-forge]>=3.6'
Expand Down
17 changes: 14 additions & 3 deletions scripts/ci_pick_versions.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,14 @@
"2.x": ["2.2", "2.3", "3.0", ""],
}

# Caps on an unpinned ("" = latest) pick, as conda specs. Pins in the pools are not
# affected; a capped package's newest release stays out of CI until the cap goes.
# MAINT: 2026-10-22 pandas 3.1.0 fits fewer columns in a repr's auto-width
# (display.max_columns=0), and warns (Pandas4Warning) when the pandas-based repr renderer
# appends its "..." row to a numeric column; both fail test_formatting.py. Remove the cap
# once #605 (the repr renderer that does not use pandas) is on main.
LATEST_CEILINGS = {"pandas": "<3.1"}

# The "2.x" pool starts at 2.6 because awkward <2.6 still uses numpy.AxisError,
# which numpy 2.0 removed. Only >=2.10 pins survive numpy >=2.5; see the awkward
# constraints in `apply_constraints`.
Expand Down Expand Up @@ -557,14 +565,17 @@ def format_output(v):
"""Format version dict as bash-eval-safe key=value lines.

Values use '=X.Y' prefix for conda install (e.g., npver='=2.2').
Empty means latest, NA means skip.
Empty means latest, NA means skip. Latest is capped by LATEST_CEILINGS
(e.g., pdver='<3.1').
psg already has its prefix baked in.
"""
lines = []
for key in ("numpy", "scipy", "pandas", "awkward", "networkx", "pyyaml", "sparse", "numba"):
var = _VAR_NAMES[key]
val = v[key]
if val in ("NA", ""):
if val == "" and key in LATEST_CEILINGS:
lines.append(f"{var}='{LATEST_CEILINGS[key]}'")
elif val in ("NA", ""):
lines.append(f"{var}='{val}'")
else:
lines.append(f"{var}='={val}'")
Expand Down Expand Up @@ -598,7 +609,7 @@ def format_summary(v):
if val == "NA":
parts.append(f"{name}=NA")
elif val == "":
parts.append(f"{name}=latest")
parts.append(f"{name}=latest{LATEST_CEILINGS.get(key, '')}")
else:
parts.append(f"{name}={val}")
return "versions: " + " ".join(parts)
Expand Down
Loading