.. currentmodule:: pymel ======================================= What's New in Version 1.0.0 ======================================= ---------------------- New Package Layout ---------------------- PyMEL 1.0 introduces a very big backward incompatibility: importing ``pymel`` no longer imports sub-packages, meaning ``pymel`` is strictly an entry point for its sub-modules. The user must now explicitly import the sub-modules they wish to use. ``pymel.core`` remains the primary module and importing it in batch mode triggers Maya's full startup sequence, just as importing the top-level ``pymel`` module did in previous versions. Sub-Modules with their own namespace ==================================== ============================ ======= ============================================================================================================= Module Alias Description ============================ ======= ============================================================================================================= `pymel.util` utilities which are independent of Maya ---------------------------- ------- ------------------------------------------------------------------------------------------------------------- `pymel.versions` functions for comparing versions of maya (does not require initializing maya) ---------------------------- ------- ------------------------------------------------------------------------------------------------------------- `pymel.mayautils` low-level maya utilities (does not require initializing maya) ---------------------------- ------- ------------------------------------------------------------------------------------------------------------- `pymel.api` OpenMaya classes; requires maya, but does not require initialization of ``maya.standalone`` ---------------------------- ------- ------------------------------------------------------------------------------------------------------------- `pymel.internal` the machinery required to fuse ``maya.OpenMaya`` and ``maya.cmds`` into `pymel.core` (formally ``mayahook``) ---------------------------- ------- ------------------------------------------------------------------------------------------------------------- `pymel.core` the primary sub-package; importing this module initializes maya.standalone in batch mode ---------------------------- ------- ------------------------------------------------------------------------------------------------------------- `pymel.core.nodetypes` ``nt`` contains all node classes, including custom nodes ---------------------------- ------- ------------------------------------------------------------------------------------------------------------- `pymel.core.uitypes` ``ui`` contains all UI classes ---------------------------- ------- ------------------------------------------------------------------------------------------------------------- `pymel.core.datatypes` ``dt`` contains all data classes ============================ ======= ============================================================================================================= Modules with an alias can be accessed by this short name once their parent module is imported. But Why?! ========= One of the tenets of PyMEL's design is that it should add object-oriented programming while still being easy for a novice to use. One way that we tried to accomplish this was by providing access to all of its sub-modules with a single top-level import. However, in the years since this design was first implemented, we've come to realize that this has certain ugly drawbacks. The new layout has several advantages: 1. load time: our new layout uses lazy loading for `pymel.core.uitypes` and `pymel.core.nodetypes`, which delays the creation of classes and methods until they are accessed. This lazy loading dramatically speeds up PyMEL's load time, but it only works if the classes that are being lazily loaded stay in their own namespace. For example, if you do a ``from pymel.core.nodetypes import *``, this forces every class within that module to be loaded. 2. API segregation: `pymel.api` will grow into a robust set of utilities for API development. Under the new design, importing `pymel.api` has very little overhead and will not import any core commands, which could be dangerous to use in the context of a plugin. 3. util accessibility: `pymel.util` contains functions and classes that are not Maya-dependent or even Maya-related so they are useful in many contexts. However, in the old layout you could not import ``pymel.util`` from a command-line script without initializing all of Maya. Similarly, there are two new modules -- `pymel.versions` and `pymel.mayautils` -- which can be used in batch mode without initializing Maya to do things like find user directories, determine what version of Maya the current mayapy corresponds to, etc, then make some decisions based on this info *before* `pymel.core` is imported and all of Maya is initialized. 4. namespace safety: part of the backward incompatibility introduced in this version is the moving of node classes into their own namespace: ``pymel.core.nodetypes``. Without a separate namespace for nodes, user created nodes and commands have the potential to clash with each other, preventing one or the other from being accessible (we're not being paranoid here, we've already had a user approach us with this exact problem). Upgrading ========= To keep things simple and to provide an easy upgrade path, PyMEL 1.0 adds a new module, ``pymel.all``, which imports all sub-modules in exactly the same way that the primary ``pymel`` module does in previous versions. PyMEL also includes a new tool, `pymel.tools.upgradeScripts`, which will find and upgrade existing PyMEL scripts, converting all imports of ``pymel`` into imports of ``pymel.all``. Additionally, PyMEL 0.9.3 is forward compatible with 1.0, meaning it will also provide a ``pymel.all`` module so that "upgraded" code is interoperable between versions. We don't take breaking backward compatibility lightly, but we feel strongly that these changes need to be made to ensure the long-term health of the package, and now is the best time to make them, before PyMEL's rapidly growing user-base gets any larger. .. note:: importing ``pymel.all`` negates the load time improvements that have been made with 1.0. Importing ``pymel.core`` is now the preferred method, but requires some manual work to ensure that all node classes are referenced from their new namespace: ``pymel.core.nodetypes`` or ``pymel.core.nt``. ---------------------- MEL GUI Creation ---------------------- Streamlined GUI Creation ======================== Anyone who has coded GUIs in Maya using both MEL and python will tell you that if there is one thing they miss about MEL (and only one thing), it is the use of indentation to organize layout hierarchy. this is not possible in python because tabs are a syntactical element, indicating code blocks. In this release, PyMEL harnesses python's ``with`` statement to use indentation to streamlines the process of GUI creation. Here is a comparison of the `uiTemplate` example from the Maya docs. First, using ``maya.cmds``:: import maya.cmds as cmds if cmds.uiTemplate( 'ExampleTemplate', exists=True ): cmds.deleteUI( 'ExampleTemplate', uiTemplate=True ) cmds.uiTemplate( 'ExampleTemplate' ) cmds.button( defineTemplate='ExampleTemplate', width=100, height=40, align='left' ) cmds.frameLayout( defineTemplate='ExampleTemplate', borderVisible=True, labelVisible=False ) window = cmds.window(menuBar=True,menuBarVisible=True) cmds.setUITemplate( 'ExampleTemplate', pushTemplate=True ) cmds.columnLayout( rowSpacing=5 ) cmds.frameLayout() cmds.columnLayout() cmds.button( label='One' ) cmds.button( label='Two' ) cmds.button( label='Three' ) cmds.setParent( '..' ) cmds.setParent( '..' ) cmds.frameLayout() cmds.optionMenu() menuItem( label='Red' ) menuItem( label='Green' ) menuItem( label='Blue' ) cmds.setParent( '..' ) cmds.setParent( '..' ) cmds.setUITemplate( popTemplate=True ) cmds.showWindow( window ) menu() menuItem(label='One') menuItem(label='Two') menuItem(label='Sub', subMenu=True) menuItem(label='A') menuItem(label='B') setParent('..', menu=1) menuItem(label='Three') Now, with PyMEL:: from __future__ import with_statement # this line is only needed for 2008 and 2009 from pymel.core import * template = uiTemplate( 'ExampleTemplate', force=True ) template.define( button, width=100, height=40, align='left' ) template.define( frameLayout, borderVisible=True, labelVisible=False ) with window(menuBar=True,menuBarVisible=True) as win: # start the template block with template: with columnLayout( rowSpacing=5 ): with frameLayout(): with columnLayout(): button( label='One' ) button( label='Two' ) button( label='Three' ) with frameLayout(): with optionMenu(): menuItem( label='Red' ) menuItem( label='Green' ) menuItem( label='Blue' ) # add a menu to an existing window with win: with menu(): menuItem(label='One') menuItem(label='Two') with subMenuItem(label='Sub'): menuItem(label='A') menuItem(label='B') menuItem(label='Three') Python's ``with`` statement was added in version 2.5 (Maya 2008 and 2009). It's purpose is to provide automatic "enter" and "exit" functions for class instances that are designed to support it. This is perfect for MEL GUI creation: for example, when we enter the ``with`` block using a PyMEL `ui.Layout` class or a command that creates one, the layout object sets itself to the active default parent, and when the code block ends, it restores the default parent to it's own parent. There is now little need to ever call `setParent`. As you can see in the example, the ``with`` statement also works with windows, menus, and templates: windows call ``setParent`` and ``showWindow``, and templates are automatically "pushed" and "popped". Layout Class ============ Support for python's 'with' statement is made possible by the new `Layout` class. Layouts also provide a number of methods for walking UI hierarchies. Continuing from our previous example:: # hide all children of the window for ctrl in win.walkChildren(): print ctrl.setVisible(False) --------------------------- Components --------------------------- all component types supported --------------------------- Tighter Maya Integration --------------------------- PyMEL now includes a partial replacement of the ``maya`` package in order to add tight, low-level integration. This allows us to easily solve several problems that have proven tricky to solve otherwise: - safe to use PyMEL inside userSetup.py in python standalone - fixes bug where certain commands don't return a result the first time they are called - shared root logger with status-line error and warning colorization --------------------------- IDE Autocompletion --------------------------- PyMEL Auto-completion in your favorite IDE -- such as Eclipse, Wing, and Komodo -- is now fast, reliable, and easy to setup. This is accomplished by providing pre-baked ``maya`` and ``pymel`` "stub" packages, which contain all of the classes and functions of the originals, stripped down to only definitions and documentation strings. Add the path to these packages to your IDE ``PYTHONPATH`` and you're ready to go. Jump over to :doc:`eclipse` for a tutorial. ------------------------------------ Python Attribute Editor Templates ------------------------------------ This version adds support for the creation of pure-python Attribute Editor templates, using a new class `uitypes.AETemplate`. Here's a simple example:: class AEmib_amb_occlusionTemplate(ui.AETemplate): def __init__(self, nodeName): print "building", nodeName self.beginScrollLayout() self.beginLayout("Parameters",collapse=0) self.addControl("spread", label="Spread", preventOverride=True) self.addControl("max_distance", label="MaxDistance") self.addControl("reflective", label="Reflective") self.addControl("output_mode", label="OutputMode") self.endLayout() self.suppress("id_nonself") self.dimControl(nodeName, "spread", True) self.endScrollLayout() For PyMEL to recognize the template, it must be in a module named ``AETemplates``. There's a new example in the pymel examples directory demonstrating more sophisticated use. ------------------------------------ Last But Not Least ------------------------------------ Attribute Aliases ================= * ``DependNode.attr()`` now casts aliases to Attributes (PyNode already does) * added ``DependNode.listAliases()`` * added 'alias' keyword to ``DependNode.listAttr()`` * added ``Attribute.setAlias()``, ``Attribute.getAlias()`` New 'regex' Flag for ``ls`` Command =================================== pass a valid regular expression string, compiled regex pattern, or list thereof. >>> group('top') nt.Transform(u'group1') >>> duplicate('group1') [nt.Transform(u'group2')] >>> group('group2') nt.Transform(u'group3') >>> ls(regex='group\d+\|top') # don't forget to escape pipes `|` [nt.Transform(u'group1|top'), nt.Transform(u'group2|top')] >>> ls(regex='group\d+\|top.*') [nt.Transform(u'group1|top'), nt.Camera(u'group1|top|topShape'), nt.Transform(u'group2|top'), nt.Camera(u'group2|top|topShape')] >>> ls(regex='group\d+\|top.*', cameras=1) [nt.Camera(u'group2|top|topShape'), nt.Camera(u'group1|top|topShape')] >>> ls(regex='\|group\d+\|top.*', cameras=1) # add a leading pipe to search for full path [nt.Camera(u'group1|top|topShape')]