Skip to content

Commit 1585183

Browse files
committed
Add a bit more coverage to both
Signed-off-by: Aleksandr Motsjonov <soswow@gmail.com>
1 parent e7d291b commit 1585183

8 files changed

Lines changed: 119 additions & 19 deletions

File tree

src/python-nanobind/py_imagespec.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ declare_imagespec(nb::module_& m)
5050
.def(nb::init<>())
5151
.def("__init__",
5252
[](ImageSpec* self, int xres, int yres, int nchans,
53-
TypeDesc::BASETYPE format) {
54-
new (self) ImageSpec(xres, yres, nchans, TypeDesc(format));
53+
const TypeDesc& format) {
54+
new (self) ImageSpec(xres, yres, nchans, format);
5555
})
5656
.def_rw("x", &ImageSpec::x)
5757
.def_rw("y", &ImageSpec::y)

src/python-nanobind/py_oiio.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ NB_MODULE(_OpenImageIO, m)
99
{
1010
m.doc() = "OpenImageIO nanobind bindings.";
1111

12+
PyOpenImageIO::declare_typedesc(m);
1213
PyOpenImageIO::declare_roi(m);
1314
PyOpenImageIO::declare_imagespec(m);
14-
PyOpenImageIO::declare_typedesc(m);
1515
m.attr("__version__") = OIIO_VERSION_STRING;
1616
}

src/python-nanobind/py_typedesc.cpp

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -97,12 +97,10 @@ declare_typedesc(nb::module_& m)
9797

9898
nb::class_<TypeDesc>(m, "TypeDesc")
9999
.def_prop_rw(
100-
"basetype",
101-
[](TypeDesc t) { return BASETYPE(t.basetype); },
100+
"basetype", [](TypeDesc t) { return BASETYPE(t.basetype); },
102101
[](TypeDesc& t, BASETYPE b) { typedesc_property(t, b); })
103102
.def_prop_rw(
104-
"aggregate",
105-
[](TypeDesc t) { return AGGREGATE(t.aggregate); },
103+
"aggregate", [](TypeDesc t) { return AGGREGATE(t.aggregate); },
106104
[](TypeDesc& t, AGGREGATE b) { typedesc_property(t, b); })
107105
.def_prop_rw(
108106
"vecsemantics",
@@ -116,33 +114,53 @@ declare_typedesc(nb::module_& m)
116114
.def(nb::init<BASETYPE, AGGREGATE, VECSEMANTICS>())
117115
.def(nb::init<BASETYPE, AGGREGATE, VECSEMANTICS, int>())
118116
.def(nb::init<const char*>())
119-
.def("c_str", [](const TypeDesc& self) { return std::string(self.c_str()); })
117+
.def("c_str",
118+
[](const TypeDesc& self) { return std::string(self.c_str()); })
120119
.def("numelements", &TypeDesc::numelements)
121120
.def("basevalues", &TypeDesc::basevalues)
122121
.def("size", &TypeDesc::size)
123122
.def("elementtype", &TypeDesc::elementtype)
124123
.def("elementsize", &TypeDesc::elementsize)
125124
.def("basesize", &TypeDesc::basesize)
126125
.def("fromstring",
127-
[](TypeDesc& t, const char* typestring) { t.fromstring(typestring); })
126+
[](TypeDesc& t, const char* typestring) {
127+
t.fromstring(typestring);
128+
})
128129
.def("equivalent", &TypeDesc::equivalent)
129130
.def("unarray", &TypeDesc::unarray)
130-
.def("is_vec2", &TypeDesc::is_vec2)
131-
.def("is_vec3", &TypeDesc::is_vec3)
132-
.def("is_vec4", &TypeDesc::is_vec4)
133-
.def("is_box2", &TypeDesc::is_box2)
134-
.def("is_box3", &TypeDesc::is_box3)
131+
.def("is_vec2",
132+
[](const TypeDesc& t, BASETYPE b = TypeDesc::FLOAT) {
133+
return t.is_vec2(b);
134+
})
135+
.def("is_vec3",
136+
[](const TypeDesc& t, BASETYPE b = TypeDesc::FLOAT) {
137+
return t.is_vec3(b);
138+
})
139+
.def("is_vec4",
140+
[](const TypeDesc& t, BASETYPE b = TypeDesc::FLOAT) {
141+
return t.is_vec4(b);
142+
})
143+
.def("is_box2",
144+
[](const TypeDesc& t, BASETYPE b = TypeDesc::FLOAT) {
145+
return t.is_box2(b);
146+
})
147+
.def("is_box3",
148+
[](const TypeDesc& t, BASETYPE b = TypeDesc::FLOAT) {
149+
return t.is_box3(b);
150+
})
135151
.def_static("all_types_equal",
136152
[](const std::vector<TypeDesc>& types) {
137153
return TypeDesc::all_types_equal(types);
138154
})
139155
.def(nb::self == nb::self)
140156
.def(nb::self != nb::self)
141157
.def("__str__", [](TypeDesc t) { return std::string(t.c_str()); })
142-
.def("__repr__",
143-
[](TypeDesc t) {
144-
return Strutil::fmt::format("<TypeDesc '{}'>", t.c_str());
145-
});
158+
.def("__repr__", [](TypeDesc t) {
159+
return Strutil::fmt::format("<TypeDesc '{}'>", t.c_str());
160+
});
161+
162+
nb::implicitly_convertible<BASETYPE, TypeDesc>();
163+
nb::implicitly_convertible<nb::str, TypeDesc>();
146164

