python-graphblas 2023.5.0__py3-none-any.whl → 2023.7.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. graphblas/agg/__init__.py +4 -4
  2. graphblas/binary/ss.py +3 -0
  3. graphblas/core/agg.py +2 -2
  4. graphblas/core/automethods.py +1 -1
  5. graphblas/core/base.py +3 -3
  6. graphblas/core/descriptor.py +1 -0
  7. graphblas/{dtypes.py → core/dtypes.py} +99 -109
  8. graphblas/core/expr.py +1 -1
  9. graphblas/core/mask.py +5 -5
  10. graphblas/core/matrix.py +18 -18
  11. graphblas/core/operator/base.py +1 -1
  12. graphblas/core/operator/binary.py +3 -3
  13. graphblas/core/operator/indexunary.py +4 -3
  14. graphblas/core/operator/semiring.py +2 -2
  15. graphblas/core/operator/unary.py +3 -3
  16. graphblas/core/recorder.py +1 -1
  17. graphblas/core/scalar.py +1 -1
  18. graphblas/core/ss/__init__.py +3 -0
  19. graphblas/core/ss/binary.py +72 -0
  20. graphblas/core/ss/config.py +46 -11
  21. graphblas/core/ss/context.py +146 -0
  22. graphblas/core/ss/descriptor.py +21 -9
  23. graphblas/core/ss/dtypes.py +88 -0
  24. graphblas/core/ss/indexunary.py +77 -0
  25. graphblas/core/ss/matrix.py +84 -83
  26. graphblas/core/ss/select.py +45 -0
  27. graphblas/core/ss/unary.py +62 -0
  28. graphblas/core/ss/vector.py +38 -37
  29. graphblas/core/utils.py +14 -12
  30. graphblas/core/vector.py +14 -11
  31. graphblas/dtypes/__init__.py +43 -0
  32. graphblas/dtypes/ss.py +1 -0
  33. graphblas/indexunary/__init__.py +13 -1
  34. graphblas/indexunary/ss.py +6 -0
  35. graphblas/io/_awkward.py +58 -52
  36. graphblas/io/_matrixmarket.py +12 -3
  37. graphblas/io/_numpy.py +6 -6
  38. graphblas/monoid/__init__.py +13 -1
  39. graphblas/monoid/ss.py +5 -0
  40. graphblas/op/ss.py +2 -0
  41. graphblas/select/__init__.py +19 -7
  42. graphblas/select/ss.py +6 -0
  43. graphblas/semiring/ss.py +2 -0
  44. graphblas/ss/__init__.py +5 -1
  45. graphblas/ss/_core.py +67 -13
  46. graphblas/tests/conftest.py +33 -6
  47. graphblas/tests/test_core.py +4 -1
  48. graphblas/tests/test_dtype.py +23 -6
  49. graphblas/tests/test_io.py +21 -5
  50. graphblas/tests/test_matrix.py +1 -1
  51. graphblas/tests/test_op.py +14 -2
  52. graphblas/tests/test_ssjit.py +269 -0
  53. graphblas/tests/test_vector.py +12 -5
  54. graphblas/unary/ss.py +3 -0
  55. graphblas/viz.py +4 -5
  56. {python_graphblas-2023.5.0.dist-info → python_graphblas-2023.7.0.dist-info}/LICENSE +1 -1
  57. {python_graphblas-2023.5.0.dist-info → python_graphblas-2023.7.0.dist-info}/METADATA +25 -8
  58. python_graphblas-2023.7.0.dist-info/RECORD +110 -0
  59. python_graphblas-2023.5.0.dist-info/RECORD +0 -98
  60. {python_graphblas-2023.5.0.dist-info → python_graphblas-2023.7.0.dist-info}/WHEEL +0 -0
  61. {python_graphblas-2023.5.0.dist-info → python_graphblas-2023.7.0.dist-info}/top_level.txt +0 -0
graphblas/agg/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
- """`graphblas.agg` is an experimental module for exploring Aggregators.
1
+ """``graphblas.agg`` is an experimental module for exploring Aggregators.
2
2
 
3
3
  Aggregators may be used in reduce methods:
4
4
  - Matrix.reduce_rowwise
@@ -59,9 +59,9 @@ Custom recipes (specific to SuiteSparse:GraphBLAS):
59
59
  - ss.argmax
60
60
 
61
61
  .. deprecated:: 2023.1.0
