Skip to main content

When python caller errors out.
It does not show error line number.

 

Message Type: fme::internal::_v0:🇵🇾:Exception
Python Exception <GEOSException>: LocateFailureException: Could not locate vertex.
🟢06-Report (PythonFactory): PythonFactory failed to close properly

What is triggering this error? Is it a PythonCaller, or a transformer that is part of FME?

If it’s a PythonCaller, can you please show the relevant part of the code.

You can also consider using the traceback module to provide (much) more detailed error messages, see https://docs.python.org/3/library/traceback.html


Thank you for the response.
Yes, a python caller i’m using for generating custom reports.
It is this part:

        try:
            m.add_gdf(
                concave_gdf.concave_hull(float(fme.macroValuesl"CONCAVE_RATIO"])),
                fc=CONCAVE_HULL_COLOR,
                lw=1,
                ec="none",
            )
        except Exception as e:
            logger.logMessageString(
                f"▶️▶️▶️▶️▶️▶️▶️ Error plotting concave hull for {feature_type_name}: {e}"
            )


Try removing the try...except block altogether. What you’re doing is effectively logging the error message but then ignoring the actual exception. It’s ofter better simply to let the exception raise itself, with all its details. That often leaves more possibilities for the Python interpreter to give a more detailed stack trace.

Alternatively, you can add “raise” on a new line under “logger.logMessageString(...” to re-raise the exception.


Sorry, forgot to mention that I added the try except after I got hold of the error line number.
Would it be possible that it is because the code is not directly enclose in the def process_group
The code is part of function that I define at the end of my python caller
outside the class definition


You can try something like this to include more information in any exceptions occurring in your PythonCallers:

import fmeobjects
import traceback


class FeatureProcessor(object):
"""Template Class Interface:
When using this class, make sure its name is set as the value of the 'Class
to Process Features' transformer parameter.
"""

def __init__(self):
"""Base constructor for class members."""
self.feature_count = 0
self.log = fmeobjects.FMELogFile()

def _log(self, message, severity=fmeobjects.FME_INFORM):
"""
Sends message to the FME log file and console window.
Severity must be one of FME_INFORM, FME_WARN, FME_ERROR,
FME_FATAL, FME_STATISTIC, or FME_STATUSREPORT.
"""
self.log.logMessageString(message, severity)

def input(self, feature):
"""This method is called for each FME Feature entering the
PythonCaller. If knowledge of all input Features is not required for
processing, then the processed Feature can be emitted from this method
through self.pyoutput(). Otherwise, the input FME Feature should be
cached to a list class member and processed in process_group() when
'Group by' attributes(s) are specified, or the close() method.

:param fmeobjects.FMEFeature feature: FME Feature entering the
transformer.
"""
try:
self.feature_count += 1

# ###########################
# Your code goes here...
# ###########################

self.pyoutput(feature)

except:
self._log('='*78, fmeobjects.FME_ERROR)
message = "{}({}) exception at feature number {}:".format(
self.factory_name, self.__class__.__name__, self.feature_count)
self._log(message, fmeobjects.FME_ERROR)
self._log('-'*78, fmeobjects.FME_ERROR)
for line in traceback.format_exc().splitlines():
self._log(line, fmeobjects.FME_ERROR)
self._log('='*78, fmeobjects.FME_ERROR)
if feature:
self.log.logFeature(feature, fmeobjects.FME_ERROR)
message = "An error occurred in {} method '{}'. See log for details.".format(
self.factory_name, self.__class__.__name__)
raise fmeobjects.FMEException(message)

As you can see, it uses the traceback module from the Python standard library to dump the entire stack trace with line numbers if an exception occurrs, then terminates your workspace.


Thank you.
I will try that out and get back to you soon.

Here is the gist of the python caller: https://gist.github.com/salahelfarissi/ea0fc67528bfc2bfdcdbc42139ef2431


You can try something like this to include more information in any exceptions occurring in your PythonCallers:

import fmeobjects
import traceback


class FeatureProcessor(object):
"""Template Class Interface:
When using this class, make sure its name is set as the value of the 'Class
to Process Features' transformer parameter.
"""

def __init__(self):
"""Base constructor for class members."""
self.feature_count = 0
self.log = fmeobjects.FMELogFile()

def _log(self, message, severity=fmeobjects.FME_INFORM):
"""
Sends message to the FME log file and console window.
Severity must be one of FME_INFORM, FME_WARN, FME_ERROR,
FME_FATAL, FME_STATISTIC, or FME_STATUSREPORT.
"""
self.log.logMessageString(message, severity)

def input(self, feature):
"""This method is called for each FME Feature entering the
PythonCaller. If knowledge of all input Features is not required for
processing, then the processed Feature can be emitted from this method
through self.pyoutput(). Otherwise, the input FME Feature should be
cached to a list class member and processed in process_group() when
'Group by' attributes(s) are specified, or the close() method.

:param fmeobjects.FMEFeature feature: FME Feature entering the
transformer.
"""
try:
self.feature_count += 1

# ###########################
# Your code goes here...
# ###########################

self.pyoutput(feature)

except:
self._log('='*78, fmeobjects.FME_ERROR)
message = "{}({}) exception at feature number {}:".format(
self.factory_name, self.__class__.__name__, self.feature_count)
self._log(message, fmeobjects.FME_ERROR)
self._log('-'*78, fmeobjects.FME_ERROR)
for line in traceback.format_exc().splitlines():
self._log(line, fmeobjects.FME_ERROR)
self._log('='*78, fmeobjects.FME_ERROR)
if feature:
self.log.logFeature(feature, fmeobjects.FME_ERROR)
message = "An error occurred in {} method '{}'. See log for details.".format(
self.factory_name, self.__class__.__name__)
raise fmeobjects.FMEException(message)

As you can see, it uses the traceback module from the Python standard library to dump the entire stack trace with line numbers if an exception occurrs, then terminates your workspace.


Thank you.
It worked like a breeze.

 


Also, I noticed that I had Log Debug unchecked.

Now I get the error line number without using the traceback module.
 

 


Reply