Question

Python Caller Error

  • 14 January 2020
  • 4 replies
  • 79 views

Badge

Hi,

 

I am trying to make use of some code in the PythonCaller to work out the number of working days.

 

I found this code that had been posted.

 

import fme
import fmeobjects

from datetime import timedelta
from datetime import datetime

(MON, TUE, WED, THU, FRI, SAT, SUN) = range(7)
weekends=(SAT,SUN)

def networkdays(start_date, end_date, holidays=[]):
 delta_days = (end_date - start_date).days + 1
 full_weeks, extra_days = divmod(delta_days, 7)
 # num_workdays = how many days/week you work * total # of weeks
 num_workdays = (full_weeks + 1) * (7 - len(weekends))
 # subtract out any working days that fall in the 'shortened week'
 for d in range(1, 8 - extra_days):
 if (end_date + timedelta(d)).weekday() not in weekends:
 num_workdays -= 1
 # skip holidays that fall on weekends
 holidays = [x for x in holidays if x.weekday() not in weekends]
 # subtract out any holidays 
 for d in holidays:
 if start_date <= d <= end_date:
 num_workdays -= 1
 return num_workdays

def processFeature(feature):
 start_date = datetime.strptime(str(feature.getAttribute("pyStartDate")), "%Y%m%d").date()
 end_date = datetime.strptime(str(feature.getAttribute("pyEndDate")), "%Y%m%d").date()
 holidays = [datetime.strptime(date, "%Y%m%d").date() for date in feature.getAttribute("pyHolidays").split("_")]
 
 feature.setAttribute("py_networkdays", networkdays(start_date, end_date, holidays)) 

 

I converted this to python 3 as was unable to run as 2.7 but got this error once converted and could run the code.

 

PythonFactory failed to load python symbol `FeatureProcessor'

Factory proxy not initialized

PythonCaller (PythonFactory): PythonFactory failed to process feature

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

 

After searching I found when getting that error it advised replacing processFeature with FeatureProcessor

 

So I now run this code after the convention and FeatureProcessor change.

 

import fme
import fmeobjects

from datetime import timedelta
from datetime import datetime

(MON, TUE, WED, THU, FRI, SAT, SUN) = list(range(7))
weekends=(SAT,SUN)

def networkdays(start_date, end_date, holidays=[]):
 delta_days = (end_date - start_date).days + 1
 full_weeks, extra_days = divmod(delta_days, 7)
 # num_workdays = how many days/week you work * total # of weeks
 num_workdays = (full_weeks + 1) * (7 - len(weekends))
 # subtract out any working days that fall in the 'shortened week'
 for d in range(1, 8 - extra_days):
 if (end_date + timedelta(d)).weekday() not in weekends:
 num_workdays -= 1
 # skip holidays that fall on weekends
 holidays = [x for x in holidays if x.weekday() not in weekends]
 # subtract out any holidays
 for d in holidays:
 if start_date <= d <= end_date:
 num_workdays -= 1
 return num_workdays

def FeatureProcessor(feature):
 start_date = datetime.strptime(str(feature.getAttribute("pyStartDate")), "%Y%m%d").date()
 end_date = datetime.strptime(str(feature.getAttribute("pyEndDate")), "%Y%m%d").date()
 holidays = [datetime.strptime(date, "%Y%m%d").date() for date in feature.getAttribute("pyHolidays").split("_")]

 feature.setAttribute("py_networkdays", networkdays(start_date, end_date, holidays))

 

I now get this error.

 

Python Exception <AttributeError>: 'NoneType' object has no attribute 'split'

Error encountered while calling function `FeatureProcessor'

PythonCaller (PythonFactory): PythonFactory failed to process feature

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

 

Bit out of my depth with this. Sorry posted so much giving the start to the end of what I have done in case I have messed up along the way.

 

Any idea on how I can fix this error or if there is a better way to do the working days calculations?

 

I have also tried the WorkingDaysCalculator feature I found but this doesn't allow for holiday dates and also won't allow the end date before the start (The start date for me is a target date in my case so this happens)

 

Thanks

 

Kevin

 

 


4 replies

Userlevel 4

Sounds like you have at least one feature missing the mandatory attribute "pyHolidays". I couldn't tell you what it expects, however.

For the future, please make sure to post any code formatted as such, as it's very difficult to read Python code without the proper indentations.
Badge

Apologies for the formatting. I tried to place the code in bold to make a bit easier to see. I will look to format properly in future.

Userlevel 1
Badge +10

pyHolidays needs to not be blank, how are you setting this attribute?

If the target date (end) is before the date (start) I don't think the holidays will work correctly as is.

I'm presuming you want something like the following outcome:

Date (start)

 

 

Start DateEnd DateHolidaysWorking Days13/01/202015/01/2020

 

14/01/2020115/01/202013/01/2020

 

14/01/2020

 

-115/01/202017/02/202014/01/2020

 

2
Badge

pyHolidays needs to not be blank, how are you setting this attribute?

If the target date (end) is before the date (start) I don't think the holidays will work correctly as is.

I'm presuming you want something like the following outcome:

Date (start)

 

 

Start DateEnd DateHolidaysWorking Days13/01/202015/01/2020

 

14/01/2020115/01/202013/01/2020

 

14/01/2020

 

-115/01/202017/02/202014/01/2020

 

2

I have added pyHolidays as a CSV.

 

Not sure I have done this correctly, to be honest.

 

Just been playing with this. I have been able to add the pyHolidays CSV and join to the table so now this is running without the errors.

 

Have this working now amazing.

 

Thanks for the help.

Reply