@@ -640,6 +640,14 @@ def same_tree(self, other: Tree) -> bool:
640
640
AnyNamedNode = TypeVar ("AnyNamedNode" , bound = "NamedNode" )
641
641
642
642
643
+ def _validate_name (name : str | None ) -> None :
644
+ if name is not None :
645
+ if not isinstance (name , str ):
646
+ raise TypeError ("node name must be a string or None" )
647
+ if "/" in name :
648
+ raise ValueError ("node names cannot contain forward slashes" )
649
+
650
+
643
651
class NamedNode (TreeNode , Generic [Tree ]):
644
652
"""
645
653
A TreeNode which knows its own name.
@@ -653,8 +661,8 @@ class NamedNode(TreeNode, Generic[Tree]):
653
661
654
662
def __init__ (self , name = None , children = None ):
655
663
super ().__init__ (children = children )
656
- self . _name = None
657
- self .name = name
664
+ _validate_name ( name )
665
+ self ._name = name
658
666
659
667
@property
660
668
def name (self ) -> str | None :
@@ -663,11 +671,13 @@ def name(self) -> str | None:
663
671
664
672
@name .setter
665
673
def name (self , name : str | None ) -> None :
666
- if name is not None :
667
- if not isinstance (name , str ):
668
- raise TypeError ("node name must be a string or None" )
669
- if "/" in name :
670
- raise ValueError ("node names cannot contain forward slashes" )
674
+ if self .parent is not None :
675
+ raise ValueError (
676
+ "cannot set the name of a node which already has a parent. "
677
+ "Consider creating a detached copy of this node via .copy() "
678
+ "on the parent node."
679
+ )
680
+ _validate_name (name )
671
681
self ._name = name
672
682
673
683
def __repr__ (self , level = 0 ):
@@ -677,11 +687,13 @@ def __repr__(self, level=0):
677
687
return repr_value
678
688
679
689
def __str__ (self ) -> str :
680
- return f"NamedNode('{ self .name } ')" if self .name else "NamedNode()"
690
+ name_repr = repr (self .name ) if self .name is not None else ""
691
+ return f"NamedNode({ name_repr } )"
681
692
682
693
def _post_attach (self : AnyNamedNode , parent : AnyNamedNode , name : str ) -> None :
683
694
"""Ensures child has name attribute corresponding to key under which it has been stored."""
684
- self .name = name
695
+ _validate_name (name ) # is this check redundant?
696
+ self ._name = name
685
697
686
698
def _copy_node (
687
699
self : AnyNamedNode ,
0 commit comments