Reload modules for iteration during UI dev in Maya

pipeline
maya

#1

I’m looking for a way to reload my UI so any updates I make in visual studio will show up when I reload the tool in Maya. Any workarounds? It’s taking a lot of time to startup maya every time I want to view changes to my code.

I have this code, but I never quite got it to work and I’m not sure why:

import inspect
import sys
from os.path import dirname 

# I'm going to define this little function to make this cleaner
# It's going to have a flag to let you specify the userPath you want to clear out
# But otherwise I'd going to assume that it's the userPath you're running the script from (__file__) 
def resetSessionForScript(userPath=None):
    if userPath is None:
        userPath = dirname(__file__)
    # Convert this to lower just for a clean comparison later  
    userPath = userPath.lower()
    print 'userPath : {0}'.format(userPath)

    toDelete = []
    # Iterate over all the modules that are currently loaded
    for key, module in sys.modules.iteritems():
        # There's a few modules that are going to complain if you try to query them
        # so I've popped this into a try/except to keep it safe
        try:
            # Use the "inspect" library to get the moduleFilePath that the current module was loaded from
            moduleFilePath = inspect.getfile(module).lower()
          
            # Don't try and remove the startup script, that will break everything
            if moduleFilePath == __file__.lower():
                print 'moduleFilePath : {0}'.format(moduleFilePath)
                continue
          
            # If the module's filepath contains the userPath, add it to the list of modules to delete
            if moduleFilePath.startswith(userPath):
                print "Removing %s" % key
                toDelete.append(key)
        except:
            pass
    
    # If we'd deleted the module in the loop above, it would have changed the size of the dictionary and
    # broken the loop. So now we go over the list we made and delete all the modules
    for module in toDelete:
        del (sys.modules[module])

#########################################
        
# So now you can either put this at the top of your script
resetSessionForScript(r"D:\Git_Stuff\mb-armada\mb_Armada\mb_Armada\modules\mb_shipyard\mb-atlantis-asset-manager\source\mb_aam")

# Or just 
#resetSessionForScript()
                      
# Personally, I only want this behaviour to be called for me while I'm debugging so I'd probably add it in a condition like
#import getpass
#if getpass.getuser() == "nrodgers":
    #resetSessionForScript()
                      
# Or just for anyone running the tool from an IDE
#if __name__ == "__main__":
    #resetSessionForScript()

#2

How are you launching your scripts?
Have you tried the reload function? You pass it a module object and it reloads the module. It works best with single modules, as dependency order can definitely become a thing.

A horribly hacky method, which I’ve used for reloading whole packages is:

import sys
package_name = 'pymel'
for mod in sys.modules.copy():
    if mod.startswith(package_name):
        del sys.modules[mod]

import pymel.core as pm

This also has issues, for example doing this with pymel leaks a crapload of memory.

Also any instances in memory could still be referencing these now deleted modules, so until they’re cleaned up you could easily get errors.


#3

If you want to be safe and you know roughly how your imports are structured, you can use a chain of reload() calls to reload modules. What you need to do is reload them in reverse order – latest imported reloads first – so that you don’t have reloaded module A retaining an in-memory reference to old module B despite the reload calls: you want B reloaded before A reloads.

If you are deliberate with your design it’s a lot easier – it’s far easier if all the code that is to be changed lives in one module that can be reloaded.


#4

I ended up switching my IDE to PyCharm and it’s exactly what I needed. I can get auto completion, run the script from the IDE and it immediately goes to Maya through MayaCharm. No more waiting for Maya to restart!

Below is an excerpt from my documentation on how to get it working. There are 3 steps: Qt.py completion, maya cmds completion, and PyCharm to Maya completion. Feel free to update if there are other useful things I can add, such as pymel or lower level MayaAPI things or let me know if anything needs more clarification.

Qt.py stubs for auto-completion

  1. Clone Qt.py fork and activate stub branch: https://github.com/fredrikaverpil/Qt.py/tree/stubs
  2. In PyCharm add the path/to/stubs directory to the content root directory
    in the project settings

Maya auto-completion

  1. Setup the Maya Python interpreter in Pycharm

    • In PyCharm, Ctrl+Alt+S to open your preferences and find Project Interpreter.
    • Next to the drop-down list, click the little gear icon, and choose Add Local.
    • Locate mayapy.exe or mayapy depending on your system.
      • This is found in the bin folder in your Maya installation directory.
        • On PC it’s located under …\Autodesk\Maya2018\bin
        • On Mac it’s located under …/Autodesk/maya2016.5/Maya.app/Contents/bin/mayapy
  2. To make completions work

    • Download the Maya developer kit at https://apps.autodesk.com/MAYA/en/Detail/Index?id=5525491636376351277&os=Win64&appLang=en
    • Inside the zip file, copy the “devkit” folder to …\Program Files\Autodesk\Maya2018\devkit
    • In PyCharm, Click the […] next to the drop-down list again and select More…
    • Select your newly added interpreter from the steps above, it will be named something like Python 2.7.6 (/path/to/mayapy)
    • Click the Paths button at the bottom of the right side toolbar
    • Click the + sign and locate the folder where you extracted the developer kit. Then navigate to …/devkit/other/pymel/extras/extras/completion/py/ and hit OK.

Maya application integration

Allows you to run code from PyCharm and have it become activated in a session of Maya

  1. Download the MayaCharm plugin into a safe place: https://plugins.jetbrains.com/plugin/8218-mayacharm
  2. In PyCharm, Ctrl+Alt+S to open your preferences and find Plugins
  3. Install plugin from disk
  4. Find the MayaCharm plugin and install it
  5. Go back to the settings and go to the MayaCharm settings
  6. Follow instructions there to complete setup