output Total Task Time

Try this:

emailArgs = StringCollection()
emailArgs.Add("-SendEmail")
emailArgs.Add("-subject")
emailArgs.Add("email")
emailArgs.Add("-to")
emailArgs.Add("me@address.com")
emailArgs.Add("-message")
emailArgs.Add("here it is")
ClientUtils.ExecuteCommand( emailArgs )

I think the missing ‘-’ is the problem.

…that works, so close! thanks

Is there a way to set/change the Monitor’s filter jobs via Python in my script? Here is the example:

User runs the script via Deadline Monitor
The user selects a Job Pool in a dialog box
The script then sets Deadline Monitor “Filter Job Pool” to the selected pool so the current monitor (the one the user is at) displays only those filtered jobs.

Does that make sense? I looked for commands but nothing stood out. Does that functionality exist?

Unfortunately, no, the filters are not exposed to the script API.

In the ScriptUIExample.py there is nifty bit of code for incrementing a progress bar. Is there a way for my script to communicate with the progress bar at the bottom right corner of the Deadline Monitor?

No, there is nothing in the API to hook up to that progress bar.

Cheers,

  • Ryan

Ok, here it is, my completed script. As it is posted, the script asks the user to select a job pool (we make a new pool for each project or job in the shop) and then it returns all the total render time for all completed jobs in that pool. In a meeting there was the question of “can we get a little bit of human double checking to make sure this thing is staying on course”? So the user running the script can verify the number of completed jobs that the Deadline Monitor is displaying vs the # of completed jobs the script found. (This is an optional step, but made some feel more comfortable that our computer friends weren’t just making stuff up!) Finally the script can email and/or save the spreadsheet that was created to the user’s specified locations or address.

There are only 2 prerequisites that I can think of:

  1. Running a version of Deadline that can make use of Python .net (5.1 or later I believe)
  2. Install xlwt libraries from python-excel.org, I installed these into the Python folder on the repository and added a pointer to the folder in the Repository settings (its discussed in earlier posts in this thread).

Feel free to use it how ever you wish, or if you are a novice you might learn a thing or 2 by poking through it since I’m a Python novice myself. Also, I’d love feedback if you anyone wants to school me on how to do things better, faster, smarter! I’m sure there are a million better ways to integrate Deadline with other billing tools, but for our small shop this gets the jobs done (for now).

brad

MY PROJECT!

[code]#Python.NET

from System.Collections.Specialized import *
from System.Drawing import *
from System.IO import *
from Deadline.Scripting import *
import os
import xlwt
from xlwt import Workbook, easyxf, Borders
from datetime import datetime
import shutil

Global variables

scriptDialog = None
location = ‘\\queue\DeadlineRepository\scripts\General\RenderBilling\output\’
filename = None
job = None
poollist = []
jobtimelist = []
totaltimelist = []
cmp = None
tt = None
runtime2 = None

def main():
global scriptDialog

job-pool selection window

scriptDialog = DeadlineScriptEngine.GetScriptDialog()
scriptDialog.SetSize( 400, 150 )
scriptDialog.SetTitle( "Job Selection" )
scriptDialog.SetIcon( Path.Combine( GetRootDirectory(), "scripts/General/RenderBilling/RenderBilling.ico" ) )

scriptDialog.AddRow()
scriptDialog.AddControl( "DefineTool1", "LabelControl", "  * * BEFORE RUNNING SCRIPT, SET FILTER JOB POOL TO DESIRED JOB * *", 380, -1 )
scriptDialog.EndRow()
scriptDialog.AddRow()
scriptDialog.AddControl( "DefineTool2", "LabelControl", "This tool will calculate the total render time for job billing.", 380, -1 )
scriptDialog.EndRow()
scriptDialog.AddRow()
scriptDialog.AddControl( "PoolLabel", "LabelControl", "Select the job:", 100, -1 )
scriptDialog.AddControl( "PoolBox", "PoolComboControl", "job", 200, -1 )
scriptDialog.EndRow()

scriptDialog.AddRow()
scriptDialog.AddControl( "DummyLabel1", "LabelControl", "", 205, -1 )
scriptDialog.EndRow()
scriptDialog.AddRow()
scriptDialog.AddControl( "DummyLabel2", "LabelControl", "Once you hit Select, be patient. Another window will appear with your total.", 385, -1 )
scriptDialog.EndRow()

scriptDialog.AddRow()
scriptDialog.AddControl( "DummyLabel3", "LabelControl", "", 175, -1 )
selectButton = scriptDialog.AddControl( "SelectButton", "ButtonControl", "Select", 100, -1 )
selectButton.ValueModified += SelectButtonPressed
closeButton = scriptDialog.AddControl( "CloseButton", "ButtonControl", "Close", 100, -1 )
closeButton.ValueModified += CloseButtonPressed
scriptDialog.EndRow()

scriptDialog.ShowDialog( False )

def SelectButtonPressed( *args ):
global job

get job from selection box

job = scriptDialog.GetValue( "PoolBox" )

check to make sure a job was selected

if job == "none":
# pop up with error
	scriptDialog.ShowMessageBox( "    Please select a job, you can't calculate NONE.    ", "Error Message")
else:
	CalculateJob()

def CalculateJob( *args ):
global scriptDialog
global job
global location
global filename
global poollist
global jobtimelist
global totaltimelist
global cmp
global tt
scriptDialog.CloseDialog()

begin = datetime.now()

get list of job IDs for the pool that are completed, archived or not

filter = "jobPool="
filter += job
poolArgs = StringCollection()
poolArgs.Add("GetJobIdsFilterAnd")
poolArgs.Add( filter )
poolArgs.Add( "status=Completed" )

poollist = ClientUtils.ExecuteCommandAndGetOutput( poolArgs )
poollist = poollist.split()

if poollist == []:
	NoHours(job)
else:

declaring some variables

	tt = 0	# total job time tallied
	jt = 0  # job time


	cmp = len(poollist)	# number of jobs that are completed

get time for each job

	for i in range(len(poollist)):
		jobid = str(poollist[i])
		jobArgs = StringCollection()
		jobArgs.Add("GetJobTaskTotalTime")
		jobArgs.Add( jobid )
		jobtime = ClientUtils.ExecuteCommandAndGetOutput( jobArgs )
		d = float(jobtime[20:22])
		h = float(jobtime[24:26])
		m = float(jobtime[28:30])
		s = float(jobtime[32:34])
		jt = (86400*d+3600*h+60*m+s)
		jt /= 3600
		tt += jt

add job time to list

		jobtimelist.append(jt)		

add total job time to list

		totaltimelist.append(tt)				

pop up if no hours exist

	if tt == 0:
		NoHours()

how long did this process take

	end = datetime.now()
	runtime = end - begin

round total render time to 2 decimal points

	ttr = str(round(tt,2))	

results and email window

	scriptDialog = DeadlineScriptEngine.GetScriptDialog()
	scriptDialog.SetSize( 450, 390 )
	scriptDialog.SetTitle( "Results for job " + job )
	scriptDialog.SetIcon( Path.Combine( GetRootDirectory(), "scripts/General/RenderBilling/RenderBilling.ico" ) )
	
	scriptDialog.AddRow()
	scriptDialog.AddControl( "DummyLabel9", "LabelControl", "", 8, -1 )
	scriptDialog.AddControl( "QuickTotalLabel", "LabelControl", "Total render hours: ", 110, -1)
	scriptDialog.AddControl( "QuickTotal", "ReadOnlyTextControl", ttr, 50, -1 )
	scriptDialog.EndRow()
	
	scriptDialog.AddRow()
	scriptDialog.AddControl( "DummyLabel8", "LabelControl", "", 100, -1 )
	scriptDialog.EndRow()

	scriptDialog.AddGroupBox( "GroupBox1", "Verification Information", True )
	scriptDialog.AddRow()
	scriptDialog.AddControl( "WhoLabel", "LabelControl", "Enter your name or initials: ", 140, -1)
	scriptDialog.AddControl( "Whoisthis", "TextControl", "", 240, -1 )
	scriptDialog.EndRow()
	scriptDialog.AddRow()
	scriptDialog.AddControl( "CheckNumbersLabel", "LabelControl", "Enter the number of completed jobs Deadline shows in the Monitor:", 330, -1)
	scriptDialog.AddControl( "CheckNumbers", "TextControl", "", 50, -1 )
	scriptDialog.EndRow()
	scriptDialog.AddRow()
	scriptDialog.AddControl( "ReadOnlyTextLabel", "LabelControl", "The script found this many completed jobs: ", 330, -1 )
	scriptDialog.AddControl( "ReadOnlyTextBox", "ReadOnlyTextControl", str(cmp), 50, -1 )
	scriptDialog.EndRow()		
	scriptDialog.AddRow()
	scriptDialog.AddSelectionControl( "CheckBox", "CheckBoxControl", False, " Check the box if the script and Deadline match.", 400, -1 )
	scriptDialog.EndRow()
	scriptDialog.EndGroupBox( False )
	
	scriptDialog.AddRow()
	scriptDialog.AddControl( "DummyLabel7", "LabelControl", "", 100, -1 )
	scriptDialog.EndRow()

	scriptDialog.AddRow()
	scriptDialog.AddControl( "ComboLabel", "LabelControl", "Select An Action:", 110, -1 )
	scriptDialog.AddComboControl( "CBox", "ComboControl", "Save and Email", ("Save and Email","Save only","Email only","Discard results"), 320, -1 )
	scriptDialog.EndRow()

	scriptDialog.AddRow()
	scriptDialog.AddControl( "SaveFolderLabel", "LabelControl", "Select folder:", 110, -1 )
	scriptDialog.AddSelectionControl( "SaveFolder", "FolderBrowserControl", "", "", 320, -1 )
	scriptDialog.EndRow()
	scriptDialog.AddRow()
	scriptDialog.AddControl( "EmailLabel", "LabelControl", "Enter email address:", 110, -1 )
	scriptDialog.AddControl( "EmailAddress", "TextControl", "", 320, -1 )
	scriptDialog.EndRow()
	scriptDialog.AddRow()
	scriptDialog.AddControl( "MultipleEmailSpacer", "LabelControl", "", 110, -1 )
	scriptDialog.AddControl( "MultipleEmail", "LabelControl", "(Multiple addresses need to be comma seperated.)", 285, -1 )
	scriptDialog.EndRow()


	scriptDialog.AddRow()
	scriptDialog.AddControl( "DummyLabel5", "LabelControl", "", 205, -1 )
	scriptDialog.EndRow()

	scriptDialog.AddRow()
	scriptDialog.EndRow()
	scriptDialog.AddRow()
	scriptDialog.AddControl( "DefineTool10", "LabelControl", "Script run time: " + str(runtime)[:7], 380, -1)
	scriptDialog.EndRow()	
	
	scriptDialog.AddRow()
	scriptDialog.AddControl( "DummyLabel6", "LabelControl", "", 225, -1 )
	selectButton = scriptDialog.AddControl( "SendButton", "ButtonControl", "OK", 100, -1 )
	selectButton.ValueModified += SendButtonPressed
	closeButton = scriptDialog.AddControl( "DiscardButton", "ButtonControl", "Discard", 100, -1 )
	closeButton.ValueModified += DiscardButtonPressed
	scriptDialog.EndRow()
	
	scriptDialog.ShowDialog( False )

def SendButtonPressed( *args ):
global scriptDialog
global poollist
global jobtimelist
global totaltimelist
global cmp
global tt
global runtime2
begin = datetime.now()
email = scriptDialog.GetValue( “EmailAddress” )
action = scriptDialog.GetValue( “CBox” )
save = scriptDialog.GetValue( “SaveFolder” )
who = scriptDialog.GetValue( “Whoisthis” )
checknumbers = scriptDialog.GetValue( “CheckNumbers” )
checkbox = scriptDialog.GetValue( “CheckBox” )
scriptDialog.CloseDialog()

jobname = []
plugname = []
username = []
cmpdate = []

get time for each job

for i in range(len(poollist)):
	jobid = str(poollist[i])

add job name to list

	nameArgs = StringCollection()
	nameArgs.Add("GetJobSetting")
	nameArgs.Add(jobid)
	nameArgs.Add("name")
	jobname.append( ClientUtils.ExecuteCommandAndGetOutput( nameArgs ))