62
- Aggregators `first`, `last`, `first_index`, `last_index`, `argmin`, and `argmax` are
63
- deprecated in the `agg` namespace such as `agg.first`. Use them from `agg.ss` namespace
64
- instead such as `agg.ss.first`. Will be removed in version 2023.9.0 or later.
62
+ Aggregators ``first``, ``last``, ``first_index``, ``last_index``, ``argmin``, and ``argmax``
63
+ are deprecated in the ``agg`` namespace such as ``agg.first``. Use them from ``agg.ss``
64
+ namespace instead such as ``agg.ss.first``. Will be removed in version 2023.9.0 or later.
65
65
 
66
66
  # Possible aggregators:
67
67
  # - absolute_deviation, sum(abs(x - mean(x))), sum_absminus(x, mean(x))
graphblas/binary/ss.py CHANGED
@@ -1,3 +1,6 @@
1
1
  from ..core import operator
2
+ from ..core.ss.binary import register_new # noqa: F401
3
+
4
+ _delayed = {}
2
5
 
3
6
  del operator
graphblas/core/agg.py CHANGED
@@ -1,8 +1,8 @@
1
1
  """graphblas.core.agg namespace is deprecated; please use graphblas.core.operator.agg instead.
2
2
 
3
3
  .. deprecated:: 2023.3.0
4
- `graphblas.core.agg` will be removed in a future release.
5
- Use `graphblas.core.operator.agg` instead.
4
+ ``graphblas.core.agg`` will be removed in a future release.
5
+ Use ``graphblas.core.operator.agg`` instead.
6
6
  Will be removed in version 2023.11.0 or later.
7
7
 
8
8
  """
@@ -1,6 +1,6 @@
1
1
  """Define functions to use as property methods on expressions.
2
2
 
3
- These will automatically compute the value and avoid the need for `.new()`.
3
+ These will automatically compute the value and avoid the need for ``.new()``.
4
4
 
5
5
  To automatically create the functions, run:
6
6
 
graphblas/core/base.py CHANGED
@@ -348,7 +348,7 @@ class BaseType:
348
348
  return
349
349
  if opts:
350
350
  # Ignore opts for now
351
- descriptor_lookup(**opts)
351
+ desc = descriptor_lookup(**opts)
352
352
  self.value = expr
353
353
  return
354
354
 
@@ -371,7 +371,7 @@ class BaseType:
371
371
  else:
372
372
  if opts:
373
373
  # Ignore opts for now
374
- descriptor_lookup(**opts)
374
+ desc = descriptor_lookup(**opts)
375
375
  self.value = expr
376
376
  return
377
377
  else:
@@ -571,7 +571,7 @@ class BaseExpression:
571
571
  ):
572
572
  if opts:
573
573
  # Ignore opts for now
574
- descriptor_lookup(**opts)
574
+ desc = descriptor_lookup(**opts) # noqa: F841 (keep desc in scope for context)
575
575
  if self._is_scalar and self._value._is_cscalar != is_cscalar:
576
576
  return self._value.dup(is_cscalar=is_cscalar, name=name)
577
577
  rv = self._value
@@ -26,6 +26,7 @@ class Descriptor:
26
26
  self.mask_structure = mask_structure
27
27
  self.transpose_first = transpose_first
28
28
  self.transpose_second = transpose_second
29
+ self._context = None # Used by SuiteSparse:GraphBLAS 8
29
30
 
30
31
  @property
31
32
  def _carg(self):
@@ -1,20 +1,16 @@
1
- import warnings as _warnings
1
+ import warnings
2
2
 
3
- import numpy as _np
4
- from numpy import find_common_type as _find_common_type
5
- from numpy import promote_types as _promote_types
3
+ import numpy as np
4
+ from numpy import promote_types, result_type
6
5
 
7
- from . import backend
8
- from .core import NULL as _NULL
9
- from .core import _has_numba
10
- from .core import ffi as _ffi
11
- from .core import lib as _lib
6
+ from .. import backend, dtypes
7
+ from ..core import NULL, _has_numba, ffi, lib
12
8
 
13
9
  if _has_numba:
14
- import numba as _numba
10
+ import numba
15
11
 
16
12
  # Default assumption unless FC32/FC64 are found in lib
17
- _supports_complex = hasattr(_lib, "GrB_FC64") or hasattr(_lib, "GxB_FC64")
13
+ _supports_complex = hasattr(lib, "GrB_FC64") or hasattr(lib, "GxB_FC64")
18
14
 
19
15
 
20
16
  class DataType:
@@ -26,7 +22,7 @@ class DataType:
26
22
  self.gb_name = gb_name
27
23
  self.c_type = c_type
28
24
  self.numba_type = numba_type
29
- self.np_type = _np.dtype(np_type)
25
+ self.np_type = np.dtype(np_type) if np_type is not None else None
30
26
 
31
27
  def __repr__(self):
32
28
  return self.name
@@ -62,7 +58,7 @@ class DataType:
62
58
 
63
59
  @property
64
60
  def _is_anonymous(self):
65
- return globals().get(self.name) is not self
61
+ return getattr(dtypes, self.name, None) is not self
66
62
 
67
63
  @property
68
64
  def _is_udt(self):
@@ -80,27 +76,29 @@ class DataType:
80
76
  def register_new(name, dtype):
81
77
  if not name.isidentifier():
82
78
  raise ValueError(f"`name` argument must be a valid Python identifier; got: {name!r}")
83
- if name in _registry or name in globals():
79
+ if name in _registry or hasattr(dtypes, name):
84
80
  raise ValueError(f"{name!r} name for dtype is unavailable")
85
81
  rv = register_anonymous(dtype, name)
86
82
  _registry[name] = rv
87
- globals()[name] = rv
83
+ setattr(dtypes, name, rv)
88
84
  return rv
89
85
 
90
86
 
91
87
  def register_anonymous(dtype, name=None):
92
88
  try:
93
- dtype = _np.dtype(dtype)
89
+ dtype = np.dtype(dtype)
94
90
  except TypeError:
95
91
  if isinstance(dtype, dict):
96
92
  # Allow dtypes such as `{'x': int, 'y': float}` for convenience
97
- dtype = _np.dtype([(key, lookup_dtype(val).np_type) for key, val in dtype.items()])
93
+ dtype = np.dtype(
94
+ [(key, lookup_dtype(val).np_type) for key, val in dtype.items()], align=True
95
+ )
98
96
  elif isinstance(dtype, str) and "[" in dtype and dtype.endswith("]"):
99
97
  # Allow dtypes such as `"INT64[3, 4]"` for convenience
100
98
  base_dtype, shape = dtype.split("[", 1)
101
99
  base_dtype = lookup_dtype(base_dtype)
102
- shape = _np.lib.format.safe_eval(f"[{shape}")
103
- dtype = _np.dtype((base_dtype.np_type, shape))
100
+ shape = np.lib.format.safe_eval(f"[{shape}")
101
+ dtype = np.dtype((base_dtype.np_type, shape))
104
102
  else:
105
103
  raise
106
104
  if dtype in _registry:
@@ -114,36 +112,36 @@ def register_anonymous(dtype, name=None):
114
112
  if dtype.hasobject:
115
113
  raise ValueError("dtype must not allow Python objects")
116
114
 
117
- from .exceptions import check_status_carg
115
+ from ..exceptions import check_status_carg
118
116
 
119
- gb_obj = _ffi.new("GrB_Type*")
117
+ gb_obj = ffi.new("GrB_Type*")
120
118
  if backend == "suitesparse":
121
119
  # We name this so that we can serialize and deserialize UDTs
122
120
  # We don't yet have C definitions
123
121
  np_repr = _dtype_to_string(dtype).encode()
124
- if len(np_repr) > _lib.GxB_MAX_NAME_LEN:
122
+ if len(np_repr) > lib.GxB_MAX_NAME_LEN:
125
123
  msg = (
126
124
  f"UDT repr is too large to serialize ({len(repr(dtype).encode())} > "
127
- f"{_lib.GxB_MAX_NAME_LEN})."
125
+ f"{lib.GxB_MAX_NAME_LEN})."
128
126
  )
129
127
  if name is not None:
130
- np_repr = name.encode()[: _lib.GxB_MAX_NAME_LEN]
128
+ np_repr = name.encode()[: lib.GxB_MAX_NAME_LEN]
131
129
  else:
132
- np_repr = np_repr[: _lib.GxB_MAX_NAME_LEN]
133
- _warnings.warn(
130
+ np_repr = np_repr[: lib.GxB_MAX_NAME_LEN]
131
+ warnings.warn(
134
132
  f"{msg}. It will use the following name, "
135
133
  f"and the dtype may need to be specified when deserializing: {np_repr}",
136
134
  stacklevel=2,
137
135
  )
138
- status = _lib.GxB_Type_new(gb_obj, dtype.itemsize, np_repr, _NULL)
136
+ status = lib.GxB_Type_new(gb_obj, dtype.itemsize, np_repr, NULL)
139
137
  else:
140
- status = _lib.GrB_Type_new(gb_obj, dtype.itemsize)
138
+ status = lib.GrB_Type_new(gb_obj, dtype.itemsize)
141
139
  check_status_carg(status, "Type", gb_obj[0])
142
140
 
143
141
  # For now, let's use "opaque" unsigned bytes for the c type.
144
142
  if name is None:
145
143
  name = _default_name(dtype)
146
- numba_type = _numba.typeof(dtype).dtype if _has_numba else None
144
+ numba_type = numba.typeof(dtype).dtype if _has_numba else None
147
145
  rv = DataType(name, gb_obj, None, f"uint8_t[{dtype.itemsize}]", numba_type, dtype)
148
146
  _registry[gb_obj] = rv
149
147
  _registry[dtype] = rv
@@ -155,153 +153,153 @@ def register_anonymous(dtype, name=None):
155
153
 
156
154
  BOOL = DataType(
157
155
  "BOOL",
158
- _lib.GrB_BOOL,
156
+ lib.GrB_BOOL,
159
157
  "GrB_BOOL",
160
158
  "_Bool",
161
- _numba.types.bool_ if _has_numba else None,
162
- _np.bool_,
159
+ numba.types.bool_ if _has_numba else None,
160
+ np.bool_,
163
161
  )
164
162
  INT8 = DataType(
165
- "INT8", _lib.GrB_INT8, "GrB_INT8", "int8_t", _numba.types.int8 if _has_numba else None, _np.int8
163
+ "INT8", lib.GrB_INT8, "GrB_INT8", "int8_t", numba.types.int8 if _has_numba else None, np.int8
166
164
  )
167
165
  UINT8 = DataType(
168
166
  "UINT8",
169
- _lib.GrB_UINT8,
167
+ lib.GrB_UINT8,
170
168
  "GrB_UINT8",
171
169
  "uint8_t",
172
- _numba.types.uint8 if _has_numba else None,
173
- _np.uint8,
170
+ numba.types.uint8 if _has_numba else None,
171
+ np.uint8,
174
172
  )
175
173
  INT16 = DataType(
176
174
  "INT16",
177
- _lib.GrB_INT16,
175
+ lib.GrB_INT16,
178
176
  "GrB_INT16",
179
177
  "int16_t",
180
- _numba.types.int16 if _has_numba else None,
181
- _np.int16,
178
+ numba.types.int16 if _has_numba else None,
179
+ np.int16,
182
180
  )
183
181
  UINT16 = DataType(
184
182
  "UINT16",
185
- _lib.GrB_UINT16,
183
+ lib.GrB_UINT16,
186
184
  "GrB_UINT16",
187
185
  "uint16_t",
188
- _numba.types.uint16 if _has_numba else None,
189
- _np.uint16,
186
+ numba.types.uint16 if _has_numba else None,
187
+ np.uint16,
190
188
  )
191
189
  INT32 = DataType(
192
190
  "INT32",
193
- _lib.GrB_INT32,
191
+ lib.GrB_INT32,
194
192
  "GrB_INT32",
195
193
  "int32_t",
196
- _numba.types.int32 if _has_numba else None,
197
- _np.int32,
194
+ numba.types.int32 if _has_numba else None,
195
+ np.int32,
198
196
  )
199
197
  UINT32 = DataType(
200
198
  "UINT32",
201
- _lib.GrB_UINT32,
199
+ lib.GrB_UINT32,
202
200
  "GrB_UINT32",
203
201
  "uint32_t",
204
- _numba.types.uint32 if _has_numba else None,
205
- _np.uint32,
202
+ numba.types.uint32 if _has_numba else None,
203
+ np.uint32,
206
204
  )
207
205
  INT64 = DataType(
208
206
  "INT64",
209
- _lib.GrB_INT64,
207
+ lib.GrB_INT64,
210
208
  "GrB_INT64",
211
209
  "int64_t",
212
- _numba.types.int64 if _has_numba else None,
213
- _np.int64,
210
+ numba.types.int64 if _has_numba else None,
211
+ np.int64,
214
212
  )
215
213
  # _Index (like UINT64) is for internal use only and shouldn't be exposed to the user
216
214
  _INDEX = DataType(
217
215
  "UINT64",
218
- _lib.GrB_UINT64,
216
+ lib.GrB_UINT64,
219
217
  "GrB_Index",
220
218
  "GrB_Index",
221
- _numba.types.uint64 if _has_numba else None,
222
- _np.uint64,
219
+ numba.types.uint64 if _has_numba else None,
220
+ np.uint64,
223
221
  )
224
222
  UINT64 = DataType(
225
223
  "UINT64",
226
- _lib.GrB_UINT64,
224
+ lib.GrB_UINT64,
227
225
  "GrB_UINT64",
228
226
  "uint64_t",
229
- _numba.types.uint64 if _has_numba else None,
230
- _np.uint64,
227
+ numba.types.uint64 if _has_numba else None,
228
+ np.uint64,
231
229
  )
232
230
  FP32 = DataType(
233
231
  "FP32",
234
- _lib.GrB_FP32,
232
+ lib.GrB_FP32,
235
233
  "GrB_FP32",
236
234
  "float",
237
- _numba.types.float32 if _has_numba else None,
238
- _np.float32,
235
+ numba.types.float32 if _has_numba else None,
236
+ np.float32,
239
237
  )
240
238
  FP64 = DataType(
241
239
  "FP64",
242
- _lib.GrB_FP64,
240
+ lib.GrB_FP64,
243
241
  "GrB_FP64",
244
242
  "double",
245
- _numba.types.float64 if _has_numba else None,
246
- _np.float64,
243
+ numba.types.float64 if _has_numba else None,
244
+ np.float64,
247
245
  )
248
246
 
249
- if _supports_complex and hasattr(_lib, "GxB_FC32"):
247
+ if _supports_complex and hasattr(lib, "GxB_FC32"):
250
248
  FC32 = DataType(
251
249
  "FC32",
252
- _lib.GxB_FC32,
250
+ lib.GxB_FC32,
253
251
  "GxB_FC32",
254
252
  "float _Complex",
255
- _numba.types.complex64 if _has_numba else None,
256
- _np.complex64,
253
+ numba.types.complex64 if _has_numba else None,
254
+ np.complex64,
257
255
  )
258
- if _supports_complex and hasattr(_lib, "GrB_FC32"): # pragma: no cover (unused)
256
+ if _supports_complex and hasattr(lib, "GrB_FC32"): # pragma: no cover (unused)
259
257
  FC32 = DataType(
260
258
  "FC32",
261
- _lib.GrB_FC32,
259
+ lib.GrB_FC32,
262
260
  "GrB_FC32",
263
261
  "float _Complex",
264
- _numba.types.complex64 if _has_numba else None,
265
- _np.complex64,
262
+ numba.types.complex64 if _has_numba else None,
263
+ np.complex64,
266
264
  )
267
- if _supports_complex and hasattr(_lib, "GxB_FC64"):
265
+ if _supports_complex and hasattr(lib, "GxB_FC64"):
268
266
  FC64 = DataType(
269
267
  "FC64",
270
- _lib.GxB_FC64,
268
+ lib.GxB_FC64,
271
269
  "GxB_FC64",
272
270
  "double _Complex",
273
- _numba.types.complex128 if _has_numba else None,
274
- _np.complex128,
271
+ numba.types.complex128 if _has_numba else None,
272
+ np.complex128,
275
273
  )
276
- if _supports_complex and hasattr(_lib, "GrB_FC64"): # pragma: no cover (unused)
274
+ if _supports_complex and hasattr(lib, "GrB_FC64"): # pragma: no cover (unused)
277
275
  FC64 = DataType(
278
276
  "FC64",
279
- _lib.GrB_FC64,
277
+ lib.GrB_FC64,
280
278
  "GrB_FC64",
281
279
  "double _Complex",
282
- _numba.types.complex128 if _has_numba else None,
283
- _np.complex128,
280
+ numba.types.complex128 if _has_numba else None,
281
+ np.complex128,
284
282
  )
285
283
 
286
284
  # Used for testing user-defined functions
287
285
  _sample_values = {
288
- INT8: _np.int8(1),
289
- UINT8: _np.uint8(1),
290
- INT16: _np.int16(1),
291
- UINT16: _np.uint16(1),
292
- INT32: _np.int32(1),
293
- UINT32: _np.uint32(1),
294
- INT64: _np.int64(1),
295
- UINT64: _np.uint64(1),
296
- FP32: _np.float32(0.5),
297
- FP64: _np.float64(0.5),
298
- BOOL: _np.bool_(True),
286
+ INT8: np.int8(1),
287
+ UINT8: np.uint8(1),
288
+ INT16: np.int16(1),
289
+ UINT16: np.uint16(1),
290
+ INT32: np.int32(1),
291
+ UINT32: np.uint32(1),
292
+ INT64: np.int64(1),
293
+ UINT64: np.uint64(1),
294
+ FP32: np.float32(0.5),
295
+ FP64: np.float64(0.5),
296
+ BOOL: np.bool_(True),
299
297
  }
300
298
  if _supports_complex:
301
299
  _sample_values.update(
302
300
  {
303
- FC32: _np.complex64(complex(0, 0.5)),
304
- FC64: _np.complex128(complex(0, 0.5)),
301
+ FC32: np.complex64(complex(0, 0.5)),
302
+ FC64: np.complex128(complex(0, 0.5)),
305
303
  }
306
304
  )
307
305
 
@@ -389,19 +387,11 @@ def unify(type1, type2, *, is_left_scalar=False, is_right_scalar=False):
389
387
  if type1 is type2:
390
388
  return type1
391
389
  if is_left_scalar:
392
- scalar_types = [type1.np_type]
393
- array_types = []
394
- elif not is_right_scalar:
395
- # Using `promote_types` is faster than `find_common_type`
396
- return lookup_dtype(_promote_types(type1.np_type, type2.np_type))
397
- else:
398
- scalar_types = []
399
- array_types = [type1.np_type]
400
- if is_right_scalar:
401
- scalar_types.append(type2.np_type)
402
- else:
403
- array_types.append(type2.np_type)
404
- return lookup_dtype(_find_common_type(array_types, scalar_types))
390
+ if not is_right_scalar:
391
+ return lookup_dtype(result_type(np.array(0, type1.np_type), type2.np_type))
392
+ elif is_right_scalar:
393
+ return lookup_dtype(result_type(type1.np_type, np.array(0, type2.np_type)))
394
+ return lookup_dtype(promote_types(type1.np_type, type2.np_type))
405
395
 
406
396
 
407
397
  def _default_name(dtype):
@@ -431,7 +421,7 @@ def _dtype_to_string(dtype):
431
421
  >>> dtype == new_dtype
432
422
  True
433
423
  """
