Making a Time-Tracking Tool in Maya

A study in writing a time-logging tool before a friend has to go to dinner


A few nights ago, I was quietly wasting time on my laptop when a message from a dear friend of mine popped up.

I have an urge to watch Flight of the Navigator again

I missed Frisbee more than anyone and while I couldn’t turn back time to our summers spent frolicking in a field with the original flying disc, I could probably write this script.

A confident reply. I’d better back it up with some fancy jargon so I sound cool.

At this point I’ve opened Maya and have already started writing it.

It’s all true

Challenge accepted. I owed Dear Friend a massive favour for the time I’d once kicked a football into her face really hard.



As with all good tools, I should have started with a clear idea of what I was doing. But a mixture of overconfidence and a passion for adventure got in my way and I started just smashing together some functions and callbacks and getting nowhere.

It was time to get a clear specification laid out. I’ll fire off a message to Dear Friend.

You’re damn right I’m still working on it

My client needed a tool that:

  • That would start and end with a Maya session
  • Could create a log of every file opened during that session and how long the session was open for
  • The overall time spent on each file needed to be calculated at the end of the day

This sounded doable, but I tried to anticipate a few fringe-cases that could trip it up:

  • The tool needed to cope with the user re-opening the same file and carry on logging it as the same session with that file
  • It needed to be able to read the report back into itself, so that should the user end their Maya session and then restart in the same day, the daily log could carry on being appended to

We wanted to get to something that would look something like this:

How am I Going to Store this Data?

Before I even worked out the actual logic of the script, I wanted to work out how I would store this information in a way that made it simple to access the relevant data when I needed it.

I decided the best way was by having a single, global dictionary that I could use to log entries to with the scene file path as the key.

Each entry in the dictionary would be a small class that would have it’s own internal list of logged entries, stored as a simple (start, end) list.

# The logging table is a dictionary which will store all the data

class SceneEntry:
A small class that stores all the information needed for an log entry
def __init__(self):
self.sceneName = cmds.file(query=True,sn=True)
self.loggedTimes = []
self.timeOpened = time.time()
self.timeClosed = None

The other key bit of information I needed to store in this session was the path to the currently opened scene. The reason I needed to do this this was because when Maya’s post-open callback gets triggered, querying the currently opened scene will give you the freshly opened scene’s path and not the scene you just closed.

You’ll need to know the path of the file you just closed so you can look up it’s entry and stop the timer.

# The currently opened scene (stored so we know if the scene has changed when you open a new file)

Well, that bit was easy.

The only other thing you’ll notice is that we’re storing time using Python’s building time.time() method which returns time as a timestamp float value.

At some point I’m going to need to turn this back into something a human can read so I make a little convenience function that will return the timestamp as a nice string. You’ll see this used later when we write out the timestamp into the log

def convertTimeStampToString(timestamp):
Tiny function to format the date
return datetime.datetime.fromtimestamp(timestamp).strftime("%Y-%m-%d %H:%M:%S")

Now, we’ve got to write the main logging function that will get called every time a new scene is opened or a Maya session is ended. Before I start coding this, lets get the flow worked out nicely.

Working Out the Logic Flow

What better way to describe this than with a flow diagram. This is how I planned it out, only in my brain.

So translating that into Python looks like this:

def logTime(quittingMaya=False):
This function gets called when someone opens a file or quits Maya
It logs the data in the main table and writes it out to the file


# Get the path of the scene you just opened
sceneName = cmds.file(query=True,sn=True)

# If the scene name has changed since from the last scene you opened, flag that
sceneChanged = False
if not sceneName == CURRENT_SCENE:
sceneChanged = True

# If there's no entry in the table for this file path
if not sceneName in LOGGING_TABLE.keys():
# Make an entry. The timer starts automatically
print "Creating new entry for " + sceneName
LOGGING_TABLE[sceneName] = SceneEntry()
# If there's an existing entry for the new scene, reset the timer
sceneEntry = LOGGING_TABLE[sceneName]
sceneEntry.timeOpened = time.time()
print "Adding new entry to " + sceneName

# And scene has changed or if you're shutting down Maya
if sceneChanged or quittingMaya:
#Finish the timer for the scene you just closed
print "Stopping logging timer for " + CURRENT_SCENE

# Write out the logging table

# Update the current scene global

At this point I had a nice function that I could fire off and it starts filling up the LOGGING_TABLE dictionary with loads of lovely entries.

Just gotta get this writing out to a file!

Better Update Dear Friend with my Progress.

Not yet.

So fancy


Writing this out to a file

I don’t have much time, Dear Friend is about to go to dinner and I really want to see this through. I had previously said this would take ten minutes. I need some time on the couch to find out why I say these things.

Writing things out should be the easiest part. I want to have a little flow that looks something like.

Which in Python looks like:

# The filepath of the text file we're making (makes a different one with the date on the end)
TABLE_PATH = "%s/TimeLogging_%s.txt" % (DESKTOP_PATH, time.strftime("%Y%m%d"))

Why do I do the date YYMMDD? Because it sorts better in file explorers, that’s why.

Time to check if there’s already an existing file.

# If there's an existing table file, load it in
if os.path.isfile(TABLE_PATH):
print "Reading Existing Logging Table..." + TABLE_PATH

Here’s the function that writes out the logging table. It’s basically iterating over the logging table dictionary and formatting into strings that people can read nicely.

The interesting bit is the section at line 35.

I opted to write all of the dictionary out to some raw data at the bottom of the file. This was so if the file already existed when you started a new Maya session, you could read this data back in and rebuild the logging table before you start adding to it again.

Reading the raw data just looks like this:

You iterate over the existing files looking for the //DATA// flag, at which point you start tokenizing the lines and adding it all back to the dictionary.

That dinner reservation is safe as houses.


The Darkest Hour

So I sent it over to Dear Friend for a test run. It’s been working fine on my machine for a good dozen of tests.

Ah crap. She’s across the pond and I’m in Cambridge, how am I meant to debug this? I begin to panic.

I start lying.

Get that smile off your face you smug b***ard


I’d been writing this script in Windows, just happily assuming that I can write these files to the desktop with a lovely bulletproof query like this:

DESKTOP_PATH = os.path.join(os.path.join(os.environ['USERPROFILE']), 'Desktop')

But, as I’m sure you know, Linux deals with paths rather differently so I need to write a switch that will find the Linux desktop if you’re in a Linux environment.

Luckily we’ve got a handy little module in Python to get the platform name.

import platform

# Are we running Windows or something else?
# Define the desktop path
if platform.system() == "Windows":
DESKTOP_PATH = os.path.join(os.path.join(os.environ['USERPROFILE']), 'Desktop')
DESKTOP_PATH = os.path.join(os.path.join(os.path.expanduser('~')), 'Desktop')

Now we’re Linux safe. But will we make dinner?

“Wise from your gwave”

Her Uber is just around the corner. Will the tool work in time?


The Final Script

Well here’s the final thing!

So far so good, it’s been working for a few days without any problems so I think it’s solved the problem. I can see this being handy for freelancers who need to keep a close eye on their working hours or just Maya users who like to spy on themselves. People are weird, no judgement here.

If you want to try this yourself then just download this script into your local Maya scripts directory as “” and add “import timeLogger” to your file in the same directory.

This could be better in all kinds of ways, so feel free to grab it and build on it. I’d love to hear how you get on.

Thanks for reading.

And thank you to my scripting muse for the adventure, and for the delicious beer you sent over as thanks.

That was casual wasn’t it.

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.