diff --git a/Wrapping/Generators/Python/Tests/PythonTemplateTest.py b/Wrapping/Generators/Python/Tests/PythonTemplateTest.py index e429b5c9744..b32ab72f0d6 100644 --- a/Wrapping/Generators/Python/Tests/PythonTemplateTest.py +++ b/Wrapping/Generators/Python/Tests/PythonTemplateTest.py @@ -119,6 +119,17 @@ median_kwarg = itk.MedianImageFilter.New(Input=reader.GetOutput()) assert itk.class_(median) == itk.class_(median_kwarg) +# filter type determined by the input passed as a primary input name input +median_primary_kwarg = itk.MedianImageFilter.New(Primary=reader.GetOutput()) +assert itk.class_(median) == itk.class_(median_primary_kwarg) + +# First RequiredInputName: "FixedImage" +fixed_image = reader.GetOutput() +moving_image = fixed_image +pde_registration = itk.PDEDeformableRegistrationFilter.New( + FixedImage=fixed_image, MovingImage=moving_image +) + # to a filter with a SetImage method calculator = itk.MinimumMaximumImageCalculator[ImageType].New(reader) # not GetImage() method here to verify it's the right image diff --git a/Wrapping/Generators/Python/Tests/extras.py b/Wrapping/Generators/Python/Tests/extras.py index aa03f539194..96eed9c743f 100644 --- a/Wrapping/Generators/Python/Tests/extras.py +++ b/Wrapping/Generators/Python/Tests/extras.py @@ -163,6 +163,18 @@ def custom_callback(name, progress): image = itk.imread(filename, imageio=itk.PNGImageIO.New()) assert type(image) == itk.Image[itk.RGBPixel[itk.UC], 2] +# Python functional interface that determines the filter type +# based on the primary input (dispatch) +image = itk.imread(filename, itk.UC) +# positional argument +filtered_positional = itk.median_image_filter(image) +# required primary named input argument +filtered_kwarg = itk.median_image_filter(primary=image) +comparison = itk.comparison_image_filter( + filtered_positional, filtered_kwarg, verify_input_information=True +) +assert np.sum(comparison) == 0.0 + # imread using a dicom series image = itk.imread(sys.argv[8]) image0 = itk.imread(sys.argv[8], series_uid=0) diff --git a/Wrapping/Generators/Python/itk/support/extras.py b/Wrapping/Generators/Python/itk/support/extras.py index 5116b086655..c4c90272777 100644 --- a/Wrapping/Generators/Python/itk/support/extras.py +++ b/Wrapping/Generators/Python/itk/support/extras.py @@ -39,6 +39,7 @@ from .helpers import wasm_type_from_image_type, image_type_from_wasm_type from .helpers import wasm_type_from_mesh_type, mesh_type_from_wasm_type, python_to_js from .helpers import wasm_type_from_pointset_type, pointset_type_from_wasm_type +from .helpers import snake_to_camel_case from .xarray import xarray_from_image, image_from_xarray @@ -1552,17 +1553,6 @@ def search(s: str, case_sensitive: bool = False) -> List[str]: # , fuzzy=True): return res -def _snake_to_camel(keyword: str): - # Helpers for set_inputs snake case to CamelCase keyword argument conversion - _snake_underscore_re = re.compile("(_)([a-z0-9A-Z])") - - def _underscore_upper(match_obj): - return match_obj.group(2).upper() - - camel = keyword[0].upper() - if _snake_underscore_re.search(keyword[1:]): - return camel + _snake_underscore_re.sub(_underscore_upper, keyword[1:]) - return camel + keyword[1:] def set_inputs( @@ -1656,7 +1646,7 @@ def SetInputs(self, *args, **kargs): # (Ex: itk.ImageFileReader.UC2.New(SetFileName='image.png')) if attribName not in ["auto_progress", "template_parameters"]: if attribName.islower(): - attribName = _snake_to_camel(attribName) + attribName = snake_to_camel_case(attribName) attrib = getattr(new_itk_object, "Set" + attribName) # Do not use try-except mechanism as this leads to @@ -2162,7 +2152,7 @@ def ipython_kw_matches(text: str): namespace = split_name_parts[:-1] function_name = split_name_parts[-1] # Find corresponding object name - object_name = _snake_to_camel(function_name) + object_name = snake_to_camel_case(function_name) # Check that this object actually exists try: object_callable_match = ".".join(namespace + [object_name]) diff --git a/Wrapping/Generators/Python/itk/support/helpers.py b/Wrapping/Generators/Python/itk/support/helpers.py index 5ff75eb8270..32a16fda540 100644 --- a/Wrapping/Generators/Python/itk/support/helpers.py +++ b/Wrapping/Generators/Python/itk/support/helpers.py @@ -40,6 +40,18 @@ pass +def snake_to_camel_case(keyword: str): + # Helpers for set_inputs snake case to CamelCase keyword argument conversion + _snake_underscore_re = re.compile("(_)([a-z0-9A-Z])") + + def _underscore_upper(match_obj): + return match_obj.group(2).upper() + + camel = keyword[0].upper() + if _snake_underscore_re.search(keyword[1:]): + return camel + _snake_underscore_re.sub(_underscore_upper, keyword[1:]) + return camel + keyword[1:] + def camel_to_snake_case(name): snake = re.sub("(.)([A-Z][a-z]+)", r"\1_\2", name) snake = re.sub("([a-z0-9])([A-Z])", r"\1_\2", snake) diff --git a/Wrapping/Generators/Python/itk/support/template_class.py b/Wrapping/Generators/Python/itk/support/template_class.py index 9601df7976c..3a14333a527 100644 --- a/Wrapping/Generators/Python/itk/support/template_class.py +++ b/Wrapping/Generators/Python/itk/support/template_class.py @@ -30,6 +30,7 @@ from itk.support import base from itk.support.extras import output from itk.support.types import itkCType +from itk.support.helpers import snake_to_camel_case import math from collections.abc import Mapping @@ -718,6 +719,20 @@ def ttype_for_input_type(keys_l, input_type_l): # try to find a type suitable for the input provided input_type = output(cur).__class__ keys = ttype_for_input_type(keys, input_type) + else: + inst = self.values()[0].New() + if hasattr(inst, "GetRequiredInputNames"): + required_input_names = inst.GetRequiredInputNames() + if len(required_input_names) > 0: + primary_input_name = required_input_names[0] + kwargs_camel = {snake_to_camel_case(k): v for k,v in kwargs.items()} + if primary_input_name in kwargs_camel.keys(): + input_type = output(kwargs_camel[primary_input_name]).__class__ + keys = ttype_for_input_type(keys, input_type) + if not hasattr(inst, f"Set{primary_input_name}"): + arg_0 = kwargs_camel.pop(primary_input_name) + kwargs = kwargs_camel + args = (arg_0,) + args if len(keys) == 0: if not input_type: