Skip to content

Commit 0436fc6

Browse files
committed
Fix typedesc_from_python_array_code parity
Signed-off-by: Aleksandr Motsjonov <soswow@gmail.com>
1 parent 2944afa commit 0436fc6

4 files changed

Lines changed: 35 additions & 5 deletions

File tree

src/python-nanobind/MIGRATION_STATUS.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,15 @@ Generated from the binding sources. The nanobind extension is `PyOpenImageIONano
77
| Source file | Python / C++ API |
88
| --- | --- |
99
| `py_roi.cpp` | <code>ROI</code><br>Free functions:<br><ul><li><code>union</code></li><li><code>intersection</code></li><li><code>get_roi</code></li><li><code>get_roi_full</code></li><li><code>set_roi</code></li><li><code>set_roi_full</code></li></ul> |
10+
| `py_typedesc.cpp` | <code>TypeDesc</code><br>Enums: <code>BASETYPE</code>, <code>AGGREGATE</code>, <code>VECSEMANTICS</code><br>Module <code>Type*</code> constants |
11+
| `py_imagespec.cpp` | <code>ImageSpec</code> (bound methods/properties, typed <code>attribute</code> / buffer paths via shared helpers). |
1012

1113
## Migrated — partial (gaps or intentional deltas vs pybind)
1214

1315
| Source file | Migrated (vs pybind) | Missing or divergent (vs pybind) |
1416
| --- | --- | --- |
1517
| `py_oiio.cpp` (`_OpenImageIO` module) | <ul><li><code>attribute</code> (one-arg and typed)</li><li><code>get_int_attribute</code></li><li><code>get_float_attribute</code></li><li><code>get_string_attribute</code></li><li><code>getattribute</code></li><li><code>__version__</code></li></ul> | <ul><li><code>geterror</code></li><li><code>get_bytes_attribute</code></li><li>Module <code>set_colorspace</code> (helper taking <code>ImageSpec</code> — the instance method is on <code>ImageSpec</code> in nanobind)</li><li><code>set_colorspace_rec709_gamma</code></li><li><code>equivalent_colorspace</code></li><li><code>is_imageio_format_name</code></li><li><code>AutoStride</code></li><li><code>openimageio_version</code>, <code>VERSION</code>, <code>VERSION_STRING</code>, <code>VERSION_MAJOR</code>, <code>VERSION_MINOR</code>, <code>VERSION_PATCH</code>, <code>INTRO_STRING</code></li><li>Optional: stack traces when <code>OPENIMAGEIO_DEBUG_PYTHON</code> is set (<code>Sysutil</code>)</li><li><code>make_pyobject</code>: no pybind-style <code>debugfmt</code> when the type is unhandled (returns default quietly)</li></ul> |
16-
| `py_typedesc.cpp` | <code>TypeDesc</code><br>Enums: <code>BASETYPE</code>, <code>AGGREGATE</code>, <code>VECSEMANTICS</code><br>Module <code>Type*</code> constants | Helper <code>typedesc_from_python_array_code</code> (used for buffer/array attribute values): pybind maps <code>l</code>→INT64, <code>L</code>→UINT64; nanobind maps <code>l</code>/<code>i</code>→INT, <code>L</code>/<code>I</code>→UINT. Does not affect <code>TypeDesc("...")</code> string construction. |
17-
| `py_paramvalue.cpp` | Types: <code>ParamValue</code>, <code>ParamValueList</code><br>Enum: <code>Interp</code><br>Rest of the bound surface matches pybind. | <code>paramvalue_from_pyobject</code>: no pybind-style path for <code>UINT8</code> + <code>bytes</code> with <code>type.arraylen</code> (incl. inferred length from <code>bytes</code> size). Typed attribute paths that rely on <code>typedesc_from_python_array_code</code> share the same buffer-format caveat as <code>py_typedesc.cpp</code>. |
18-
| `py_imagespec.cpp` | <code>ImageSpec</code> (bound methods/properties as implemented). | Typed <code>attribute</code> / buffer paths use shared helpers; same <code>typedesc_from_python_array_code</code> behavior as <code>py_typedesc.cpp</code>. |
18+
| `py_paramvalue.cpp` | Types: <code>ParamValue</code>, <code>ParamValueList</code><br>Enum: <code>Interp</code><br>Rest of the bound surface matches pybind. | <code>paramvalue_from_pyobject</code>: no pybind-style path for <code>UINT8</code> + <code>bytes</code> with <code>type.arraylen</code> (incl. inferred length from <code>bytes</code> size). |
1919
| `__init__.py` (package) | Env / DLL path setup, <code>from ._OpenImageIO import *</code>, version docstring. | <strong>TODO:</strong> Python CLI entry-point trampolines when the install layout matches the full wheel. |
2020

2121
---

src/python-nanobind/py_oiio.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,14 @@ typedesc_from_python_array_code(string_view code)
5959
return TypeDesc::INT16;
6060
if (code == "H")
6161
return TypeDesc::UINT16;
62-
if (code == "i" || code == "l")
62+
if (code == "i")
6363
return TypeDesc::INT;
64-
if (code == "I" || code == "L")
64+
if (code == "I")
6565
return TypeDesc::UINT;
66+
if (code == "l")
67+
return TypeDesc::INT64;
68+
if (code == "L")
69+
return TypeDesc::UINT64;
6670
if (code == "q")
6771
return TypeDesc::INT64;
6872
if (code == "Q")

testsuite/python-typedesc/ref/out.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,4 +247,6 @@ type 'TypeURational'
247247
type 'TypeUInt'
248248
c_str "uint"
249249

250+
Passed: array('l')+int[2] does not mis-read int64 as two 32-bit ints (matches pybind)
251+
250252
Done.

testsuite/python-typedesc/src/test_typedesc.py

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

77
from __future__ import annotations
88

9+
import array
910
import OpenImageIO as oiio
1011

1112

@@ -214,6 +215,29 @@ def breakdown_test(t, name="", verbose=True):
214215
breakdown_test (oiio.TypeUInt, "TypeUInt", verbose=False)
215216
print ("")
216217

218+
# 8-byte array('l'): PEP 3118 'l' must not be treated as 32-bit int when
219+
# copying into int[2], or the first 8 bytes are split into (low32, high32)
220+
# and the attribute can read as (1, 0) for values [1, 2] (see
221+
# typedesc_from_python_array_code in py_oiio.cpp). Where C long is
222+
# 4 bytes, the check below is skipped; the final message is unchanged so
223+
# reference output is stable across platforms.
224+
_passed_msg = (
225+
"Passed: array('l')+int[2] does not mis-read int64 as two 32-bit ints (matches pybind)"
226+
)
227+
if array.array("l", [0]).itemsize == 8:
228+
b = array.array("l", [1, 2])
229+
spec = oiio.ImageSpec()
230+
spec.attribute("regression_k", oiio.TypeDesc("int[2]"), memoryview(b))
231+
v = spec.get("regression_k", None)
232+
if v is not None and tuple(v) == (1, 0):
233+
print(
234+
"Failed: array('l')+int[2] mis-stored (1,0) — 'l' must not be INT32-typed in buffer code"
235+
)
236+
else:
237+
print(_passed_msg)
238+
else:
239+
print(_passed_msg)
240+
217241
print ("Done.")
218242
except Exception as detail:
219243
print ("Unknown exception:", detail)

0 commit comments

Comments
 (0)