147165
m.attr("UNKNOWN") = nb::cast(TypeDesc::UNKNOWN);
148166
m.attr("NONE") = nb::cast(TypeDesc::NONE);

testsuite/python-roi/ref/out.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ r contains (10,10) (expect yes): True
3030
r contains (1000,10) (expect no): False
3131
r contains roi(10,20,10,20,0,1,0,1) (expect yes): True
3232
r contains roi(1010,1020,10,20,0,1,0,1) (expect no): False
33+
ROI(0, 10, 0, 10, 2, 4) = 0 10 0 10 2 4 0 10000
34+
r5 contains (1,1,2,1) (expect yes): True
35+
r5 contains (1,1,1,1) (expect no): False
36+
r5 contains (1,1,2,3) (expect no): False
3337
A = 0 10 0 8 0 1 0 4
3438
B = 5 15 -1 10 0 1 0 4
3539
ROI.union(A,B) = 0 15 -1 10 0 1 0 4

testsuite/python-roi/src/test_roi.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,14 @@ def run(oiio):
4848
print ("r contains (1000,10) (expect no): ", r.contains(1000,10))
4949
print ("r contains roi(10,20,10,20,0,1,0,1) (expect yes): ", r.contains(oiio.ROI(10,20,10,20,0,1,0,1)))
5050
print ("r contains roi(1010,1020,10,20,0,1,0,1) (expect no): ", r.contains(oiio.ROI(1010,1020,10,20,0,1,0,1)))
51+
# Cover the 6-argument ROI constructor and the contains(x, y, z, ch)
52+
# overload with explicit z/channel arguments.
53+
r4 = oiio.ROI (0, 10, 0, 10, 2, 4)
54+
print ("ROI(0, 10, 0, 10, 2, 4) =", r4)
55+
r5 = oiio.ROI (0, 10, 0, 10, 2, 4, 1, 3)
56+
print ("r5 contains (1,1,2,1) (expect yes): ", r5.contains(1,1,2,1))
57+
print ("r5 contains (1,1,1,1) (expect no): ", r5.contains(1,1,1,1))
58+
print ("r5 contains (1,1,2,3) (expect no): ", r5.contains(1,1,2,3))
5159

5260
A = oiio.ROI (0, 10, 0, 8, 0, 1, 0, 4)
5361
B = oiio.ROI (5, 15, -1, 10, 0, 1, 0, 4)

testsuite/python-typedesc/ref/out.txt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,31 @@ equivalent(vector,color) True
159159
vector.equivalent(float) False
160160
equivalent(vector,float) False
161161

162+
type 'mutated FLOAT, VEC3, COLOR, array of 2'
163+
c_str "color[2]"
164+
basetype BASETYPE.FLOAT
165+
aggregate AGGREGATE.VEC3
166+
vecsemantics VECSEMANTICS.COLOR
167+
arraylen 2
168+
str(t) = "color[2]"
169+
size = 24
170+
elementtype = color
171+
numelements = 2
172+
basevalues = 6
173+
elementsize = 12
174+
basesize = 4
175+
type 'fromstring('point')'
176+
c_str "point"
177+
after unarray('float[2]') = float
178+
vector is_vec2,is_vec3,is_vec4 = False True False
179+
box2i is_box2,is_box3 = True False
180+
all_types_equal([uint8,uint8]) = True
181+
all_types_equal([uint8,uint16]) = False
182+
repr(TypeFloat) = <TypeDesc 'float'>
183+
184+
implicit enum ImageSpec roi = 0 8 0 9 0 1 0 3
185+
implicit str ImageSpec roi = 0 8 0 9 0 1 0 3
186+
162187
type 'TypeFloat'
163188
c_str "float"
164189
type 'TypeColor'

