@@ -1582,12 +1582,19 @@ def visit_Output(self, node: nodes.Output, frame: Frame) -> None:
15821582 def visit_Assign (self , node : nodes .Assign , frame : Frame ) -> None :
15831583 self .push_assign_tracking ()
15841584
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+
15901591 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 )
15911598 ref = frame .symbols .ref (nsref .name )
15921599 self .writeline (f"if not isinstance({ ref } , Namespace):" )
15931600 self .indent ()
@@ -1653,9 +1660,10 @@ def visit_Name(self, node: nodes.Name, frame: Frame) -> None:
16531660 self .write (ref )
16541661
16551662 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.
16591667 ref = frame .symbols .ref (node .name )
16601668 self .writeline (f"{ ref } [{ node .attr !r} ]" )
16611669
0 commit comments