From cf69e8b8b77eaa390934967d092c4435267e699c Mon Sep 17 00:00:00 2001 From: Larry Gritz Date: Sat, 21 Feb 2026 20:56:54 -0800 Subject: [PATCH 1/4] fix(python): Address new pybind11 float/int auto-conversion behavior It's not in any pybind11 tagged release yet, but in its master, a change has been introduced that causes it to allow functions with float paramters to automatically match int arguments. This is fatal for us, as we have set up several cases of methods that overload on int vs float, and with this change, the float one gets called when an int is passed. Pybind11 docs say that the `.noconvert()` modifier on the argument will do the trick, but I'm finding that it doesn't help for overloaded function names. The solution is to find these cases, change our declaration to a generic py::object, and then sort out what type was passed with py::isinstance. It seems to mainly affect `attribute()` style calls. In the process, minor changes to the pybind11 auto-builder allow it to take a git commit hash directly. Also, I took the opportunity to remove a few reference outputs that are no longer needed because they were python2-specific. Meanwhile, just in case anybody had been paying attention, the problem in pybind11 master that had caused us to temporarily stop CI testing against master seems to have been resolved. So re-enable the bleeding edge test to use pybind11 master (which will fail if not for this PR here), and bump the "latest version" tests t the new pybind11 3.0.2. Signed-off-by: Larry Gritz --- .github/workflows/ci.yml | 8 +- src/cmake/build_pybind11.cmake | 1 + src/python/py_imagecache.cpp | 14 +- src/python/py_imagespec.cpp | 6 +- src/python/py_oiio.cpp | 24 +- src/python/py_oiio.h | 18 ++ src/python/py_paramvalue.cpp | 22 +- src/python/py_texturesys.cpp | 14 +- .../python-imagebuf/ref/out-alt-python3.txt | 262 ------------------ testsuite/python-imagebuf/ref/out-alt.txt | 8 +- testsuite/python-imagebuf/ref/out-python3.txt | 262 ------------------ testsuite/python-imagebuf/ref/out.txt | 8 +- .../python-imageinput/ref/out-python3.txt | 210 -------------- testsuite/python-imageinput/ref/out.txt | 38 +-- .../python-imagespec/ref/out-python3.txt | 215 -------------- testsuite/python-imagespec/ref/out.txt | 1 - 16 files changed, 81 insertions(+), 1030 deletions(-) delete mode 100644 testsuite/python-imagebuf/ref/out-alt-python3.txt delete mode 100644 testsuite/python-imagebuf/ref/out-python3.txt delete mode 100644 testsuite/python-imageinput/ref/out-python3.txt delete mode 100644 testsuite/python-imagespec/ref/out-python3.txt diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 94a95efbf7..c7354c1e01 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -439,7 +439,7 @@ jobs: fmt_ver: 12.1.0 opencolorio_ver: v2.5.0 openexr_ver: v3.4.3 - pybind11_ver: v3.0.1 + pybind11_ver: v3.0.2 python_ver: "3.12" simd: avx2,f16c setenvs: export LIBJPEGTURBO_VERSION=3.1.2 @@ -465,7 +465,7 @@ jobs: fmt_ver: master opencolorio_ver: main openexr_ver: main - pybind11_ver: v3.0.1 + pybind11_ver: master python_ver: "3.12" simd: avx2,f16c benchmark: 1 @@ -524,7 +524,7 @@ jobs: fmt_ver: 12.1.0 opencolorio_ver: v2.5.0 openexr_ver: v3.4.3 - pybind11_ver: v3.0.1 + pybind11_ver: v3.0.2 python_ver: "3.12" setenvs: export LIBJPEGTURBO_VERSION=3.1.2 LIBPNG_VERSION=v1.6.50 @@ -545,7 +545,7 @@ jobs: fmt_ver: 12.1.0 opencolorio_ver: v2.5.0 openexr_ver: v3.4.3 - pybind11_ver: v3.0.1 + pybind11_ver: v3.0.2 python_ver: "3.12" setenvs: export LIBJPEGTURBO_VERSION=3.1.2 LIBPNG_VERSION=v1.6.50 diff --git a/src/cmake/build_pybind11.cmake b/src/cmake/build_pybind11.cmake index b6c827f764..526f18c68e 100644 --- a/src/cmake/build_pybind11.cmake +++ b/src/cmake/build_pybind11.cmake @@ -21,6 +21,7 @@ build_dependency_with_cmake(pybind11 VERSION ${pybind11_BUILD_VERSION} GIT_REPOSITORY ${pybind11_GIT_REPOSITORY} GIT_TAG ${pybind11_GIT_TAG} + GIT_COMMIT ${pybind11_GIT_COMMIT} CMAKE_ARGS -D PYBIND11_PYTHON_VERSION=${PYTHON3_VERSION} # Don't built unnecessary parts of Pybind11 diff --git a/src/python/py_imagecache.cpp b/src/python/py_imagecache.cpp index ba3e9258b8..706f2597e9 100644 --- a/src/python/py_imagecache.cpp +++ b/src/python/py_imagecache.cpp @@ -80,21 +80,11 @@ declare_imagecache(py::module& m) .def_static("destroy", &ImageCacheWrap::destroy, "cache"_a, "teardown"_a = false) - .def("attribute", - [](ImageCacheWrap& ic, const std::string& name, float val) { - if (ic.m_cache) - ic.m_cache->attribute(name, val); - }) - .def("attribute", - [](ImageCacheWrap& ic, const std::string& name, int val) { - if (ic.m_cache) - ic.m_cache->attribute(name, val); - }) .def("attribute", [](ImageCacheWrap& ic, const std::string& name, - const std::string& val) { + const py::object& obj) { if (ic.m_cache) - ic.m_cache->attribute(name, val); + attribute_onearg(*ic.m_cache, name, obj); }) .def("attribute", [](ImageCacheWrap& ic, const std::string& name, TypeDesc type, diff --git a/src/python/py_imagespec.cpp b/src/python/py_imagespec.cpp index 05eadc3f93..64a637fd9d 100644 --- a/src/python/py_imagespec.cpp +++ b/src/python/py_imagespec.cpp @@ -175,13 +175,9 @@ declare_imagespec(py::module& m) // For now, do not expose auto_stride. It's not obvious that // anybody will want to do pointer work and strides from Python. - .def("attribute", [](ImageSpec& spec, const std::string& name, - float val) { spec.attribute(name, val); }) - .def("attribute", [](ImageSpec& spec, const std::string& name, - int val) { spec.attribute(name, val); }) .def("attribute", [](ImageSpec& spec, const std::string& name, - const std::string& val) { spec.attribute(name, val); }) + const py::object& obj) { attribute_onearg(spec, name, obj); }) .def("attribute", [](ImageSpec& spec, const std::string& name, TypeDesc type, const py::object& obj) { diff --git a/src/python/py_oiio.cpp b/src/python/py_oiio.cpp index f906f7dc1a..8ba16fa27e 100644 --- a/src/python/py_oiio.cpp +++ b/src/python/py_oiio.cpp @@ -249,12 +249,24 @@ oiio_getattribute_typed(const std::string& name, TypeDesc type = TypeUnknown) } -// Wrapper to let attribute_typed work for global attributes. +// Wrapper to let attribute_typed/attribute_onearg work for global attributes. struct oiio_global_attrib_wrapper { bool attribute(string_view name, TypeDesc type, const void* data) { return OIIO::attribute(name, type, data); } + bool attribute(string_view name, int val) + { + return OIIO::attribute(name, val); + } + bool attribute(string_view name, float val) + { + return OIIO::attribute(name, val); + } + bool attribute(string_view name, const std::string& val) + { + return OIIO::attribute(name, val); + } }; @@ -297,13 +309,9 @@ OIIO_DECLARE_PYMODULE(PYMODULE_NAME) // Global (OpenImageIO scope) functions and symbols m.def("geterror", &OIIO::geterror, "clear"_a = true); - m.def("attribute", [](const std::string& name, float val) { - OIIO::attribute(name, val); - }); - m.def("attribute", - [](const std::string& name, int val) { OIIO::attribute(name, val); }); - m.def("attribute", [](const std::string& name, const std::string& val) { - OIIO::attribute(name, val); + m.def("attribute", [](const std::string& name, const py::object& obj) { + oiio_global_attrib_wrapper wrapper; + attribute_onearg(wrapper, name, obj); }); m.def("attribute", [](const std::string& name, TypeDesc type, const py::object& obj) { diff --git a/src/python/py_oiio.h b/src/python/py_oiio.h index ddd6aba743..27d15f48a1 100644 --- a/src/python/py_oiio.h +++ b/src/python/py_oiio.h @@ -509,6 +509,24 @@ attribute_typed(T& myobj, string_view name, TypeDesc type, const POBJ& dataobj) +// Dispatch a single-value attribute() call based on the type of the +// Python object (int, float, or string). +template +inline void +attribute_onearg(T& myobj, string_view name, const py::object& obj) +{ + if (py::isinstance(obj)) + myobj.attribute(name, float(obj.template cast())); + else if (py::isinstance(obj)) + myobj.attribute(name, int(obj.template cast())); + else if (py::isinstance(obj)) + myobj.attribute(name, std::string(obj.template cast())); + else + throw std::invalid_argument("Bad type for attribute"); +} + + + // `data` points to values of `type`. Make a python object that represents // them. py::object diff --git a/src/python/py_paramvalue.cpp b/src/python/py_paramvalue.cpp index 98e6b01f75..945dbf3984 100644 --- a/src/python/py_paramvalue.cpp +++ b/src/python/py_paramvalue.cpp @@ -79,6 +79,15 @@ ParamValue_from_pyobject(string_view name, TypeDesc type, int nvalues, +void +ParamValueList_attribute_onearg(ParamValueList& self, const std::string& name, + const py::object& obj) +{ + attribute_onearg(self, name, obj); +} + + + // Based on attribute_typed in py_oiio.h, but with nvalues. template bool @@ -240,18 +249,7 @@ declare_paramvalue(py::module& m) "value"_a, "casesensitive"_a = true) .def("sort", &ParamValueList::sort, "casesensitive"_a = true) .def("merge", &ParamValueList::merge, "other"_a, "override"_a = false) - .def("attribute", - [](ParamValueList& self, const std::string& name, float val) { - self.attribute(name, TypeFloat, &val); - }) - .def("attribute", [](ParamValueList& self, const std::string& name, - int val) { self.attribute(name, TypeInt, &val); }) - .def("attribute", - [](ParamValueList& self, const std::string& name, - const std::string& val) { - const char* s = val.c_str(); - self.attribute(name, TypeString, &s); - }) + .def("attribute", ParamValueList_attribute_onearg, "name"_a, "val"_a) .def("attribute", [](ParamValueList& self, const std::string& name, TypeDesc type, const py::object& obj) { diff --git a/src/python/py_texturesys.cpp b/src/python/py_texturesys.cpp index c81965ce34..d80b48bbe2 100644 --- a/src/python/py_texturesys.cpp +++ b/src/python/py_texturesys.cpp @@ -177,21 +177,11 @@ declare_texturesystem(py::module& m) .def(py::init(), "shared"_a = true) .def_static("destroy", &TextureSystemWrap::destroy) - .def("attribute", - [](TextureSystemWrap& ts, const std::string& name, float val) { - if (ts.m_texsys) - ts.m_texsys->attribute(name, val); - }) - .def("attribute", - [](TextureSystemWrap& ts, const std::string& name, int val) { - if (ts.m_texsys) - ts.m_texsys->attribute(name, val); - }) .def("attribute", [](TextureSystemWrap& ts, const std::string& name, - const std::string& val) { + const py::object& obj) { if (ts.m_texsys) - ts.m_texsys->attribute(name, val); + attribute_onearg(*ts.m_texsys, name, obj); }) .def("attribute", [](TextureSystemWrap& ts, const std::string& name, TypeDesc type, diff --git a/testsuite/python-imagebuf/ref/out-alt-python3.txt b/testsuite/python-imagebuf/ref/out-alt-python3.txt deleted file mode 100644 index cb2f545958..0000000000 --- a/testsuite/python-imagebuf/ref/out-alt-python3.txt +++ /dev/null @@ -1,262 +0,0 @@ -Constructing to be a writable 320x240,4 UINT16: - resolution 320x240+0+0 - untiled - 4 channels: ('R', 'G', 'B', 'A') - format = uint16 - alpha channel = 3 - z channel = -1 - deep = False -Resetting to be a writable 640x480,3 Float: - resolution 640x480+0+0 - untiled - 3 channels: ('R', 'G', 'B') - format = float - alpha channel = -1 - z channel = -1 - deep = False -Constructing from a bare numpy array: - from 3D, shape is float 0 2 0 3 0 1 0 4 - resolution 2x3+0+0 - untiled - 4 channels: ('R', 'G', 'B', 'A') - format = float - alpha channel = 3 - z channel = -1 - deep = False - pixel (0,1) = 0.3 0 0.8 1 - - from 2D uint8, shape is uint8 0 2 0 3 0 1 0 1 - - from 4D, shape is float 0 2 0 2 0 2 0 4 - -Testing read of ../common/textures/grid.tx: -channels: 4 -name: ../common/textures/grid.tx -file_format_name: tiff -deep: False -orientation: 1 -oriented x,y,width,height: 0 0 1024 1024 -oriented full x,y,width,height: 0 0 1024 1024 -xyz beg/end: 0 1024 0 1024 0 1 -xyz min/max: 0 1023 0 1023 0 0 -setting full res... -roi = 0 1024 0 1024 0 1 0 4 -full roi = 0 2048 0 2048 0 1 0 4 -setting full roi again, as ROI... -Changing origin... -Printing the whole spec to be sure: - resolution 1024x1024+15+20 - tile size 64x64x1 - 4 channels: ('R', 'G', 'B', 'A') - format = uint8 - alpha channel = 3 - z channel = -1 - deep = False - oiio:BitsPerSample = 8 - Orientation = 1 - XResolution = 72.0 - YResolution = 72.0 - ResolutionUnit = "in" - Software = "OpenImageIO 1.5.7dev : maketx -filter lanczos3 --resize grid.tif -o grid.tx" - DateTime = "2014:11:29 23:20:23" - DocumentName = "g.tif" - textureformat = "Plain Texture" - wrapmodes = "black,black" - fovcot = 1.0 - tiff:Compression = 8 - tiff:PhotometricInterpretation = 2 - tiff:PlanarConfiguration = 1 - planarconfig = "contig" - compression = "zip" - PixelAspectRatio = 1.0 - oiio:AverageColor = "0.608983,0.608434,0.608728,1" - oiio:SHA-1 = "233A1D3412A54A5F49814AB7BFFD04F56F46D3D7" - -Resetting to a different MIP level: - resolution 256x256+0+0 - tile size 64x64x1 - 4 channels: ('R', 'G', 'B', 'A') - format = uint8 - alpha channel = 3 - z channel = -1 - deep = False - oiio:BitsPerSample = 8 - Orientation = 1 - XResolution = 72.0 - YResolution = 72.0 - ResolutionUnit = "in" - Software = "OpenImageIO 1.5.7dev : maketx -filter lanczos3 --resize grid.tif -o grid.tx" - DateTime = "2014:11:29 23:20:23" - DocumentName = "g.tif" - textureformat = "Plain Texture" - wrapmodes = "black,black" - fovcot = 1.0 - tiff:Compression = 8 - tiff:PhotometricInterpretation = 2 - tiff:PlanarConfiguration = 1 - planarconfig = "contig" - compression = "zip" - PixelAspectRatio = 1.0 - oiio:AverageColor = "0.608983,0.608434,0.608728,1" - oiio:SHA-1 = "233A1D3412A54A5F49814AB7BFFD04F56F46D3D7" - -Making 2x2 RGB image: - resolution 2x2+0+0 - untiled - 3 channels: ('R', 'G', 'B') - format = uint8 - alpha channel = -1 - z channel = -1 - deep = False -Pixel 0,0 is (1.0, 0.0, 0.0) -Pixel 1,0 is (0.0, 1.0, 0.0) -Pixel 0,1 is (0.0, 0.0, 1.0) -Interpolating 1,0.5 -> (0.5, 0.5, 0.0) -Interpolating NDC 0.25,0.5 -> (0.5, 0.0, 0.5) -Interpolating bicubic 0.25,0.5 -> (0.31944, 0.31944, 0.079861) -Interpolating NDC bicubic 0.25,0.5 -> (0.31944, 0.079861, 0.31944) -The whole image is: [[[1. 0. 0.] - [0. 1. 0.]] - - [[0. 0. 1.] - [0. 0. 0.]]] - -Saving file... - -Writing deep buffer... - -Reading back deep buffer: -Pixel 0 1 had 3 samples -Sample 0 - c 0 : 0.420 - c 1 : 0.000 - c 2 : 0.000 - c 3 : 0.000 - c 4 : 42.000 -Sample 1 - c 0 : 0.100 - c 1 : 0.200 - c 2 : 0.300 - c 3 : 42.500 - c 4 : 0.000 -Sample 2 - c 0 : 0.470 - c 1 : 0.000 - c 2 : 0.000 - c 3 : 0.000 - c 4 : 43.000 -Writing multi-image file -Testing uninitialized bufs - empty nchannels: 0 - -Testing metadata copying - A's spec - resolution 64x64+0+0 - untiled - 3 channels: ('R', 'G', 'B') - format = uint8 - alpha channel = -1 - z channel = -1 - deep = False - abc = 1 - def = 3.140000104904175 - B's spec - resolution 64x64+0+0 - untiled - 3 channels: ('R', 'G', 'B') - format = uint8 - alpha channel = -1 - z channel = -1 - deep = False - def = "Bfoo" - camera:x = "Bx" - camera:y = "By" - A full copy of A should have abc and def as A does: - result of C = A.copy(): - resolution 64x64+0+0 - untiled - 3 channels: ('R', 'G', 'B') - format = uint8 - alpha channel = -1 - z channel = -1 - deep = False - abc = 1 - def = 3.140000104904175 - A.copy_metadata(B) should be identical to B - result of A.copy_metadata(B): - resolution 64x64+0+0 - untiled - 3 channels: ('R', 'G', 'B') - format = uint8 - alpha channel = -1 - z channel = -1 - deep = False - def = "Bfoo" - camera:x = "Bx" - camera:y = "By" - A.merge_metadata(B) should have abc, def from A, camera from B - result of A.merge_metadata(B): - resolution 64x64+0+0 - untiled - 3 channels: ('R', 'G', 'B') - format = uint8 - alpha channel = -1 - z channel = -1 - deep = False - abc = 1 - def = 3.140000104904175 - camera:x = "Bx" - camera:y = "By" - A.merge_metadata(B,True) should have abc from A, def and camera from B - result of A.merge_metadata(B, override=True): - resolution 64x64+0+0 - untiled - 3 channels: ('R', 'G', 'B') - format = uint8 - alpha channel = -1 - z channel = -1 - deep = False - abc = 1 - def = "Bfoo" - camera:x = "Bx" - camera:y = "By" - A.merge_metadata(B,pattern) should have abc,def from A, camera from B - result of A.merge_metadata(B, pattern='^camera:'): - resolution 64x64+0+0 - untiled - 3 channels: ('R', 'G', 'B') - format = uint8 - alpha channel = -1 - z channel = -1 - deep = False - abc = 1 - def = 3.140000104904175 - camera:x = "Bx" - camera:y = "By" - -Testing error handling for out-of-range subimage, miplevel - bayer.png subimage 1 mip 0: False Could not seek to subimage=1 miplevel=0 - bayer.png subimage 0 mip 0: True - bayer.png subimage 0 mip 1: False Could not seek to subimage=0 miplevel=1 - grid-small.exr subimage 1 mip 0: False Could not seek to subimage=1 miplevel=0 - grid-small.exr subimage 0 mip 0: True - grid-small.exr subimage 0 mip 1: False Could not seek to subimage=0 miplevel=1 - tahoe-tiny.tif subimage 1 mip 0: False Error reading: could not seek to subimage 1 - tahoe-tiny.tif subimage 0 mip 0: True - tahoe-tiny.tif subimage 0 mip 1: False Could not seek to subimage=0 miplevel=1 - -Done. -Comparing "out.tif" and "ref/out.tif" -PASS -Comparing "outtuple.tif" and "ref/outtuple.tif" -PASS -Comparing "outarray.tif" and "ref/outarray.tif" -PASS -Comparing "outarrayB.tif" and "ref/outarrayB.tif" -PASS -Comparing "outarrayH.tif" and "ref/outarrayH.tif" -PASS -Comparing "perchan.exr" and "ref/perchan.exr" -PASS -Comparing "multipart.exr" and "ref/multipart.exr" -PASS diff --git a/testsuite/python-imagebuf/ref/out-alt.txt b/testsuite/python-imagebuf/ref/out-alt.txt index de8a31b16b..cb2f545958 100644 --- a/testsuite/python-imagebuf/ref/out-alt.txt +++ b/testsuite/python-imagebuf/ref/out-alt.txt @@ -115,11 +115,11 @@ Interpolating 1,0.5 -> (0.5, 0.5, 0.0) Interpolating NDC 0.25,0.5 -> (0.5, 0.0, 0.5) Interpolating bicubic 0.25,0.5 -> (0.31944, 0.31944, 0.079861) Interpolating NDC bicubic 0.25,0.5 -> (0.31944, 0.079861, 0.31944) -The whole image is: [[[ 1. 0. 0.] - [ 0. 1. 0.]] +The whole image is: [[[1. 0. 0.] + [0. 1. 0.]] - [[ 0. 0. 1.] - [ 0. 0. 0.]]] + [[0. 0. 1.] + [0. 0. 0.]]] Saving file... diff --git a/testsuite/python-imagebuf/ref/out-python3.txt b/testsuite/python-imagebuf/ref/out-python3.txt deleted file mode 100644 index cb2f545958..0000000000 --- a/testsuite/python-imagebuf/ref/out-python3.txt +++ /dev/null @@ -1,262 +0,0 @@ -Constructing to be a writable 320x240,4 UINT16: - resolution 320x240+0+0 - untiled - 4 channels: ('R', 'G', 'B', 'A') - format = uint16 - alpha channel = 3 - z channel = -1 - deep = False -Resetting to be a writable 640x480,3 Float: - resolution 640x480+0+0 - untiled - 3 channels: ('R', 'G', 'B') - format = float - alpha channel = -1 - z channel = -1 - deep = False -Constructing from a bare numpy array: - from 3D, shape is float 0 2 0 3 0 1 0 4 - resolution 2x3+0+0 - untiled - 4 channels: ('R', 'G', 'B', 'A') - format = float - alpha channel = 3 - z channel = -1 - deep = False - pixel (0,1) = 0.3 0 0.8 1 - - from 2D uint8, shape is uint8 0 2 0 3 0 1 0 1 - - from 4D, shape is float 0 2 0 2 0 2 0 4 - -Testing read of ../common/textures/grid.tx: -channels: 4 -name: ../common/textures/grid.tx -file_format_name: tiff -deep: False -orientation: 1 -oriented x,y,width,height: 0 0 1024 1024 -oriented full x,y,width,height: 0 0 1024 1024 -xyz beg/end: 0 1024 0 1024 0 1 -xyz min/max: 0 1023 0 1023 0 0 -setting full res... -roi = 0 1024 0 1024 0 1 0 4 -full roi = 0 2048 0 2048 0 1 0 4 -setting full roi again, as ROI... -Changing origin... -Printing the whole spec to be sure: - resolution 1024x1024+15+20 - tile size 64x64x1 - 4 channels: ('R', 'G', 'B', 'A') - format = uint8 - alpha channel = 3 - z channel = -1 - deep = False - oiio:BitsPerSample = 8 - Orientation = 1 - XResolution = 72.0 - YResolution = 72.0 - ResolutionUnit = "in" - Software = "OpenImageIO 1.5.7dev : maketx -filter lanczos3 --resize grid.tif -o grid.tx" - DateTime = "2014:11:29 23:20:23" - DocumentName = "g.tif" - textureformat = "Plain Texture" - wrapmodes = "black,black" - fovcot = 1.0 - tiff:Compression = 8 - tiff:PhotometricInterpretation = 2 - tiff:PlanarConfiguration = 1 - planarconfig = "contig" - compression = "zip" - PixelAspectRatio = 1.0 - oiio:AverageColor = "0.608983,0.608434,0.608728,1" - oiio:SHA-1 = "233A1D3412A54A5F49814AB7BFFD04F56F46D3D7" - -Resetting to a different MIP level: - resolution 256x256+0+0 - tile size 64x64x1 - 4 channels: ('R', 'G', 'B', 'A') - format = uint8 - alpha channel = 3 - z channel = -1 - deep = False - oiio:BitsPerSample = 8 - Orientation = 1 - XResolution = 72.0 - YResolution = 72.0 - ResolutionUnit = "in" - Software = "OpenImageIO 1.5.7dev : maketx -filter lanczos3 --resize grid.tif -o grid.tx" - DateTime = "2014:11:29 23:20:23" - DocumentName = "g.tif" - textureformat = "Plain Texture" - wrapmodes = "black,black" - fovcot = 1.0 - tiff:Compression = 8 - tiff:PhotometricInterpretation = 2 - tiff:PlanarConfiguration = 1 - planarconfig = "contig" - compression = "zip" - PixelAspectRatio = 1.0 - oiio:AverageColor = "0.608983,0.608434,0.608728,1" - oiio:SHA-1 = "233A1D3412A54A5F49814AB7BFFD04F56F46D3D7" - -Making 2x2 RGB image: - resolution 2x2+0+0 - untiled - 3 channels: ('R', 'G', 'B') - format = uint8 - alpha channel = -1 - z channel = -1 - deep = False -Pixel 0,0 is (1.0, 0.0, 0.0) -Pixel 1,0 is (0.0, 1.0, 0.0) -Pixel 0,1 is (0.0, 0.0, 1.0) -Interpolating 1,0.5 -> (0.5, 0.5, 0.0) -Interpolating NDC 0.25,0.5 -> (0.5, 0.0, 0.5) -Interpolating bicubic 0.25,0.5 -> (0.31944, 0.31944, 0.079861) -Interpolating NDC bicubic 0.25,0.5 -> (0.31944, 0.079861, 0.31944) -The whole image is: [[[1. 0. 0.] - [0. 1. 0.]] - - [[0. 0. 1.] - [0. 0. 0.]]] - -Saving file... - -Writing deep buffer... - -Reading back deep buffer: -Pixel 0 1 had 3 samples -Sample 0 - c 0 : 0.420 - c 1 : 0.000 - c 2 : 0.000 - c 3 : 0.000 - c 4 : 42.000 -Sample 1 - c 0 : 0.100 - c 1 : 0.200 - c 2 : 0.300 - c 3 : 42.500 - c 4 : 0.000 -Sample 2 - c 0 : 0.470 - c 1 : 0.000 - c 2 : 0.000 - c 3 : 0.000 - c 4 : 43.000 -Writing multi-image file -Testing uninitialized bufs - empty nchannels: 0 - -Testing metadata copying - A's spec - resolution 64x64+0+0 - untiled - 3 channels: ('R', 'G', 'B') - format = uint8 - alpha channel = -1 - z channel = -1 - deep = False - abc = 1 - def = 3.140000104904175 - B's spec - resolution 64x64+0+0 - untiled - 3 channels: ('R', 'G', 'B') - format = uint8 - alpha channel = -1 - z channel = -1 - deep = False - def = "Bfoo" - camera:x = "Bx" - camera:y = "By" - A full copy of A should have abc and def as A does: - result of C = A.copy(): - resolution 64x64+0+0 - untiled - 3 channels: ('R', 'G', 'B') - format = uint8 - alpha channel = -1 - z channel = -1 - deep = False - abc = 1 - def = 3.140000104904175 - A.copy_metadata(B) should be identical to B - result of A.copy_metadata(B): - resolution 64x64+0+0 - untiled - 3 channels: ('R', 'G', 'B') - format = uint8 - alpha channel = -1 - z channel = -1 - deep = False - def = "Bfoo" - camera:x = "Bx" - camera:y = "By" - A.merge_metadata(B) should have abc, def from A, camera from B - result of A.merge_metadata(B): - resolution 64x64+0+0 - untiled - 3 channels: ('R', 'G', 'B') - format = uint8 - alpha channel = -1 - z channel = -1 - deep = False - abc = 1 - def = 3.140000104904175 - camera:x = "Bx" - camera:y = "By" - A.merge_metadata(B,True) should have abc from A, def and camera from B - result of A.merge_metadata(B, override=True): - resolution 64x64+0+0 - untiled - 3 channels: ('R', 'G', 'B') - format = uint8 - alpha channel = -1 - z channel = -1 - deep = False - abc = 1 - def = "Bfoo" - camera:x = "Bx" - camera:y = "By" - A.merge_metadata(B,pattern) should have abc,def from A, camera from B - result of A.merge_metadata(B, pattern='^camera:'): - resolution 64x64+0+0 - untiled - 3 channels: ('R', 'G', 'B') - format = uint8 - alpha channel = -1 - z channel = -1 - deep = False - abc = 1 - def = 3.140000104904175 - camera:x = "Bx" - camera:y = "By" - -Testing error handling for out-of-range subimage, miplevel - bayer.png subimage 1 mip 0: False Could not seek to subimage=1 miplevel=0 - bayer.png subimage 0 mip 0: True - bayer.png subimage 0 mip 1: False Could not seek to subimage=0 miplevel=1 - grid-small.exr subimage 1 mip 0: False Could not seek to subimage=1 miplevel=0 - grid-small.exr subimage 0 mip 0: True - grid-small.exr subimage 0 mip 1: False Could not seek to subimage=0 miplevel=1 - tahoe-tiny.tif subimage 1 mip 0: False Error reading: could not seek to subimage 1 - tahoe-tiny.tif subimage 0 mip 0: True - tahoe-tiny.tif subimage 0 mip 1: False Could not seek to subimage=0 miplevel=1 - -Done. -Comparing "out.tif" and "ref/out.tif" -PASS -Comparing "outtuple.tif" and "ref/outtuple.tif" -PASS -Comparing "outarray.tif" and "ref/outarray.tif" -PASS -Comparing "outarrayB.tif" and "ref/outarrayB.tif" -PASS -Comparing "outarrayH.tif" and "ref/outarrayH.tif" -PASS -Comparing "perchan.exr" and "ref/perchan.exr" -PASS -Comparing "multipart.exr" and "ref/multipart.exr" -PASS diff --git a/testsuite/python-imagebuf/ref/out.txt b/testsuite/python-imagebuf/ref/out.txt index de8a31b16b..cb2f545958 100644 --- a/testsuite/python-imagebuf/ref/out.txt +++ b/testsuite/python-imagebuf/ref/out.txt @@ -115,11 +115,11 @@ Interpolating 1,0.5 -> (0.5, 0.5, 0.0) Interpolating NDC 0.25,0.5 -> (0.5, 0.0, 0.5) Interpolating bicubic 0.25,0.5 -> (0.31944, 0.31944, 0.079861) Interpolating NDC bicubic 0.25,0.5 -> (0.31944, 0.079861, 0.31944) -The whole image is: [[[ 1. 0. 0.] - [ 0. 1. 0.]] +The whole image is: [[[1. 0. 0.] + [0. 1. 0.]] - [[ 0. 0. 1.] - [ 0. 0. 0.]]] + [[0. 0. 1.] + [0. 0. 0.]]] Saving file... diff --git a/testsuite/python-imageinput/ref/out-python3.txt b/testsuite/python-imageinput/ref/out-python3.txt deleted file mode 100644 index 0d15bac4b0..0000000000 --- a/testsuite/python-imageinput/ref/out-python3.txt +++ /dev/null @@ -1,210 +0,0 @@ -Could not open "badname.tif" - Error: Could not open file: badname.tif: No such file or directory -Opened "../oiio-images/tahoe-gps.jpg" as a jpeg - resolution 2048x1536+0+0 - untiled - 3 channels: ('R', 'G', 'B') - format = uint8 - alpha channel = -1 - z channel = -1 - deep = False - oiio:ColorSpace = "srgb_rec709_scene" - jpeg:subsampling = "4:2:0" - Make = "HTC" - Model = "T-Mobile G1" - Orientation = 1 - XResolution = 72.0 - YResolution = 72.0 - ResolutionUnit = "none" - Software = "title;va" - Exif:YCbCrPositioning = 1 - Exif:ExifVersion = "0220" - Exif:DateTimeOriginal = "2009:02:21 08:32:04" - Exif:DateTimeDigitized = "2009:02:21 08:32:04" - Exif:FlashPixVersion = "0100" - Exif:ColorSpace = 1 - Exif:PixelXDimension = 2048 - Exif:PixelYDimension = 1536 - Exif:WhiteBalance = 0 - GPS:VersionID = (2, 2, 0, 0) - GPS:LatitudeRef = "N" - GPS:Latitude = (39.0, 18.0, 24.399999618530273) - GPS:LongitudeRef = "W" - GPS:Longitude = (120.0, 20.0, 6.25) - GPS:AltitudeRef = 0 - GPS:Altitude = 0.0 - GPS:TimeStamp = (17.0, 56.0, 33.0) - GPS:MapDatum = "WGS-84" - GPS:DateStamp = "1915:08:08" - -Opened "grid.tx" as a tiff - resolution 1024x1024+0+0 - tile size 64x64x1 - 4 channels: ('R', 'G', 'B', 'A') - format = uint8 - alpha channel = 3 - z channel = -1 - deep = False - oiio:BitsPerSample = 8 - Orientation = 1 - XResolution = 72.0 - YResolution = 72.0 - ResolutionUnit = "in" - Software = "OpenImageIO 1.5.7dev : maketx -filter lanczos3 --resize grid.tif -o grid.tx" - DateTime = "2014:11:29 23:20:23" - DocumentName = "g.tif" - textureformat = "Plain Texture" - wrapmodes = "black,black" - fovcot = 1.0 - tiff:Compression = 8 - tiff:PhotometricInterpretation = 2 - tiff:PlanarConfiguration = 1 - planarconfig = "contig" - compression = "zip" - PixelAspectRatio = 1.0 - oiio:AverageColor = "0.608983,0.608434,0.608728,1" - oiio:SHA-1 = "233A1D3412A54A5F49814AB7BFFD04F56F46D3D7" -Subimage 0 MIP level 1 : - resolution 512x512+0+0 - tile size 64x64x1 -Subimage 0 MIP level 2 : - resolution 256x256+0+0 - tile size 64x64x1 -Subimage 0 MIP level 3 : - resolution 128x128+0+0 - tile size 64x64x1 -Subimage 0 MIP level 4 : - resolution 64x64+0+0 - tile size 64x64x1 -Subimage 0 MIP level 5 : - resolution 32x32+0+0 - tile size 64x64x1 -Subimage 0 MIP level 6 : - resolution 16x16+0+0 - tile size 64x64x1 -Subimage 0 MIP level 7 : - resolution 8x8+0+0 - tile size 64x64x1 -Subimage 0 MIP level 8 : - resolution 4x4+0+0 - tile size 64x64x1 -Subimage 0 MIP level 9 : - resolution 2x2+0+0 - tile size 64x64x1 -Subimage 0 MIP level 10 : - resolution 1x1+0+0 - tile size 64x64x1 - -Testing read_image: -Opened "../oiio-images/tahoe-gps.jpg" as a jpeg -@ (0, 0) = [40 35 57] -@ (2047, 1535) = [37 56 89] -@ (1024, 768) = [137 183 233] - -Opened "../oiio-images/tahoe-gps.jpg" as a jpeg -@ (0, 0) = [0.15686275 0.13725491 0.22352943] -@ (2047, 1535) = [0.14509805 0.21960786 0.34901962] -@ (1024, 768) = [0.5372549 0.7176471 0.91372555] - -Opened "../oiio-images/tahoe-gps.jpg" as a jpeg -@ (0, 0) = [40] -@ (2047, 1535) = [37] -@ (1024, 768) = [137] - -Testing read_scanline: -Opened "../oiio-images/tahoe-gps.jpg" as a jpeg -@ (0, 0) = [40 35 57] -@ (0, 1535) = [ 82 94 136] - -Testing read_tile: -Opened "grid.tx" as a tiff -@ (32, 32) = [ 1 1 1 255] -@ (32, 32) = [255 127 127 255] - -Testing read_scanlines: -Opened "../oiio-images/tahoe-gps.jpg" as a jpeg -@ (0, 0) = [40 35 57] -@ (2047, 1535) = [37 56 89] -@ (1024, 768) = [137 183 233] - -Testing read_tiles: -Opened "grid.tx" as a tiff -@ (0, 0) = [ 0 0 0 255] -@ (1023, 1023) = [ 0 0 0 255] -@ (512, 512) = [ 0 0 0 255] - -Test read_image native u16: -Opened "testu16.tif" as a tiff -Read array typecode uint16 [ 12288 ] - -Test read_scanlines native u16: -Opened "testu16.tif" as a tiff -Read array typecode uint16 [ 12288 ] - -Test read_tiles native half: -Opened "testf16.exr" as a openexr -Read array typecode float16 [ 12288 ] - -Test read_image into half: -Opened "testu16.tif" as a tiff -Read array typecode float16 [ 12288 ] - -Test read_image into FLOAT: -Opened "testu16.tif" as a tiff -Read array typecode float32 [ 12288 ] - -Testing write and read of unassociated: - writing: [[[0.5 0.5 0.5 0.5] - [0.5 0.5 0.5 0.5]] - - [[0.5 0.5 0.5 0.5] - [0.5 0.5 0.5 0.5]]] - - default reading as IB: [[[0.25 0.25 0.25 0.5 ] - [0.25 0.25 0.25 0.5 ]] - - [[0.25 0.25 0.25 0.5 ] - [0.25 0.25 0.25 0.5 ]]] - - reading as IB with unassoc hint: [[[0.5 0.5 0.5 0.5] - [0.5 0.5 0.5 0.5]] - - [[0.5 0.5 0.5 0.5] - [0.5 0.5 0.5 0.5]]] - - reading as II with hint, read scanlines backward: - [1] = [[0.5 0.5 0.5 0.5] - [0.5 0.5 0.5 0.5]] - [0] = [[0.5 0.5 0.5 0.5] - [0.5 0.5 0.5 0.5]] - - -Testing write and read of TIFF CMYK with auto RGB translation: - writing: [[[0.5019608 0. 0. 0.5019608] - [0.5019608 0. 0. 0.5019608]] - - [[0.5019608 0. 0. 0.5019608] - [0.5019608 0. 0. 0.5019608]]] - - default reading as IB: [[[0.24705884 0.49803925 0.49803925] - [0.24705884 0.49803925 0.49803925]] - - [[0.24705884 0.49803925 0.49803925] - [0.24705884 0.49803925 0.49803925]]] - - reading as IB with rawcolor=1: [[[0.5019608 0. 0. 0.5019608] - [0.5019608 0. 0. 0.5019608]] - - [[0.5019608 0. 0. 0.5019608] - [0.5019608 0. 0. 0.5019608]]] - - reading as II with rawcolor=0, read scanlines backward: - [1] = [[0.24705884 0.49803925 0.49803925] - [0.24705884 0.49803925 0.49803925]] - [0] = [[0.24705884 0.49803925 0.49803925] - [0.24705884 0.49803925 0.49803925]] - - -is_imageio_format_name('tiff') = True -is_imageio_format_name('txff') = False -Done. diff --git a/testsuite/python-imageinput/ref/out.txt b/testsuite/python-imageinput/ref/out.txt index a3eed8e9a5..0d15bac4b0 100644 --- a/testsuite/python-imageinput/ref/out.txt +++ b/testsuite/python-imageinput/ref/out.txt @@ -97,41 +97,41 @@ Subimage 0 MIP level 10 : Testing read_image: Opened "../oiio-images/tahoe-gps.jpg" as a jpeg -@ (0L, 0L) = [40 35 57] -@ (2047L, 1535L) = [37 56 89] -@ (1024L, 768L) = [137 183 233] +@ (0, 0) = [40 35 57] +@ (2047, 1535) = [37 56 89] +@ (1024, 768) = [137 183 233] Opened "../oiio-images/tahoe-gps.jpg" as a jpeg -@ (0L, 0L) = [0.15686275 0.13725491 0.22352943] -@ (2047L, 1535L) = [0.14509805 0.21960786 0.34901962] -@ (1024L, 768L) = [0.5372549 0.7176471 0.91372555] +@ (0, 0) = [0.15686275 0.13725491 0.22352943] +@ (2047, 1535) = [0.14509805 0.21960786 0.34901962] +@ (1024, 768) = [0.5372549 0.7176471 0.91372555] Opened "../oiio-images/tahoe-gps.jpg" as a jpeg -@ (0L, 0L) = [40] -@ (2047L, 1535L) = [37] -@ (1024L, 768L) = [137] +@ (0, 0) = [40] +@ (2047, 1535) = [37] +@ (1024, 768) = [137] Testing read_scanline: Opened "../oiio-images/tahoe-gps.jpg" as a jpeg -@ (0L, 0L) = [40 35 57] -@ (0L, 1535L) = [ 82 94 136] +@ (0, 0) = [40 35 57] +@ (0, 1535) = [ 82 94 136] Testing read_tile: Opened "grid.tx" as a tiff -@ (32L, 32L) = [ 1 1 1 255] -@ (32L, 32L) = [255 127 127 255] +@ (32, 32) = [ 1 1 1 255] +@ (32, 32) = [255 127 127 255] Testing read_scanlines: Opened "../oiio-images/tahoe-gps.jpg" as a jpeg -@ (0L, 0L) = [40 35 57] -@ (2047L, 1535L) = [37 56 89] -@ (1024L, 768L) = [137 183 233] +@ (0, 0) = [40 35 57] +@ (2047, 1535) = [37 56 89] +@ (1024, 768) = [137 183 233] Testing read_tiles: Opened "grid.tx" as a tiff -@ (0L, 0L) = [ 0 0 0 255] -@ (1023L, 1023L) = [ 0 0 0 255] -@ (512L, 512L) = [ 0 0 0 255] +@ (0, 0) = [ 0 0 0 255] +@ (1023, 1023) = [ 0 0 0 255] +@ (512, 512) = [ 0 0 0 255] Test read_image native u16: Opened "testu16.tif" as a tiff diff --git a/testsuite/python-imagespec/ref/out-python3.txt b/testsuite/python-imagespec/ref/out-python3.txt deleted file mode 100644 index 3b21fad6e8..0000000000 --- a/testsuite/python-imagespec/ref/out-python3.txt +++ /dev/null @@ -1,215 +0,0 @@ -ctr: null - resolution (width,height,depth) = 0 0 1 - origin (x,y,z) = 0 0 0 - full res = 0 0 0 - full origin = 0 0 0 - untiled - format = unknown - nchannels = 0 - channelformats = () - channel names = () - alpha channel = -1 - z channel = -1 - deep = False - -ctr: UINT16 - resolution (width,height,depth) = 0 0 1 - origin (x,y,z) = 0 0 0 - full res = 0 0 0 - full origin = 0 0 0 - untiled - format = uint16 - nchannels = 0 - channelformats = () - channel names = () - alpha channel = -1 - z channel = -1 - deep = False - -ctr: 640x480,3 UINT8 - resolution (width,height,depth) = 640 480 1 - origin (x,y,z) = 0 0 0 - full res = 640 480 1 - full origin = 0 0 0 - untiled - format = uint8 - nchannels = 3 - channelformats = () - channel names = ('R', 'G', 'B') - alpha channel = -1 - z channel = -1 - deep = False - -lots of fields - resolution (width,height,depth) = 640 480 1 - origin (x,y,z) = 1 2 3 - full res = 1280 960 7 - full origin = 4 5 6 - tile size = 32 64 16 - format = float - nchannels = 5 - channelformats = (, , , , ) - channel names = ('R', 'G', 'B', 'A', 'channel4') - alpha channel = 3 - z channel = -1 - deep = False - - B channel = 2 - foo channel = -1 -channel bytes = 4 - channel_bytes(1) = 4 native 1 - channel_bytes(4) = 4 native 4 -pixel bytes = 20 native 8 -scanline bytes = 12800 native 5120 if uint16 6400 -tile bytes = 655360 native 262144 if uint16 327680 -image bytes = 6144000 native 2457600 if uint16 3072000 -tile pixels = 32768 -image_pixels = 307200 -size_t_safe = True -get_channelformats: (, , , , ) -channelindex('G') = 1 -channel_name(1) = G -channelformat(1) = uint8 - -get_int_attribute('foo_int') retrieves 14 -get_int_attribute('foo_int',21) with default retrieves 14 -get_int_attribute('foo_no',23) retrieves 23 -get_float_attribute('foo_float') retrieves 3.140000104904175 -get_float_attribute('foo_float_no') retrieves 0.0 -get_float_attribute('foo_float_no',2.7) retrieves 2.700000047683716 -get_string_attribute('foo_str') retrieves blah -get_string_attribute('foo_str_no') retrieves -get_string_attribute('foo_str_no','xx') retrieves xx - -getattribute('foo_int') retrieves 14 -getattribute('foo_float') retrieves 3.140000104904175 -getattribute('foo_str') retrieves blah -getattribute('foo_vector') retrieves (1.0, 0.0, 11.0) -getattribute('foo_matrix') retrieves (1.0, 0.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 2.0, 3.0, 1.0) -getattribute('foo_no') retrieves None -getattribute('smpte:TimeCode') retrieves (18356486, 4294967295) -getattribute('ucarr') retrieves [49 50 51 0 0 97 98 99 1 88] -getattribute('unknown') retrieves None -s.get('foo_int') = 14 -s.get('ucarr') retrieves [49 50 51 0 0 97 98 99 1 88] -s['ucarr'] retrieves [49 50 51 0 0 97 98 99 1 88] -s.get('unknown') = None -s.get('unknown', 123) = None -s['delfoo_float'] = 99.5 -s['delfoo_int'] = 29 -s['delfoo_str'] = egg -s['unknown'] raised a KeyError (as expected) -'foo_int' in s = True -'unknown' in s = False - -extra_attribs size is 10 -0 foo_str string blah -"blah" -1 foo_int int 14 -14 -2 foo_float float 3.140000104904175 -3.14 -3 foo_vector vector (1.0, 0.0, 11.0) -1, 0, 11 -4 foo_matrix matrix (1.0, 0.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 2.0, 3.0, 1.0) -1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0, 1, 2, 3, 1 -5 smpte:TimeCode timecode (18356486, 4294967295) -01:18:19:06 -6 ucarr uint8[10] [49 50 51 0 0 97 98 99 1 88] -49, 50, 51, 0, 0, 97, 98, 99, 1, 88 -7 delfoo_str string egg -"egg" -8 delfoo_int int 29 -29 -9 delfoo_float float 99.5 -99.5 - -seralize(xml): - -1 -2 -3 -640 -480 -1 -4 -5 -6 -1280 -960 -7 -32 -64 -16 -float -5 - -R -G -B -A -channel4 - -3 --1 -0 -blah -14 -3.14 -1, 0, 11 -1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0, 1, 2, 3, 1 -01:18:19:06 -49, 50, 51, 0, 0, 97, 98, 99, 1, 88 -egg -29 -99.5 - - -serialize(text, human): - 640 x 480, 5 channel, uint8/uint8/uint8/uint8/float - channel list: R (uint8), G (uint8), B (uint8), A (uint8), channel4 (float) - pixel data origin: x=1, y=2 - full/display size: 1280 x 960 - full/display origin: 4, 5 - tile size: 32 x 64 - delfoo_float: 99.5 - delfoo_int: 29 - delfoo_str: "egg" - foo_float: 3.14 - foo_int: 14 - foo_matrix: 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0, 1, 2, 3, 1 - foo_str: "blah" - foo_vector: 1, 0, 11 - ucarr: 49, 50, 51, 0, 0, 97, 98, 99, 1, 88 - smpte:TimeCode: 01:18:19:06 - - -Added dog: Spot -After erasing dog, dog = None - -Testing construction from ROI: - resolution (width,height,depth) = 640 480 1 - origin (x,y,z) = 0 0 0 - full res = 640 480 1 - full origin = 0 0 0 - untiled - format = float - nchannels = 3 - channelformats = () - channel names = ('R', 'G', 'B') - alpha channel = -1 - z channel = -1 - deep = False - - -Testing set_colorspace: - after set_colorspace('sRGB'): sRGB - after set_colorspace(''): - -Testing global attribute store/retrieve: -get_string_attribute plugin_searchpath : perfect -get_int_attribute plugin_searchpath : 0 -getattribute TypeString plugin_searchpath : perfect -getattribute TypeFloat plugin_searchpath : None -getattribute TypeString blahblah : None -Done. diff --git a/testsuite/python-imagespec/ref/out.txt b/testsuite/python-imagespec/ref/out.txt index f5c303addc..3b21fad6e8 100644 --- a/testsuite/python-imagespec/ref/out.txt +++ b/testsuite/python-imagespec/ref/out.txt @@ -206,7 +206,6 @@ Testing set_colorspace: after set_colorspace('sRGB'): sRGB after set_colorspace(''): - Testing global attribute store/retrieve: get_string_attribute plugin_searchpath : perfect get_int_attribute plugin_searchpath : 0 From 88d9b37dfa3873702ac264bc41f864ea970122fe Mon Sep 17 00:00:00 2001 From: Larry Gritz Date: Sun, 1 Mar 2026 17:47:01 -0800 Subject: [PATCH 2/4] improve exception type and wording Signed-off-by: Larry Gritz --- src/python/py_oiio.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/python/py_oiio.h b/src/python/py_oiio.h index 27d15f48a1..047d7aa121 100644 --- a/src/python/py_oiio.h +++ b/src/python/py_oiio.h @@ -522,7 +522,7 @@ attribute_onearg(T& myobj, string_view name, const py::object& obj) else if (py::isinstance(obj)) myobj.attribute(name, std::string(obj.template cast())); else - throw std::invalid_argument("Bad type for attribute"); + throw py::type_error("attribute() value must be int, float, or str"); } From ad74ffe2fd0cf3646ae2245549925fc7e04cf87a Mon Sep 17 00:00:00 2001 From: Larry Gritz Date: Sun, 1 Mar 2026 17:50:49 -0800 Subject: [PATCH 3/4] Make ParamValueList_attribute_onearg static, since it's not called outside this file Signed-off-by: Larry Gritz --- src/python/py_paramvalue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/python/py_paramvalue.cpp b/src/python/py_paramvalue.cpp index 945dbf3984..660c168b3b 100644 --- a/src/python/py_paramvalue.cpp +++ b/src/python/py_paramvalue.cpp @@ -79,7 +79,7 @@ ParamValue_from_pyobject(string_view name, TypeDesc type, int nvalues, -void +static void ParamValueList_attribute_onearg(ParamValueList& self, const std::string& name, const py::object& obj) { From 4e445fa6a4ed4794d6ba23840705769631480612 Mon Sep 17 00:00:00 2001 From: Larry Gritz Date: Sun, 1 Mar 2026 17:51:02 -0800 Subject: [PATCH 4/4] Handle bytes as well as str Signed-off-by: Larry Gritz --- src/python/py_oiio.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/python/py_oiio.h b/src/python/py_oiio.h index 047d7aa121..23301f30dc 100644 --- a/src/python/py_oiio.h +++ b/src/python/py_oiio.h @@ -521,6 +521,8 @@ attribute_onearg(T& myobj, string_view name, const py::object& obj) myobj.attribute(name, int(obj.template cast())); else if (py::isinstance(obj)) myobj.attribute(name, std::string(obj.template cast())); + else if (py::isinstance(obj)) + myobj.attribute(name, std::string(obj.template cast())); else throw py::type_error("attribute() value must be int, float, or str"); }