Blog

Drag&Drop Installer in Maya.

Maya expects a certain folder structure such as the module being placed inside a folder named scripts. The following is a simple example:

.
├── installer.py # <-- This file will be dropped into Maya's viewport.
└── scripts # <-- Expected folder by Maya.
   ├── foo # <-- Our module.
   │  ├── main.py
   │  └── __init__.py
   └ userSetup.py # <-- Optional file to be loaded on Maya startup.

Our installer.py can be simple drag-&-dropped into Maya's viewport to run the installation process of creating a .mod file in the Maya's modules directory with the correct path to our module.

The installer.py expected to be live next to the scripts folder since it uses the parents' directory for the contents of the .mod file. Please replace the MODULE_NAME variable with the name of your module.

from pathlib import Path
import importlib, sys, os


MODULE_NAME = "foo" # <-- The name of the module.
MOD_TEMPLATE = "{name} 1.0.1 {path}"

REPOSITORY_DIR = Path(__file__).parent
MAYA_APP_DIR = os.getenv("MAYA_APP_DIR")


def install_mod():
    """Installs the module by creating a .mod file in the Maya modules directory
    with the parent's directory as the path."""

    target_mod_filepath = Path(MAYA_APP_DIR, "modules", f"{MODULE_NAME}.mod")
    target_mod_filepath.parent.mkdir(parents=True, exist_ok=True)

    mod_contents = MOD_TEMPLATE.format(name=MODULE_NAME, path=REPOSITORY_DIR.as_posix())
    target_mod_filepath.write_text(mod_contents)


def load_user_setup():
    """Adds the module to the sys.path and imports the userSetup.py file (if it
    exists) manually for the current session. On the next startup, these will be
    loaded automatically."""

    scripts_dir = REPOSITORY_DIR.joinpath("scripts")
    user_setup = scripts_dir.joinpath("userSetup.py")

    if scripts_dir.exists():
        if scripts_dir not in sys.path:
            sys.path.append(scripts_dir.as_posix())

        if user_setup.exists():
            spec = importlib.util.spec_from_file_location(user_setup.stem, user_setup.as_posix())
            module = importlib.util.module_from_spec(spec)
            spec.loader.exec_module(module)


def onMayaDroppedPythonFile(*args, **kwargs):
    """Callback function to be executed when a Python file is dropped into the Maya
    viewport. It reloads the current module, installs the module, and loads the
    userSetup.py file."""

    self_import = importlib.import_module(__name__)
    importlib.reload(self_import)

    self_import.install_mod()
    self_import.load_user_setup()

The userSetup.py file is optional and can be used to load any custom setup code when Maya starts up. It is placed in the scripts directory for Maya to be able to find it.

from maya import utils


def initialize():
    ...


utils.executeDeferred(initialize)