@@ -1582,12 +1582,19 @@ def visit_Output(self, node: nodes.Output, frame: Frame) -> None:
1582
1582
def visit_Assign (self , node : nodes .Assign , frame : Frame ) -> None :
1583
1583
self .push_assign_tracking ()
1584
1584
1585
- # NSRef can only ever be used during assignment so we need to check
1586
- # to make sure that it is only being used to assign using a Namespace.
1587
- # This check is done here because it is used an expression during the
1588
- # assignment and therefore cannot have this check done when the NSRef
1589
- # node is visited
1585
+ # ``a.b`` is allowed for assignment, and is parsed as an NSRef. However,
1586
+ # it is only valid if it references a Namespace object. Emit a check for
1587
+ # that for each ref here, before assignment code is emitted. This can't
1588
+ # be done in visit_NSRef as the ref could be in the middle of a tuple.
1589
+ seen_refs : t .Set [str ] = set ()
1590
+
1590
1591
for nsref in node .find_all (nodes .NSRef ):
1592
+ if nsref .name in seen_refs :
1593
+ # Only emit the check for each reference once, in case the same
1594
+ # ref is used multiple times in a tuple, `ns.a, ns.b = c, d`.
1595
+ continue
1596
+
1597
+ seen_refs .add (nsref .name )
1591
1598
ref = frame .symbols .ref (nsref .name )
1592
1599
self .writeline (f"if not isinstance({ ref } , Namespace):" )
1593
1600
self .indent ()
@@ -1653,9 +1660,10 @@ def visit_Name(self, node: nodes.Name, frame: Frame) -> None:
1653
1660
self .write (ref )
1654
1661
1655
1662
def visit_NSRef (self , node : nodes .NSRef , frame : Frame ) -> None :
1656
- # NSRefs can only be used to store values; since they use the normal
1657
- # `foo.bar` notation they will be parsed as a normal attribute access
1658
- # when used anywhere but in a `set` context
1663
+ # NSRef is a dotted assignment target a.b=c, but uses a[b]=c internally.
1664
+ # visit_Assign emits code to validate that each ref is to a Namespace
1665
+ # object only. That can't be emitted here as the ref could be in the
1666
+ # middle of a tuple assignment.
1659
1667
ref = frame .symbols .ref (node .name )
1660
1668
self .writeline (f"{ ref } [{ node .attr !r} ]" )
1661
1669
0 commit comments