diff -Nru tifffile-20230710/CHANGES.rst tifffile-20230718/CHANGES.rst --- tifffile-20230710/CHANGES.rst 2023-07-10 23:26:02.000000000 +0000 +++ tifffile-20230718/CHANGES.rst 2023-07-19 19:18:36.000000000 +0000 @@ -1,6 +1,12 @@ Revisions --------- +2023.7.18 + +- Pass 4993 tests. +- Limit threading via TIFFFILE_NUM_THREADS environment variable (#215). +- Remove maxworkers parameter from tiff2fsspec (breaking). + 2023.7.10 - Increase default strip size to 256 KB when writing with compression. @@ -8,7 +14,6 @@ 2023.7.4 -- Pass 4992 tests. - Add option to return selection from imread (#200). - Fix reading OME series with missing trailing frames (#199). - Fix fsspec reference for WebP compressed segments missing alpha channel. diff -Nru tifffile-20230710/debian/changelog tifffile-20230718/debian/changelog --- tifffile-20230710/debian/changelog 2023-07-12 12:59:47.000000000 +0000 +++ tifffile-20230718/debian/changelog 2023-07-25 08:14:52.000000000 +0000 @@ -1,3 +1,10 @@ +tifffile (20230718-1) unstable; urgency=medium + + * New upstream version 20230718 + * Rediff patches + + -- Ole Streicher Tue, 25 Jul 2023 10:14:52 +0200 + tifffile (20230710-1) unstable; urgency=medium * New upstream version 20230710 diff -Nru tifffile-20230710/debian/patches/Disable-tests-that-require-remote-files.patch tifffile-20230718/debian/patches/Disable-tests-that-require-remote-files.patch --- tifffile-20230710/debian/patches/Disable-tests-that-require-remote-files.patch 2023-07-12 12:59:47.000000000 +0000 +++ tifffile-20230718/debian/patches/Disable-tests-that-require-remote-files.patch 2023-07-25 08:14:40.000000000 +0000 @@ -7,7 +7,7 @@ 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/test_tifffile.py b/tests/test_tifffile.py -index a356989..3b055b1 100644 +index 68d7688..6716200 100644 --- a/tests/test_tifffile.py +++ b/tests/test_tifffile.py @@ -548,6 +548,7 @@ def test_issue_imread_kwargs_legacy(): @@ -18,7 +18,7 @@ def test_issue_infinite_loop(): """Test infinite loop reading more than two tags of same code in IFD.""" # Reported by D. Hughes on 2019.7.26 -@@ -3455,6 +3456,7 @@ def test_class_omexml_fail(shape, storedshape, dtype, axes, error): +@@ -3468,6 +3469,7 @@ def test_class_omexml_fail(shape, storedshape, dtype, axes, error): ], ) @pytest.mark.parametrize('metadata', ('axes', None)) @@ -26,7 +26,7 @@ def test_class_omexml(axes, autoaxes, shape, storedshape, dimorder, metadata): """Test OmeXml class.""" dtype = numpy.uint8 -@@ -3546,6 +3548,7 @@ def test_class_omexml(axes, autoaxes, shape, storedshape, dimorder, metadata): +@@ -3559,6 +3561,7 @@ def test_class_omexml(axes, autoaxes, shape, storedshape, dimorder, metadata): ), ], ) @@ -34,7 +34,7 @@ def test_class_omexml_modulo(axes, shape, storedshape, sizetzc, dimorder): """Test OmeXml class with modulo dimensions.""" dtype = numpy.uint8 -@@ -3560,6 +3563,7 @@ def test_class_omexml_modulo(axes, shape, storedshape, sizetzc, dimorder): +@@ -3573,6 +3576,7 @@ def test_class_omexml_modulo(axes, shape, storedshape, sizetzc, dimorder): assert_valid_omexml(omexml) @@ -42,7 +42,7 @@ def test_class_omexml_attributes(): """Test OmeXml class with attributes and elements.""" from uuid import uuid1 -@@ -3603,6 +3607,7 @@ def test_class_omexml_attributes(): +@@ -3616,6 +3620,7 @@ def test_class_omexml_attributes(): assert '\n ' in str(omexml) @@ -50,7 +50,7 @@ def test_class_omexml_multiimage(): """Test OmeXml class with multiple images.""" omexml = OmeXml(description='multiimage') -@@ -4636,7 +4641,7 @@ def test_func_pformat_xml(): +@@ -4649,7 +4654,7 @@ def test_func_pformat_xml(): ) assert pformat(value, height=8, width=60, linewidth=None) == ( @@ -59,7 +59,7 @@ DIMAP -@@ -5040,6 +5045,7 @@ def assert_filehandle(fh, offset=0): +@@ -5053,6 +5058,7 @@ def assert_filehandle(fh, offset=0): @pytest.mark.skipif(SKIP_HTTP, reason=REASON) @@ -67,7 +67,7 @@ def test_filehandle_seekable(): """Test FileHandle must be seekable.""" from urllib.request import HTTPHandler, build_opener -@@ -13016,6 +13022,7 @@ def test_write_codecs(mode, tile, codec): +@@ -13029,6 +13035,7 @@ def test_write_codecs(mode, tile, codec): 'dtype', ['u1', 'u2', 'u4', 'i1', 'i2', 'i4', 'f2', 'f4', 'f8'] ) @pytest.mark.parametrize('byteorder', ['>', '<']) @@ -75,7 +75,7 @@ def test_write_predictor(byteorder, dtype, tile, mode): """Test predictors.""" if dtype[0] == 'f' and SKIP_CODECS: -@@ -17512,6 +17519,7 @@ def test_write_imagej_raw(): +@@ -17525,6 +17532,7 @@ def test_write_imagej_raw(): ((2, 3, 4, 5, 6, 7, 33, 31, 3), 'TQCPZRYXS'), ], ) @@ -83,7 +83,7 @@ def test_write_ome(shape, axes): """Test write OME-TIFF format.""" photometric = None -@@ -17703,6 +17711,7 @@ def test_write_ome_methods(method): +@@ -17716,6 +17724,7 @@ def test_write_ome_methods(method): @pytest.mark.parametrize('contiguous', [True, False]) diff -Nru tifffile-20230710/debian/patches/Don-t-install-lsm2bin.patch tifffile-20230718/debian/patches/Don-t-install-lsm2bin.patch --- tifffile-20230710/debian/patches/Don-t-install-lsm2bin.patch 2023-07-12 12:59:47.000000000 +0000 +++ tifffile-20230718/debian/patches/Don-t-install-lsm2bin.patch 2023-07-25 08:14:40.000000000 +0000 @@ -8,7 +8,7 @@ 1 file changed, 3 deletions(-) diff --git a/setup.py b/setup.py -index ea4e8cf..f78e562 100644 +index 931e36c..255f0f7 100644 --- a/setup.py +++ b/setup.py @@ -116,9 +116,6 @@ setup( diff -Nru tifffile-20230710/debian/patches/Skip-large-tests.patch tifffile-20230718/debian/patches/Skip-large-tests.patch --- tifffile-20230710/debian/patches/Skip-large-tests.patch 2023-07-12 12:59:47.000000000 +0000 +++ tifffile-20230718/debian/patches/Skip-large-tests.patch 2023-07-25 08:14:40.000000000 +0000 @@ -7,7 +7,7 @@ 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_tifffile.py b/tests/test_tifffile.py -index 88e0c84..3238143 100644 +index d9bbe28..aade541 100644 --- a/tests/test_tifffile.py +++ b/tests/test_tifffile.py @@ -205,7 +205,7 @@ def skip(key, default): diff -Nru tifffile-20230710/debian/patches/xfail-tests-that-may-require-the-imagecodecs-package.patch tifffile-20230718/debian/patches/xfail-tests-that-may-require-the-imagecodecs-package.patch --- tifffile-20230710/debian/patches/xfail-tests-that-may-require-the-imagecodecs-package.patch 2023-07-12 12:59:47.000000000 +0000 +++ tifffile-20230718/debian/patches/xfail-tests-that-may-require-the-imagecodecs-package.patch 2023-07-25 08:14:40.000000000 +0000 @@ -8,10 +8,10 @@ 1 file changed, 2 insertions(+) diff --git a/tests/test_tifffile.py b/tests/test_tifffile.py -index 3b055b1..88e0c84 100644 +index 6716200..d9bbe28 100644 --- a/tests/test_tifffile.py +++ b/tests/test_tifffile.py -@@ -4821,6 +4821,8 @@ def test_func_bitorder_decode(): +@@ -4834,6 +4834,8 @@ def test_func_bitorder_decode(): def test_func_delta_codec(byteorder, kind): """Test delta codec functions.""" from tifffile._imagecodecs import delta_decode, delta_encode diff -Nru tifffile-20230710/PKG-INFO tifffile-20230718/PKG-INFO --- tifffile-20230710/PKG-INFO 2023-07-10 23:26:08.143567000 +0000 +++ tifffile-20230718/PKG-INFO 2023-07-19 19:18:41.139704200 +0000 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: tifffile -Version: 2023.7.10 +Version: 2023.7.18 Summary: Read and write TIFF files Home-page: https://www.cgohlke.com Author: Christoph Gohlke @@ -19,7 +19,7 @@ Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 Classifier: Programming Language :: Python :: 3.12 -Requires-Python: >=3.8 +Requires-Python: >=3.9 Description-Content-Type: text/x-rst Provides-Extra: all License-File: LICENSE @@ -56,7 +56,7 @@ :Author: `Christoph Gohlke `_ :License: BSD 3-Clause -:Version: 2023.7.10 +:Version: 2023.7.18 :DOI: `10.5281/zenodo.6795860 `_ Quickstart @@ -92,7 +92,7 @@ This revision was tested with the following requirements and dependencies (other versions may work): -- `CPython `_ 3.9.13, 3.10.11, 3.11.4, 3.12.0b3, 64-bit +- `CPython `_ 3.9.13, 3.10.11, 3.11.4, 3.12.0b4, 64-bit - `NumPy `_ 1.25.0 - `Imagecodecs `_ 2023.7.10 (required for encoding or decoding LZW, JPEG, etc. compressed segments) @@ -108,6 +108,12 @@ Revisions --------- +2023.7.18 + +- Pass 4993 tests. +- Limit threading via TIFFFILE_NUM_THREADS environment variable (#215). +- Remove maxworkers parameter from tiff2fsspec (breaking). + 2023.7.10 - Increase default strip size to 256 KB when writing with compression. @@ -115,7 +121,6 @@ 2023.7.4 -- Pass 4992 tests. - Add option to return selection from imread (#200). - Fix reading OME series with missing trailing frames (#199). - Fix fsspec reference for WebP compressed segments missing alpha channel. @@ -644,8 +649,9 @@ ... ) Write a multi-dimensional, multi-resolution (pyramidal), multi-series OME-TIFF -file with metadata. Sub-resolution images are written to SubIFDs. Write a -thumbnail image as a separate image series: +file with metadata. Sub-resolution images are written to SubIFDs. Limit +parallel encoding to 2 threads. Write a thumbnail image as a separate image +series: >>> data = numpy.random.randint(0, 255, (8, 2, 512, 512, 3), 'uint8') >>> subresolutions = 2 @@ -667,7 +673,8 @@ ... photometric='rgb', ... tile=(128, 128), ... compression='jpeg', -... resolutionunit='CENTIMETER' +... resolutionunit='CENTIMETER', +... maxworkers=2 ... ) ... tif.write( ... data, @@ -770,11 +777,14 @@ >>> z[3, 100:200, 200:300:2] = 1024 >>> store.close() -Read images from a sequence of TIFF files as NumPy array: +Read images from a sequence of TIFF files as NumPy array using two I/O worker +threads: >>> imwrite('temp_C001T001.tif', numpy.random.rand(64, 64)) >>> imwrite('temp_C001T002.tif', numpy.random.rand(64, 64)) ->>> image_sequence = imread(['temp_C001T001.tif', 'temp_C001T002.tif']) +>>> image_sequence = imread( +... ['temp_C001T001.tif', 'temp_C001T002.tif'], ioworkers=2, maxworkers=1 +... ) >>> image_sequence.shape (2, 64, 64) >>> image_sequence.dtype diff -Nru tifffile-20230710/README.rst tifffile-20230718/README.rst --- tifffile-20230710/README.rst 2023-07-10 23:26:02.000000000 +0000 +++ tifffile-20230718/README.rst 2023-07-19 19:18:36.000000000 +0000 @@ -30,7 +30,7 @@ :Author: `Christoph Gohlke `_ :License: BSD 3-Clause -:Version: 2023.7.10 +:Version: 2023.7.18 :DOI: `10.5281/zenodo.6795860 `_ Quickstart @@ -66,7 +66,7 @@ This revision was tested with the following requirements and dependencies (other versions may work): -- `CPython `_ 3.9.13, 3.10.11, 3.11.4, 3.12.0b3, 64-bit +- `CPython `_ 3.9.13, 3.10.11, 3.11.4, 3.12.0b4, 64-bit - `NumPy `_ 1.25.0 - `Imagecodecs `_ 2023.7.10 (required for encoding or decoding LZW, JPEG, etc. compressed segments) @@ -82,6 +82,12 @@ Revisions --------- +2023.7.18 + +- Pass 4993 tests. +- Limit threading via TIFFFILE_NUM_THREADS environment variable (#215). +- Remove maxworkers parameter from tiff2fsspec (breaking). + 2023.7.10 - Increase default strip size to 256 KB when writing with compression. @@ -89,7 +95,6 @@ 2023.7.4 -- Pass 4992 tests. - Add option to return selection from imread (#200). - Fix reading OME series with missing trailing frames (#199). - Fix fsspec reference for WebP compressed segments missing alpha channel. @@ -618,8 +623,9 @@ ... ) Write a multi-dimensional, multi-resolution (pyramidal), multi-series OME-TIFF -file with metadata. Sub-resolution images are written to SubIFDs. Write a -thumbnail image as a separate image series: +file with metadata. Sub-resolution images are written to SubIFDs. Limit +parallel encoding to 2 threads. Write a thumbnail image as a separate image +series: >>> data = numpy.random.randint(0, 255, (8, 2, 512, 512, 3), 'uint8') >>> subresolutions = 2 @@ -641,7 +647,8 @@ ... photometric='rgb', ... tile=(128, 128), ... compression='jpeg', -... resolutionunit='CENTIMETER' +... resolutionunit='CENTIMETER', +... maxworkers=2 ... ) ... tif.write( ... data, @@ -744,11 +751,14 @@ >>> z[3, 100:200, 200:300:2] = 1024 >>> store.close() -Read images from a sequence of TIFF files as NumPy array: +Read images from a sequence of TIFF files as NumPy array using two I/O worker +threads: >>> imwrite('temp_C001T001.tif', numpy.random.rand(64, 64)) >>> imwrite('temp_C001T002.tif', numpy.random.rand(64, 64)) ->>> image_sequence = imread(['temp_C001T001.tif', 'temp_C001T002.tif']) +>>> image_sequence = imread( +... ['temp_C001T001.tif', 'temp_C001T002.tif'], ioworkers=2, maxworkers=1 +... ) >>> image_sequence.shape (2, 64, 64) >>> image_sequence.dtype diff -Nru tifffile-20230710/setup.py tifffile-20230718/setup.py --- tifffile-20230710/setup.py 2023-07-10 22:54:55.000000000 +0000 +++ tifffile-20230718/setup.py 2023-07-19 18:28:42.000000000 +0000 @@ -82,7 +82,7 @@ # 'Documentation': 'https://', }, packages=['tifffile'], - python_requires='>=3.8', + python_requires='>=3.9', install_requires=[ 'numpy', # 'imagecodecs>=2023.1.23', diff -Nru tifffile-20230710/tests/test_tifffile.py tifffile-20230718/tests/test_tifffile.py --- tifffile-20230710/tests/test_tifffile.py 2023-07-10 23:24:28.000000000 +0000 +++ tifffile-20230718/tests/test_tifffile.py 2023-07-19 18:40:13.000000000 +0000 @@ -37,7 +37,7 @@ Public data files can be requested from the author. Private data files are not available due to size and copyright restrictions. -:Version: 2023.7.10 +:Version: 2023.7.18 """ @@ -2623,6 +2623,19 @@ assert__str__(tif) +def test_issue_maxworkers(): + """Test maxworkers defaults.""" + if 'TIFFFILE_NUM_THREADS' in os.environ: + assert TIFF.MAXWORKERS == int(os.environ['TIFFFILE_NUM_THREADS']) + else: + assert TIFF.MAXWORKERS == max(1, os.cpu_count() // 2) + + if 'TIFFFILE_NUM_IOTHREADS' in os.environ: + assert TIFF.MAXIOWORKERS == int(os.environ['TIFFFILE_NUM_IOTHREADS']) + else: + assert TIFF.MAXIOWORKERS == os.cpu_count() * 5 + + class TestExceptions: """Test various Exceptions and Warnings.""" diff -Nru tifffile-20230710/tifffile/tifffile.py tifffile-20230718/tifffile/tifffile.py --- tifffile-20230710/tifffile/tifffile.py 2023-07-10 22:56:11.000000000 +0000 +++ tifffile-20230718/tifffile/tifffile.py 2023-07-19 19:16:58.000000000 +0000 @@ -60,7 +60,7 @@ :Author: `Christoph Gohlke `_ :License: BSD 3-Clause -:Version: 2023.7.10 +:Version: 2023.7.18 :DOI: `10.5281/zenodo.6795860 `_ Quickstart @@ -96,7 +96,7 @@ This revision was tested with the following requirements and dependencies (other versions may work): -- `CPython `_ 3.9.13, 3.10.11, 3.11.4, 3.12.0b3, 64-bit +- `CPython `_ 3.9.13, 3.10.11, 3.11.4, 3.12.0b4, 64-bit - `NumPy `_ 1.25.0 - `Imagecodecs `_ 2023.7.10 (required for encoding or decoding LZW, JPEG, etc. compressed segments) @@ -112,6 +112,12 @@ Revisions --------- +2023.7.18 + +- Pass 4993 tests. +- Limit threading via TIFFFILE_NUM_THREADS environment variable (#215). +- Remove maxworkers parameter from tiff2fsspec (breaking). + 2023.7.10 - Increase default strip size to 256 KB when writing with compression. @@ -119,7 +125,6 @@ 2023.7.4 -- Pass 4992 tests. - Add option to return selection from imread (#200). - Fix reading OME series with missing trailing frames (#199). - Fix fsspec reference for WebP compressed segments missing alpha channel. @@ -648,8 +653,9 @@ ... ) Write a multi-dimensional, multi-resolution (pyramidal), multi-series OME-TIFF -file with metadata. Sub-resolution images are written to SubIFDs. Write a -thumbnail image as a separate image series: +file with metadata. Sub-resolution images are written to SubIFDs. Limit +parallel encoding to 2 threads. Write a thumbnail image as a separate image +series: >>> data = numpy.random.randint(0, 255, (8, 2, 512, 512, 3), 'uint8') >>> subresolutions = 2 @@ -671,7 +677,8 @@ ... photometric='rgb', ... tile=(128, 128), ... compression='jpeg', -... resolutionunit='CENTIMETER' +... resolutionunit='CENTIMETER', +... maxworkers=2 ... ) ... tif.write( ... data, @@ -774,11 +781,14 @@ >>> z[3, 100:200, 200:300:2] = 1024 >>> store.close() -Read images from a sequence of TIFF files as NumPy array: +Read images from a sequence of TIFF files as NumPy array using two I/O worker +threads: >>> imwrite('temp_C001T001.tif', numpy.random.rand(64, 64)) >>> imwrite('temp_C001T002.tif', numpy.random.rand(64, 64)) ->>> image_sequence = imread(['temp_C001T001.tif', 'temp_C001T002.tif']) +>>> image_sequence = imread( +... ['temp_C001T001.tif', 'temp_C001T002.tif'], ioworkers=2, maxworkers=1 +... ) >>> image_sequence.shape (2, 64, 64) >>> image_sequence.dtype @@ -826,7 +836,7 @@ from __future__ import annotations -__version__ = '2023.7.10' +__version__ = '2023.7.18' __all__ = [ 'TiffFile', @@ -1003,7 +1013,7 @@ chunkshape: tuple[int, ...] | None = None, dtype: DTypeLike | None = None, axestiled: dict[int, int] | Sequence[tuple[int, int]] | None = None, - ioworkers: int = 1, + ioworkers: int | None = 1, chunkmode: CHUNKMODE | int | str | None = None, fillvalue: int | float | None = None, zattrs: dict[str, Any] | None = None, @@ -1908,10 +1918,8 @@ maxworkers: Maximum number of threads to concurrently compress tiles or strips. - If *1*, multi-threading is disabled. - By default, multithreading is disabled for small segments - <8 KB and PackBits compression. Else, up to half the CPU - cores are used. + If *None* or *0*, use up to :py:attr:`_TIFF.MAXWORKERS` CPU + cores for compressing large segments. Using multiple threads can significantly speed up this function if the bottleneck is encoding the data, for example, in case of large JPEG compressed tiles. @@ -1951,6 +1959,8 @@ compressiontag: int compressionfunc: Callable[..., Any] | None = None tags: list[tuple[int, bytes, bytes | None, bool]] + numtiles: int + numstrips: int fh = self._fh byteorder = self.tiff.byteorder @@ -4224,9 +4234,8 @@ maxworkers: Maximum number of threads to concurrently decode data from multiple pages or compressed segments. - By default, up to half the CPU cores are used. - If *1*, multi-threading is disabled. - Reading data from file is limited to a single thread. + If *None* or *0*, use up to :py:attr:`_TIFF.MAXWORKERS` + threads. Reading data from file is limited to the main thread. Using multiple threads can significantly speed up this function if the bottleneck is decoding compressed data, for example, in case of large LZW compressed LSM files or @@ -8825,8 +8834,8 @@ The default is the lock of the parent's file handle. maxworkers: Maximum number of threads to concurrently decode segments. - By default, up to half the CPU cores are used. - See remarks in :py:meth:`TiffFile.asarray`. + If *None* or *0*, use up to :py:attr:`_TIFF.MAXWORKERS` + threads. See remarks in :py:meth:`TiffFile.asarray`. Returns: NumPy array of decompressed, unpredicted, and unpacked image data @@ -12320,7 +12329,8 @@ Remove length-1 dimensions from shape of TiffPageSeries. maxworkers: Maximum number of threads to concurrently decode strips or tiles - if `chunkmode=2`. By default, up to half the CPU cores are used. + if `chunkmode=2`. + If *None* or *0*, use up to :py:attr:`_TIFF.MAXWORKERS` threads. _openfiles: Internal API. @@ -13512,7 +13522,7 @@ dtype: DTypeLike | None = None, axestiled: dict[int, int] | Sequence[tuple[int, int]] | None = None, out_inplace: bool | None = None, - ioworkers: int = 1, + ioworkers: int | None = 1, out: OutputType = None, **kwargs: Any, ) -> NDArray[Any]: @@ -13533,8 +13543,7 @@ ioworkers: Maximum number of threads to execute :py:attr:`FileSequence.imread` asynchronously. - If *None*, default to the number of processors multiplied - by 5. + If *0*, use up to :py:attr:`_TIFF.MAXIOWORKERS` threads. Using threads can significantly improve runtime when reading many small files from a network share. out_inplace: @@ -13558,12 +13567,10 @@ IndexError, ValueError: Array shapes do not match. """ - if len(self.files) < 2: - ioworkers = 1 - elif ioworkers is None or ioworkers < 1: - import multiprocessing - - ioworkers = max(multiprocessing.cpu_count() * 5, 1) + if ioworkers is None or ioworkers < 1: + ioworkers = TIFF.MAXIOWORKERS + ioworkers = min(len(self.files), ioworkers) + assert isinstance(ioworkers, int) # mypy bug? if out_inplace is None and self.imread == imread: out_inplace = True @@ -18757,10 +18764,29 @@ @cached_property def MAXWORKERS(self) -> int: - # half of CPU cores - import multiprocessing + """Default maximum number of threads for de/compressing segments. + + The value of the ``TIFFFILE_NUM_THREADS`` environment variable if set, + else half the CPU cores. + + """ + if 'TIFFFILE_NUM_THREADS' in os.environ: + return max(1, int(os.environ['TIFFFILE_NUM_THREADS'])) + cpu_count = os.cpu_count() + return max(1, cpu_count // 2) if cpu_count is not None else 1 + + @cached_property + def MAXIOWORKERS(self) -> int: + """Default maximum number of I/O threads for reading file sequences. + + The value of the ``TIFFFILE_NUM_IOTHREADS`` environment variable if + set, else five times the CPU cores. - return max(multiprocessing.cpu_count() // 2, 1) + """ + if 'TIFFFILE_NUM_IOTHREADS' in os.environ: + return max(1, int(os.environ['TIFFFILE_NUM_IOTHREADS'])) + cpu_count = os.cpu_count() + return max(1, cpu_count * 5) if cpu_count is not None else 1 BUFFERSIZE: int = 268435456 # 256 MB buffer for read and writes @@ -21580,7 +21606,7 @@ encode: Callable[[NDArray[Any]], bytes], shape: Sequence[int], dtype: numpy.dtype[Any], - maxworkers: int, + maxworkers: int | None, buffersize: int | None, /, ) -> Iterator[bytes]: @@ -21662,7 +21688,7 @@ pagedata: NDArray[Any], encode: Callable[[NDArray[Any]], bytes], rowsperstrip: int, - maxworkers: int, + maxworkers: int | None, /, ) -> Iterator[bytes]: """Return iterator over encoded strips.""" @@ -22196,6 +22222,7 @@ Reentrant lock to synchronize seeks and reads from file. maxworkers: Maximum number of threads to concurrently decode pages or segments. + By default, use up to :py:attr:`_TIFF.MAXWORKERS` threads. out: Specifies how image array is returned. By default, a new NumPy array is created. @@ -23666,7 +23693,6 @@ fillvalue: int | float | None = None, zattrs: dict[str, Any] | None = None, squeeze: bool | None = None, - maxworkers: int | None = None, groupname: str | None = None, version: int | None = None, ) -> None: @@ -23682,7 +23708,7 @@ out: Name of output JSON file. The default is the `filename` with a '.json' extension. - key, series, level, chunkmode, fillvalue, zattrs, squeeze, maxworkers: + key, series, level, chunkmode, fillvalue, zattrs, squeeze: Passed to :py:meth:`TiffFile.aszarr`. groupname, version: Passed to :py:meth:`ZarrTiffStore.write_fsspec`. @@ -23700,7 +23726,6 @@ fillvalue=fillvalue, zattrs=zattrs, squeeze=squeeze, - maxworkers=maxworkers, ) as store: store.write_fsspec(out, url, groupname=groupname, version=version) @@ -24266,6 +24291,13 @@ help='colormap name used to map data to colors', ) opt( + '--maxworkers', + dest='maxworkers', + type='int', + default=0, + help='maximum number of threads', + ) + opt( '--debug', dest='debug', action='store_true', @@ -24339,7 +24371,9 @@ if settings.page >= 0: images = [ ( - tif.asarray(key=settings.page), + tif.asarray( + key=settings.page, maxworkers=settings.maxworkers + ), tif.pages[settings.page], None, ) @@ -24358,7 +24392,11 @@ level = 0 images = [ ( - tif.asarray(series=settings.series, level=level), + tif.asarray( + series=settings.series, + level=level, + maxworkers=settings.maxworkers, + ), notnone(tif.series[settings.series]._pages), tif.series[settings.series], ) @@ -24376,7 +24414,11 @@ try: images.append( ( - tif.asarray(series=i, level=level), + tif.asarray( + series=i, + level=level, + maxworkers=settings.maxworkers, + ), notnone(s._pages), tif.series[i], ) diff -Nru tifffile-20230710/tifffile.egg-info/PKG-INFO tifffile-20230718/tifffile.egg-info/PKG-INFO --- tifffile-20230710/tifffile.egg-info/PKG-INFO 2023-07-10 23:26:06.000000000 +0000 +++ tifffile-20230718/tifffile.egg-info/PKG-INFO 2023-07-19 19:18:39.000000000 +0000 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: tifffile -Version: 2023.7.10 +Version: 2023.7.18 Summary: Read and write TIFF files Home-page: https://www.cgohlke.com Author: Christoph Gohlke @@ -19,7 +19,7 @@ Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 Classifier: Programming Language :: Python :: 3.12 -Requires-Python: >=3.8 +Requires-Python: >=3.9 Description-Content-Type: text/x-rst Provides-Extra: all License-File: LICENSE @@ -56,7 +56,7 @@ :Author: `Christoph Gohlke `_ :License: BSD 3-Clause -:Version: 2023.7.10 +:Version: 2023.7.18 :DOI: `10.5281/zenodo.6795860 `_ Quickstart @@ -92,7 +92,7 @@ This revision was tested with the following requirements and dependencies (other versions may work): -- `CPython `_ 3.9.13, 3.10.11, 3.11.4, 3.12.0b3, 64-bit +- `CPython `_ 3.9.13, 3.10.11, 3.11.4, 3.12.0b4, 64-bit - `NumPy `_ 1.25.0 - `Imagecodecs `_ 2023.7.10 (required for encoding or decoding LZW, JPEG, etc. compressed segments) @@ -108,6 +108,12 @@ Revisions --------- +2023.7.18 + +- Pass 4993 tests. +- Limit threading via TIFFFILE_NUM_THREADS environment variable (#215). +- Remove maxworkers parameter from tiff2fsspec (breaking). + 2023.7.10 - Increase default strip size to 256 KB when writing with compression. @@ -115,7 +121,6 @@ 2023.7.4 -- Pass 4992 tests. - Add option to return selection from imread (#200). - Fix reading OME series with missing trailing frames (#199). - Fix fsspec reference for WebP compressed segments missing alpha channel. @@ -644,8 +649,9 @@ ... ) Write a multi-dimensional, multi-resolution (pyramidal), multi-series OME-TIFF -file with metadata. Sub-resolution images are written to SubIFDs. Write a -thumbnail image as a separate image series: +file with metadata. Sub-resolution images are written to SubIFDs. Limit +parallel encoding to 2 threads. Write a thumbnail image as a separate image +series: >>> data = numpy.random.randint(0, 255, (8, 2, 512, 512, 3), 'uint8') >>> subresolutions = 2 @@ -667,7 +673,8 @@ ... photometric='rgb', ... tile=(128, 128), ... compression='jpeg', -... resolutionunit='CENTIMETER' +... resolutionunit='CENTIMETER', +... maxworkers=2 ... ) ... tif.write( ... data, @@ -770,11 +777,14 @@ >>> z[3, 100:200, 200:300:2] = 1024 >>> store.close() -Read images from a sequence of TIFF files as NumPy array: +Read images from a sequence of TIFF files as NumPy array using two I/O worker +threads: >>> imwrite('temp_C001T001.tif', numpy.random.rand(64, 64)) >>> imwrite('temp_C001T002.tif', numpy.random.rand(64, 64)) ->>> image_sequence = imread(['temp_C001T001.tif', 'temp_C001T002.tif']) +>>> image_sequence = imread( +... ['temp_C001T001.tif', 'temp_C001T002.tif'], ioworkers=2, maxworkers=1 +... ) >>> image_sequence.shape (2, 64, 64) >>> image_sequence.dtype