PageRenderTime 45ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/python/pymel/tools/mel2py/__init__.py

https://bitbucket.org/jspatrick/emacs
Python | 451 lines | 298 code | 48 blank | 105 comment | 36 complexity | e967c4df81493ea94c7f4530e9725a99 MD5 | raw file
Possible License(s): GPL-2.0, GPL-3.0
  1. """
  2. ==========================
  3. Mel To Python Translator
  4. ==========================
  5. Convert mel scripts into python scripts.
  6. Known Limitations
  7. =================
  8. array index assignment
  9. ----------------------
  10. In mel, you can directly assign the value of any element in an array, and all intermediate elements will be
  11. automatically filled. This is not the case in python: if the list index is out of range an IndexError will be
  12. raised. I've added fixes for several common array assignment conventions:
  13. append new element
  14. ~~~~~~~~~~~~~~~~~~
  15. **MEL**
  16. .. python::
  17. string $strArray[];
  18. $strArray[`size $strArray`] = "foo";
  19. Python
  20. >>> strArray = [] #doctest: +SKIP
  21. >>> strArray.append("foo") #doctest: +SKIP
  22. assignment relative to end of array
  23. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  24. **MEL**
  25. .. python::
  26. strArray[`size $strArray`-3] = "foo";
  27. Python
  28. >>> strArray[-3] = "foo" #doctest: +SKIP
  29. However, since the translator does not track values of variables, it does not know if any given index is out of
  30. range or not. so, the following would raise a 'list assignment index out of range' error when converted to
  31. python and would need to be manually fixed:
  32. .. python::
  33. string $strArray[];
  34. for ($i=0; $i<5; $i++)
  35. $strArray[$i] = "foo"
  36. for(init; condition; update)
  37. ----------------------------
  38. the closest equivalent to this in python is something akin to:
  39. >>> for i in range(start, end): #doctest: +SKIP
  40. in order for this type of for loop to be translated into a python for loop it must meet several requirements:
  41. 1. the initialization, condition, and update expressions must not be empty.
  42. not translatable:
  43. .. python::
  44. for(; ; $i++) print $i;
  45. 2. there can be only one conditional expression.
  46. not translatable:
  47. .. python::
  48. for($i=0; $i<10, $j<20; $i++) print $i;
  49. 3. the variable which is being updated and tested in the condition (aka, the iterator) must exist alone on one
  50. side of the conditional expression. this one is easy enough to fix, just do some algebra:
  51. not translatable:
  52. .. python::
  53. for($i=0; ($i-2)<10, $i++) print $i;
  54. translatable:
  55. .. python::
  56. for($i=0; $i<(10+2), $i++) print $i;
  57. 4. the iterator can appear only once in the update expression:
  58. not translatable:
  59. .. python::
  60. for($i=0; $i<10; $i++, $i+=2) print $i;
  61. if these conditions are not met, the for loop will be converted into a while loop:
  62. >>> i=0
  63. >>> while 1: #doctest: +SKIP
  64. ... if not ( (i - 2)<10 ):
  65. ... break
  66. ... print i
  67. ... i+=1
  68. Inconveniences
  69. ==============
  70. Switch Statements
  71. -----------------
  72. Alas, switch statements are not supported by python. the translator will convert them into an if/elif/else statement.
  73. Global Variables
  74. ----------------
  75. Global variables are not shared between mel and python. two functions have been added to pymel for this purpose:
  76. `getMelGlobal` and `setMelGlobal`. by default, the translator will convert mel global variables into python global
  77. variables AND intialize them to the value of their corresponding mel global variable using getMelGlobal(). if your
  78. python global variable does not need to be shared with other mel scripts, you can remove the get- and
  79. setMelGlobals lines (for how to filter global variables, see below). however, if it does need to be shared, it is very
  80. important that you manually add setMelGlobal() to update the variable in the mel environment before calling any mel
  81. procedures that will use the global variable.
  82. In order to hone the accuracy of the translation of global variables, you will find two dictionary parameters below --
  83. `global_var_include_regex` and `global_var_exclude_regex` -- which you can use to set a regular expression string
  84. to tell the translator which global variables to share with the mel environment (i.e. which will use the get and set
  85. methods described above) and which to not. for instance, in my case, it is desirable for all of maya's global
  86. variables to be initialized from their mel value but for our in-house variables not to be, since the latter are often
  87. used to pass values within a single script. see below for the actual regular expressions used to accomplish this.
  88. Comments
  89. --------
  90. Rules on where comments may be placed is more strict in python, so expect your comments to be shifted around a bit
  91. after translation.
  92. Formatting
  93. ----------
  94. Much of the formatting of your original script will be lost. I apologize for this, but python is much more strict
  95. about formatting than mel, so the conversion is infinitely simpler when the formatting is largely discarded
  96. and reconstructed based on pythonic rules.
  97. Solutions and Caveats
  98. =====================
  99. catch and catchQuiet
  100. --------------------
  101. 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
  102. python commands of the same name and put them into pymel. these are provided primarily for compatibility with
  103. automatically translated scripts. try/except statements should be used instead of catch or catchQuiet if coding
  104. from scratch.
  105. for( $elem in $list )
  106. ---------------------
  107. This variety of for loop has a direct syntactical equivalent in python. the only catch here is that maya.cmds
  108. functions which are supposed to return lists, return None when there are no matches. life would be much simpler
  109. if they returned empty lists instead. the solution currently lies in pymel, where i have begun
  110. correcting all of these command to return proper results. i've started with the obvious ones, but there
  111. are many more that i need to fix. you'll know you hit the problem when you get this error: 'TypeError: iteration
  112. over non-sequence'. just email me with commands that are giving you problems and i'll fix them as
  113. quickly as i can.
  114. """
  115. import pymel.internal.factories as _factories
  116. import pymel.core.animation as animation
  117. import pymel.api as api
  118. import __builtin__ as builtin_module
  119. import maya.cmds as cmds
  120. import pymel.core.context as context
  121. import pymel.core.datatypes as datatypes
  122. import pymel.core.datatypes as dt
  123. import pymel.core.effects as effects
  124. import pymel.internal.factories as factories
  125. import functools
  126. import pymel.core.general as general
  127. import inspect
  128. import pymel.internal as internal
  129. import itertools
  130. import pymel.core.language as language
  131. import pymel.util.external.ply.lex as lex
  132. import logging
  133. import mellex
  134. import melparse
  135. import melscan
  136. import pymel.core.modeling as modeling
  137. import pymel.core.nodetypes as nodetypes
  138. import pymel.core.nodetypes as nt
  139. import os
  140. import pymel.core.other as other
  141. import pymel
  142. import re
  143. import pymel.core.rendering as rendering
  144. import pymel.core.runtime as runtime
  145. import string
  146. import sys
  147. import pymel.core.system as system
  148. import tempfile
  149. import traceback
  150. import pymel.core.uitypes as ui
  151. import pymel.core.uitypes as uitypes
  152. import pymel.util as util
  153. import pymel.versions as versions
  154. import pymel.core.windows as windows
  155. import pymel.util.external.ply.yacc as yacc
  156. from maya._OpenMaya import *
  157. from pymel.core.windows import *
  158. from pymel.core.system import *
  159. from pymel.tools.mel2py.melparse import *
  160. from pymel.internal.pmcmds import *
  161. from pymel.core.general import *
  162. from pymel.util.utilitytypes import *
  163. from pymel.util.common import *
  164. from pymel.internal.pwarnings import *
  165. from pymel.util.scanf import *
  166. from pymel.core.effects import *
  167. from pymel.core.animation import *
  168. from pymel.core.context import *
  169. from pymel.util.external.ply.yacc import *
  170. from pymel.util.path import *
  171. from pymel.core.rendering import *
  172. from pymel.util.decoration import *
  173. from pymel.core.language import *
  174. from logging import *
  175. from pymel.core.uitypes import *
  176. from pymel.core.other import *
  177. from pymel.core.modeling import *
  178. from pymel.util.external.ply.lex import *
  179. def displayError(*args, **kwargs):
  180. pass
  181. def displayInfo(*args, **kwargs):
  182. pass
  183. def displayWarning(*args, **kwargs):
  184. pass
  185. def fileOnMelPath(file):
  186. """
  187. Return True if this file is on the mel path.
  188. """
  189. pass
  190. def findMelOnlyCommands():
  191. """
  192. Using maya's documentation, find commands which were not ported to python.
  193. """
  194. pass
  195. def mel2py(input, outputDir=None, pymelNamespace='', forceCompatibility=False, verbosity=0, test=False, recurse=False, exclude=(), melPathOnly=False, basePackage=None):
  196. """
  197. Batch convert an entire directory
  198. :Parameters:
  199. input
  200. 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.
  201. If only the name of the mel file is passed, mel2py will attempt to determine the location
  202. of the file using the 'whatIs' mel command, which relies on the script already being sourced by maya.
  203. outputDir : `str`
  204. Directory where resulting python files will be written to
  205. pymelNamespace : `str`
  206. the namespace into which pymel will be imported. the default is '', which means ``from pymel.all import *``
  207. forceCompatibility : `bool`
  208. If True, the translator will attempt to use non-standard python types in order to produce
  209. python code which more exactly reproduces the behavior of the original mel file, but which
  210. will produce "uglier" code. Use this option if you wish to produce the most reliable code
  211. without any manual cleanup.
  212. verbosity : `int`
  213. Set to non-zero for a *lot* of feedback
  214. test : `bool`
  215. After translation, attempt to import the modules to test for errors
  216. recurse : `bool`
  217. If the input is a directory, whether or not to recursively search subdirectories as well.
  218. Subdirectories will be converted into packages, and any mel files within those subdirectories
  219. will be submodules of that package.
  220. exclude : `str`
  221. A comma-separated list of files/directories to exclude from processing, if input is a directory.
  222. melPathOnly : `bool`
  223. If true, will only translate mel files found on the mel script path.
  224. basePackage : `str`
  225. Gives the package that all translated modules will be a part of; if None or an empty string, all
  226. translated modules are assumed to have no base package.
  227. """
  228. pass
  229. def mel2pyStr(data, currentModule=None, pymelNamespace='', forceCompatibility=False, verbosity=0, basePackage=None):
  230. """
  231. convert a string representing mel code into a string representing python code
  232. >>> import pymel.tools.mel2py as mel2py
  233. >>> print mel2py.mel2pyStr('paneLayout -e -configuration "top3" test;')
  234. from pymel.all import *
  235. paneLayout('test',configuration="top3",e=1)
  236. <BLANKLINE>
  237. Note that when converting single lines, the lines must end in a semi-colon, otherwise it is technically
  238. invalid syntax.
  239. :Parameters:
  240. data : `str`
  241. string representing coe to convert
  242. currentModule : `str`
  243. the name of the module that the hypothetical code is executing in. In most cases you will
  244. leave it at its default, the __main__ namespace.
  245. pymelNamespace : `str`
  246. the namespace into which pymel will be imported. the default is '', which means ``from pymel.all import *``
  247. forceCompatibility : `bool`
  248. If True, the translator will attempt to use non-standard python types in order to produce
  249. python code which more exactly reproduces the behavior of the original mel file, but which
  250. will produce "uglier" code. Use this option if you wish to produce the most reliable code
  251. without any manual cleanup.
  252. verbosity : `int`
  253. Set to non-zero for a *lot* of feedback
  254. """
  255. pass
  256. def melInfo(input):
  257. """
  258. Get information about procedures in a mel file.
  259. >>> import pymel.tools.mel2py as mel2py
  260. >>> mel2py.melInfo('attributeExists')
  261. (['attributeExists'], {'attributeExists': {'returnType': 'int', 'args': [('string', '$attr'), ('string', '$node')]}}, {})
  262. :Parameters:
  263. input
  264. can be a mel file or a sourced mel procedure
  265. :return:
  266. A 3-element tuple:
  267. 1. the list of procedures in the order the are defined
  268. 2. a dictionary of global procedures, with the following entries:
  269. - returnType: mel type to be returned
  270. - args: a list of (type, variable_name) pairs
  271. 3. a dictionary of local procedures, formatted the same as with globals
  272. """
  273. pass
  274. def resolvePath(melobj, recurse=False, exclude=(), melPathOnly=False, basePackage=''):
  275. """
  276. if passed a directory, get all mel files in the directory
  277. if passed a file, ensure it is a mel file
  278. if passed a procedure name, find its file
  279. Returns tuples of the form (moduleName, melfile).
  280. """
  281. pass
  282. MELTYPES = None
  283. SCENE = None
  284. batchData = None
  285. catch = None
  286. contstraintCmdName = None
  287. custom_proc_remap = None
  288. deprecated_str_methods = None
  289. env = None
  290. fileInfo = None
  291. filteredCmds = None
  292. lexer = None
  293. log = None
  294. mel = None
  295. melCmdFlagList = None
  296. melCmdList = None
  297. melGlobals = None
  298. mel_type_to_python_type = None
  299. optionVar = None
  300. parser = None
  301. proc_remap = None
  302. pythonReservedWords = None
  303. reserved = None
  304. scanner = None
  305. scriptTableCmds = None
  306. tag = None
  307. thisModuleCmd = None
  308. tokens = None
  309. workspace = None
  310. x = None