Skip to content

Commit cef7af5

Browse files
authored
Merge pull request #461 from Blosc/array-api
Array api
2 parents 06760e1 + 30422a1 commit cef7af5

21 files changed

+1105
-391
lines changed

README_DEVELOPERS.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,13 @@ We are using Sphinx for documentation. You can build the documentation by execu
7070
[You may need to install the `pandoc` package first: https://pandoc.org/installing.html]
7171

7272
You will find the documentation in the `../html` directory.
73+
74+
## Array API tests compatibility
75+
76+
You can test array API compatibility with the `array-api-tests` module.
77+
Use the `tests/array-api-xfails.txt` to skip the tests that are not supported
78+
and run pytest from the `array-api-tests` source dir like this:
79+
80+
``` bash
81+
ARRAY_API_TESTS_MODULE=blosc2 pytest array_api_tests --xfails-file ${BLOSC2_DIR}/tests/array-api-xfails.txt -xs
82+
```

pyproject.toml

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,13 @@ dependencies = [
3737
"ndindex",
3838
"msgpack",
3939
"platformdirs",
40-
"numexpr; platform_machine != 'wasm32'",
40+
"numexpr>=2.12.1; platform_machine != 'wasm32'",
4141
"py-cpuinfo; platform_machine != 'wasm32'",
4242
"requests",
4343
]
4444
version = "3.7.3.dev0"
45+
[project.entry-points."array_api"]
46+
blosc2 = "blosc2"
4547

4648

4749
[project.optional-dependencies]
@@ -99,8 +101,6 @@ exclude = ["bench*", ".github*"]
99101

100102
[tool.ruff]
101103
line-length = 109
102-
# Raise complexity from the default 10 to 13
103-
complexity = 13
104104
extend-exclude = ["bench"]
105105

106106
[tool.ruff.lint]
@@ -116,7 +116,7 @@ extend-select = [
116116
"SIM",
117117
"TC",
118118
"UP",
119-
]
119+
"C901"] # enable complexity rule
120120
ignore = [
121121
"B028",
122122
"PT011",
@@ -130,3 +130,7 @@ ignore = [
130130

131131
[tool.ruff.lint.extend-per-file-ignores]
132132
"tests/**" = ["F841"]
133+
134+
[tool.ruff.lint.mccabe]
135+
# Raise complexity from the default 10 to 13
136+
max-complexity = 13

src/blosc2/__init__.py

Lines changed: 129 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
import platform
1414
from enum import Enum
1515

16+
import numpy as np
17+
1618
# Do the platform check once at module level
1719
IS_WASM = platform.machine() == "wasm32"
1820
# IS_WASM = True # for testing (comment this line out for production)
@@ -23,9 +25,10 @@
2325
if not IS_WASM:
2426
import numexpr
2527

26-
from .version import __version__
28+
from .version import __array_api_version__, __version__
2729

2830
__version__ = __version__
31+
__array_api_version__ = __array_api_version__
2932
"""
3033
Python-Blosc2 version.
3134
"""
@@ -164,6 +167,94 @@ class Tuner(Enum):
164167
"""
165168
The C-Blosc2 version's string."""
166169

170+
171+
# For array-api compatibility
172+
iinfo = np.iinfo
173+
finfo = np.finfo
174+
175+
# dtypes for array-api
176+
str_ = np.str_
177+
bytes_ = np.bytes_
178+
object_ = np.object_
179+
180+
from numpy import (
181+
bool_,
182+
complex64,
183+
complex128,
184+
e,
185+
euler_gamma,
186+
float16,
187+
float32,
188+
float64,
189+
inf,
190+
int8,
191+
int16,
192+
int32,
193+
int64,
194+
nan,
195+
newaxis,
196+
pi,
197+
uint8,
198+
uint16,
199+
uint32,
200+
uint64,
201+
)
202+
203+
DEFAULT_COMPLEX = complex128
204+
"""
205+
Default complex floating dtype."""
206+
207+
DEFAULT_FLOAT = float64
208+
"""
209+
Default real floating dtype."""
210+
211+
DEFAULT_INT = int64
212+
"""
213+
Default integer dtype."""
214+
215+
DEFAULT_INDEX = int64
216+
"""
217+
Default indexing dtype."""
218+
219+
220+
class Info:
221+
def __init__(self, **kwargs):
222+
for key, value in kwargs.items():
223+
setattr(self, key, value)
224+
225+
226+
def __array_namespace_info__() -> Info:
227+
"""
228+
Return information about the array namespace following the Array API specification.
229+
"""
230+
231+
def _raise(exc):
232+
raise exc
233+
234+
return Info(
235+
capabilities=lambda: {
236+
"boolean indexing": True,
237+
"data-dependent shapes": False,
238+
"max dimensions": MAX_DIM,
239+
},
240+
default_device=lambda: "cpu",
241+
default_dtypes=lambda device=None: {
242+
"real floating": DEFAULT_FLOAT,
243+
"complex floating": DEFAULT_COMPLEX,
244+
"integral": DEFAULT_INT,
245+
"indexing": DEFAULT_INDEX,
246+
}
247+
if (device == "cpu" or device is None)
248+
else _raise(ValueError("Only cpu devices allowed")),
249+
dtypes=lambda device=None, kind=None: np.__array_namespace_info__().dtypes(kind=kind, device=device)
250+
if (device == "cpu" or device is None)
251+
else _raise(ValueError("Only cpu devices allowed")),
252+
devices=lambda: ["cpu"],
253+
name="blosc2",
254+
version=__version__,
255+
)
256+
257+
167258
# Public API for container module
168259
from .core import (
169260
clib_info,
@@ -237,9 +328,11 @@ class Tuner(Enum):
237328
are_partitions_aligned,
238329
are_partitions_behaved,
239330
arange,
331+
broadcast_to,
240332
linspace,
241333
eye,
242334
asarray,
335+
astype,
243336
indices,
244337
sort,
245338
reshape,
@@ -248,14 +341,19 @@ class Tuner(Enum):
248341
concatenate,
249342
expand_dims,
250343
empty,
344+
empty_like,
251345
frombuffer,
252346
fromiter,
253347
get_slice_nchunks,
348+
meshgrid,
254349
nans,
255350
uninit,
256351
zeros,
352+
zeros_like,
257353
ones,
354+
ones_like,
258355
full,
356+
full_like,
259357
save,
260358
matmul,
261359
permute_dims,
@@ -278,6 +376,7 @@ class Tuner(Enum):
278376
get_expr_operands,
279377
validate_expr,
280378
evaluate,
379+
slices_eval,
281380
)
282381
from .proxy import Proxy, ProxySource, ProxyNDSource, ProxyNDField, SimpleProxy, jit
283382

@@ -333,9 +432,13 @@ class Tuner(Enum):
333432
contains,
334433
cos,
335434
cosh,
435+
equal,
336436
exp,
337437
expm1,
338438
imag,
439+
isfinite,
440+
isinf,
441+
isnan,
339442
lazywhere,
340443
log,
341444
log1p,
@@ -356,14 +459,25 @@ class Tuner(Enum):
356459
where,
357460
)
358461

359-
__all__ = [
462+
__all__ = [ # noqa : RUF022
360463
# Constants
361464
"EXTENDED_HEADER_LENGTH",
362465
"MAX_BUFFERSIZE",
363466
"MAX_TYPESIZE",
364467
"MIN_HEADER_LENGTH",
365468
"VERSION_DATE",
366469
"VERSION_STRING",
470+
# Default dtypes
471+
"DEFAULT_COMPLEX",
472+
"DEFAULT_FLOAT",
473+
"DEFAULT_INDEX",
474+
"DEFAULT_INT",
475+
# Mathematical constants
476+
"e",
477+
"pi",
478+
"inf",
479+
"nan",
480+
"newaxis",
367481
# Classes
368482
"C2Array",
369483
"CParams",
@@ -407,7 +521,8 @@ class Tuner(Enum):
407521
"are_partitions_aligned",
408522
"are_partitions_behaved",
409523
"asarray",
410-
"clib_info",
524+
"astypeclib_info",
525+
"broadcast_to",
411526
"compress",
412527
"compress2",
413528
"compressor_list",
@@ -421,6 +536,9 @@ class Tuner(Enum):
421536
"decompress2",
422537
"detect_number_of_cores",
423538
"dparams_dflts",
539+
"empty",
540+
"empty_like",
541+
"equal",
424542
"estore_from_cframe",
425543
"expand_dims",
426544
"expm1",
@@ -430,6 +548,7 @@ class Tuner(Enum):
430548
"frombuffer",
431549
"fromiter",
432550
"full",
551+
"full_like",
433552
"get_blocksize",
434553
"get_cbuffer_sizes",
435554
"get_clib",
@@ -438,6 +557,9 @@ class Tuner(Enum):
438557
"get_expr_operands",
439558
"get_slice_nchunks",
440559
"indices",
560+
"isfinite",
561+
"isinf",
562+
"isnan",
441563
"jit",
442564
"lazyexpr",
443565
"lazyudf",
@@ -452,10 +574,12 @@ class Tuner(Enum):
452574
"matrix_transpose",
453575
"max",
454576
"mean",
577+
"meshgrid",
455578
"min",
456579
"nans",
457580
"ndarray_from_cframe",
458581
"ones",
582+
"ones_like",
459583
"open",
460584
"pack",
461585
"pack_array",
@@ -494,4 +618,6 @@ class Tuner(Enum):
494618
"validate_expr",
495619
"var",
496620
"where",
621+
"zeros",
622+
"zeros_like",
497623
]

src/blosc2/blosc2_ext.pyx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2612,8 +2612,8 @@ cdef class NDArray:
26122612
mask_[i] = mask[i]
26132613
_check_rc(b2nd_squeeze_index(self.array, mask_), "Error while squeezing array")
26142614

2615-
if self.array.shape[0] == 1 and self.ndim == 1:
2616-
self.array.ndim = 0
2615+
#if self.array.shape[0] == 1 and self.ndim == 1:
2616+
# self.array.ndim = 0
26172617

26182618
def as_ffi_ptr(self):
26192619
return PyCapsule_New(self.array, <char *> "b2nd_array_t*", NULL)

src/blosc2/core.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1467,7 +1467,7 @@ def compute_chunks_blocks( # noqa: C901
14671467

14681468
# Return an arbitrary value for chunks and blocks when shape has any 0 dim
14691469
if 0 in shape:
1470-
return (1,) * len(shape), (1,) * len(shape)
1470+
return shape, shape
14711471

14721472
if blocks:
14731473
if not isinstance(blocks, tuple | list):

0 commit comments

Comments
 (0)