Skip to main content

I feel like everytime I try the PythonCaller I really struggle with the scripting and usually switch to a start up script to avoid it. Can anyone help me figure out why I don’t have any outputs when I run this in my PythonCaller. 

 

import fme
import fmeobjects
import re

class FeatureProcessor:
    def __init__(self):
        pass

    def input(self, feature):
        """
        Processes a feature to extract and set address components.

        Args:
            feature (fmeobjects.FMEFeature): The feature containing the address attribute.
        """
        # Retrieve the address attribute from the feature
        address = feature.getAttribute('ADDRESS')

        # If the address is missing, set all related attributes to empty strings
        if not address:
            for attr in ['Suite', 'AddressNumber', 'StreetName', 'StreetType', 'Direction', 'Street']:
                feature.setAttribute(attr, '')
            return

        # Split the address into suite and core address parts
        parts = [p.strip() for p in address.split(',', 1)]
        suite = parts[0] if len(parts) == 2 else ''
        address_core = parts[1] if len(parts) == 2 else parts[0]

        # Tokenize the core address and define possible street types and directions
        tokens = address_core.split()
        directions = {'NE', 'NW', 'SE', 'SW'}
        street_types = {
            'ST', 'STREET', 'AVE', 'AVENUE', 'BLVD', 'ROAD', 'RD', 'DR', 'DRIVE', 'TRL', 'TRAIL', 'CRES', 'CRESCENT',
            'WAY', 'PL', 'PLACE', 'LANE', 'LN', 'CLOSE', 'CT', 'COURT', 'HWY', 'HIGHWAY', 'TER', 'TERRACE', 'CIR', 'CIRCLE'
        }

        # Initialize variables for address components
        addr_num = ''
        street_type = ''
        direction = ''
        street_name = ''

        # Extract the address number if it exists
        if tokens and re.match(r'^\d+', tokens[0]):
            addr_num = tokens.pop(0)

        # Extract the direction if it exists at the end of the tokens
        if tokens and tokens[-1].upper() in directions:
            direction = tokens.pop(-1).upper()

        # Extract the street type if it exists at the end of the tokens
        if tokens and tokens[-1].upper() in street_types:
            street_type = tokens.pop(-1).title()

        # The remaining tokens form the street name
        street_name = ' '.join(tokens).title()

        # Construct the full street address
        street = f"{addr_num} {street_name} {street_type} {direction}".strip()

        # Set the extracted attributes back to the feature
        feature.setAttribute('Suite', suite)
        feature.setAttribute('AddressNumber', addr_num)
        feature.setAttribute('StreetName', street_name)
        feature.setAttribute('StreetType', street_type)
        feature.setAttribute('Direction', direction)
        feature.setAttribute('Street', street)

    def close(self):
        """
        Perform any necessary cleanup after processing features.
        """
        pass
 

It seems the last line of your input() method is missing the call that actually outputs your feature. Try adding:

self.pyoutput(feature)

PS, next time please consider formatting your Python code using the Embed Code formatting option, it makes it much easier to read:

 


So in your case you need to add a “self.pyoutput(feature)” line whenever you want features to come out of the PythonCaller.

The input function will get run for every feature that goes in an every time the strip uses the self.pyoutput(feature) method a feature will come out. In your script you haven’t told FME to output any features.

This means you can have a single feature go in and have many features come out. For example you could trigger the read of a database table with a single features and a new feature could come out for each row in the table.
 
I’ve added the lines where I thought it made sense below

import fme
import fmeobjects
import re

class FeatureProcessor:
def __init__(self):
pass

def input(self, feature):
"""
Processes a feature to extract and set address components.

Args:
feature (fmeobjects.FMEFeature): The feature containing the address attribute.
"""
# Retrieve the address attribute from the feature
address = feature.getAttribute('ADDRESS')

# If the address is missing, set all related attributes to empty strings
if not address:
for attr in ['Suite', 'AddressNumber', 'StreetName', 'StreetType', 'Direction', 'Street']:
feature.setAttribute(attr, '')

self.pyoutput(feature)
return

# Split the address into suite and core address parts
parts = [p.strip() for p in address.split(',', 1)]
suite = parts[0] if len(parts) == 2 else ''
address_core = parts[1] if len(parts) == 2 else parts[0]

# Tokenize the core address and define possible street types and directions
tokens = address_core.split()
directions = {'NE', 'NW', 'SE', 'SW'}
street_types = {
'ST', 'STREET', 'AVE', 'AVENUE', 'BLVD', 'ROAD', 'RD', 'DR', 'DRIVE', 'TRL', 'TRAIL', 'CRES', 'CRESCENT',
'WAY', 'PL', 'PLACE', 'LANE', 'LN', 'CLOSE', 'CT', 'COURT', 'HWY', 'HIGHWAY', 'TER', 'TERRACE', 'CIR', 'CIRCLE'
}

# Initialize variables for address components
addr_num = ''
street_type = ''
direction = ''
street_name = ''

# Extract the address number if it exists
if tokens and re.match(r'^\d+', tokens[0]):
addr_num = tokens.pop(0)

# Extract the direction if it exists at the end of the tokens
if tokens and tokens[-1].upper() in directions:
direction = tokens.pop(-1).upper()

# Extract the street type if it exists at the end of the tokens
if tokens and tokens[-1].upper() in street_types:
street_type = tokens.pop(-1).title()

# The remaining tokens form the street name
street_name = ' '.join(tokens).title()

# Construct the full street address
street = f"{addr_num} {street_name} {street_type} {direction}".strip()

# Set the extracted attributes back to the feature
feature.setAttribute('Suite', suite)
feature.setAttribute('AddressNumber', addr_num)
feature.setAttribute('StreetName', street_name)
feature.setAttribute('StreetType', street_type)
feature.setAttribute('Direction', direction)
feature.setAttribute('Street', street)

#output features
self.pyoutput(feature)

def close(self):
"""
Perform any necessary cleanup after processing features.
"""
pass

 

 

 


Amazing, yes thank you this works! Sorry about not embedding the code, it was the first time I posted code into the forum and didn’t realize that option was there.