Skip to content

COMP: Resolve Python ST/IT/OT from the wrapped C types - #6772

Open
hjmjohnson wants to merge 1 commit into
InsightSoftwareConsortium:mainfrom
hjmjohnson:comp-itk-identifier-type-from-cmake
Open

COMP: Resolve Python ST/IT/OT from the wrapped C types#6772
hjmjohnson wants to merge 1 commit into
InsightSoftwareConsortium:mainfrom
hjmjohnson:comp-itk-identifier-type-from-cmake

Conversation

@hjmjohnson

Copy link
Copy Markdown
Member

itk.IT did not agree with the identifier type the wrapping actually instantiated: Wrapping/WrapBasicTypes.cmake selects unsigned long long only when both WIN32 and ITK_USE_64BITS_IDS hold, while itk/support/types.py derived the alias independently. On Windows with ITK_USE_64BITS_IDS=OFF the two disagreed, so itk.VectorContainer[itk.IT, ...] named an instantiation that does not exist.

Export ITKM_ST / ITKM_IT / ITKM_OT through itkConfig and resolve the Python aliases from there, so both sides come from one definition.

Surfaced while answering #6769 (comment) — that PR wants to use itk.IT as IdentifierType, which needs this first.

The disagreement

Wrapping/WrapBasicTypes.cmake:221:

if(WIN32 AND ITK_USE_64BITS_IDS)
  set(ITKM_IT ${ITKM_ULL})
else()
  set(ITKM_IT ${ITKM_UL})
endif()

Wrapping/Generators/Python/itk/support/types.py, after #6767:

ST = uint64_t
IT = uint64_t
OT = int64_t

On Windows with ITK_USE_64BITS_IDS=OFF, CMake instantiates unsigned long (32-bit there) while Python reports a 64-bit type. Elsewhere the two happen to coincide, which is why this has gone unnoticed.

ITKM_IT expands to the literal "UL" / "ULL", which is exactly the itkCType short name, so the CMake value maps to the Python object by direct lookup with no translation table to drift.

Local verification

macOS, ITK_WRAP_PYTHON=ON, Module_ITKVtkGlue=OFF (incompatible with ITK_USE_PYTHON_LIMITED_API). Build exit 0, 4610/4610 targets, zero errors.

aliases from CMake: {'ST': 'UL', 'IT': 'UL', 'OT': 'SL'}
ST unsigned long | IT unsigned long | OT signed long
IT == Mesh PointDataContainer identifier: unsigned long
VectorContainer[itk.IT, itk.Array.D] instantiation exists: True

ctest -R "[Pp]ython" -> 176/176 passed, including PythonTypeTest, PythonVerifyTTypeAPIConsistency and PythonTemplateTest.

Not verifiable locally: the defect case is WIN32 + ITK_USE_64BITS_IDS=OFF. Every build available to me resolves ITKM_IT=UL, so what is shown above is that the new path reproduces the correct answer where the old path was also right. Windows CI is the first real executor for the case this targets.

@github-actions github-actions Bot added type:Compiler Compiler support or related warnings area:Python wrapping Python bindings for a class labels Aug 20, 2026

