Skip to content

Multi-port transformers

Adding an input port

Note

This functionality is new to FME 2024 and requires fmetools>=0.9.0.

By default, transformers have a single input port. Here are the steps to add another input port to a transformer:

  1. Open the transformer definition FMXJ in FME Transformer Designer.
  2. Rename the original input port by selecting the port and editing its Configuration. By default, the original input port has no identifier, but an Execution Template Identifier is required when adding additional input ports.

    Setting Value
    Execution Instance Identifier
    Execution Template Identifier Input1
    Display Name Input1
    Description First input port

    Note

    The Execution Instance Identifier must be left blank for all input ports, as required by the TeeFactory.

  3. Add a new input port using the Port button from the top menu and selecting Input. Add Input Port Transformer Designer

  4. Edit the new input port's Configuration:

    Setting Value
    Execution Instance Identifier
    Execution Template Identifier Input2
    Display Name Input2
    Description Second input port
  5. Open the Execution Instructions pane from the View menu.

  6. In the execution instructions, edit the original TeeFactory so that it only handles features from Input1.

    Execution Instructions
    # Put config values onto input feature from `Input1` as internal-prefixed attributes.
    FACTORY_DEF {*} TeeFactory
       FACTORY_NAME { $(XFORMER_NAME)_Input1_CATCHER }
       $(INPUT_Input1_LINES)
       OUTPUT { FEATURE_TYPE $(XFORMER_NAME)_Input1_READY
          @SupplyAttributes(___XF_VERSION, 1)
          $(FME_PARM_VAL_LIST)
       } 
    

    Note

    @SupplyAttributes(___XF_VERSION, 1) is required for usage of TransformerParameterParser. For information on parameter parsing, refer to the Hello World guide.

  7. Add another TeeFactory that handles features from Input2.

    Execution Instructions
    # Put config values onto input feature from `Input1` as internal-prefixed attributes.
    FACTORY_DEF {*} TeeFactory
        FACTORY_NAME { $(XFORMER_NAME)_Input1_CATCHER }
        $(INPUT_Input1_LINES)
        OUTPUT { FEATURE_TYPE $(XFORMER_NAME)_Input1_READY
           @SupplyAttributes(___XF_VERSION, 1)
           $(FME_PARM_VAL_LIST)
        }
    
    # Put config values onto input feature from `Input2` as internal-prefixed attributes.
    FACTORY_DEF {*} TeeFactory
        FACTORY_NAME { $(XFORMER_NAME)_Input2_CATCHER }
        $(INPUT_Input2_LINES)
        OUTPUT { FEATURE_TYPE $(XFORMER_NAME)_Input2_READY
           @SupplyAttributes(___XF_VERSION, 1)
           $(FME_PARM_VAL_LIST)
        } 
    

  8. Update the PythonFactory to handle input coming from both TeeFactories.
    Execution Instructions
    # Pass input feature to Python.
    # Remove all internal-prefixed attributes before emitting feature
    # through the correct output port.
    FACTORY_DEF {*} PythonFactory
        FACTORY_NAME { $(XFORMER_NAME) }
        INPUT { Input1 FEATURE_TYPE $(XFORMER_NAME)_Input1_READY }
        INPUT { Input2 FEATURE_TYPE $(XFORMER_NAME)_Input2_READY }
        SYMBOL_NAME fme_demogreeter.transformer.TransformerImpl
        PY_OUTPUT_TAGS { Output <Rejected> }
        OUTPUT { Output FEATURE_TYPE $(OUTPUT_Output_FTYPE)
           @RemoveAttributes(fme_regexp_match,^___XF_.*$)
           $(OUTPUT_Output_FUNCS) }
        OUTPUT { <Rejected> FEATURE_TYPE $(OUTPUT_<Rejected>_FTYPE)
           @RemoveAttributes(fme_regexp_match,^___XF_.*$)
           $(OUTPUT_<Rejected>_FUNCS) }
    
  9. In the PythonFactory, add a PY_INPUT_TAGS clause. For more information on the PY_INPUT_TAGS clause, refer to the PythonFactory section in the FME Factory and Function Documentation.
    Execution Instructions
    # Pass input feature to Python.
    # Remove all internal-prefixed attributes before emitting feature
    # through the correct output port.
    FACTORY_DEF {*} PythonFactory
        FACTORY_NAME { $(XFORMER_NAME) }
        PY_INPUT_TAGS { Input1 Input2 }
        INPUT { Input1 FEATURE_TYPE $(XFORMER_NAME)_Input1_READY }
        INPUT { Input2 FEATURE_TYPE $(XFORMER_NAME)_Input2_READY }
        SYMBOL_NAME fme_demogreeter.transformer.TransformerImpl
        PY_OUTPUT_TAGS { Output <Rejected> }
        OUTPUT { Output FEATURE_TYPE $(OUTPUT_Output_FTYPE)
           @RemoveAttributes(fme_regexp_match,^___XF_.*$)
           $(OUTPUT_Output_FUNCS) }
        OUTPUT { <Rejected> FEATURE_TYPE $(OUTPUT_<Rejected>_FTYPE)
           @RemoveAttributes(fme_regexp_match,^___XF_.*$)
           $(OUTPUT_<Rejected>_FUNCS) }
    
  10. A transformer with multiple input ports will need to use a different set of Python methods than a transformer with a single input port. These methods are available in the FMEEnhancedTransformer. An example of a Python transformer implementation for a single input port can be found in the Python transformer implementation section in the Hello World guide. This example can be updated to handle multiple input ports by using setup_from() and receive_feature_from():

    class TransformerImpl(FMEEnhancedTransformer):
       """
       The Python implementation of the DemoGreeter transformer, updated to handle 
       multiple input ports. Each instance of the transformer in the workspace 
       has an instance of this class.
       """
    
       params: TransformerParameterParser
       version: int
    
       def setup_from(self, first_feature: FMEFeature, input_tag: str):
           """
           Initialization steps based the first feature received by the transformer.
           """
           super().setup_from(first_feature, input_tag)
           # Get transformer version from internal attribute on first feature,
           # and load its parameter definitions.
           # Note: TransformerParameterParser requires >=b24145 when running on FME Flow.
           self.version = int(first_feature.getAttribute("___XF_VERSION"))
           self.params = TransformerParameterParser(
               "example.my-package.DemoGreeter",
               version=self.version,
           )
    
       def receive_feature_from(self, feature: FMEFeature, input_tag: str):
           # Pass internal attributes on feature into parameter parser.
           # Then get the parsed value of the First Name parameter.
           # By default, these methods assume a prefix of '___XF_'.
           self.params.set_all(feature)
           first_name = self.params.get("FIRST_NAME")
    
           # Set the output attributes, and output the feature.
           feature.setAttribute("_greeting", "Hello, {}!".format(first_name))
           feature.setAttribute("_input_tag", input_tag)    # For this demo
           self.pyoutput(feature)
    
    For more information, refer to the FMEEnhancedTransformer documentation.