add plug-in to list

	plugArgs = StringCollection()
	plugArgs.Add("GetJobSetting")
	plugArgs.Add(jobid)
	plugArgs.Add("pluginname")
	plugname.append( ClientUtils.ExecuteCommandAndGetOutput( plugArgs ))		

add artist to list

	userArgs = StringCollection()
	userArgs.Add("GetJobSetting")
	userArgs.Add(jobid)
	userArgs.Add("username")
	username.append( ClientUtils.ExecuteCommandAndGetOutput( userArgs ))

add completion date to list

	dateArgs = StringCollection()
	dateArgs.Add("GetJobSetting")
	dateArgs.Add(jobid)
	dateArgs.Add("completeddatetime")
	cmpdate.append( ClientUtils.ExecuteCommandAndGetOutput( dateArgs ))	

##### WRITE EXCEL DOC

define excel doc and sheet

wb = xlwt.Workbook()
ws = wb.add_sheet('RenderStats')

style1 = xlwt.XFStyle()

style1.num_format_str = ‘D-MMM-YY’

font2 = xlwt.Font()
font2.colour_index = 1
style2 = xlwt.XFStyle()
style2.font = font2

define a style for a bottom border

borders = Borders()
borders.bottom = Borders.MEDIUM
styleB = xlwt.XFStyle()
styleB.borders = borders

avgrentime = round(tt/cmp,2)
datemin = min(cmpdate)[:10]
datemax = max(cmpdate)[:10]

line01 = "Job: " + job
line02 = "Report date: " + str(datetime.now().strftime('%Y-%m-%d')) + " @ " + str(datetime.now().strftime('%H:%M'))
line03 = "Total render time: " + str(round(tt,2)) + " hours"
line04 = "Number of jobs submitted: " + str(cmp) + " jobs"
line05 = "Average render time: " + str(avgrentime) + " hours"
line06 = "Project dates: " + str(datemin) + " to " + str(datemax)

ws.write(0, 1, line01)
ws.write(1, 1, line02)
ws.write(2, 1, line03)
ws.write(3, 1, line04)
ws.write(4, 1, line05)
ws.write(5, 1, line06)
ws.write(1, 5, "Validation by: " + str(who))
ws.write(2, 5, "User entered job count: " + str(int(checknumbers)))
if int(checknumbers) == int(cmp):
	ws.write(3, 5, "These numbers match")
else:
	mistmatch = abs(int(checknumbers) - int(cmp))
	ws.write(3, 5, "There is a mismatch of " + str(int(mistmatch)) + " jobs")
if checkbox == True:
	ws.write(4, 5, str(who) + " verifies this data")
if checkbox == False:
	ws.write(4, 5, "Data does not have user verification")	
maxCell = len(poollist)
maxCell += 8
formulaCheck = "IF(COUNTIF(J9:J" + str(maxCell) + ",\"yes\")>0,\"Time discrepancies: Yes\",\"Time discrepancies: No\")"
ws.write(5, 5, xlwt.Formula(formulaCheck))

establish table headers

ws.write(7, 0, "#", styleB)
ws.write(7, 1, "ID", styleB)
ws.write(7, 2, "Name", styleB)
ws.write(7, 3, "Application", styleB)
ws.write(7, 4, "Artist", styleB)
ws.write(7, 5, "Date", styleB)
ws.write(7, 6, "Time", styleB)
ws.write(7, 7, "Deadline Tally", styleB)
ws.write(7, 8, "Excel Tally", styleB)
ws.write(7, 9, "Discrepancies?", styleB)

declare max length variables

maxId = 20
maxName = 8
maxApp = 8 
maxArtist = 5
maxDate = 8
maxTime = 4
maxTallyDl = 10
maxTallyEx = 8
maxDscp = 10

start for loop here

