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.
- {blosc2-3.3.2 → blosc2-3.3.4}/.pre-commit-config.yaml +1 -1
- {blosc2-3.3.2 → blosc2-3.3.4}/ANNOUNCE.rst +6 -6
- {blosc2-3.3.2 → blosc2-3.3.4}/CMakeLists.txt +1 -1
- {blosc2-3.3.2 → blosc2-3.3.4}/PKG-INFO +1 -1
- {blosc2-3.3.2 → blosc2-3.3.4}/RELEASE_NOTES.md +46 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/python-blosc2.rst +1 -1
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/classes.rst +1 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/proxysource.rst +2 -2
- blosc2-3.3.4/doc/reference/simpleproxy.rst +30 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/storage.rst +2 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/jit-numpy-funcs.py +1 -1
- {blosc2-3.3.2 → blosc2-3.3.4}/pyproject.toml +2 -2
- {blosc2-3.3.2 → blosc2-3.3.4}/src/blosc2/__init__.py +1 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/src/blosc2/blosc2_ext.pyx +29 -3
- {blosc2-3.3.2 → blosc2-3.3.4}/src/blosc2/core.py +34 -26
- {blosc2-3.3.2 → blosc2-3.3.4}/src/blosc2/lazyexpr.py +200 -16
- {blosc2-3.3.2 → blosc2-3.3.4}/src/blosc2/ndarray.py +21 -7
- {blosc2-3.3.2 → blosc2-3.3.4}/src/blosc2/proxy.py +20 -5
- {blosc2-3.3.2 → blosc2-3.3.4}/src/blosc2/schunk.py +12 -3
- blosc2-3.3.4/src/blosc2/version.py +1 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_evaluate.py +1 -1
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_jit.py +1 -1
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_lazyexpr.py +69 -42
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_lazyexpr_fields.py +41 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_ndarray.py +8 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_reductions.py +70 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_zeros.py +37 -0
- blosc2-3.3.2/src/blosc2/version.py +0 -1
- {blosc2-3.3.2 → blosc2-3.3.4}/.gitignore +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/.guix/modules/python-blosc2-package.scm +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/.guix-channel +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/CONTRIBUTING.rst +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/LICENSE.txt +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/README.rst +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/README_DEVELOPERS.md +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/RELEASING.rst +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/code_of_conduct.md +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/_static/blosc-favicon_32x32.png +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/_static/blosc-favicon_64x64.png +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/_static/blosc-logo_128.png +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/_static/blosc-logo_256.png +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/_static/css/custom.css +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/conf.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/development/code-of-conduct.rst +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/development/contributing.rst +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/development/index.rst +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/index.rst +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/installation.rst +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/overview.rst +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/01.ndarray-basics.ipynb +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/02.lazyarray-expressions.ipynb +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/03.lazyarray-udf.ipynb +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/04.reductions.ipynb +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/05.persistent-reductions.ipynb +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/06.remote_proxy.ipynb +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/07.schunk-basics.ipynb +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/08.schunk-slicing_and_beyond.ipynb +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/10.ucodecs-ufilters.ipynb +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/11.prefilters.ipynb +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/12.postfilters.ipynb +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/images/blosc2-pipeline.png +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/images/blosc2-pipeline.svg +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/images/lazyexpr-broadcast.png +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/images/reductions/3D-cube-plane.png +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/images/reductions/3D-cube.png +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/images/reductions/memory-access-2D-x.png +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/images/reductions/memory-access-2D-y.png +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/images/remote_proxy.png +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/images/ucodecs-filters/backward.png +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/images/ucodecs-filters/backward.svg +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/images/ucodecs-filters/decoder.png +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/images/ucodecs-filters/decoder.svg +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/images/ucodecs-filters/decoder2.png +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/images/ucodecs-filters/decoder2.svg +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/images/ucodecs-filters/encoder.png +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/images/ucodecs-filters/encoder.svg +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/images/ucodecs-filters/encoder2.png +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/images/ucodecs-filters/encoder2.svg +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/images/ucodecs-filters/forward.png +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials/images/ucodecs-filters/forward.svg +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/getting_started/tutorials.rst +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/index.rst +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/array_operations.rst +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.__getitem__.rst +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.__init__.rst +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.__len__.rst +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.__setitem__.rst +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.append_data.rst +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.decompress_chunk.rst +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.delete_chunk.rst +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.fill_special.rst +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.filler.rst +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.get_chunk.rst +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.get_slice.rst +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.insert_chunk.rst +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.insert_data.rst +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.iterchunks.rst +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.iterchunks_info.rst +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.postfilter.rst +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.prefilter.rst +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.remove_postfilter.rst +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.remove_prefilter.rst +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.to_cframe.rst +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.update_chunk.rst +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/autofiles/schunk/blosc2.schunk.SChunk.update_data.rst +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/c2array.rst +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/decorators.rst +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/index.rst +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/lazy_functions.rst +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/lazyarray.rst +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/linear_algebra.rst +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/low_level.rst +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/ndarray.rst +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/ndfield.rst +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/proxy.rst +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/proxyndsource.rst +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/reduction_functions.rst +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/save_load.rst +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/schunk.rst +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/reference/utilities.rst +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/doc/release_notes/index.md +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/btune.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/c2array-get-slice.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/compress2_decompress2.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/compress_decompress.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/filler.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/gil.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/mmap-rw.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/arange-constructor.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/asarray_.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/broadcast_expr.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/buffer.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/bytedelta_filter.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/c2array_expr.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/compute_expr.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/compute_fields.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/compute_udf_numba.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/compute_where.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/copy_.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/empty_.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/eye-constructor.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/filter_sort_fields.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/formats.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/fromiter-constructor.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/general_expressions.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/getitem.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/iterchunks_info.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/jit-expr.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/jit-reduc.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/linspace-constructor.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/lists-vs-bools-idx.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/meta.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/ndarray_copy.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/ndmean.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/persistency.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/proxy-carray.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/proxy-ndarray.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/reduce_and_enlarge.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/reduce_expr.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/reduce_expr_save.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/reduce_string_expr.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/resize_.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/work_with_numpy.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/ndarray/zfp_codec.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/pack_array.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/pack_tensor.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/postfilter1.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/postfilter2.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/postfilter3.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/prefilter.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/save_tensor.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/schunk.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/schunk_roundtrip.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/ucodecs.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/ufilters.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/examples/vlmeta.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/generate_version.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/guix.scm +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/images/Complete-Write-Read-B2ND.png +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/images/M1-i386-vs-arm64-pack.png +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/images/M1-i386-vs-arm64-unpack.png +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/images/Read-Partial-Slices-B2ND.png +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/images/b2nd-2level-parts.png +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/images/eval-expr-full-mem-M2.png +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/images/eval-expr-scarce-mem-M2.png +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/images/lazyarray-dask-large.png +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/images/lazyarray-dask-small.png +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/images/lazyarray-expr-large.png +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/images/lazyarray-expr.png +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/images/linspace-compress.png +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/images/linspace-decompress.png +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/images/pack-array-cratios.png +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/images/reduc-float64-amd.png +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/images/reduc-float64-log-amd.png +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/pytest.ini +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/src/blosc2/c2array.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/src/blosc2/helpers.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/src/blosc2/info.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/src/blosc2/storage.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/conftest.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_auto_parts.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_buffer.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_c2array_expr.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_c2array_reductions.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_c2array_udf.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_copy.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_empty.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_full.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_get_slice_nchunks.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_getitem.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_iterchunks_info.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_lazyudf.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_lossy.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_matmul.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_metalayers.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_mode.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_nans.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_numpy.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_persistency.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_proxy.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_proxy_c2array.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_proxy_expr.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_resize.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_setitem.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_slice.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_squeeze.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_struct_dtype.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/ndarray/test_transpose.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_bytes_array.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_comp_info.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_compress2.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_compression_parameters.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_compressors.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_decompress.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_iterchunks.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_mmap.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_open.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_open_c2array.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_pathlib.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_postfilters.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_prefilters.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_proxy_schunk.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_python_blosc.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_schunk.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_schunk_constructor.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_schunk_delete.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_schunk_get_slice.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_schunk_get_slice_nchunks.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_schunk_insert.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_schunk_set_slice.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_schunk_update.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_storage.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_tensor.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_ucodecs.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_ufilters.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/tests/test_vlmeta.py +0 -0
- {blosc2-3.3.2 → blosc2-3.3.4}/update_version.py +0 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
Announcing Python-Blosc2 3.3.
|
|
1
|
+
Announcing Python-Blosc2 3.3.4
|
|
2
2
|
==============================
|
|
3
3
|
|
|
4
|
-
This is a bugfix release, with some minor optimizations.
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
|
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,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.
|
|
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>
|
|
@@ -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
|
|
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
|
|
@@ -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,
|
|
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.
|
|
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
|
-
"
|
|
114
|
+
"TC",
|
|
115
115
|
"UP",
|
|
116
116
|
]
|
|
117
117
|
ignore = [
|
|
@@ -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
|
-
|
|
2598
|
-
|
|
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
|
|
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"] == "
|
|
1173
|
+
if entry["field"] == f"L{cache_level} cache:":
|
|
1172
1174
|
size_str, instances_str = entry["data"].split(" (")
|
|
1173
|
-
size =
|
|
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("
|
|
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]) *
|
|
1199
|
+
cache_size = int(size[:-2]) * 2**10
|
|
1206
1200
|
elif size.endswith("M\n"):
|
|
1207
|
-
cache_size = int(size[:-2]) *
|
|
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
|
-
#
|
|
1210
|
-
|
|
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"[
|
|
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 = {
|
|
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
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
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
|
-
|
|
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
|
-
#
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
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)
|