referenceQuery / getReferenceEdit bug - Pymel?

666 views
Skip to first unread message

MarkJ

unread,
Jun 18, 2010, 6:30:04 AM6/18/10
to python_inside_maya
I've been deep in referencing hell for the last few weeks, trying to
debug some issues with the way Maya handles namespaces and references
in our pipeline. Part of this is to do a fast checker that will give
the guys a heads up as to the health status of the ref scenes they're
working on. I'm basically trying to get a printout of all failed
referenceEdits for all loaded referenceNodes.

It looks like I've come across a possible bug in the way Pymel hadles
this. Code below is a simple test wrapper, in the scene I've got 3
references all pointing to the same file. I know that all 3 have
failed edits on them and if I run the below code using the
cmds.refQuery I get all 3 as fails + the count. But using either of
the Pymel blocks I only get the fails caught for the first ref, not
the other 3.

refNodes=[ref for ref in pCore.listReferences() if ref.isLoaded()]
for ref in refNodes:
print ref,
len(pm.referenceQuery(ref.refNode,successfulEdits=False,failedEdits=True,es=True))
print ref,
len(cmds.referenceQuery(str(ref.refNode),successfulEdits=False,failedEdits=True,es=True))
print ref, len(ref.getReferenceEdits(failedEdits=True))

anybody else come across issues with this?

thanks

Mark

Erkan Özgür Yılmaz

unread,
Jun 28, 2010, 8:19:22 AM6/28/10
to python_in...@googlegroups.com
I have a similiar problem with references:

- trying to get referenceEdits for a referenced node inside another referenced node gives nothing until I specify that I want to get the edits those has been done in a specific reference node by using onReferenceNode flag whereas both maya and pymel documentation says not using onReferenceNode causes you to get all the edits.

- trying to change edit targets with referenceEdit.changeEditTarget is not working in above case with or without onReferenceNode flag

I'm not saying that these are bugs, may be they are not very well documented or I don't understand the correct usage... But I must say that in other cases I use these commands successfully to change referenced files with new ones. I only have problem when the referenced file also has some references to other files...

E.Ozgur Yilmaz
Lead Technical Director
eoyilmaz.blogspot.com
www.ozgurfx.com



Mark Jackson

unread,
Jun 28, 2010, 9:26:56 AM6/28/10
to python_in...@googlegroups.com
Ok, I think I've found the issue, and it's the fact that PyMel is passing in the reference path to the cmds.referenceQuery command and not the refNode itself.

 Looks like Maya cmds can't cope with copyNumbers {x} being passed in, I've got multiple references pointing to a single file so the paths are given with the copyNumber{x} and it looks like this isn't handled. The minute you pass the refNode itself all is well:

In pm.core.system I just edited line 1222 so that the refNode is passed in instead.

            edits = cmds.referenceQuery(fr.refNode,
                                        failedEdits = not mode,
                                        successfulEdits = mode,
                                        **kwargs)


In cmds try this, make a cube, add an attr 'foo', save it and then reference multiple times to a new file, animate foo save the scene. Open the cube file and delete foo to generate the failedEdits and reopen the file with the multiple refs: try this:

edits = cmds.referenceQuery('cubeRN1', failedEdits=True, successfulEdits=False, es=True)

edits = cmds.referenceQuery('C:/cube{1}', failedEdits=True, successfulEdits=False, es=True)


First one finds the edits, second one finds nothing.


I've added that to our server copy of pymel but let me know if that's safe and there's no other reason for you were passing in the path in the first place


cheers


Mark





Erkan Özgür Yılmaz

unread,
Jun 29, 2010, 4:55:17 PM6/29/10
to python_in...@googlegroups.com
I was wrong about getting the right reference edits. The method, FileReference.getReferenceEdits, returns the list of the edits done in the reference node of that FileReference instance (FileReference.refNode). To get the edits on a differenct reference node, which is what I want, I should always give a reference node to onReferenceNode flag. The behaviour of maya and pymel is correct... I was wrong about that in previous posts... Also changeEditTarget is not working in my case, but its behaviour is somewhat correct (where I don't expect that to happen).


E.Ozgur Yilmaz
Lead Technical Director
eoyilmaz.blogspot.com
www.ozgurfx.com


Paul Molodowitch

unread,
Jul 9, 2010, 1:25:41 AM7/9/10
to python_in...@googlegroups.com
Mark, your fix is in my latest pymel, as well as a test for it.

Been taking a look at the way getReferenceEdits works (as well as how
cmds.referenceQuery(es=1) works), and I think we're gonna need to
change it's behavior. Right now, what it returns just isn't very
useful.

To explain - there's basically two ways you can group refEdits in
relation to reference nodes - by what ref node they're stored on, and
by which objects they affect (and which ref node those objects are
'introduced' in). (These can be different reference nodes when
reference nodes are nested...) So, if you're querying a reference
node for it's ref edits, I can think of three possible results it
could return which you might consider 'useful':

1) All the refEdits which affects nodes introduced by it
2) All the refEdits stored on it
3) All the refEdits which affect nodes introduced by it, but stored on
the 'topReference' node

