From 826f9493f9336ac4c8b5dc18b44dcb0dadf7716c Mon Sep 17 00:00:00 2001 From: Benoit Fouletier Date: Wed, 4 Nov 2020 08:52:39 +0100 Subject: [PATCH 01/17] fix for string attributes default values - see https://github.com/mottosso/cmdx/issues/34 - handles Compounds recursively --- cmdx.py | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/cmdx.py b/cmdx.py index 49c51c3..250290a 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 @@ -5119,9 +5129,11 @@ class String(_AbstractAttribute): Type = om.MFnData.kString 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() def default(self, cls=None): - default = str(super(String, self).default(cls)) - return om.MFnStringData().create(default) + return None def read(self, data): return data.inputValue(self["mobject"]).asString() From fff67552e512ea1557db876a9d55daead0afe0df Mon Sep 17 00:00:00 2001 From: Benoit Fouletier Date: Wed, 4 Nov 2020 11:37:05 +0100 Subject: [PATCH 02/17] add unit test --- cmdx.py | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/cmdx.py b/cmdx.py index 250290a..abbe2f5 100644 --- a/cmdx.py +++ b/cmdx.py @@ -5129,10 +5129,30 @@ class String(_AbstractAttribute): Type = om.MFnData.kString 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() def default(self, cls=None): + """ + 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: + >>> # 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")) + >>> + >>> # save scene + >>> scene_path = "test.ma" + >>> 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) + >>> sphere["my_string"] == "foo" + True + """ return None def read(self, data): From d8299673a88327353d8e99bf6735b5cd88184edf Mon Sep 17 00:00:00 2001 From: Benoit Fouletier Date: Wed, 4 Nov 2020 11:54:57 +0100 Subject: [PATCH 03/17] unit test needs `import cmdx` --- cmdx.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cmdx.py b/cmdx.py index abbe2f5..91d19fc 100644 --- a/cmdx.py +++ b/cmdx.py @@ -5136,6 +5136,7 @@ def default(self, cls=None): -> don't pass the default to OpenMaya, instead set it during Node.addAttr() Test: + >>> import cmdx >>> # new scene with a sphere with "my_string" attribute >>> cmds.file(new=True, force=True) >>> sphere_name = cmds.sphere()[0] From f6faddd913341aeb881f1d6403881cc27ea49872 Mon Sep 17 00:00:00 2001 From: Benoit Fouletier Date: Wed, 4 Nov 2020 12:05:24 +0100 Subject: [PATCH 04/17] add some prints to debug the test --- cmdx.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cmdx.py b/cmdx.py index 91d19fc..fc9a9a6 100644 --- a/cmdx.py +++ b/cmdx.py @@ -5150,8 +5150,12 @@ def default(self, cls=None): >>> >>> # reload scene & check "my_string" >>> cmds.file(scene_path, open=True, force=True) + >>> print(sphere_name) >>> sphere = cmdx.encode(sphere_name) - >>> sphere["my_string"] == "foo" + >>> print(sphere) + >>> my_string = sphere["my_string"] + >>> print(my_string) + >>> my_string == "foo" True """ return None From 1987cfd42b8d68275bc762e6247e2adfe4078775 Mon Sep 17 00:00:00 2001 From: Benoit Fouletier Date: Wed, 4 Nov 2020 12:28:14 +0100 Subject: [PATCH 05/17] fix test --- cmdx.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/cmdx.py b/cmdx.py index fc9a9a6..42a37c5 100644 --- a/cmdx.py +++ b/cmdx.py @@ -5138,25 +5138,23 @@ def default(self, cls=None): Test: >>> import cmdx >>> # new scene with a sphere with "my_string" attribute - >>> cmds.file(new=True, force=True) + >>> _ = 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")) >>> >>> # save scene >>> scene_path = "test.ma" - >>> cmds.file(rename=scene_path) - >>> cmds.file(save=True, type="mayaAscii") + >>> _ = cmds.file(rename=scene_path) + >>> _ = cmds.file(save=True, type="mayaAscii") >>> >>> # reload scene & check "my_string" - >>> cmds.file(scene_path, open=True, force=True) - >>> print(sphere_name) + >>> _ = cmds.file(scene_path, open=True, force=True) >>> sphere = cmdx.encode(sphere_name) >>> print(sphere) - >>> my_string = sphere["my_string"] - >>> print(my_string) - >>> my_string == "foo" - True + |nurbsSphere1 + >>> sphere["my_string"] + "foo" """ return None From 25f7133d72f6bff677e5c1feafa175b545d76429 Mon Sep 17 00:00:00 2001 From: Benoit Fouletier Date: Wed, 4 Nov 2020 13:06:05 +0100 Subject: [PATCH 06/17] str() + remove quotes --- cmdx.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmdx.py b/cmdx.py index 42a37c5..967c319 100644 --- a/cmdx.py +++ b/cmdx.py @@ -5153,8 +5153,8 @@ def default(self, cls=None): >>> sphere = cmdx.encode(sphere_name) >>> print(sphere) |nurbsSphere1 - >>> sphere["my_string"] - "foo" + >>> str(sphere["my_string"]) + foo """ return None From 48b9c68bc75c6b88c067b9b3283a27aaac926170 Mon Sep 17 00:00:00 2001 From: Benoit Fouletier Date: Wed, 4 Nov 2020 13:15:39 +0100 Subject: [PATCH 07/17] test plug name + use read() instead of str() --- cmdx.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/cmdx.py b/cmdx.py index 967c319..352ef5e 100644 --- a/cmdx.py +++ b/cmdx.py @@ -5142,18 +5142,20 @@ def default(self, cls=None): >>> 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 >>> scene_path = "test.ma" >>> _ = 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) >>> print(sphere) |nurbsSphere1 - >>> str(sphere["my_string"]) + >>> sphere["my_string"].name() + my_string + >>> sphere["my_string"].read() foo """ return None From fb118b44c118a22aa803171c9952c00a772bb235 Mon Sep 17 00:00:00 2001 From: Benoit Fouletier Date: Wed, 4 Nov 2020 13:25:21 +0100 Subject: [PATCH 08/17] so apparently the plug name is single-quoted in doctest... this is fun... --- cmdx.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmdx.py b/cmdx.py index 352ef5e..610ff47 100644 --- a/cmdx.py +++ b/cmdx.py @@ -5143,7 +5143,7 @@ def default(self, cls=None): >>> sphere = cmdx.encode(sphere_name) >>> sphere.add_attr(cmdx.String("my_string", default="foo")) >>> sphere["my_string"].name() - my_string + 'my_string' >>> # save scene >>> scene_path = "test.ma" >>> _ = cmds.file(rename=scene_path) @@ -5154,7 +5154,7 @@ def default(self, cls=None): >>> print(sphere) |nurbsSphere1 >>> sphere["my_string"].name() - my_string + 'my_string' >>> sphere["my_string"].read() foo """ From 2aac97c5100bfdd98467859084d4e49360c41aed Mon Sep 17 00:00:00 2001 From: Benoit Fouletier Date: Wed, 4 Nov 2020 13:51:26 +0100 Subject: [PATCH 09/17] print content of the "test.ma" scene --- cmdx.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cmdx.py b/cmdx.py index 610ff47..7eaf3cf 100644 --- a/cmdx.py +++ b/cmdx.py @@ -5147,11 +5147,12 @@ def default(self, cls=None): >>> # save scene >>> scene_path = "test.ma" >>> _ = cmds.file(rename=scene_path) - >>> _ = cmds.file(save=True, type="mayaAscii") + >>> full_path = cmds.file(save=True, type="mayaAscii") + >>> with open(full_path) as f: print(f.read()) >>> # reload scene & check "my_string" >>> _ = cmds.file(scene_path, open=True, force=True) >>> sphere = cmdx.encode(sphere_name) - >>> print(sphere) + >>> str(sphere) |nurbsSphere1 >>> sphere["my_string"].name() 'my_string' From 5f3daf6a20136995e133ea57229903e71acb0239 Mon Sep 17 00:00:00 2001 From: Benoit Fouletier Date: Wed, 4 Nov 2020 14:06:30 +0100 Subject: [PATCH 10/17] get the absolute scene_path early --- cmdx.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cmdx.py b/cmdx.py index 7eaf3cf..b49dbc6 100644 --- a/cmdx.py +++ b/cmdx.py @@ -5145,10 +5145,10 @@ def default(self, cls=None): >>> sphere["my_string"].name() 'my_string' >>> # save scene - >>> scene_path = "test.ma" - >>> _ = cmds.file(rename=scene_path) - >>> full_path = cmds.file(save=True, type="mayaAscii") - >>> with open(full_path) as f: print(f.read()) + >>> scene_path = cmds.file(rename="test.ma") + >>> print(scene_path) + >>> _ = cmds.file(save=True, type="mayaAscii") + >>> with open(scene_path) as f: print(f.read()) >>> # reload scene & check "my_string" >>> _ = cmds.file(scene_path, open=True, force=True) >>> sphere = cmdx.encode(sphere_name) From bd01cfb779ee30f22d86f5928b759a8592164627 Mon Sep 17 00:00:00 2001 From: Benoit Fouletier Date: Wed, 4 Nov 2020 14:19:09 +0100 Subject: [PATCH 11/17] quotes again + only print in case of failure --- cmdx.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cmdx.py b/cmdx.py index b49dbc6..c54a4cd 100644 --- a/cmdx.py +++ b/cmdx.py @@ -5146,14 +5146,15 @@ def default(self, cls=None): 'my_string' >>> # save scene >>> scene_path = cmds.file(rename="test.ma") - >>> print(scene_path) >>> _ = cmds.file(save=True, type="mayaAscii") - >>> with open(scene_path) as f: print(f.read()) >>> # reload scene & check "my_string" >>> _ = cmds.file(scene_path, open=True, force=True) >>> sphere = cmdx.encode(sphere_name) >>> str(sphere) - |nurbsSphere1 + '|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' >>> sphere["my_string"].read() From 117d884d4011eba73daec130c0a9a76610edc027 Mon Sep 17 00:00:00 2001 From: Benoit Fouletier Date: Wed, 4 Nov 2020 14:46:10 +0100 Subject: [PATCH 12/17] use tempfile + quote 'foo' --- cmdx.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cmdx.py b/cmdx.py index c54a4cd..777403a 100644 --- a/cmdx.py +++ b/cmdx.py @@ -5145,10 +5145,14 @@ def default(self, cls=None): >>> 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 >>> scene_path = cmds.file(rename="test.ma") >>> _ = cmds.file(save=True, type="mayaAscii") >>> # reload scene & check "my_string" >>> _ = cmds.file(scene_path, open=True, force=True) + >>> scene_file.close() # deletes the temp file (supposedly) >>> sphere = cmdx.encode(sphere_name) >>> str(sphere) '|nurbsSphere1' @@ -5158,7 +5162,7 @@ def default(self, cls=None): >>> sphere["my_string"].name() 'my_string' >>> sphere["my_string"].read() - foo + 'foo' """ return None From 668539d921e1f7d90961e7372bdd8178be752f7a Mon Sep 17 00:00:00 2001 From: Benoit Fouletier Date: Wed, 4 Nov 2020 14:55:14 +0100 Subject: [PATCH 13/17] ... dammit! --- cmdx.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmdx.py b/cmdx.py index 777403a..76cf221 100644 --- a/cmdx.py +++ b/cmdx.py @@ -5148,7 +5148,7 @@ def default(self, cls=None): >>> import tempfile >>> scene_file = tempfile.NamedTemporaryFile(prefix="test_string_attribute_", suffix=".ma") >>> scene_path = scene_file.name - >>> scene_path = cmds.file(rename="test.ma") + >>> _ = cmds.file(rename=scene_path) >>> _ = cmds.file(save=True, type="mayaAscii") >>> # reload scene & check "my_string" >>> _ = cmds.file(scene_path, open=True, force=True) From c8fef98ec0815d48e3b585834ee06e3eec221a83 Mon Sep 17 00:00:00 2001 From: Benoit Fouletier Date: Wed, 4 Nov 2020 15:00:57 +0100 Subject: [PATCH 14/17] unicode + don't delete the tempfile too soon --- cmdx.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmdx.py b/cmdx.py index 76cf221..5c31d78 100644 --- a/cmdx.py +++ b/cmdx.py @@ -5152,7 +5152,6 @@ def default(self, cls=None): >>> _ = cmds.file(save=True, type="mayaAscii") >>> # reload scene & check "my_string" >>> _ = cmds.file(scene_path, open=True, force=True) - >>> scene_file.close() # deletes the temp file (supposedly) >>> sphere = cmdx.encode(sphere_name) >>> str(sphere) '|nurbsSphere1' @@ -5161,8 +5160,9 @@ def default(self, cls=None): ... 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() - 'foo' + u'foo' """ return None From e300eeb545850c81499140e137b3cedbb646352d Mon Sep 17 00:00:00 2001 From: Benoit Fouletier Date: Wed, 4 Nov 2020 15:10:26 +0100 Subject: [PATCH 15/17] disable caching --- cmdx.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmdx.py b/cmdx.py index 5c31d78..d0b5744 100644 --- a/cmdx.py +++ b/cmdx.py @@ -5136,6 +5136,8 @@ def default(self, cls=None): -> don't pass the default to OpenMaya, instead set it during Node.addAttr() Test: + >>> import os + >>> os.environ["CMDX_SAFE_MODE"] = 1 # disable caching (node/plug reuse) >>> import cmdx >>> # new scene with a sphere with "my_string" attribute >>> _ = cmds.file(new=True, force=True) From f46416a18c894b4702f8bece7186fe980db607fe Mon Sep 17 00:00:00 2001 From: Benoit Fouletier Date: Wed, 4 Nov 2020 15:14:58 +0100 Subject: [PATCH 16/17] must be string, not int --- cmdx.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmdx.py b/cmdx.py index d0b5744..5cf981f 100644 --- a/cmdx.py +++ b/cmdx.py @@ -5137,7 +5137,7 @@ def default(self, cls=None): Test: >>> import os - >>> os.environ["CMDX_SAFE_MODE"] = 1 # disable caching (node/plug reuse) + >>> os.environ["CMDX_SAFE_MODE"] = "1" # disable caching (node/plug reuse) >>> import cmdx >>> # new scene with a sphere with "my_string" attribute >>> _ = cmds.file(new=True, force=True) From e5b7246df5845314cc83c3bd7d8e9ec3208d4ebc Mon Sep 17 00:00:00 2001 From: Benoit Fouletier Date: Wed, 4 Nov 2020 16:47:17 +0100 Subject: [PATCH 17/17] CMDX_SAFE_MODE needs to be a proper "True/False" bool, not "1/0" --- cmdx.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmdx.py b/cmdx.py index 5cf981f..fa9b740 100644 --- a/cmdx.py +++ b/cmdx.py @@ -5137,7 +5137,7 @@ def default(self, cls=None): Test: >>> import os - >>> os.environ["CMDX_SAFE_MODE"] = "1" # disable caching (node/plug reuse) + >>> 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)