434
- if isinstance(dtype, _np.dtype) and dtype not in _registry:
424
+ if isinstance(dtype, np.dtype) and dtype not in _registry:
435
425
  np_type = dtype
436
426
  else:
437
427
  dtype = lookup_dtype(dtype)
@@ -440,11 +430,11 @@ def _dtype_to_string(dtype):
440
430
  np_type = dtype.np_type
441
431
  s = str(np_type)
442
432
  try:
443
- if _np.dtype(_np.lib.format.safe_eval(s)) == np_type: # pragma: no branch (safety)
433
+ if np.dtype(np.lib.format.safe_eval(s)) == np_type: # pragma: no branch (safety)
444
434
  return s
445
435
  except Exception:
446
436
  pass
447
- if _np.dtype(np_type.str) != np_type: # pragma: no cover (safety)
437
+ if np.dtype(np_type.str) != np_type: # pragma: no cover (safety)
448
438
  raise ValueError(f"Unable to reliably convert dtype to string and back: {dtype}")
449
439
  return repr(np_type.str)
450
440
 
@@ -459,5 +449,5 @@ def _string_to_dtype(s):
459
449
  return lookup_dtype(s)
460
450
  except Exception:
461
451
  pass
462
- np_type = _np.dtype(_np.lib.format.safe_eval(s))
452
+ np_type = np.dtype(np.lib.format.safe_eval(s))
463
453
  return lookup_dtype(np_type)