testsuite/python-typedesc/run.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@
55
# https://github.com/AcademySoftwareFoundation/OpenImageIO
66

77

8-
command += pythonbin + " src/test_typedesc.py > out.txt"
8+
command += pythonbin + " src/test_typedesc.py " + OIIO_BUILD_ROOT + " > out.txt"

testsuite/python-typedesc/src/test_typedesc.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66

77
from __future__ import annotations
88

9+
import pathlib
10+
import sys
11+
912
# Test that every expected enum value of BASETYPE exists
1013
def basetype_enum_test(oiio):
1114
try:
@@ -135,6 +138,44 @@ def run(oiio):
135138
print ("equivalent(vector,float)", oiio.TypeDesc.equivalent(oiio.TypeDesc("vector"), oiio.TypeDesc("float")))
136139
print ("")
137140

141+
# Exercise property mutation and helper methods that are easy to miss in
142+
# binding ports because they are not just plain constructors/accessors.
143+
t_mut = oiio.TypeDesc()
144+
t_mut.basetype = oiio.FLOAT
145+
t_mut.aggregate = oiio.VEC3
146+
t_mut.vecsemantics = oiio.COLOR
147+
t_mut.arraylen = 2
148+
breakdown_test (t_mut, "mutated FLOAT, VEC3, COLOR, array of 2")
149+
t_from = oiio.TypeDesc()
150+
t_from.fromstring("point")
151+
breakdown_test (t_from, "fromstring('point')", verbose=False)
152+
t_unarray = oiio.TypeDesc("float[2]")
153+
t_unarray.unarray()
154+
print ("after unarray('float[2]') =", t_unarray)
155+
print ("vector is_vec2,is_vec3,is_vec4 =",
156+
oiio.TypeDesc("vector").is_vec2(oiio.FLOAT),
157+
oiio.TypeDesc("vector").is_vec3(oiio.FLOAT),
158+
oiio.TypeDesc("vector").is_vec4(oiio.FLOAT))
159+
print ("box2i is_box2,is_box3 =",
160+
oiio.TypeDesc("box2i").is_box2(oiio.INT),
161+
oiio.TypeDesc("box2i").is_box3(oiio.INT))
162+
print ("all_types_equal([uint8,uint8]) =",
163+
oiio.TypeDesc.all_types_equal([oiio.TypeDesc("uint8"),
164+
oiio.TypeDesc("uint8")]))
165+
print ("all_types_equal([uint8,uint16]) =",
166+
oiio.TypeDesc.all_types_equal([oiio.TypeDesc("uint8"),
167+
oiio.TypeDesc("uint16")]))
168+
print ("repr(TypeFloat) =", repr(oiio.TypeFloat))
169+
print ("")
170+
171+
# Exercise implicit conversion paths used by the production pybind11
172+
# binding: BASETYPE -> TypeDesc and Python str -> TypeDesc.
173+
implicit_enum_spec = oiio.ImageSpec(8, 9, 3, oiio.UINT8)
174+
implicit_str_spec = oiio.ImageSpec(8, 9, 3, "uint8")
175+
print ("implicit enum ImageSpec roi =", implicit_enum_spec.roi)
176+
print ("implicit str ImageSpec roi =", implicit_str_spec.roi)
177+
print ("")
178+
138179
# Test the pre-constructed types
139180
breakdown_test (oiio.TypeFloat, "TypeFloat", verbose=False)
140181
breakdown_test (oiio.TypeColor, "TypeColor", verbose=False)
@@ -176,6 +217,10 @@ def main() -> int:
176217
# Keep the real import-and-execute path in main() so this file still runs
177218
# as the standalone pybind11 TypeDesc test, while the nanobind TypeDesc
178219
# runner can import and reuse run(oiio) without immediately executing it.
220+
if len(sys.argv) > 1:
221+
build_root = pathlib.Path(sys.argv[1]).resolve()
222+
sys.path.insert(0, str(build_root / "lib/python/site-packages"))
223+
179224
import OpenImageIO as oiio
180225

181226
try:

0 commit comments

Comments
 (0)