From 4f335ed1eba63d8628f1fe406abffe046ff71653 Mon Sep 17 00:00:00 2001
From: Marcelo Saguas Iacovone <marceloiaco@gmail.com>
Date: Sat, 17 Feb 2024 10:37:53 -0800
Subject: [PATCH 1/8] Implements a different approach for __repr__

---
 cmdx.py  | 85 +++++++++++++++++++++++++++++++-------------------------
 tests.py |  3 +-
 2 files changed, 49 insertions(+), 39 deletions(-)

diff --git a/cmdx.py b/cmdx.py
index d592474..64f00d6 100644
--- a/cmdx.py
+++ b/cmdx.py
@@ -511,7 +511,7 @@ class Node(object):
         >>> transform = createNode("transform")
         >>> transform["tx"] = 5
         >>> transform["worldMatrix"][0] >> decompose["inputMatrix"]
-        >>> decompose["outputTranslate"]
+        >>> decompose["outputTranslate"].read()
         (5.0, 0.0, 0.0)
 
     """
@@ -548,7 +548,8 @@ def __str__(self):
         return self.name(namespace=True)
 
     def __repr__(self):
-        return self.name(namespace=True)
+        cls_name = '{}.{}'.format(__name__, self.__class__.__name__)
+        return "<{} : '{}'>".format(cls_name, self.name(namespace=True))
 
     def __add__(self, other):
         """Support legacy + '.attr' behavior
@@ -578,7 +579,7 @@ def __getitem__(self, key):
         Example:
             >>> node = createNode("transform")
             >>> node["translate"] = (1, 1, 1)
-            >>> node["translate", Meters]
+            >>> node["translate", Meters].read()
             (0.01, 0.01, 0.01)
 
         """
@@ -624,7 +625,7 @@ def __setitem__(self, key, value):
             True
             >>> node["rotateX", Degrees] = 1.0
             >>> node["rotateX"] = Degrees(1)
-            >>> node["rotateX", Degrees]
+            >>> node["rotateX", Degrees].read()
             1.0
             >>> node["myDist"] = Distance()
             >>> node["myDist"] = node["translateX"]
@@ -980,7 +981,7 @@ def update(self, attrs):
         Examples:
             >>> node = createNode("transform")
             >>> node.update({"tx": 5.0, ("ry", Degrees): 30.0})
-            >>> node["tx"]
+            >>> node["tx"].read()
             5.0
 
         """
@@ -998,14 +999,14 @@ def clear(self):
         Example:
             >>> node = createNode("transform")
             >>> node["translateX"] = 5
-            >>> node["translateX"]
+            >>> node["translateX"].read()
             5.0
             >>> # Plug was reused
-            >>> node["translateX"]
+            >>> node["translateX"].read()
             5.0
             >>> # Value was reused
             >>> node.clear()
-            >>> node["translateX"]
+            >>> node["translateX"].read()
             5.0
             >>> # Plug and value was recomputed
 
@@ -1513,7 +1514,8 @@ def __str__(self):
         return self.path()
 
     def __repr__(self):
-        return self.path()
+        cls_name = '{}.{}'.format(__name__, self.__class__.__name__)
+        return "<{} : '{}'>".format(cls_name, self.path())
 
     def __or__(self, other):
         """Syntax sugar for finding a child
@@ -1522,13 +1524,13 @@ def __or__(self, other):
             >>> _new()
             >>> parent = createNode("transform", "parent")
             >>> child =  createNode("transform", "child", parent)
-            >>> parent | "child"
-            |parent|child
+            >>> (parent | "child").path()
+            '|parent|child'
 
             # Stackable too
             >>> grand =  createNode("transform", "grand", child)
-            >>> parent | "child" | "grand"
-            |parent|child|grand
+            >>> (parent | "child" | "grand").path()
+            '|parent|child|grand'
 
         """
 
@@ -2301,8 +2303,8 @@ def flatten(self, type=None):
             >>> cc = cmds.sets([gc, b], name="child")
             >>> parent = cmds.sets([cc, c], name="parent")
             >>> mainset = encode(parent)
-            >>> sorted(mainset.flatten(), key=lambda n: n.name())
-            [|a, |b, |c]
+            >>> sorted([n.path() for n in mainset.flatten()])
+            ['|a', '|b', '|c']
 
         """
 
@@ -2560,9 +2562,9 @@ def __add__(self, other):
         Example:
             >>> node = createNode("transform")
             >>> node["tx"] = 5
-            >>> node["translate"] + "X"
+            >>> (node["translate"] + "X").read()
             5.0
-            >>> node["t"] + "x"
+            >>> (node["t"] + "x").read()
             5.0
             >>> try:
             ...   node["t"] + node["r"]
@@ -2597,11 +2599,11 @@ def __iadd__(self, other):
             >>> node["myArray"].extend([2.0, 3.0])
             >>> node["myArray"] += 5.1
             >>> node["myArray"] += [1.1, 2.3, 999.0]
-            >>> node["myArray"][0]
+            >>> node["myArray"][0].read()
             1.0
-            >>> node["myArray"][6]
+            >>> node["myArray"][6].read()
             999.0
-            >>> node["myArray"][-1]
+            >>> node["myArray"][-1].read()
             999.0
 
         """
@@ -2627,7 +2629,13 @@ def __str__(self):
         return str(self.read())
 
     def __repr__(self):
-        return str(self.read())
+        cls_name = '{}.{}'.format(__name__, self.__class__.__name__)
+        read_val = self.read()
+        if isinstance(read_val, string_types):
+            # Add surrounding single quotes, indicating the value is a string
+            read_val = "'{}'".format(read_val)
+
+        return "<{} : {}>".format(cls_name, read_val)
 
     def __rshift__(self, other):
         """Support connecting attributes via A >> B"""
