blosc2 3.3.1__tar.gz → 3.3.3__tar.gz

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 (256) hide show
  1. {blosc2-3.3.1 → blosc2-3.3.3}/.pre-commit-config.yaml +1 -1
  2. {blosc2-3.3.1 → blosc2-3.3.3}/ANNOUNCE.rst +5 -11
  3. {blosc2-3.3.1 → blosc2-3.3.3}/CMakeLists.txt +1 -1
  4. {blosc2-3.3.1 → blosc2-3.3.3}/PKG-INFO +3 -2
  5. {blosc2-3.3.1 → blosc2-3.3.3}/RELEASE_NOTES.md +43 -0
  6. {blosc2-3.3.1 → blosc2-3.3.3}/doc/python-blosc2.rst +1 -1
  7. {blosc2-3.3.1 → blosc2-3.3.3}/pyproject.toml +4 -3
  8. {blosc2-3.3.1 → blosc2-3.3.3}/src/blosc2/__init__.py +1 -0
  9. {blosc2-3.3.1 → blosc2-3.3.3}/src/blosc2/blosc2_ext.pyx +2 -1
  10. {blosc2-3.3.1 → blosc2-3.3.3}/src/blosc2/core.py +42 -29
  11. {blosc2-3.3.1 → blosc2-3.3.3}/src/blosc2/lazyexpr.py +117 -10
  12. {blosc2-3.3.1 → blosc2-3.3.3}/src/blosc2/ndarray.py +48 -27
  13. blosc2-3.3.3/src/blosc2/version.py +1 -0
  14. {blosc2-3.3.1 → blosc2-3.3.3}/tests/ndarray/test_evaluate.py +1 -1
  15. {blosc2-3.3.1 → blosc2-3.3.3}/tests/ndarray/test_jit.py +1 -1
  16. {blosc2-3.3.1 → blosc2-3.3.3}/tests/ndarray/test_lazyexpr.py +73 -0
  17. {blosc2-3.3.1 → blosc2-3.3.3}/tests/ndarray/test_ndarray.py +8 -0
  18. {blosc2-3.3.1 → blosc2-3.3.3}/tests/ndarray/test_reductions.py +10 -0
  19. {blosc2-3.3.1 → blosc2-3.3.3}/tests/ndarray/test_transpose.py +27 -32
  20. {blosc2-3.3.1 → blosc2-3.3.3}/tests/ndarray/test_zeros.py +37 -0
  21. blosc2-3.3.1/src/blosc2/version.py +0 -1
  22. {blosc2-3.3.1 → blosc2-3.3.3}/.gitignore +0 -0
  23. {blosc2-3.3.1 → blosc2-3.3.3}/.guix/modules/python-blosc2-package.scm +0 -0
  24. {blosc2-3.3.1 → blosc2-3.3.3}/.guix-channel +0 -0
  25. {blosc2-3.3.1 → blosc2-3.3.3}/CONTRIBUTING.rst +0 -0
  26. {blosc2-3.3.1 → blosc2-3.3.3}/LICENSE.txt +0 -0
  27. {blosc2-3.3.1 → blosc2-3.3.3}/README.rst +0 -0
  28. {blosc2-3.3.1 → blosc2-3.3.3}/README_DEVELOPERS.md +0 -0
  29. {blosc2-3.3.1 → blosc2-3.3.3}/RELEASING.rst +0 -0
  30. {blosc2-3.3.1 → blosc2-3.3.3}/code_of_conduct.md +0 -0
  31. {blosc2-3.3.1 → blosc2-3.3.3}/doc/_static/blosc-favicon_32x32.png +0 -0
  32. {blosc2-3.3.1 → blosc2-3.3.3}/doc/_static/blosc-favicon_64x64.png +0 -0
  33. {blosc2-3.3.1 → blosc2-3.3.3}/doc/_static/blosc-logo_128.png +0 -0
  34. {blosc2-3.3.1 → blosc2-3.3.3}/doc/_static/blosc-logo_256.png +0 -0
  35. {blosc2-3.3.1 → blosc2-3.3.3}/doc/_static/css/custom.css +0 -0
  36. {blosc2-3.3.1 → blosc2-3.3.3}/doc/conf.py +0 -0
  37. {blosc2-3.3.1 → blosc2-3.3.3}/doc/development/code-of-conduct.rst +0 -0
  38. {blosc2-3.3.1 → blosc2-3.3.3}/doc/development/contributing.rst +0 -0
  39. {blosc2-3.3.1 → blosc2-3.3.3}/doc/development/index.rst +0 -0
  40. {blosc2-3.3.1 → blosc2-3.3.3}/doc/getting_started/index.rst +0 -0
  41. {blosc2-3.3.1 → blosc2-3.3.3}/doc/getting_started/installation.rst +0 -0
  42. {blosc2-3.3.1 → blosc2-3.3.3}/doc/getting_started/overview.rst +0 -0
  43. {blosc2-3.3.1 → blosc2-3.3.3}/doc/getting_started/tutorials/01.ndarray-basics.ipynb +0 -0
  44. {blosc2-3.3.1 → blosc2-3.3.3}/doc/getting_started/tutorials/02.lazyarray-expressions.ipynb +0 -0
  45. {blosc2-3.3.1 → blosc2-3.3.3}/doc/getting_started/tutorials/03.lazyarray-udf.ipynb +0 -0
  46. {blosc2-3.3.1 → blosc2-3.3.3}/doc/getting_started/tutorials/04.reductions.ipynb +0 -0
  47. {blosc2-3.3.1 → blosc2-3.3.3}/doc/getting_started/tutorials/05.persistent-reductions.ipynb +0 -0
  48. {blosc2-3.3.1 → blosc2-3.3.3}/doc/getting_started/tutorials/06.remote_proxy.ipynb +0 -0
  49. {blosc2-3.3.1 → blosc2-3.3.3}/doc/getting_started/tutorials/07.schunk-basics.ipynb +0 -0
  50. {blosc2-3.3.1 → blosc2-3.3.3}/doc/getting_started/tutorials/08.schunk-slicing_and_beyond.ipynb +0 -0
  51. {blosc2-3.3.1 → blosc2-3.3.3}/doc/getting_started/tutorials/10.ucodecs-ufilters.ipynb +0 -0
  52. {blosc2-3.3.1 → blosc2-3.3.3}/doc/getting_started/tutorials/11.prefilters.ipynb +0 -0
  53. {blosc2-3.3.1 → blosc2-3.3.3}/doc/getting_started/tutorials/12.postfilters.ipynb +0 -0
  54. {blosc2-3.3.1 → blosc2-3.3.3}/doc/getting_started/tutorials/images/blosc2-pipeline.png +0 -0
  55. {blosc2-3.3.1 → blosc2-3.3.3}/doc/getting_started/tutorials/images/blosc2-pipeline.svg +0 -0
  56. {blosc2-3.3.1 → blosc2-3.3.3}/doc/getting_started/tutorials/images/lazyexpr-broadcast.png +0 -0
  57. {blosc2-3.3.1 → blosc2-3.3.3}/doc/getting_started/tutorials/images/reductions/3D-cube-plane.png +0 -0
  58. {blosc2-3.3.1 → blosc2-3.3.3}/doc/getting_started/tutorials/images/reductions/3D-cube.png +0 -0
  59. {blosc2-3.3.1 → blosc2-3.3.3}/doc/getting_started/tutorials/images/reductions/memory-access-2D-x.png +0 -0
  60. {blosc2-3.3.1 → blosc2-3.3.3}/doc/getting_started/tutorials/images/reductions/memory-access-2D-y.png +0 -0
  61. {blosc2-3.3.1 → blosc2-3.3.3}/doc/getting_started/tutorials/images/remote_proxy.png +0 -0
  62. {blosc2-3.3.1 → blosc2-3.3.3}/doc/getting_started/tutorials/images/ucodecs-filters/backward.png +0 -0
  63. {blosc2-3.3.1 → blosc2-3.3.3}/doc/getting_started/tutorials/images/ucodecs-filters/backward.svg +0 -0
  64. {blosc2-3.3.1 → blosc2-3.3.3}/doc/getting_started/tutorials/images/ucodecs-filters/decoder.png +0 -0
  65. {blosc2-3.3.1 → blosc2-3.3.3}/doc/getting_started/tutorials/images/ucodecs-filters/decoder.svg +0 -0
  66. {blosc2-3.3.1 → blosc2-3.3.3}/doc/getting_started/tutorials/images/ucodecs-filters/decoder2.png +0 -0
  67. {blosc2-3.3.1 → blosc2-3.3.3}/doc/getting_started/tutorials/images/ucodecs-filters/decoder2.svg +0 -0
  68. {blosc2-3.3.1 → blosc2-3.3.3}/doc/getting_started/tutorials/images/ucodecs-filters/encoder.png +0 -0
  69. {blosc2-3.3.1 → blosc2-3.3.3}/doc/getting_started/tutorials/images/ucodecs-filters/encoder.svg +0 -0
  70. {blosc2-3.3.1 → blosc2-3.3.3}/doc/getting_started/tutorials/images/ucodecs-filters/encoder2.png +0 -0
  71. {blosc2-3.3.1 → blosc2-3.3.3}/doc/getting_started/tutorials/images/ucodecs-filters/encoder2.svg +0 -0
  72. {blosc2-3.3.1 → blosc2-3.3.3}/doc/getting_started/tutorials/images/ucodecs-filters/forward.png +0 -0
  73. {blosc2-3.3.1 → blosc2-3.3.3}/doc/getting_started/tutorials/images/ucodecs-filters/forward.svg +0 -0
  74. {blosc2-3.3.1 → blosc2-3.3.3}/doc/getting_started/tutorials.rst +0 -0
  75. {blosc2-3.3.1 → blosc2-3.3.3}/doc/index.rst +0 -0
  76. {blosc2-3.3.1 → blosc2-3.3.3}/doc/reference/array_operations.rst +0 -0
  77. {blosc2-3.3.1 → blosc2-3.3.3}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.__getitem__.rst +0 -0
  78. {blosc2-3.3.1 → blosc2-3.3.3}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.__init__.rst +0 -0
  79. {blosc2-3.3.1 → blosc2-3.3.3}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.__len__.rst +0 -0
  80. {blosc2-3.3.1 → blosc2-3.3.3}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.__setitem__.rst +0 -0
  81. {blosc2-3.3.1 → blosc2-3.3.3}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.append_data.rst +0 -0
  82. {blosc2-3.3.1 → blosc2-3.3.3}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.decompress_chunk.rst +0 -0
  83. {blosc2-3.3.1 → blosc2-3.3.3}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.delete_chunk.rst +0 -0
  84. {blosc2-3.3.1 → blosc2-3.3.3}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.fill_special.rst +0 -0
  85. {blosc2-3.3.1 → blosc2-3.3.3}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.filler.rst +0 -0
  86. {blosc2-3.3.1 → blosc2-3.3.3}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.get_chunk.rst +0 -0
  87. {blosc2-3.3.1 → blosc2-3.3.3}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.get_slice.rst +0 -0
  88. {blosc2-3.3.1 → blosc2-3.3.3}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.insert_chunk.rst +0 -0
  89. {blosc2-3.3.1 → blosc2-3.3.3}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.insert_data.rst +0 -0
  90. {blosc2-3.3.1 → blosc2-3.3.3}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.iterchunks.rst +0 -0
  91. {blosc2-3.3.1 → blosc2-3.3.3}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.iterchunks_info.rst +0 -0
  92. {blosc2-3.3.1 → blosc2-3.3.3}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.postfilter.rst +0 -0
  93. {blosc2-3.3.1 → blosc2-3.3.3}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.prefilter.rst +0 -0
  94. {blosc2-3.3.1 → blosc2-3.3.3}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.remove_postfilter.rst +0 -0
  95. {blosc2-3.3.1 → blosc2-3.3.3}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.remove_prefilter.rst +0 -0
  96. {blosc2-3.3.1 → blosc2-3.3.3}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.to_cframe.rst +0 -0
  97. {blosc2-3.3.1 → blosc2-3.3.3}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.update_chunk.rst +0 -0
  98. {blosc2-3.3.1 → blosc2-3.3.3}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.update_data.rst +0 -0
  99. {blosc2-3.3.1 → blosc2-3.3.3}/doc/reference/c2array.rst +0 -0
  100. {blosc2-3.3.1 → blosc2-3.3.3}/doc/reference/classes.rst +0 -0
  101. {blosc2-3.3.1 → blosc2-3.3.3}/doc/reference/decorators.rst +0 -0
  102. {blosc2-3.3.1 → blosc2-3.3.3}/doc/reference/index.rst +0 -0
  103. {blosc2-3.3.1 → blosc2-3.3.3}/doc/reference/lazy_functions.rst +0 -0
  104. {blosc2-3.3.1 → blosc2-3.3.3}/doc/reference/lazyarray.rst +0 -0
  105. {blosc2-3.3.1 → blosc2-3.3.3}/doc/reference/linear_algebra.rst +0 -0
  106. {blosc2-3.3.1 → blosc2-3.3.3}/doc/reference/low_level.rst +0 -0
  107. {blosc2-3.3.1 → blosc2-3.3.3}/doc/reference/ndarray.rst +0 -0
  108. {blosc2-3.3.1 → blosc2-3.3.3}/doc/reference/ndfield.rst +0 -0
  109. {blosc2-3.3.1 → blosc2-3.3.3}/doc/reference/proxy.rst +0 -0
  110. {blosc2-3.3.1 → blosc2-3.3.3}/doc/reference/proxyndsource.rst +0 -0
  111. {blosc2-3.3.1 → blosc2-3.3.3}/doc/reference/proxysource.rst +0 -0
  112. {blosc2-3.3.1 → blosc2-3.3.3}/doc/reference/reduction_functions.rst +0 -0
  113. {blosc2-3.3.1 → blosc2-3.3.3}/doc/reference/save_load.rst +0 -0
  114. {blosc2-3.3.1 → blosc2-3.3.3}/doc/reference/schunk.rst +0 -0
  115. {blosc2-3.3.1 → blosc2-3.3.3}/doc/reference/storage.rst +0 -0
  116. {blosc2-3.3.1 → blosc2-3.3.3}/doc/reference/utilities.rst +0 -0
  117. {blosc2-3.3.1 → blosc2-3.3.3}/doc/release_notes/index.md +0 -0
  118. {blosc2-3.3.1 → blosc2-3.3.3}/examples/btune.py +0 -0
  119. {blosc2-3.3.1 → blosc2-3.3.3}/examples/c2array-get-slice.py +0 -0
  120. {blosc2-3.3.1 → blosc2-3.3.3}/examples/compress2_decompress2.py +0 -0
  121. {blosc2-3.3.1 → blosc2-3.3.3}/examples/compress_decompress.py +0 -0
  122. {blosc2-3.3.1 → blosc2-3.3.3}/examples/filler.py +0 -0
  123. {blosc2-3.3.1 → blosc2-3.3.3}/examples/gil.py +0 -0
  124. {blosc2-3.3.1 → blosc2-3.3.3}/examples/mmap-rw.py +0 -0
  125. {blosc2-3.3.1 → blosc2-3.3.3}/examples/ndarray/arange-constructor.py +0 -0
  126. {blosc2-3.3.1 → blosc2-3.3.3}/examples/ndarray/asarray_.py +0 -0
  127. {blosc2-3.3.1 → blosc2-3.3.3}/examples/ndarray/broadcast_expr.py +0 -0
  128. {blosc2-3.3.1 → blosc2-3.3.3}/examples/ndarray/buffer.py +0 -0
  129. {blosc2-3.3.1 → blosc2-3.3.3}/examples/ndarray/bytedelta_filter.py +0 -0
  130. {blosc2-3.3.1 → blosc2-3.3.3}/examples/ndarray/c2array_expr.py +0 -0
  131. {blosc2-3.3.1 → blosc2-3.3.3}/examples/ndarray/compute_expr.py +0 -0
  132. {blosc2-3.3.1 → blosc2-3.3.3}/examples/ndarray/compute_fields.py +0 -0
  133. {blosc2-3.3.1 → blosc2-3.3.3}/examples/ndarray/compute_udf_numba.py +0 -0
  134. {blosc2-3.3.1 → blosc2-3.3.3}/examples/ndarray/compute_where.py +0 -0
  135. {blosc2-3.3.1 → blosc2-3.3.3}/examples/ndarray/copy_.py +0 -0
  136. {blosc2-3.3.1 → blosc2-3.3.3}/examples/ndarray/empty_.py +0 -0
  137. {blosc2-3.3.1 → blosc2-3.3.3}/examples/ndarray/eye-constructor.py +0 -0
  138. {blosc2-3.3.1 → blosc2-3.3.3}/examples/ndarray/filter_sort_fields.py +0 -0
  139. {blosc2-3.3.1 → blosc2-3.3.3}/examples/ndarray/formats.py +0 -0
  140. {blosc2-3.3.1 → blosc2-3.3.3}/examples/ndarray/fromiter-constructor.py +0 -0
  141. {blosc2-3.3.1 → blosc2-3.3.3}/examples/ndarray/general_expressions.py +0 -0
  142. {blosc2-3.3.1 → blosc2-3.3.3}/examples/ndarray/getitem.py +0 -0
  143. {blosc2-3.3.1 → blosc2-3.3.3}/examples/ndarray/iterchunks_info.py +0 -0
  144. {blosc2-3.3.1 → blosc2-3.3.3}/examples/ndarray/jit-expr.py +0 -0
  145. {blosc2-3.3.1 → blosc2-3.3.3}/examples/ndarray/jit-numpy-funcs.py +0 -0
  146. {blosc2-3.3.1 → blosc2-3.3.3}/examples/ndarray/jit-reduc.py +0 -0
  147. {blosc2-3.3.1 → blosc2-3.3.3}/examples/ndarray/linspace-constructor.py +0 -0
  148. {blosc2-3.3.1 → blosc2-3.3.3}/examples/ndarray/lists-vs-bools-idx.py +0 -0
  149. {blosc2-3.3.1 → blosc2-3.3.3}/examples/ndarray/meta.py +0 -0
  150. {blosc2-3.3.1 → blosc2-3.3.3}/examples/ndarray/ndarray_copy.py +0 -0
  151. {blosc2-3.3.1 → blosc2-3.3.3}/examples/ndarray/ndmean.py +0 -0
  152. {blosc2-3.3.1 → blosc2-3.3.3}/examples/ndarray/persistency.py +0 -0
  153. {blosc2-3.3.1 → blosc2-3.3.3}/examples/ndarray/proxy-carray.py +0 -0
  154. {blosc2-3.3.1 → blosc2-3.3.3}/examples/ndarray/proxy-ndarray.py +0 -0
  155. {blosc2-3.3.1 → blosc2-3.3.3}/examples/ndarray/reduce_and_enlarge.py +0 -0
  156. {blosc2-3.3.1 → blosc2-3.3.3}/examples/ndarray/reduce_expr.py +0 -0
  157. {blosc2-3.3.1 → blosc2-3.3.3}/examples/ndarray/reduce_expr_save.py +0 -0
  158. {blosc2-3.3.1 → blosc2-3.3.3}/examples/ndarray/reduce_string_expr.py +0 -0
  159. {blosc2-3.3.1 → blosc2-3.3.3}/examples/ndarray/resize_.py +0 -0
  160. {blosc2-3.3.1 → blosc2-3.3.3}/examples/ndarray/work_with_numpy.py +0 -0
  161. {blosc2-3.3.1 → blosc2-3.3.3}/examples/ndarray/zfp_codec.py +0 -0
  162. {blosc2-3.3.1 → blosc2-3.3.3}/examples/pack_array.py +0 -0
  163. {blosc2-3.3.1 → blosc2-3.3.3}/examples/pack_tensor.py +0 -0
  164. {blosc2-3.3.1 → blosc2-3.3.3}/examples/postfilter1.py +0 -0
  165. {blosc2-3.3.1 → blosc2-3.3.3}/examples/postfilter2.py +0 -0
  166. {blosc2-3.3.1 → blosc2-3.3.3}/examples/postfilter3.py +0 -0
  167. {blosc2-3.3.1 → blosc2-3.3.3}/examples/prefilter.py +0 -0
  168. {blosc2-3.3.1 → blosc2-3.3.3}/examples/save_tensor.py +0 -0
  169. {blosc2-3.3.1 → blosc2-3.3.3}/examples/schunk.py +0 -0
  170. {blosc2-3.3.1 → blosc2-3.3.3}/examples/schunk_roundtrip.py +0 -0
  171. {blosc2-3.3.1 → blosc2-3.3.3}/examples/ucodecs.py +0 -0
  172. {blosc2-3.3.1 → blosc2-3.3.3}/examples/ufilters.py +0 -0
  173. {blosc2-3.3.1 → blosc2-3.3.3}/examples/vlmeta.py +0 -0
  174. {blosc2-3.3.1 → blosc2-3.3.3}/generate_version.py +0 -0
  175. {blosc2-3.3.1 → blosc2-3.3.3}/guix.scm +0 -0
  176. {blosc2-3.3.1 → blosc2-3.3.3}/images/Complete-Write-Read-B2ND.png +0 -0
  177. {blosc2-3.3.1 → blosc2-3.3.3}/images/M1-i386-vs-arm64-pack.png +0 -0
  178. {blosc2-3.3.1 → blosc2-3.3.3}/images/M1-i386-vs-arm64-unpack.png +0 -0
  179. {blosc2-3.3.1 → blosc2-3.3.3}/images/Read-Partial-Slices-B2ND.png +0 -0
  180. {blosc2-3.3.1 → blosc2-3.3.3}/images/b2nd-2level-parts.png +0 -0
  181. {blosc2-3.3.1 → blosc2-3.3.3}/images/eval-expr-full-mem-M2.png +0 -0
  182. {blosc2-3.3.1 → blosc2-3.3.3}/images/eval-expr-scarce-mem-M2.png +0 -0
  183. {blosc2-3.3.1 → blosc2-3.3.3}/images/lazyarray-dask-large.png +0 -0
  184. {blosc2-3.3.1 → blosc2-3.3.3}/images/lazyarray-dask-small.png +0 -0
  185. {blosc2-3.3.1 → blosc2-3.3.3}/images/lazyarray-expr-large.png +0 -0
  186. {blosc2-3.3.1 → blosc2-3.3.3}/images/lazyarray-expr.png +0 -0
  187. {blosc2-3.3.1 → blosc2-3.3.3}/images/linspace-compress.png +0 -0
  188. {blosc2-3.3.1 → blosc2-3.3.3}/images/linspace-decompress.png +0 -0
  189. {blosc2-3.3.1 → blosc2-3.3.3}/images/pack-array-cratios.png +0 -0
  190. {blosc2-3.3.1 → blosc2-3.3.3}/images/reduc-float64-amd.png +0 -0
  191. {blosc2-3.3.1 → blosc2-3.3.3}/images/reduc-float64-log-amd.png +0 -0
  192. {blosc2-3.3.1 → blosc2-3.3.3}/pytest.ini +0 -0
  193. {blosc2-3.3.1 → blosc2-3.3.3}/src/blosc2/c2array.py +0 -0
  194. {blosc2-3.3.1 → blosc2-3.3.3}/src/blosc2/helpers.py +0 -0
  195. {blosc2-3.3.1 → blosc2-3.3.3}/src/blosc2/info.py +0 -0
  196. {blosc2-3.3.1 → blosc2-3.3.3}/src/blosc2/proxy.py +0 -0
  197. {blosc2-3.3.1 → blosc2-3.3.3}/src/blosc2/schunk.py +0 -0
  198. {blosc2-3.3.1 → blosc2-3.3.3}/src/blosc2/storage.py +0 -0
  199. {blosc2-3.3.1 → blosc2-3.3.3}/tests/conftest.py +0 -0
  200. {blosc2-3.3.1 → blosc2-3.3.3}/tests/ndarray/test_auto_parts.py +0 -0
  201. {blosc2-3.3.1 → blosc2-3.3.3}/tests/ndarray/test_buffer.py +0 -0
  202. {blosc2-3.3.1 → blosc2-3.3.3}/tests/ndarray/test_c2array_expr.py +0 -0
  203. {blosc2-3.3.1 → blosc2-3.3.3}/tests/ndarray/test_c2array_reductions.py +0 -0
  204. {blosc2-3.3.1 → blosc2-3.3.3}/tests/ndarray/test_c2array_udf.py +0 -0
  205. {blosc2-3.3.1 → blosc2-3.3.3}/tests/ndarray/test_copy.py +0 -0
  206. {blosc2-3.3.1 → blosc2-3.3.3}/tests/ndarray/test_empty.py +0 -0
  207. {blosc2-3.3.1 → blosc2-3.3.3}/tests/ndarray/test_full.py +0 -0
  208. {blosc2-3.3.1 → blosc2-3.3.3}/tests/ndarray/test_get_slice_nchunks.py +0 -0
  209. {blosc2-3.3.1 → blosc2-3.3.3}/tests/ndarray/test_getitem.py +0 -0
  210. {blosc2-3.3.1 → blosc2-3.3.3}/tests/ndarray/test_iterchunks_info.py +0 -0
  211. {blosc2-3.3.1 → blosc2-3.3.3}/tests/ndarray/test_lazyexpr_fields.py +0 -0
  212. {blosc2-3.3.1 → blosc2-3.3.3}/tests/ndarray/test_lazyudf.py +0 -0
  213. {blosc2-3.3.1 → blosc2-3.3.3}/tests/ndarray/test_lossy.py +0 -0
  214. {blosc2-3.3.1 → blosc2-3.3.3}/tests/ndarray/test_matmul.py +0 -0
  215. {blosc2-3.3.1 → blosc2-3.3.3}/tests/ndarray/test_metalayers.py +0 -0
  216. {blosc2-3.3.1 → blosc2-3.3.3}/tests/ndarray/test_mode.py +0 -0
  217. {blosc2-3.3.1 → blosc2-3.3.3}/tests/ndarray/test_nans.py +0 -0
  218. {blosc2-3.3.1 → blosc2-3.3.3}/tests/ndarray/test_numpy.py +0 -0
  219. {blosc2-3.3.1 → blosc2-3.3.3}/tests/ndarray/test_persistency.py +0 -0
  220. {blosc2-3.3.1 → blosc2-3.3.3}/tests/ndarray/test_proxy.py +0 -0
  221. {blosc2-3.3.1 → blosc2-3.3.3}/tests/ndarray/test_proxy_c2array.py +0 -0
  222. {blosc2-3.3.1 → blosc2-3.3.3}/tests/ndarray/test_proxy_expr.py +0 -0
  223. {blosc2-3.3.1 → blosc2-3.3.3}/tests/ndarray/test_resize.py +0 -0
  224. {blosc2-3.3.1 → blosc2-3.3.3}/tests/ndarray/test_setitem.py +0 -0
  225. {blosc2-3.3.1 → blosc2-3.3.3}/tests/ndarray/test_slice.py +0 -0
  226. {blosc2-3.3.1 → blosc2-3.3.3}/tests/ndarray/test_squeeze.py +0 -0
  227. {blosc2-3.3.1 → blosc2-3.3.3}/tests/ndarray/test_struct_dtype.py +0 -0
  228. {blosc2-3.3.1 → blosc2-3.3.3}/tests/test_bytes_array.py +0 -0
  229. {blosc2-3.3.1 → blosc2-3.3.3}/tests/test_comp_info.py +0 -0
  230. {blosc2-3.3.1 → blosc2-3.3.3}/tests/test_compress2.py +0 -0
  231. {blosc2-3.3.1 → blosc2-3.3.3}/tests/test_compression_parameters.py +0 -0
  232. {blosc2-3.3.1 → blosc2-3.3.3}/tests/test_compressors.py +0 -0
  233. {blosc2-3.3.1 → blosc2-3.3.3}/tests/test_decompress.py +0 -0
  234. {blosc2-3.3.1 → blosc2-3.3.3}/tests/test_iterchunks.py +0 -0
  235. {blosc2-3.3.1 → blosc2-3.3.3}/tests/test_mmap.py +0 -0
  236. {blosc2-3.3.1 → blosc2-3.3.3}/tests/test_open.py +0 -0
  237. {blosc2-3.3.1 → blosc2-3.3.3}/tests/test_open_c2array.py +0 -0
  238. {blosc2-3.3.1 → blosc2-3.3.3}/tests/test_pathlib.py +0 -0
  239. {blosc2-3.3.1 → blosc2-3.3.3}/tests/test_postfilters.py +0 -0
  240. {blosc2-3.3.1 → blosc2-3.3.3}/tests/test_prefilters.py +0 -0
  241. {blosc2-3.3.1 → blosc2-3.3.3}/tests/test_proxy_schunk.py +0 -0
  242. {blosc2-3.3.1 → blosc2-3.3.3}/tests/test_python_blosc.py +0 -0
  243. {blosc2-3.3.1 → blosc2-3.3.3}/tests/test_schunk.py +0 -0
  244. {blosc2-3.3.1 → blosc2-3.3.3}/tests/test_schunk_constructor.py +0 -0
  245. {blosc2-3.3.1 → blosc2-3.3.3}/tests/test_schunk_delete.py +0 -0
  246. {blosc2-3.3.1 → blosc2-3.3.3}/tests/test_schunk_get_slice.py +0 -0
  247. {blosc2-3.3.1 → blosc2-3.3.3}/tests/test_schunk_get_slice_nchunks.py +0 -0
  248. {blosc2-3.3.1 → blosc2-3.3.3}/tests/test_schunk_insert.py +0 -0
  249. {blosc2-3.3.1 → blosc2-3.3.3}/tests/test_schunk_set_slice.py +0 -0
  250. {blosc2-3.3.1 → blosc2-3.3.3}/tests/test_schunk_update.py +0 -0
  251. {blosc2-3.3.1 → blosc2-3.3.3}/tests/test_storage.py +0 -0
  252. {blosc2-3.3.1 → blosc2-3.3.3}/tests/test_tensor.py +0 -0
  253. {blosc2-3.3.1 → blosc2-3.3.3}/tests/test_ucodecs.py +0 -0
  254. {blosc2-3.3.1 → blosc2-3.3.3}/tests/test_ufilters.py +0 -0
  255. {blosc2-3.3.1 → blosc2-3.3.3}/tests/test_vlmeta.py +0 -0
  256. {blosc2-3.3.1 → blosc2-3.3.3}/update_version.py +0 -0
