Maya py2 to py 3 impact to fileInfo strings

Hey.

I am going through the conversion for py2 to py3 for Maya. I have noticed that strings retrieved from from pm.fileInfo() may have been impacted. My guess is that it is related to unicode changes in python. (All of this used to ‘just’ work with python 2.)

Before I do any grunt work reformatting the string from fileInfo I thought I’d ask you all if you had any suggestion.

Sample Code:

import pymel.core as pm
from xml.etree import ElementTree as ET
from xml.dom import minidom

root = ET.Element("root")
doc = ET.SubElement(root, "animations")

joint_attributes = {'node_type':'joints'}
joints = ET.SubElement(doc, 'joint', attrib=joint_attributes)
joint1 = ET.SubElement(joints, 'joint1')
transform1 = ET.SubElement(joint1, 'transform')
ET.SubElement(transform1, "rotate").text = '(1,2,3)'
ET.SubElement(transform1, "translate").text = '(1,2,3)'
ET.SubElement(transform1, "scale").text = '(1,2,3)'

xmlstr = minidom.parseString(ET.tostring(root, encoding='utf-8')).toprettyxml(indent="   ")

print(xmlstr)

print output


<?xml version="1.0" ?>
<root>
   <animations>
      <joint node_type="joints">
         <joint1>
            <transform>
               <rotate>(1,2,3)</rotate>
               <translate>(1,2,3)</translate>
               <scale>(1,2,3)</scale>
            </transform>
         </joint1>
      </joint>
   </animations>
</root>

I can read this string (xmlstr) into ET

read_string = ET.fromstring(xmlstr)

I then take the string and add it to fileInfo and retrieve it

pm.fileInfo['xml_test'] = xmlstr
xml_test = pm.fileInfo['xml_test']
print(xml_test )

print output

<?xml version=\"1.0\" ?>\n<root>\n <animations>\n <joint node_type=\"joints\">\n <joint1>\n <transform>\n <rotate>(1,2,3)</rotate>\n <translate>(1,2,3)</translate>\n <scale>(1,2,3)</scale>\n </transform>\n </joint1>\n </joint>\n </animations>\n</root>\n

And the string from fileInfo (xml_test) throws an error while with ElementTree

read_string = ET.fromstring(xml_test)

Error:


Error: ParseError: file C:\Program Files\Autodesk\Maya2022\Python37\lib\xml\etree\ElementTree.py line 1315: XML declaration not well-formed: line 1, column 14

I have tried different encoding passes on the string both before and after adding to fileInfo. (As well as set the encoding for the xml to be ‘utf-8’ and ‘unicode’) :

pm.fileInfo['xml_test'] = xmlstr.encode('utf-8')

or

xml_test = (pm.fileInfo['xml_test']).encode('utf-8')

The desired result would be to read the string from fileInfo (xml_test) and have it comply with ElementTrees expectations. The authoritative version of data lives in fileInfo to be consumed by other tools later after it is converted to xml.

Thanks in advance
-jonathan

    def __getitem__(self, item):
        # type: (str) -> str
        result = cmds.fileInfo(item, q=1)
        if not result:
            raise KeyError(item)
        elif len(result) > 1:
            raise RuntimeError("error getting fileInfo for key %r - "
                               "more than one value returned" % item)
        else:
            value = result[0]
            if PY2:
                if isinstance(value, bytes):
                    return value.decode('string_escape')
                else:
                    # unicode
                    return value.decode('unicode_escape')
            else:
                return value

    def __setitem__(self, item, value):
        cmds.fileInfo(item, value)

This is currently what the FileInfo class does to handle its __getitem__ and __setitem__.
It looks like it is returning the value directly when in PY3, I’ve not tested this yet, but it’s possible that it needs to be escaped properly as cmds.fileInfo has a habit of adding extra backslashes to things that might piss off the xml code.

Thanks bob.w. I’ll play around with backslashes.

The problem seemed to be a combination the ‘attrib=’ added to the xml file

        doc = ET.SubElement(root, Identifiers.layer_str, attrib=model_layer_attr)
        models = ET.SubElement(doc, Identifiers.model_str, attrib=model_attr)

and minidom.toprettyxml()

return minidom.parseString(ET.tostring(root)).toprettyxml(indent=" ")

I can read and write to fileInfo now. I just need to automate a conversion for preexisting data.

Thanks
-jonathan

1 Like

…actually, I found a better solution. after looking into unicode and python 3 i found that if i do this:

xml_test = xml_test.encode().decode('unicode-escape')

it fixes the issue with no other changes