[PYTHON] Remplacez tous les indicateurs écrits par des noms courts dans maya.cmds par des noms longs

Cet article est un article du 20 décembre du Calendrier de l'Avent Maya-Python 2016.

introduction

Dans maya.cmds, vous pouvez écrire l'indicateur à passer à la commande de deux manières: ** notation de nom court ** et ** notation de nom long **. Par exemple, si vous utilisez la commande maya.cmds.optionMenu pour écrire des processus avec la même signification en notation de nom court et en notation de nom long, cela ressemblera à ceci.

#Notation de nom court
cmds.optionMenu(name, en=True, l="top_node:",
                vis=True, ann=u"Sélectionnez le nœud supérieur", w=200,
                cc=partial(self.change_topnode, name))

#Notation de nom long
cmds.optionMenu(name, enable=True, label="top_node:",
                visible=True, annotation=u"Sélectionnez le nœud supérieur", width=200,
                changeCommand=partial(self.change_topnode, name))

La notation de nom court rend le code plus compact, donc il peut être préférable pour ceux qui y sont habitués. Cependant, pour les débutants de maya.cmds comme moi, chaque fois qu'un indicateur de nom court apparaît lors de l'héritage ou de la révision du code écrit par quelqu'un d'autre, [Autodesk Maya Python Command Reference](http: // aide) .autodesk.com / cloudhelp / 2016 / JPN / Maya-Tech-Docs / CommandsPython / index.html) est inefficace.

Par conséquent, cette fois, nous allons créer un script qui remplace l'indicateur de notation de nom court par la notation de nom long à la fois.

environnement

Le fonctionnement du programme a été confirmé dans l'environnement suivant.

Préparation

Seul un module externe appelé astor est requis, donc installez-le avec pip.

pip install astor

Utiliser AST (arbre de syntaxe abstraite)

AST (Abstract Syntax Tree) est utilisé pour analyser et remplacer les noms de paramètres utilisés lors de l'appel de la fonction maya.cmds. Avec le module ast inclus dans le standard python, vous pouvez obtenir un AST simplement en analysant le code que vous souhaitez analyser.

import ast


if __name__ == '__main__':

    example = """def fake(x):
        import maya.cmds as cmds
        cmds.optionMenu(name, q=True, v=True)
        return 0
    """

    tree = ast.parse(example)
    print ast.dump(tree)

Lorsque le programme ci-dessus est exécuté, le résultat suivant sera affiché.

Module(body=[FunctionDef(name='fake', args=arguments(args=[Name(id='x', ctx=Param())], 
vararg=None, kwarg=None, defaults=[]), body=[Import(names=[alias(name='maya.cmds', 
asname='cmds')]), Expr(value=Call(func=Attribute(value=Name(id='cmds', ctx=Load()), 
attr='optionMenu', ctx=Load()), args=[Name(id='name', ctx=Load())], 
keywords=[keyword(arg='q', value=Name(id='True', ctx=Load())), keyword(arg='v', 
value=Name(id='True', ctx=Load()))], starargs=None, kwargs=None)), 
Return(value=Num(n=0))], decorator_list=[])])

C'est un peu long et difficile à lire, mais ici

Il est important que vous puissiez obtenir des informations sur la région. En d'autres termes, vous pouvez voir quelle commande dans maya.cmds est exécutée avec quel argument indicateur.

Exécutez la commande help () à l'aide de mayapy

Maintenant que nous savons que nous pouvons utiliser AST pour savoir si la notation de nom court est utilisée dans le code, l'étape suivante consiste à obtenir la table de correspondance entre la notation de nom court et la notation de nom long dans chaque maya.cmds. Si vous passez le nom de la commande à maya.cmds.help (), elle renverra la notation du nom court et la notation du nom long comme indiqué ci-dessous.

import maya.cmds
print(maya.cmds.help("optionMenu"))

-----------------------------------------------------
emballer: optionMenu [flags] [String]
Flags:
   -e -edit
   -q -query
 -acc -alwaysCallChangeCommand 
 -ann -annotation               String
 -bgc -backgroundColor          Float Float Float
  -cc -changeCommand            Script
...(réduction)

Générez dynamiquement un dict avec la notation du nom court comme clé et la notation du nom long comme valeur à l'aide d'expressions régulières.

help_regex.py


method_name_dict = {}

help_messages = cmds.help(method_name)
method_name_dict[method_name] = {}

for line in help_messages.split(os.linesep):
    arg_names = re.search(r"-([a-zA-Z0-9]+) -([a-zA-Z0-9]+)", line)
    if arg_names:
        method_name_dict[method_name][arg_names.group(1)] = arg_names.group(2)

Vous pouvez créer un objet dict comme celui-ci

[('optionMenu', {u'en': u'enable', u'cc': u'changeCommand', u'm': u'manage', u'ann': u'annotation',  ...(réduction)

Cependant, la commande maya.cmds.help () doit être exécutée dans l'environnement d'exécution python de maya. (Normalement, fonctionner avec python aaa.py ne renvoie rien)

Pour Mac /Applications/Autodesk/maya2015/Maya.app/Contents/bin/mayapy Pour les fenêtres C:\Program Files\Autodesk\Maya2015\bin\mayapy.exe

Il y a mayapy autour, donc si vous exécutez un programme python avec lui, vous obtiendrez le résultat de la commande help (). /Applications/Autodesk/maya2015/Maya.app/Contents/bin/mayapy aaa.py

Vous êtes maintenant prêt à remplacer le nom court par le nom long.

Remplacez les nœuds par ast.NodeTransformer

Utilisez NodeTransformer pour vérifier, remplacer ou supprimer chaque élément de l'AST. Par exemple, si vous voulez faire quelque chose sur le nœud d'appel de fonction (Call) comme cette fois, définissez la fonction visit_Call (self, node) et écrivez le processus.

class MayaPythonShort2LongNameNodeTransformer(ast.NodeTransformer):
    def visit_Call(self, node):
        #J'écrirai le processus de remplacement ici

Après avoir remplacé le nom du drapeau par NodeTransformer, revenez enfin au code python avec astor.to_source ().

print(astor.to_source(tree).decode("unicode-escape"))

Nom court-> script de remplacement de nom long

Le code suivant est un résumé approprié du traitement ci-dessus.

maya_cmds_name_converter.py


# -*- coding: utf-8 -*-
from __future__ import absolute_import, division, print_function, unicode_literals
import os
import re
import ast
import astor
import maya.standalone
import maya.cmds as cmds


class MayaPythonShort2LongNameNodeTransformer(ast.NodeTransformer):
    def __init__(self):
        self.method_name_dict = {}

    @staticmethod
    def is_maya_cmds_func(node):
        return hasattr(node, "func") and hasattr(node.func, "value") and hasattr(node.func.value, "id") and \
            node.func.value.id == "cmds"

    def visit_Call(self, node):

        if self.is_maya_cmds_func(node):
            method_name = node.func.attr

            if not self.method_name_dict.get(method_name):
                # short_nom et long_Créer un dict correspondant pour le nom
                try:
                    help_messages = cmds.help(method_name)
                except RuntimeError:
                    # print(u"help()Est une commande non prise en charge: " + method_name)
                    return node

                self.method_name_dict[method_name] = {}
                for line in help_messages.split(os.linesep):
                    arg_names = re.search(r"-([a-zA-Z0-9]+) -([a-zA-Z0-9]+)", line)
                    if arg_names:
                        self.method_name_dict[method_name][arg_names.group(1)] = arg_names.group(2)

            for keyword in node.keywords:
                if keyword.arg in {"q", "e", "c", "m"}:
                    #Ignorer si drapeau de base
                    continue

                long_name = self.method_name_dict[method_name].get(keyword.arg)
                if long_name:
                    if long_name == "import":
                        #Dans ce cas, ça devient étrange comme python
                        continue

                    # print(keyword.arg + u"À" + long_name + u"Convertir en")
                    keyword.arg = long_name

        return node


if __name__ == '__main__':
    maya.standalone.initialize(name='python')

    #Exemple de code pour les tests
    example = """def fake(x):
        import maya.cmds as cmds
        cmds.optionMenu(name, en=True, l="top_node:",
                vis=True, ann=u"Sélectionnez le nœud supérieur", w=200,
                cc=partial(self.change_topnode, name))
        return top_node
    """

    tree = ast.parse(example)
    tree = MayaPythonShort2LongNameNodeTransformer().visit(tree)

    # after convert python code
    print(astor.to_source(tree).decode("unicode-escape"))

    if float(cmds.about(v=True)) >= 2016:
        maya.standalone.uninitialize()

Lorsque ce programme est exécuté, la commande de l'indicateur de notation de nom court introduit au début est remplacée par la notation de nom long et la sortie.

Avant le remplacement


def fake(x):
        import maya.cmds as cmds
        cmds.optionMenu(name, en=True, l="top_node:",
                vis=True, ann=u"Sélectionnez le nœud supérieur", w=200,
                cc=partial(self.change_topnode, name))
        return top_node

Après remplacement


def fake(x):
    import maya.cmds as cmds
    cmds.optionMenu(name, enable=True, label='top_node:', visible=True, annotation=u'Sélectionnez le nœud supérieur', width=200, changeCommand=partial(self.change_topnode, name))
    return top_node

Précautions / restrictions

Cela semblait fonctionner, mais après ast.parse le code python, lorsque je le reconvertis en code python avec astor.to_source (), je perds beaucoup d'informations de formatage.

--u "" "Ceci est une chaîne de documentation" "" est tout u \ Ceci est une chaîne de documentation \

Donc, après avoir effectué le remplacement du nom court -> nom long, je le nettoie séparément avec AutoFormatter / suppression / remplacement d'avertissement avec PyCharm. ..

Résumé

Si vous vous y habituez, la notation du nom court peut être plus facile à écrire et à lire, mais je ne me souviens toujours pas du grand nombre d'indicateurs contenus dans maya.cmds.

Maintenant que nous savons que l est label et v est value, je pense que c'est une bonne idée de décider des règles pour les noms de drapeau en fonction de la compétence de l'équipe impliquée dans le code. Si c'est un drapeau qui semble rarement utilisé, vous pouvez comprendre la signification en regardant le nom long, mais s'il s'agit d'un nom court, il sera certainement envoyé comme référence de commande, alors soyez prudent.

bsp -> beforeShowPopup npm -> numberOfPopupMenus vcc -> visibleChangeCommand Et.

Recommended Posts

Remplacez tous les indicateurs écrits par des noms courts dans maya.cmds par des noms longs
Remplacez tout d'un coup par sed
Test de stress avec Locust écrit en Python
Gacha écrit en python-Rareté confirmée avec bonus-
Remplacer non-ASCII par des expressions régulières en Python
Remplacez les noms / valeurs des colonnes par pandas dataframe