# Mangled names of the C types the wrapping instantiated for itk::SizeValueType,
# itk::IdentifierType and itk::OffsetValueType, from Wrapping/WrapBasicTypes.cmake.
ITK_GLOBAL_WRAPPING_TYPE_ALIASES: dict[str, str] = {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this identifier start with an underscore (as in _ITK_GLOBAL_WRAPPING_TYPE_ALIASES), to indicate that it is only for internal use?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd lean toward keeping it un-prefixed, for consistency with its two immediate siblings in this same file — ITK_GLOBAL_VERSION_STRING (line 182) and ITK_GLOBAL_WRAPPING_BUILD_OPTIONS (line 185) — both of which are equally internal and neither of which is underscore-prefixed.

The established convention here looks like it puts the privacy marker on the consumer side rather than the definition side, e.g. itk/support/build_options.py:

from itkConfig import ITK_GLOBAL_WRAPPING_BUILD_OPTIONS as _itkwrapbo

That is what the as _wrapping_type_aliases in this PR was imitating — but since you and Dzenan both preferred a single name for the dict, I have dropped the rename and instead del the imported name after use, so nothing leaks into itk.support.types either way.

Happy to go the other direction if you'd rather: either underscore-prefix this one alone (accepting the inconsistency), or rename all three ITK_GLOBAL_* names in a separate STYLE: commit so the file stays uniform. Your call — just say which and I'll make the change.

Comment thread Wrapping/Generators/Python/itk/support/types.py Outdated
Comment thread Wrapping/Generators/Python/itk/support/types.py

@dzenanz dzenanz left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally looks good. Niels' suggestions make sense.

Comment thread Wrapping/Generators/Python/itk/support/types.py Outdated
Wrapping/WrapBasicTypes.cmake selects unsigned long long for
itk::IdentifierType only when both WIN32 and ITK_USE_64BITS_IDS hold,
while itk.support.types derived the alias independently. On Windows with
ITK_USE_64BITS_IDS=OFF the wrapping instantiates unsigned long while
itk.IT reported a 64-bit type, so itk.VectorContainer[itk.IT, ...] named
an instantiation that does not exist.

Export the mangled names ITKM_ST, ITKM_IT and ITKM_OT through itkConfig
and look the aliases up from there, so the Python aliases and the
instantiated templates come from one definition.
@hjmjohnson
hjmjohnson force-pushed the comp-itk-identifier-type-from-cmake branch from 2fa8836 to cd67e98 Compare August 20, 2026 17:51
@N-Dekker

Copy link
Copy Markdown
Contributor

Thanks for addressing my comments so far, Hans! For my understanding, the current itk.IT definition is only incorrect on Windows, with ITK_USE_64BITS_IDS=OFF, right?

For the record, itk.IT was introduced by pull request #3502 commit 6a9aca9, July 2022.

Back in 2019, we had some discussion at discourse.itk.org about ITK_USE_64BITS_IDS: Could ITK drop ITK_USE_64BITS_IDS and just do SizeValueType = std::size_t?. At that time, it still appeared useful to support ITK_USE_64BITS_IDS=OFF. Is it still useful nowadays? Why would some users still want to switch off ITK_USE_64BITS_IDS on Windows, nowadays?

@hjmjohnson

Copy link
Copy Markdown
Member Author

Thanks for addressing my comments so far, Hans! For my understanding, the current itk.IT definition is only incorrect on Windows, with ITK_USE_64BITS_IDS=OFF, right?

correct.

@hjmjohnson

Copy link
Copy Markdown
Member Author

Split your ITK_USE_64BITS_IDS question out into #6774 so it doesn't block this PR — with the history from Discourse #2053, the commits that introduced and then defaulted-ON the option, and four options with trade-offs.

One correction worth stating here: OFF is not a Windows-specific state — it is the default everywhere except 64-bit Windows. The guard at itkIntTypes.h:65 requires ULLONG_MAX != ULONG_MAX, so on LP64 (Linux, macOS) the option is a no-op in both positions. It only changes types on Windows LLP64 and on 32-bit targets. That is also why this mismatch survived since #3502 in 2022: every platform where wrapping is routinely built resolves ITKM_IT to UL either way.

@hjmjohnson
hjmjohnson marked this pull request as ready for review August 20, 2026 20:52
@greptile-apps

greptile-apps Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This change makes Python’s ST, IT, and OT aliases follow the CMake-selected wrapped C types. An isolated package-import regression check exercised both Windows identifier-width configurations: with 64-bit IDs disabled, the aliases resolved to UL, UL, and SL; with 64-bit IDs enabled, they resolved to ULL, ULL, and SLL. In both configurations, the aliases exactly matched the selected CMake types and the Python support package imported successfully.

Confidence Score: 5/5

Safe to merge: the changed alias-resolution behavior matches the wrapped C++ type selections in both relevant Windows configurations.

No defects remain. The executed regression harness covered the prior Windows width-mismatch path and confirmed that the checked-out implementation resolves every alias to the configured wrapped type.

Files Needing Attention: No additional files need attention.

Reviews (1): Last reviewed commit: "COMP: Resolve Python ST/IT/OT from the w..." | Re-trigger Greptile

@N-Dekker N-Dekker left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you so far, Hans. Can we please take a little bit more time for this PR? Specifically, does this solves a real problem for end-users nowadays? (As you reported by issue #6774). If it does solve a significant problem, I still have some more detailed questions.

Comment on lines +170 to +172
ST = _c_type_by_mangled_name[ITK_GLOBAL_WRAPPING_TYPE_ALIASES["ST"]]
IT = _c_type_by_mangled_name[ITK_GLOBAL_WRAPPING_TYPE_ALIASES["IT"]]
OT = _c_type_by_mangled_name[ITK_GLOBAL_WRAPPING_TYPE_ALIASES["OT"]]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find the use of two dictionaries here a bit complicated. It may make the code harder to understand for human readers. Would it be possible to simplify these three lines to just:

ST = uint64_t if ITK_USE_64BITS_IDS else uint32_t
IT = ST
OT = int64_t if ITK_USE_64BITS_IDS else int32_t

Then we would only need to make ITK_USE_64BITS_IDS accessible in Python, right? (Assuming ITK_USE_64BITS_IDS is still needed, of course, as discussed at issue #6774.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:Python wrapping Python bindings for a class type:Compiler Compiler support or related warnings

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants