1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
# -*- coding: utf-8 -*- ## Copyright 2019 Trevor van Hoof and Jan Pijpers. ## Licensed under the Apache License, Version 2.0 ## Downloaded from https://janpijpers.com or https://gumroad.com/janpijpers ## See the license file attached or on https://www.janpijpers.com/script-licenses/ ''' Name: youtubeUrlToName Description: Get the name of a video from a youtube link. it handles the reading of the youtube html page. its a nice example on how to parse any html page. Note this might change in the future as youtube tends to change its page quite often. ''' from HTMLParser import HTMLParser import urllib class HtmlYoutubeTitleFinder(HTMLParser): def __init__(self): HTMLParser.__init__(self) ## Create a variable to hold the title once we found it. self.title = None def handle_starttag(self, tag, attributes): ''' Here we overwrite the handle_starttag function. This function gets called for each tag the html parser finds. There are tons of places where you can find the title of a video in a youtube html page but this seemd to work well :param tag: :param attributes: :return: ''' if not tag == 'span': ## We only want 'span' tags. If its not span. Just return. return ## Store all attribute name and value pairs. ## could also be a dict but doesnt matter much. names = [] values = [] for name, value in attributes: names.append(name ) values.append(value ) if 'id' in names: id_index = names.index("id") if "eow-title" == values[id_index]: title_index = names.index("title") self.title = values[title_index] #print values def get_title(self): return self.title titleFinder = HtmlYoutubeTitleFinder() ## Read all the data and make sure its properly decoded. #Liquid Drum and Bass Mix #60 data = urllib.urlopen("https://www.youtube.com/watch?v=aJoo79OwZEI").read().decode('utf-8') titleFinder.feed( data ) print titleFinder.get_title() |
Category Archives: Scripts
Export save data from a connected xbox one
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
# -*- coding: utf-8 -*- ## Copyright 2019 Trevor van Hoof and Jan Pijpers. ## Licensed under the Apache License, Version 2.0 ## Downloaded from https://janpijpers.com or https://gumroad.com/janpijpers ## See the license file attached or on https://www.janpijpers.com/script-licenses/ ''' Name: exportXboxSaveDataToDisk Description: script that exports the save data from your connected xbox to disk you do have to be in xbox developer mode I think. also you need to have the xbox xdk more info about the command here https://docs.microsoft.com/en-us/gaming/xbox-live/storage-platform/connected-storage/connected-storage-xb-storage ''' ## Xbox quick save script import os import datetime import subprocess SCID = "<your personal configuration identifier>" USER_ACCOUNT = "an@example.com" def exportSaveGame( savePath ): saveBin = r'"C:\Program Files (x86)\Microsoft Durango XDK\bin\xbstorage.exe" ' command = 'export "{}" /msa:{} /f /scid:{}'.format(savePath, USER_ACCOUNT, SCID) print subprocess.check_output(saveBin + command ) ## Ask the user for a file name description = raw_input("Write a filename for the savegame:") ## construct path baseDirectory = r"C:\saveGames" fullFileName = "{}_{}_xboxSaveGame.xml".format(description, datetime.datetime.now().date()) fullPath = os.path.join(baseDirectory, fullFileName) ## export the save game exportSaveGame(fullPath) |
Intercept the stdOut and stdErr to a log file
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# -*- coding: utf-8 -*- ## Copyright 2019 Trevor van Hoof and Jan Pijpers. ## Licensed under the Apache License, Version 2.0 ## Downloaded from https://janpijpers.com or https://gumroad.com/janpijpers ## See the license file attached or on https://www.janpijpers.com/script-licenses/ ''' Name: interceptStdOutAndStdErr Description: intercept the std out and write it to a log file. it could cause a bunch of errors if any file operations are called on an std pipe though XD need to implement the std pipe functions in the class but you get the idea i hope. ''' import sys import tempfile import uuid import time import os ## Make a temp output folder to keep track of the logs. TEMP_DIR = os.path.join(tempfile.gettempdir(), "StdOut") if not os.path.exists(TEMP_DIR): os.makedirs(TEMP_DIR) class stdOverwrite( object ): ''' Should also add a get attr for any unimplemented std pipe functions like all the file functions ''' def __init__( self, stdPipe, pipeName= "_output" ): self._terminal = stdPipe unique_filename = str(uuid.uuid4()) logPath = os.path.join(TEMP_DIR, unique_filename+"_{}.log".format(pipeName)) self.log = open( logPath , "w") print "Saving: ", pipeName, " to: ", logPath def write( self, message ): self._terminal.write( message ) self.log.write(message) self.log.flush() def close( self ): self._terminal.close() self.log.close() def flush(self): self._terminal.flush() sys.stdout = stdOverwrite(sys.stdout, "stdOut") sys.stderr = stdOverwrite(sys.stderr, "stdErr") print "漢字カタカナ" raise Exception("ble") ## this should all have been written to the log files in the temp folder |
Run a python function daily.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
# -*- coding: utf-8 -*- ## Copyright 2019 Trevor van Hoof and Jan Pijpers. ## Licensed under the Apache License, Version 2.0 ## Downloaded from https://janpijpers.com or https://gumroad.com/janpijpers ## See the license file attached or on https://www.janpijpers.com/script-licenses/ ''' Name: daylyRunFunction Description: Simple task scheduler to run at a daily interval. ''' import datetime import time import sched SCHEDULER = sched.scheduler(time.time,time.sleep) def repeat_action( message, timing ): ''' Do whatever magic you want to do here :D :param message: :param timing: :return: ''' print "Run forrest run!" ## Create the next scheduled event run_schedule_daily(repeat_action, *timing) def run_schedule_daily( function, hours = 0,minutes = 0, seconds = 0 ): ## what time of the day do you want to run this runTime = datetime.time(hour = hours, minute= minutes, second = seconds) nowPlus = datetime.datetime.combine(datetime.datetime.now(), runTime) if nowPlus <= datetime.datetime.now(): nowPlus = nowPlus + datetime.timedelta(days = 1) tTuple = time.mktime(nowPlus.timetuple()) SCHEDULER.enterabs(tTuple, 1, function, ("",(hours, minutes, seconds),)) print "Next run scheduled for: ", nowPlus run_schedule_daily(repeat_action, hours = 14,minutes =45, seconds = 0) SCHEDULER.run() |
Get time in iso format in a string.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
# -*- coding: utf-8 -*- ## Copyright 2019 Trevor van Hoof and Jan Pijpers. ## Licensed under the Apache License, Version 2.0 ## Downloaded from https://janpijpers.com or https://gumroad.com/janpijpers ## See the license file attached or on https://www.janpijpers.com/script-licenses/ ''' Name: timeInIsoStandardFormat Description: For whatever reason I found it hard to get python to output a timestamp of a continuous string with all info in it. Hence making this function. Im sure there should be a better way to do this buuuuttttt this works XD ''' from datetime import datetime def get_now_time( ): ''' I think this is called the iso format timestamp. I think in python 3 you can do this a lot easier but I keep this as a usefull time manipulation example Just prints a timestamp in a neat string with timezone information. 2019-12-08T09:32:55.423000+09:00 :return: ''' ## Diff local now and utcnow localnow = datetime.now() utcnow = datetime.utcnow() # compute the time difference in seconds tzd = localnow - utcnow secs = tzd.total_seconds() # get a positive or negative prefix for the timezone prefix = '+' if secs < 0: prefix = '-' secs = abs(secs) ## fix the remaining seconds. # print the local time with the difference, correctly formatted suffix = "%s%02d:%02d" % (prefix, secs/3600, secs/60%60) return "%s%s" % (localnow.isoformat('T'), suffix) print get_now_time() |
Find json section in other text.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
# -*- coding: utf-8 -*- ## Copyright 2019 Trevor van Hoof and Jan Pijpers. ## Licensed under the Apache License, Version 2.0 ## Downloaded from https://janpijpers.com or https://gumroad.com/janpijpers ## See the license file attached or on https://www.janpijpers.com/script-licenses/ ''' Name: jsonFromBlob Description: simple example on how to read json data that has noise / random data surrounding it. in a nutshell it just finds everything between { and } at the beginning of a line. ''' import re data = """ dsjkfkjdsaf;lkjsadklfjlksadjfklsjdfjlksajfks < random data XD { "contents": "", "file_type": "json", "listy_things": [ { "key": "sleutel", "value": "gratis" } ], "version": { "major_version": 0, "minor_version": 1 } } jfkdsjfkdsajfsajlkfdsajfjskfdslkj other random data /o/ { "list": [ "entry" ], } } """ import json pattern = re.compile(r'{(.+?)\n}\n', flags = re.DOTALL) for x in pattern.findall(data): jsonData = eval("{%s}"%x) print json.dumps(jsonData, indent=4) |
Extract paths from a string
On occasion i get the request to find a bunch of paths from a blob of text. Hence trying to figure out how to do this with a nice regex function. This is my favorite one so far.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
# -*- coding: utf-8 -*- ## Copyright 2019 Trevor van Hoof and Jan Pijpers. ## Licensed under the Apache License, Version 2.0 ## Downloaded from https://janpijpers.com or https://gumroad.com/janpijpers ## See the license file attached or on https://www.janpijpers.com/script-licenses/ ''' Name: pathsFromString Description: a regex solution that finds the paths from a string. pro tip: this wonderfull site https://regex101.com if you write any regex add "/codegen?language=python" this will give you a python generated script. ''' import re import os def extract_paths_from_string( string, requiresExt = False ): """ Returns a list of file paths found in the string i.e. sdkjflkjfakjkfjakljf,lasf://sdjkjsdfa/fjskaljf/dfsdf.exe,fdsjfksj, returns lasf://sdjkjsdfa/fjskaljf/dfsdf.exe whitespace file paths are not supported in this case """ ''' regex magic: [a-zA-Z] one a,b,c.. character [\:] a colon (\\|\/) a backslash or forward slash or |\\\\ two backslashes |\/\/) or two forward slashes [a-zA-Z0-9\/\.\\:]* any a,b,c dot 0 to 9 character but not a colon. ''' ## Search the string with the provided expression regex = r"([a-zA-Z][\:](\\|\/)|\\\\|\/\/)[a-zA-Z0-9_\-\/\.\\:]*" matches = re.finditer(regex, string, re.MULTILINE) paths = [] ## if we found any path for match in matches: path = match.group() if requiresExt and os.path.splitext(path)[1]: ## If we require an extension and we have an extension, return paths.append(path) elif not requiresExt: ## if we dont reqruire a nextension, return the path ## we could do a warning message here saying we found a path but no extension paths.append(path) return paths test_str = (u"{'C:/this/is/an/example.tesst':'ble'}json\n" "<xml>\\\\test/is/an/example.tesst<html>\n" "//test\\is\\an\\example.tesst\n" "*otherMagi*//test\\is\\an\\example\\<end> \n\n" "whatC:/this/is/an/example.tesst#%@$%@#\n" "a\\\\test/is/an/exampl_-0112371987509e.tesst#@&^%$&^%\n" "drag//test\\is\\an\\e-xample.tesst$@!$#@$!asdfds\\\\abc\\def g:\\bleee\n" "regex//a/nightmare//of\\slashes //a.saaa.;;fdsfws[ewrw") print extract_paths_from_string( test_str , requiresExt=False) |
Catch close console script.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# -*- coding: utf-8 -*- ## Copyright 2019 Trevor van Hoof and Jan Pijpers. ## Licensed under the Apache License, Version 2.0 ## Downloaded from https://janpijpers.com or https://gumroad.com/janpijpers ## See the license file attached or on https://www.janpijpers.com/script-licenses/ ''' Name: catchCloseRequest Description: How to handle user closing the command prompt with ctrl-c alt-f4 or pressing the x button of the window. Also "run a function on exit". windows only i guess. ''' from ctypes import wintypes, WINFUNCTYPE import signal import ctypes import time MESSAGE_BOX = ctypes.windll.user32.MessageBoxW def _ctrl_handler(sig): """ Handle a sig event and return 0 to terminate the process. Note if there is any bug in here the process will terminate right away. """ try: if sig == signal.CTRL_C_EVENT: print "User pressed: Ctrl C " MESSAGE_BOX(None, u'User pressed ctrl - C', u'User action', 0) #print "(╯°□°)╯︵ ┻━┻ ## We dont allow Ctrl C closing. muhuhahahahah" #return False elif sig == signal.CTRL_BREAK_EVENT: print "User pressed: Ctrl break " MESSAGE_BOX(None, u'User pressed ctrl - break', u'User action', 0) elif sig == signal.SIGINT: print "User closed window. (alt-f4, x button) " MESSAGE_BOX(None, u'User pressed alt f4 or x button', u'User action', 0) else: print "Unknown even number: ",sig,dir(signal) MESSAGE_BOX(None, u'Not sure what you did but cool :D', u'User action', 0) ## Certain things like time.sleep dont work anymore. MESSAGE_BOX(None, u'Closing now', u'Closing now', 0) ## If we return 0 it continues the close event. ## If we return 1 it ignores the event. except Exception as e: ## Just in case because any error will not show up. print e time.sleep(10) return 0 ## This needs to be global. If its not global it gets garbage collected and it wont work. # Register a function what returns a boolean, and takes a dword(8bit int ?) . HANDLER_ROUTINE = WINFUNCTYPE(wintypes.BOOL, wintypes.DWORD) SIGNAL_HANDLER = HANDLER_ROUTINE(_ctrl_handler) def setup_signal_handling(): SetConsoleCtrlHandler = ctypes.windll.kernel32.SetConsoleCtrlHandler SetConsoleCtrlHandler.argtypes = (HANDLER_ROUTINE, wintypes.BOOL) SetConsoleCtrlHandler.restype = wintypes.BOOL ## The first argument is the function, the second arument is add(1) or remove (0) if not SetConsoleCtrlHandler(SIGNAL_HANDLER, 1): print ("Unable to setup handler.") if __name__ == "__main__": setup_signal_handling() print "Try closing the window with alt f4 or ctrl c" while True: time.sleep(0.01) pass print " end " |
Run function on script exit.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
# -*- coding: utf-8 -*- ## Copyright 2019 Trevor van Hoof and Jan Pijpers. ## Licensed under the Apache License, Version 2.0 ## Downloaded from https://janpijpers.com or https://gumroad.com/janpijpers ## See the license file attached or on https://www.janpijpers.com/script-licenses/ ''' Name: functionOnExit Description: Run a function on closing a console window. windows only i guess. ''' import atexit import time def _run_function_on_exit(): ''' Function that will be called when the program actually exits. This is also called on a ctrl-c event. alt-f4 or x button will skip the raw input, but the function will still be called. ''' print "You are exiting, press enter to exit" raw_input() if __name__ == "__main__": ## Register the function to be run when the system exits. atexit.register( _run_function_on_exit ) for x in range(5,0,-1): print "Closing in:", x time.sleep(1) |
Fast(est?) get attr for each frame.
*update. Found another method. still open maya with mdg time is faster. But this is not half bad.
T.L.D.R
the “om_plug_as_double_mdg_set_time” function is the fastest I could find.
be careful with currentTime eval=False and cmds.keyframe. Scroll down for the script.
Explanation:
Soooo I had to export a bunch of data (10k+ maya files) for some dataset.
Which forced me to find a fast way to export attrbutes per frame.
(And it also had to work in mayapy)
And I dint want to have to dive into a c++ plugin or anything.
So I compared a bunch of different ways that i know to getAttr and updating the maya time.
Problems:
1. Dont use cmds.currentTime(frameNr, eval=False) !!
This results in the attribute dg not being evaluated. sooooo its useless.
2. cmds.keyframe(attr, query=True, eval=True)
This only evaluates the active anim layer’s keyframe data.
And changing the active anim layer in mayapy is a nightmare soooo… yeah don’t use it. Also it only works if there are keyframes set. So a channel with a constraint will not return any value.
So for testing i made a simple sphere and 2 additive anim layers with some animation in them.
Timings with a sphere:
Shortest duration for each function tested 100 times:
1 2 3 4 5 6 7 8 9 |
cmds_get_attr_cmds_set_time 4.07231167047 cmds_get_attr_no_eval 0.142337732946 = ERROR RESULT IS NOT CORRECT!!! cmds_get_attr_arg_time 0.188162308316 cmds_get_attr_om_set_time 0.367623159295 mel_get_attr 0.211408009643 pymel_get_attr_om_set_time 0.466954109253 pymel_get_attr_arg_time 0.274113534882 cmds_eval_keyframe_om_set_time 0.0870191721787 = WARNING RESULT IS NOT CORRECT WHEN USING ANIM LAYERS or no keyframes exist!!! om_plug_as_double_om_set_time 0.159895729674 = FASTEST RESULT! |
Timing with a heavier scene with skinning and constraints.
1 2 3 4 5 6 7 8 9 |
cmds_get_attr_cmds_set_time 8.21378763774 cmds_get_attr_no_eval 0.0179609034819 = ERROR RESULT IS NOT CORRECT!!! cmds_get_attr_arg_time 0.484571124028 cmds_get_attr_om_set_time 6.1720235551 mel_get_attr 0.494029596401 pymel_get_attr_om_set_time 6.14228203626 pymel_get_attr_arg_time 0.499620215035 cmds_eval_keyframe_om_set_time 0.00708293210846 = WARNING RESULT IS NOT CORRECT WHEN USING ANIM LAYERS or no keyframes exist!!! om_plug_as_double_om_set_time 0.468321232931 = FASTEST RESULT! |
Timing becomes more clear this way.
Code should mostly speak for itself.
If you have any questions just ask.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 |
from maya.api import OpenMayaAnim from maya.api import OpenMaya from maya import mel import inspect import timeit import pymel.core as pm ## Get the current UI Unit uiUnit = OpenMaya.MTime.uiUnit() ##### ## Util functions ##### def get_dep_node(n): return OpenMaya.MGlobal.getSelectionListByName(n).getDependNode(0) ################################ ## Get attr methods ################################ def cmds_get_attr_cmds_set_time(obj, attr): ''' The normal method of getting an attribute. :param obj: object string name i.e. "pSphere1" :param attr: the attribute to check i.e. "tx" :return: a list of values per frame. ''' fullName = "%s.%s" % (obj, attr) values = [] for frameNr in xrange(20): cmds.currentTime(frameNr) value = cmds.getAttr(fullName) values.append(value) return values def cmds_get_attr_no_eval(obj, attr): ''' ERROR DOESNT EVAL THE ATTR SO NO DATA WILL CHANGE The normal method of getting an attribute but without updating the time Doesnt work correctly as the attribute does not update. :param obj: object string name i.e. "pSphere1" :param attr: the attribute to check i.e. "tx" :return: a list of values per frame. ''' fullName = "%s.%s" % (obj, attr) values = [] for frameNr in xrange(20): cmds.currentTime(frameNr, update=False) value = cmds.getAttr(fullName) values.append(value) return values def cmds_get_attr_arg_time(obj, attr): ''' The normal method of getting an attribute but without updating the time but using the time argument of the get attr. Definitly the fastest method if you dont want to use open maya. :param obj: object string name i.e. "pSphere1" :param attr: the attribute to check i.e. "tx" :return: a list of values per frame. ''' fullName = "%s.%s" % (obj, attr) values = [] for frameNr in xrange(20): value = cmds.getAttr(fullName, time = frameNr) values.append(value) return values def cmds_get_attr_om_set_time(obj, attr): ''' Normal get attr but using open maya to change the time. :param obj: object string name i.e. "pSphere1" :param attr: the attribute to check i.e. "tx" :return: a list of values per frame. ''' fullName = "%s.%s" % (obj, attr) values = [] for frameNr in xrange(20): OpenMayaAnim.MAnimControl.setCurrentTime(OpenMaya.MTime(frameNr, uiUnit)) value = cmds.getAttr(fullName) values.append(value) return values def mel_get_attr(obj, attr): ''' Using mel get attr. using open maya to change the time. :param obj: object string name i.e. "pSphere1" :param attr: the attribute to check i.e. "tx" :return: a list of values per frame. ''' ## Slight speed optimisation, this way we dont have to construct the string every time. fullName = "getAttr -time %s "+obj+"."+attr values = [] for frameNr in xrange(20): #OpenMayaAnim.MAnimControl.setCurrentTime(OpenMaya.MTime(frameNr, uiUnit)) value = mel.eval(fullName%frameNr) values.append(value) return values def pymel_get_attr_om_set_time(obj, attr): ''' Using pymel get with openmaya set time. pymel basically uses the openmaya api so should be faster. :param obj: object string name i.e. "pSphere1" :param attr: the attribute to check i.e. "tx" :return: a list of values per frame. ''' ## Slight speed optimisation, this way we dont have to construct the string every time. pmAttr = pm.PyNode("%s.%s" % (obj, attr)) values = [] for frameNr in xrange(20): OpenMayaAnim.MAnimControl.setCurrentTime(OpenMaya.MTime(frameNr, uiUnit)) value = pmAttr.get() values.append(value) return values def pymel_get_attr_arg_time(obj, attr): ''' Using pymel get with passing time as argument pymel basically uses the openmaya api so should be faster. Definitly faster as setting time with maya api :param obj: object string name i.e. "pSphere1" :param attr: the attribute to check i.e. "tx" :return: a list of values per frame. ''' ## Slight speed optimisation, this way we dont have to construct the string every time. pmAttr = pm.PyNode("%s.%s" % (obj, attr)) values = [] for frameNr in xrange(20): value = pmAttr.get(time=frameNr) values.append(value) return values def cmds_eval_keyframe_om_set_time(obj, attr): ''' WARNING DOESNT EVAL CORRECTLY WITH MULTIPLE ANIM LAYERS!! Use the cmds.keyframe function to evaluate the keyframe. Its really fast! but .... doesnt eval correctly with anim layers. :param obj: object string name i.e. "pSphere1" :param attr: the attribute to check i.e. "tx" :return: a list of values per frame. ''' fullName = "%s.%s" % (obj, attr) values = [] for frameNr in xrange(20): value = cmds.keyframe(fullName, query=True, eval=True, t=(frameNr,)) or 0 values.append(value) return values def om_plug_as_double_mdg_set_time(obj, attr): ''' Getting the plug from openMaya. Then create a time mdgContext and evaluate it. This is the fastest with layer compatability... however i suspect there to be issues when doing complex simulations. :param obj: object string name i.e. "pSphere1" :param attr: the attribute to check i.e. "tx" :return: a list of values per frame. ''' values = [] obj = get_dep_node(obj) objMfn = OpenMaya.MFnDependencyNode(obj) ## Get the plug of the node. (networkedplug = False, as it no longer profides a speed improvement) plug = objMfn.findPlug(attr, False) for frameNr in xrange(20): ## The creaction of the MDG context takes the longest! mdg = OpenMaya.MDGContext(OpenMaya.MTime(frameNr, uiUnit)) value = plug.asDouble(mdg) values.append(value ) return values ## Put all functions in a nice list fList = [cmds_get_attr_cmds_set_time, cmds_get_attr_no_eval, cmds_get_attr_arg_time, cmds_get_attr_om_set_time, mel_get_attr, pymel_get_attr_om_set_time, pymel_get_attr_arg_time, cmds_eval_keyframe_om_set_time, om_plug_as_double_mdg_set_time] ## Prepare some constants obj = "pSphere1" attr = "tx" ## Start testing all results resultList = [] print "Duration for each function 100 times: " for f in fList: ## Using the timeit module to check how long the functions last duration = timeit.timeit(f.__name__ + "('%s','%s')" % (obj, attr), setup="from __main__ import %s" % f.__name__, number=10) ## Run it once more to get the actual results result = f(obj, attr) ## Store the results in a list resultList.append(result) ## And report the total duration. print "\t", f.__name__, duration print "Accuracy comparison: " for index, results in enumerate( resultList[1:]): print "Function Name: ",fList[index+1].__name__ for rIndex, result in enumerate( results ): print "\t", result - resultList[0][rIndex] |