/python/pymel/tools/mel2py/__init__.py
Python | 451 lines | 298 code | 48 blank | 105 comment | 36 complexity | e967c4df81493ea94c7f4530e9725a99 MD5 | raw file
Possible License(s): GPL-2.0, GPL-3.0
- """
- ==========================
- Mel To Python Translator
- ==========================
- Convert mel scripts into python scripts.
- Known Limitations
- =================
- array index assignment
- ----------------------
- In mel, you can directly assign the value of any element in an array, and all intermediate elements will be
- automatically filled. This is not the case in python: if the list index is out of range an IndexError will be
- raised. I've added fixes for several common array assignment conventions:
- append new element
- ~~~~~~~~~~~~~~~~~~
- **MEL**
- .. python::
- string $strArray[];
- $strArray[`size $strArray`] = "foo";
- Python
- >>> strArray = [] #doctest: +SKIP
- >>> strArray.append("foo") #doctest: +SKIP
- assignment relative to end of array
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- **MEL**
- .. python::
- strArray[`size $strArray`-3] = "foo";
- Python
- >>> strArray[-3] = "foo" #doctest: +SKIP
- However, since the translator does not track values of variables, it does not know if any given index is out of
- range or not. so, the following would raise a 'list assignment index out of range' error when converted to
- python and would need to be manually fixed:
- .. python::
- string $strArray[];
- for ($i=0; $i<5; $i++)
- $strArray[$i] = "foo"
- for(init; condition; update)
- ----------------------------
- the closest equivalent to this in python is something akin to:
- >>> for i in range(start, end): #doctest: +SKIP
- in order for this type of for loop to be translated into a python for loop it must meet several requirements:
- 1. the initialization, condition, and update expressions must not be empty.
- not translatable:
- .. python::
- for(; ; $i++) print $i;
- 2. there can be only one conditional expression.
- not translatable:
- .. python::
- for($i=0; $i<10, $j<20; $i++) print $i;
- 3. the variable which is being updated and tested in the condition (aka, the iterator) must exist alone on one
- side of the conditional expression. this one is easy enough to fix, just do some algebra:
- not translatable:
- .. python::
- for($i=0; ($i-2)<10, $i++) print $i;
- translatable:
- .. python::
- for($i=0; $i<(10+2), $i++) print $i;
- 4. the iterator can appear only once in the update expression:
- not translatable:
- .. python::
- for($i=0; $i<10; $i++, $i+=2) print $i;
- if these conditions are not met, the for loop will be converted into a while loop:
- >>> i=0
- >>> while 1: #doctest: +SKIP
- ... if not ( (i - 2)<10 ):
- ... break
- ... print i
- ... i+=1
- Inconveniences
- ==============
- Switch Statements
- -----------------
- Alas, switch statements are not supported by python. the translator will convert them into an if/elif/else statement.
- Global Variables
- ----------------
- Global variables are not shared between mel and python. two functions have been added to pymel for this purpose:
- `getMelGlobal` and `setMelGlobal`. by default, the translator will convert mel global variables into python global
- variables AND intialize them to the value of their corresponding mel global variable using getMelGlobal(). if your
- python global variable does not need to be shared with other mel scripts, you can remove the get- and
- setMelGlobals lines (for how to filter global variables, see below). however, if it does need to be shared, it is very
- important that you manually add setMelGlobal() to update the variable in the mel environment before calling any mel
- procedures that will use the global variable.
- In order to hone the accuracy of the translation of global variables, you will find two dictionary parameters below --
- `global_var_include_regex` and `global_var_exclude_regex` -- which you can use to set a regular expression string
- to tell the translator which global variables to share with the mel environment (i.e. which will use the get and set
- methods described above) and which to not. for instance, in my case, it is desirable for all of maya's global
- variables to be initialized from their mel value but for our in-house variables not to be, since the latter are often
- used to pass values within a single script. see below for the actual regular expressions used to accomplish this.
- Comments
- --------
- Rules on where comments may be placed is more strict in python, so expect your comments to be shifted around a bit
- after translation.
- Formatting
- ----------
- Much of the formatting of your original script will be lost. I apologize for this, but python is much more strict
- about formatting than mel, so the conversion is infinitely simpler when the formatting is largely discarded
- and reconstructed based on pythonic rules.
- Solutions and Caveats
- =====================
- catch and catchQuiet
- --------------------
- There is no direct equivalent in python to the catch and catchQuiet command and it does not exist in maya.cmds so i wrote two
- python commands of the same name and put them into pymel. these are provided primarily for compatibility with
- automatically translated scripts. try/except statements should be used instead of catch or catchQuiet if coding
- from scratch.
- for( $elem in $list )
- ---------------------
- This variety of for loop has a direct syntactical equivalent in python. the only catch here is that maya.cmds
- functions which are supposed to return lists, return None when there are no matches. life would be much simpler
- if they returned empty lists instead. the solution currently lies in pymel, where i have begun
- correcting all of these command to return proper results. i've started with the obvious ones, but there
- are many more that i need to fix. you'll know you hit the problem when you get this error: 'TypeError: iteration
- over non-sequence'. just email me with commands that are giving you problems and i'll fix them as
- quickly as i can.
- """
- import pymel.internal.factories as _factories
- import pymel.core.animation as animation
- import pymel.api as api
- import __builtin__ as builtin_module
- import maya.cmds as cmds
- import pymel.core.context as context
- import pymel.core.datatypes as datatypes
- import pymel.core.datatypes as dt
- import pymel.core.effects as effects
- import pymel.internal.factories as factories
- import functools
- import pymel.core.general as general
- import inspect
- import pymel.internal as internal
- import itertools
- import pymel.core.language as language
- import pymel.util.external.ply.lex as lex
- import logging
- import mellex
- import melparse
- import melscan
- import pymel.core.modeling as modeling
- import pymel.core.nodetypes as nodetypes
- import pymel.core.nodetypes as nt
- import os
- import pymel.core.other as other
- import pymel
- import re
- import pymel.core.rendering as rendering
- import pymel.core.runtime as runtime
- import string
- import sys
- import pymel.core.system as system
- import tempfile
- import traceback
- import pymel.core.uitypes as ui
- import pymel.core.uitypes as uitypes
- import pymel.util as util
- import pymel.versions as versions
- import pymel.core.windows as windows
- import pymel.util.external.ply.yacc as yacc
- from maya._OpenMaya import *
- from pymel.core.windows import *
- from pymel.core.system import *
- from pymel.tools.mel2py.melparse import *
- from pymel.internal.pmcmds import *
- from pymel.core.general import *
- from pymel.util.utilitytypes import *
- from pymel.util.common import *
- from pymel.internal.pwarnings import *
- from pymel.util.scanf import *
- from pymel.core.effects import *
- from pymel.core.animation import *
- from pymel.core.context import *
- from pymel.util.external.ply.yacc import *
- from pymel.util.path import *
- from pymel.core.rendering import *
- from pymel.util.decoration import *
- from pymel.core.language import *
- from logging import *
- from pymel.core.uitypes import *
- from pymel.core.other import *
- from pymel.core.modeling import *
- from pymel.util.external.ply.lex import *
- def displayError(*args, **kwargs):
- pass
- def displayInfo(*args, **kwargs):
- pass
- def displayWarning(*args, **kwargs):
- pass
- def fileOnMelPath(file):
- """
- Return True if this file is on the mel path.
- """
- pass
- def findMelOnlyCommands():
- """
- Using maya's documentation, find commands which were not ported to python.
- """
- pass
- def mel2py(input, outputDir=None, pymelNamespace='', forceCompatibility=False, verbosity=0, test=False, recurse=False, exclude=(), melPathOnly=False, basePackage=None):
- """
- Batch convert an entire directory
-
- :Parameters:
- input
- May be a directory, a list of directories, the name of a mel file, a list of mel files, or the name of a sourced procedure.
- If only the name of the mel file is passed, mel2py will attempt to determine the location
- of the file using the 'whatIs' mel command, which relies on the script already being sourced by maya.
-
- outputDir : `str`
- Directory where resulting python files will be written to
-
- pymelNamespace : `str`
- the namespace into which pymel will be imported. the default is '', which means ``from pymel.all import *``
-
- forceCompatibility : `bool`
- If True, the translator will attempt to use non-standard python types in order to produce
- python code which more exactly reproduces the behavior of the original mel file, but which
- will produce "uglier" code. Use this option if you wish to produce the most reliable code
- without any manual cleanup.
-
- verbosity : `int`
- Set to non-zero for a *lot* of feedback
-
- test : `bool`
- After translation, attempt to import the modules to test for errors
-
- recurse : `bool`
- If the input is a directory, whether or not to recursively search subdirectories as well.
- Subdirectories will be converted into packages, and any mel files within those subdirectories
- will be submodules of that package.
-
- exclude : `str`
- A comma-separated list of files/directories to exclude from processing, if input is a directory.
-
- melPathOnly : `bool`
- If true, will only translate mel files found on the mel script path.
-
- basePackage : `str`
- Gives the package that all translated modules will be a part of; if None or an empty string, all
- translated modules are assumed to have no base package.
- """
- pass
- def mel2pyStr(data, currentModule=None, pymelNamespace='', forceCompatibility=False, verbosity=0, basePackage=None):
- """
- convert a string representing mel code into a string representing python code
-
- >>> import pymel.tools.mel2py as mel2py
- >>> print mel2py.mel2pyStr('paneLayout -e -configuration "top3" test;')
- from pymel.all import *
- paneLayout('test',configuration="top3",e=1)
- <BLANKLINE>
-
- Note that when converting single lines, the lines must end in a semi-colon, otherwise it is technically
- invalid syntax.
-
- :Parameters:
- data : `str`
- string representing coe to convert
-
- currentModule : `str`
- the name of the module that the hypothetical code is executing in. In most cases you will
- leave it at its default, the __main__ namespace.
-
- pymelNamespace : `str`
- the namespace into which pymel will be imported. the default is '', which means ``from pymel.all import *``
-
- forceCompatibility : `bool`
- If True, the translator will attempt to use non-standard python types in order to produce
- python code which more exactly reproduces the behavior of the original mel file, but which
- will produce "uglier" code. Use this option if you wish to produce the most reliable code
- without any manual cleanup.
-
- verbosity : `int`
- Set to non-zero for a *lot* of feedback
- """
- pass
- def melInfo(input):
- """
- Get information about procedures in a mel file.
-
- >>> import pymel.tools.mel2py as mel2py
- >>> mel2py.melInfo('attributeExists')
- (['attributeExists'], {'attributeExists': {'returnType': 'int', 'args': [('string', '$attr'), ('string', '$node')]}}, {})
-
- :Parameters:
- input
- can be a mel file or a sourced mel procedure
-
- :return:
- A 3-element tuple:
- 1. the list of procedures in the order the are defined
- 2. a dictionary of global procedures, with the following entries:
- - returnType: mel type to be returned
- - args: a list of (type, variable_name) pairs
- 3. a dictionary of local procedures, formatted the same as with globals
- """
- pass
- def resolvePath(melobj, recurse=False, exclude=(), melPathOnly=False, basePackage=''):
- """
- if passed a directory, get all mel files in the directory
- if passed a file, ensure it is a mel file
- if passed a procedure name, find its file
-
- Returns tuples of the form (moduleName, melfile).
- """
- pass
- MELTYPES = None
- SCENE = None
- batchData = None
- catch = None
- contstraintCmdName = None
- custom_proc_remap = None
- deprecated_str_methods = None
- env = None
- fileInfo = None
- filteredCmds = None
- lexer = None
- log = None
- mel = None
- melCmdFlagList = None
- melCmdList = None
- melGlobals = None
- mel_type_to_python_type = None
- optionVar = None
- parser = None
- proc_remap = None
- pythonReservedWords = None
- reserved = None
- scanner = None
- scriptTableCmds = None
- tag = None
- thisModuleCmd = None
- tokens = None
- workspace = None
- x = None