Adding an output port

Note

This functionality is new to FME 2024 and requires fmetools>=0.8.0.

By default, transformers generated with the FME Transformer Designer have two output ports: a standard Output port and a <Rejected> port. Here are the steps to add another output port to a transformer:

  1. Open the transformer definition FMXJ in FME Transformer Designer.
  2. Add a new output port using the Port button from the top menu and selecting Output. Add Output Port Transformer Designer
  3. Edit the new output port's Configuration:

    Setting Value
    Execution Instance Identifier Output2
    Display Name Output2
    Description Another output port
  4. Open the Execution Instructions pane from the View menu.

  5. In the execution instructions, update the PythonFactory's PY_OUTPUT_TAGS clause to include the new output tag. For more information on the PY_OUTPUT_TAGS clause, refer to the PythonFactory section in the FME Factory and Function Documentation.
    Execution Instructions
    # Pass input feature to Python.
    # Remove all internal-prefixed attributes before emitting feature
    # through the correct output port.
    FACTORY_DEF {*} PythonFactory
        FACTORY_NAME { $(XFORMER_NAME) }
        INPUT { FEATURE_TYPE $(XFORMER_NAME)_READY }
        SYMBOL_NAME fme_demogreeter.transformer.TransformerImpl
        PY_OUTPUT_TAGS { Output Output2 <Rejected> }
        OUTPUT { Output FEATURE_TYPE $(OUTPUT_Output_FTYPE)
            @RemoveAttributes(fme_regexp_match,^___XF_.*$)
            $(OUTPUT_Output_FUNCS) }
        OUTPUT { <Rejected> FEATURE_TYPE $(OUTPUT_<Rejected>_FTYPE)
            @RemoveAttributes(fme_regexp_match,^___XF_.*$)
            $(OUTPUT_<Rejected>_FUNCS) }
    
  6. In the same PythonFactory, add an OUTPUT clause for the new output tag.
    Execution Instructions
    # Pass input feature to Python.
    # Remove all internal-prefixed attributes before emitting feature
    # through the correct output port.
    FACTORY_DEF {*} PythonFactory
        FACTORY_NAME { $(XFORMER_NAME) }
        INPUT { FEATURE_TYPE $(XFORMER_NAME)_READY }
        SYMBOL_NAME fme_demogreeter.transformer.TransformerImpl
        PY_OUTPUT_TAGS { Output Output2 <Rejected> }
        OUTPUT { Output FEATURE_TYPE $(OUTPUT_Output_FTYPE)
            @RemoveAttributes(fme_regexp_match,^___XF_.*$)
            $(OUTPUT_Output_FUNCS) }
        OUTPUT { Output2 FEATURE_TYPE $(OUTPUT_Output2_FTYPE)
            @RemoveAttributes(fme_regexp_match,^___XF_.*$)
            $(OUTPUT_Output2_FUNCS) }
        OUTPUT { <Rejected> FEATURE_TYPE $(OUTPUT_<Rejected>_FTYPE)
            @RemoveAttributes(fme_regexp_match,^___XF_.*$)
            $(OUTPUT_<Rejected>_FUNCS) }
    
  7. To output features from the new output port, use .pyoutput(feature, output_tag="Output2") in the Python transformer implementation. For more information on .pyoutput, refer to the pyoutput documentation.