blosc2 3.3.2__tar.gz → 3.3.4__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 (257) hide show
  1. {blosc2-3.3.2 → blosc2-3.3.4}/.pre-commit-config.yaml +1 -1
  2. {blosc2-3.3.2 → blosc2-3.3.4}/ANNOUNCE.rst +6 -6
  3. {blosc2-3.3.2 → blosc2-3.3.4}/CMakeLists.txt +1 -1
  4. {blosc2-3.3.2 → blosc2-3.3.4}/PKG-INFO +1 -1
  5. {blosc2-3.3.2 → blosc2-3.3.4}/RELEASE_NOTES.md +46 -0
  6. {blosc2-3.3.2 → blosc2-3.3.4}/doc/python-blosc2.rst +1 -1
  7. {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/classes.rst +1 -0
  8. {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/proxysource.rst +2 -2
  9. blosc2-3.3.4/doc/reference/simpleproxy.rst +30 -0
  10. {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/storage.rst +2 -0
  11. {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/jit-numpy-funcs.py +1 -1
  12. {blosc2-3.3.2 → blosc2-3.3.4}/pyproject.toml +2 -2
  13. {blosc2-3.3.2 → blosc2-3.3.4}/src/blosc2/__init__.py +1 -0
  14. {blosc2-3.3.2 → blosc2-3.3.4}/src/blosc2/blosc2_ext.pyx +29 -3
  15. {blosc2-3.3.2 → blosc2-3.3.4}/src/blosc2/core.py +34 -26
  16. {blosc2-3.3.2 → blosc2-3.3.4}/src/blosc2/lazyexpr.py +200 -16
  17. {blosc2-3.3.2 → blosc2-3.3.4}/src/blosc2/ndarray.py +21 -7
  18. {blosc2-3.3.2 → blosc2-3.3.4}/src/blosc2/proxy.py +20 -5
  19. {blosc2-3.3.2 → blosc2-3.3.4}/src/blosc2/schunk.py +12 -3
  20. blosc2-3.3.4/src/blosc2/version.py +1 -0
  21. {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_evaluate.py +1 -1
  22. {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_jit.py +1 -1
  23. {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_lazyexpr.py +69 -42
  24. {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_lazyexpr_fields.py +41 -0
  25. {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_ndarray.py +8 -0
  26. {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_reductions.py +70 -0
  27. {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_zeros.py +37 -0
  28. blosc2-3.3.2/src/blosc2/version.py +0 -1
  29. {blosc2-3.3.2 → blosc2-3.3.4}/.gitignore +0 -0
  30. {blosc2-3.3.2 → blosc2-3.3.4}/.guix/modules/python-blosc2-package.scm +0 -0
  31. {blosc2-3.3.2 → blosc2-3.3.4}/.guix-channel +0 -0
  32. {blosc2-3.3.2 → blosc2-3.3.4}/CONTRIBUTING.rst +0 -0
  33. {blosc2-3.3.2 → blosc2-3.3.4}/LICENSE.txt +0 -0
  34. {blosc2-3.3.2 → blosc2-3.3.4}/README.rst +0 -0
  35. {blosc2-3.3.2 → blosc2-3.3.4}/README_DEVELOPERS.md +0 -0
  36. {blosc2-3.3.2 → blosc2-3.3.4}/RELEASING.rst +0 -0
  37. {blosc2-3.3.2 → blosc2-3.3.4}/code_of_conduct.md +0 -0
  38. {blosc2-3.3.2 → blosc2-3.3.4}/doc/_static/blosc-favicon_32x32.png +0 -0
  39. {blosc2-3.3.2 → blosc2-3.3.4}/doc/_static/blosc-favicon_64x64.png +0 -0
  40. {blosc2-3.3.2 → blosc2-3.3.4}/doc/_static/blosc-logo_128.png +0 -0
  41. {blosc2-3.3.2 → blosc2-3.3.4}/doc/_static/blosc-logo_256.png +0 -0
  42. {blosc2-3.3.2 → blosc2-3.3.4}/doc/_static/css/custom.css +0 -0
  43. {blosc2-3.3.2 → blosc2-3.3.4}/doc/conf.py +0 -0
  44. {blosc2-3.3.2 → blosc2-3.3.4}/doc/development/code-of-conduct.rst +0 -0
  45. {blosc2-3.3.2 → blosc2-3.3.4}/doc/development/contributing.rst +0 -0
  46. {blosc2-3.3.2 → blosc2-3.3.4}/doc/development/index.rst +0 -0
  47. {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/index.rst +0 -0
  48. {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/installation.rst +0 -0
  49. {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/overview.rst +0 -0
  50. {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/01.ndarray-basics.ipynb +0 -0
  51. {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/02.lazyarray-expressions.ipynb +0 -0
  52. {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/03.lazyarray-udf.ipynb +0 -0
  53. {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/04.reductions.ipynb +0 -0
  54. {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/05.persistent-reductions.ipynb +0 -0
  55. {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/06.remote_proxy.ipynb +0 -0
  56. {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/07.schunk-basics.ipynb +0 -0
  57. {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/08.schunk-slicing_and_beyond.ipynb +0 -0
  58. {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/10.ucodecs-ufilters.ipynb +0 -0
  59. {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/11.prefilters.ipynb +0 -0
  60. {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/12.postfilters.ipynb +0 -0
  61. {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/images/blosc2-pipeline.png +0 -0
  62. {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/images/blosc2-pipeline.svg +0 -0
  63. {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/images/lazyexpr-broadcast.png +0 -0
  64. {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/images/reductions/3D-cube-plane.png +0 -0
  65. {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/images/reductions/3D-cube.png +0 -0
  66. {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/images/reductions/memory-access-2D-x.png +0 -0
  67. {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/images/reductions/memory-access-2D-y.png +0 -0
  68. {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/images/remote_proxy.png +0 -0
  69. {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/images/ucodecs-filters/backward.png +0 -0
  70. {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/images/ucodecs-filters/backward.svg +0 -0
  71. {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/images/ucodecs-filters/decoder.png +0 -0
  72. {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/images/ucodecs-filters/decoder.svg +0 -0
  73. {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/images/ucodecs-filters/decoder2.png +0 -0
  74. {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/images/ucodecs-filters/decoder2.svg +0 -0
  75. {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/images/ucodecs-filters/encoder.png +0 -0
  76. {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/images/ucodecs-filters/encoder.svg +0 -0
  77. {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/images/ucodecs-filters/encoder2.png +0 -0
  78. {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/images/ucodecs-filters/encoder2.svg +0 -0
  79. {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/images/ucodecs-filters/forward.png +0 -0
  80. {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/images/ucodecs-filters/forward.svg +0 -0
  81. {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials.rst +0 -0
  82. {blosc2-3.3.2 → blosc2-3.3.4}/doc/index.rst +0 -0
  83. {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/array_operations.rst +0 -0
  84. {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.__getitem__.rst +0 -0
  85. {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.__init__.rst +0 -0
  86. {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.__len__.rst +0 -0
  87. {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.__setitem__.rst +0 -0
  88. {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.append_data.rst +0 -0
  89. {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.decompress_chunk.rst +0 -0
  90. {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.delete_chunk.rst +0 -0
  91. {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.fill_special.rst +0 -0
  92. {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.filler.rst +0 -0
  93. {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.get_chunk.rst +0 -0
  94. {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.get_slice.rst +0 -0
  95. {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.insert_chunk.rst +0 -0
  96. {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.insert_data.rst +0 -0
  97. {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.iterchunks.rst +0 -0
  98. {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.iterchunks_info.rst +0 -0
  99. {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.postfilter.rst +0 -0
  100. {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.prefilter.rst +0 -0
  101. {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.remove_postfilter.rst +0 -0
  102. {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.remove_prefilter.rst +0 -0
  103. {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.to_cframe.rst +0 -0
  104. {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.update_chunk.rst +0 -0
  105. {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.update_data.rst +0 -0
  106. {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/c2array.rst +0 -0
  107. {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/decorators.rst +0 -0
  108. {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/index.rst +0 -0
  109. {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/lazy_functions.rst +0 -0
  110. {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/lazyarray.rst +0 -0
  111. {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/linear_algebra.rst +0 -0
  112. {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/low_level.rst +0 -0
  113. {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/ndarray.rst +0 -0
  114. {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/ndfield.rst +0 -0
  115. {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/proxy.rst +0 -0
  116. {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/proxyndsource.rst +0 -0
  117. {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/reduction_functions.rst +0 -0
  118. {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/save_load.rst +0 -0
  119. {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/schunk.rst +0 -0
  120. {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/utilities.rst +0 -0
  121. {blosc2-3.3.2 → blosc2-3.3.4}/doc/release_notes/index.md +0 -0
  122. {blosc2-3.3.2 → blosc2-3.3.4}/examples/btune.py +0 -0
  123. {blosc2-3.3.2 → blosc2-3.3.4}/examples/c2array-get-slice.py +0 -0
  124. {blosc2-3.3.2 → blosc2-3.3.4}/examples/compress2_decompress2.py +0 -0
  125. {blosc2-3.3.2 → blosc2-3.3.4}/examples/compress_decompress.py +0 -0
  126. {blosc2-3.3.2 → blosc2-3.3.4}/examples/filler.py +0 -0
  127. {blosc2-3.3.2 → blosc2-3.3.4}/examples/gil.py +0 -0
  128. {blosc2-3.3.2 → blosc2-3.3.4}/examples/mmap-rw.py +0 -0
  129. {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/arange-constructor.py +0 -0
  130. {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/asarray_.py +0 -0
  131. {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/broadcast_expr.py +0 -0
  132. {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/buffer.py +0 -0
  133. {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/bytedelta_filter.py +0 -0
  134. {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/c2array_expr.py +0 -0
  135. {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/compute_expr.py +0 -0
  136. {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/compute_fields.py +0 -0
  137. {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/compute_udf_numba.py +0 -0
  138. {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/compute_where.py +0 -0
  139. {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/copy_.py +0 -0
  140. {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/empty_.py +0 -0
  141. {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/eye-constructor.py +0 -0
  142. {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/filter_sort_fields.py +0 -0
  143. {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/formats.py +0 -0
  144. {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/fromiter-constructor.py +0 -0
  145. {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/general_expressions.py +0 -0
  146. {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/getitem.py +0 -0
  147. {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/iterchunks_info.py +0 -0
  148. {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/jit-expr.py +0 -0
  149. {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/jit-reduc.py +0 -0
  150. {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/linspace-constructor.py +0 -0
  151. {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/lists-vs-bools-idx.py +0 -0
  152. {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/meta.py +0 -0
  153. {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/ndarray_copy.py +0 -0
  154. {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/ndmean.py +0 -0
  155. {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/persistency.py +0 -0
  156. {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/proxy-carray.py +0 -0
  157. {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/proxy-ndarray.py +0 -0
  158. {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/reduce_and_enlarge.py +0 -0
  159. {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/reduce_expr.py +0 -0
  160. {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/reduce_expr_save.py +0 -0
  161. {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/reduce_string_expr.py +0 -0
  162. {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/resize_.py +0 -0
  163. {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/work_with_numpy.py +0 -0
  164. {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/zfp_codec.py +0 -0
  165. {blosc2-3.3.2 → blosc2-3.3.4}/examples/pack_array.py +0 -0
  166. {blosc2-3.3.2 → blosc2-3.3.4}/examples/pack_tensor.py +0 -0
  167. {blosc2-3.3.2 → blosc2-3.3.4}/examples/postfilter1.py +0 -0
  168. {blosc2-3.3.2 → blosc2-3.3.4}/examples/postfilter2.py +0 -0
  169. {blosc2-3.3.2 → blosc2-3.3.4}/examples/postfilter3.py +0 -0
  170. {blosc2-3.3.2 → blosc2-3.3.4}/examples/prefilter.py +0 -0
  171. {blosc2-3.3.2 → blosc2-3.3.4}/examples/save_tensor.py +0 -0
  172. {blosc2-3.3.2 → blosc2-3.3.4}/examples/schunk.py +0 -0
  173. {blosc2-3.3.2 → blosc2-3.3.4}/examples/schunk_roundtrip.py +0 -0
  174. {blosc2-3.3.2 → blosc2-3.3.4}/examples/ucodecs.py +0 -0
  175. {blosc2-3.3.2 → blosc2-3.3.4}/examples/ufilters.py +0 -0
  176. {blosc2-3.3.2 → blosc2-3.3.4}/examples/vlmeta.py +0 -0
  177. {blosc2-3.3.2 → blosc2-3.3.4}/generate_version.py +0 -0
  178. {blosc2-3.3.2 → blosc2-3.3.4}/guix.scm +0 -0
  179. {blosc2-3.3.2 → blosc2-3.3.4}/images/Complete-Write-Read-B2ND.png +0 -0
  180. {blosc2-3.3.2 → blosc2-3.3.4}/images/M1-i386-vs-arm64-pack.png +0 -0
  181. {blosc2-3.3.2 → blosc2-3.3.4}/images/M1-i386-vs-arm64-unpack.png +0 -0
  182. {blosc2-3.3.2 → blosc2-3.3.4}/images/Read-Partial-Slices-B2ND.png +0 -0
  183. {blosc2-3.3.2 → blosc2-3.3.4}/images/b2nd-2level-parts.png +0 -0
  184. {blosc2-3.3.2 → blosc2-3.3.4}/images/eval-expr-full-mem-M2.png +0 -0
  185. {blosc2-3.3.2 → blosc2-3.3.4}/images/eval-expr-scarce-mem-M2.png +0 -0
  186. {blosc2-3.3.2 → blosc2-3.3.4}/images/lazyarray-dask-large.png +0 -0
  187. {blosc2-3.3.2 → blosc2-3.3.4}/images/lazyarray-dask-small.png +0 -0
  188. {blosc2-3.3.2 → blosc2-3.3.4}/images/lazyarray-expr-large.png +0 -0
  189. {blosc2-3.3.2 → blosc2-3.3.4}/images/lazyarray-expr.png +0 -0
  190. {blosc2-3.3.2 → blosc2-3.3.4}/images/linspace-compress.png +0 -0
  191. {blosc2-3.3.2 → blosc2-3.3.4}/images/linspace-decompress.png +0 -0
  192. {blosc2-3.3.2 → blosc2-3.3.4}/images/pack-array-cratios.png +0 -0
  193. {blosc2-3.3.2 → blosc2-3.3.4}/images/reduc-float64-amd.png +0 -0
  194. {blosc2-3.3.2 → blosc2-3.3.4}/images/reduc-float64-log-amd.png +0 -0
  195. {blosc2-3.3.2 → blosc2-3.3.4}/pytest.ini +0 -0
  196. {blosc2-3.3.2 → blosc2-3.3.4}/src/blosc2/c2array.py +0 -0
  197. {blosc2-3.3.2 → blosc2-3.3.4}/src/blosc2/helpers.py +0 -0
  198. {blosc2-3.3.2 → blosc2-3.3.4}/src/blosc2/info.py +0 -0
  199. {blosc2-3.3.2 → blosc2-3.3.4}/src/blosc2/storage.py +0 -0
  200. {blosc2-3.3.2 → blosc2-3.3.4}/tests/conftest.py +0 -0
  201. {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_auto_parts.py +0 -0
  202. {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_buffer.py +0 -0
  203. {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_c2array_expr.py +0 -0
  204. {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_c2array_reductions.py +0 -0
  205. {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_c2array_udf.py +0 -0
  206. {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_copy.py +0 -0
  207. {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_empty.py +0 -0
  208. {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_full.py +0 -0
  209. {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_get_slice_nchunks.py +0 -0
  210. {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_getitem.py +0 -0
  211. {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_iterchunks_info.py +0 -0
  212. {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_lazyudf.py +0 -0
  213. {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_lossy.py +0 -0
  214. {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_matmul.py +0 -0
  215. {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_metalayers.py +0 -0
  216. {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_mode.py +0 -0
  217. {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_nans.py +0 -0
  218. {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_numpy.py +0 -0
  219. {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_persistency.py +0 -0
  220. {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_proxy.py +0 -0
  221. {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_proxy_c2array.py +0 -0
  222. {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_proxy_expr.py +0 -0
  223. {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_resize.py +0 -0
  224. {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_setitem.py +0 -0
  225. {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_slice.py +0 -0
  226. {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_squeeze.py +0 -0
  227. {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_struct_dtype.py +0 -0
  228. {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_transpose.py +0 -0
  229. {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_bytes_array.py +0 -0
  230. {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_comp_info.py +0 -0
  231. {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_compress2.py +0 -0
  232. {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_compression_parameters.py +0 -0
  233. {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_compressors.py +0 -0
  234. {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_decompress.py +0 -0
  235. {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_iterchunks.py +0 -0
  236. {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_mmap.py +0 -0
  237. {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_open.py +0 -0
  238. {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_open_c2array.py +0 -0
  239. {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_pathlib.py +0 -0
  240. {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_postfilters.py +0 -0
  241. {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_prefilters.py +0 -0
  242. {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_proxy_schunk.py +0 -0
  243. {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_python_blosc.py +0 -0
  244. {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_schunk.py +0 -0
  245. {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_schunk_constructor.py +0 -0
  246. {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_schunk_delete.py +0 -0
  247. {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_schunk_get_slice.py +0 -0
  248. {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_schunk_get_slice_nchunks.py +0 -0
  249. {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_schunk_insert.py +0 -0
  250. {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_schunk_set_slice.py +0 -0
  251. {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_schunk_update.py +0 -0
  252. {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_storage.py +0 -0
  253. {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_tensor.py +0 -0
  254. {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_ucodecs.py +0 -0
  255. {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_ufilters.py +0 -0
  256. {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_vlmeta.py +0 -0
  257. {blosc2-3.3.2 → blosc2-3.3.4}/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,11 +1,11 @@
1
- Announcing Python-Blosc2 3.3.2
1
+ Announcing Python-Blosc2 3.3.4
2
2
  ==============================
3
3
 
4
- This is a bugfix release, with some minor optimizations. We fixed
5
- specially a bug in the determination of chunk shape in constructors
6
- on CPUs with large L3 cache sizes (like AMD EPYC). We also fixed a
7
- bug preventing the correct chaining of *string* lazy expressions for
8
- logical operators (``&``, ``|``, ``^``...).
4
+ This is a bugfix release, with some minor optimizations. We further improved the
5
+ correct chaining of *string* lazy expressions (to allow operands with more
6
+ diverse data types). In addition, both indexing and where expressions are now
7
+ supported within *string* lazy expressions. Finally, casting rules have
8
+ been improved to be more consistent with NumPy.
9
9
 
10
10
  You can think of Python-Blosc2 3.x as an extension of NumPy/numexpr that:
11
11
 
@@ -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 4ef3c7440a85632e6c8b6c5d2a9e651e45569fc1 # 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.2
3
+ Version: 3.3.4
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>
@@ -1,5 +1,49 @@
1
1
  # Release notes
2
2
 
3
+ ## Changes from 3.3.4 to 3.3.5
4
+
5
+ XXX version-specific blurb XXX
6
+
7
+ ## Changes from 3.3.3 to 3.3.4
8
+
9
+ * Expand possibilities for chaining string-based lazy expressions to incorporate
10
+ data types which do not have shape attribute, e.g. int, float etc.
11
+ See #406 and PR #411.
12
+
13
+ * Enable slicing within string-based lazy expressions. See PR #414.
14
+
15
+ * Improved casting for string-based lazy expressions.
16
+
17
+ * Documentation improvements, see PR #410.
18
+
19
+ * Compatibility fixes for working with `h5py` files.
20
+
21
+ ## Changes from 3.3.2 to 3.3.3
22
+
23
+ * Expand possibilities for chaining string-based lazy expressions to include
24
+ main operand types (LazyExpr and NDArray). Still have to incorporate other
25
+ data types (which do not have shape attribute, e.g. int, float etc.).
26
+ See #406.
27
+
28
+ * Fix indexing for lazy expressions, and allow use of None in getitem.
29
+ See PR #402.
30
+
31
+ * Fix incorrect appending of dim to computed reductions. See PR #404.
32
+
33
+ * Fix `blosc2.linspace()` for incompatible num/shape. See PR #408.
34
+
35
+ * Add support for NumPy dtypes that are n-dimensional (e.g.
36
+ `np.dtype(("<i4,>f4", (10,))),`).
37
+
38
+ * New MAX_DIM constant for the maximum number of dimensions supported.
39
+ This is useful for checking if a given array is too large to be handled.
40
+
41
+ * More refinements on guessing cache sizes for Linux.
42
+
43
+ * Update to C-Blosc2 2.17.2.dev. Now, we are forcing the flush of modified
44
+ pages only in write mode for mmap files. This fixes mmap issues on Windows.
45
+ Thanks to @JanSellner for the implementation.
46
+
3
47
  ## Changes from 3.3.1 to 3.3.2
4
48
 
5
49
  * Fixed a bug in the determination of chunk shape for the `NDArray` constructor.
@@ -15,6 +59,8 @@
15
59
  * Now, storage defaults (`blosc2.storage_dflts`) are honored, even if no
16
60
  `storage=` param is used in constructors.
17
61
 
62
+ * We are distributing Python 3.10 wheels now.
63
+
18
64
  ## Changes from 3.3.0 to 3.3.1
19
65
 
20
66
  * 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.1 released on 2025-04-20!</a>
9
+ style="font-size: 1.5em;">Version 3.3.3 released on 2025-05-14!</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>
@@ -12,3 +12,4 @@ Main Classes
12
12
  proxy
13
13
  proxysource
14
14
  proxyndsource
15
+ simpleproxy
@@ -4,8 +4,8 @@ ProxySource
4
4
  ===========
5
5
 
6
6
  Base interface for all supported sources in :ref:`Proxy` and are not NDim objects.
7
- For example, a file, a memory buffer, a network resource, etc. For NDims, see
8
- :ref:`ProxyNDSource`.
7
+ For example, a file, a memory buffer, a network resource, etc. For n-dimemsional
8
+ ones, see :ref:`ProxyNDSource`.
9
9
 
10
10
  .. currentmodule:: blosc2.ProxySource
11
11
 
@@ -0,0 +1,30 @@
1
+ .. _SimpleProxy:
2
+
3
+ SimpleProxy
4
+ ===========
5
+
6
+ Simple proxy for a NumPy array (or similar) that can be used with the Blosc2 compute engine.
7
+
8
+ This only supports the __getitem__ method. No caching is performed.
9
+
10
+ .. currentmodule:: blosc2.SimpleProxy
11
+
12
+ Methods
13
+ -------
14
+
15
+ .. autosummary::
16
+ :toctree: autofiles/simpleproxy
17
+ :nosignatures:
18
+
19
+ __init__
20
+ __getitem__
21
+
22
+ Attributes
23
+ ----------
24
+
25
+ .. autosummary::
26
+ :toctree: autofiles/simpleproxy
27
+
28
+ shape
29
+ dtype
30
+ src
@@ -1,3 +1,5 @@
1
+ .. _CompStorParams:
2
+
1
3
  Compression, decompression and storage parameters
2
4
  =================================================
3
5
 
@@ -18,7 +18,7 @@ import blosc2
18
18
  # Create some sample data
19
19
  a = blosc2.linspace(0, 1, 10 * 100, dtype="float32", shape=(10, 100))
20
20
  b = blosc2.linspace(1, 2, 10 * 100, dtype="float32", shape=(10, 100))
21
- c = blosc2.linspace(-10, 10, 10, dtype="float32", shape=(100,))
21
+ c = blosc2.linspace(-10, 10, 100, dtype="float32", shape=(100,))
22
22
 
23
23
 
24
24
  # Example 1: Basic usage of the jit decorator with reduction
@@ -41,7 +41,7 @@ dependencies = [
41
41
  "py-cpuinfo; platform_machine != 'wasm32'",
42
42
  "requests",
43
43
  ]
44
- version = "3.3.2"
44
+ version = "3.3.4"
45
45
 
46
46
 
47
47
  [project.optional-dependencies]
@@ -111,7 +111,7 @@ extend-select = [
111
111
  "RET",
112
112
  "RUF",
113
113
  "SIM",
114
- "TCH",
114
+ "TC",
115
115
  "UP",
116
116
  ]
117
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
@@ -2594,8 +2595,33 @@ cdef class NDArray:
2594
2595
 
2595
2596
 
2596
2597
  cdef b2nd_context_t* create_b2nd_context(shape, chunks, blocks, dtype, kwargs):
2597
- # This is used only in constructors, dtype will always have NumPy format
2598
- dtype = np.dtype(dtype)
2598
+ if isinstance(dtype, list) and len(dtype) > 0 and isinstance(dtype[0], tuple):
2599
+ # Extract just the field names and basic dtype info
2600
+ fields = []
2601
+ for field in dtype:
2602
+ name = field[0]
2603
+ field_dtype = field[1]
2604
+
2605
+ # Handle different field formats:
2606
+ # 1. ('name', ('|S10', {'h5py_encoding': 'ascii'})) - h5py style
2607
+ # 2. ('name', '<i4') - standard NumPy style
2608
+ # 3. ('name', '<i4', (shape,)) - NumPy with shape info
2609
+
2610
+ if isinstance(field_dtype, tuple) and len(field_dtype) > 0:
2611
+ # h5py nested representation with metadata dict
2612
+ field_dtype = field_dtype[0]
2613
+
2614
+ # Check if we have shape information as third element
2615
+ if len(field) > 2 and field[2] is not None:
2616
+ # Include the shape information
2617
+ fields.append((name, field_dtype, field[2]))
2618
+ else:
2619
+ fields.append((name, field_dtype))
2620
+
2621
+ dtype = np.dtype(fields)
2622
+ else:
2623
+ dtype = np.dtype(dtype)
2624
+
2599
2625
  typesize = dtype.itemsize
2600
2626
  if 'cparams' in kwargs:
2601
2627
  kwargs['cparams']['typesize'] = typesize
@@ -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
 
@@ -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
@@ -116,7 +116,7 @@ dtype_symbols = {
116
116
  constructors = ("arange", "linspace", "fromiter", "zeros", "ones", "empty", "full", "frombuffer")
117
117
  # Note that, as reshape is accepted as a method too, it should always come last in the list
118
118
  constructors += ("reshape",)
119
- reducers = ("sum", "prod", "min", "max", "std", "mean", "var", "any", "all")
119
+ reducers = ("sum", "prod", "min", "max", "std", "mean", "var", "any", "all", "slice")
120
120
 
121
121
  functions = [
122
122
  "sin",
@@ -541,7 +541,7 @@ def compute_smaller_slice(larger_shape, smaller_shape, larger_slice):
541
541
 
542
542
  # Define the patterns for validation
543
543
  validation_patterns = [
544
- r"[\;\[\:]", # Flow control characters
544
+ r"[\;]", # Flow control characters
545
545
  r"(^|[^\w])__[\w]+__($|[^\w])", # Dunder methods
546
546
  r"\.\b(?!real|imag|(\d*[eE]?[+-]?\d+)|(\d*[eE]?[+-]?\d+j)|\d*j\b|(sum|prod|min|max|std|mean|var|any|all|where)"
547
547
  r"\s*\([^)]*\)|[a-zA-Z_]\w*\s*\([^)]*\))", # Attribute patterns
@@ -551,7 +551,20 @@ validation_patterns = [
551
551
  _blacklist_re = re.compile("|".join(validation_patterns))
552
552
 
553
553
  # Define valid method names
554
- valid_methods = {"sum", "prod", "min", "max", "std", "mean", "var", "any", "all", "where", "reshape"}
554
+ valid_methods = {
555
+ "sum",
556
+ "prod",
557
+ "min",
558
+ "max",
559
+ "std",
560
+ "mean",
561
+ "var",
562
+ "any",
563
+ "all",
564
+ "where",
565
+ "reshape",
566
+ "slice",
567
+ }
555
568
  valid_methods |= {"int8", "int16", "int32", "int64", "uint8", "uint16", "uint32", "uint64"}
556
569
  valid_methods |= {"float32", "float64", "complex64", "complex128"}
557
570
  valid_methods |= {"bool", "str", "bytes"}
@@ -579,7 +592,7 @@ def validate_expr(expr: str) -> None:
579
592
  raise ValueError(f"'{expr}' is not a valid expression.")
580
593
 
581
594
  # Check for invalid characters not covered by the tokenizer
582
- invalid_chars = re.compile(r"[^\w\s+\-*/%().,=<>!&|~^]")
595
+ invalid_chars = re.compile(r"[^\w\s+\-*/%()[].,=<>!&|~^]")
583
596
  if invalid_chars.search(skip_quotes) is not None:
584
597
  invalid_chars = invalid_chars.findall(skip_quotes)
585
598
  raise ValueError(f"Expression {expr} contains invalid characters: {invalid_chars}")
@@ -630,6 +643,144 @@ def get_expr_operands(expression: str) -> set:
630
643
  return set(visitor.operands)
631
644
 
632
645
 
646
+ def conserve_functions( # noqa: C901
647
+ expression: str,
648
+ operands_old: dict[str, blosc2.NDArray | blosc2.LazyExpr],
649
+ operands_new: dict[str, blosc2.NDArray | blosc2.LazyExpr],
650
+ ) -> tuple(str, dict[str, blosc2.NDArray]):
651
+ """
652
+ Given an expression in string form, return its operands.
653
+
654
+ Parameters
655
+ ----------
656
+ expression : str
657
+ The expression in string form.
658
+
659
+ operands_old: dict[str : blosc2.ndarray | blosc2.LazyExpr]
660
+ Dict of operands from expression prior to eval.
661
+
662
+ operands_new: dict[str : blosc2.ndarray | blosc2.LazyExpr]
663
+ Dict of operands from expression after eval.
664
+ Returns
665
+ -------
666
+ newexpression
667
+ A modified string expression with the functions/constructors conserved and
668
+ true operands rebased and written in o- notation.
669
+ newoperands
670
+ Dict of the set of rebased operands.
671
+ """
672
+
673
+ operand_to_key = {id(v): k for k, v in operands_new.items()}
674
+ for k, v in operands_old.items(): # extend operands_to_key with old operands
675
+ if isinstance(
676
+ v, blosc2.LazyExpr
677
+ ): # unroll operands in LazyExpr (only necessary when have reduced a lazyexpr)
678
+ d = v.operands
679
+ else:
680
+ d = {k: v}
681
+ for newk, newv in d.items():
682
+ try:
683
+ operand_to_key[id(newv)]
684
+ except KeyError:
685
+ newk = (
686
+ f"o{len(operands_new)}" if newk in operands_new else newk
687
+ ) # possible that names coincide
688
+ operand_to_key[id(newv)] = newk
689
+ operands_new[newk] = newv
690
+
691
+ class OperandVisitor(ast.NodeVisitor):
692
+ def __init__(self):
693
+ self.operandmap = {}
694
+ self.operands = {}
695
+ self.opcounter = 0
696
+ self.function_names = set()
697
+
698
+ def update_func(self, localop):
699
+ k = operand_to_key[id(localop)]
700
+ if k not in self.operandmap:
701
+ newkey = f"o{self.opcounter}"
702
+ self.operands[newkey] = operands_new[k]
703
+ self.operandmap[k] = newkey
704
+ self.opcounter += 1
705
+ return newkey
706
+ else:
707
+ return self.operandmap[k]
708
+
709
+ def visit_Name(self, node):
710
+ if node.id == "np": # Skip NumPy namespace (e.g. np.int8, which will be treated separately)
711
+ return
712
+ if node.id in self.function_names: # Skip function names
713
+ return
714
+ elif node.id not in dtype_symbols:
715
+ localop = operands_old[node.id]
716
+ if isinstance(localop, blosc2.LazyExpr):
717
+ newexpr = localop.expression
718
+ for (
719
+ opname,
720
+ v,
721
+ ) in localop.operands.items(): # expression operands already in terms of basic operands
722
+ # add illegal character ; to track changed operands and not overwrite later
723
+ newopname = ";" + self.update_func(v)
724
+ newexpr = re.sub(
725
+ rf"(?<=\s){opname}|(?<=\(){opname}", newopname, newexpr
726
+ ) # replace with newopname
727
+ # remove all instances of ; as all changes completed
728
+ node.id = newexpr.replace(";", "")
729
+ else:
730
+ node.id = self.update_func(localop)
731
+ else:
732
+ pass
733
+ self.generic_visit(node)
734
+
735
+ def visit_Call(self, node):
736
+ if isinstance(
737
+ node.func, ast.Name
738
+ ): # visits Call first, then Name, so don't increment operandcounter yet
739
+ self.function_names.add(node.func.id)
740
+ self.generic_visit(node)
741
+
742
+ tree = ast.parse(expression)
743
+ visitor = OperandVisitor()
744
+ visitor.visit(tree)
745
+ newexpression, newoperands = ast.unparse(tree), visitor.operands
746
+ return newexpression, newoperands
747
+
748
+
749
+ def convert_to_slice(expression):
750
+ """
751
+ Takes expression and converts all instances of [] to .slice(....)
752
+
753
+ Parameters
754
+ ----------
755
+ expression: str
756
+
757
+ Returns
758
+ -------
759
+ new_expr : str
760
+ """
761
+
762
+ new_expr = ""
763
+ skip_to_char = 0
764
+ for i, expr_i in enumerate(expression):
765
+ if i < skip_to_char:
766
+ continue
767
+ if expr_i == "[":
768
+ k = expression[i:].find("]") # start checking from after [
769
+ slice_convert = expression[i : i + k + 1] # include [ and ]
770
+ slicer = eval(f"np.s_{slice_convert}")
771
+ slicer = (slicer,) if not isinstance(slicer, tuple) else slicer # standardise to tuple
772
+ if any(isinstance(el, str) for el in slicer): # handle fields
773
+ raise ValueError("Cannot handle fields for slicing lazy expressions.")
774
+ slicer = str(slicer)
775
+ # use slice so that lazyexpr uses blosc arrays internally
776
+ # (and doesn't decompress according to getitem syntax)
777
+ new_expr += ".slice(" + slicer + ")"
778
+ skip_to_char = i + k + 1
779
+ else:
780
+ new_expr += expr_i
781
+ return new_expr
782
+
783
+
633
784
  class TransformNumpyCalls(ast.NodeTransformer):
634
785
  def __init__(self):
635
786
  self.replacements = {}
@@ -1802,9 +1953,18 @@ def infer_dtype(op, value1, value2):
1802
1953
  if op != "~" and value2.dtype != np.bool_:
1803
1954
  raise ValueError(f"Invalid operand type for {op}: {value2.dtype}")
1804
1955
  return np.dtype(np.bool_)
1805
- dtype1 = value1.dtype if hasattr(value1, "dtype") else np.array(value1).dtype
1806
- dtype2 = value2.dtype if hasattr(value2, "dtype") else np.array(value2).dtype
1807
- return np.result_type(dtype1, dtype2)
1956
+
1957
+ # Follow NumPy rules for scalar-array operations
1958
+ # Create small arrays with the same dtypes and let NumPy's type promotion determine the result type
1959
+ if np.isscalar(value1) and hasattr(value2, "shape"):
1960
+ arr2 = np.array([0], dtype=value2.dtype)
1961
+ return (value1 + arr2).dtype
1962
+ elif np.isscalar(value2) and hasattr(value1, "shape"):
1963
+ arr1 = np.array([0], dtype=value1.dtype)
1964
+ return (arr1 + value2).dtype
1965
+ else:
1966
+ # Both are arrays or both are scalars, use NumPy's type promotion rules
1967
+ return np.result_type(value1, value2)
1808
1968
 
1809
1969
 
1810
1970
  class LazyExpr(LazyArray):
@@ -1990,6 +2150,8 @@ class LazyExpr(LazyArray):
1990
2150
 
1991
2151
  operands = {
1992
2152
  key: np.ones(np.ones(len(value.shape), dtype=int), dtype=value.dtype)
2153
+ if hasattr(value, "shape")
2154
+ else value
1993
2155
  for key, value in self.operands.items()
1994
2156
  }
1995
2157
 
@@ -2431,25 +2593,28 @@ class LazyExpr(LazyArray):
2431
2593
  def _compute_expr(self, item, kwargs): # noqa: C901
2432
2594
  if any(method in self.expression for method in reducers):
2433
2595
  # We have reductions in the expression (probably coming from a string lazyexpr)
2596
+ # Also includes slice
2434
2597
  _globals = get_expr_globals(self.expression)
2435
2598
  lazy_expr = eval(self.expression, _globals, self.operands)
2436
2599
  if not isinstance(lazy_expr, blosc2.LazyExpr):
2600
+ key, _ = process_key(item, self.shape)
2437
2601
  # An immediate evaluation happened (e.g. all operands are numpy arrays)
2438
2602
  if hasattr(self, "_where_args"):
2439
2603
  # We need to apply the where() operation
2440
2604
  if len(self._where_args) == 1:
2441
2605
  # We have a single argument
2442
2606
  where_x = self._where_args["_where_x"]
2443
- return where_x[:][lazy_expr]
2607
+ return (where_x[:][lazy_expr])[key]
2444
2608
  if len(self._where_args) == 2:
2445
2609
  # We have two arguments
2446
2610
  where_x = self._where_args["_where_x"]
2447
2611
  where_y = self._where_args["_where_y"]
2448
- return np.where(lazy_expr, where_x, where_y)
2612
+ return np.where(lazy_expr, where_x, where_y)[key]
2449
2613
  if hasattr(self, "_output"):
2450
2614
  # This is not exactly optimized, but it works for now
2451
- self._output[:] = lazy_expr
2452
- return lazy_expr
2615
+ self._output[:] = lazy_expr[key]
2616
+ return self._output
2617
+ return lazy_expr[key]
2453
2618
 
2454
2619
  return chunked_eval(lazy_expr.expression, lazy_expr.operands, item, **kwargs)
2455
2620
 
@@ -2661,6 +2826,7 @@ class LazyExpr(LazyArray):
2661
2826
  def _new_expr(cls, expression, operands, guess, out=None, where=None, ne_args=None):
2662
2827
  # Validate the expression
2663
2828
  validate_expr(expression)
2829
+ expression = convert_to_slice(expression)
2664
2830
  if guess:
2665
2831
  # The expression has been validated, so we can evaluate it
2666
2832
  # in guessing mode to avoid computing reductions
@@ -2676,10 +2842,28 @@ class LazyExpr(LazyArray):
2676
2842
  _dtype = new_expr.dtype
2677
2843
  _shape = new_expr.shape
2678
2844
  if isinstance(new_expr, blosc2.LazyExpr):
2679
- # Restore the original expression and operands
2680
- new_expr.expression = f"({_expression})" # forcibly add parenthesis
2681
- new_expr.expression_tosave = _expression
2682
- new_expr.operands = _operands
2845
+ # DO NOT restore the original expression and operands
2846
+ # Instead rebase operands and restore only constructors
2847
+ expression_, operands_ = conserve_functions(
2848
+ _expression, _operands, new_expr.operands | local_vars
2849
+ )
2850
+ # if new_expr has where_args, must have come from where(...) - or possibly where(where(..
2851
+ # since 5*where, where + ... are evaluated eagerly
2852
+ if hasattr(new_expr, "_where_args"):
2853
+ st = expression_.find("where(") + len(
2854
+ "where("
2855
+ ) # expr always begins where( - should have st = 6 always
2856
+ finalexpr = ""
2857
+ counter = 0
2858
+ for char in expression_[st:]: # get rid of external where(...)
2859
+ finalexpr += char
2860
+ counter += 1 * (char == "(") - 1 * (char == ")")
2861
+ if counter == 0 and char == ",":
2862
+ break
2863
+ expression_ = finalexpr[:-1] # remove trailing comma
2864
+ new_expr.expression = f"({expression_})" # force parenthesis
2865
+ new_expr.expression_tosave = expression
2866
+ new_expr.operands = operands_
2683
2867
  new_expr.operands_tosave = operands
2684
2868
  else:
2685
2869
  # An immediate evaluation happened (e.g. all operands are numpy arrays)