graphblas/core/expr.py CHANGED
@@ -421,7 +421,7 @@ class Updater:
421
421
  # Fast path using assignElement
422
422
  if self.opts:
423
423
  # Ignore opts for now
424
- descriptor_lookup(**self.opts)
424
+ desc = descriptor_lookup(**self.opts) # noqa: F841 (keep desc in scope for context)
425
425
  self.parent._assign_element(resolved_indexes, obj)
426
426
  else:
427
427
  mask = self.kwargs.get("mask")
graphblas/core/mask.py CHANGED
@@ -35,7 +35,7 @@ class Mask:
35
35
  """Return a new object with True values determined by the mask(s).
36
36
 
37
37
  By default, the result is True wherever the mask(s) would have been applied,
38
- and empty otherwise. If `complement` is True, then these are switched:
38
+ and empty otherwise. If ``complement`` is True, then these are switched:
39
39
  the result is empty where the mask(s) would have been applied, and True otherwise.
40
40
 
41
41
  In other words, these are equivalent if complement is False (and mask keyword is None):
@@ -48,14 +48,14 @@ class Mask:
48
48
  >>> C(self) << expr
49
49
  >>> C(~result.S) << expr # equivalent when complement is True
50
50
 
51
- This can also efficiently merge two masks by using the `mask=` argument.
51
+ This can also efficiently merge two masks by using the ``mask=`` argument.
52
52
  This is equivalent to the following (but uses more efficient recipes):
53
53
 
54
54
  >>> val = Matrix(...)
55
55
  >>> val(self) << True
56
56
  >>> val(mask, replace=True) << val
57
57
 
58
- If `complement=` argument is True, then the *complement* will be returned.
58
+ If ``complement=`` argument is True, then the *complement* will be returned.
59
59
  This is equivalent to the following (but uses more efficient recipes):
60
60
 
61
61
  >>> val = Matrix(...)
@@ -83,7 +83,7 @@ class Mask:
83
83
  def __and__(self, other, **opts):
84
84
  """Return the intersection of two masks as a new mask.
85
85
 
86
- `new_mask = mask1 & mask2` is equivalent to the following:
86
+ ``new_mask = mask1 & mask2`` is equivalent to the following:
87
87
 
88
88
  >>> val = Matrix(bool, nrows, ncols)
89
89
  >>> val(mask1) << True
@@ -109,7 +109,7 @@ class Mask:
109
109
  def __or__(self, other, **opts):
110
110
  """Return the union of two masks as a new mask.
111
111
 
112
- `new_mask = mask1 | mask2` is equivalent to the following:
112
+ ``new_mask = mask1 | mask2`` is equivalent to the following:
113
113
 
114
114
  >>> val = Matrix(bool, nrows, ncols)
115
115
  >>> val(mask1) << True
graphblas/core/matrix.py CHANGED
@@ -355,7 +355,7 @@ class Matrix(BaseType):
355
355
  Returns
356
356
  -------
357
357
  bool
358
- Whether all values of the Matrix are close to the values in `other`.
358
+ Whether all values of the Matrix are close to the values in ``other``.
359
359
  """
360
360
  other = self._expect_type(
361
361
  other, (Matrix, TransposedMatrix), within="isclose", argname="other"
@@ -448,19 +448,19 @@ class Matrix(BaseType):
448
448
  corresponding to the COO format of the Matrix.
449
449
 
450
450
  .. deprecated:: 2022.11.0
451
- `Matrix.to_values` will be removed in a future release.
452
- Use `Matrix.to_coo` instead. Will be removed in version 2023.9.0 or later
451
+ ``Matrix.to_values`` will be removed in a future release.
452
+ Use ``Matrix.to_coo`` instead. Will be removed in version 2023.9.0 or later
453
453
 
454
454
  Parameters
455
455
  ----------
456
456
  dtype :
457
457
  Requested dtype for the output values array.
458
458
  rows : bool, default=True
459
- Whether to return rows; will return `None` for rows if `False`
460
- columns :bool, default=True
461
- Whether to return columns; will return `None` for columns if `False`
459
+ Whether to return rows; will return ``None`` for rows if ``False``
460
+ columns : bool, default=True
461
+ Whether to return columns; will return ``None`` for columns if ``False``
462
462
  values : bool, default=True
463
- Whether to return values; will return `None` for values if `False`
463
+ Whether to return values; will return ``None`` for values if ``False``
464
464
  sort : bool, default=True
465
465
  Whether to require sorted indices.
466
466
  If internally stored rowwise, the sorting will be first by rows, then by column.
@@ -488,11 +488,11 @@ class Matrix(BaseType):
488
488
  dtype :
489
489
  Requested dtype for the output values array.
490
490
  rows : bool, default=True
491
- Whether to return rows; will return `None` for rows if `False`
491
+ Whether to return rows; will return ``None`` for rows if ``False``
492
492
  columns :bool, default=True
493
- Whether to return columns; will return `None` for columns if `False`
493
+ Whether to return columns; will return ``None`` for columns if ``False``
494
494
  values : bool, default=True
495
- Whether to return values; will return `None` for values if `False`
495
+ Whether to return values; will return ``None`` for values if ``False``
496
496
  sort : bool, default=True
497
497
  Whether to require sorted indices.
498
498
  If internally stored rowwise, the sorting will be first by rows, then by column.
@@ -559,7 +559,7 @@ class Matrix(BaseType):
559
559
  dtype :
560
560
  Requested dtype for the output values array.
561
561
  values : bool, default=True
562
- Whether to return values; will return `None` for values if `False`
562
+ Whether to return values; will return ``None`` for values if ``False``
563
563
  sort : bool, default=True
564
564
  Whether to require sorted indices.
565
565
  If internally stored rowwise, the sorting will be first by rows, then by column.
@@ -585,7 +585,7 @@ class Matrix(BaseType):
585
585
  The typical use case is to create a new Matrix and insert values
586
586
  at the same time using :meth:`from_coo`.
587
587
 
588
- All the arguments are used identically in :meth:`from_coo`, except for `clear`, which
588
+ All the arguments are used identically in :meth:`from_coo`, except for ``clear``, which
589
589
  indicates whether to clear the Matrix prior to adding the new values.
590
590
  """
591
591
  # TODO: accept `dtype` keyword to match the dtype of `values`?
@@ -665,7 +665,7 @@ class Matrix(BaseType):
665
665
  else:
666
666
  if opts:
667
667
  # Ignore opts for now
668
- descriptor_lookup(**opts)
668
+ desc = descriptor_lookup(**opts) # noqa: F841 (keep desc in scope for context)
669
669
  new_mat = ffi_new("GrB_Matrix*")
670
670
  rv = Matrix._from_obj(new_mat, self.dtype, self._nrows, self._ncols, name=name)
671
671
  call("GrB_Matrix_dup", [_Pointer(rv), self])
@@ -781,8 +781,8 @@ class Matrix(BaseType):
781
781
  """Create a new Matrix from row and column indices and values.
782
782
 
783
783
  .. deprecated:: 2022.11.0
784
- `Matrix.from_values` will be removed in a future release.
785
- Use `Matrix.from_coo` instead. Will be removed in version 2023.9.0 or later
784
+ ``Matrix.from_values`` will be removed in a future release.
785
+ Use ``Matrix.from_coo`` instead. Will be removed in version 2023.9.0 or later
786
786
 
787
787
  Parameters
788
788
  ----------
@@ -1086,7 +1086,7 @@ class Matrix(BaseType):
1086
1086
  Parameters
1087
1087
  ----------
1088
1088
  indptr : list or np.ndarray
1089
- Pointers for each row into col_indices and values; `indptr.size == nrows + 1`.
1089
+ Pointers for each row into col_indices and values; ``indptr.size == nrows + 1``.
1090
1090
  col_indices : list or np.ndarray
1091
1091
  Column indices.
1092
1092
  values : list or np.ndarray or scalar, default 1.0
@@ -1133,7 +1133,7 @@ class Matrix(BaseType):
1133
1133
  Parameters
1134
1134
  ----------
1135
1135
  indptr : list or np.ndarray
1136
- Pointers for each column into row_indices and values; `indptr.size == ncols + 1`.
1136
+ Pointers for each column into row_indices and values; ``indptr.size == ncols + 1``.
1137
1137
  col_indices : list or np.ndarray
1138
1138
  Column indices.
1139
1139
  values : list or np.ndarray or scalar, default 1.0
@@ -2707,7 +2707,7 @@ class Matrix(BaseType):
2707
2707
  result = Scalar(dtype, is_cscalar=is_cscalar, name=name)
2708
2708
  if opts:
2709
2709
  # Ignore opts for now
2710
- descriptor_lookup(**opts)
2710
+ desc = descriptor_lookup(**opts) # noqa: F841 (keep desc in scope for context)
2711
2711
  if is_cscalar:
2712
2712
  dtype_name = "UDT" if dtype._is_udt else dtype.name
2713
2713
  if (
@@ -398,7 +398,7 @@ class OpBase:
398
398
  def _initialize(cls, include_in_ops=True):
399
399
  """
400
400
  include_in_ops determines whether the operators are included in the
401
- `gb.ops` namespace in addition to the defined module.
401
+ ``gb.ops`` namespace in addition to the defined module.
402
402
  """
403
403
  if cls._initialized: # pragma: no cover (safety)
404
404
  return