Skip to main content

I have been given the following python code but get errors every time i try to run it, anyone know what is wrong...

import fmeobjects

def FeatureProcessor(feature): to_concatenate = ("buildingNumber", "throughfare", "dependantthroughfare")

# Modify as needed

join_string = ","

# Modify as needed

result = join_string.join([feature.getAttribute(attr) \\

for attr in to_concatenate if feature.getAttribute(attr)])

feature.setAttribute("CONCATENATED", result)

 

What error is logged?


Does it work if you separate the list comprehension into for and if components?


Here are the errors

Python Exception <SyntaxError>: unexpected character after line continuation character (<string>, line 7)

Error executing string `import<space>fmeobjects<space><space><space><lf>def<space>FeatureProcessor<openparen>feature<closeparen>:to_concatenate<space>=<space><openparen><quote>buildingNumber<quote><comma><space><quote>throughfare<quote><comma><space><quote>dependantthroughfare<quote><closeparen><space><lf>#<space>Modify<space>as<space>needed<space><space><space><space><space><lf>join_string<space>=<space><quote><comma><quote><space><lf>#<space>Modify<space>as<space>needed<space><space><space><space><space><lf>result<space>=<space>join_string.join<openparen><openbracket>feature.getAttribute<openparen>attr<closeparen><space><backslash><space>for<space>attr<space>in<space>to_concatenate<space>if<space>feature.getAttribute<openparen>attr<closeparen><closebracket><closeparen><space><space><space><lf>feature.setAttribute<openparen><quote>CONCATENATED<quote><comma><space>result<closeparen>'

Factory proxy not initialized

PythonCaller(PythonFactory): PythonFactory failed to process feature

A fatal error has occurred. Check the logfile above for details


Could you please repost the script as-is, using a code block?


import fmeobjects

def FeatureProcessor(feature):to_concatenate = ("buildingNumber", "throughfare", "dependantthroughfare")

# Modify as needed

join_string = ","

# Modify as needed

result = join_string.join([feature.getAttribute(attr) \\ for attr in to_concatenate if feature.getAttribute(attr)])

feature.setAttribute("CONCATENATED", result)

 


Could this be solved by replacing the PythonCaller by a StringConcatenator transformer?

That seems so much easier.


I would expect the code to work with the following formatting

 

import fmeobjects

def FeatureProcessor(feature): 
  Â  to_concatenate = ("buildingNumber", "throughfare", "dependantthroughfare")
  Â  # Modify as needed

  Â  join_string = ","

  Â  # Modify as needed

  Â  result = join_string.join( feature.getAttribute(attr)\
    for attr in to_concatenate if feature.getAttribute(attr)])

  Â  feature.setAttribute("CONCATENATED", result)

 

 


I would expect the code to work with the following formatting

 

import fmeobjects

def FeatureProcessor(feature): 
  Â  to_concatenate = ("buildingNumber", "throughfare", "dependantthroughfare")
  Â  # Modify as needed

  Â  join_string = ","

  Â  # Modify as needed

  Â  result = join_string.join( feature.getAttribute(attr)\
    for attr in to_concatenate if feature.getAttribute(attr)])

  Â  feature.setAttribute("CONCATENATED", result)

 

 

ignore the Â, that's a problem with the knowledgebase upgrade.

 

Put to_concatenate on a separate (indented) line from the function definition.

Either break the list comprehension line, or don't, if you do there can be nothing after it.

result = join_string.join(sfeature.getAttribute(attr)\
for attr in to_concatenate if feature.getAttribute(attr)])

or

result = join_string.join(ofeature.getAttribute(attr)for attr in to_concatenate if feature.getAttribute(attr)])

in the second case, it's all on one line.


Could this be solved by replacing the PythonCaller by a StringConcatenator transformer?

That seems so much easier.

I am assuming they don't want ,, when the attribute is empty/missing.


I am assuming they don't want ,, when the attribute is empty/missing.

Then create an attribute for the concatenation character, like this:

And the StringConcatenator to do the magic:


You could also use this code:

import fmeobjects

def get_attributes(feature, attr_names):
  Â Â for attr_name in attr_names:
  Â  Â  Â  value = feature.getAttribute(attr_name)
  Â  Â  Â Â if value:
  Â  Â  Â  Â  Â Â yield value

def FeatureProcessor(feature): 
  Â  to_concatenate = ("buildingNumber", "throughfare", "dependantthroughfare")

  Â Â # Modify as needed
  Â  result = ",".join(get_attributes(feature, to_concatenate))

  Â Â # Modify as needed
  Â  feature.setAttribute("CONCATENATED", result)

 

I'm not a big fan of list comprehensions in this particular case, because they call feature.getAttribute() twice, which is unnecessary. This is why I created the generator function get_attributes(), which only returns the attributes with a "truthy" value.

Please be aware that if the feature attribute contains the number 0 (stored as integer or float), this value is considered to be "falsy", which means that it will not be concatenated in the result. What's worse though, is that the script will choke on the str.join() call if 1 or more attributes aren't string values (which is actually what your attribute names suggest).

To tackle both problems, you could replace the get_attributes() function with this block:

def get_attributes(feature, attr_names):
  Â Â for attr_name in attr_names:
  Â  Â  Â  value = feature.getAttribute(attr_name)
  Â  Â  Â Â if value not in ('', None):
  Â  Â  Â  Â  Â  yield format(value)

This will work as long as you don't have any non-ASCII characters in your attributes...


You could also use this code:

import fmeobjects

def get_attributes(feature, attr_names):
  Â Â for attr_name in attr_names:
  Â  Â  Â  value = feature.getAttribute(attr_name)
  Â  Â  Â Â if value:
  Â  Â  Â  Â  Â Â yield value

def FeatureProcessor(feature): 
  Â  to_concatenate = ("buildingNumber", "throughfare", "dependantthroughfare")

  Â Â # Modify as needed
  Â  result = ",".join(get_attributes(feature, to_concatenate))

  Â Â # Modify as needed
  Â  feature.setAttribute("CONCATENATED", result)

 

I'm not a big fan of list comprehensions in this particular case, because they call feature.getAttribute() twice, which is unnecessary. This is why I created the generator function get_attributes(), which only returns the attributes with a "truthy" value.

Please be aware that if the feature attribute contains the number 0 (stored as integer or float), this value is considered to be "falsy", which means that it will not be concatenated in the result. What's worse though, is that the script will choke on the str.join() call if 1 or more attributes aren't string values (which is actually what your attribute names suggest).

To tackle both problems, you could replace the get_attributes() function with this block:

def get_attributes(feature, attr_names):
  Â Â for attr_name in attr_names:
  Â  Â  Â  value = feature.getAttribute(attr_name)
  Â  Â  Â Â if value not in ('', None):
  Â  Â  Â  Â  Â  yield format(value)

This will work as long as you don't have any non-ASCII characters in your attributes...

Oh dear, this new <code> style formatting in the Knowledge Base is absolutely horrible...


Oh dear, this new <code> style formatting in the Knowledge Base is absolutely horrible...

I agree, it's really terrible. I think Safe is working on it, however...


Alternatively, FME String functions might be helpful. e.g.

@ReplaceRegEx(@Trim(@CurrentAttribute(),","),",{2,}",",")

0684Q00000ArKVPQA3.png


Reply