1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
|
# ==========================================================================
#
# Copyright NumFOCUS
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0.txt
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# ==========================================================================*/
# a short program to check that ITK's API is consistent across the library.
import itk
import sys
from itk.support.template_class import itkTemplate
itk.auto_progress(2)
# must force the load to return all the names with dir(itk)
itk.force_load()
wrongAPI = 0
totalAPI = 0
# a list of classes to exclude. Typically, the classes with a custom New()
# method, which return a subclass of the current class.
exclude = [
# The following class API could be updated.
"GDCMSeriesFileNames",
"HistogramToRunLengthFeaturesFilter",
"HistogramToTextureFeaturesFilter",
"ScalarImageToRunLengthFeaturesFilter",
"ScalarImageToTextureFeaturesFilter",
# These classes are just ignored.
"ScanlineFilterCommon", # Segfault
"templated_class",
"auto_pipeline",
"pipeline",
"cvar",
]
def checkGetOutputConsistency(o, t):
totalAPI = 0
wrongAPI = 0
try:
i = o.New()
except AttributeError:
# We only care about object that can be constructed with New() since
# we only worry about ITK ProcessObjects.
return totalAPI, wrongAPI
# Skip abstract classes
if i.GetNameOfClass() != t:
return totalAPI, wrongAPI
# Only check itkProcessObjects
if issubclass(o, itk.ProcessObject):
totalAPI = 1
numberOfIndexedOutputs = i.GetNumberOfIndexedOutputs()
has_GetOutput = hasattr(i, "GetOutput")
if ((numberOfIndexedOutputs == 0) == has_GetOutput) or (
numberOfIndexedOutputs >= 1 and not has_GetOutput
):
msg = (
"%s: Wrong API: `GetOutput()` %s found, NumberOfIndexedOutputs: %d"
% (
i.GetNameOfClass(),
"not" * (not has_GetOutput),
numberOfIndexedOutputs,
)
)
print(msg, file=sys.stderr)
wrongAPI = 1
elif numberOfIndexedOutputs >= 1:
i.GetOutput()
return totalAPI, wrongAPI
# Test that `itkProcessObject` derived class have an API that is consistent
# with what is expected in the Python wrapping.
# Check that all the itkProcessObjects (to which a `__call()__` function is
# added in Python) can actually run that call function. More specifically,
# check that they...
for t in dir(itk):
if t not in exclude:
T = itk.__dict__[t]
# first case - that's a templated class
if isinstance(T, itkTemplate) and len(T) > 0:
# Most templated object would simply instantiate the first type
# listed if `New()` is called directly on the template type, but
# this is not the case for all templates
# (e.g. itk.ImageFileReader).
# So we manually select the first type available.
# Note: converting to `list` to be compatible with Python3
o = T[list(T.keys())[0]]
tot, w = checkGetOutputConsistency(o, t)
totalAPI += tot
wrongAPI += w
else:
tot, w = checkGetOutputConsistency(T, t)
totalAPI += tot
wrongAPI += w
print(f"{totalAPI} classes checked.")
if wrongAPI:
print(f"{wrongAPI} classes are not providing the API.", file=sys.stderr)
sys.exit(1)
|