@@ -16,7 +16,7 @@ repos:
16
16
  - id: trailing-whitespace
17
17
 
18
18
  - repo: https://github.com/astral-sh/ruff-pre-commit
19
- rev: v0.11.4
19
+ rev: v0.11.8
20
20
  hooks:
21
21
  - id: ruff
22
22
  args: ["--fix", "--show-fixes"]
@@ -1,16 +1,10 @@
1
- Announcing Python-Blosc2 3.3.1
1
+ Announcing Python-Blosc2 3.3.3
2
2
  ==============================
3
3
 
4
- In our effort to better adapt to better adapt to the array API
5
- (https://data-apis.org/array-api/latest/), we have introduced
6
- permute_dims() and matrix_transpose() functions, and the .T property.
7
- This replaces to previous transpose() function, which is now deprecated.
8
- See PR #384. Thanks to Ricardo Sales Piquer (@ricardosp4).
9
-
10
- We have also reduced the memory footprint of constructors like ``arange()``,
11
- ``linspace()`` and ``fromiter()`` by a large factor. As an example, a 5 TB
12
- array of 8-byte floats now uses less than 200 MB of memory instead of
13
- 170 GB previously.
4
+ This is a bugfix release, with some minor optimizations. We improved the
5
+ correct chaining of *string* lazy expressions (there is still room for
6
+ improvement). Also, a new version of C-Blosc2 (v2.7.2.dev) that fixes
7
+ mmap issues on Windows is used; thanks to @JanSellner for the fix.
14
8
 
15
9
  You can think of Python-Blosc2 3.x as an extension of NumPy/numexpr that:
16
10
 
@@ -50,7 +50,7 @@ else()
50
50
  include(FetchContent)
51
51
  FetchContent_Declare(blosc2
52
52
  GIT_REPOSITORY https://github.com/Blosc/c-blosc2
53
- GIT_TAG 5fcd6fbf9ffcf613fabdb1eb3a90eeb12f7c04fe # v2.17.1
53
+ GIT_TAG 3f9c085c0c0f357b140fb5a50d1f8df06de3383a # v2.17.1 + mmap fix
54
54
  )
55
55
  FetchContent_MakeAvailable(blosc2)
56
56
  include_directories("${blosc2_SOURCE_DIR}/include")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: blosc2
3
- Version: 3.3.1
3
+ Version: 3.3.3
4
4
  Summary: A fast & compressed ndarray library with a flexible compute engine.
5
5
  Author-Email: Blosc Development Team <blosc@blosc.org>
6
6
  Maintainer-Email: Blosc Development Team <blosc@blosc.org>
@@ -15,12 +15,13 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
15
15
  Classifier: Operating System :: Microsoft :: Windows
16
16
  Classifier: Operating System :: Unix
17
17
  Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.10
18
19
  Classifier: Programming Language :: Python :: 3.11
19
20
  Classifier: Programming Language :: Python :: 3.12
20
21
  Classifier: Programming Language :: Python :: 3.13
21
22
  Project-URL: homepage, https://github.com/Blosc/python-blosc2
22
23
  Project-URL: documentation, https://www.blosc.org/python-blosc2/python-blosc2.html
23
- Requires-Python: >=3.11
24
+ Requires-Python: >=3.10
24
25
  Requires-Dist: numpy>=1.26
25
26
  Requires-Dist: ndindex
26
27
  Requires-Dist: msgpack
@@ -1,5 +1,48 @@
1
1
  # Release notes
2
2
 
3
+ ## Changes from 3.3.2 to 3.3.3
4
+
5
+ * Expand possibilities for chaining string-based lazy expressions to include
6
+ main operand types (LazyExpr and NDArray). Still have to incorporate other
7
+ data types (which do not have shape attribute, e.g. int, float etc.).
8
+ See #406.
9
+
10
+ * Fix indexing for lazy expressions, and allow use of None in getitem.
11
+ See PR #402.
12
+
13
+ * Fix incorrect appending of dim to computed reductions. See PR #404.
14
+
15
+ * Fix `blosc2.linspace()` for incompatible num/shape. See PR #408.
16
+
17
+ * Add support for NumPy dtypes that are n-dimensional (e.g.
18
+ `np.dtype(("<i4,>f4", (10,))),`).
19
+
20
+ * New MAX_DIM constant for the maximum number of dimensions supported.
21
+ This is useful for checking if a given array is too large to be handled.
22
+
23
+ * More refinements on guessing cache sizes for Linux.
24
+
25
+ * Update to C-Blosc2 2.17.2.dev. Now, we are forcing the flush of modified
26
+ pages only in write mode for mmap files. This fixes mmap issues on Windows.
27
+ Thanks to @JanSellner for the implementation.
28
+
29
+ ## Changes from 3.3.1 to 3.3.2
30
+
31
+ * Fixed a bug in the determination of chunk shape for the `NDArray` constructor.
32
+ This was causing problems when creating `NDArray` instances with a CPU that
33
+ was reporting a L3 cache size close (or exceeding) 2 GB. See PR #392.
34
+
35
+ * Fixed a bug preventing the correct chaining of *string* lazy expressions for
36
+ logical operators (`&`, `|`, `^`...). See PR #391.
37
+
38
+ * More performance optimization for `blosc2.permute_dims`. Thanks to
39
+ Ricardo Sales Piquer (@ricardosp4) for the implementation.
40
+
41
+ * Now, storage defaults (`blosc2.storage_dflts`) are honored, even if no
42
+ `storage=` param is used in constructors.
43
+
44
+ * We are distributing Python 3.10 wheels now.
45
+
3
46
  ## Changes from 3.3.0 to 3.3.1
4
47
 
5
48
  * In our effort to better adapt to better adapt to the array API
@@ -6,7 +6,7 @@
6
6
 
7
7
  <p style="text-align: center; color: black; background-color: rgba(230, 169, 9, 0.65);">
8
8
  <a href="https://github.com/Blosc/python-blosc2/blob/main/RELEASE_NOTES.md"
9
- style="font-size: 1.5em;">Version 3.3.0 released on 2025-04-08!</a>
9
+ style="font-size: 1.5em;">Version 3.3.2 released on 2025-05-01!</a>
10
10
  <span style="display: inline-block; width: 20px;"></span>
11
11
  <span style="font-family: monospace;">pip install blosc2 -U</span>
12
12
  </p>
@@ -24,11 +24,12 @@ classifiers = [
24
24
  "Operating System :: Microsoft :: Windows",
25
25
  "Operating System :: Unix",
26
26
  "Programming Language :: Python :: 3",
27
+ "Programming Language :: Python :: 3.10",
27
28
  "Programming Language :: Python :: 3.11",
28
29
  "Programming Language :: Python :: 3.12",
29
30
  "Programming Language :: Python :: 3.13",
30
31
  ]
31
- requires-python = ">=3.11"
32
+ requires-python = ">=3.10"
32
33
  # Follow guidelines from https://scientific-python.org/specs/spec-0000/
33
34
  dependencies = [
34
35
  "numpy>=1.26",
@@ -40,7 +41,7 @@ dependencies = [
40
41
  "py-cpuinfo; platform_machine != 'wasm32'",
41
42
  "requests",
42
43
  ]
43
- version = "3.3.1"
44
+ version = "3.3.3"
44
45
 
45
46
 
46
47
  [project.optional-dependencies]
@@ -110,7 +111,7 @@ extend-select = [
110
111
  "RET",
111
112
  "RUF",
112
113
  "SIM",
113
- "TCH",
114
+ "TC",
114
115
  "UP",
115
116
  ]
116
117
  ignore = [
@@ -109,6 +109,7 @@ from .blosc2_ext import (
109
109
  GLOBAL_REGISTERED_CODECS_STOP,
110
110
  MAX_BLOCKSIZE,
111
111
  MAX_BUFFERSIZE,
112
+ MAX_DIM,
112
113
  MAX_OVERHEAD,
113
114
  MAX_TYPESIZE,
114
115
  MIN_HEADER_LENGTH,
@@ -542,6 +542,7 @@ MAX_TYPESIZE = BLOSC2_MAXTYPESIZE
542
542
  MAX_BUFFERSIZE = BLOSC2_MAX_BUFFERSIZE
543
543
  MAX_BLOCKSIZE = BLOSC2_MAXBLOCKSIZE
544
544
  MAX_OVERHEAD = BLOSC2_MAX_OVERHEAD
545
+ MAX_DIM = B2ND_MAX_DIM
545
546
  VERSION_STRING = (<char*>BLOSC2_VERSION_STRING).decode("utf-8")
546
547
  VERSION_DATE = (<char*>BLOSC2_VERSION_DATE).decode("utf-8")
547
548
  MIN_HEADER_LENGTH = BLOSC_MIN_HEADER_LENGTH
@@ -2391,7 +2392,7 @@ cdef class NDArray:
2391
2392
  str_dtype = bytes_dtype.decode("utf-8")
2392
2393
  try:
2393
2394
  dtype = np.dtype(str_dtype)
2394
- except TypeError:
2395
+ except (ValueError, TypeError):
2395
2396
  dtype = np.dtype(ast.literal_eval(str_dtype))
2396
2397
  self._dtype = dtype
2397
2398
  return dtype
@@ -1164,50 +1164,58 @@ def apple_silicon_cache_size(cache_level: int) -> int:
1164
1164
  return size.value
1165
1165
 
1166
1166
 
1167
- def get_l3_cache_info():
1167
+ def get_cache_info(cache_level: int) -> tuple:
1168
1168
  result = subprocess.run(["lscpu", "--json"], capture_output=True, text=True)
1169
1169
  lscpu_info = json.loads(result.stdout)
1170
+ if cache_level == 0:
1171
+ cache_level = "1d"
1170
1172
  for entry in lscpu_info["lscpu"]:
1171
- if entry["field"] == "L3 cache:":
1173
+ if entry["field"] == f"L{cache_level} cache:":
1172
1174
  size_str, instances_str = entry["data"].split(" (")
1173
- size = int(size_str.split()[0]) * 1024 * 1024 # Convert MiB to bytes
1175
+ size, units = size_str.split()
1176
+ size = int(size)
1177
+ if units == "KiB":
1178
+ size *= 2**10
1179
+ elif units == "MiB":
1180
+ size *= 2**20
1181
+ elif units == "GiB":
1182
+ size *= 2**30
1183
+ else:
1184
+ raise ValueError("Unrecognized unit when guessing cache units")
1174
1185
  instances = int(instances_str.split()[0])
1175
1186
  return size, instances
1176
1187
 
1177
- raise ValueError("L3 cache not found in lscpu output")
1188
+ raise ValueError(f"L{cache_level} cache not found in lscpu output")
1178
1189
 
1179
1190
 
1180
1191
  def linux_cache_size(cache_level: int, default_size: int) -> int:
1181
1192
  """Get the data cache_level size in bytes for Linux."""
1182
1193
  cache_size = default_size
1183
- if cache_level == 3:
1184
- # In modern multicore CPUs, the L3 cache is normally shared among all core complexes (CCX),
1185
- # but sysfs only reports the cache size for each complex, so better use lscpu, if available.
1186
- try:
1187
- l3_cache_size, l3_cache_instances = get_l3_cache_info()
1188
- # What comes next is a heuristic to guess the most appropriate L3 cache size.
1189
- # Essentially, this is the result of different experiments, mainly on AMD CPUs
1190
- # (in particular, Ryzen 9800X3D with 8 cores, and EPYC 9454P with 48 cores).
1191
- # For Intel, YMMV, but my guess is that they are not using the same CCX approach.
1192
- l3_cache_size *= l3_cache_instances
1193
- if l3_cache_instances > 1:
1194
- # This is yet another heuristic for large CPUs with core sets (CCX) having
1195
- # their own L3. No idea why, but it seems to work well.
1196
- l3_cache_size *= l3_cache_instances // 2
1197
- return l3_cache_size
1198
- except (FileNotFoundError, ValueError):
1199
- # If lscpu is not available or the cache size cannot be read, try with sysfs
1200
- pass
1201
1194
  try:
1195
+ # Try to read the cache size from sysfs
1202
1196
  with open(f"/sys/devices/system/cpu/cpu0/cache/index{cache_level}/size") as f:
1203
1197
  size = f.read()
1204
1198
  if size.endswith("K\n"):
1205
- cache_size = int(size[:-2]) * 1024
1199
+ cache_size = int(size[:-2]) * 2**10
1206
1200
  elif size.endswith("M\n"):
1207
- cache_size = int(size[:-2]) * 1024 * 1024
1201
+ cache_size = int(size[:-2]) * 2**20
1202
+ elif size.endswith("G\n"):
1203
+ cache_size = int(size[:-2]) * 2**30
1208
1204
  except FileNotFoundError:
1209
- # If the cache size cannot be read, return the default size
1210
- pass
1205
+ # Try with lscpu, if available.
1206
+ try:
1207
+ cache_size, cache_instances = get_cache_info(cache_level)
1208
+ # cache_instances typically refers to the number of sockets, CCXs or cores,
1209
+ # depending on the CPU and cache level.
1210
+ # In general, dividing the cache size by the number of instances would bring
1211
+ # best performance for private caches (L1 and L2). For shared caches (L3),
1212
+ # this should be the case as well, but more experimentation is needed.
1213
+ cache_size //= cache_instances
1214
+ return cache_size
1215
+ except (FileNotFoundError, ValueError):
1216
+ # If lscpu is not available or the cache size cannot be read from sysfs,
1217
+ # return the default size.
1218
+ pass
1211
1219
  return cache_size
1212
1220
 
1213
1221
 
@@ -1322,9 +1330,9 @@ def get_chunksize(blocksize, l3_minimum=4 * 2**20, l3_maximum=2**26):
1322
1330
  if isinstance(l2_cache_size, int) and l3_cache_size > l2_cache_size:
1323
1331
  chunksize = l3_cache_size
1324
1332
  # When computing expressions, it is convenient to keep chunks for all operands
1325
- # in L3 cache, so let's divide by 4 (3 operands + result is a typical situation
1333
+ # in L3 cache, so let's divide by 5 (4 operands + result is a typical situation
1326
1334
  # for moderately complex expressions)
1327
- chunksize //= 4
1335
+ chunksize //= 5
1328
1336
 
1329
1337
  # Chunksize should be at least the size of L2
1330
1338
  l2_cache_size = cpu_info.get("l2_cache_size", "Not found")
@@ -1529,7 +1537,7 @@ def compute_chunks_blocks( # noqa: C901
1529
1537
  # min_blocksize = blosc2.cpu_info["l1_data_cache_size"] * 4
1530
1538
  elif platform.system() == "Darwin" and "arm" in platform.machine():
1531
1539
  # For Apple Silicon, experiments say we can use 4x the L1 size
1532
- min_blocksize = blosc2.cpu_info["l1_data_cache_size"] * 2
1540
+ min_blocksize = blosc2.cpu_info["l1_data_cache_size"] * 4
1533
1541
  elif "l1_data_cache_size" in blosc2.cpu_info and isinstance(
1534
1542
  blosc2.cpu_info["l1_data_cache_size"], int
1535
1543
  ):
@@ -1562,6 +1570,11 @@ def compute_chunks_blocks( # noqa: C901
1562
1570
  if chunks is None:
1563
1571
  blocksize = math.prod(blocks) * itemsize
1564
1572
  chunksize = get_chunksize(blocksize)
1573
+ # Make chunksize to be a multiple of the blocksize. This allows for:
1574
+ # 1. Avoid unnecessary padding in chunks
1575
+ # 2. Avoid exceeding the maximum buffer size (see #392)
1576
+ if chunksize % blocksize != 0:
1577
+ chunksize = chunksize // blocksize * blocksize
1565
1578
  chunks = compute_partition(chunksize // itemsize, shape, blocks)
1566
1579
 
1567
1580
  return tuple(chunks), tuple(blocks)
@@ -37,7 +37,7 @@ import numpy as np
37
37
  import blosc2
38
38
  from blosc2 import compute_chunks_blocks
39
39
  from blosc2.info import InfoReporter
40
- from blosc2.ndarray import _check_allowed_dtypes, get_chunks_idx, is_inside_new_expr
40
+ from blosc2.ndarray import _check_allowed_dtypes, get_chunks_idx, is_inside_new_expr, process_key
41
41
 
42
42
  if not blosc2.IS_WASM:
43
43
  import numexpr
@@ -630,6 +630,107 @@ def get_expr_operands(expression: str) -> set:
630
630
  return set(visitor.operands)
631
631
 
632
632
 
633
+ def conserve_functions( # noqa: C901
634
+ expression: str,
635
+ operands_old: dict[str, blosc2.NDArray | blosc2.LazyExpr],
636
+ operands_new: dict[str, blosc2.NDArray | blosc2.LazyExpr],
637
+ ) -> tuple(str, dict[str, blosc2.NDArray]):
638
+ """
639
+ Given an expression in string form, return its operands.
640
+
641
+ Parameters
642
+ ----------
643
+ expression : str
644
+ The expression in string form.
645
+
646
+ operands_old: dict[str : blosc2.ndarray | blosc2.LazyExpr]
647
+ Dict of operands from expression prior to eval.
648
+
649
+ operands_new: dict[str : blosc2.ndarray | blosc2.LazyExpr]
650
+ Dict of operands from expression after eval.
651
+ Returns
652
+ -------
653
+ newexpression
654
+ A modified string expression with the functions/constructors conserved and
655
+ true operands rebased and written in o- notation.
656
+ newoperands
657
+ Dict of the set of rebased operands.
658
+ """
659
+
660
+ operand_to_key = {id(v): k for k, v in operands_new.items()}
661
+ for k, v in operands_old.items(): # extend operands_to_key with old operands
662
+ if isinstance(
663
+ v, blosc2.LazyExpr
664
+ ): # unroll operands in LazyExpr (only necessary when have reduced a lazyexpr)
665
+ d = v.operands
666
+ else:
667
+ d = {k: v}
668
+ for newk, newv in d.items():
669
+ try:
670
+ operand_to_key[id(newv)]
671
+ except KeyError:
672
+ newk = (
673
+ f"o{len(operands_new)}" if newk in operands_new else newk
674
+ ) # possible that names coincide
675
+ operand_to_key[id(newv)] = newk
676
+ operands_new[newk] = newv
677
+
678
+ class OperandVisitor(ast.NodeVisitor):
679
+ def __init__(self):
680
+ self.operandmap = {}
681
+ self.operands = {}
682
+ self.opcounter = 0
683
+ self.function_names = set()
684
+
685
+ def update_func(self, localop):
686
+ k = operand_to_key[id(localop)]
687
+ if k not in self.operandmap:
688
+ newkey = f"o{self.opcounter}"
689
+ self.operands[newkey] = operands_new[k]
690
+ self.operandmap[k] = newkey
691
+ self.opcounter += 1
692
+ return newkey
693
+ else:
694
+ return self.operandmap[k]
695
+
696
+ def visit_Name(self, node):
697
+ if node.id == "np": # Skip NumPy namespace (e.g. np.int8, which will be treated separately)
698
+ return
699
+ if node.id in self.function_names: # Skip function names
700
+ return
701
+ elif node.id not in dtype_symbols:
702
+ localop = operands_old[node.id]
703
+ if isinstance(localop, blosc2.LazyExpr):
704
+ newexpr = localop.expression
705
+ for (
706
+ opname,
707
+ v,
708
+ ) in localop.operands.items(): # expression operands already in terms of basic operands
709
+ newopname = self.update_func(v)
710
+ newexpr = re.sub(
711
+ rf"(?<=\s){opname}|(?<=\(){opname}", newopname, newexpr
712
+ ) # replace with newopname
713
+ node.id = newexpr
714
+ else:
715
+ node.id = self.update_func(localop)
716
+ else:
717
+ pass
718
+ self.generic_visit(node)
719
+
720
+ def visit_Call(self, node):
721
+ if isinstance(
722
+ node.func, ast.Name
723
+ ): # visits Call first, then Name, so don't increment operandcounter yet
724
+ self.function_names.add(node.func.id)
725
+ self.generic_visit(node)
726
+
727
+ tree = ast.parse(expression)
728
+ visitor = OperandVisitor()
729
+ visitor.visit(tree)
730
+ newexpression, newoperands = ast.unparse(tree), visitor.operands
731
+ return newexpression, newoperands
732
+
733
+
633
734
  class TransformNumpyCalls(ast.NodeTransformer):
634
735
  def __init__(self):
635
736
  self.replacements = {}
@@ -1481,7 +1582,8 @@ def reduce_slices( # noqa: C901
1481
1582
  iter_disk = all_ndarray and any_persisted
1482
1583
  # Experiments say that iter_disk is faster than the regular path for reductions
1483
1584
  # even when all operands are in memory, so no need to check any_persisted
1484
- # New benchs are saying the contrary (> 10% slower), so this needs more investigation
1585
+ # New benchmarks are saying the contrary (> 10% slower), so this needs more
1586
+ # investigation
1485
1587
  # iter_disk = all_ndarray
1486
1588
  else:
1487
1589
  # WebAssembly does not support threading, so we cannot use the iter_disk option
@@ -1919,7 +2021,6 @@ class LazyExpr(LazyArray):
1919
2021
  if hasattr(value2, "_where_args"):
1920
2022
  value2 = value2.compute()
1921
2023
 
1922
- self._dtype = infer_dtype(op, value1, value2)
1923
2024
  if not isinstance(value1, LazyExpr) and not isinstance(value2, LazyExpr):
1924
2025
  # We converted some of the operands to NDArray (where() handling above)
1925
2026
  new_operands = {"o0": value1, "o1": value2}
@@ -2434,22 +2535,24 @@ class LazyExpr(LazyArray):
2434
2535
  _globals = get_expr_globals(self.expression)
2435
2536
  lazy_expr = eval(self.expression, _globals, self.operands)
2436
2537
  if not isinstance(lazy_expr, blosc2.LazyExpr):
2538
+ key, _ = process_key(item, self.shape)
2437
2539
  # An immediate evaluation happened (e.g. all operands are numpy arrays)
2438
2540
  if hasattr(self, "_where_args"):
2439
2541
  # We need to apply the where() operation
2440
2542
  if len(self._where_args) == 1:
2441
2543
  # We have a single argument
2442
2544
  where_x = self._where_args["_where_x"]
2443
- return where_x[:][lazy_expr]
2545
+ return (where_x[:][lazy_expr])[key]
2444
2546
  if len(self._where_args) == 2:
2445
2547
  # We have two arguments
2446
2548
  where_x = self._where_args["_where_x"]
2447
2549
  where_y = self._where_args["_where_y"]
2448
- return np.where(lazy_expr, where_x, where_y)
2550
+ return np.where(lazy_expr, where_x, where_y)[key]
2449
2551
  if hasattr(self, "_output"):
2450
2552
  # This is not exactly optimized, but it works for now
2451
- self._output[:] = lazy_expr
2452
- return lazy_expr
2553
+ self._output[:] = lazy_expr[key]
2554
+ return self._output
2555
+ return lazy_expr[key]
2453
2556
 
2454
2557
  return chunked_eval(lazy_expr.expression, lazy_expr.operands, item, **kwargs)
2455
2558
 
@@ -2676,10 +2779,14 @@ class LazyExpr(LazyArray):
2676
2779
  _dtype = new_expr.dtype
2677
2780
  _shape = new_expr.shape
2678
2781
  if isinstance(new_expr, blosc2.LazyExpr):
2679
- # Restore the original expression and operands
2680
- new_expr.expression = _expression
2782
+ # DO NOT restore the original expression and operands
2783
+ # Instead rebase operands and restore only constructors
2784
+ expression_, operands_ = conserve_functions(
2785
+ _expression, _operands, new_expr.operands | local_vars
2786
+ )
2787
+ new_expr.expression = f"({expression_})" # force parenthesis
2681
2788
  new_expr.expression_tosave = expression
2682
- new_expr.operands = _operands
2789
+ new_expr.operands = operands_
2683
2790
  new_expr.operands_tosave = operands
2684
2791
  else:
2685
2792
  # An immediate evaluation happened (e.g. all operands are numpy arrays)
@@ -2914,6 +2914,8 @@ def _check_shape(shape):
2914
2914
  shape = (shape,)
2915
2915
  elif not isinstance(shape, tuple | list):
2916
2916
  raise TypeError("shape should be a tuple or a list!")
2917
+ if len(shape) > blosc2.MAX_DIM:
2918
+ raise ValueError(f"shape length {len(shape)} is too large (>{blosc2.MAX_DIM})!")
2917
2919
  return shape
2918
2920
 
2919
2921
 
@@ -3266,7 +3268,9 @@ def arange(
3266
3268
 
3267
3269
 
3268
3270
  # Define a numpy linspace-like function
3269
- def linspace(start, stop, num=50, endpoint=True, dtype=np.float64, shape=None, c_order=True, **kwargs: Any):
3271
+ def linspace(
3272
+ start, stop, num=None, endpoint=True, dtype=np.float64, shape=None, c_order=True, **kwargs: Any
3273
+ ):
3270
3274
  """Return evenly spaced numbers over a specified interval.
3271
3275
 
3272
3276
  This is similar to `numpy.linspace` but it returns a `NDArray`
@@ -3308,8 +3312,17 @@ def linspace(start, stop, num=50, endpoint=True, dtype=np.float64, shape=None, c
3308
3312
  stop_ = start_ + lout / num * (stop - start)
3309
3313
  output[:] = np.linspace(start_, stop_, lout, endpoint=False, dtype=output.dtype)
3310
3314
 
3311
- if not shape:
3312
- shape = (num,)
3315
+ if shape is None or num is None:
3316
+ if shape is None and num is None:
3317
+ raise ValueError("Either `shape` or `num` must be specified.")
3318
+ if shape is None: # num is not None
3319
+ shape = (num,)
3320
+ else: # num is none
3321
+ num = math.prod(shape)
3322
+
3323
+ # check compatibility of shape and num
3324
+ if math.prod(shape) != num:
3325
+ raise ValueError("The specified shape is not consistent with the specified num value")
3313
3326
  dtype = _check_dtype(dtype)
3314
3327
 
3315
3328
  if is_inside_new_expr():
@@ -3624,17 +3637,22 @@ def asarray(array: np.ndarray | blosc2.C2Array, **kwargs: Any) -> NDArray:
3624
3637
 
3625
3638
 
3626
3639
  def _check_ndarray_kwargs(**kwargs): # noqa: C901
3627
- if "storage" in kwargs:
3640
+ storage = kwargs.get("storage")
3641
+ if storage is not None:
3628
3642
  for key in kwargs:
3629
3643
  if key in list(blosc2.Storage.__annotations__):
3630
3644
  raise AttributeError(
3631
3645
  "Cannot pass both `storage` and other kwargs already included in Storage"
3632
3646
  )
3633
- storage = kwargs.get("storage")
3634
3647
  if isinstance(storage, blosc2.Storage):
3635
3648
  kwargs = {**kwargs, **asdict(storage)}
3636
3649
  else:
3637
3650
  kwargs = {**kwargs, **storage}
3651
+ else:
3652
+ # Add the default storage values as long as they are not already passed
3653
+ storage_dflts = asdict(blosc2.Storage(urlpath=kwargs.get("urlpath"))) # urlpath can affect defaults
3654
+ not_passed = {k: v for k, v in storage_dflts.items() if k not in kwargs}
3655
+ kwargs = {**kwargs, **not_passed}
3638
3656
 
3639
3657
  supported_keys = [
3640
3658
  "chunks",
@@ -3871,11 +3889,11 @@ def matmul(x1: NDArray, x2: NDArray, **kwargs: Any) -> NDArray:
3871
3889
  r = x2.chunks[-1]
3872
3890
 
3873
3891
  for row in range(0, n, p):
3874
- row_end = (row + p) if (row + p) < n else n
3892
+ row_end = builtins.min(row + p, n)
3875
3893
  for col in range(0, m, q):
3876
- col_end = (col + q) if (col + q) < m else m
3894
+ col_end = builtins.min(col + q, m)
3877
3895
  for aux in range(0, k, r):
3878
- aux_end = (aux + r) if (aux + r) < k else k
3896
+ aux_end = builtins.min(aux + r, k)
3879
3897
  bx1 = x1[row:row_end, aux:aux_end]
3880
3898
  bx2 = x2[aux:aux_end, col:col_end]
3881
3899
  result[row:row_end, col:col_end] += np.matmul(bx1, bx2)
@@ -3946,6 +3964,7 @@ def permute_dims(arr: NDArray, axes: tuple[int] | list[int] | None = None, **kwa
3946
3964
  [[13, 14, 15, 16],
3947
3965
  [17, 18, 19, 20],
3948
3966
  [21, 22, 23, 24]]])
3967
+
3949
3968
  >>> at = blosc2.permute_dims(a, axes=(1, 0, 2))
3950
3969
  >>> at[:]
3951
3970
  array([[[ 1, 2, 3, 4],
@@ -3955,37 +3974,39 @@ def permute_dims(arr: NDArray, axes: tuple[int] | list[int] | None = None, **kwa
3955
3974
  [[ 9, 10, 11, 12],
3956
3975
  [21, 22, 23, 24]]])
3957
3976
  """
3958
-
3959
3977
  if np.isscalar(arr) or arr.ndim < 2:
3960
3978
  return arr
3961
3979
 
3980
+ ndim = arr.ndim
3981
+
3962
3982
  if axes is None:
3963
- axes = range(arr.ndim)[::-1]
3983
+ axes = tuple(range(ndim))[::-1]
3964
3984
  else:
3965
- axes_transformed = tuple(axis if axis >= 0 else arr.ndim + axis for axis in axes)
3966
- if sorted(axes_transformed) != list(range(arr.ndim)):
3967
- raise ValueError(f"axes {axes} is not a valid permutation of {arr.ndim} dimensions")
3968
- axes = axes_transformed
3985
+ axes = tuple(axis if axis >= 0 else ndim + axis for axis in axes)
3986
+ if sorted(axes) != list(range(ndim)):
3987
+ raise ValueError(f"axes {axes} is not a valid permutation of {ndim} dimensions")
3969
3988
 
3970
3989
  new_shape = tuple(arr.shape[axis] for axis in axes)
3971
- if "chunks" not in kwargs:
3990
+ if "chunks" not in kwargs or kwargs["chunks"] is None:
3972
3991
  kwargs["chunks"] = tuple(arr.chunks[axis] for axis in axes)
3973
3992
 
3974
3993
  result = blosc2.empty(shape=new_shape, dtype=arr.dtype, **kwargs)
3975
3994
 
3976
- chunk_slices = [
3977
- [slice(start, builtins.min(dim, start + chunk)) for start in range(0, dim, chunk)]
3978
- for dim, chunk in zip(arr.shape, arr.chunks, strict=False)
3979
- ]
3995
+ chunks = arr.chunks
3996
+ shape = arr.shape
3997
+
3998
+ for info in arr.iterchunks_info():
3999
+ coords = info.coords
4000
+ start_stop = [
4001
+ (coord * chunk, builtins.min(chunk * (coord + 1), dim))
4002
+ for coord, chunk, dim in zip(coords, chunks, shape, strict=False)
4003
+ ]
3980
4004
 
3981
- block_counts = [len(s) for s in chunk_slices]
3982
- grid = np.indices(block_counts).reshape(len(block_counts), -1).T
4005
+ src_slice = tuple(slice(start, stop) for start, stop in start_stop)
4006
+ dst_slice = tuple(slice(start_stop[ax][0], start_stop[ax][1]) for ax in axes)
3983
4007
 
3984
- for idx in grid:
3985
- block_slices = tuple(chunk_slices[axis][i] for axis, i in enumerate(idx))
3986
- block = arr[block_slices]
3987
- target_slices = tuple(block_slices[axis] for axis in axes)
3988
- result[target_slices] = np.transpose(block, axes=axes).copy()
4008
+ transposed = np.transpose(arr[src_slice], axes=axes)
4009
+ result[dst_slice] = np.ascontiguousarray(transposed)
3989
4010
 
3990
4011
  return result
3991
4012
 
@@ -4019,7 +4040,7 @@ def transpose(x, **kwargs: Any) -> NDArray:
4019
4040
  stacklevel=2,
4020
4041
  )
4021
4042
 
4022
- # If arguments are dimension < 2 they are returned
4043
+ # If arguments are dimension < 2, they are returned
4023
4044
  if np.isscalar(x) or x.ndim < 2:
4024
4045
  return x
4025
4046
 
@@ -0,0 +1 @@
1
+ __version__ = "3.3.3"
@@ -27,7 +27,7 @@ def sample_data(request):
27
27
  # The jit decorator can work with any numpy or NDArray params in functions
28
28
  a = blosc2.linspace(0, 1, shape[0] * shape[1], dtype=dtype, shape=shape)
29
29
  b = np.linspace(1, 2, shape[0] * shape[1], dtype=dtype).reshape(shape)
30
- c = blosc2.linspace(-10, 10, cshape[0], dtype=dtype, shape=cshape)
30
+ c = blosc2.linspace(-10, 10, np.prod(cshape), dtype=dtype, shape=cshape)
31
31
  return a, b, c, shape
32
32
 
33
33
 
@@ -26,7 +26,7 @@ def sample_data(request):
26
26
  # The jit decorator can work with any numpy or NDArray params in functions
27
27
  a = blosc2.linspace(0, 1, shape[0] * shape[1], dtype=dtype, shape=shape)
28
28
  b = np.linspace(1, 2, shape[0] * shape[1], dtype=dtype).reshape(shape)
29
- c = blosc2.linspace(-10, 10, cshape[0], dtype=dtype, shape=cshape)
29
+ c = blosc2.linspace(-10, 10, np.prod(cshape), dtype=dtype, shape=cshape)
30
30
  return a, b, c, shape
31
31
 
32
32