diff --git a/cmdx.py b/cmdx.py index 49c51c3..fa9b740 100644 --- a/cmdx.py +++ b/cmdx.py @@ -1022,10 +1022,20 @@ def addAttr(self, attr): """ - if isinstance(attr, _AbstractAttribute): - attr = attr.create() + attr_obj = attr.create() if isinstance(attr, _AbstractAttribute) else attr + self._fn.addAttribute(attr_obj) + + # workaround for string attribute default value, see String.default() for details + def setAttr(attr): + if isinstance(attr, String): + default = _AbstractAttribute.default(attr) + if default: + self.findPlug(attr["name"]).setString(default) + elif isinstance(attr, Compound): + for child in attr["children"]: + setAttr(child) + setAttr(attr) - self._fn.addAttribute(attr) def hasAttr(self, attr): """Return whether or not `attr` exists @@ -5120,8 +5130,43 @@ class String(_AbstractAttribute): Default = "" def default(self, cls=None): - default = str(super(String, self).default(cls)) - return om.MFnStringData().create(default) + """ + string attributes can't have default values (http://help.autodesk.com/cloudhelp/2020/ENU/Maya-Tech-Docs/Commands/addAttr.html#flagdefaultValue), + or at least it isn't saved in scenes (https://github.com/mottosso/cmdx/issues/34) + -> don't pass the default to OpenMaya, instead set it during Node.addAttr() + + Test: + >>> import os + >>> os.environ["CMDX_SAFE_MODE"] = "True" # disable caching (node/plug reuse) + >>> import cmdx + >>> # new scene with a sphere with "my_string" attribute + >>> _ = cmds.file(new=True, force=True) + >>> sphere_name = cmds.sphere()[0] + >>> sphere = cmdx.encode(sphere_name) + >>> sphere.add_attr(cmdx.String("my_string", default="foo")) + >>> sphere["my_string"].name() + 'my_string' + >>> # save scene + >>> import tempfile + >>> scene_file = tempfile.NamedTemporaryFile(prefix="test_string_attribute_", suffix=".ma") + >>> scene_path = scene_file.name + >>> _ = cmds.file(rename=scene_path) + >>> _ = cmds.file(save=True, type="mayaAscii") + >>> # reload scene & check "my_string" + >>> _ = cmds.file(scene_path, open=True, force=True) + >>> sphere = cmdx.encode(sphere_name) + >>> str(sphere) + '|nurbsSphere1' + >>> if sphere["my_string"].name() != "my_string": + ... print(scene_path) + ... with open(scene_path) as f: print(f.read()) + >>> sphere["my_string"].name() + 'my_string' + >>> scene_file.close() # deletes the temp file (supposedly) + >>> sphere["my_string"].read() + u'foo' + """ + return None def read(self, data): return data.inputValue(self["mobject"]).asString()