Dev Space

Customize and extend the power of Alteryx with SDKs, APIs, custom tools, and more.
SOLVED

Python SDK - Distinguish left and right input in the def ii_push_record Method

Chriszou
8 - Asteroid

Hi, 

 

I have created a Python plugin that has two input steams (left and right). When Alteryx is calling the "def ii_push_record", is there a way we could tell if a given in_record is associated to the left or right input stream ? Below is the snippet of the Python push_record method. Thanks for your help  ! 

 

def ii_push_record(self, in_record: object) -> bool:
"""
Preserving the state of the incoming record data, since the reference to a record dies beyond this point.
Called when an input record is being sent to the plugin.
:param in_record: The data for the incoming record.
:return: False if method calling limit (record_cnt) is hit.
"""

self.record_list.append(self.record_info_in.construct_record_creator())
self.record_copier.copy(self.record_list[-1], in_record)

4 REPLIES 4
tlarsen7572
11 - Bolide
11 - Bolide

The association happens when Alteryx calls pi_add_incoming_connection on your plugin class.  One of the parameters of pi_add_incoming_connection is the name of the incoming connection.  This function needs to return an object that implements the incoming interface.  I would recommend using a separate class to implement the incoming interface; it keeps things a bit more separated and cleaner.

 

One option is to process the records directly in the incoming interface class.  An example might look something like this:

 

 

class MyPlugin:
    def pi_add_incoming_connection(self, str_type, str_name):
        return Input(str_name)

# The rest of the pi_ methods are defined in this class class Input: def __init__(self, input_str_name: str): self.input_str_name = input_str_name def ii_push_records(self, in_record): if self.input_str_name == 'Left': doSomething(in_record) elif self.input_str_name == 'Right': doSomethingElse(in_record)

# the rest of the ii_ methods are defined in this class

In this example the incoming connection name is passed to the Input class, which then executes ii_push_records differently based on the value.

 

 

If, for some reason, you need to handle the logic in the plugin class, you could pass a reference of the plugin class to your incoming interface class and then call the necessary methods on the plugin.  An example might look like this:

 

class MyPlugin:
    def pi_add_incoming_connection(self, str_type, str_name):
        return Input(self,str_name)

    def processRecord(self,input_str_name: str, in_record):
        if input_str_name == 'Left':
            doSomething(in_record)
        elif input_str_name == 'Right':
            doSomethingElse(in_record)

# The rest of the pi_ methods are defined in this class
class Input: def __init__(self, parent: MyPlugin, input_str_name: str): self.parent = parent self.input_str_name = input_str_name def ii_push_records(self, in_record): self.parent.processRecord(self.input_str_name,in_record)

# the rest of the ii_ methods are defined in this class

 

Chriszou
8 - Asteroid

Thanks for your quick response ! 

 

I think below codes should work but have a few questions and hope you can clarify. (I am still learning the Python SDK, please forgive all my dump questions):

 

1, for the return statement (return Input(str_name)) in the MyPlugin class. Can you explain where the Input() function come from ? I noticed sample code returns a IncomingInterface object here so want to confirm what this line of code is doing.

 

2, for the Input class: I noticed you wrote the init method as follow "def __init__(self, input_str_name: str):". The sample code was written as follow " __init__(self, parent: object)". Is this going to work since Alteryx might not recognize the "input_str_name: str" argument. 

 

 

class MyPlugin:
    def pi_add_incoming_connection(self, str_type, str_name):
        return Input(str_name)

# The rest of the pi_ methods are defined in this class class Input: def __init__(self, input_str_name: str): self.input_str_name = input_str_name def ii_push_records(self, in_record): if self.input_str_name == 'Left': doSomething(in_record) elif self.input_str_name == 'Right': doSomethingElse(in_record)

# the rest of the ii_ methods are defined in this class I 

 

tlarsen7572
11 - Bolide
11 - Bolide

The Input() statement is the constructor for the Input class.  When you create a class in Python, you instantiate an instance of that class using its name.  Python links it all together behind the scenes.  The __init__ method in the Input class is what ends up getting called when you run Input().  As long as the Input class implements all of the IncomingInterface methods, then returning Input() will return an IncomingInterface object.

 

For 2, I think it would still work, but it might be nice if the Input class holds a reference to the plugin class, so you can, e.g., call methods on the Alteryx engine object which is usually stored in the plugin class.  You should be able to do something like this and everything will play nicely with Alteryx:

 

class MyPlugin:
    def pi_add_incoming_connection(self, str_type, str_name):
        return Input(self, str_name)

    # The rest of the pi_ methods are defined in this class

class Input:
    def __init__(self, parent: MyPlugin, input_str_name: str):
        self.parent = parent
        self.input_str_name = input_str_name

    def ii_push_records(self, in_record):
        if self.input_str_name == 'Left':
            doSomething(in_record)
        elif self.input_str_name == 'Right':
            doSomethingElse(in_record)

    # the rest of the ii_ methods are defined in this class

Hope that helps!

 

 

Chriszou
8 - Asteroid

Thanks for your clarification ! It worked ! Much appreciated for your help !