The first two are potentially useful for partioning; ie, if you
iterated over all the reference nodes in the scene, using either
methods 1 or 2, you'd end up with all the ref edits, grouped in some
sort of sane manner. The third is useful for getting the reference
edits which "make sense" in the context of a given scene (see the docs
on referenceQuery for only the edits on the topReference are the ones
you'll usually care about in a given scene).

Unfortunately, currently getReferenceEdits returns none of these -
instead, it returns the ref edits which affect the it's nodes, and are
stored on it. While this might seem appealing from a symmetry
standpoint, it's actually not very useful when the node is not it's
own 'topReference'. I really can't think of any situation in which
you'd be interested in that particular set of edits.

So, I think I'll probably alter the behavior of getReferenceEdits to
instead return #3.... at least by default - the ideal would be to have
flags to alter which set of edits is returned...

This would break backward compatibility for this command, but since I
can't imagine many people actually wanting the current behavior (as
Erkan's case illustrates), I don't think that will be a big issue.

Also - Erkan, haven't had a chance yet to look at your
changeEditTarget issue... if you could supply some sample code
illustrating a case where it's broken, it would help, though...

- Paul

2010/6/29 Erkan Özgür Yılmaz <eoyi...@gmail.com>:

> --
> http://groups.google.com/group/python_inside_maya

Mark Jackson

unread,
Jul 9, 2010, 4:28:31 AM7/9/10
to python_in...@googlegroups.com
Thanks for that, I'll get Dave to grab the next Git build. In our case it was a simple SceneHealth function that I was writing, pass each refNode and check for editFails, then report those back on file open/referenceSwitch to catch issues. Fortunately we don't run nested refs, we force the riggers to flatten all their referencing before the files are passed over to the animators, at which point they're ref managed by our AssetManager.

I can see your point with the topRef though, nested child refEdits wouldn't be of much use anyway unless you're just debugging

Mark




Erkan Özgür Yılmaz

unread,
Jul 9, 2010, 7:08:25 AM7/9/10
to python_in...@googlegroups.com
Hi Paul,

What I wanted to achieve was to replace a referenced file with another, where the first reference (the replaced one) is actually a reference inside the newly replaced file.

May be it is somehow a wrong pipeline design I did. In our current pipeline, we reference the rig assets to shading assets and do the shading in this scene. There is no problem if the rig asset doesn't have any references ( ex. the model asset is not referenced to the rig asset but imported ). So referencing the rig asset to shading asset, and replacing all the references in animations with the shading asset and using the changeEditTarget doesn't cause any problem.

The problem is, when you have a rig asset that has some references to ( lets say ) model assets, then in animation scene when I replace the rig asset with shading asset I loose all the edits, even I don't have a single edit that I can change the target on. In any case I should be able to get all the edits done in top level reference node as failed edits, but I can't...

So as a work around, I query all the edit commands, replace the assets and apply the edits by changing the namespace in the MEL commands. With this workaround I got errors in "parent" commands because the long name of the objects are changing, and the other edits becomes invalid.

So that's all I think :)

and thank you for your interest...

Cheers...


E.Ozgur Yilmaz
Lead Technical Director
eoyilmaz.blogspot.com
www.ozgurfx.com



Mark Jackson

unread,
Jul 9, 2010, 8:52:57 AM7/9/10
to python_in...@googlegroups.com
Are you in 2011? I've just spend the last few weeks in deep discussions with Autodesk over a number of bugs in the way reference edits and specifically namespaces are handled. In 2010 the namespaces were all based on root space ':' and there were some issues with editing namespaces which left the edits incorrect and therefore broke the files.

In 2011 they added the 'relative' flag and things are way more stable. What it doesn't say in the docs (or not that I can find) is that the namespaces are relative to the namespace of the refNode itself. We've always renamed the refNode when switching characters so that things are consistent, I could never understand why, when switching the referenced Namespace there wasn't some name handling performed on the refNode itself so that when you looked in the referenceEditor, things actually made sense.

Anyway, with the relative flag all the namespace handling is solid, at last..... you just have to remember that it's all 'relative' (or at least it is if you want to take advantage of it)

If it's of any use to anybody here's our rename snippet... Like i say, this is after a lot of snag catching between us and Autodesk:

namespace=fileRef.namespace
        parentNS=pCore.Namespace(cmds.file(path, q=True, pns=True )[0])

        if checkNSClashes:
            # Resolve ns clashes prior to renaming
            NewNameSpace=NameSpaceUtils.ResolveNameSpaceClash(NewNameSpace,DebugPrint=True)

        print '\nparentSpace : %s \npath : %s \nnewNS : %s' % (parentNS,path,NewNameSpace)
        try:
            if parentNS:
                pCore.lockNode(refNode,lock=False)
                pCore.rename(refNode, '%s:%sRN' % (str(parentNS),str(NewNameSpace)))
                pCore.lockNode(refNode,lock=True)
                pCore.namespace(set=parentNS) # move to the child's parent space
                cmds.namespace(rel=True)
            else:
                pCore.lockNode(refNode,lock=False)
                pCore.rename(refNode, '%sRN' % (str(NewNameSpace)))
                pCore.lockNode(refNode,lock=True)

            # rename the namespace using the relative namespace code form 2011
            cmds.file(path,e=True,ns=NewNameSpace)
            cmds.namespace(rel=False)
            cmds.namespace(set=':')


Not sure if that's of any help to anybody


cheers

Mark




John Creson

unread,
Jul 9, 2010, 2:43:12 PM7/9/10
to python_in...@googlegroups.com
The other thing to keep in mind around relative namespaces...

by default, expressions are executed in relative namespace...
This is good thing because you can use hard coded node names in your
child file and reference the scene into another as many times as you
like and each expression will find its intended nodes.
This can be turned off with a line at the top of the expression
namespace -relative false

just so you know, at this point particle expressions are not by
default using relative namespaces

also, if you don't like using hard-coded names...
you can use the (node) keyword in an expression and you will be
returned the name of the expression node - with which you may do what
you like to get to the nodes you need - walking message connections
perhaps? (relative or not depending on which mode it is in at the
moment - this can be important if you need to put something in an
expression that is evalDeferred - since by the time it gets around to
executing it, you'll be back in root relative mode)

> --
> http://groups.google.com/group/python_inside_maya

Reply all
Reply to author
Forward
0 new messages