@@ -487,21 +487,18 @@ def parse_assign_target(
487487 """
488488 target : nodes .Expr
489489
490- if with_namespace and self .stream .look ().type == "dot" :
491- token = self .stream .expect ("name" )
492- next (self .stream ) # dot
493- attr = self .stream .expect ("name" )
494- target = nodes .NSRef (token .value , attr .value , lineno = token .lineno )
495- elif name_only :
490+ if name_only :
496491 token = self .stream .expect ("name" )
497492 target = nodes .Name (token .value , "store" , lineno = token .lineno )
498493 else :
499494 if with_tuple :
500495 target = self .parse_tuple (
501- simplified = True , extra_end_rules = extra_end_rules
496+ simplified = True ,
497+ extra_end_rules = extra_end_rules ,
498+ with_namespace = with_namespace ,
502499 )
503500 else :
504- target = self .parse_primary ()
501+ target = self .parse_primary (with_namespace = with_namespace )
505502
506503 target .set_ctx ("store" )
507504
@@ -643,17 +640,25 @@ def parse_unary(self, with_filter: bool = True) -> nodes.Expr:
643640 node = self .parse_filter_expr (node )
644641 return node
645642
646- def parse_primary (self ) -> nodes .Expr :
643+ def parse_primary (self , with_namespace : bool = False ) -> nodes .Expr :
644+ """Parse a name or literal value. If ``with_namespace`` is enabled, also
645+ parse namespace attr refs, for use in assignments."""
647646 token = self .stream .current
648647 node : nodes .Expr
649648 if token .type == "name" :
649+ next (self .stream )
650650 if token .value in ("true" , "false" , "True" , "False" ):
651651 node = nodes .Const (token .value in ("true" , "True" ), lineno = token .lineno )
652652 elif token .value in ("none" , "None" ):
653653 node = nodes .Const (None , lineno = token .lineno )
654+ elif with_namespace and self .stream .current .type == "dot" :
655+ # If namespace attributes are allowed at this point, and the next
656+ # token is a dot, produce a namespace reference.
657+ next (self .stream )
658+ attr = self .stream .expect ("name" )
659+ node = nodes .NSRef (token .value , attr .value , lineno = token .lineno )
654660 else :
655661 node = nodes .Name (token .value , "load" , lineno = token .lineno )
656- next (self .stream )
657662 elif token .type == "string" :
658663 next (self .stream )
659664 buf = [token .value ]
@@ -683,15 +688,17 @@ def parse_tuple(
683688 with_condexpr : bool = True ,
684689 extra_end_rules : t .Optional [t .Tuple [str , ...]] = None ,
685690 explicit_parentheses : bool = False ,
691+ with_namespace : bool = False ,
686692 ) -> t .Union [nodes .Tuple , nodes .Expr ]:
687693 """Works like `parse_expression` but if multiple expressions are
688694 delimited by a comma a :class:`~jinja2.nodes.Tuple` node is created.
689695 This method could also return a regular expression instead of a tuple
690696 if no commas where found.
691697
692698 The default parsing mode is a full tuple. If `simplified` is `True`
693- only names and literals are parsed. The `no_condexpr` parameter is
694- forwarded to :meth:`parse_expression`.
699+ only names and literals are parsed; ``with_namespace`` allows namespace
700+ attr refs as well. The `no_condexpr` parameter is forwarded to
701+ :meth:`parse_expression`.
695702
696703 Because tuples do not require delimiters and may end in a bogus comma
697704 an extra hint is needed that marks the end of a tuple. For example
@@ -704,13 +711,14 @@ def parse_tuple(
704711 """
705712 lineno = self .stream .current .lineno
706713 if simplified :
707- parse = self .parse_primary
708- elif with_condexpr :
709- parse = self .parse_expression
714+
715+ def parse () -> nodes .Expr :
716+ return self .parse_primary (with_namespace = with_namespace )
717+
710718 else :
711719
712720 def parse () -> nodes .Expr :
713- return self .parse_expression (with_condexpr = False )
721+ return self .parse_expression (with_condexpr = with_condexpr )
714722
715723 args : t .List [nodes .Expr ] = []
716724 is_tuple = False
0 commit comments