for r in range(len(poollist)):
	myRow = r + 8
	myCell = r + 9
	jobCounter = r+1
	formula1 = "round(sum(L9:L" + str(myCell) + "),2)"
	formula2 = "if(H" + str(myCell) + "-I" + str(myCell) + "=0,\"\",\"yes\")"
	formulaJT = "round(L" + str(myCell) + ",2)"
	formulaTT = "round(M" + str(myCell) + ",2)"
	ws.write(myRow, 0, jobCounter)
	ws.write(myRow, 1, poollist[r])
	ws.write(myRow, 2, jobname[r])
	ws.write(myRow, 3, plugname[r])
	ws.write(myRow, 4, username[r])
	ws.write(myRow, 5, cmpdate[r][:10])
	ws.write(myRow, 6, xlwt.Formula(formulaJT))		
	ws.write(myRow, 7, xlwt.Formula(formulaTT))		
	ws.write(myRow, 11, jobtimelist[r], style2)
	ws.write(myRow, 12, totaltimelist[r], style2)
	ws.write(myRow, 8, xlwt.Formula(formula1))

discrepancy

	ws.write(myRow, 9, xlwt.Formula(formula2))

find max lengths

	if maxName < len(jobname[r]):
		maxName = len(jobname[r])
	if maxApp < len(plugname[r]):
		maxApp = len(plugname[r])
	if maxArtist < len(username[r]):
		maxArtist = len(username[r])
	if maxTime < len(str(round(jobtimelist[r],2))):
		maxTime = len(str(round(jobtimelist[r],2)))

set column widths

ws.col(0).width = 1250
ws.col(1).width = (maxId+4)*256 # max letter length + 4
ws.col(2).width = (maxName+1)*256
ws.col(3).width = (maxApp+4)*256
ws.col(4).width = (maxArtist+4)*256
ws.col(5).width = (maxDate+4)*256
ws.col(6).width = (maxTime+4)*256
ws.col(7).width = (maxTallyDl+4)*256
ws.col(8).width = (maxTallyEx+4)*256
ws.col(9).width = (maxDscp+4)*256

spreadsheet NOT SAVED yet

filename = job + '_' + str(datetime.now().strftime('%Y-%m-%d-%H-%M')) + '.xls'

###### EXCEL FILE DONE

if action == "Save and Email":
	wb.save(location + filename)
	shutil.copy2(location + filename,save + filename)
	emailArgs = StringCollection()
	emailArgs.Add("-SendEmail")
	emailArgs.Add("-subject")
	emailArgs.Add("Render farm totals for " + job)
	emailArgs.Add("-to")
	emailArgs.Add( email )
	emailArgs.Add("-message")
	emailArgs.Add(line01 + "\r" + line02 + "\r" + line03 + "\r" + line04 + "\r" + line05 + "\r" + line06)
	emailArgs.Add("-attach")
	emailArgs.Add(location + filename)		
	ClientUtils.ExecuteCommand( emailArgs )

how long did this process take

	end = datetime.now()
	runtime2 = end - begin
	TaskCompleted()
if action == "Save only":
	wb.save(location + filename)
	shutil.copy2(location + filename,save + filename)

how long did this process take

	end = datetime.now()
	runtime2 = end - begin
	TaskCompleted()		
if action == "Email only":
	wb.save(location + filename)
	emailArgs = StringCollection()
	emailArgs.Add("-SendEmail")
	emailArgs.Add("-subject")
	emailArgs.Add("Render farm totals for " + job)
	emailArgs.Add("-to")
	emailArgs.Add( email )
	emailArgs.Add("-message")
	emailArgs.Add(line01 + "\r" + line02 + "\r" + line03 + "\r" + line04 + "\r" + line05 + "\r" + line06)
	emailArgs.Add("-attach")
	emailArgs.Add(location + filename)
	ClientUtils.ExecuteCommand( emailArgs )

how long did this process take

	end = datetime.now()
	runtime2 = end - begin
	TaskCompleted()		
if action == "Discard results":
	CloseButtonPressed()

def DiscardButtonPressed( *args ):
global scriptDialog
scriptDialog.CloseDialog()

def CloseButtonPressed( *args ):
global scriptDialog
scriptDialog.CloseDialog()

def NoHours( *args ):
global scriptDialog
global job
scriptDialog.CloseDialog()
scriptDialog.ShowMessageBox( " There are no completed renders for job " + x + " ", “No Render Time”)

def TaskCompleted():
global scriptDialog
global runtime2
scriptDialog.CloseDialog()
scriptDialog.ShowMessageBox( " Task completed successfully. (Script run time: " + str(runtime2)[:7] + ") ", “Finished!!!”) [/code]