@@ -2798,7 +2806,7 @@ def __setitem__(self, index, value):
         Example:
             >>> node = createNode("transform")
             >>> node["translate"][0] = 5
-            >>> node["tx"]
+            >>> node["tx"].read()
             5.0
 
         """
@@ -3173,9 +3181,9 @@ def extend(self, values):
             >>> node = createNode("transform")
             >>> node["myArray"] = Double(array=True)
             >>> node["myArray"].extend([1.0, 2.0, 3.0])
-            >>> node["myArray"][0]
+            >>> node["myArray"][0].read()
             1.0
-            >>> node["myArray"][-1]
+            >>> node["myArray"][-1].read()
             3.0
 
         """
@@ -4101,7 +4109,7 @@ def connections(self,
             True
             >>> b["ihi"].connection() == a
             True
-            >>> a["ihi"]
+            >>> a["ihi"].read()
             2
             >>> b["arrayAttr"] = Long(array=True)
             >>> b["arrayAttr"][0] >> a["ihi"]
@@ -6350,16 +6358,16 @@ def connect(self, src, dst, force=True):
             >>> with DagModifier() as mod:
             ...     mod.connect(tm["sx"], tm["tx"])
             ...
-            >>> tm["tx"].connection()
-            |myTransform
+            >>> tm["tx"].connection().path()
+            '|myTransform'
             >>> cmds.undo()
             >>> tm["tx"].connection() is None
             True
 
             # Connect without undo
             >>> tm["tx"] << tx["output"]
-            >>> tm["tx"].connection()
-            myAnimCurve
+            >>> tm["tx"].connection().name()
+            'myAnimCurve'
 
             # Disconnect without undo
             >>> tm["tx"] // tx["output"]
@@ -6444,12 +6452,12 @@ def connectAttr(self, srcPlug, dstNode, dstAttr):
             ...     otherAttr = mod.addAttr(otherNode, Message("otherAttr"))
             ...     mod.connectAttr(newNode["newAttr"], otherNode, otherAttr)
             ...
-            >>> newNode["newAttr"].connection()
-            |otherNode
+            >>> newNode["newAttr"].connection().path()
+            '|otherNode'
 
             >>> cmds.undo()
-            >>> newNode["newAttr"].connection()
-            |newNode
+            >>> newNode["newAttr"].connection().path()
+            '|newNode'
 
         """
 
@@ -6768,9 +6776,9 @@ class DagModifier(_BaseModifier):
         ...
         >>> getAttr(node1 + ".translateX")
         1.0
-        >>> node2["translate"][0]
+        >>> node2["translate"][0].read()
         1.0
-        >>> node2["translate"][1]
+        >>> node2["translate"][1].read()
         2.0
         >>> with DagModifier() as mod:
         ...     node1 = mod.createNode("transform")
@@ -6778,9 +6786,9 @@ class DagModifier(_BaseModifier):
         ...     node1["translate"] = (5, 6, 7)
         ...     node1["translate"] >> node2["translate"]
         ...
-        >>> node2["translate"][0]
+        >>> node2["translate"][0].read()
         5.0
-        >>> node2["translate"][1]
+        >>> node2["translate"][1].read()
         6.0
 
     Example, without context manager:
@@ -7721,7 +7729,8 @@ def __hash__(self):
 
     def __repr__(self):
         """Avoid repr depicting the full contents of this dict"""
-        return self["name"]
+        cls_name = '{}.{}'.format(__name__, self.__class__.__name__)
+        return "<{} : '{}'>".format(cls_name, self["name"])
 
     def __new__(cls, *args, **kwargs):
         """Support for using name of assignment
diff --git a/tests.py b/tests.py
index 73ccac6..7f7834f 100644
--- a/tests.py
+++ b/tests.py
@@ -383,8 +383,9 @@ def test_nodeoperators():
 
     node = cmdx.createNode(cmdx.tTransform, name="myNode")
     assert_equals(node, "|myNode")
+    assert_equals(repr(node), "<cmdx.DagNode : '|myNode'>")
     assert_not_equals(node, "|NotEquals")
-    assert_equals(str(node), repr(node))
+    assert_not_equals(str(node), repr(node))
 
 
 @with_setup(new_scene)

From 5d8a033f7610be6f1c20460e9cfda070ba5684b6 Mon Sep 17 00:00:00 2001
From: Marcelo Saguas Iacovone <marceloiaco@gmail.com>
Date: Sat, 17 Feb 2024 13:02:18 -0800
Subject: [PATCH 2/8] Fixes Python2.7 compatibility for doctests

---
 cmdx.py | 57 +++++++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 43 insertions(+), 14 deletions(-)

diff --git a/cmdx.py b/cmdx.py
index 64f00d6..49923bb 100644
--- a/cmdx.py
+++ b/cmdx.py
@@ -1524,13 +1524,21 @@ def __or__(self, other):
             >>> _new()
             >>> parent = createNode("transform", "parent")
             >>> child =  createNode("transform", "child", parent)
-            >>> (parent | "child").path()
-            '|parent|child'
+            >>> result = (parent | "child").path()
+            >>> result in (
+            ...    '|parent|child',
+            ...   u'|parent|child'
+            ... )
+            True
 
             # Stackable too
             >>> grand =  createNode("transform", "grand", child)
-            >>> (parent | "child" | "grand").path()
-            '|parent|child|grand'
+            >>> result = (parent | "child" | "grand").path()
+            >>> result in (
+            ...    '|parent|child|grand',
+            ...   u'|parent|child|grand'
+            ... )
+            True
 
         """
 
@@ -2303,8 +2311,12 @@ def flatten(self, type=None):
             >>> cc = cmds.sets([gc, b], name="child")
             >>> parent = cmds.sets([cc, c], name="parent")
             >>> mainset = encode(parent)
-            >>> sorted([n.path() for n in mainset.flatten()])
-            ['|a', '|b', '|c']
+            >>> result = sorted([n.path() for n in mainset.flatten()])
+            >>> result in (
+            ...    ['|a', '|b', '|c'],
+            ...    [u'|a', u'|b', u'|c']
+            ... )
+            True
 
         """
 
@@ -6358,16 +6370,25 @@ def connect(self, src, dst, force=True):
             >>> with DagModifier() as mod:
             ...     mod.connect(tm["sx"], tm["tx"])
             ...
-            >>> tm["tx"].connection().path()
-            '|myTransform'
+            >>> result = tm["tx"].connection().path()
+            >>> result in (
+            ...    '|myTransform',
+            ...   u'|myTransform'
+            ... )
+            True
+
             >>> cmds.undo()
             >>> tm["tx"].connection() is None
             True
 
             # Connect without undo
             >>> tm["tx"] << tx["output"]
-            >>> tm["tx"].connection().name()
-            'myAnimCurve'
+            >>> result = tm["tx"].connection().name()
+            >>> result in (
+            ...    'myAnimCurve',
+            ...   u'myAnimCurve'
+            ... )
+            True
 
             # Disconnect without undo
             >>> tm["tx"] // tx["output"]
@@ -6452,12 +6473,20 @@ def connectAttr(self, srcPlug, dstNode, dstAttr):
             ...     otherAttr = mod.addAttr(otherNode, Message("otherAttr"))
             ...     mod.connectAttr(newNode["newAttr"], otherNode, otherAttr)
             ...
-            >>> newNode["newAttr"].connection().path()
-            '|otherNode'
+            >>> result = newNode["newAttr"].connection().path()
+            >>> result in (
+            ...    '|otherNode',
+            ...   u'|otherNode'
+            ... )
+            True
 
             >>> cmds.undo()
-            >>> newNode["newAttr"].connection().path()
-            '|newNode'
+            >>> result = newNode["newAttr"].connection().path()
+            >>> result in (
+            ...    '|newNode',
+            ...   u'|newNode'
+            ... )
+            True
 
         """
 

From eb98987634267acd3b35ac6c6226cab215d3a85b Mon Sep 17 00:00:00 2001
From: Marcelo Saguas Iacovone <marceloiaco@gmail.com>
Date: Sun, 18 Feb 2024 10:48:49 -0800
Subject: [PATCH 3/8] Reimplements old doctests without .name(), .path() and
 .read()

---
 cmdx.py | 104 +++++++++++++++++++++++++++++++++++++++++---------------
 1 file changed, 76 insertions(+), 28 deletions(-)

diff --git a/cmdx.py b/cmdx.py
index 49923bb..b2e633f 100644
--- a/cmdx.py
+++ b/cmdx.py
@@ -511,6 +511,8 @@ class Node(object):
         >>> transform = createNode("transform")
         >>> transform["tx"] = 5
         >>> transform["worldMatrix"][0] >> decompose["inputMatrix"]
+        >>> decompose["outputTranslate"]
+        <cmdx.Plug : (5.0, 0.0, 0.0)>
         >>> decompose["outputTranslate"].read()
         (5.0, 0.0, 0.0)
 
@@ -579,6 +581,8 @@ def __getitem__(self, key):
         Example:
             >>> node = createNode("transform")
             >>> node["translate"] = (1, 1, 1)
+            >>> node["translate", Meters]
+            <cmdx.Plug : (0.01, 0.01, 0.01)>
             >>> node["translate", Meters].read()
             (0.01, 0.01, 0.01)
 
@@ -625,6 +629,8 @@ def __setitem__(self, key, value):
             True
             >>> node["rotateX", Degrees] = 1.0
             >>> node["rotateX"] = Degrees(1)
+            >>> node["rotateX", Degrees]
+            <cmdx.Plug : 1.0>
             >>> node["rotateX", Degrees].read()
             1.0
             >>> node["myDist"] = Distance()
@@ -981,6 +987,8 @@ def update(self, attrs):
         Examples:
             >>> node = createNode("transform")
             >>> node.update({"tx": 5.0, ("ry", Degrees): 30.0})
+            >>> node["tx"]
+            <cmdx.Plug : 5.0>
             >>> node["tx"].read()
             5.0
 
@@ -999,13 +1007,19 @@ def clear(self):
         Example:
             >>> node = createNode("transform")
             >>> node["translateX"] = 5
+            >>> node["translateX"]
+            <cmdx.Plug : 5.0>
             >>> node["translateX"].read()
             5.0
             >>> # Plug was reused
+            >>> node["translateX"]
+            <cmdx.Plug : 5.0>
             >>> node["translateX"].read()
             5.0
             >>> # Value was reused
             >>> node.clear()
+            >>> node["translateX"]
+            <cmdx.Plug : 5.0>
             >>> node["translateX"].read()
             5.0
             >>> # Plug and value was recomputed
@@ -1524,8 +1538,9 @@ def __or__(self, other):
             >>> _new()
             >>> parent = createNode("transform", "parent")
             >>> child =  createNode("transform", "child", parent)
-            >>> result = (parent | "child").path()
-            >>> result in (
+            >>> parent | "child"
+            <cmdx.DagNode : '|parent|child'>
+            >>> (parent | "child").path() in (
             ...    '|parent|child',
             ...   u'|parent|child'
             ... )
@@ -1533,8 +1548,9 @@ def __or__(self, other):
 
             # Stackable too
             >>> grand =  createNode("transform", "grand", child)
-            >>> result = (parent | "child" | "grand").path()
-            >>> result in (
+            >>> parent | "child" | "grand"
+            <cmdx.DagNode : '|parent|child|grand'>
+            >>> (parent | "child" | "grand").path() in (
             ...    '|parent|child|grand',
             ...   u'|parent|child|grand'
             ... )
@@ -2301,22 +2317,24 @@ def flatten(self, type=None):
         """Return members, converting nested object sets into its members
 
         Example:
-            >>> from maya import cmds
-            >>> _ = cmds.file(new=True, force=True)
-            >>> a = cmds.createNode("transform", name="a")
-            >>> b = cmds.createNode("transform", name="b")
-            >>> c = cmds.createNode("transform", name="c")
-            >>> cmds.select(a)
-            >>> gc = cmds.sets([a], name="grandchild")
-            >>> cc = cmds.sets([gc, b], name="child")
-            >>> parent = cmds.sets([cc, c], name="parent")
-            >>> mainset = encode(parent)
-            >>> result = sorted([n.path() for n in mainset.flatten()])
-            >>> result in (
-            ...    ['|a', '|b', '|c'],
-            ...    [u'|a', u'|b', u'|c']
-            ... )
-            True
+          >>> from maya import cmds
+          >>> _ = cmds.file(new=True, force=True)
+          >>> a = cmds.createNode("transform", name="a")
+          >>> b = cmds.createNode("transform", name="b")
+          >>> c = cmds.createNode("transform", name="c")
+          >>> cmds.select(a)
+          >>> gc = cmds.sets([a], name="grandchild")
+          >>> cc = cmds.sets([gc, b], name="child")
+          >>> parent = cmds.sets([cc, c], name="parent")
+          >>> mainset = encode(parent)
+          >>> sorted(mainset.flatten(), key=lambda n: n.name())
+          [<cmdx.DagNode : '|a'>, <cmdx.DagNode : '|b'>, <cmdx.DagNode : '|c'>]
+          >>> result = sorted([n.name() for n in mainset.flatten()])
+          >>> result in (
+          ...    ['a', 'b', 'c'],
+          ...    [u'a', u'b', u'c']
+          ... )
+          True
 
         """
 
@@ -2574,8 +2592,12 @@ def __add__(self, other):
         Example:
             >>> node = createNode("transform")
             >>> node["tx"] = 5
+            >>> node["translate"] + "X"
+            <cmdx.Plug : 5.0>
             >>> (node["translate"] + "X").read()
             5.0
+            >>> node["t"] + "x"
+            <cmdx.Plug : 5.0>
             >>> (node["t"] + "x").read()
             5.0
             >>> try:
@@ -2611,10 +2633,16 @@ def __iadd__(self, other):
             >>> node["myArray"].extend([2.0, 3.0])
             >>> node["myArray"] += 5.1
             >>> node["myArray"] += [1.1, 2.3, 999.0]
+            >>> node["myArray"][0]
+            <cmdx.Plug : 1.0>
             >>> node["myArray"][0].read()
             1.0
+            >>> node["myArray"][6]
+            <cmdx.Plug : 999.0>
             >>> node["myArray"][6].read()
             999.0
+            >>> node["myArray"][-1]
+            <cmdx.Plug : 999.0>
             >>> node["myArray"][-1].read()
             999.0
 
@@ -2818,6 +2846,8 @@ def __setitem__(self, index, value):
         Example:
             >>> node = createNode("transform")
             >>> node["translate"][0] = 5
+            >>> node["tx"]
+            <cmdx.Plug : 5.0>
             >>> node["tx"].read()
             5.0
 
@@ -3193,8 +3223,12 @@ def extend(self, values):
             >>> node = createNode("transform")
             >>> node["myArray"] = Double(array=True)
             >>> node["myArray"].extend([1.0, 2.0, 3.0])
+            >>> node["myArray"][0]
+            <cmdx.Plug : 1.0>
             >>> node["myArray"][0].read()
             1.0
+            >>> node["myArray"][-1]
+            <cmdx.Plug : 3.0>
             >>> node["myArray"][-1].read()
             3.0
 
@@ -4121,6 +4155,8 @@ def connections(self,
             True
             >>> b["ihi"].connection() == a
             True
+            >>> a["ihi"]
+            <cmdx.Plug : 2>
             >>> a["ihi"].read()
             2
             >>> b["arrayAttr"] = Long(array=True)
@@ -6370,8 +6406,9 @@ def connect(self, src, dst, force=True):
             >>> with DagModifier() as mod:
             ...     mod.connect(tm["sx"], tm["tx"])
             ...
-            >>> result = tm["tx"].connection().path()
-            >>> result in (
+            >>> tm["tx"].connection()
+            <cmdx.DagNode : '|myTransform'>
+            >>> tm["tx"].connection().path() in (
             ...    '|myTransform',
             ...   u'|myTransform'
             ... )
@@ -6383,8 +6420,9 @@ def connect(self, src, dst, force=True):
 
             # Connect without undo
             >>> tm["tx"] << tx["output"]
-            >>> result = tm["tx"].connection().name()
-            >>> result in (
+            >>> tm["tx"].connection()
+            <cmdx.AnimCurve : 'myAnimCurve'>
+            >>> tm["tx"].connection().name() in (
             ...    'myAnimCurve',
             ...   u'myAnimCurve'
             ... )
@@ -6473,16 +6511,18 @@ def connectAttr(self, srcPlug, dstNode, dstAttr):
             ...     otherAttr = mod.addAttr(otherNode, Message("otherAttr"))
             ...     mod.connectAttr(newNode["newAttr"], otherNode, otherAttr)
             ...
-            >>> result = newNode["newAttr"].connection().path()
-            >>> result in (
+            >>> newNode["newAttr"].connection()
+            <cmdx.DagNode : '|otherNode'>
+            >>> newNode["newAttr"].connection().path() in (
             ...    '|otherNode',
             ...   u'|otherNode'
             ... )
             True
 
             >>> cmds.undo()
-            >>> result = newNode["newAttr"].connection().path()
-            >>> result in (
+            >>> newNode["newAttr"].connection()
+            <cmdx.DagNode : '|newNode'>
+            >>> newNode["newAttr"].connection().path() in (
             ...    '|newNode',
             ...   u'|newNode'
             ... )
@@ -6805,8 +6845,12 @@ class DagModifier(_BaseModifier):
         ...
         >>> getAttr(node1 + ".translateX")
         1.0
+        >>> node2["translate"][0]
+        <cmdx.Plug : 1.0>
         >>> node2["translate"][0].read()
         1.0
+        >>> node2["translate"][1]
+        <cmdx.Plug : 2.0>
         >>> node2["translate"][1].read()
         2.0
         >>> with DagModifier() as mod:
@@ -6815,8 +6859,12 @@ class DagModifier(_BaseModifier):
         ...     node1["translate"] = (5, 6, 7)
         ...     node1["translate"] >> node2["translate"]
         ...
+        >>> node2["translate"][0]
+        <cmdx.Plug : 5.0>
         >>> node2["translate"][0].read()
         5.0
+        >>> node2["translate"][1]
+        <cmdx.Plug : 6.0>
         >>> node2["translate"][1].read()
         6.0
 

From b482befd9077c42160d894b17672e267d9d46874 Mon Sep 17 00:00:00 2001
From: Marcelo Saguas Iacovone <marceloiaco@gmail.com>
Date: Tue, 20 Feb 2024 23:39:47 -0800
Subject: [PATCH 4/8] Changes the repr diplay to be more code-like

---
 cmdx.py  | 113 ++++++++++++++++++++++++++++++-------------------------
 tests.py |   2 +-
 2 files changed, 63 insertions(+), 52 deletions(-)

diff --git a/cmdx.py b/cmdx.py
index b2e633f..58a9441 100644
--- a/cmdx.py
+++ b/cmdx.py
@@ -512,7 +512,7 @@ class Node(object):
         >>> transform["tx"] = 5
         >>> transform["worldMatrix"][0] >> decompose["inputMatrix"]
         >>> decompose["outputTranslate"]
-        <cmdx.Plug : (5.0, 0.0, 0.0)>
+        cmdx.Plug("decompose", "outputTranslate") == (5.0, 0.0, 0.0)
         >>> decompose["outputTranslate"].read()
         (5.0, 0.0, 0.0)
 
@@ -551,7 +551,7 @@ def __str__(self):
 
     def __repr__(self):
         cls_name = '{}.{}'.format(__name__, self.__class__.__name__)
-        return "<{} : '{}'>".format(cls_name, self.name(namespace=True))
+        return '{}("{}")'.format(cls_name, self.name(namespace=True))
 
     def __add__(self, other):
         """Support legacy + '.attr' behavior
@@ -579,10 +579,11 @@ def __getitem__(self, key):
                 optionally pass tuple to include unit.
 
         Example:
+            >>> _new()
             >>> node = createNode("transform")
             >>> node["translate"] = (1, 1, 1)
             >>> node["translate", Meters]
-            <cmdx.Plug : (0.01, 0.01, 0.01)>
+            cmdx.Plug("transform1", "translate") == (0.01, 0.01, 0.01)
             >>> node["translate", Meters].read()
             (0.01, 0.01, 0.01)
 
@@ -630,7 +631,7 @@ def __setitem__(self, key, value):
             >>> node["rotateX", Degrees] = 1.0
             >>> node["rotateX"] = Degrees(1)
             >>> node["rotateX", Degrees]
-            <cmdx.Plug : 1.0>
+            cmdx.Plug("myNode", "rotateX") == 1.0
             >>> node["rotateX", Degrees].read()
             1.0
             >>> node["myDist"] = Distance()
@@ -985,10 +986,11 @@ def update(self, attrs):
             attrs (dict): Key/value pairs of name and attribute
 
         Examples:
+            >>> _new()
             >>> node = createNode("transform")
             >>> node.update({"tx": 5.0, ("ry", Degrees): 30.0})
             >>> node["tx"]
-            <cmdx.Plug : 5.0>
+            cmdx.Plug("transform1", "translateX") == 5.0
             >>> node["tx"].read()
             5.0
 
@@ -1005,21 +1007,22 @@ def clear(self):
         values, freeing up memory at the expense of performance.
 
         Example:
+            >>> _new()
             >>> node = createNode("transform")
             >>> node["translateX"] = 5
             >>> node["translateX"]
-            <cmdx.Plug : 5.0>
+            cmdx.Plug("transform1", "translateX") == 5.0
             >>> node["translateX"].read()
             5.0
             >>> # Plug was reused
             >>> node["translateX"]
-            <cmdx.Plug : 5.0>
+            cmdx.Plug("transform1", "translateX") == 5.0
             >>> node["translateX"].read()
             5.0
             >>> # Value was reused
             >>> node.clear()
             >>> node["translateX"]
-            <cmdx.Plug : 5.0>
+            cmdx.Plug("transform1", "translateX") == 5.0
             >>> node["translateX"].read()
             5.0
             >>> # Plug and value was recomputed
@@ -1529,7 +1532,7 @@ def __str__(self):
 
     def __repr__(self):
         cls_name = '{}.{}'.format(__name__, self.__class__.__name__)
-        return "<{} : '{}'>".format(cls_name, self.path())
+        return '{}("{}")'.format(cls_name, self.name())
 
     def __or__(self, other):
         """Syntax sugar for finding a child
@@ -1537,9 +1540,9 @@ def __or__(self, other):
         Examples:
             >>> _new()
             >>> parent = createNode("transform", "parent")
-            >>> child =  createNode("transform", "child", parent)
+            >>> child = createNode("transform", "child", parent)
             >>> parent | "child"
-            <cmdx.DagNode : '|parent|child'>
+            cmdx.DagNode("child")
             >>> (parent | "child").path() in (
             ...    '|parent|child',
             ...   u'|parent|child'
@@ -1547,9 +1550,9 @@ def __or__(self, other):
             True
 
             # Stackable too
-            >>> grand =  createNode("transform", "grand", child)
+            >>> grand = createNode("transform", "grand", child)
             >>> parent | "child" | "grand"
-            <cmdx.DagNode : '|parent|child|grand'>
+            cmdx.DagNode("grand")
             >>> (parent | "child" | "grand").path() in (
             ...    '|parent|child|grand',
             ...   u'|parent|child|grand'
@@ -2317,24 +2320,24 @@ def flatten(self, type=None):
         """Return members, converting nested object sets into its members
 
         Example:
-          >>> from maya import cmds
-          >>> _ = cmds.file(new=True, force=True)
-          >>> a = cmds.createNode("transform", name="a")
-          >>> b = cmds.createNode("transform", name="b")
-          >>> c = cmds.createNode("transform", name="c")
-          >>> cmds.select(a)
-          >>> gc = cmds.sets([a], name="grandchild")
-          >>> cc = cmds.sets([gc, b], name="child")
-          >>> parent = cmds.sets([cc, c], name="parent")
-          >>> mainset = encode(parent)
-          >>> sorted(mainset.flatten(), key=lambda n: n.name())
-          [<cmdx.DagNode : '|a'>, <cmdx.DagNode : '|b'>, <cmdx.DagNode : '|c'>]
-          >>> result = sorted([n.name() for n in mainset.flatten()])
-          >>> result in (
-          ...    ['a', 'b', 'c'],
-          ...    [u'a', u'b', u'c']
-          ... )
-          True
+            >>> from maya import cmds
+            >>> _ = cmds.file(new=True, force=True)
+            >>> a = cmds.createNode("transform", name="a")
+            >>> b = cmds.createNode("transform", name="b")
+            >>> c = cmds.createNode("transform", name="c")
+            >>> cmds.select(a)
+            >>> gc = cmds.sets([a], name="grandchild")
+            >>> cc = cmds.sets([gc, b], name="child")
+            >>> parent = cmds.sets([cc, c], name="parent")
+            >>> mainset = encode(parent)
+            >>> sorted(mainset.flatten(), key=lambda n: n.name())
+            [cmdx.DagNode("a"), cmdx.DagNode("b"), cmdx.DagNode("c")]
+            >>> result = sorted([n.name() for n in mainset.flatten()])
+            >>> result in (
+            ...    ['a', 'b', 'c'],
+            ...    [u'a', u'b', u'c']
+            ... )
+            True
 
         """
 
@@ -2590,14 +2593,15 @@ def __add__(self, other):
             than adding to longName, e.g. node["translate"] + "X"
 
         Example:
+            >>> _new()
             >>> node = createNode("transform")
             >>> node["tx"] = 5
             >>> node["translate"] + "X"
-            <cmdx.Plug : 5.0>
+            cmdx.Plug("transform1", "translateX") == 5.0
             >>> (node["translate"] + "X").read()
             5.0
             >>> node["t"] + "x"
-            <cmdx.Plug : 5.0>
+            cmdx.Plug("transform1", "translateX") == 5.0
             >>> (node["t"] + "x").read()
             5.0
             >>> try:
@@ -2627,6 +2631,7 @@ def __iadd__(self, other):
         """Support += operator, for .append()
 
         Example:
+            >>> _new()
             >>> node = createNode("transform")
             >>> node["myArray"] = Double(array=True)
             >>> node["myArray"].append(1.0)
@@ -2634,15 +2639,15 @@ def __iadd__(self, other):
             >>> node["myArray"] += 5.1
             >>> node["myArray"] += [1.1, 2.3, 999.0]
             >>> node["myArray"][0]
-            <cmdx.Plug : 1.0>
+            cmdx.Plug("transform1", "myArray[0]") == 1.0
             >>> node["myArray"][0].read()
             1.0
             >>> node["myArray"][6]
-            <cmdx.Plug : 999.0>
+            cmdx.Plug("transform1", "myArray[6]") == 999.0
             >>> node["myArray"][6].read()
             999.0
             >>> node["myArray"][-1]
-            <cmdx.Plug : 999.0>
+            cmdx.Plug("transform1", "myArray[6]") == 999.0
             >>> node["myArray"][-1].read()
             999.0
 
@@ -2669,13 +2674,16 @@ def __str__(self):
         return str(self.read())
 
     def __repr__(self):
-        cls_name = '{}.{}'.format(__name__, self.__class__.__name__)
         read_val = self.read()
         if isinstance(read_val, string_types):
             # Add surrounding single quotes, indicating the value is a string
-            read_val = "'{}'".format(read_val)
+            read_val = '"{}"'.format(read_val)
 
-        return "<{} : {}>".format(cls_name, read_val)
+        cls_name = '{}.{}'.format(__name__, self.__class__.__name__)
+        return '{}("{}", "{}") == {}'.format(cls_name,
+                                             self.node().name(),
+                                             self.name(),
+                                             read_val)
 
     def __rshift__(self, other):
         """Support connecting attributes via A >> B"""
@@ -2844,10 +2852,11 @@ def __setitem__(self, index, value):
         """Write to child of array or compound plug
 
         Example:
+            >>> _new()
             >>> node = createNode("transform")
             >>> node["translate"][0] = 5
             >>> node["tx"]
-            <cmdx.Plug : 5.0>
+            cmdx.Plug("transform1", "translateX") == 5.0
             >>> node["tx"].read()
             5.0
 
@@ -3220,15 +3229,16 @@ def extend(self, values):
                 If cmdx.Plug's, create a new entry and connect it.
 
         Example:
+            >>> _new()
             >>> node = createNode("transform")
             >>> node["myArray"] = Double(array=True)
             >>> node["myArray"].extend([1.0, 2.0, 3.0])
             >>> node["myArray"][0]
-            <cmdx.Plug : 1.0>
+            cmdx.Plug("transform1", "myArray[0]") == 1.0
             >>> node["myArray"][0].read()
             1.0
             >>> node["myArray"][-1]
-            <cmdx.Plug : 3.0>
+            cmdx.Plug("transform1", "myArray[2]") == 3.0
             >>> node["myArray"][-1].read()
             3.0
 
@@ -4156,7 +4166,7 @@ def connections(self,
             >>> b["ihi"].connection() == a
             True
             >>> a["ihi"]
-            <cmdx.Plug : 2>
+            cmdx.Plug("A", "isHistoricallyInteresting") == 2
             >>> a["ihi"].read()
             2
             >>> b["arrayAttr"] = Long(array=True)
@@ -6407,7 +6417,7 @@ def connect(self, src, dst, force=True):
             ...     mod.connect(tm["sx"], tm["tx"])
             ...
             >>> tm["tx"].connection()
-            <cmdx.DagNode : '|myTransform'>
+            cmdx.DagNode("myTransform")
             >>> tm["tx"].connection().path() in (
             ...    '|myTransform',
             ...   u'|myTransform'
@@ -6421,7 +6431,7 @@ def connect(self, src, dst, force=True):
             # Connect without undo
             >>> tm["tx"] << tx["output"]
             >>> tm["tx"].connection()
-            <cmdx.AnimCurve : 'myAnimCurve'>
+            cmdx.AnimCurve("myAnimCurve")
             >>> tm["tx"].connection().name() in (
             ...    'myAnimCurve',
             ...   u'myAnimCurve'
@@ -6512,7 +6522,7 @@ def connectAttr(self, srcPlug, dstNode, dstAttr):
             ...     mod.connectAttr(newNode["newAttr"], otherNode, otherAttr)
             ...
             >>> newNode["newAttr"].connection()
-            <cmdx.DagNode : '|otherNode'>
+            cmdx.DagNode("otherNode")
             >>> newNode["newAttr"].connection().path() in (
             ...    '|otherNode',
             ...   u'|otherNode'
@@ -6521,7 +6531,7 @@ def connectAttr(self, srcPlug, dstNode, dstAttr):
 
             >>> cmds.undo()
             >>> newNode["newAttr"].connection()
-            <cmdx.DagNode : '|newNode'>
+            cmdx.DagNode("newNode")
             >>> newNode["newAttr"].connection().path() in (
             ...    '|newNode',
             ...   u'|newNode'
@@ -6837,6 +6847,7 @@ class DagModifier(_BaseModifier):
     """Modifier for DAG nodes
 
     Example:
+        >>> _new()
         >>> with DagModifier() as mod:
         ...     node1 = mod.createNode("transform")
         ...     node2 = mod.createNode("transform", parent=node1)
@@ -6846,11 +6857,11 @@ class DagModifier(_BaseModifier):
         >>> getAttr(node1 + ".translateX")
         1.0
         >>> node2["translate"][0]
-        <cmdx.Plug : 1.0>
+        cmdx.Plug("transform2", "translateX") == 1.0
         >>> node2["translate"][0].read()
         1.0
         >>> node2["translate"][1]
-        <cmdx.Plug : 2.0>
+        cmdx.Plug("transform2", "translateY") == 2.0
         >>> node2["translate"][1].read()
         2.0
         >>> with DagModifier() as mod:
@@ -6860,11 +6871,11 @@ class DagModifier(_BaseModifier):
         ...     node1["translate"] >> node2["translate"]
         ...
         >>> node2["translate"][0]
-        <cmdx.Plug : 5.0>
+        cmdx.Plug("transform4", "translateX") == 5.0
         >>> node2["translate"][0].read()
         5.0
         >>> node2["translate"][1]
-        <cmdx.Plug : 6.0>
+        cmdx.Plug("transform4", "translateY") == 6.0
         >>> node2["translate"][1].read()
         6.0
 
diff --git a/tests.py b/tests.py
index 7f7834f..3a327b6 100644
--- a/tests.py
+++ b/tests.py
@@ -383,7 +383,7 @@ def test_nodeoperators():
 
     node = cmdx.createNode(cmdx.tTransform, name="myNode")
     assert_equals(node, "|myNode")
-    assert_equals(repr(node), "<cmdx.DagNode : '|myNode'>")
+    assert_equals(repr(node), 'cmdx.DagNode("myNode")')
     assert_not_equals(node, "|NotEquals")
     assert_not_equals(str(node), repr(node))
 

From 019abe4d3e5a5513c40dc663b03b3026c9e78512 Mon Sep 17 00:00:00 2001
From: Marcelo Saguas Iacovone <marceloiaco@gmail.com>
Date: Wed, 21 Feb 2024 23:10:30 -0800
Subject: [PATCH 5/8] Skips read() call within Plug __repr__ if the plug's
 apiType is of type Mfn.kCompoundAttribute

---
 cmdx.py | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/cmdx.py b/cmdx.py
index 58a9441..66907f2 100644
--- a/cmdx.py
+++ b/cmdx.py
@@ -2674,12 +2674,16 @@ def __str__(self):
         return str(self.read())
 
     def __repr__(self):
+        cls_name = '{}.{}'.format(__name__, self.__class__.__name__)
+        if self._mplug.attribute().apiType() == om.MFn.kCompoundAttribute:
+            return '{}("{}", "{}")'.format(cls_name,
+                                           self.node().name(),
+                                           self.name())
         read_val = self.read()
         if isinstance(read_val, string_types):
             # Add surrounding single quotes, indicating the value is a string
             read_val = '"{}"'.format(read_val)
 
-        cls_name = '{}.{}'.format(__name__, self.__class__.__name__)
         return '{}("{}", "{}") == {}'.format(cls_name,
                                              self.node().name(),
                                              self.name(),
@@ -7818,7 +7822,7 @@ def __hash__(self):
     def __repr__(self):
         """Avoid repr depicting the full contents of this dict"""
         cls_name = '{}.{}'.format(__name__, self.__class__.__name__)
-        return "<{} : '{}'>".format(cls_name, self["name"])
+        return 'cmdx.{}("{}")'.format(cls_name, self["name"])
 
     def __new__(cls, *args, **kwargs):
         """Support for using name of assignment

From 73f1aefaf1b4514ed07f4c96350f7b669a9d39e2 Mon Sep 17 00:00:00 2001
From: Marcelo Saguas Iacovone <marceloiaco@gmail.com>
Date: Thu, 22 Feb 2024 21:03:49 -0800
Subject: [PATCH 6/8] Delegates Plug __repr__ value reading to __str__

---
 cmdx.py | 33 ++++++++++++++++++++-------------
 1 file changed, 20 insertions(+), 13 deletions(-)

diff --git a/cmdx.py b/cmdx.py
index 66907f2..8f79282 100644
--- a/cmdx.py
+++ b/cmdx.py
@@ -2674,20 +2674,27 @@ def __str__(self):
         return str(self.read())
 
     def __repr__(self):
+        try:
+            # Delegate the value reading to __str__
+            read_result = str(self)
+            valid = True
+        except:
+            valid = False
+
         cls_name = '{}.{}'.format(__name__, self.__class__.__name__)
-        if self._mplug.attribute().apiType() == om.MFn.kCompoundAttribute:
-            return '{}("{}", "{}")'.format(cls_name,
-                                           self.node().name(),
-                                           self.name())
-        read_val = self.read()
-        if isinstance(read_val, string_types):
-            # Add surrounding single quotes, indicating the value is a string
-            read_val = '"{}"'.format(read_val)
-
-        return '{}("{}", "{}") == {}'.format(cls_name,
-                                             self.node().name(),
-                                             self.name(),
-                                             read_val)
+        msg = '{}("{}", "{}")'.format(cls_name,
+                                      self.node().name(),
+                                      self.name())
+        if valid:
+            try:
+                if self.typeClass() == String:
+                    # Add surrounding quotes, indicating it is a string
+                    read_result = '"{}"'.format(read_result)
+            except TypeError:
+                pass
+            msg += ' == {}'.format(read_result)
+
+        return msg
 
     def __rshift__(self, other):
         """Support connecting attributes via A >> B"""

From 8da17d3235828ec2fff902bb04eb40fed6bdd22c Mon Sep 17 00:00:00 2001
From: Marcelo Saguas Iacovone <marceloiaco@gmail.com>
Date: Mon, 26 Feb 2024 23:52:55 -0800
Subject: [PATCH 7/8] Removes try/excepts and implements test case for string
 plugs

---
 cmdx.py | 28 ++++++++++++++++------------
 1 file changed, 16 insertions(+), 12 deletions(-)

diff --git a/cmdx.py b/cmdx.py
index 8f79282..f16ce74 100644
--- a/cmdx.py
+++ b/cmdx.py
@@ -653,6 +653,13 @@ def __setitem__(self, key, value):
             ... else:
             ...   assert False
             >>>
+            >>> node["myString"] = String()
+            >>> node["myString"]
+            cmdx.Plug("myNode", "myString") == ""
+            >>> node["myString"] = "Hello, world!"
+            >>> node["myString"]
+            cmdx.Plug("myNode", "myString") == "Hello, world!"
+            >>>
             >>> delete(node)
 
         """
@@ -2674,24 +2681,21 @@ def __str__(self):
         return str(self.read())
 
     def __repr__(self):
-        try:
-            # Delegate the value reading to __str__
-            read_result = str(self)
-            valid = True
-        except:
-            valid = False
-
         cls_name = '{}.{}'.format(__name__, self.__class__.__name__)
         msg = '{}("{}", "{}")'.format(cls_name,
                                       self.node().name(),
                                       self.name())
-        if valid:
-            try:
-                if self.typeClass() == String:
+
+        if not self.isCompound and not self.isArray:
+            # Delegate and include the value result from __str__
+            read_result = str(self)
+            attr = self._mplug.attribute()
+            typ = attr.apiType()
+            if typ == om.MFn.kTypedAttribute:
+                typ = om.MFnTypedAttribute(attr).attrType()
+                if typ == om.MFnData.kString:
                     # Add surrounding quotes, indicating it is a string
                     read_result = '"{}"'.format(read_result)
-            except TypeError:
-                pass
             msg += ' == {}'.format(read_result)
 
         return msg

From 70857defa2beeb9886eeec675f50e3a90a220d6e Mon Sep 17 00:00:00 2001
From: Marcelo Saguas Iacovone <marceloiaco@gmail.com>
Date: Mon, 26 Feb 2024 23:59:23 -0800
Subject: [PATCH 8/8] Fixes if statement for not isCompound/isArray

---
 cmdx.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/cmdx.py b/cmdx.py
index f16ce74..024829b 100644
--- a/cmdx.py
+++ b/cmdx.py
@@ -2686,7 +2686,7 @@ def __repr__(self):
                                       self.node().name(),
                                       self.name())
 
-        if not self.isCompound and not self.isArray:
+        if not all((self.isCompound, self.isArray)):
             # Delegate and include the value result from __str__
             read_result = str(self)
             attr = self._mplug.attribute()