Skip to content

Instantly share code, notes, and snippets.

@tokejepsen
Last active July 6, 2026 14:13
Show Gist options
  • Select an option

  • Save tokejepsen/bb1e5249595e183cbcf2c706d5a3f051 to your computer and use it in GitHub Desktop.

Select an option

Save tokejepsen/bb1e5249595e183cbcf2c706d5a3f051 to your computer and use it in GitHub Desktop.
Maya: Change Namespace
# maya_change_namespace.py
#
# USAGE
# -----
# Run this script from Maya's Script Editor (Python tab).
#
# 1. Set `namespace` (below) to the NEW namespace you want to assign.
# !! Do this EVERY time before running — the value is not remembered !!
#
# 2. Select any node that belongs to the reference you want to rename
# (a mesh, a joint, a shape — anything from that reference).
#
# 3. Run the script.
#
# WHAT IT DOES
# ------------
# Maya's built-in namespace rename is unreliable on complex scenes,
# and cannot handle moving a reference from the root namespace (no prefix)
# to a named namespace. This script works around that by:
#
# a) Saving the current scene as Maya ASCII (.ma).
# b) Editing the ASCII text directly — updating the reference file
# command and every node reference in the body via regex.
# c) Writing the result to a new auto-versioned file and reopening it.
#
# REQUIREMENTS
# ------------
# - The current scene must already be saved as a Maya ASCII file (.ma).
# Running on a Maya Binary (.mb) scene will raise an error to prevent
# the original file being silently overwritten in a different format.
# - The scene must be saved (not untitled) before running.
# - Exactly one node from the target reference must be selected.
#
# SAFETY
# ------
# - The original file is never modified; output is always a new version.
# - The new file is written atomically (temp file → rename) to prevent
# corrupt output if a write is interrupted.
#
# DISCLAIMER
# ----------
# THIS SCRIPT IS PROVIDED AS-IS. Bumpybox accepts no responsibility for
# data loss or scene corruption. Always back up your files before testing
# or running this script on production assets.
import re
import os
import tempfile
from maya import cmds
# !! SET THIS TO THE DESIRED NEW NAMESPACE BEFORE RUNNING !!
namespace = "temp"
selection = cmds.ls(selection=True)
if not selection:
raise RuntimeError("No objects selected.")
ref_node = cmds.referenceQuery(selection[0], referenceNode=True)
file_path = cmds.referenceQuery(selection[0], filename=True)
# 1. Process ALL nodes in the reference (including Shading, Materials, Sets, etc.)
ref_nodes = cmds.referenceQuery(ref_node, nodes=True)
# Sort nodes by string length descending to prevent shorter names
# accidentally replacing parts of longer names (e.g., 'pSphere1' vs 'pSphere10')
ref_nodes.sort(key=len, reverse=True)
# Normalize the existing namespace string
raw_namespace = cmds.referenceQuery(ref_node, namespace=True)
old_namespace = raw_namespace.strip(":")
current_file = cmds.file(q=True, sn=True)
if not current_file:
raise RuntimeError("No file currently open in Maya.")
if not current_file.lower().endswith(".ma"):
raise RuntimeError(
f"Current scene must be saved as Maya ASCII (.ma) before running this script.\n"
f"Current file: {current_file}\n"
f"Save the scene via File > Save As, choosing 'Maya ASCII', then try again."
)
cmds.file(save=True, type="mayaAscii")
with open(current_file, "r", encoding="utf-8") as f:
contents = f.read()
# Normalise line endings so the ;\n split works on files from any OS
contents = contents.replace("\r\n", "\n").replace("\r", "\n")
new_contents = ""
for line in contents.split(";\n"):
if file_path in line:
# Strip -renamingPrefix / -rpr first — mutually exclusive with -ns in Maya ASCII.
# Maya uses the short flag -rpr in practice; both forms must be removed to prevent
# the conflict "The -renamingPrefix flag and -namespaceName flag are mutually exclusive".
line = re.sub(r'\s*-(renamingPrefix|rpr)\s+"[^"]*"', '', line)
if re.search(r'-(ns|namespace)\s+"[^"]*"', line):
line_replacement = re.sub(r'-(ns|namespace)\s+"[^"]*"', f'-ns "{namespace}"', line)
else:
line_replacement = line.replace('file ', f'file -ns "{namespace}" ', 1)
print(f"Replacing reference line: {line}\nwith: {line_replacement}")
line = line_replacement
new_contents += line + ";\n"
# 2. Loop through all nodes with an upgraded, flexible regex pattern
for node in ref_nodes:
# Isolate the base node name (stripping any existing namespace paths)
base_node = node.split(":")[-1]
if old_namespace:
# Targets: "old_ns:node", :old_ns:node, or |old_ns:node
pattern = rf'(["|:])(:?){re.escape(old_namespace)}:{re.escape(base_node)}(\b)'
replacement = rf'\1{namespace}:{base_node}\3'
else:
# Targets root namespace: "node", :node, or |node
# This catches "rootGroup.visibility" and "mesh.instObjGroups" seamlessly
pattern = rf'(["|:])(:?){re.escape(base_node)}(\b)'
replacement = rf'\1{namespace}:{base_node}\3'
new_contents = re.sub(pattern, replacement, new_contents)
# 3. Handle versioning and save file
base, ext = os.path.splitext(current_file)
match = re.search(r'_v(\d{3,})', base)
if match:
version = int(match.group(1)) + 1
base = base[:match.start()]
else:
version = 1
new_file = f"{base}_v{version:03d}{ext}"
while os.path.exists(new_file):
version += 1
new_file = f"{base}_v{version:03d}{ext}"
# Write atomically: write to a temp file alongside the target, then rename.
# This prevents a corrupt partial file if the write is interrupted.
target_dir = os.path.dirname(new_file)
fd, tmp_path = tempfile.mkstemp(dir=target_dir, suffix=".tmp")
try:
with os.fdopen(fd, "w", encoding="utf-8") as f:
f.write(new_contents)
os.replace(tmp_path, new_file)
except Exception:
os.unlink(tmp_path)
raise
cmds.file(new_file, open=True, force=True)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment